[ELF] Reorder SectionBase/InputSectionBase members
[llvm-project.git] / clang / utils / TableGen / ClangSACheckersEmitter.cpp
blobdcb3cac3850beae53b476c764cb8ebecda01c639
1 //===-- ClangSACheckersEmitter.cpp - Generate SA checkers tables ----------===//
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.
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"
18 #include <string>
20 using namespace llvm;
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);
32 return "";
35 static std::string getPackageFullName(const Record *R, StringRef Sep) {
36 std::string name = getParentPackageFullName(R, Sep);
37 if (!name.empty())
38 name += Sep;
39 assert(!R->getValueAsString("PackageName").empty());
40 name += R->getValueAsString("PackageName");
41 return name;
44 static std::string getCheckerFullName(const Record *R, StringRef Sep = ".") {
45 std::string name = getParentPackageFullName(R, Sep);
46 if (!name.empty())
47 name += Sep;
48 assert(!R->getValueAsString("CheckerName").empty());
49 name += R->getValueAsString("CheckerName");
50 return name;
53 static StringRef getStringValue(const Record &R, StringRef field) {
54 if (const StringInit *SI = dyn_cast<StringInit>(R.getValueInit(field)))
55 return SI->getValue();
56 return "";
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!");
63 uint64_t Value = 0;
64 for (unsigned i = 0, e = B->getNumBits(); i != e; ++i) {
65 const auto *Bit = dyn_cast<BitInit>(B->getBit(i));
66 if (Bit)
67 Value |= uint64_t(Bit->getValue()) << i;
68 else
69 PrintFatalError(R.getLoc(),
70 "missing Documentation for " + getCheckerFullName(&R));
72 return Value;
75 static std::string getCheckerDocs(const Record &R) {
76 const BitsInit *BI = R.getValueAsBitsInit("Documentation");
77 if (!BI)
78 PrintFatalError(R.getLoc(), "missing Documentation<...> member for " +
79 getCheckerFullName(&R));
81 // Ignore 'Documentation<NotDocumented>' checkers.
82 if (getValueFromBitsInit(BI, R) == 0)
83 return "";
85 std::string CheckerFullName = StringRef(getCheckerFullName(&R, "-")).lower();
86 return (Twine("https://clang.llvm.org/docs/analyzer/checkers.html#") +
87 CheckerFullName)
88 .str();
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
93 /// CheckerBase.td.
94 static StringRef getCheckerOptionType(const Record &R) {
95 if (const BitsInit *BI = R.getValueAsBitsInit("Type")) {
96 switch(getValueFromBitsInit(BI, R)) {
97 case 0:
98 return "int";
99 case 1:
100 return "string";
101 case 2:
102 return "bool";
105 PrintFatalError(R.getLoc(),
106 "unable to parse command line option type for "
107 + getCheckerFullName(&R));
108 return "";
111 static StringRef getDevelopmentStage(const Record &R) {
112 if (const BitsInit *BI = R.getValueAsBitsInit("DevelopmentStage")) {
113 switch(getValueFromBitsInit(BI, R)) {
114 case 0:
115 return "alpha";
116 case 1:
117 return "released";
121 PrintFatalError(R.getLoc(),
122 "unable to parse command line option type for "
123 + getCheckerFullName(&R));
124 return "";
127 static bool isHidden(const Record *R) {
128 if (R->getValueAsBit("Hidden"))
129 return true;
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());
135 return false;
138 static void printChecker(raw_ostream &OS, const Record &R) {
139 OS << "CHECKER(" << "\"";
140 OS.write_escaped(getCheckerFullName(&R)) << "\", ";
141 OS << R.getName() << ", ";
142 OS << "\"";
143 OS.write_escaped(getStringValue(R, "HelpText")) << "\", ";
144 OS << "\"";
145 OS.write_escaped(getCheckerDocs(R));
146 OS << "\", ";
148 if (!isHidden(&R))
149 OS << "false";
150 else
151 OS << "true";
153 OS << ")\n";
156 static void printOption(raw_ostream &OS, StringRef FullName, const Record &R) {
157 OS << "\"";
158 OS.write_escaped(getCheckerOptionType(R)) << "\", \"";
159 OS.write_escaped(FullName) << "\", ";
160 OS << '\"' << getStringValue(R, "CmdFlag") << "\", ";
161 OS << '\"';
162 OS.write_escaped(getStringValue(R, "Desc")) << "\", ";
163 OS << '\"';
164 OS.write_escaped(getStringValue(R, "DefaultVal")) << "\", ";
165 OS << '\"';
166 OS << getDevelopmentStage(R) << "\", ";
168 if (!R.getValueAsBit("Hidden"))
169 OS << "false";
170 else
171 OS << "true";
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 "
181 "hand.\n";
183 // Emit packages.
185 // PACKAGE(PACKAGENAME)
186 // - PACKAGENAME: The name of the package.
187 OS << "\n"
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)) << '\"';
197 OS << ")\n";
200 OS << "#endif // GET_PACKAGES\n"
201 "\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.
213 // - DESCRIPTION
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
218 OS << "\n"
219 "#ifdef GET_PACKAGE_OPTIONS\n";
220 for (const Record *Package : packages) {
221 if (Package->isValueUnset("PackageOptions"))
222 continue;
224 for (const Record *PackageOpt :
225 Package->getValueAsListOfDefs("PackageOptions")) {
226 OS << "PACKAGE_OPTION(";
227 printOption(OS, getPackageFullName(Package), *PackageOpt);
228 OS << ")\n";
231 OS << "#endif // GET_PACKAGE_OPTIONS\n"
232 "\n";
234 // Emit checkers.
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.
242 OS << "\n"
243 "#ifdef GET_CHECKERS\n"
244 "\n";
245 for (const Record *checker : checkers)
246 printChecker(OS, *checker);
248 OS << "\n"
249 "#endif // GET_CHECKERS\n"
250 "\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.
257 OS << "\n"
258 "#ifdef GET_CHECKER_DEPENDENCIES\n";
259 for (const Record *Checker : checkers) {
260 if (Checker->isValueUnset("Dependencies"))
261 continue;
263 for (const Record *Dependency :
264 Checker->getValueAsListOfDefs("Dependencies")) {
265 OS << "CHECKER_DEPENDENCY(";
266 OS << '\"';
267 OS.write_escaped(getCheckerFullName(Checker)) << "\", ";
268 OS << '\"';
269 OS.write_escaped(getCheckerFullName(Dependency)) << '\"';
270 OS << ")\n";
273 OS << "\n"
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
280 // registered first.
281 // - DEPENDENCY: The full name of the checker FULLNAME weak depends on.
282 OS << "\n"
283 "#ifdef GET_CHECKER_WEAK_DEPENDENCIES\n";
284 for (const Record *Checker : checkers) {
285 if (Checker->isValueUnset("WeakDependencies"))
286 continue;
288 for (const Record *Dependency :
289 Checker->getValueAsListOfDefs("WeakDependencies")) {
290 OS << "CHECKER_WEAK_DEPENDENCY(";
291 OS << '\"';
292 OS.write_escaped(getCheckerFullName(Checker)) << "\", ";
293 OS << '\"';
294 OS.write_escaped(getCheckerFullName(Dependency)) << '\"';
295 OS << ")\n";
298 OS << "\n"
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.
311 // - DESCRIPTION
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
316 OS << "\n"
317 "#ifdef GET_CHECKER_OPTIONS\n";
318 for (const Record *Checker : checkers) {
319 if (Checker->isValueUnset("CheckerOptions"))
320 continue;
322 for (const Record *CheckerOpt :
323 Checker->getValueAsListOfDefs("CheckerOptions")) {
324 OS << "CHECKER_OPTION(";
325 printOption(OS, getCheckerFullName(Checker), *CheckerOpt);
326 OS << ")\n";
329 OS << "#endif // GET_CHECKER_OPTIONS\n"
330 "\n";