Add the ClangSACheckersEmitter tablegen backend which will be used for the clang...
[oota-llvm.git] / utils / TableGen / ClangSACheckersEmitter.cpp
1 //=- ClangSACheckersEmitter.cpp - Generate Clang SA checkers tables -*- C++ -*-
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This tablegen backend emits Clang Static Analyzer checkers tables.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "ClangSACheckersEmitter.h"
15 #include "Record.h"
16 #include "llvm/ADT/DenseSet.h"
17 #include <map>
18 #include <string>
19 using namespace llvm;
20
21 //===----------------------------------------------------------------------===//
22 // Static Analyzer Checkers Tables generation
23 //===----------------------------------------------------------------------===//
24
25 /// \brief True if it is specified hidden or a parent package is specified
26 /// as hidden, otherwise false.
27 static bool isHidden(const Record &R) {
28   if (R.getValueAsBit("Hidden"))
29     return true;
30   // Not declared as hidden, check the parent package if it is hidden.
31   if (DefInit *DI = dynamic_cast<DefInit*>(R.getValueInit("ParentPackage")))
32     return isHidden(*DI->getDef());
33
34   return false;
35 }
36
37 static std::string getPackageFullName(Record *R);
38
39 static std::string getParentPackageFullName(Record *R) {
40   std::string name;
41   if (DefInit *DI = dynamic_cast<DefInit*>(R->getValueInit("ParentPackage")))
42     name = getPackageFullName(DI->getDef());
43   return name;
44 }
45
46 static std::string getPackageFullName(Record *R) {
47   std::string name = getParentPackageFullName(R);
48   if (!name.empty()) name += ".";
49   return name + R->getValueAsString("PackageName");
50 }
51
52 static std::string getCheckerFullName(Record *R) {
53   std::string name = getParentPackageFullName(R);
54   if (!name.empty()) name += ".";
55   return name + R->getValueAsString("CheckerName");
56 }
57
58 namespace {
59 struct GroupInfo {
60   std::vector<const Record*> Checkers;
61   llvm::DenseSet<const Record *> SubGroups;
62   unsigned Index;
63 };
64 }
65
66 void ClangSACheckersEmitter::run(raw_ostream &OS) {
67   std::vector<Record*> checkers = Records.getAllDerivedDefinitions("Checker");
68   llvm::DenseMap<const Record *, unsigned> checkerRecIndexMap;
69   for (unsigned i = 0, e = checkers.size(); i != e; ++i)
70     checkerRecIndexMap[checkers[i]] = i;
71   
72   OS << "\n#ifdef GET_CHECKERS\n";
73   for (unsigned i = 0, e = checkers.size(); i != e; ++i) {
74     const Record &R = *checkers[i];
75     
76     OS << "CHECKER(" << "\"";
77     OS.write_escaped(R.getValueAsString("CheckerName")) << "\", ";
78     OS << R.getValueAsString("ClassName") << ", ";
79     OS << R.getValueAsString("DescFile") << ", ";
80     OS << "\"";
81     OS.write_escaped(R.getValueAsString("HelpText")) << "\", ";
82     // Hidden bit
83     if (isHidden(R))
84       OS << "true";
85     else
86       OS << "false";
87     OS << ")\n";
88   }
89   OS << "#endif // GET_CHECKERS\n\n";
90
91   // Invert the mapping of checkers to package/group into a one to many
92   // mapping of packages/groups to checkers.
93   std::map<std::string, GroupInfo> groupInfoByName;
94   llvm::DenseMap<const Record *, GroupInfo *> recordGroupMap;
95
96   std::vector<Record*> packages = Records.getAllDerivedDefinitions("Package");
97   for (unsigned i = 0, e = packages.size(); i != e; ++i) {
98     Record *R = packages[i];
99     std::string fullName = getPackageFullName(R);
100     if (!fullName.empty()) {
101       GroupInfo &info = groupInfoByName[fullName];
102       recordGroupMap[R] = &info;
103     }
104   }
105
106   std::vector<Record*>
107       checkerGroups = Records.getAllDerivedDefinitions("CheckerGroup");
108   for (unsigned i = 0, e = checkerGroups.size(); i != e; ++i) {
109     Record *R = checkerGroups[i];
110     std::string name = R->getValueAsString("GroupName");
111     if (!name.empty()) {
112       GroupInfo &info = groupInfoByName[name];
113       recordGroupMap[R] = &info;
114     }
115   }
116
117   for (unsigned i = 0, e = checkers.size(); i != e; ++i) {
118     Record *R = checkers[i];
119     std::string fullName = getCheckerFullName(R);
120     if (!fullName.empty()) {
121       GroupInfo &info = groupInfoByName[fullName];
122       recordGroupMap[R] = &info;
123       info.Checkers.push_back(R);
124       Record *currR = R;
125       // Insert the checker and its parent packages into the set of the
126       // corresponding parent package.
127       while (DefInit *DI
128                = dynamic_cast<DefInit*>(currR->getValueInit("ParentPackage"))) {
129         Record *parentPackage = DI->getDef();
130         recordGroupMap[parentPackage]->SubGroups.insert(currR);
131         currR = parentPackage;
132       }
133       // Insert the checker into the set of its group.
134       if (DefInit *DI = dynamic_cast<DefInit*>(R->getValueInit("Group")))
135         recordGroupMap[DI->getDef()]->SubGroups.insert(R);
136     }
137   }
138
139   unsigned index = 0;
140   for (std::map<std::string, GroupInfo>::iterator
141          I = groupInfoByName.begin(), E = groupInfoByName.end(); I != E; ++I)
142     I->second.Index = index++;
143
144   // Walk through the packages/groups/checkers emitting an array for each
145   // set of checkers and an array for each set of subpackages.
146
147   OS << "\n#ifdef GET_MEMBER_ARRAYS\n";
148   unsigned maxLen = 0;
149   for (std::map<std::string, GroupInfo>::iterator
150          I = groupInfoByName.begin(), E = groupInfoByName.end(); I != E; ++I) {
151     maxLen = std::max(maxLen, (unsigned)I->first.size());
152     
153     std::vector<const Record*> &V = I->second.Checkers;
154     if (!V.empty()) {
155       OS << "static const short CheckerArray" << I->second.Index << "[] = { ";
156       for (unsigned i = 0, e = V.size(); i != e; ++i)
157         OS << checkerRecIndexMap[V[i]] << ", ";
158       OS << "-1 };\n";
159     }
160     
161     llvm::DenseSet<const Record *> &subGroups = I->second.SubGroups;
162     if (!subGroups.empty()) {
163       OS << "static const short SubPackageArray" << I->second.Index << "[] = { ";
164       for (llvm::DenseSet<const Record *>::iterator
165              I = subGroups.begin(), E = subGroups.end(); I != E; ++I) {
166         OS << recordGroupMap[*I]->Index << ", ";
167       }
168       OS << "-1 };\n";
169     }
170   }
171   OS << "#endif // GET_MEMBER_ARRAYS\n\n";
172
173   OS << "\n#ifdef GET_CHECKNAME_TABLE\n";
174   for (std::map<std::string, GroupInfo>::iterator
175          I = groupInfoByName.begin(), E = groupInfoByName.end(); I != E; ++I) {
176     // Group option string.
177     OS << "  { \"";
178     OS.write_escaped(I->first) << "\","
179                                << std::string(maxLen-I->first.size()+1, ' ');
180     
181     if (I->second.Checkers.empty())
182       OS << "0, ";
183     else
184       OS << "CheckerArray" << I->second.Index << ", ";
185     
186     // Subgroups.
187     if (I->second.SubGroups.empty())
188       OS << 0;
189     else
190       OS << "SubPackageArray" << I->second.Index;
191     OS << " },\n";
192   }
193   OS << "#endif // GET_CHECKNAME_TABLE\n\n";
194 }