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"
27using namespace checker_registry;
28using llvm::sys::DynamicLibrary;
54 :
Data(
Data), Diags(Diags), AnOpts(AnOpts) {
58#define CHECKER(FULLNAME, CLASS, HELPTEXT, DOC_URI, IS_HIDDEN) \
59 addChecker(register##CLASS, shouldRegister##CLASS, FULLNAME, HELPTEXT, \
63#define PACKAGE(FULLNAME) addPackage(FULLNAME);
65#include "clang/StaticAnalyzer/Checkers/Checkers.inc"
72 for (
const std::string &Plugin : Plugins) {
76 DynamicLibrary::getPermanentLibrary(Plugin.c_str(), &ErrorMsg);
78 Diags.
Report(diag::err_fe_unable_to_load_plugin) << Plugin << ErrorMsg;
83 const char *PluginAPIVersion =
static_cast<const char *
>(
84 Lib.getAddressOfSymbol(
"clang_analyzerAPIVersionString"));
87 Diags.
Report(diag::warn_incompatible_analyzer_plugin_api)
88 << llvm::sys::path::filename(Plugin);
89 Diags.
Report(diag::note_incompatible_analyzer_plugin_api)
96 RegisterPluginCheckerFn RegisterPluginCheckers =
97 reinterpret_cast<RegisterPluginCheckerFn
>(
98 Lib.getAddressOfSymbol(
"clang_registerCheckers"));
99 if (RegisterPluginCheckers)
100 RegisterPluginCheckers(*
this);
107 for (
const auto &Fn : CheckerRegistrationFns)
117#define GET_CHECKER_DEPENDENCIES
119#define CHECKER_DEPENDENCY(FULLNAME, DEPENDENCY) \
120 addDependency(FULLNAME, DEPENDENCY);
122#define GET_CHECKER_WEAK_DEPENDENCIES
124#define CHECKER_WEAK_DEPENDENCY(FULLNAME, DEPENDENCY) \
125 addWeakDependency(FULLNAME, DEPENDENCY);
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);
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);
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
145#undef GET_CHECKER_OPTIONS
147#undef GET_PACKAGE_OPTIONS
149 resolveDependencies<true>();
150 resolveDependencies<false>();
153 for (
auto &DepPair :
Data.Dependencies) {
154 for (
auto &WeakDepPair :
Data.WeakDependencies) {
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!");
168 resolveCheckerAndPackageOptions();
174 Data.getMutableCheckersForCmdLineArg(Opt.first);
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);
181 for (
CheckerInfo &checker : CheckerForCmdLineArg) {
182 checker.State = Opt.second ? StateFromCmdLine::State_Enabled
183 : StateFromCmdLine::State_Disabled;
193template <
typename IsEnabledFn>
197 IsEnabledFn IsEnabled);
200template <
typename IsEnabledFn>
212 return !
Checker->isDisabled(Mgr);
220 IsEnabledFromCmdLine)) {
226 Tmp.insert(Deps.begin(), Deps.end());
247 IsEnabledFromCmdLine)) {
254 Data.EnabledCheckers.set_union(Deps);
259template <
typename IsEnabledFn>
263 IsEnabledFn IsEnabled) {
266 if (!IsEnabled(Dependency))
273 Ret.insert(Dependency);
279template <
typename IsEnabledFn>
283 IsEnabledFn IsEnabled) {
290 if (IsEnabled(Dependency) &&
293 Ret.insert(Dependency);
297template <
bool IsWeak>
void CheckerRegistry::resolveDependencies() {
298 for (
const std::pair<StringRef, StringRef> &Entry :
299 (IsWeak ?
Data.WeakDependencies :
Data.Dependencies)) {
302 assert(CheckerIt !=
Data.Checkers.end() &&
303 CheckerIt->FullName == Entry.first &&
304 "Failed to find the checker while attempting to set up its "
308 assert(DependencyIt !=
Data.Checkers.end() &&
309 DependencyIt->FullName == Entry.second &&
310 "Failed to find the dependency of a checker!");
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!");
320 CheckerIt->WeakDependencies.emplace_back(&*DependencyIt);
322 CheckerIt->Dependencies.emplace_back(&*DependencyIt);
331 StringRef Dependency) {
332 Data.WeakDependencies.emplace_back(
FullName, Dependency);
360 StringRef SuppliedValue = It.first->getValue();
363 if (SuppliedValue !=
"true" && SuppliedValue !=
"false") {
365 Diags.
Report(diag::err_analyzer_checker_option_invalid_input)
366 << FullOption <<
"a boolean value";
376 bool HasFailed = SuppliedValue.getAsInteger(0, Tmp);
379 Diags.
Report(diag::err_analyzer_checker_option_invalid_input)
380 << FullOption <<
"an integer value";
395 assert(It != Collection.end() &&
396 "Failed to find the checker while attempting to add a command line "
401 It->CmdLineOptions.emplace_back(Option);
404void CheckerRegistry::resolveCheckerAndPackageOptions() {
405 for (
const std::pair<StringRef, CmdLineOption> &CheckerOptEntry :
406 Data.CheckerOptions) {
408 CheckerOptEntry.second, AnOpts, Diags);
411 for (
const std::pair<StringRef, CmdLineOption> &PackageOptEntry :
412 Data.PackageOptions) {
414 PackageOptEntry.second, AnOpts, Diags);
423 StringRef PackageFullName,
424 StringRef OptionName,
425 StringRef DefaultValStr,
426 StringRef Description,
427 StringRef DevelopmentStatus,
429 Data.PackageOptions.emplace_back(
430 PackageFullName,
CmdLineOption{OptionType, OptionName, DefaultValStr,
431 Description, DevelopmentStatus, IsHidden});
436 StringRef Desc, StringRef DocsUri,
438 Data.Checkers.emplace_back(Rfn, Sfn, Name, Desc, DocsUri, IsHidden);
441 StringRef PackageName, LeafName;
443 while (!LeafName.empty()) {
444 Data.PackageSizes[PackageName] += 1;
450 StringRef CheckerFullName,
451 StringRef OptionName,
452 StringRef DefaultValStr,
453 StringRef Description,
454 StringRef DevelopmentStatus,
456 Data.CheckerOptions.emplace_back(
457 CheckerFullName,
CmdLineOption{OptionType, OptionName, DefaultValStr,
458 Description, DevelopmentStatus, IsHidden});
465 Checker->Initialize(CheckerMgr);
470 StringRef SuppliedChecker,
471 StringRef SuppliedOption,
478 auto SameOptName = [SuppliedOption](
const CmdLineOption &Opt) {
479 return Opt.OptionName == SuppliedOption;
482 if (llvm::none_of(OptionList, SameOptName)) {
483 Diags.
Report(diag::err_analyzer_checker_option_unknown)
484 << SuppliedChecker << SuppliedOption;
490 for (
const auto &Config : AnOpts.
Config) {
492 StringRef SuppliedCheckerOrPackage;
493 StringRef SuppliedOption;
494 std::tie(SuppliedCheckerOrPackage, SuppliedOption) =
495 Config.getKey().split(
':');
497 if (SuppliedOption.empty())
510 if (CheckerIt !=
Data.Checkers.end()) {
512 SuppliedOption, AnOpts, Diags);
516 const auto *PackageIt =
518 if (PackageIt !=
Data.Packages.end()) {
520 SuppliedOption, AnOpts, Diags);
524 Diags.
Report(diag::err_unknown_analyzer_checker_or_package)
525 << 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, 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.