blob: 7dd0895b76d451997c19097dd51838a188d81990 [file] [log] [blame]
Peter Collingbournebee583f2011-10-06 13:03:08 +00001//=- ClangSACheckersEmitter.cpp - Generate Clang SA checkers tables -*- C++ -*-
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Peter Collingbournebee583f2011-10-06 13:03:08 +00006//
7//===----------------------------------------------------------------------===//
8//
9// This tablegen backend emits Clang Static Analyzer checkers tables.
10//
11//===----------------------------------------------------------------------===//
12
Kristof Umann35fc356f2018-11-12 17:49:51 +000013#include "llvm/ADT/StringMap.h"
Joerg Sonnenberger691a16b2012-10-25 16:37:08 +000014#include "llvm/TableGen/Error.h"
Jakob Stoklund Olesen995e0e12012-06-13 05:12:41 +000015#include "llvm/TableGen/Record.h"
16#include "llvm/TableGen/TableGenBackend.h"
Peter Collingbournebee583f2011-10-06 13:03:08 +000017#include <map>
18#include <string>
Kristof Umann35fc356f2018-11-12 17:49:51 +000019
Peter Collingbournebee583f2011-10-06 13:03:08 +000020using namespace llvm;
21
22//===----------------------------------------------------------------------===//
23// Static Analyzer Checkers Tables generation
24//===----------------------------------------------------------------------===//
25
Peter Collingbournebee583f2011-10-06 13:03:08 +000026static std::string getPackageFullName(const Record *R);
27
28static std::string getParentPackageFullName(const Record *R) {
29 std::string name;
Sean Silva1c4aaa82012-10-10 20:25:43 +000030 if (DefInit *DI = dyn_cast<DefInit>(R->getValueInit("ParentPackage")))
Peter Collingbournebee583f2011-10-06 13:03:08 +000031 name = getPackageFullName(DI->getDef());
32 return name;
33}
34
35static std::string getPackageFullName(const Record *R) {
36 std::string name = getParentPackageFullName(R);
Kristof Umann35fc356f2018-11-12 17:49:51 +000037 if (!name.empty())
38 name += ".";
39 assert(!R->getValueAsString("PackageName").empty());
Craig Topper00648582017-05-31 19:01:22 +000040 name += R->getValueAsString("PackageName");
41 return name;
Peter Collingbournebee583f2011-10-06 13:03:08 +000042}
43
44static std::string getCheckerFullName(const Record *R) {
45 std::string name = getParentPackageFullName(R);
Kristof Umann35fc356f2018-11-12 17:49:51 +000046 if (!name.empty())
47 name += ".";
48 assert(!R->getValueAsString("CheckerName").empty());
49 name += R->getValueAsString("CheckerName");
Peter Collingbournebee583f2011-10-06 13:03:08 +000050 return name;
51}
52
53static std::string getStringValue(const Record &R, StringRef field) {
Sean Silva1c4aaa82012-10-10 20:25:43 +000054 if (StringInit *SI = dyn_cast<StringInit>(R.getValueInit(field)))
Peter Collingbournebee583f2011-10-06 13:03:08 +000055 return SI->getValue();
56 return std::string();
57}
58
Aaron Ballman2f234cb2018-12-20 20:20:20 +000059// Calculates the integer value representing the BitsInit object
Aaron Ballmanc682c192018-12-22 15:31:57 +000060static inline uint64_t getValueFromBitsInit(const BitsInit *B, const Record &R) {
Aaron Ballman2f234cb2018-12-20 20:20:20 +000061 assert(B->getNumBits() <= sizeof(uint64_t) * 8 && "BitInits' too long!");
62
63 uint64_t Value = 0;
64 for (unsigned i = 0, e = B->getNumBits(); i != e; ++i) {
Aaron Ballman88b36702018-12-21 19:16:38 +000065 const auto *Bit = dyn_cast<BitInit>(B->getBit(i));
66 if (Bit)
67 Value |= uint64_t(Bit->getValue()) << i;
68 else
Aaron Ballmanc682c192018-12-22 15:31:57 +000069 PrintFatalError(R.getLoc(),
70 "missing Documentation for " + getCheckerFullName(&R));
Aaron Ballman2f234cb2018-12-20 20:20:20 +000071 }
72 return Value;
73}
74
75static std::string getCheckerDocs(const Record &R) {
76 StringRef LandingPage;
77 if (BitsInit *BI = R.getValueAsBitsInit("Documentation")) {
Aaron Ballmanc682c192018-12-22 15:31:57 +000078 uint64_t V = getValueFromBitsInit(BI, R);
Aaron Ballman2f234cb2018-12-20 20:20:20 +000079 if (V == 1)
80 LandingPage = "available_checks.html";
81 else if (V == 2)
82 LandingPage = "alpha_checks.html";
83 }
84
85 if (LandingPage.empty())
86 return "";
87
88 return (llvm::Twine("https://clang-analyzer.llvm.org/") + LandingPage + "#" +
89 getCheckerFullName(&R))
90 .str();
91}
92
Kristof Umannb4788b22019-04-19 12:32:10 +000093/// Retrieves the type from a CmdOptionTypeEnum typed Record object. Note that
94/// the class itself has to be modified for adding a new option type in
95/// CheckerBase.td.
96static std::string getCheckerOptionType(const Record &R) {
97 if (BitsInit *BI = R.getValueAsBitsInit("Type")) {
98 switch(getValueFromBitsInit(BI, R)) {
99 case 0:
100 return "int";
101 case 1:
102 return "string";
103 case 2:
104 return "bool";
105 }
106 }
107 PrintFatalError(R.getLoc(),
108 "unable to parse command line option type for "
109 + getCheckerFullName(&R));
110 return "";
111}
112
Kristof Umannac95c862019-05-23 22:52:09 +0000113static std::string getDevelopmentStage(const Record &R) {
114 if (BitsInit *BI = R.getValueAsBitsInit("DevelopmentStage")) {
115 switch(getValueFromBitsInit(BI, R)) {
116 case 0:
117 return "alpha";
118 case 1:
119 return "released";
120 }
121 }
122
123 PrintFatalError(R.getLoc(),
124 "unable to parse command line option type for "
125 + getCheckerFullName(&R));
126 return "";
127}
128
Kristof Umann9f7fc982019-05-01 19:56:47 +0000129static bool isHidden(const Record *R) {
130 if (R->getValueAsBit("Hidden"))
131 return true;
Kristof Umann7e55ed82019-05-23 22:07:16 +0000132
Kristof Umann9f7fc982019-05-01 19:56:47 +0000133 // Not declared as hidden, check the parent package if it is hidden.
134 if (DefInit *DI = dyn_cast<DefInit>(R->getValueInit("ParentPackage")))
135 return isHidden(DI->getDef());
136
137 return false;
138}
139
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000140static void printChecker(llvm::raw_ostream &OS, const Record &R) {
Kristof Umann7e55ed82019-05-23 22:07:16 +0000141 OS << "CHECKER(" << "\"";
142 OS.write_escaped(getCheckerFullName(&R)) << "\", ";
143 OS << R.getName() << ", ";
144 OS << "\"";
145 OS.write_escaped(getStringValue(R, "HelpText")) << "\", ";
146 OS << "\"";
147 OS.write_escaped(getCheckerDocs(R));
148 OS << "\", ";
Kristof Umann9f7fc982019-05-01 19:56:47 +0000149
Kristof Umann7e55ed82019-05-23 22:07:16 +0000150 if (!isHidden(&R))
151 OS << "false";
152 else
153 OS << "true";
Kristof Umann9f7fc982019-05-01 19:56:47 +0000154
Kristof Umann7e55ed82019-05-23 22:07:16 +0000155 OS << ")\n";
156}
157
158static void printOption(llvm::raw_ostream &OS, StringRef FullName,
159 const Record &R) {
160 OS << "\"";
161 OS.write_escaped(getCheckerOptionType(R)) << "\", \"";
162 OS.write_escaped(FullName) << "\", ";
163 OS << '\"' << getStringValue(R, "CmdFlag") << "\", ";
164 OS << '\"';
165 OS.write_escaped(getStringValue(R, "Desc")) << "\", ";
166 OS << '\"';
167 OS.write_escaped(getStringValue(R, "DefaultVal")) << "\", ";
Kristof Umannac95c862019-05-23 22:52:09 +0000168 OS << '\"';
169 OS << getDevelopmentStage(R) << "\", ";
Kristof Umann7e55ed82019-05-23 22:07:16 +0000170
171 if (!R.getValueAsBit("Hidden"))
172 OS << "false";
173 else
174 OS << "true";
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000175}
176
Jakob Stoklund Olesen995e0e12012-06-13 05:12:41 +0000177namespace clang {
178void EmitClangSACheckers(RecordKeeper &Records, raw_ostream &OS) {
Peter Collingbournebee583f2011-10-06 13:03:08 +0000179 std::vector<Record*> checkers = Records.getAllDerivedDefinitions("Checker");
Peter Collingbournebee583f2011-10-06 13:03:08 +0000180 std::vector<Record*> packages = Records.getAllDerivedDefinitions("Package");
Peter Collingbournebee583f2011-10-06 13:03:08 +0000181
Kristof Umann35fc356f2018-11-12 17:49:51 +0000182 using SortedRecords = llvm::StringMap<const Record *>;
Peter Collingbournebee583f2011-10-06 13:03:08 +0000183
Aaron Ballman2f234cb2018-12-20 20:20:20 +0000184 OS << "// This file is automatically generated. Do not edit this file by "
185 "hand.\n";
186
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000187 // Emit packages.
188 //
189 // PACKAGE(PACKAGENAME)
190 // - PACKAGENAME: The name of the package.
191 OS << "\n"
192 "#ifdef GET_PACKAGES\n";
Peter Collingbournebee583f2011-10-06 13:03:08 +0000193 {
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(" << "\"";
Kristof Umann35fc356f2018-11-12 17:49:51 +0000203 OS.write_escaped(getPackageFullName(&R)) << '\"';
Peter Collingbournebee583f2011-10-06 13:03:08 +0000204 OS << ")\n";
205 }
206 }
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000207 OS << "#endif // GET_PACKAGES\n"
208 "\n";
Peter Collingbournebee583f2011-10-06 13:03:08 +0000209
Kristof Umannb4788b22019-04-19 12:32:10 +0000210 // 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) {
Kristof Umann7e55ed82019-05-23 22:07:16 +0000235 OS << "PACKAGE_OPTION(";
236 printOption(OS, getPackageFullName(Package), *PackageOpt);
Kristof Umannb4788b22019-04-19 12:32:10 +0000237 OS << ")\n";
238 }
239 }
240 OS << "#endif // GET_PACKAGE_OPTIONS\n"
241 "\n";
242
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000243 // 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);
Peter Collingbournebee583f2011-10-06 13:03:08 +0000256 }
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000257 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";
Kristof Umannb4788b22019-04-19 12:32:10 +0000268 for (const Record *Checker : checkers) {
269 if (Checker->isValueUnset("Dependencies"))
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000270 continue;
271
272 for (const Record *Dependency :
Kristof Umannb4788b22019-04-19 12:32:10 +0000273 Checker->getValueAsListOfDefs("Dependencies")) {
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000274 OS << "CHECKER_DEPENDENCY(";
275 OS << '\"';
Kristof Umannb4788b22019-04-19 12:32:10 +0000276 OS.write_escaped(getCheckerFullName(Checker)) << "\", ";
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000277 OS << '\"';
278 OS.write_escaped(getCheckerFullName(Dependency)) << '\"';
279 OS << ")\n";
280 }
281 }
282 OS << "\n"
283 "#endif // GET_CHECKER_DEPENDENCIES\n";
Kristof Umannb4788b22019-04-19 12:32:10 +0000284
285 // Emit a package option.
286 //
287 // CHECKER_OPTION(OPTIONTYPE, CHECKERNAME, OPTIONNAME, DESCRIPTION, DEFAULT)
288 // - OPTIONTYPE: Type of the option, whether it's integer or boolean etc.
289 // This is important for validating user input. Note that
290 // it's a string, rather than an actual type: since we can
291 // load checkers runtime, we can't use template hackery for
292 // sorting this out compile-time.
293 // - CHECKERNAME: Name of the package.
294 // - OPTIONNAME: Name of the option.
295 // - DESCRIPTION
296 // - DEFAULT: The default value for this option.
297 //
298 // The full option can be specified in the command like like this:
299 // -analyzer-config CHECKERNAME:OPTIONNAME=VALUE
300 OS << "\n"
301 "#ifdef GET_CHECKER_OPTIONS\n";
302 for (const Record *Checker : checkers) {
303
304 if (Checker->isValueUnset("CheckerOptions"))
305 continue;
306
307 std::vector<Record *> CheckerOptions = Checker
308 ->getValueAsListOfDefs("CheckerOptions");
309 for (Record *CheckerOpt : CheckerOptions) {
Kristof Umann7e55ed82019-05-23 22:07:16 +0000310 OS << "CHECKER_OPTION(";
311 printOption(OS, getCheckerFullName(Checker), *CheckerOpt);
312 OS << ")\n";
Kristof Umannb4788b22019-04-19 12:32:10 +0000313 }
314 }
315 OS << "#endif // GET_CHECKER_OPTIONS\n"
316 "\n";
Peter Collingbournebee583f2011-10-06 13:03:08 +0000317}
Jakob Stoklund Olesen995e0e12012-06-13 05:12:41 +0000318} // end namespace clang