17 #include "llvm/ADT/STLExtras.h"
18 #include "llvm/ADT/SetVector.h"
19 #include "llvm/ADT/StringMap.h"
20 #include "llvm/ADT/StringRef.h"
21 #include "llvm/Support/DynamicLibrary.h"
22 #include "llvm/Support/Path.h"
23 #include "llvm/Support/raw_ostream.h"
26 using namespace clang;
28 using namespace checker_registry;
29 using llvm::sys::DynamicLibrary;
55 : Data(Data), Diags(Diags), AnOpts(AnOpts) {
59 #define CHECKER(FULLNAME, CLASS, HELPTEXT, DOC_URI, IS_HIDDEN) \
60 addChecker(register##CLASS, shouldRegister##CLASS, FULLNAME, HELPTEXT, \
64 #define PACKAGE(FULLNAME) addPackage(FULLNAME);
66 #include "clang/StaticAnalyzer/Checkers/Checkers.inc"
77 DynamicLibrary::getPermanentLibrary(Plugin.c_str(), &ErrorMsg);
79 Diags.
Report(diag::err_fe_unable_to_load_plugin) << Plugin << ErrorMsg;
84 const char *PluginAPIVersion =
static_cast<const char *
>(
85 Lib.getAddressOfSymbol(
"clang_analyzerAPIVersionString"));
88 Diags.
Report(diag::warn_incompatible_analyzer_plugin_api)
89 << llvm::sys::path::filename(Plugin);
90 Diags.
Report(diag::note_incompatible_analyzer_plugin_api)
97 RegisterPluginCheckerFn RegisterPluginCheckers =
98 reinterpret_cast<RegisterPluginCheckerFn
>(
99 Lib.getAddressOfSymbol(
"clang_registerCheckers"));
100 if (RegisterPluginCheckers)
101 RegisterPluginCheckers(*
this);
108 for (
const auto &Fn : CheckerRegistrationFns)
118 #define GET_CHECKER_DEPENDENCIES
120 #define CHECKER_DEPENDENCY(FULLNAME, DEPENDENCY) \
121 addDependency(FULLNAME, DEPENDENCY);
123 #define GET_CHECKER_WEAK_DEPENDENCIES
125 #define CHECKER_WEAK_DEPENDENCY(FULLNAME, DEPENDENCY) \
126 addWeakDependency(FULLNAME, DEPENDENCY);
128 #define GET_CHECKER_OPTIONS
129 #define CHECKER_OPTION(TYPE, FULLNAME, CMDFLAG, DESC, DEFAULT_VAL, \
130 DEVELOPMENT_STATUS, IS_HIDDEN) \
131 addCheckerOption(TYPE, FULLNAME, CMDFLAG, DEFAULT_VAL, DESC, \
132 DEVELOPMENT_STATUS, IS_HIDDEN);
134 #define GET_PACKAGE_OPTIONS
135 #define PACKAGE_OPTION(TYPE, FULLNAME, CMDFLAG, DESC, DEFAULT_VAL, \
136 DEVELOPMENT_STATUS, IS_HIDDEN) \
137 addPackageOption(TYPE, FULLNAME, CMDFLAG, DEFAULT_VAL, DESC, \
138 DEVELOPMENT_STATUS, IS_HIDDEN);
140 #include "clang/StaticAnalyzer/Checkers/Checkers.inc"
141 #undef CHECKER_DEPENDENCY
142 #undef GET_CHECKER_DEPENDENCIES
143 #undef CHECKER_WEAK_DEPENDENCY
144 #undef GET_CHECKER_WEAK_DEPENDENCIES
145 #undef CHECKER_OPTION
146 #undef GET_CHECKER_OPTIONS
147 #undef PACKAGE_OPTION
148 #undef GET_PACKAGE_OPTIONS
150 resolveDependencies<true>();
151 resolveDependencies<false>();
159 assert(WeakDepPair != DepPair &&
160 "A checker cannot strong and weak depend on the same checker!");
161 assert(WeakDepPair.first != DepPair.second &&
162 "A strong dependency mustn't have weak dependencies!");
163 assert(WeakDepPair.second != DepPair.second &&
164 "A strong dependency mustn't be a weak dependency as well!");
169 resolveCheckerAndPackageOptions();
177 if (CheckerForCmdLineArg.begin() == CheckerForCmdLineArg.end()) {
178 Diags.
Report(diag::err_unknown_analyzer_checker_or_package) << Opt.first;
179 Diags.
Report(diag::note_suggest_disabling_all_checkers);
182 for (
CheckerInfo &checker : CheckerForCmdLineArg) {
194 template <
typename IsEnabledFn>
198 IsEnabledFn IsEnabled);
201 template <
typename IsEnabledFn>
213 return !
Checker->isDisabled(Mgr);
221 IsEnabledFromCmdLine)) {
227 Tmp.insert(Deps.begin(), Deps.end());
237 return llvm::is_contained(Tmp,
Checker);
248 IsEnabledFromCmdLine)) {
260 template <
typename IsEnabledFn>
262 const CheckerManager &Mgr,
264 IsEnabledFn IsEnabled) {
266 for (
const CheckerInfo *Dependency : Deps) {
267 if (!IsEnabled(Dependency))
274 Ret.insert(Dependency);
280 template <
typename IsEnabledFn>
282 const CheckerManager &Mgr,
284 IsEnabledFn IsEnabled) {
286 for (
const CheckerInfo *Dependency : WeakDeps) {
291 if (IsEnabled(Dependency) &&
294 Ret.insert(Dependency);
298 template <
bool IsWeak>
void CheckerRegistry::resolveDependencies() {
299 for (
const std::pair<StringRef, StringRef> &Entry :
303 assert(CheckerIt != Data.
Checkers.end() &&
304 CheckerIt->FullName == Entry.first &&
305 "Failed to find the checker while attempting to set up its "
309 assert(DependencyIt != Data.
Checkers.end() &&
310 DependencyIt->FullName == Entry.second &&
311 "Failed to find the dependency of a checker!");
314 assert((DependencyIt->FullName.startswith(
"test") ||
315 DependencyIt->FullName.startswith(
"example") || IsWeak ||
316 DependencyIt->IsHidden) &&
317 "Strong dependencies are modeling checkers, and as such "
318 "non-user facing! Mark them hidden in Checkers.td!");
321 CheckerIt->WeakDependencies.emplace_back(&*DependencyIt);
323 CheckerIt->Dependencies.emplace_back(&*DependencyIt);
332 StringRef Dependency) {
346 std::string FullOption = (FullName +
":" + Option.OptionName).str();
361 StringRef SuppliedValue = It.first->getValue();
363 if (Option.OptionType ==
"bool") {
364 if (SuppliedValue !=
"true" && SuppliedValue !=
"false") {
366 Diags.
Report(diag::err_analyzer_checker_option_invalid_input)
367 << FullOption <<
"a boolean value";
370 It.first->setValue(
std::string(Option.DefaultValStr));
375 if (Option.OptionType ==
"int") {
377 bool HasFailed = SuppliedValue.getAsInteger(0, Tmp);
380 Diags.
Report(diag::err_analyzer_checker_option_invalid_input)
381 << FullOption <<
"an integer value";
384 It.first->setValue(
std::string(Option.DefaultValStr));
392 const CmdLineOption &Option,
396 assert(It != Collection.end() &&
397 "Failed to find the checker while attempting to add a command line "
402 It->CmdLineOptions.emplace_back(Option);
405 void CheckerRegistry::resolveCheckerAndPackageOptions() {
406 for (
const std::pair<StringRef, CmdLineOption> &CheckerOptEntry :
409 CheckerOptEntry.second, AnOpts, Diags);
412 for (
const std::pair<StringRef, CmdLineOption> &PackageOptEntry :
415 PackageOptEntry.second, AnOpts, Diags);
424 StringRef PackageFullName,
425 StringRef OptionName,
426 StringRef DefaultValStr,
427 StringRef Description,
428 StringRef DevelopmentStatus,
431 PackageFullName,
CmdLineOption{OptionType, OptionName, DefaultValStr,
432 Description, DevelopmentStatus, IsHidden});
437 StringRef Desc, StringRef DocsUri,
439 Data.
Checkers.emplace_back(Rfn, Sfn, Name, Desc, DocsUri, IsHidden);
442 StringRef PackageName, LeafName;
444 while (!LeafName.empty()) {
451 StringRef CheckerFullName,
452 StringRef OptionName,
453 StringRef DefaultValStr,
454 StringRef Description,
455 StringRef DevelopmentStatus,
458 CheckerFullName,
CmdLineOption{OptionType, OptionName, DefaultValStr,
459 Description, DevelopmentStatus, IsHidden});
466 Checker->Initialize(CheckerMgr);
471 StringRef SuppliedChecker,
472 StringRef SuppliedOption,
479 auto SameOptName = [SuppliedOption](
const CmdLineOption &Opt) {
480 return Opt.OptionName == SuppliedOption;
483 const auto *OptionIt = llvm::find_if(OptionList, SameOptName);
485 if (OptionIt == OptionList.end()) {
486 Diags.
Report(diag::err_analyzer_checker_option_unknown)
487 << SuppliedChecker << SuppliedOption;
493 for (
const auto &Config : AnOpts.
Config) {
495 StringRef SuppliedCheckerOrPackage;
496 StringRef SuppliedOption;
497 std::tie(SuppliedCheckerOrPackage, SuppliedOption) =
498 Config.getKey().split(
':');
500 if (SuppliedOption.empty())
513 if (CheckerIt != Data.
Checkers.end()) {
515 SuppliedOption, AnOpts, Diags);
519 const auto *PackageIt =
521 if (PackageIt != Data.
Packages.end()) {
523 SuppliedOption, AnOpts, Diags);
527 Diags.
Report(diag::err_unknown_analyzer_checker_or_package)
528 << SuppliedCheckerOrPackage;