1*67e74705SXin Li //=- ClangSACheckersEmitter.cpp - Generate Clang SA checkers tables -*- C++ -*-
2*67e74705SXin Li //
3*67e74705SXin Li // The LLVM Compiler Infrastructure
4*67e74705SXin Li //
5*67e74705SXin Li // This file is distributed under the University of Illinois Open Source
6*67e74705SXin Li // License. See LICENSE.TXT for details.
7*67e74705SXin Li //
8*67e74705SXin Li //===----------------------------------------------------------------------===//
9*67e74705SXin Li //
10*67e74705SXin Li // This tablegen backend emits Clang Static Analyzer checkers tables.
11*67e74705SXin Li //
12*67e74705SXin Li //===----------------------------------------------------------------------===//
13*67e74705SXin Li
14*67e74705SXin Li #include "llvm/ADT/DenseSet.h"
15*67e74705SXin Li #include "llvm/TableGen/Error.h"
16*67e74705SXin Li #include "llvm/TableGen/Record.h"
17*67e74705SXin Li #include "llvm/TableGen/TableGenBackend.h"
18*67e74705SXin Li #include <map>
19*67e74705SXin Li #include <string>
20*67e74705SXin Li using namespace llvm;
21*67e74705SXin Li
22*67e74705SXin Li //===----------------------------------------------------------------------===//
23*67e74705SXin Li // Static Analyzer Checkers Tables generation
24*67e74705SXin Li //===----------------------------------------------------------------------===//
25*67e74705SXin Li
26*67e74705SXin Li /// \brief True if it is specified hidden or a parent package is specified
27*67e74705SXin Li /// as hidden, otherwise false.
isHidden(const Record & R)28*67e74705SXin Li static bool isHidden(const Record &R) {
29*67e74705SXin Li if (R.getValueAsBit("Hidden"))
30*67e74705SXin Li return true;
31*67e74705SXin Li // Not declared as hidden, check the parent package if it is hidden.
32*67e74705SXin Li if (DefInit *DI = dyn_cast<DefInit>(R.getValueInit("ParentPackage")))
33*67e74705SXin Li return isHidden(*DI->getDef());
34*67e74705SXin Li
35*67e74705SXin Li return false;
36*67e74705SXin Li }
37*67e74705SXin Li
isCheckerNamed(const Record * R)38*67e74705SXin Li static bool isCheckerNamed(const Record *R) {
39*67e74705SXin Li return !R->getValueAsString("CheckerName").empty();
40*67e74705SXin Li }
41*67e74705SXin Li
42*67e74705SXin Li static std::string getPackageFullName(const Record *R);
43*67e74705SXin Li
getParentPackageFullName(const Record * R)44*67e74705SXin Li static std::string getParentPackageFullName(const Record *R) {
45*67e74705SXin Li std::string name;
46*67e74705SXin Li if (DefInit *DI = dyn_cast<DefInit>(R->getValueInit("ParentPackage")))
47*67e74705SXin Li name = getPackageFullName(DI->getDef());
48*67e74705SXin Li return name;
49*67e74705SXin Li }
50*67e74705SXin Li
getPackageFullName(const Record * R)51*67e74705SXin Li static std::string getPackageFullName(const Record *R) {
52*67e74705SXin Li std::string name = getParentPackageFullName(R);
53*67e74705SXin Li if (!name.empty()) name += ".";
54*67e74705SXin Li return name + R->getValueAsString("PackageName");
55*67e74705SXin Li }
56*67e74705SXin Li
getCheckerFullName(const Record * R)57*67e74705SXin Li static std::string getCheckerFullName(const Record *R) {
58*67e74705SXin Li std::string name = getParentPackageFullName(R);
59*67e74705SXin Li if (isCheckerNamed(R)) {
60*67e74705SXin Li if (!name.empty()) name += ".";
61*67e74705SXin Li name += R->getValueAsString("CheckerName");
62*67e74705SXin Li }
63*67e74705SXin Li return name;
64*67e74705SXin Li }
65*67e74705SXin Li
getStringValue(const Record & R,StringRef field)66*67e74705SXin Li static std::string getStringValue(const Record &R, StringRef field) {
67*67e74705SXin Li if (StringInit *SI = dyn_cast<StringInit>(R.getValueInit(field)))
68*67e74705SXin Li return SI->getValue();
69*67e74705SXin Li return std::string();
70*67e74705SXin Li }
71*67e74705SXin Li
72*67e74705SXin Li namespace {
73*67e74705SXin Li struct GroupInfo {
74*67e74705SXin Li llvm::DenseSet<const Record*> Checkers;
75*67e74705SXin Li llvm::DenseSet<const Record *> SubGroups;
76*67e74705SXin Li bool Hidden;
77*67e74705SXin Li unsigned Index;
78*67e74705SXin Li
GroupInfo__anonecc5ad380111::GroupInfo79*67e74705SXin Li GroupInfo() : Hidden(false) { }
80*67e74705SXin Li };
81*67e74705SXin Li }
82*67e74705SXin Li
addPackageToCheckerGroup(const Record * package,const Record * group,llvm::DenseMap<const Record *,GroupInfo * > & recordGroupMap)83*67e74705SXin Li static void addPackageToCheckerGroup(const Record *package, const Record *group,
84*67e74705SXin Li llvm::DenseMap<const Record *, GroupInfo *> &recordGroupMap) {
85*67e74705SXin Li llvm::DenseSet<const Record *> &checkers = recordGroupMap[package]->Checkers;
86*67e74705SXin Li for (llvm::DenseSet<const Record *>::iterator
87*67e74705SXin Li I = checkers.begin(), E = checkers.end(); I != E; ++I)
88*67e74705SXin Li recordGroupMap[group]->Checkers.insert(*I);
89*67e74705SXin Li
90*67e74705SXin Li llvm::DenseSet<const Record *> &subGroups = recordGroupMap[package]->SubGroups;
91*67e74705SXin Li for (llvm::DenseSet<const Record *>::iterator
92*67e74705SXin Li I = subGroups.begin(), E = subGroups.end(); I != E; ++I)
93*67e74705SXin Li addPackageToCheckerGroup(*I, group, recordGroupMap);
94*67e74705SXin Li }
95*67e74705SXin Li
96*67e74705SXin Li namespace clang {
EmitClangSACheckers(RecordKeeper & Records,raw_ostream & OS)97*67e74705SXin Li void EmitClangSACheckers(RecordKeeper &Records, raw_ostream &OS) {
98*67e74705SXin Li std::vector<Record*> checkers = Records.getAllDerivedDefinitions("Checker");
99*67e74705SXin Li llvm::DenseMap<const Record *, unsigned> checkerRecIndexMap;
100*67e74705SXin Li for (unsigned i = 0, e = checkers.size(); i != e; ++i)
101*67e74705SXin Li checkerRecIndexMap[checkers[i]] = i;
102*67e74705SXin Li
103*67e74705SXin Li // Invert the mapping of checkers to package/group into a one to many
104*67e74705SXin Li // mapping of packages/groups to checkers.
105*67e74705SXin Li std::map<std::string, GroupInfo> groupInfoByName;
106*67e74705SXin Li llvm::DenseMap<const Record *, GroupInfo *> recordGroupMap;
107*67e74705SXin Li
108*67e74705SXin Li std::vector<Record*> packages = Records.getAllDerivedDefinitions("Package");
109*67e74705SXin Li for (unsigned i = 0, e = packages.size(); i != e; ++i) {
110*67e74705SXin Li Record *R = packages[i];
111*67e74705SXin Li std::string fullName = getPackageFullName(R);
112*67e74705SXin Li if (!fullName.empty()) {
113*67e74705SXin Li GroupInfo &info = groupInfoByName[fullName];
114*67e74705SXin Li info.Hidden = isHidden(*R);
115*67e74705SXin Li recordGroupMap[R] = &info;
116*67e74705SXin Li }
117*67e74705SXin Li }
118*67e74705SXin Li
119*67e74705SXin Li std::vector<Record*>
120*67e74705SXin Li checkerGroups = Records.getAllDerivedDefinitions("CheckerGroup");
121*67e74705SXin Li for (unsigned i = 0, e = checkerGroups.size(); i != e; ++i) {
122*67e74705SXin Li Record *R = checkerGroups[i];
123*67e74705SXin Li std::string name = R->getValueAsString("GroupName");
124*67e74705SXin Li if (!name.empty()) {
125*67e74705SXin Li GroupInfo &info = groupInfoByName[name];
126*67e74705SXin Li recordGroupMap[R] = &info;
127*67e74705SXin Li }
128*67e74705SXin Li }
129*67e74705SXin Li
130*67e74705SXin Li for (unsigned i = 0, e = checkers.size(); i != e; ++i) {
131*67e74705SXin Li Record *R = checkers[i];
132*67e74705SXin Li Record *package = nullptr;
133*67e74705SXin Li if (DefInit *
134*67e74705SXin Li DI = dyn_cast<DefInit>(R->getValueInit("ParentPackage")))
135*67e74705SXin Li package = DI->getDef();
136*67e74705SXin Li if (!isCheckerNamed(R) && !package)
137*67e74705SXin Li PrintFatalError(R->getLoc(), "Checker '" + R->getName() +
138*67e74705SXin Li "' is neither named, nor in a package!");
139*67e74705SXin Li
140*67e74705SXin Li if (isCheckerNamed(R)) {
141*67e74705SXin Li // Create a pseudo-group to hold this checker.
142*67e74705SXin Li std::string fullName = getCheckerFullName(R);
143*67e74705SXin Li GroupInfo &info = groupInfoByName[fullName];
144*67e74705SXin Li info.Hidden = R->getValueAsBit("Hidden");
145*67e74705SXin Li recordGroupMap[R] = &info;
146*67e74705SXin Li info.Checkers.insert(R);
147*67e74705SXin Li } else {
148*67e74705SXin Li recordGroupMap[package]->Checkers.insert(R);
149*67e74705SXin Li }
150*67e74705SXin Li
151*67e74705SXin Li Record *currR = isCheckerNamed(R) ? R : package;
152*67e74705SXin Li // Insert the checker and its parent packages into the subgroups set of
153*67e74705SXin Li // the corresponding parent package.
154*67e74705SXin Li while (DefInit *DI
155*67e74705SXin Li = dyn_cast<DefInit>(currR->getValueInit("ParentPackage"))) {
156*67e74705SXin Li Record *parentPackage = DI->getDef();
157*67e74705SXin Li recordGroupMap[parentPackage]->SubGroups.insert(currR);
158*67e74705SXin Li currR = parentPackage;
159*67e74705SXin Li }
160*67e74705SXin Li // Insert the checker into the set of its group.
161*67e74705SXin Li if (DefInit *DI = dyn_cast<DefInit>(R->getValueInit("Group")))
162*67e74705SXin Li recordGroupMap[DI->getDef()]->Checkers.insert(R);
163*67e74705SXin Li }
164*67e74705SXin Li
165*67e74705SXin Li // If a package is in group, add all its checkers and its sub-packages
166*67e74705SXin Li // checkers into the group.
167*67e74705SXin Li for (unsigned i = 0, e = packages.size(); i != e; ++i)
168*67e74705SXin Li if (DefInit *DI = dyn_cast<DefInit>(packages[i]->getValueInit("Group")))
169*67e74705SXin Li addPackageToCheckerGroup(packages[i], DI->getDef(), recordGroupMap);
170*67e74705SXin Li
171*67e74705SXin Li typedef std::map<std::string, const Record *> SortedRecords;
172*67e74705SXin Li typedef llvm::DenseMap<const Record *, unsigned> RecToSortIndex;
173*67e74705SXin Li
174*67e74705SXin Li SortedRecords sortedGroups;
175*67e74705SXin Li RecToSortIndex groupToSortIndex;
176*67e74705SXin Li OS << "\n#ifdef GET_GROUPS\n";
177*67e74705SXin Li {
178*67e74705SXin Li for (unsigned i = 0, e = checkerGroups.size(); i != e; ++i)
179*67e74705SXin Li sortedGroups[checkerGroups[i]->getValueAsString("GroupName")]
180*67e74705SXin Li = checkerGroups[i];
181*67e74705SXin Li
182*67e74705SXin Li unsigned sortIndex = 0;
183*67e74705SXin Li for (SortedRecords::iterator
184*67e74705SXin Li I = sortedGroups.begin(), E = sortedGroups.end(); I != E; ++I) {
185*67e74705SXin Li const Record *R = I->second;
186*67e74705SXin Li
187*67e74705SXin Li OS << "GROUP(" << "\"";
188*67e74705SXin Li OS.write_escaped(R->getValueAsString("GroupName")) << "\"";
189*67e74705SXin Li OS << ")\n";
190*67e74705SXin Li
191*67e74705SXin Li groupToSortIndex[R] = sortIndex++;
192*67e74705SXin Li }
193*67e74705SXin Li }
194*67e74705SXin Li OS << "#endif // GET_GROUPS\n\n";
195*67e74705SXin Li
196*67e74705SXin Li OS << "\n#ifdef GET_PACKAGES\n";
197*67e74705SXin Li {
198*67e74705SXin Li SortedRecords sortedPackages;
199*67e74705SXin Li for (unsigned i = 0, e = packages.size(); i != e; ++i)
200*67e74705SXin Li sortedPackages[getPackageFullName(packages[i])] = packages[i];
201*67e74705SXin Li
202*67e74705SXin Li for (SortedRecords::iterator
203*67e74705SXin Li I = sortedPackages.begin(), E = sortedPackages.end(); I != E; ++I) {
204*67e74705SXin Li const Record &R = *I->second;
205*67e74705SXin Li
206*67e74705SXin Li OS << "PACKAGE(" << "\"";
207*67e74705SXin Li OS.write_escaped(getPackageFullName(&R)) << "\", ";
208*67e74705SXin Li // Group index
209*67e74705SXin Li if (DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group")))
210*67e74705SXin Li OS << groupToSortIndex[DI->getDef()] << ", ";
211*67e74705SXin Li else
212*67e74705SXin Li OS << "-1, ";
213*67e74705SXin Li // Hidden bit
214*67e74705SXin Li if (isHidden(R))
215*67e74705SXin Li OS << "true";
216*67e74705SXin Li else
217*67e74705SXin Li OS << "false";
218*67e74705SXin Li OS << ")\n";
219*67e74705SXin Li }
220*67e74705SXin Li }
221*67e74705SXin Li OS << "#endif // GET_PACKAGES\n\n";
222*67e74705SXin Li
223*67e74705SXin Li OS << "\n#ifdef GET_CHECKERS\n";
224*67e74705SXin Li for (unsigned i = 0, e = checkers.size(); i != e; ++i) {
225*67e74705SXin Li const Record &R = *checkers[i];
226*67e74705SXin Li
227*67e74705SXin Li OS << "CHECKER(" << "\"";
228*67e74705SXin Li std::string name;
229*67e74705SXin Li if (isCheckerNamed(&R))
230*67e74705SXin Li name = getCheckerFullName(&R);
231*67e74705SXin Li OS.write_escaped(name) << "\", ";
232*67e74705SXin Li OS << R.getName() << ", ";
233*67e74705SXin Li OS << getStringValue(R, "DescFile") << ", ";
234*67e74705SXin Li OS << "\"";
235*67e74705SXin Li OS.write_escaped(getStringValue(R, "HelpText")) << "\", ";
236*67e74705SXin Li // Group index
237*67e74705SXin Li if (DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group")))
238*67e74705SXin Li OS << groupToSortIndex[DI->getDef()] << ", ";
239*67e74705SXin Li else
240*67e74705SXin Li OS << "-1, ";
241*67e74705SXin Li // Hidden bit
242*67e74705SXin Li if (isHidden(R))
243*67e74705SXin Li OS << "true";
244*67e74705SXin Li else
245*67e74705SXin Li OS << "false";
246*67e74705SXin Li OS << ")\n";
247*67e74705SXin Li }
248*67e74705SXin Li OS << "#endif // GET_CHECKERS\n\n";
249*67e74705SXin Li
250*67e74705SXin Li unsigned index = 0;
251*67e74705SXin Li for (std::map<std::string, GroupInfo>::iterator
252*67e74705SXin Li I = groupInfoByName.begin(), E = groupInfoByName.end(); I != E; ++I)
253*67e74705SXin Li I->second.Index = index++;
254*67e74705SXin Li
255*67e74705SXin Li // Walk through the packages/groups/checkers emitting an array for each
256*67e74705SXin Li // set of checkers and an array for each set of subpackages.
257*67e74705SXin Li
258*67e74705SXin Li OS << "\n#ifdef GET_MEMBER_ARRAYS\n";
259*67e74705SXin Li unsigned maxLen = 0;
260*67e74705SXin Li for (std::map<std::string, GroupInfo>::iterator
261*67e74705SXin Li I = groupInfoByName.begin(), E = groupInfoByName.end(); I != E; ++I) {
262*67e74705SXin Li maxLen = std::max(maxLen, (unsigned)I->first.size());
263*67e74705SXin Li
264*67e74705SXin Li llvm::DenseSet<const Record *> &checkers = I->second.Checkers;
265*67e74705SXin Li if (!checkers.empty()) {
266*67e74705SXin Li OS << "static const short CheckerArray" << I->second.Index << "[] = { ";
267*67e74705SXin Li // Make the output order deterministic.
268*67e74705SXin Li std::map<int, const Record *> sorted;
269*67e74705SXin Li for (llvm::DenseSet<const Record *>::iterator
270*67e74705SXin Li I = checkers.begin(), E = checkers.end(); I != E; ++I)
271*67e74705SXin Li sorted[(*I)->getID()] = *I;
272*67e74705SXin Li
273*67e74705SXin Li for (std::map<int, const Record *>::iterator
274*67e74705SXin Li I = sorted.begin(), E = sorted.end(); I != E; ++I)
275*67e74705SXin Li OS << checkerRecIndexMap[I->second] << ", ";
276*67e74705SXin Li OS << "-1 };\n";
277*67e74705SXin Li }
278*67e74705SXin Li
279*67e74705SXin Li llvm::DenseSet<const Record *> &subGroups = I->second.SubGroups;
280*67e74705SXin Li if (!subGroups.empty()) {
281*67e74705SXin Li OS << "static const short SubPackageArray" << I->second.Index << "[] = { ";
282*67e74705SXin Li // Make the output order deterministic.
283*67e74705SXin Li std::map<int, const Record *> sorted;
284*67e74705SXin Li for (llvm::DenseSet<const Record *>::iterator
285*67e74705SXin Li I = subGroups.begin(), E = subGroups.end(); I != E; ++I)
286*67e74705SXin Li sorted[(*I)->getID()] = *I;
287*67e74705SXin Li
288*67e74705SXin Li for (std::map<int, const Record *>::iterator
289*67e74705SXin Li I = sorted.begin(), E = sorted.end(); I != E; ++I) {
290*67e74705SXin Li OS << recordGroupMap[I->second]->Index << ", ";
291*67e74705SXin Li }
292*67e74705SXin Li OS << "-1 };\n";
293*67e74705SXin Li }
294*67e74705SXin Li }
295*67e74705SXin Li OS << "#endif // GET_MEMBER_ARRAYS\n\n";
296*67e74705SXin Li
297*67e74705SXin Li OS << "\n#ifdef GET_CHECKNAME_TABLE\n";
298*67e74705SXin Li for (std::map<std::string, GroupInfo>::iterator
299*67e74705SXin Li I = groupInfoByName.begin(), E = groupInfoByName.end(); I != E; ++I) {
300*67e74705SXin Li // Group option string.
301*67e74705SXin Li OS << " { \"";
302*67e74705SXin Li OS.write_escaped(I->first) << "\","
303*67e74705SXin Li << std::string(maxLen-I->first.size()+1, ' ');
304*67e74705SXin Li
305*67e74705SXin Li if (I->second.Checkers.empty())
306*67e74705SXin Li OS << "0, ";
307*67e74705SXin Li else
308*67e74705SXin Li OS << "CheckerArray" << I->second.Index << ", ";
309*67e74705SXin Li
310*67e74705SXin Li // Subgroups.
311*67e74705SXin Li if (I->second.SubGroups.empty())
312*67e74705SXin Li OS << "0, ";
313*67e74705SXin Li else
314*67e74705SXin Li OS << "SubPackageArray" << I->second.Index << ", ";
315*67e74705SXin Li
316*67e74705SXin Li OS << (I->second.Hidden ? "true" : "false");
317*67e74705SXin Li
318*67e74705SXin Li OS << " },\n";
319*67e74705SXin Li }
320*67e74705SXin Li OS << "#endif // GET_CHECKNAME_TABLE\n\n";
321*67e74705SXin Li }
322*67e74705SXin Li } // end namespace clang
323