Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/utils/TableGen/ClangSACheckersEmitter.cpp
35231 views
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, StringRef Sep = ".");
28
29
static std::string getParentPackageFullName(const Record *R,
30
StringRef Sep = ".") {
31
std::string name;
32
if (DefInit *DI = dyn_cast<DefInit>(R->getValueInit("ParentPackage")))
33
name = getPackageFullName(DI->getDef(), Sep);
34
return name;
35
}
36
37
static std::string getPackageFullName(const Record *R, StringRef Sep) {
38
std::string name = getParentPackageFullName(R, Sep);
39
if (!name.empty())
40
name += Sep;
41
assert(!R->getValueAsString("PackageName").empty());
42
name += R->getValueAsString("PackageName");
43
return name;
44
}
45
46
static std::string getCheckerFullName(const Record *R, StringRef Sep = ".") {
47
std::string name = getParentPackageFullName(R, Sep);
48
if (!name.empty())
49
name += Sep;
50
assert(!R->getValueAsString("CheckerName").empty());
51
name += R->getValueAsString("CheckerName");
52
return name;
53
}
54
55
static std::string getStringValue(const Record &R, StringRef field) {
56
if (StringInit *SI = dyn_cast<StringInit>(R.getValueInit(field)))
57
return std::string(SI->getValue());
58
return std::string();
59
}
60
61
// Calculates the integer value representing the BitsInit object
62
static inline uint64_t getValueFromBitsInit(const BitsInit *B, const Record &R) {
63
assert(B->getNumBits() <= sizeof(uint64_t) * 8 && "BitInits' too long!");
64
65
uint64_t Value = 0;
66
for (unsigned i = 0, e = B->getNumBits(); i != e; ++i) {
67
const auto *Bit = dyn_cast<BitInit>(B->getBit(i));
68
if (Bit)
69
Value |= uint64_t(Bit->getValue()) << i;
70
else
71
PrintFatalError(R.getLoc(),
72
"missing Documentation for " + getCheckerFullName(&R));
73
}
74
return Value;
75
}
76
77
static std::string getCheckerDocs(const Record &R) {
78
const BitsInit *BI = R.getValueAsBitsInit("Documentation");
79
if (!BI)
80
PrintFatalError(R.getLoc(), "missing Documentation<...> member for " +
81
getCheckerFullName(&R));
82
83
// Ignore 'Documentation<NotDocumented>' checkers.
84
if (getValueFromBitsInit(BI, R) == 0)
85
return "";
86
87
std::string CheckerFullName = StringRef(getCheckerFullName(&R, "-")).lower();
88
return (llvm::Twine("https://clang.llvm.org/docs/analyzer/checkers.html#") +
89
CheckerFullName)
90
.str();
91
}
92
93
/// 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.
96
static 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
113
static 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
129
static bool isHidden(const Record *R) {
130
if (R->getValueAsBit("Hidden"))
131
return true;
132
133
// 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
140
static void printChecker(llvm::raw_ostream &OS, const Record &R) {
141
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 << "\", ";
149
150
if (!isHidden(&R))
151
OS << "false";
152
else
153
OS << "true";
154
155
OS << ")\n";
156
}
157
158
static 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")) << "\", ";
168
OS << '\"';
169
OS << getDevelopmentStage(R) << "\", ";
170
171
if (!R.getValueAsBit("Hidden"))
172
OS << "false";
173
else
174
OS << "true";
175
}
176
177
void clang::EmitClangSACheckers(RecordKeeper &Records, raw_ostream &OS) {
178
std::vector<Record*> checkers = Records.getAllDerivedDefinitions("Checker");
179
std::vector<Record*> packages = Records.getAllDerivedDefinitions("Package");
180
181
using SortedRecords = llvm::StringMap<const Record *>;
182
183
OS << "// This file is automatically generated. Do not edit this file by "
184
"hand.\n";
185
186
// Emit packages.
187
//
188
// PACKAGE(PACKAGENAME)
189
// - PACKAGENAME: The name of the package.
190
OS << "\n"
191
"#ifdef GET_PACKAGES\n";
192
{
193
SortedRecords sortedPackages;
194
for (unsigned i = 0, e = packages.size(); i != e; ++i)
195
sortedPackages[getPackageFullName(packages[i])] = packages[i];
196
197
for (SortedRecords::iterator
198
I = sortedPackages.begin(), E = sortedPackages.end(); I != E; ++I) {
199
const Record &R = *I->second;
200
201
OS << "PACKAGE(" << "\"";
202
OS.write_escaped(getPackageFullName(&R)) << '\"';
203
OS << ")\n";
204
}
205
}
206
OS << "#endif // GET_PACKAGES\n"
207
"\n";
208
209
// Emit a package option.
210
//
211
// PACKAGE_OPTION(OPTIONTYPE, PACKAGENAME, OPTIONNAME, DESCRIPTION, DEFAULT)
212
// - OPTIONTYPE: Type of the option, whether it's integer or boolean etc.
213
// This is important for validating user input. Note that
214
// it's a string, rather than an actual type: since we can
215
// load checkers runtime, we can't use template hackery for
216
// sorting this out compile-time.
217
// - PACKAGENAME: Name of the package.
218
// - OPTIONNAME: Name of the option.
219
// - DESCRIPTION
220
// - DEFAULT: The default value for this option.
221
//
222
// The full option can be specified in the command like this:
223
// -analyzer-config PACKAGENAME:OPTIONNAME=VALUE
224
OS << "\n"
225
"#ifdef GET_PACKAGE_OPTIONS\n";
226
for (const Record *Package : packages) {
227
228
if (Package->isValueUnset("PackageOptions"))
229
continue;
230
231
std::vector<Record *> PackageOptions = Package
232
->getValueAsListOfDefs("PackageOptions");
233
for (Record *PackageOpt : PackageOptions) {
234
OS << "PACKAGE_OPTION(";
235
printOption(OS, getPackageFullName(Package), *PackageOpt);
236
OS << ")\n";
237
}
238
}
239
OS << "#endif // GET_PACKAGE_OPTIONS\n"
240
"\n";
241
242
// Emit checkers.
243
//
244
// CHECKER(FULLNAME, CLASS, HELPTEXT)
245
// - FULLNAME: The full name of the checker, including packages, e.g.:
246
// alpha.cplusplus.UninitializedObject
247
// - CLASS: The name of the checker, with "Checker" appended, e.g.:
248
// UninitializedObjectChecker
249
// - HELPTEXT: The description of the checker.
250
OS << "\n"
251
"#ifdef GET_CHECKERS\n"
252
"\n";
253
for (const Record *checker : checkers) {
254
printChecker(OS, *checker);
255
}
256
OS << "\n"
257
"#endif // GET_CHECKERS\n"
258
"\n";
259
260
// Emit dependencies.
261
//
262
// CHECKER_DEPENDENCY(FULLNAME, DEPENDENCY)
263
// - FULLNAME: The full name of the checker that depends on another checker.
264
// - DEPENDENCY: The full name of the checker FULLNAME depends on.
265
OS << "\n"
266
"#ifdef GET_CHECKER_DEPENDENCIES\n";
267
for (const Record *Checker : checkers) {
268
if (Checker->isValueUnset("Dependencies"))
269
continue;
270
271
for (const Record *Dependency :
272
Checker->getValueAsListOfDefs("Dependencies")) {
273
OS << "CHECKER_DEPENDENCY(";
274
OS << '\"';
275
OS.write_escaped(getCheckerFullName(Checker)) << "\", ";
276
OS << '\"';
277
OS.write_escaped(getCheckerFullName(Dependency)) << '\"';
278
OS << ")\n";
279
}
280
}
281
OS << "\n"
282
"#endif // GET_CHECKER_DEPENDENCIES\n";
283
284
// Emit weak dependencies.
285
//
286
// CHECKER_DEPENDENCY(FULLNAME, DEPENDENCY)
287
// - FULLNAME: The full name of the checker that is supposed to be
288
// registered first.
289
// - DEPENDENCY: The full name of the checker FULLNAME weak depends on.
290
OS << "\n"
291
"#ifdef GET_CHECKER_WEAK_DEPENDENCIES\n";
292
for (const Record *Checker : checkers) {
293
if (Checker->isValueUnset("WeakDependencies"))
294
continue;
295
296
for (const Record *Dependency :
297
Checker->getValueAsListOfDefs("WeakDependencies")) {
298
OS << "CHECKER_WEAK_DEPENDENCY(";
299
OS << '\"';
300
OS.write_escaped(getCheckerFullName(Checker)) << "\", ";
301
OS << '\"';
302
OS.write_escaped(getCheckerFullName(Dependency)) << '\"';
303
OS << ")\n";
304
}
305
}
306
OS << "\n"
307
"#endif // GET_CHECKER_WEAK_DEPENDENCIES\n";
308
309
// Emit a package option.
310
//
311
// CHECKER_OPTION(OPTIONTYPE, CHECKERNAME, OPTIONNAME, DESCRIPTION, DEFAULT)
312
// - OPTIONTYPE: Type of the option, whether it's integer or boolean etc.
313
// This is important for validating user input. Note that
314
// it's a string, rather than an actual type: since we can
315
// load checkers runtime, we can't use template hackery for
316
// sorting this out compile-time.
317
// - CHECKERNAME: Name of the package.
318
// - OPTIONNAME: Name of the option.
319
// - DESCRIPTION
320
// - DEFAULT: The default value for this option.
321
//
322
// The full option can be specified in the command like this:
323
// -analyzer-config CHECKERNAME:OPTIONNAME=VALUE
324
OS << "\n"
325
"#ifdef GET_CHECKER_OPTIONS\n";
326
for (const Record *Checker : checkers) {
327
328
if (Checker->isValueUnset("CheckerOptions"))
329
continue;
330
331
std::vector<Record *> CheckerOptions = Checker
332
->getValueAsListOfDefs("CheckerOptions");
333
for (Record *CheckerOpt : CheckerOptions) {
334
OS << "CHECKER_OPTION(";
335
printOption(OS, getCheckerFullName(Checker), *CheckerOpt);
336
OS << ")\n";
337
}
338
}
339
OS << "#endif // GET_CHECKER_OPTIONS\n"
340
"\n";
341
}
342
343