clang: lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
17#include "llvm/ADT/STLExtras.h"
18#include "llvm/ADT/StringMap.h"
19#include "llvm/ADT/StringRef.h"
20#include "llvm/Support/DynamicLibrary.h"
21#include "llvm/Support/Path.h"
22
23using namespace clang;
24using namespace ento;
26using llvm::sys::DynamicLibrary;
27
28
29
30
31
33
34 if (!VersionString)
35 return false;
36
37
38
40}
41
43
44
45
46
47
52 : Data(Data), Diags(Diags), AnOpts(AnOpts) {
53
54
55#define GET_CHECKERS
56#define CHECKER(FULLNAME, CLASS, HELPTEXT, DOC_URI, IS_HIDDEN) \
57 addChecker(register##CLASS, shouldRegister##CLASS, FULLNAME, HELPTEXT, \
58 DOC_URI, IS_HIDDEN);
59
60#define GET_PACKAGES
61#define PACKAGE(FULLNAME) addPackage(FULLNAME);
62
63#include "clang/StaticAnalyzer/Checkers/Checkers.inc"
64#undef CHECKER
65#undef GET_CHECKERS
66#undef PACKAGE
67#undef GET_PACKAGES
68
69
70 for (const std::string &Plugin : Plugins) {
71
72 std::string ErrorMsg;
73 DynamicLibrary Lib =
74 DynamicLibrary::getPermanentLibrary(Plugin.c_str(), &ErrorMsg);
75 if (!Lib.isValid()) {
76 Diags.Report(diag::err_fe_unable_to_load_plugin) << Plugin << ErrorMsg;
77 continue;
78 }
79
80
81 const char *PluginAPIVersion = static_cast<const char *>(
82 Lib.getAddressOfSymbol("clang_analyzerAPIVersionString"));
83
85 Diags.Report(diag::warn_incompatible_analyzer_plugin_api)
86 << llvm::sys::path::filename(Plugin);
87 Diags.Report(diag::note_incompatible_analyzer_plugin_api)
89 continue;
90 }
91
92 using RegisterPluginCheckerFn = void (*)(CheckerRegistry &);
93
94 RegisterPluginCheckerFn RegisterPluginCheckers =
95 reinterpret_cast<RegisterPluginCheckerFn>(
96 Lib.getAddressOfSymbol("clang_registerCheckers"));
97 if (RegisterPluginCheckers)
98 RegisterPluginCheckers(*this);
99 }
100
101
102
103
104
105 for (const auto &Fn : CheckerRegistrationFns)
106 Fn(*this);
107
108
109
110
111
114
115#define GET_CHECKER_DEPENDENCIES
116
117#define CHECKER_DEPENDENCY(FULLNAME, DEPENDENCY) \
118 addDependency(FULLNAME, DEPENDENCY);
119
120#define GET_CHECKER_WEAK_DEPENDENCIES
121
122#define CHECKER_WEAK_DEPENDENCY(FULLNAME, DEPENDENCY) \
123 addWeakDependency(FULLNAME, DEPENDENCY);
124
125#define GET_CHECKER_OPTIONS
126#define CHECKER_OPTION(TYPE, FULLNAME, CMDFLAG, DESC, DEFAULT_VAL, \
127 DEVELOPMENT_STATUS, IS_HIDDEN) \
128 addCheckerOption(TYPE, FULLNAME, CMDFLAG, DEFAULT_VAL, DESC, \
129 DEVELOPMENT_STATUS, IS_HIDDEN);
130
131#define GET_PACKAGE_OPTIONS
132#define PACKAGE_OPTION(TYPE, FULLNAME, CMDFLAG, DESC, DEFAULT_VAL, \
133 DEVELOPMENT_STATUS, IS_HIDDEN) \
134 addPackageOption(TYPE, FULLNAME, CMDFLAG, DEFAULT_VAL, DESC, \
135 DEVELOPMENT_STATUS, IS_HIDDEN);
136
137#include "clang/StaticAnalyzer/Checkers/Checkers.inc"
138#undef CHECKER_DEPENDENCY
139#undef GET_CHECKER_DEPENDENCIES
140#undef CHECKER_WEAK_DEPENDENCY
141#undef GET_CHECKER_WEAK_DEPENDENCIES
142#undef CHECKER_OPTION
143#undef GET_CHECKER_OPTIONS
144#undef PACKAGE_OPTION
145#undef GET_PACKAGE_OPTIONS
146
147 resolveDependencies();
148 resolveDependencies();
149
150#ifndef NDEBUG
151 for (auto &DepPair : Data.Dependencies) {
152 for (auto &WeakDepPair : Data.WeakDependencies) {
153
154
155
156 assert(WeakDepPair != DepPair &&
157 "A checker cannot strong and weak depend on the same checker!");
158 assert(WeakDepPair.first != DepPair.second &&
159 "A strong dependency mustn't have weak dependencies!");
160 assert(WeakDepPair.second != DepPair.second &&
161 "A strong dependency mustn't be a weak dependency as well!");
162 }
163 }
164#endif
165
166 resolveCheckerAndPackageOptions();
167
168
169
170 for (const std::pair<std::string, bool> &Opt : AnOpts.CheckersAndPackages) {
172 Data.getMutableCheckersForCmdLineArg(Opt.first);
173
174 if (CheckerForCmdLineArg.begin() == CheckerForCmdLineArg.end()) {
175 Diags.Report(diag::err_unknown_analyzer_checker_or_package) << Opt.first;
176 Diags.Report(diag::note_suggest_disabling_all_checkers);
177 }
178
179 for (CheckerInfo &checker : CheckerForCmdLineArg) {
180 checker.State = Opt.second ? StateFromCmdLine::State_Enabled
181 : StateFromCmdLine::State_Disabled;
182 }
183 }
185}
186
187
188
189
190
191template
195 IsEnabledFn IsEnabled);
196
197
198template
202
204
205
206
207
210 return ->isDisabled(Mgr);
211 };
214 continue;
215
218 IsEnabledFromCmdLine)) {
219
220
221 continue;
222 }
223
224 Tmp.insert_range(Deps);
225
226
228 }
229
230
231
232
234 return Tmp.contains(Checker);
235 };
238 continue;
239
241
243
245 IsEnabledFromCmdLine)) {
246
247
248 continue;
249 }
250
251
252 Data.EnabledCheckers.set_union(Deps);
253 Data.EnabledCheckers.insert(&Checker);
254 }
255}
256
257template
261 IsEnabledFn IsEnabled) {
262
263 for (const CheckerInfo *Dependency : Deps) {
264 if (!IsEnabled(Dependency))
265 return false;
266
267
269 IsEnabled))
270 return false;
271 Ret.insert(Dependency);
272 }
273
274 return true;
275}
276
277template
281 IsEnabledFn IsEnabled) {
282
283 for (const CheckerInfo *Dependency : WeakDeps) {
284
285
287
288 if (IsEnabled(Dependency) &&
290 IsEnabled))
291 Ret.insert(Dependency);
292 }
293}
294
295template void CheckerRegistry::resolveDependencies() {
296 for (const std::pair<StringRef, StringRef> &Entry :
297 (IsWeak ? Data.WeakDependencies : Data.Dependencies)) {
298
299 auto CheckerIt = binaryFind(Data.Checkers, Entry.first);
300 assert(CheckerIt != Data.Checkers.end() &&
301 CheckerIt->FullName == Entry.first &&
302 "Failed to find the checker while attempting to set up its "
303 "dependencies!");
304
305 auto DependencyIt = binaryFind(Data.Checkers, Entry.second);
306 assert(DependencyIt != Data.Checkers.end() &&
307 DependencyIt->FullName == Entry.second &&
308 "Failed to find the dependency of a checker!");
309
310
311 assert((DependencyIt->FullName.starts_with("test") ||
312 DependencyIt->FullName.starts_with("example") || IsWeak ||
313 DependencyIt->IsHidden) &&
314 "Strong dependencies are modeling checkers, and as such "
315 "non-user facing! Mark them hidden in Checkers.td!");
316
317 if (IsWeak)
318 CheckerIt->WeakDependencies.emplace_back(&*DependencyIt);
319 else
320 CheckerIt->Dependencies.emplace_back(&*DependencyIt);
321 }
322}
323
325 Data.Dependencies.emplace_back(FullName, Dependency);
326}
327
329 StringRef Dependency) {
330 Data.WeakDependencies.emplace_back(FullName, Dependency);
331}
332
333
334
335
336
337
338
342
343 std::string FullOption = (FullName + ":" + Option.OptionName).str();
344
345 auto It =
347
348
349
350 if (It.second)
351 return;
352
353
354
355
356
357
358 StringRef SuppliedValue = It.first->getValue();
359
361 if (SuppliedValue != "true" && SuppliedValue != "false") {
363 Diags.Report(diag::err_analyzer_checker_option_invalid_input)
364 << FullOption << "a boolean value";
365 }
366
367 It.first->setValue(std::string(Option.DefaultValStr));
368 }
369 return;
370 }
371
373 int Tmp;
374 bool HasFailed = SuppliedValue.getAsInteger(0, Tmp);
375 if (HasFailed) {
377 Diags.Report(diag::err_analyzer_checker_option_invalid_input)
378 << FullOption << "an integer value";
379 }
380
381 It.first->setValue(std::string(Option.DefaultValStr));
382 }
383 return;
384 }
385}
386
387template
392 auto It = binaryFind(Collection, FullName);
393 assert(It != Collection.end() &&
394 "Failed to find the checker while attempting to add a command line "
395 "option to it!");
396
398
399 It->CmdLineOptions.emplace_back(Option);
400}
401
402void CheckerRegistry::resolveCheckerAndPackageOptions() {
403 for (const std::pair<StringRef, CmdLineOption> &CheckerOptEntry :
404 Data.CheckerOptions) {
406 CheckerOptEntry.second, AnOpts, Diags);
407 }
408
409 for (const std::pair<StringRef, CmdLineOption> &PackageOptEntry :
410 Data.PackageOptions) {
412 PackageOptEntry.second, AnOpts, Diags);
413 }
414}
415
417 Data.Packages.emplace_back(PackageInfo(FullName));
418}
419
421 StringRef PackageFullName,
422 StringRef OptionName,
423 StringRef DefaultValStr,
424 StringRef Description,
425 StringRef DevelopmentStatus,
426 bool IsHidden) {
427 Data.PackageOptions.emplace_back(
428 PackageFullName, CmdLineOption{OptionType, OptionName, DefaultValStr,
429 Description, DevelopmentStatus, IsHidden});
430}
431
434 StringRef Desc, StringRef DocsUri,
435 bool IsHidden) {
436 Data.Checkers.emplace_back(Rfn, Sfn, Name, Desc, DocsUri, IsHidden);
437
438
439 StringRef PackageName, LeafName;
440 std::tie(PackageName, LeafName) = Name.rsplit(PackageSeparator);
441 while (!LeafName.empty()) {
442 Data.PackageSizes[PackageName] += 1;
443 std::tie(PackageName, LeafName) = PackageName.rsplit(PackageSeparator);
444 }
445}
446
448 StringRef CheckerFullName,
449 StringRef OptionName,
450 StringRef DefaultValStr,
451 StringRef Description,
452 StringRef DevelopmentStatus,
453 bool IsHidden) {
454 Data.CheckerOptions.emplace_back(
455 CheckerFullName, CmdLineOption{OptionType, OptionName, DefaultValStr,
456 Description, DevelopmentStatus, IsHidden});
457}
458
459void CheckerRegistry::initializeManager(CheckerManager &CheckerMgr) const {
460
461 for (const auto *Checker : Data.EnabledCheckers) {
463 Checker->Initialize(CheckerMgr);
464 }
465}
466
468 StringRef SuppliedChecker,
469 StringRef SuppliedOption,
472
474 return;
475
476 auto SameOptName = [SuppliedOption](const CmdLineOption &Opt) {
477 return Opt.OptionName == SuppliedOption;
478 };
479
480 if (llvm::none_of(OptionList, SameOptName)) {
481 Diags.Report(diag::err_analyzer_checker_option_unknown)
482 << SuppliedChecker << SuppliedOption;
483 return;
484 }
485}
486
488 for (const auto &Config : AnOpts.Config) {
489
490 StringRef SuppliedCheckerOrPackage;
491 StringRef SuppliedOption;
492 std::tie(SuppliedCheckerOrPackage, SuppliedOption) =
493 Config.getKey().split(':');
494
495 if (SuppliedOption.empty())
496 continue;
497
498
499
500
501
502
503
504
505
506 auto CheckerIt =
507 llvm::find(Data.Checkers, CheckerInfo(SuppliedCheckerOrPackage));
508 if (CheckerIt != Data.Checkers.end()) {
510 SuppliedOption, AnOpts, Diags);
511 continue;
512 }
513
514 const auto *PackageIt =
515 llvm::find(Data.Packages, PackageInfo(SuppliedCheckerOrPackage));
516 if (PackageIt != Data.Packages.end()) {
518 SuppliedOption, AnOpts, Diags);
519 continue;
520 }
521
522 Diags.Report(diag::err_unknown_analyzer_checker_or_package)
523 << SuppliedCheckerOrPackage;
524 }
525}
Defines the Diagnostic-related interfaces.
static constexpr char PackageSeparator
static bool isCompatibleAPIVersion(const char *VersionString)
Definition CheckerRegistry.cpp:32
static void collectWeakDependencies(const ConstCheckerInfoList &Deps, const CheckerManager &Mgr, CheckerInfoSet &Ret, IsEnabledFn IsEnabled)
Collects weak dependencies in enabledData.Checkers.
Definition CheckerRegistry.cpp:278
static void insertAndValidate(StringRef FullName, const CmdLineOption &Option, AnalyzerOptions &AnOpts, DiagnosticsEngine &Diags)
Insert the checker/package option to AnalyzerOptions' config table, and validate it,...
Definition CheckerRegistry.cpp:339
static void isOptionContainedIn(const CmdLineOptionList &OptionList, StringRef SuppliedChecker, StringRef SuppliedOption, const AnalyzerOptions &AnOpts, DiagnosticsEngine &Diags)
Definition CheckerRegistry.cpp:467
static bool collectStrongDependencies(const ConstCheckerInfoList &Deps, const CheckerManager &Mgr, CheckerInfoSet &Ret, IsEnabledFn IsEnabled)
Definition CheckerRegistry.cpp:258
static void insertOptionToCollection(StringRef FullName, T &Collection, const CmdLineOption &Option, AnalyzerOptions &AnOpts, DiagnosticsEngine &Diags)
Definition CheckerRegistry.cpp:388
#define CLANG_ANALYZER_API_VERSION_STRING
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
Stores options for the analyzer from the command line.
ConfigTable Config
A key-value table of use-specified configuration values.
unsigned ShouldEmitErrorsOnInvalidConfigValue
Concrete class used by the front-end to report problems and issues.
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
void setCurrentCheckerName(CheckerNameRef name)
This wrapper is used to ensure that only StringRefs originating from the CheckerRegistry are used as ...
void addCheckerOption(StringRef OptionType, StringRef CheckerFullName, StringRef OptionName, StringRef DefaultValStr, StringRef Description, StringRef DevelopmentStatus, bool IsHidden=false)
Registers an option to a given checker.
Definition CheckerRegistry.cpp:447
void addWeakDependency(StringRef FullName, StringRef Dependency)
Makes the checker with the full name fullName weak depend on the checker called dependency.
Definition CheckerRegistry.cpp:328
void addPackageOption(StringRef OptionType, StringRef PackageFullName, StringRef OptionName, StringRef DefaultValStr, StringRef Description, StringRef DevelopmentStatus, bool IsHidden=false)
Registers an option to a given package.
Definition CheckerRegistry.cpp:420
void initializeRegistry(const CheckerManager &Mgr)
Collects all enabled checkers in the field EnabledCheckers.
Definition CheckerRegistry.cpp:203
void addChecker(RegisterCheckerFn Fn, ShouldRegisterFunction Sfn, StringRef FullName, StringRef Desc, StringRef DocsUri="NoDocsUri", bool IsHidden=false)
Adds a checker to the registry.
Definition CheckerRegistry.cpp:432
void addPackage(StringRef FullName)
Adds a package to the registry.
Definition CheckerRegistry.cpp:416
void validateCheckerOptions() const
Check if every option corresponds to a specific checker or package.
Definition CheckerRegistry.cpp:487
void addDependency(StringRef FullName, StringRef Dependency)
Makes the checker with the full name fullName depend on the checker called dependency.
Definition CheckerRegistry.cpp:324
CheckerRegistry(CheckerRegistryData &Data, ArrayRef< std::string > Plugins, DiagnosticsEngine &Diags, AnalyzerOptions &AnOpts, ArrayRef< std::function< void(CheckerRegistry &)> > CheckerRegistrationFns={})
Definition CheckerRegistry.cpp:48
Simple checker classes that implement one frontend (i.e.
FullNameLT< CheckerInfo > CheckerNameLT
std::conditional_t< std::is_const< CheckerOrPackageInfoList >::value, typename CheckerOrPackageInfoList::const_iterator, typename CheckerOrPackageInfoList::iterator > binaryFind(CheckerOrPackageInfoList &Collection, StringRef FullName)
FullNameLT< PackageInfo > PackageNameLT
void(*)(CheckerManager &) RegisterCheckerFn
Initialization functions perform any necessary setup for a checker.
llvm::iterator_range< CheckerInfoList::iterator > CheckerInfoListRange
llvm::SetVector< const CheckerInfo * > CheckerInfoSet
llvm::SmallVector< CmdLineOption, 0 > CmdLineOptionList
llvm::SmallVector< const CheckerInfo *, 0 > ConstCheckerInfoList
bool(*)(const CheckerManager &) ShouldRegisterFunction
The JSON file list parser is used to communicate input to InstallAPI.
const FunctionProtoType * T
int const char * function
Specifies a command line option.