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"
25using namespace checker_registry;
26using llvm::sys::DynamicLibrary;
52 :
Data(
Data), Diags(Diags), AnOpts(AnOpts) {
56#define CHECKER(FULLNAME, CLASS, HELPTEXT, DOC_URI, IS_HIDDEN) \
57 addChecker(register##CLASS, shouldRegister##CLASS, FULLNAME, HELPTEXT, \
61#define PACKAGE(FULLNAME) addPackage(FULLNAME);
63#include "clang/StaticAnalyzer/Checkers/Checkers.inc"
70 for (
const std::string &Plugin : Plugins) {
74 DynamicLibrary::getPermanentLibrary(Plugin.c_str(), &ErrorMsg);
76 Diags.
Report(diag::err_fe_unable_to_load_plugin) << Plugin << ErrorMsg;
81 const char *PluginAPIVersion =
static_cast<const char *
>(
82 Lib.getAddressOfSymbol(
"clang_analyzerAPIVersionString"));
85 Diags.
Report(diag::warn_incompatible_analyzer_plugin_api)
86 << llvm::sys::path::filename(Plugin);
87 Diags.
Report(diag::note_incompatible_analyzer_plugin_api)
94 RegisterPluginCheckerFn RegisterPluginCheckers =
95 reinterpret_cast<RegisterPluginCheckerFn
>(
96 Lib.getAddressOfSymbol(
"clang_registerCheckers"));
97 if (RegisterPluginCheckers)
98 RegisterPluginCheckers(*
this);
105 for (
const auto &Fn : CheckerRegistrationFns)
115#define GET_CHECKER_DEPENDENCIES
117#define CHECKER_DEPENDENCY(FULLNAME, DEPENDENCY) \
118 addDependency(FULLNAME, DEPENDENCY);
120#define GET_CHECKER_WEAK_DEPENDENCIES
122#define CHECKER_WEAK_DEPENDENCY(FULLNAME, DEPENDENCY) \
123 addWeakDependency(FULLNAME, DEPENDENCY);
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);
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);
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
143#undef GET_CHECKER_OPTIONS
145#undef GET_PACKAGE_OPTIONS
147 resolveDependencies<true>();
148 resolveDependencies<false>();
151 for (
auto &DepPair :
Data.Dependencies) {
152 for (
auto &WeakDepPair :
Data.WeakDependencies) {
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!");
166 resolveCheckerAndPackageOptions();
172 Data.getMutableCheckersForCmdLineArg(Opt.first);
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);
179 for (
CheckerInfo &checker : CheckerForCmdLineArg) {
180 checker.State = Opt.second ? StateFromCmdLine::State_Enabled
181 : StateFromCmdLine::State_Disabled;
191template <
typename IsEnabledFn>
195 IsEnabledFn IsEnabled);
198template <
typename IsEnabledFn>
210 return !
Checker->isDisabled(Mgr);
218 IsEnabledFromCmdLine)) {
224 Tmp.insert_range(Deps);
245 IsEnabledFromCmdLine)) {
252 Data.EnabledCheckers.set_union(Deps);
257template <
typename IsEnabledFn>
261 IsEnabledFn IsEnabled) {
264 if (!IsEnabled(Dependency))
271 Ret.insert(Dependency);
277template <
typename IsEnabledFn>
281 IsEnabledFn IsEnabled) {
288 if (IsEnabled(Dependency) &&
291 Ret.insert(Dependency);
295template <
bool IsWeak>
void CheckerRegistry::resolveDependencies() {
296 for (
const std::pair<StringRef, StringRef> &Entry :
297 (IsWeak ?
Data.WeakDependencies :
Data.Dependencies)) {
300 assert(CheckerIt !=
Data.Checkers.end() &&
301 CheckerIt->FullName == Entry.first &&
302 "Failed to find the checker while attempting to set up its "
306 assert(DependencyIt !=
Data.Checkers.end() &&
307 DependencyIt->FullName == Entry.second &&
308 "Failed to find the dependency of a checker!");
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!");
318 CheckerIt->WeakDependencies.emplace_back(&*DependencyIt);
320 CheckerIt->Dependencies.emplace_back(&*DependencyIt);
329 StringRef Dependency) {
330 Data.WeakDependencies.emplace_back(
FullName, Dependency);
358 StringRef SuppliedValue = It.first->getValue();
361 if (SuppliedValue !=
"true" && SuppliedValue !=
"false") {
363 Diags.
Report(diag::err_analyzer_checker_option_invalid_input)
364 << FullOption <<
"a boolean value";
374 bool HasFailed = SuppliedValue.getAsInteger(0, Tmp);
377 Diags.
Report(diag::err_analyzer_checker_option_invalid_input)
378 << FullOption <<
"an integer value";
393 assert(It != Collection.end() &&
394 "Failed to find the checker while attempting to add a command line "
399 It->CmdLineOptions.emplace_back(Option);
402void CheckerRegistry::resolveCheckerAndPackageOptions() {
403 for (
const std::pair<StringRef, CmdLineOption> &CheckerOptEntry :
404 Data.CheckerOptions) {
406 CheckerOptEntry.second, AnOpts, Diags);
409 for (
const std::pair<StringRef, CmdLineOption> &PackageOptEntry :
410 Data.PackageOptions) {
412 PackageOptEntry.second, AnOpts, Diags);
421 StringRef PackageFullName,
422 StringRef OptionName,
423 StringRef DefaultValStr,
424 StringRef Description,
425 StringRef DevelopmentStatus,
427 Data.PackageOptions.emplace_back(
428 PackageFullName,
CmdLineOption{OptionType, OptionName, DefaultValStr,
429 Description, DevelopmentStatus, IsHidden});
434 StringRef Desc, StringRef DocsUri,
436 Data.Checkers.emplace_back(Rfn, Sfn, Name, Desc, DocsUri, IsHidden);
439 StringRef PackageName, LeafName;
441 while (!LeafName.empty()) {
442 Data.PackageSizes[PackageName] += 1;
448 StringRef CheckerFullName,
449 StringRef OptionName,
450 StringRef DefaultValStr,
451 StringRef Description,
452 StringRef DevelopmentStatus,
454 Data.CheckerOptions.emplace_back(
455 CheckerFullName,
CmdLineOption{OptionType, OptionName, DefaultValStr,
456 Description, DevelopmentStatus, IsHidden});
463 Checker->Initialize(CheckerMgr);
468 StringRef SuppliedChecker,
469 StringRef SuppliedOption,
476 auto SameOptName = [SuppliedOption](
const CmdLineOption &Opt) {
477 return Opt.OptionName == SuppliedOption;
480 if (llvm::none_of(OptionList, SameOptName)) {
481 Diags.
Report(diag::err_analyzer_checker_option_unknown)
482 << SuppliedChecker << SuppliedOption;
488 for (
const auto &Config : AnOpts.
Config) {
490 StringRef SuppliedCheckerOrPackage;
491 StringRef SuppliedOption;
492 std::tie(SuppliedCheckerOrPackage, SuppliedOption) =
493 Config.getKey().split(
':');
495 if (SuppliedOption.empty())
508 if (CheckerIt !=
Data.Checkers.end()) {
510 SuppliedOption, AnOpts, Diags);
514 const auto *PackageIt =
516 if (PackageIt !=
Data.Packages.end()) {
518 SuppliedOption, AnOpts, Diags);
522 Diags.
Report(diag::err_unknown_analyzer_checker_or_package)
523 << SuppliedCheckerOrPackage;
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="NoDocsUri", bool IsHidden=false)
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={})
Simple checker classes that implement one frontend (i.e.
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
int const char * function
Specifies a command line option.