1 //=- ClangSACheckersEmitter.cpp - Generate Clang SA checkers tables -*- C++ -*-
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This tablegen backend emits Clang Static Analyzer checkers tables.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #include "TableGenBackends.h"
14 #include "llvm/ADT/StringMap.h"
15 #include "llvm/TableGen/Error.h"
16 #include "llvm/TableGen/Record.h"
17 #include "llvm/TableGen/TableGenBackend.h"
18 #include <map>
19 #include <string>
20
21 using namespace llvm;
22
23 //===----------------------------------------------------------------------===//
24 // Static Analyzer Checkers Tables generation
25 //===----------------------------------------------------------------------===//
26
27 static std::string getPackageFullName(const Record *R);
28
getParentPackageFullName(const Record * R)29 static std::string getParentPackageFullName(const Record *R) {
30 std::string name;
31 if (DefInit *DI = dyn_cast<DefInit>(R->getValueInit("ParentPackage")))
32 name = getPackageFullName(DI->getDef());
33 return name;
34 }
35
getPackageFullName(const Record * R)36 static std::string getPackageFullName(const Record *R) {
37 std::string name = getParentPackageFullName(R);
38 if (!name.empty())
39 name += ".";
40 assert(!R->getValueAsString("PackageName").empty());
41 name += R->getValueAsString("PackageName");
42 return name;
43 }
44
getCheckerFullName(const Record * R)45 static std::string getCheckerFullName(const Record *R) {
46 std::string name = getParentPackageFullName(R);
47 if (!name.empty())
48 name += ".";
49 assert(!R->getValueAsString("CheckerName").empty());
50 name += R->getValueAsString("CheckerName");
51 return name;
52 }
53
getStringValue(const Record & R,StringRef field)54 static std::string getStringValue(const Record &R, StringRef field) {
55 if (StringInit *SI = dyn_cast<StringInit>(R.getValueInit(field)))
56 return std::string(SI->getValue());
57 return std::string();
58 }
59
60 // Calculates the integer value representing the BitsInit object
getValueFromBitsInit(const BitsInit * B,const Record & R)61 static inline uint64_t getValueFromBitsInit(const BitsInit *B, const Record &R) {
62 assert(B->getNumBits() <= sizeof(uint64_t) * 8 && "BitInits' too long!");
63
64 uint64_t Value = 0;
65 for (unsigned i = 0, e = B->getNumBits(); i != e; ++i) {
66 const auto *Bit = dyn_cast<BitInit>(B->getBit(i));
67 if (Bit)
68 Value |= uint64_t(Bit->getValue()) << i;
69 else
70 PrintFatalError(R.getLoc(),
71 "missing Documentation for " + getCheckerFullName(&R));
72 }
73 return Value;
74 }
75
getCheckerDocs(const Record & R)76 static std::string getCheckerDocs(const Record &R) {
77 StringRef LandingPage;
78 if (BitsInit *BI = R.getValueAsBitsInit("Documentation")) {
79 uint64_t V = getValueFromBitsInit(BI, R);
80 if (V == 1)
81 LandingPage = "available_checks.html";
82 else if (V == 2)
83 LandingPage = "alpha_checks.html";
84 }
85
86 if (LandingPage.empty())
87 return "";
88
89 return (llvm::Twine("https://clang-analyzer.llvm.org/") + LandingPage + "#" +
90 getCheckerFullName(&R))
91 .str();
92 }
93
94 /// Retrieves the type from a CmdOptionTypeEnum typed Record object. Note that
95 /// the class itself has to be modified for adding a new option type in
96 /// CheckerBase.td.
getCheckerOptionType(const Record & R)97 static std::string getCheckerOptionType(const Record &R) {
98 if (BitsInit *BI = R.getValueAsBitsInit("Type")) {
99 switch(getValueFromBitsInit(BI, R)) {
100 case 0:
101 return "int";
102 case 1:
103 return "string";
104 case 2:
105 return "bool";
106 }
107 }
108 PrintFatalError(R.getLoc(),
109 "unable to parse command line option type for "
110 + getCheckerFullName(&R));
111 return "";
112 }
113
getDevelopmentStage(const Record & R)114 static std::string getDevelopmentStage(const Record &R) {
115 if (BitsInit *BI = R.getValueAsBitsInit("DevelopmentStage")) {
116 switch(getValueFromBitsInit(BI, R)) {
117 case 0:
118 return "alpha";
119 case 1:
120 return "released";
121 }
122 }
123
124 PrintFatalError(R.getLoc(),
125 "unable to parse command line option type for "
126 + getCheckerFullName(&R));
127 return "";
128 }
129
isHidden(const Record * R)130 static bool isHidden(const Record *R) {
131 if (R->getValueAsBit("Hidden"))
132 return true;
133
134 // Not declared as hidden, check the parent package if it is hidden.
135 if (DefInit *DI = dyn_cast<DefInit>(R->getValueInit("ParentPackage")))
136 return isHidden(DI->getDef());
137
138 return false;
139 }
140
printChecker(llvm::raw_ostream & OS,const Record & R)141 static void printChecker(llvm::raw_ostream &OS, const Record &R) {
142 OS << "CHECKER(" << "\"";
143 OS.write_escaped(getCheckerFullName(&R)) << "\", ";
144 OS << R.getName() << ", ";
145 OS << "\"";
146 OS.write_escaped(getStringValue(R, "HelpText")) << "\", ";
147 OS << "\"";
148 OS.write_escaped(getCheckerDocs(R));
149 OS << "\", ";
150
151 if (!isHidden(&R))
152 OS << "false";
153 else
154 OS << "true";
155
156 OS << ")\n";
157 }
158
printOption(llvm::raw_ostream & OS,StringRef FullName,const Record & R)159 static void printOption(llvm::raw_ostream &OS, StringRef FullName,
160 const Record &R) {
161 OS << "\"";
162 OS.write_escaped(getCheckerOptionType(R)) << "\", \"";
163 OS.write_escaped(FullName) << "\", ";
164 OS << '\"' << getStringValue(R, "CmdFlag") << "\", ";
165 OS << '\"';
166 OS.write_escaped(getStringValue(R, "Desc")) << "\", ";
167 OS << '\"';
168 OS.write_escaped(getStringValue(R, "DefaultVal")) << "\", ";
169 OS << '\"';
170 OS << getDevelopmentStage(R) << "\", ";
171
172 if (!R.getValueAsBit("Hidden"))
173 OS << "false";
174 else
175 OS << "true";
176 }
177
EmitClangSACheckers(RecordKeeper & Records,raw_ostream & OS)178 void clang::EmitClangSACheckers(RecordKeeper &Records, raw_ostream &OS) {
179 std::vector<Record*> checkers = Records.getAllDerivedDefinitions("Checker");
180 std::vector<Record*> packages = Records.getAllDerivedDefinitions("Package");
181
182 using SortedRecords = llvm::StringMap<const Record *>;
183
184 OS << "// This file is automatically generated. Do not edit this file by "
185 "hand.\n";
186
187 // Emit packages.
188 //
189 // PACKAGE(PACKAGENAME)
190 // - PACKAGENAME: The name of the package.
191 OS << "\n"
192 "#ifdef GET_PACKAGES\n";
193 {
194 SortedRecords sortedPackages;
195 for (unsigned i = 0, e = packages.size(); i != e; ++i)
196 sortedPackages[getPackageFullName(packages[i])] = packages[i];
197
198 for (SortedRecords::iterator
199 I = sortedPackages.begin(), E = sortedPackages.end(); I != E; ++I) {
200 const Record &R = *I->second;
201
202 OS << "PACKAGE(" << "\"";
203 OS.write_escaped(getPackageFullName(&R)) << '\"';
204 OS << ")\n";
205 }
206 }
207 OS << "#endif // GET_PACKAGES\n"
208 "\n";
209
210 // Emit a package option.
211 //
212 // PACKAGE_OPTION(OPTIONTYPE, PACKAGENAME, OPTIONNAME, DESCRIPTION, DEFAULT)
213 // - OPTIONTYPE: Type of the option, whether it's integer or boolean etc.
214 // This is important for validating user input. Note that
215 // it's a string, rather than an actual type: since we can
216 // load checkers runtime, we can't use template hackery for
217 // sorting this out compile-time.
218 // - PACKAGENAME: Name of the package.
219 // - OPTIONNAME: Name of the option.
220 // - DESCRIPTION
221 // - DEFAULT: The default value for this option.
222 //
223 // The full option can be specified in the command like like this:
224 // -analyzer-config PACKAGENAME:OPTIONNAME=VALUE
225 OS << "\n"
226 "#ifdef GET_PACKAGE_OPTIONS\n";
227 for (const Record *Package : packages) {
228
229 if (Package->isValueUnset("PackageOptions"))
230 continue;
231
232 std::vector<Record *> PackageOptions = Package
233 ->getValueAsListOfDefs("PackageOptions");
234 for (Record *PackageOpt : PackageOptions) {
235 OS << "PACKAGE_OPTION(";
236 printOption(OS, getPackageFullName(Package), *PackageOpt);
237 OS << ")\n";
238 }
239 }
240 OS << "#endif // GET_PACKAGE_OPTIONS\n"
241 "\n";
242
243 // Emit checkers.
244 //
245 // CHECKER(FULLNAME, CLASS, HELPTEXT)
246 // - FULLNAME: The full name of the checker, including packages, e.g.:
247 // alpha.cplusplus.UninitializedObject
248 // - CLASS: The name of the checker, with "Checker" appended, e.g.:
249 // UninitializedObjectChecker
250 // - HELPTEXT: The description of the checker.
251 OS << "\n"
252 "#ifdef GET_CHECKERS\n"
253 "\n";
254 for (const Record *checker : checkers) {
255 printChecker(OS, *checker);
256 }
257 OS << "\n"
258 "#endif // GET_CHECKERS\n"
259 "\n";
260
261 // Emit dependencies.
262 //
263 // CHECKER_DEPENDENCY(FULLNAME, DEPENDENCY)
264 // - FULLNAME: The full name of the checker that depends on another checker.
265 // - DEPENDENCY: The full name of the checker FULLNAME depends on.
266 OS << "\n"
267 "#ifdef GET_CHECKER_DEPENDENCIES\n";
268 for (const Record *Checker : checkers) {
269 if (Checker->isValueUnset("Dependencies"))
270 continue;
271
272 for (const Record *Dependency :
273 Checker->getValueAsListOfDefs("Dependencies")) {
274 OS << "CHECKER_DEPENDENCY(";
275 OS << '\"';
276 OS.write_escaped(getCheckerFullName(Checker)) << "\", ";
277 OS << '\"';
278 OS.write_escaped(getCheckerFullName(Dependency)) << '\"';
279 OS << ")\n";
280 }
281 }
282 OS << "\n"
283 "#endif // GET_CHECKER_DEPENDENCIES\n";
284
285 // Emit weak dependencies.
286 //
287 // CHECKER_DEPENDENCY(FULLNAME, DEPENDENCY)
288 // - FULLNAME: The full name of the checker that is supposed to be
289 // registered first.
290 // - DEPENDENCY: The full name of the checker FULLNAME weak depends on.
291 OS << "\n"
292 "#ifdef GET_CHECKER_WEAK_DEPENDENCIES\n";
293 for (const Record *Checker : checkers) {
294 if (Checker->isValueUnset("WeakDependencies"))
295 continue;
296
297 for (const Record *Dependency :
298 Checker->getValueAsListOfDefs("WeakDependencies")) {
299 OS << "CHECKER_WEAK_DEPENDENCY(";
300 OS << '\"';
301 OS.write_escaped(getCheckerFullName(Checker)) << "\", ";
302 OS << '\"';
303 OS.write_escaped(getCheckerFullName(Dependency)) << '\"';
304 OS << ")\n";
305 }
306 }
307 OS << "\n"
308 "#endif // GET_CHECKER_WEAK_DEPENDENCIES\n";
309
310 // Emit a package option.
311 //
312 // CHECKER_OPTION(OPTIONTYPE, CHECKERNAME, OPTIONNAME, DESCRIPTION, DEFAULT)
313 // - OPTIONTYPE: Type of the option, whether it's integer or boolean etc.
314 // This is important for validating user input. Note that
315 // it's a string, rather than an actual type: since we can
316 // load checkers runtime, we can't use template hackery for
317 // sorting this out compile-time.
318 // - CHECKERNAME: Name of the package.
319 // - OPTIONNAME: Name of the option.
320 // - DESCRIPTION
321 // - DEFAULT: The default value for this option.
322 //
323 // The full option can be specified in the command like like this:
324 // -analyzer-config CHECKERNAME:OPTIONNAME=VALUE
325 OS << "\n"
326 "#ifdef GET_CHECKER_OPTIONS\n";
327 for (const Record *Checker : checkers) {
328
329 if (Checker->isValueUnset("CheckerOptions"))
330 continue;
331
332 std::vector<Record *> CheckerOptions = Checker
333 ->getValueAsListOfDefs("CheckerOptions");
334 for (Record *CheckerOpt : CheckerOptions) {
335 OS << "CHECKER_OPTION(";
336 printOption(OS, getCheckerFullName(Checker), *CheckerOpt);
337 OS << ")\n";
338 }
339 }
340 OS << "#endif // GET_CHECKER_OPTIONS\n"
341 "\n";
342 }
343