xref: /aosp_15_r20/external/clang/utils/TableGen/ClangSACheckersEmitter.cpp (revision 67e74705e28f6214e480b399dd47ea732279e315)
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