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#include "llvm/Support/raw_ostream.h"
23#include
24
25using namespace clang;
26using namespace ento;
27using namespace checker_registry;
28using llvm::sys::DynamicLibrary;
29
30
31
32
33
35
36 if (!VersionString)
37 return false;
38
39
40
42}
43
45
46
47
48
49
54 : Data(Data), Diags(Diags), AnOpts(AnOpts) {
55
56
57#define GET_CHECKERS
58#define CHECKER(FULLNAME, CLASS, HELPTEXT, DOC_URI, IS_HIDDEN) \
59 addChecker(register##CLASS, shouldRegister##CLASS, FULLNAME, HELPTEXT, \
60 DOC_URI, IS_HIDDEN);
61
62#define GET_PACKAGES
63#define PACKAGE(FULLNAME) addPackage(FULLNAME);
64
65#include "clang/StaticAnalyzer/Checkers/Checkers.inc"
66#undef CHECKER
67#undef GET_CHECKERS
68#undef PACKAGE
69#undef GET_PACKAGES
70
71
72 for (const std::string &Plugin : Plugins) {
73
74 std::string ErrorMsg;
75 DynamicLibrary Lib =
76 DynamicLibrary::getPermanentLibrary(Plugin.c_str(), &ErrorMsg);
77 if (!Lib.isValid()) {
78 Diags.Report(diag::err_fe_unable_to_load_plugin) << Plugin << ErrorMsg;
79 continue;
80 }
81
82
83 const char *PluginAPIVersion = static_cast<const char *>(
84 Lib.getAddressOfSymbol("clang_analyzerAPIVersionString"));
85
87 Diags.Report(diag::warn_incompatible_analyzer_plugin_api)
88 << llvm::sys::path::filename(Plugin);
89 Diags.Report(diag::note_incompatible_analyzer_plugin_api)
91 continue;
92 }
93
94 using RegisterPluginCheckerFn = void (*)(CheckerRegistry &);
95
96 RegisterPluginCheckerFn RegisterPluginCheckers =
97 reinterpret_cast<RegisterPluginCheckerFn>(
98 Lib.getAddressOfSymbol("clang_registerCheckers"));
99 if (RegisterPluginCheckers)
100 RegisterPluginCheckers(*this);
101 }
102
103
104
105
106
107 for (const auto &Fn : CheckerRegistrationFns)
108 Fn(*this);
109
110
111
112
113
116
117#define GET_CHECKER_DEPENDENCIES
118
119#define CHECKER_DEPENDENCY(FULLNAME, DEPENDENCY) \
120 addDependency(FULLNAME, DEPENDENCY);
121
122#define GET_CHECKER_WEAK_DEPENDENCIES
123
124#define CHECKER_WEAK_DEPENDENCY(FULLNAME, DEPENDENCY) \
125 addWeakDependency(FULLNAME, DEPENDENCY);
126
127#define GET_CHECKER_OPTIONS
128#define CHECKER_OPTION(TYPE, FULLNAME, CMDFLAG, DESC, DEFAULT_VAL, \
129 DEVELOPMENT_STATUS, IS_HIDDEN) \
130 addCheckerOption(TYPE, FULLNAME, CMDFLAG, DEFAULT_VAL, DESC, \
131 DEVELOPMENT_STATUS, IS_HIDDEN);
132
133#define GET_PACKAGE_OPTIONS
134#define PACKAGE_OPTION(TYPE, FULLNAME, CMDFLAG, DESC, DEFAULT_VAL, \
135 DEVELOPMENT_STATUS, IS_HIDDEN) \
136 addPackageOption(TYPE, FULLNAME, CMDFLAG, DEFAULT_VAL, DESC, \
137 DEVELOPMENT_STATUS, IS_HIDDEN);
138
139#include "clang/StaticAnalyzer/Checkers/Checkers.inc"
140#undef CHECKER_DEPENDENCY
141#undef GET_CHECKER_DEPENDENCIES
142#undef CHECKER_WEAK_DEPENDENCY
143#undef GET_CHECKER_WEAK_DEPENDENCIES
144#undef CHECKER_OPTION
145#undef GET_CHECKER_OPTIONS
146#undef PACKAGE_OPTION
147#undef GET_PACKAGE_OPTIONS
148
149 resolveDependencies();
150 resolveDependencies();
151
152#ifndef NDEBUG
153 for (auto &DepPair : Data.Dependencies) {
154 for (auto &WeakDepPair : Data.WeakDependencies) {
155
156
157
158 assert(WeakDepPair != DepPair &&
159 "A checker cannot strong and weak depend on the same checker!");
160 assert(WeakDepPair.first != DepPair.second &&
161 "A strong dependency mustn't have weak dependencies!");
162 assert(WeakDepPair.second != DepPair.second &&
163 "A strong dependency mustn't be a weak dependency as well!");
164 }
165 }
166#endif
167
168 resolveCheckerAndPackageOptions();
169
170
171
172 for (const std::pair<std::string, bool> &Opt : AnOpts.CheckersAndPackages) {
174 Data.getMutableCheckersForCmdLineArg(Opt.first);
175
176 if (CheckerForCmdLineArg.begin() == CheckerForCmdLineArg.end()) {
177 Diags.Report(diag::err_unknown_analyzer_checker_or_package) << Opt.first;
178 Diags.Report(diag::note_suggest_disabling_all_checkers);
179 }
180
181 for (CheckerInfo &checker : CheckerForCmdLineArg) {
182 checker.State = Opt.second ? StateFromCmdLine::State_Enabled
183 : StateFromCmdLine::State_Disabled;
184 }
185 }
187}
188
189
190
191
192
193template
197 IsEnabledFn IsEnabled);
198
199
200template
204
206
207
208
209
212 return ->isDisabled(Mgr);
213 };
215 if (.isEnabled(Mgr))
216 continue;
217
220 IsEnabledFromCmdLine)) {
221
222
223 continue;
224 }
225
226 Tmp.insert(Deps.begin(), Deps.end());
227
228
230 }
231
232
233
234
236 return Tmp.contains(Checker);
237 };
239 if (.isEnabled(Mgr))
240 continue;
241
243
245
247 IsEnabledFromCmdLine)) {
248
249
250 continue;
251 }
252
253
254 Data.EnabledCheckers.set_union(Deps);
256 }
257}
258
259template
263 IsEnabledFn IsEnabled) {
264
265 for (const CheckerInfo *Dependency : Deps) {
266 if (!IsEnabled(Dependency))
267 return false;
268
269
271 IsEnabled))
272 return false;
273 Ret.insert(Dependency);
274 }
275
276 return true;
277}
278
279template
283 IsEnabledFn IsEnabled) {
284
285 for (const CheckerInfo *Dependency : WeakDeps) {
286
287
289
290 if (IsEnabled(Dependency) &&
292 IsEnabled))
293 Ret.insert(Dependency);
294 }
295}
296
297template void CheckerRegistry::resolveDependencies() {
298 for (const std::pair<StringRef, StringRef> &Entry :
299 (IsWeak ? Data.WeakDependencies : Data.Dependencies)) {
300
301 auto CheckerIt = binaryFind(Data.Checkers, Entry.first);
302 assert(CheckerIt != Data.Checkers.end() &&
303 CheckerIt->FullName == Entry.first &&
304 "Failed to find the checker while attempting to set up its "
305 "dependencies!");
306
307 auto DependencyIt = binaryFind(Data.Checkers, Entry.second);
308 assert(DependencyIt != Data.Checkers.end() &&
309 DependencyIt->FullName == Entry.second &&
310 "Failed to find the dependency of a checker!");
311
312
313 assert((DependencyIt->FullName.starts_with("test") ||
314 DependencyIt->FullName.starts_with("example") || IsWeak ||
315 DependencyIt->IsHidden) &&
316 "Strong dependencies are modeling checkers, and as such "
317 "non-user facing! Mark them hidden in Checkers.td!");
318
319 if (IsWeak)
320 CheckerIt->WeakDependencies.emplace_back(&*DependencyIt);
321 else
322 CheckerIt->Dependencies.emplace_back(&*DependencyIt);
323 }
324}
325
327 Data.Dependencies.emplace_back(FullName, Dependency);
328}
329
331 StringRef Dependency) {
332 Data.WeakDependencies.emplace_back(FullName, Dependency);
333}
334
335
336
337
338
339
340
344
346
347 auto It =
349
350
351
352 if (It.second)
353 return;
354
355
356
357
358
359
360 StringRef SuppliedValue = It.first->getValue();
361
363 if (SuppliedValue != "true" && SuppliedValue != "false") {
365 Diags.Report(diag::err_analyzer_checker_option_invalid_input)
366 << FullOption << "a boolean value";
367 }
368
369 It.first->setValue(std::string(Option.DefaultValStr));
370 }
371 return;
372 }
373
375 int Tmp;
376 bool HasFailed = SuppliedValue.getAsInteger(0, Tmp);
377 if (HasFailed) {
379 Diags.Report(diag::err_analyzer_checker_option_invalid_input)
380 << FullOption << "an integer value";
381 }
382
383 It.first->setValue(std::string(Option.DefaultValStr));
384 }
385 return;
386 }
387}
388
389template
395 assert(It != Collection.end() &&
396 "Failed to find the checker while attempting to add a command line "
397 "option to it!");
398
400
401 It->CmdLineOptions.emplace_back(Option);
402}
403
404void CheckerRegistry::resolveCheckerAndPackageOptions() {
405 for (const std::pair<StringRef, CmdLineOption> &CheckerOptEntry :
406 Data.CheckerOptions) {
408 CheckerOptEntry.second, AnOpts, Diags);
409 }
410
411 for (const std::pair<StringRef, CmdLineOption> &PackageOptEntry :
412 Data.PackageOptions) {
414 PackageOptEntry.second, AnOpts, Diags);
415 }
416}
417
420}
421
423 StringRef PackageFullName,
424 StringRef OptionName,
425 StringRef DefaultValStr,
426 StringRef Description,
427 StringRef DevelopmentStatus,
428 bool IsHidden) {
429 Data.PackageOptions.emplace_back(
430 PackageFullName, CmdLineOption{OptionType, OptionName, DefaultValStr,
431 Description, DevelopmentStatus, IsHidden});
432}
433
436 StringRef Desc, StringRef DocsUri,
437 bool IsHidden) {
438 Data.Checkers.emplace_back(Rfn, Sfn, Name, Desc, DocsUri, IsHidden);
439
440
441 StringRef PackageName, LeafName;
442 std::tie(PackageName, LeafName) = Name.rsplit(PackageSeparator);
443 while (!LeafName.empty()) {
444 Data.PackageSizes[PackageName] += 1;
445 std::tie(PackageName, LeafName) = PackageName.rsplit(PackageSeparator);
446 }
447}
448
450 StringRef CheckerFullName,
451 StringRef OptionName,
452 StringRef DefaultValStr,
453 StringRef Description,
454 StringRef DevelopmentStatus,
455 bool IsHidden) {
456 Data.CheckerOptions.emplace_back(
457 CheckerFullName, CmdLineOption{OptionType, OptionName, DefaultValStr,
458 Description, DevelopmentStatus, IsHidden});
459}
460
461void CheckerRegistry::initializeManager(CheckerManager &CheckerMgr) const {
462
463 for (const auto *Checker : Data.EnabledCheckers) {
465 Checker->Initialize(CheckerMgr);
466 }
467}
468
470 StringRef SuppliedChecker,
471 StringRef SuppliedOption,
474
476 return;
477
478 auto SameOptName = [SuppliedOption](const CmdLineOption &Opt) {
479 return Opt.OptionName == SuppliedOption;
480 };
481
482 if (llvm::none_of(OptionList, SameOptName)) {
483 Diags.Report(diag::err_analyzer_checker_option_unknown)
484 << SuppliedChecker << SuppliedOption;
485 return;
486 }
487}
488
490 for (const auto &Config : AnOpts.Config) {
491
492 StringRef SuppliedCheckerOrPackage;
493 StringRef SuppliedOption;
494 std::tie(SuppliedCheckerOrPackage, SuppliedOption) =
495 Config.getKey().split(':');
496
497 if (SuppliedOption.empty())
498 continue;
499
500
501
502
503
504
505
506
507
508 auto CheckerIt =
509 llvm::find(Data.Checkers, CheckerInfo(SuppliedCheckerOrPackage));
510 if (CheckerIt != Data.Checkers.end()) {
512 SuppliedOption, AnOpts, Diags);
513 continue;
514 }
515
516 const auto *PackageIt =
517 llvm::find(Data.Packages, PackageInfo(SuppliedCheckerOrPackage));
518 if (PackageIt != Data.Packages.end()) {
520 SuppliedOption, AnOpts, Diags);
521 continue;
522 }
523
524 Diags.Report(diag::err_unknown_analyzer_checker_or_package)
525 << SuppliedCheckerOrPackage;
526 }
527}
Defines the Diagnostic-related interfaces.
static constexpr char PackageSeparator
static bool isCompatibleAPIVersion(const char *VersionString)
static void collectWeakDependencies(const ConstCheckerInfoList &Deps, const CheckerManager &Mgr, CheckerInfoSet &Ret, IsEnabledFn IsEnabled)
Collects weak dependencies in enabledData.Checkers.
static constexpr char PackageSeparator
static void insertAndValidate(StringRef FullName, const CmdLineOption &Option, AnalyzerOptions &AnOpts, DiagnosticsEngine &Diags)
Insert the checker/package option to AnalyzerOptions' config table, and validate it,...
static void isOptionContainedIn(const CmdLineOptionList &OptionList, StringRef SuppliedChecker, StringRef SuppliedOption, const AnalyzerOptions &AnOpts, DiagnosticsEngine &Diags)
static bool collectStrongDependencies(const ConstCheckerInfoList &Deps, const CheckerManager &Mgr, CheckerInfoSet &Ret, IsEnabledFn IsEnabled)
static void insertOptionToCollection(StringRef FullName, T &Collection, const CmdLineOption &Option, AnalyzerOptions &AnOpts, DiagnosticsEngine &Diags)
#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.
std::vector< std::pair< std::string, bool > > CheckersAndPackages
Pairs of checker/package name and enable/disable.
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 ...
Manages a set of available checkers for running a static analysis.
void addCheckerOption(StringRef OptionType, StringRef CheckerFullName, StringRef OptionName, StringRef DefaultValStr, StringRef Description, StringRef DevelopmentStatus, bool IsHidden=false)
Registers an option to a given checker.
void addWeakDependency(StringRef FullName, StringRef Dependency)
Makes the checker with the full name fullName weak depend on the checker called dependency.
void addPackageOption(StringRef OptionType, StringRef PackageFullName, StringRef OptionName, StringRef DefaultValStr, StringRef Description, StringRef DevelopmentStatus, bool IsHidden=false)
Registers an option to a given package.
void initializeRegistry(const CheckerManager &Mgr)
Collects all enabled checkers in the field EnabledCheckers.
void addChecker(RegisterCheckerFn Fn, ShouldRegisterFunction sfn, StringRef FullName, StringRef Desc, StringRef DocsUri, bool IsHidden)
Adds a checker to the registry.
void addPackage(StringRef FullName)
Adds a package to the registry.
void validateCheckerOptions() const
Check if every option corresponds to a specific checker or package.
void addDependency(StringRef FullName, StringRef Dependency)
Makes the checker with the full name fullName depend on the checker called dependency.
CheckerRegistry(CheckerRegistryData &Data, ArrayRef< std::string > Plugins, DiagnosticsEngine &Diags, AnalyzerOptions &AnOpts, ArrayRef< std::function< void(CheckerRegistry &)> > CheckerRegistrationFns={})
std::conditional_t< std::is_const< CheckerOrPackageInfoList >::value, typename CheckerOrPackageInfoList::const_iterator, typename CheckerOrPackageInfoList::iterator > binaryFind(CheckerOrPackageInfoList &Collection, StringRef FullName)
llvm::iterator_range< CheckerInfoList::iterator > CheckerInfoListRange
bool(*)(const CheckerManager &) ShouldRegisterFunction
void(*)(CheckerManager &) RegisterCheckerFn
Initialization functions perform any necessary setup for a checker.
llvm::SetVector< const CheckerInfo * > CheckerInfoSet
The JSON file list parser is used to communicate input to InstallAPI.
const FunctionProtoType * T
Specifies a command line option.