1 //===-- ClangSACheckersEmitter.cpp - Generate SA checkers tables ----------===//
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
7 //===----------------------------------------------------------------------===//
9 // This tablegen backend emits Clang Static Analyzer checkers tables.
11 //===----------------------------------------------------------------------===//
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"
22 //===----------------------------------------------------------------------===//
23 // Static Analyzer Checkers Tables generation
24 //===----------------------------------------------------------------------===//
26 static std::string
getPackageFullName(const Record
*R
, StringRef Sep
= ".");
28 static std::string
getParentPackageFullName(const Record
*R
,
29 StringRef Sep
= ".") {
30 if (const DefInit
*DI
= dyn_cast
<DefInit
>(R
->getValueInit("ParentPackage")))
31 return getPackageFullName(DI
->getDef(), Sep
);
35 static std::string
getPackageFullName(const Record
*R
, StringRef Sep
) {
36 std::string name
= getParentPackageFullName(R
, Sep
);
39 assert(!R
->getValueAsString("PackageName").empty());
40 name
+= R
->getValueAsString("PackageName");
44 static std::string
getCheckerFullName(const Record
*R
, StringRef Sep
= ".") {
45 std::string name
= getParentPackageFullName(R
, Sep
);
48 assert(!R
->getValueAsString("CheckerName").empty());
49 name
+= R
->getValueAsString("CheckerName");
53 static StringRef
getStringValue(const Record
&R
, StringRef field
) {
54 if (const StringInit
*SI
= dyn_cast
<StringInit
>(R
.getValueInit(field
)))
55 return SI
->getValue();
59 // Calculates the integer value representing the BitsInit object
60 static inline uint64_t getValueFromBitsInit(const BitsInit
*B
, const Record
&R
) {
61 assert(B
->getNumBits() <= sizeof(uint64_t) * 8 && "BitInits' too long!");
64 for (unsigned i
= 0, e
= B
->getNumBits(); i
!= e
; ++i
) {
65 const auto *Bit
= dyn_cast
<BitInit
>(B
->getBit(i
));
67 Value
|= uint64_t(Bit
->getValue()) << i
;
69 PrintFatalError(R
.getLoc(),
70 "missing Documentation for " + getCheckerFullName(&R
));
75 static std::string
getCheckerDocs(const Record
&R
) {
76 const BitsInit
*BI
= R
.getValueAsBitsInit("Documentation");
78 PrintFatalError(R
.getLoc(), "missing Documentation<...> member for " +
79 getCheckerFullName(&R
));
81 // Ignore 'Documentation<NotDocumented>' checkers.
82 if (getValueFromBitsInit(BI
, R
) == 0)
85 std::string CheckerFullName
= StringRef(getCheckerFullName(&R
, "-")).lower();
86 return (Twine("https://clang.llvm.org/docs/analyzer/checkers.html#") +
91 /// Retrieves the type from a CmdOptionTypeEnum typed Record object. Note that
92 /// the class itself has to be modified for adding a new option type in
94 static StringRef
getCheckerOptionType(const Record
&R
) {
95 if (const BitsInit
*BI
= R
.getValueAsBitsInit("Type")) {
96 switch(getValueFromBitsInit(BI
, R
)) {
105 PrintFatalError(R
.getLoc(),
106 "unable to parse command line option type for "
107 + getCheckerFullName(&R
));
111 static StringRef
getDevelopmentStage(const Record
&R
) {
112 if (const BitsInit
*BI
= R
.getValueAsBitsInit("DevelopmentStage")) {
113 switch(getValueFromBitsInit(BI
, R
)) {
121 PrintFatalError(R
.getLoc(),
122 "unable to parse command line option type for "
123 + getCheckerFullName(&R
));
127 static bool isHidden(const Record
*R
) {
128 if (R
->getValueAsBit("Hidden"))
131 // Not declared as hidden, check the parent package if it is hidden.
132 if (const DefInit
*DI
= dyn_cast
<DefInit
>(R
->getValueInit("ParentPackage")))
133 return isHidden(DI
->getDef());
138 static void printChecker(raw_ostream
&OS
, const Record
&R
) {
139 OS
<< "CHECKER(" << "\"";
140 OS
.write_escaped(getCheckerFullName(&R
)) << "\", ";
141 OS
<< R
.getName() << ", ";
143 OS
.write_escaped(getStringValue(R
, "HelpText")) << "\", ";
145 OS
.write_escaped(getCheckerDocs(R
));
156 static void printOption(raw_ostream
&OS
, StringRef FullName
, const Record
&R
) {
158 OS
.write_escaped(getCheckerOptionType(R
)) << "\", \"";
159 OS
.write_escaped(FullName
) << "\", ";
160 OS
<< '\"' << getStringValue(R
, "CmdFlag") << "\", ";
162 OS
.write_escaped(getStringValue(R
, "Desc")) << "\", ";
164 OS
.write_escaped(getStringValue(R
, "DefaultVal")) << "\", ";
166 OS
<< getDevelopmentStage(R
) << "\", ";
168 if (!R
.getValueAsBit("Hidden"))
174 void clang::EmitClangSACheckers(const RecordKeeper
&Records
, raw_ostream
&OS
) {
175 ArrayRef
<const Record
*> checkers
=
176 Records
.getAllDerivedDefinitions("Checker");
177 ArrayRef
<const Record
*> packages
=
178 Records
.getAllDerivedDefinitions("Package");
180 OS
<< "// This file is automatically generated. Do not edit this file by "
185 // PACKAGE(PACKAGENAME)
186 // - PACKAGENAME: The name of the package.
188 "#ifdef GET_PACKAGES\n";
190 StringMap
<const Record
*> sortedPackages
;
191 for (const Record
*Package
: packages
)
192 sortedPackages
[getPackageFullName(Package
)] = Package
;
194 for (const auto &[_
, R
] : sortedPackages
) {
195 OS
<< "PACKAGE(" << "\"";
196 OS
.write_escaped(getPackageFullName(R
)) << '\"';
200 OS
<< "#endif // GET_PACKAGES\n"
203 // Emit a package option.
205 // PACKAGE_OPTION(OPTIONTYPE, PACKAGENAME, OPTIONNAME, DESCRIPTION, DEFAULT)
206 // - OPTIONTYPE: Type of the option, whether it's integer or boolean etc.
207 // This is important for validating user input. Note that
208 // it's a string, rather than an actual type: since we can
209 // load checkers runtime, we can't use template hackery for
210 // sorting this out compile-time.
211 // - PACKAGENAME: Name of the package.
212 // - OPTIONNAME: Name of the option.
214 // - DEFAULT: The default value for this option.
216 // The full option can be specified in the command like this:
217 // -analyzer-config PACKAGENAME:OPTIONNAME=VALUE
219 "#ifdef GET_PACKAGE_OPTIONS\n";
220 for (const Record
*Package
: packages
) {
221 if (Package
->isValueUnset("PackageOptions"))
224 for (const Record
*PackageOpt
:
225 Package
->getValueAsListOfDefs("PackageOptions")) {
226 OS
<< "PACKAGE_OPTION(";
227 printOption(OS
, getPackageFullName(Package
), *PackageOpt
);
231 OS
<< "#endif // GET_PACKAGE_OPTIONS\n"
236 // CHECKER(FULLNAME, CLASS, HELPTEXT)
237 // - FULLNAME: The full name of the checker, including packages, e.g.:
238 // alpha.cplusplus.UninitializedObject
239 // - CLASS: The name of the checker, with "Checker" appended, e.g.:
240 // UninitializedObjectChecker
241 // - HELPTEXT: The description of the checker.
243 "#ifdef GET_CHECKERS\n"
245 for (const Record
*checker
: checkers
)
246 printChecker(OS
, *checker
);
249 "#endif // GET_CHECKERS\n"
252 // Emit dependencies.
254 // CHECKER_DEPENDENCY(FULLNAME, DEPENDENCY)
255 // - FULLNAME: The full name of the checker that depends on another checker.
256 // - DEPENDENCY: The full name of the checker FULLNAME depends on.
258 "#ifdef GET_CHECKER_DEPENDENCIES\n";
259 for (const Record
*Checker
: checkers
) {
260 if (Checker
->isValueUnset("Dependencies"))
263 for (const Record
*Dependency
:
264 Checker
->getValueAsListOfDefs("Dependencies")) {
265 OS
<< "CHECKER_DEPENDENCY(";
267 OS
.write_escaped(getCheckerFullName(Checker
)) << "\", ";
269 OS
.write_escaped(getCheckerFullName(Dependency
)) << '\"';
274 "#endif // GET_CHECKER_DEPENDENCIES\n";
276 // Emit weak dependencies.
278 // CHECKER_DEPENDENCY(FULLNAME, DEPENDENCY)
279 // - FULLNAME: The full name of the checker that is supposed to be
281 // - DEPENDENCY: The full name of the checker FULLNAME weak depends on.
283 "#ifdef GET_CHECKER_WEAK_DEPENDENCIES\n";
284 for (const Record
*Checker
: checkers
) {
285 if (Checker
->isValueUnset("WeakDependencies"))
288 for (const Record
*Dependency
:
289 Checker
->getValueAsListOfDefs("WeakDependencies")) {
290 OS
<< "CHECKER_WEAK_DEPENDENCY(";
292 OS
.write_escaped(getCheckerFullName(Checker
)) << "\", ";
294 OS
.write_escaped(getCheckerFullName(Dependency
)) << '\"';
299 "#endif // GET_CHECKER_WEAK_DEPENDENCIES\n";
301 // Emit a package option.
303 // CHECKER_OPTION(OPTIONTYPE, CHECKERNAME, OPTIONNAME, DESCRIPTION, DEFAULT)
304 // - OPTIONTYPE: Type of the option, whether it's integer or boolean etc.
305 // This is important for validating user input. Note that
306 // it's a string, rather than an actual type: since we can
307 // load checkers runtime, we can't use template hackery for
308 // sorting this out compile-time.
309 // - CHECKERNAME: Name of the package.
310 // - OPTIONNAME: Name of the option.
312 // - DEFAULT: The default value for this option.
314 // The full option can be specified in the command like this:
315 // -analyzer-config CHECKERNAME:OPTIONNAME=VALUE
317 "#ifdef GET_CHECKER_OPTIONS\n";
318 for (const Record
*Checker
: checkers
) {
319 if (Checker
->isValueUnset("CheckerOptions"))
322 for (const Record
*CheckerOpt
:
323 Checker
->getValueAsListOfDefs("CheckerOptions")) {
324 OS
<< "CHECKER_OPTION(";
325 printOption(OS
, getCheckerFullName(Checker
), *CheckerOpt
);
329 OS
<< "#endif // GET_CHECKER_OPTIONS\n"