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 llvm::sys::DynamicLibrary;
43 template <
class T>
struct FullNameLT {
44 bool operator()(
const T &Lhs,
const T &Rhs) {
45 return Lhs.FullName < Rhs.FullName;
49 using PackageNameLT = FullNameLT<CheckerRegistry::PackageInfo>;
50 using CheckerNameLT = FullNameLT<CheckerRegistry::CheckerInfo>;
53 template <
class CheckerOrPackageInfoList>
55 typename std::conditional<std::is_const<CheckerOrPackageInfoList>::value,
56 typename CheckerOrPackageInfoList::const_iterator,
57 typename CheckerOrPackageInfoList::iterator>
::type 58 binaryFind(CheckerOrPackageInfoList &Collection, StringRef FullName) {
60 using CheckerOrPackage =
typename CheckerOrPackageInfoList::value_type;
61 using CheckerOrPackageFullNameLT = FullNameLT<CheckerOrPackage>;
63 assert(std::is_sorted(Collection.begin(), Collection.end(),
64 CheckerOrPackageFullNameLT{}) &&
65 "In order to efficiently gather checkers/packages, this function " 66 "expects them to be already sorted!");
68 return llvm::lower_bound(Collection, CheckerOrPackage(FullName),
69 CheckerOrPackageFullNameLT{});
74 static bool isInPackage(
const CheckerRegistry::CheckerInfo &Checker,
75 StringRef PackageName) {
77 if (!Checker.FullName.startswith(PackageName))
81 if (Checker.FullName.size() == PackageName.size())
92 CheckerRegistry::getMutableCheckersForCmdLineArg(StringRef CmdLineArg) {
96 return {Checkers.end(), Checkers.end()};
102 llvm::StringMap<size_t>::const_iterator PackageSize =
103 PackageSizes.find(CmdLineArg);
105 if (PackageSize != PackageSizes.end())
106 Size = PackageSize->getValue();
108 return {It, It + Size};
115 : Diags(Diags), AnOpts(AnOpts), LangOpts(LangOpts) {
119 #define CHECKER(FULLNAME, CLASS, HELPTEXT, DOC_URI, IS_HIDDEN) \ 120 addChecker(register##CLASS, shouldRegister##CLASS, FULLNAME, HELPTEXT, \ 124 #define PACKAGE(FULLNAME) addPackage(FULLNAME); 126 #include "clang/StaticAnalyzer/Checkers/Checkers.inc" 133 for (
const std::string &Plugin : Plugins) {
135 std::string ErrorMsg;
137 DynamicLibrary::getPermanentLibrary(Plugin.c_str(), &ErrorMsg);
138 if (!Lib.isValid()) {
139 Diags.
Report(diag::err_fe_unable_to_load_plugin) << Plugin << ErrorMsg;
144 const char *PluginAPIVersion =
static_cast<const char *
>(
145 Lib.getAddressOfSymbol(
"clang_analyzerAPIVersionString"));
148 Diags.
Report(diag::warn_incompatible_analyzer_plugin_api)
149 << llvm::sys::path::filename(Plugin);
150 Diags.
Report(diag::note_incompatible_analyzer_plugin_api)
158 Lib.getAddressOfSymbol(
"clang_registerCheckers"));
159 if (RegisterPluginCheckers)
160 RegisterPluginCheckers(*
this);
167 for (
const auto &Fn : CheckerRegistrationFns)
174 llvm::sort(Packages, PackageNameLT{});
175 llvm::sort(Checkers, CheckerNameLT{});
177 #define GET_CHECKER_DEPENDENCIES 179 #define CHECKER_DEPENDENCY(FULLNAME, DEPENDENCY) \ 180 addDependency(FULLNAME, DEPENDENCY); 182 #define GET_CHECKER_OPTIONS 183 #define CHECKER_OPTION(TYPE, FULLNAME, CMDFLAG, DESC, DEFAULT_VAL, DEVELOPMENT_STATUS, IS_HIDDEN) \ 184 addCheckerOption(TYPE, FULLNAME, CMDFLAG, DEFAULT_VAL, DESC, DEVELOPMENT_STATUS, IS_HIDDEN); 186 #define GET_PACKAGE_OPTIONS 187 #define PACKAGE_OPTION(TYPE, FULLNAME, CMDFLAG, DESC, DEFAULT_VAL, DEVELOPMENT_STATUS, IS_HIDDEN) \ 188 addPackageOption(TYPE, FULLNAME, CMDFLAG, DEFAULT_VAL, DESC, DEVELOPMENT_STATUS, IS_HIDDEN); 190 #include "clang/StaticAnalyzer/Checkers/Checkers.inc" 191 #undef CHECKER_DEPENDENCY 192 #undef GET_CHECKER_DEPENDENCIES 193 #undef CHECKER_OPTION 194 #undef GET_CHECKER_OPTIONS 195 #undef PACKAGE_OPTION 196 #undef GET_PACKAGE_OPTIONS 198 resolveDependencies();
199 resolveCheckerAndPackageOptions();
205 getMutableCheckersForCmdLineArg(Opt.first);
207 if (CheckerForCmdLineArg.begin() == CheckerForCmdLineArg.end()) {
208 Diags.
Report(diag::err_unknown_analyzer_checker_or_package) << Opt.first;
209 Diags.
Report(diag::note_suggest_disabling_all_checkers);
212 for (
CheckerInfo &checker : CheckerForCmdLineArg) {
245 for (
const CheckerRegistry::CheckerInfo *Dependency : Deps) {
247 if (Dependency->isDisabled(LO))
254 Ret.insert(Dependency);
264 for (
const CheckerInfo &Checker : Checkers) {
265 if (!Checker.isEnabled(LangOpts))
279 EnabledCheckers.set_union(*Deps);
282 EnabledCheckers.insert(&Checker);
285 return EnabledCheckers;
288 void CheckerRegistry::resolveDependencies() {
289 for (
const std::pair<StringRef, StringRef> &Entry : Dependencies) {
290 auto CheckerIt =
binaryFind(Checkers, Entry.first);
291 assert(CheckerIt != Checkers.end() && CheckerIt->FullName == Entry.first &&
292 "Failed to find the checker while attempting to set up its " 295 auto DependencyIt =
binaryFind(Checkers, Entry.second);
296 assert(DependencyIt != Checkers.end() &&
297 DependencyIt->FullName == Entry.second &&
298 "Failed to find the dependency of a checker!");
300 CheckerIt->Dependencies.emplace_back(&*DependencyIt);
303 Dependencies.clear();
307 Dependencies.emplace_back(FullName, Dependency);
313 const CheckerRegistry::CmdLineOption &Option,
317 std::string FullOption = (FullName +
":" + Option.OptionName).str();
319 auto It = AnOpts.
Config.insert({FullOption, Option.DefaultValStr});
331 StringRef SuppliedValue = It.first->getValue();
333 if (Option.OptionType ==
"bool") {
334 if (SuppliedValue !=
"true" && SuppliedValue !=
"false") {
336 Diags.
Report(diag::err_analyzer_checker_option_invalid_input)
337 << FullOption <<
"a boolean value";
340 It.first->setValue(Option.DefaultValStr);
345 if (Option.OptionType ==
"int") {
347 bool HasFailed = SuppliedValue.getAsInteger(0, Tmp);
350 Diags.
Report(diag::err_analyzer_checker_option_invalid_input)
351 << FullOption <<
"an integer value";
354 It.first->setValue(Option.DefaultValStr);
363 const CheckerRegistry::CmdLineOption &Option,
366 assert(It != Collection.end() &&
367 "Failed to find the checker while attempting to add a command line " 372 It->CmdLineOptions.emplace_back(Option);
375 void CheckerRegistry::resolveCheckerAndPackageOptions() {
376 for (
const std::pair<StringRef, CmdLineOption> &CheckerOptEntry :
379 CheckerOptEntry.second, AnOpts, Diags);
381 CheckerOptions.clear();
383 for (
const std::pair<StringRef, CmdLineOption> &PackageOptEntry :
386 PackageOptEntry.second, AnOpts, Diags);
388 PackageOptions.clear();
396 StringRef PackageFullName,
397 StringRef OptionName,
398 StringRef DefaultValStr,
399 StringRef Description,
400 StringRef DevelopmentStatus,
402 PackageOptions.emplace_back(
403 PackageFullName,
CmdLineOption{OptionType, OptionName, DefaultValStr,
404 Description, DevelopmentStatus, IsHidden});
409 StringRef Desc, StringRef DocsUri,
411 Checkers.emplace_back(Rfn, Sfn, Name, Desc, DocsUri, IsHidden);
414 StringRef PackageName, LeafName;
416 while (!LeafName.empty()) {
417 PackageSizes[PackageName] += 1;
423 StringRef CheckerFullName,
424 StringRef OptionName,
425 StringRef DefaultValStr,
426 StringRef Description,
427 StringRef DevelopmentStatus,
429 CheckerOptions.emplace_back(
430 CheckerFullName,
CmdLineOption{OptionType, OptionName, DefaultValStr,
431 Description, DevelopmentStatus, IsHidden});
439 for (
const auto *
Checker : enabledCheckers) {
441 Checker->Initialize(CheckerMgr);
447 StringRef SuppliedChecker, StringRef SuppliedOption,
453 using CmdLineOption = CheckerRegistry::CmdLineOption;
455 auto SameOptName = [SuppliedOption](
const CmdLineOption &Opt) {
456 return Opt.OptionName == SuppliedOption;
459 auto OptionIt = llvm::find_if(OptionList, SameOptName);
461 if (OptionIt == OptionList.end()) {
462 Diags.
Report(diag::err_analyzer_checker_option_unknown)
463 << SuppliedChecker << SuppliedOption;
469 for (
const auto &Config : AnOpts.
Config) {
471 StringRef SuppliedCheckerOrPackage;
472 StringRef SuppliedOption;
473 std::tie(SuppliedCheckerOrPackage, SuppliedOption) =
474 Config.getKey().split(
':');
476 if (SuppliedOption.empty())
488 llvm::find(Checkers,
CheckerInfo(SuppliedCheckerOrPackage));
489 if (CheckerIt != Checkers.end()) {
491 SuppliedOption, AnOpts, Diags);
496 llvm::find(Packages,
PackageInfo(SuppliedCheckerOrPackage));
497 if (PackageIt != Packages.end()) {
499 SuppliedOption, AnOpts, Diags);
503 Diags.
Report(diag::err_unknown_analyzer_checker_or_package)
504 << SuppliedCheckerOrPackage;
509 size_t MaxNameChars)
const {
512 Out <<
"CHECKERS:\n";
515 size_t OptionFieldWidth = 0;
516 for (
const auto &
Checker : Checkers) {
519 size_t NameLength =
Checker.FullName.size();
520 if (NameLength <= MaxNameChars)
521 OptionFieldWidth =
std::max(OptionFieldWidth, NameLength);
524 const size_t InitialPad = 2;
527 StringRef Description) {
529 InitialPad, OptionFieldWidth);
533 for (
const auto &Checker : Checkers) {
540 if (Checker.IsHidden) {
542 Print(Out, Checker, Checker.Desc);
546 if (Checker.FullName.startswith(
"alpha")) {
549 (
"(Enable only for development!) " + Checker.Desc).str());
554 Print(Out, Checker, Checker.Desc);
562 for (
const auto *i : EnabledCheckers)
563 Out << i->FullName <<
'\n';
567 Out <<
"OVERVIEW: Clang Static Analyzer Checker and Package Option List\n\n";
568 Out <<
"USAGE: -analyzer-config <OPTION1=VALUE,OPTION2=VALUE,...>\n\n";
569 Out <<
" -analyzer-config OPTION1=VALUE, -analyzer-config " 570 "OPTION2=VALUE, ...\n\n";
571 Out <<
"OPTIONS:\n\n";
573 std::multimap<StringRef, const CmdLineOption &> OptionMap;
577 OptionMap.insert({
Checker.FullName, Option});
583 OptionMap.insert({Package.FullName, Option});
587 auto Print = [] (llvm::raw_ostream &Out, StringRef FullOption, StringRef Desc) {
594 for (
const std::pair<const StringRef, const CmdLineOption &> &Entry :
597 std::string FullOption = (Entry.first +
":" + Option.
OptionName).str();
610 Print(Out, FullOption, Desc);
615 Entry.first.startswith(
"alpha")) {
617 Print(Out, FullOption,
618 llvm::Twine(
"(Enable only for development!) " + Desc).str());
623 Print(Out, FullOption, Desc);
Manages a set of available checkers for running a static analysis.
This wrapper is used to ensure that only StringRefs originating from the CheckerRegistry are used as ...
StringRef DevelopmentStatus
void addChecker(InitializationFunction Fn, ShouldRegisterFunction sfn, StringRef FullName, StringRef Desc, StringRef DocsUri, bool IsHidden)
Adds a checker to the registry.
unsigned ShowCheckerHelpDeveloper
void setCurrentCheckerName(CheckerNameRef name)
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
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 printCheckerWithDescList(raw_ostream &Out, size_t MaxNameChars=30) const
Prints the name and description of all checkers in this registry.
void printEnabledCheckerList(raw_ostream &Out) const
#define CLANG_ANALYZER_API_VERSION_STRING
static bool isCompatibleAPIVersion(const char *VersionString)
static void printFormattedEntry(llvm::raw_ostream &Out, std::pair< StringRef, StringRef > EntryDescPair, size_t EntryWidth, size_t InitialPad, size_t MinLineWidth=0)
Convenience function for printing options or checkers and their description in a formatted manner...
__DEVICE__ int max(int __a, int __b)
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
unsigned ShowCheckerHelpAlpha
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified...
Concrete class used by the front-end to report problems and issues.
void addPackage(StringRef FullName)
Adds a package to the registry.
Defines the Diagnostic-related interfaces.
unsigned ShowCheckerOptionList
void(*)(CheckerRegistry &) RegisterCheckersFn
static void insertAndValidate(StringRef FullName, const CheckerRegistry::CmdLineOption &Option, AnalyzerOptions &AnOpts, DiagnosticsEngine &Diags)
Insert the checker/package option to AnalyzerOptions' config table, and validate it, if the user supplied it on the command line.
static void insertOptionToCollection(StringRef FullName, T &Collection, const CheckerRegistry::CmdLineOption &Option, AnalyzerOptions &AnOpts, DiagnosticsEngine &Diags)
static LLVM_NODISCARD llvm::Optional< CheckerRegistry::CheckerInfoSet > collectDependencies(const CheckerRegistry::CheckerInfo &checker, const LangOptions &LO)
Collects dependenies in enabledCheckers. Return None on failure.
void addCheckerOption(StringRef OptionType, StringRef CheckerFullName, StringRef OptionName, StringRef DefaultValStr, StringRef Description, StringRef DevelopmentStatus, bool IsHidden=false)
Registers an option to a given checker.
static bool isInPackage(const CheckerRegistry::CheckerInfo &Checker, StringRef PackageName)
static void isOptionContainedIn(const CheckerRegistry::CmdLineOptionList &OptionList, StringRef SuppliedChecker, StringRef SuppliedOption, const AnalyzerOptions &AnOpts, DiagnosticsEngine &Diags)
llvm::SmallVector< const CheckerInfo *, 0 > ConstCheckerInfoList
static bool Ret(InterpState &S, CodePtr &PC, APValue &Result)
bool(*)(const LangOptions &) ShouldRegisterFunction
ConfigTable Config
A key-value table of use-specified configuration values.
unsigned ShowCheckerOptionDeveloperList
std::vector< std::pair< std::string, bool > > CheckersAndPackages
Pairs of checker/package name and enable/disable.
void printCheckerOptionList(raw_ostream &Out) const
llvm::SmallVector< CmdLineOption, 0 > CmdLineOptionList
llvm::SetVector< const CheckerInfo * > CheckerInfoSet
Dataflow Directional Tag Classes.
llvm::iterator_range< CheckerInfoList::iterator > CheckerInfoListRange
void addDependency(StringRef FullName, StringRef Dependency)
Makes the checker with the full name fullName depends on the checker called dependency.
static bool collectDependenciesImpl(const CheckerRegistry::ConstCheckerInfoList &Deps, const LangOptions &LO, CheckerRegistry::CheckerInfoSet &Ret)
Collects dependencies in ret, returns false on failure.
void(*)(CheckerManager &) InitializationFunction
Initialization functions perform any necessary setup for a checker.
static std::conditional< std::is_const< CheckerOrPackageInfoList >::value, typename CheckerOrPackageInfoList::const_iterator, typename CheckerOrPackageInfoList::iterator >::type binaryFind(CheckerOrPackageInfoList &Collection, StringRef FullName)
CheckerRegistry(ArrayRef< std::string > plugins, DiagnosticsEngine &diags, AnalyzerOptions &AnOpts, const LangOptions &LangOpts, ArrayRef< std::function< void(CheckerRegistry &)>> checkerRegistrationFns={})
Stores options for the analyzer from the command line.
unsigned ShowCheckerOptionAlphaList
Specifies a command line option.
void validateCheckerOptions() const
Check if every option corresponds to a specific checker or package.
unsigned ShouldEmitErrorsOnInvalidConfigValue
static constexpr char PackageSeparator