10b57cec5SDimitry Andric //===- CheckerRegistry.cpp - Maintains all available checkers -------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h" 100b57cec5SDimitry Andric #include "clang/Basic/Diagnostic.h" 110b57cec5SDimitry Andric #include "clang/Basic/LLVM.h" 120b57cec5SDimitry Andric #include "clang/Driver/DriverDiagnostic.h" 130b57cec5SDimitry Andric #include "clang/Frontend/FrontendDiagnostic.h" 140b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" 150b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" 160b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/CheckerManager.h" 170b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h" 180b57cec5SDimitry Andric #include "llvm/ADT/SetVector.h" 190b57cec5SDimitry Andric #include "llvm/ADT/StringMap.h" 200b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h" 210b57cec5SDimitry Andric #include "llvm/Support/DynamicLibrary.h" 220b57cec5SDimitry Andric #include "llvm/Support/Path.h" 230b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 240b57cec5SDimitry Andric #include <algorithm> 250b57cec5SDimitry Andric 260b57cec5SDimitry Andric using namespace clang; 270b57cec5SDimitry Andric using namespace ento; 285ffd83dbSDimitry Andric using namespace checker_registry; 290b57cec5SDimitry Andric using llvm::sys::DynamicLibrary; 300b57cec5SDimitry Andric 315ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 325ffd83dbSDimitry Andric // Utilities. 335ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 340b57cec5SDimitry Andric 350b57cec5SDimitry Andric static bool isCompatibleAPIVersion(const char *VersionString) { 360b57cec5SDimitry Andric // If the version string is null, its not an analyzer plugin. 370b57cec5SDimitry Andric if (!VersionString) 380b57cec5SDimitry Andric return false; 390b57cec5SDimitry Andric 400b57cec5SDimitry Andric // For now, none of the static analyzer API is considered stable. 410b57cec5SDimitry Andric // Versions must match exactly. 420b57cec5SDimitry Andric return strcmp(VersionString, CLANG_ANALYZER_API_VERSION_STRING) == 0; 430b57cec5SDimitry Andric } 440b57cec5SDimitry Andric 450b57cec5SDimitry Andric static constexpr char PackageSeparator = '.'; 460b57cec5SDimitry Andric 475ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 485ffd83dbSDimitry Andric // Methods of CheckerRegistry. 495ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 500b57cec5SDimitry Andric 510b57cec5SDimitry Andric CheckerRegistry::CheckerRegistry( 525ffd83dbSDimitry Andric CheckerRegistryData &Data, ArrayRef<std::string> Plugins, 535ffd83dbSDimitry Andric DiagnosticsEngine &Diags, AnalyzerOptions &AnOpts, 540b57cec5SDimitry Andric ArrayRef<std::function<void(CheckerRegistry &)>> CheckerRegistrationFns) 555ffd83dbSDimitry Andric : Data(Data), Diags(Diags), AnOpts(AnOpts) { 560b57cec5SDimitry Andric 570b57cec5SDimitry Andric // Register builtin checkers. 580b57cec5SDimitry Andric #define GET_CHECKERS 590b57cec5SDimitry Andric #define CHECKER(FULLNAME, CLASS, HELPTEXT, DOC_URI, IS_HIDDEN) \ 600b57cec5SDimitry Andric addChecker(register##CLASS, shouldRegister##CLASS, FULLNAME, HELPTEXT, \ 610b57cec5SDimitry Andric DOC_URI, IS_HIDDEN); 620b57cec5SDimitry Andric 630b57cec5SDimitry Andric #define GET_PACKAGES 640b57cec5SDimitry Andric #define PACKAGE(FULLNAME) addPackage(FULLNAME); 650b57cec5SDimitry Andric 660b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Checkers/Checkers.inc" 670b57cec5SDimitry Andric #undef CHECKER 680b57cec5SDimitry Andric #undef GET_CHECKERS 690b57cec5SDimitry Andric #undef PACKAGE 700b57cec5SDimitry Andric #undef GET_PACKAGES 710b57cec5SDimitry Andric 720b57cec5SDimitry Andric // Register checkers from plugins. 730b57cec5SDimitry Andric for (const std::string &Plugin : Plugins) { 740b57cec5SDimitry Andric // Get access to the plugin. 750b57cec5SDimitry Andric std::string ErrorMsg; 760b57cec5SDimitry Andric DynamicLibrary Lib = 770b57cec5SDimitry Andric DynamicLibrary::getPermanentLibrary(Plugin.c_str(), &ErrorMsg); 780b57cec5SDimitry Andric if (!Lib.isValid()) { 790b57cec5SDimitry Andric Diags.Report(diag::err_fe_unable_to_load_plugin) << Plugin << ErrorMsg; 800b57cec5SDimitry Andric continue; 810b57cec5SDimitry Andric } 820b57cec5SDimitry Andric 830b57cec5SDimitry Andric // See if its compatible with this build of clang. 840b57cec5SDimitry Andric const char *PluginAPIVersion = static_cast<const char *>( 850b57cec5SDimitry Andric Lib.getAddressOfSymbol("clang_analyzerAPIVersionString")); 860b57cec5SDimitry Andric 870b57cec5SDimitry Andric if (!isCompatibleAPIVersion(PluginAPIVersion)) { 880b57cec5SDimitry Andric Diags.Report(diag::warn_incompatible_analyzer_plugin_api) 890b57cec5SDimitry Andric << llvm::sys::path::filename(Plugin); 900b57cec5SDimitry Andric Diags.Report(diag::note_incompatible_analyzer_plugin_api) 910b57cec5SDimitry Andric << CLANG_ANALYZER_API_VERSION_STRING << PluginAPIVersion; 920b57cec5SDimitry Andric continue; 930b57cec5SDimitry Andric } 940b57cec5SDimitry Andric 955ffd83dbSDimitry Andric using RegisterPluginCheckerFn = void (*)(CheckerRegistry &); 960b57cec5SDimitry Andric // Register its checkers. 975ffd83dbSDimitry Andric RegisterPluginCheckerFn RegisterPluginCheckers = 985ffd83dbSDimitry Andric reinterpret_cast<RegisterPluginCheckerFn>( 990b57cec5SDimitry Andric Lib.getAddressOfSymbol("clang_registerCheckers")); 1000b57cec5SDimitry Andric if (RegisterPluginCheckers) 1010b57cec5SDimitry Andric RegisterPluginCheckers(*this); 1020b57cec5SDimitry Andric } 1030b57cec5SDimitry Andric 1040b57cec5SDimitry Andric // Register statically linked checkers, that aren't generated from the tblgen 1050b57cec5SDimitry Andric // file, but rather passed their registry function as a parameter in 1060b57cec5SDimitry Andric // checkerRegistrationFns. 1070b57cec5SDimitry Andric 1080b57cec5SDimitry Andric for (const auto &Fn : CheckerRegistrationFns) 1090b57cec5SDimitry Andric Fn(*this); 1100b57cec5SDimitry Andric 1110b57cec5SDimitry Andric // Sort checkers for efficient collection. 1120b57cec5SDimitry Andric // FIXME: Alphabetical sort puts 'experimental' in the middle. 1130b57cec5SDimitry Andric // Would it be better to name it '~experimental' or something else 1140b57cec5SDimitry Andric // that's ASCIIbetically last? 1155ffd83dbSDimitry Andric llvm::sort(Data.Packages, checker_registry::PackageNameLT{}); 1165ffd83dbSDimitry Andric llvm::sort(Data.Checkers, checker_registry::CheckerNameLT{}); 1170b57cec5SDimitry Andric 1180b57cec5SDimitry Andric #define GET_CHECKER_DEPENDENCIES 1190b57cec5SDimitry Andric 1200b57cec5SDimitry Andric #define CHECKER_DEPENDENCY(FULLNAME, DEPENDENCY) \ 1210b57cec5SDimitry Andric addDependency(FULLNAME, DEPENDENCY); 1220b57cec5SDimitry Andric 1235ffd83dbSDimitry Andric #define GET_CHECKER_WEAK_DEPENDENCIES 1245ffd83dbSDimitry Andric 1255ffd83dbSDimitry Andric #define CHECKER_WEAK_DEPENDENCY(FULLNAME, DEPENDENCY) \ 1265ffd83dbSDimitry Andric addWeakDependency(FULLNAME, DEPENDENCY); 1275ffd83dbSDimitry Andric 1280b57cec5SDimitry Andric #define GET_CHECKER_OPTIONS 1295ffd83dbSDimitry Andric #define CHECKER_OPTION(TYPE, FULLNAME, CMDFLAG, DESC, DEFAULT_VAL, \ 1305ffd83dbSDimitry Andric DEVELOPMENT_STATUS, IS_HIDDEN) \ 1315ffd83dbSDimitry Andric addCheckerOption(TYPE, FULLNAME, CMDFLAG, DEFAULT_VAL, DESC, \ 1325ffd83dbSDimitry Andric DEVELOPMENT_STATUS, IS_HIDDEN); 1330b57cec5SDimitry Andric 1340b57cec5SDimitry Andric #define GET_PACKAGE_OPTIONS 1355ffd83dbSDimitry Andric #define PACKAGE_OPTION(TYPE, FULLNAME, CMDFLAG, DESC, DEFAULT_VAL, \ 1365ffd83dbSDimitry Andric DEVELOPMENT_STATUS, IS_HIDDEN) \ 1375ffd83dbSDimitry Andric addPackageOption(TYPE, FULLNAME, CMDFLAG, DEFAULT_VAL, DESC, \ 1385ffd83dbSDimitry Andric DEVELOPMENT_STATUS, IS_HIDDEN); 1390b57cec5SDimitry Andric 1400b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Checkers/Checkers.inc" 1410b57cec5SDimitry Andric #undef CHECKER_DEPENDENCY 1420b57cec5SDimitry Andric #undef GET_CHECKER_DEPENDENCIES 1435ffd83dbSDimitry Andric #undef CHECKER_WEAK_DEPENDENCY 1445ffd83dbSDimitry Andric #undef GET_CHECKER_WEAK_DEPENDENCIES 1450b57cec5SDimitry Andric #undef CHECKER_OPTION 1460b57cec5SDimitry Andric #undef GET_CHECKER_OPTIONS 1470b57cec5SDimitry Andric #undef PACKAGE_OPTION 1480b57cec5SDimitry Andric #undef GET_PACKAGE_OPTIONS 1490b57cec5SDimitry Andric 1505ffd83dbSDimitry Andric resolveDependencies<true>(); 1515ffd83dbSDimitry Andric resolveDependencies<false>(); 1525ffd83dbSDimitry Andric 1535ffd83dbSDimitry Andric #ifndef NDEBUG 1545ffd83dbSDimitry Andric for (auto &DepPair : Data.Dependencies) { 1555ffd83dbSDimitry Andric for (auto &WeakDepPair : Data.WeakDependencies) { 1565ffd83dbSDimitry Andric // Some assertions to enforce that strong dependencies are relations in 1575ffd83dbSDimitry Andric // between purely modeling checkers, and weak dependencies are about 1585ffd83dbSDimitry Andric // diagnostics. 1595ffd83dbSDimitry Andric assert(WeakDepPair != DepPair && 1605ffd83dbSDimitry Andric "A checker cannot strong and weak depend on the same checker!"); 1615ffd83dbSDimitry Andric assert(WeakDepPair.first != DepPair.second && 1625ffd83dbSDimitry Andric "A strong dependency mustn't have weak dependencies!"); 1635ffd83dbSDimitry Andric assert(WeakDepPair.second != DepPair.second && 1645ffd83dbSDimitry Andric "A strong dependency mustn't be a weak dependency as well!"); 1655ffd83dbSDimitry Andric } 1665ffd83dbSDimitry Andric } 1675ffd83dbSDimitry Andric #endif 1685ffd83dbSDimitry Andric 1690b57cec5SDimitry Andric resolveCheckerAndPackageOptions(); 1700b57cec5SDimitry Andric 1710b57cec5SDimitry Andric // Parse '-analyzer-checker' and '-analyzer-disable-checker' options from the 1720b57cec5SDimitry Andric // command line. 173a7dea167SDimitry Andric for (const std::pair<std::string, bool> &Opt : AnOpts.CheckersAndPackages) { 1740b57cec5SDimitry Andric CheckerInfoListRange CheckerForCmdLineArg = 1755ffd83dbSDimitry Andric Data.getMutableCheckersForCmdLineArg(Opt.first); 1760b57cec5SDimitry Andric 1770b57cec5SDimitry Andric if (CheckerForCmdLineArg.begin() == CheckerForCmdLineArg.end()) { 178a7dea167SDimitry Andric Diags.Report(diag::err_unknown_analyzer_checker_or_package) << Opt.first; 1790b57cec5SDimitry Andric Diags.Report(diag::note_suggest_disabling_all_checkers); 1800b57cec5SDimitry Andric } 1810b57cec5SDimitry Andric 1820b57cec5SDimitry Andric for (CheckerInfo &checker : CheckerForCmdLineArg) { 1830b57cec5SDimitry Andric checker.State = Opt.second ? StateFromCmdLine::State_Enabled 1840b57cec5SDimitry Andric : StateFromCmdLine::State_Disabled; 1850b57cec5SDimitry Andric } 1860b57cec5SDimitry Andric } 1875ffd83dbSDimitry Andric validateCheckerOptions(); 1880b57cec5SDimitry Andric } 1890b57cec5SDimitry Andric 1905ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 1915ffd83dbSDimitry Andric // Dependency resolving. 1925ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 1930b57cec5SDimitry Andric 1945ffd83dbSDimitry Andric template <typename IsEnabledFn> 1955ffd83dbSDimitry Andric static bool collectStrongDependencies(const ConstCheckerInfoList &Deps, 1965ffd83dbSDimitry Andric const CheckerManager &Mgr, 1975ffd83dbSDimitry Andric CheckerInfoSet &Ret, 1985ffd83dbSDimitry Andric IsEnabledFn IsEnabled); 1990b57cec5SDimitry Andric 2005ffd83dbSDimitry Andric /// Collects weak dependencies in \p enabledData.Checkers. 2015ffd83dbSDimitry Andric template <typename IsEnabledFn> 2025ffd83dbSDimitry Andric static void collectWeakDependencies(const ConstCheckerInfoList &Deps, 2035ffd83dbSDimitry Andric const CheckerManager &Mgr, 2045ffd83dbSDimitry Andric CheckerInfoSet &Ret, IsEnabledFn IsEnabled); 2050b57cec5SDimitry Andric 2065ffd83dbSDimitry Andric void CheckerRegistry::initializeRegistry(const CheckerManager &Mgr) { 2075ffd83dbSDimitry Andric // First, we calculate the list of enabled checkers as specified by the 2085ffd83dbSDimitry Andric // invocation. Weak dependencies will not enable their unspecified strong 2095ffd83dbSDimitry Andric // depenencies, but its only after resolving strong dependencies for all 2105ffd83dbSDimitry Andric // checkers when we know whether they will be enabled. 2115ffd83dbSDimitry Andric CheckerInfoSet Tmp; 2125ffd83dbSDimitry Andric auto IsEnabledFromCmdLine = [&](const CheckerInfo *Checker) { 2135ffd83dbSDimitry Andric return !Checker->isDisabled(Mgr); 2145ffd83dbSDimitry Andric }; 2155ffd83dbSDimitry Andric for (const CheckerInfo &Checker : Data.Checkers) { 2165ffd83dbSDimitry Andric if (!Checker.isEnabled(Mgr)) 2170b57cec5SDimitry Andric continue; 2180b57cec5SDimitry Andric 2195ffd83dbSDimitry Andric CheckerInfoSet Deps; 2205ffd83dbSDimitry Andric if (!collectStrongDependencies(Checker.Dependencies, Mgr, Deps, 2215ffd83dbSDimitry Andric IsEnabledFromCmdLine)) { 2225ffd83dbSDimitry Andric // If we failed to enable any of the dependencies, don't enable this 2235ffd83dbSDimitry Andric // checker. 2245ffd83dbSDimitry Andric continue; 2255ffd83dbSDimitry Andric } 2260b57cec5SDimitry Andric 2275ffd83dbSDimitry Andric Tmp.insert(Deps.begin(), Deps.end()); 2285ffd83dbSDimitry Andric 2295ffd83dbSDimitry Andric // Enable the checker. 2305ffd83dbSDimitry Andric Tmp.insert(&Checker); 2315ffd83dbSDimitry Andric } 2325ffd83dbSDimitry Andric 2335ffd83dbSDimitry Andric // Calculate enabled checkers with the correct registration order. As this is 2345ffd83dbSDimitry Andric // done recursively, its arguably cheaper, but for sure less error prone to 2355ffd83dbSDimitry Andric // recalculate from scratch. 2365ffd83dbSDimitry Andric auto IsEnabled = [&](const CheckerInfo *Checker) { 2375ffd83dbSDimitry Andric return llvm::is_contained(Tmp, Checker); 2385ffd83dbSDimitry Andric }; 2395ffd83dbSDimitry Andric for (const CheckerInfo &Checker : Data.Checkers) { 2405ffd83dbSDimitry Andric if (!Checker.isEnabled(Mgr)) 2415ffd83dbSDimitry Andric continue; 2425ffd83dbSDimitry Andric 2435ffd83dbSDimitry Andric CheckerInfoSet Deps; 2445ffd83dbSDimitry Andric 2455ffd83dbSDimitry Andric collectWeakDependencies(Checker.WeakDependencies, Mgr, Deps, IsEnabled); 2465ffd83dbSDimitry Andric 2475ffd83dbSDimitry Andric if (!collectStrongDependencies(Checker.Dependencies, Mgr, Deps, 2485ffd83dbSDimitry Andric IsEnabledFromCmdLine)) { 2490b57cec5SDimitry Andric // If we failed to enable any of the dependencies, don't enable this 2500b57cec5SDimitry Andric // checker. 2510b57cec5SDimitry Andric continue; 2520b57cec5SDimitry Andric } 2530b57cec5SDimitry Andric 2540b57cec5SDimitry Andric // Note that set_union also preserves the order of insertion. 2555ffd83dbSDimitry Andric Data.EnabledCheckers.set_union(Deps); 2565ffd83dbSDimitry Andric Data.EnabledCheckers.insert(&Checker); 2575ffd83dbSDimitry Andric } 2580b57cec5SDimitry Andric } 2590b57cec5SDimitry Andric 2605ffd83dbSDimitry Andric template <typename IsEnabledFn> 2615ffd83dbSDimitry Andric static bool collectStrongDependencies(const ConstCheckerInfoList &Deps, 2625ffd83dbSDimitry Andric const CheckerManager &Mgr, 2635ffd83dbSDimitry Andric CheckerInfoSet &Ret, 2645ffd83dbSDimitry Andric IsEnabledFn IsEnabled) { 2655ffd83dbSDimitry Andric 2665ffd83dbSDimitry Andric for (const CheckerInfo *Dependency : Deps) { 2675ffd83dbSDimitry Andric if (!IsEnabled(Dependency)) 2685ffd83dbSDimitry Andric return false; 2695ffd83dbSDimitry Andric 2705ffd83dbSDimitry Andric // Collect dependencies recursively. 2715ffd83dbSDimitry Andric if (!collectStrongDependencies(Dependency->Dependencies, Mgr, Ret, 2725ffd83dbSDimitry Andric IsEnabled)) 2735ffd83dbSDimitry Andric return false; 2745ffd83dbSDimitry Andric Ret.insert(Dependency); 2750b57cec5SDimitry Andric } 2760b57cec5SDimitry Andric 2775ffd83dbSDimitry Andric return true; 2785ffd83dbSDimitry Andric } 2795ffd83dbSDimitry Andric 2805ffd83dbSDimitry Andric template <typename IsEnabledFn> 2815ffd83dbSDimitry Andric static void collectWeakDependencies(const ConstCheckerInfoList &WeakDeps, 2825ffd83dbSDimitry Andric const CheckerManager &Mgr, 2835ffd83dbSDimitry Andric CheckerInfoSet &Ret, 2845ffd83dbSDimitry Andric IsEnabledFn IsEnabled) { 2855ffd83dbSDimitry Andric 2865ffd83dbSDimitry Andric for (const CheckerInfo *Dependency : WeakDeps) { 2875ffd83dbSDimitry Andric // Don't enable this checker if strong dependencies are unsatisfied, but 2885ffd83dbSDimitry Andric // assume that weak dependencies are transitive. 2895ffd83dbSDimitry Andric collectWeakDependencies(Dependency->WeakDependencies, Mgr, Ret, IsEnabled); 2905ffd83dbSDimitry Andric 2915ffd83dbSDimitry Andric if (IsEnabled(Dependency) && 2925ffd83dbSDimitry Andric collectStrongDependencies(Dependency->Dependencies, Mgr, Ret, 2935ffd83dbSDimitry Andric IsEnabled)) 2945ffd83dbSDimitry Andric Ret.insert(Dependency); 2955ffd83dbSDimitry Andric } 2965ffd83dbSDimitry Andric } 2975ffd83dbSDimitry Andric 2985ffd83dbSDimitry Andric template <bool IsWeak> void CheckerRegistry::resolveDependencies() { 2995ffd83dbSDimitry Andric for (const std::pair<StringRef, StringRef> &Entry : 3005ffd83dbSDimitry Andric (IsWeak ? Data.WeakDependencies : Data.Dependencies)) { 3015ffd83dbSDimitry Andric 3025ffd83dbSDimitry Andric auto CheckerIt = binaryFind(Data.Checkers, Entry.first); 3035ffd83dbSDimitry Andric assert(CheckerIt != Data.Checkers.end() && 3045ffd83dbSDimitry Andric CheckerIt->FullName == Entry.first && 3050b57cec5SDimitry Andric "Failed to find the checker while attempting to set up its " 3060b57cec5SDimitry Andric "dependencies!"); 3070b57cec5SDimitry Andric 3085ffd83dbSDimitry Andric auto DependencyIt = binaryFind(Data.Checkers, Entry.second); 3095ffd83dbSDimitry Andric assert(DependencyIt != Data.Checkers.end() && 3100b57cec5SDimitry Andric DependencyIt->FullName == Entry.second && 3110b57cec5SDimitry Andric "Failed to find the dependency of a checker!"); 3120b57cec5SDimitry Andric 3135ffd83dbSDimitry Andric // We do allow diagnostics from unit test/example dependency checkers. 3145ffd83dbSDimitry Andric assert((DependencyIt->FullName.startswith("test") || 3155ffd83dbSDimitry Andric DependencyIt->FullName.startswith("example") || IsWeak || 3165ffd83dbSDimitry Andric DependencyIt->IsHidden) && 3175ffd83dbSDimitry Andric "Strong dependencies are modeling checkers, and as such " 3185ffd83dbSDimitry Andric "non-user facing! Mark them hidden in Checkers.td!"); 3195ffd83dbSDimitry Andric 3205ffd83dbSDimitry Andric if (IsWeak) 3215ffd83dbSDimitry Andric CheckerIt->WeakDependencies.emplace_back(&*DependencyIt); 3225ffd83dbSDimitry Andric else 3230b57cec5SDimitry Andric CheckerIt->Dependencies.emplace_back(&*DependencyIt); 3240b57cec5SDimitry Andric } 3250b57cec5SDimitry Andric } 3260b57cec5SDimitry Andric 3270b57cec5SDimitry Andric void CheckerRegistry::addDependency(StringRef FullName, StringRef Dependency) { 3285ffd83dbSDimitry Andric Data.Dependencies.emplace_back(FullName, Dependency); 3290b57cec5SDimitry Andric } 3300b57cec5SDimitry Andric 3315ffd83dbSDimitry Andric void CheckerRegistry::addWeakDependency(StringRef FullName, 3325ffd83dbSDimitry Andric StringRef Dependency) { 3335ffd83dbSDimitry Andric Data.WeakDependencies.emplace_back(FullName, Dependency); 3345ffd83dbSDimitry Andric } 3355ffd83dbSDimitry Andric 3365ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 3375ffd83dbSDimitry Andric // Checker option resolving and validating. 3385ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 3395ffd83dbSDimitry Andric 3400b57cec5SDimitry Andric /// Insert the checker/package option to AnalyzerOptions' config table, and 3410b57cec5SDimitry Andric /// validate it, if the user supplied it on the command line. 3425ffd83dbSDimitry Andric static void insertAndValidate(StringRef FullName, const CmdLineOption &Option, 3430b57cec5SDimitry Andric AnalyzerOptions &AnOpts, 3440b57cec5SDimitry Andric DiagnosticsEngine &Diags) { 3450b57cec5SDimitry Andric 3460b57cec5SDimitry Andric std::string FullOption = (FullName + ":" + Option.OptionName).str(); 3470b57cec5SDimitry Andric 3485ffd83dbSDimitry Andric auto It = 3495ffd83dbSDimitry Andric AnOpts.Config.insert({FullOption, std::string(Option.DefaultValStr)}); 3500b57cec5SDimitry Andric 3510b57cec5SDimitry Andric // Insertation was successful -- CmdLineOption's constructor will validate 3520b57cec5SDimitry Andric // whether values received from plugins or TableGen files are correct. 3530b57cec5SDimitry Andric if (It.second) 3540b57cec5SDimitry Andric return; 3550b57cec5SDimitry Andric 3560b57cec5SDimitry Andric // Insertion failed, the user supplied this package/checker option on the 3570b57cec5SDimitry Andric // command line. If the supplied value is invalid, we'll restore the option 3580b57cec5SDimitry Andric // to it's default value, and if we're in non-compatibility mode, we'll also 3590b57cec5SDimitry Andric // emit an error. 3600b57cec5SDimitry Andric 3610b57cec5SDimitry Andric StringRef SuppliedValue = It.first->getValue(); 3620b57cec5SDimitry Andric 3630b57cec5SDimitry Andric if (Option.OptionType == "bool") { 3640b57cec5SDimitry Andric if (SuppliedValue != "true" && SuppliedValue != "false") { 3650b57cec5SDimitry Andric if (AnOpts.ShouldEmitErrorsOnInvalidConfigValue) { 3660b57cec5SDimitry Andric Diags.Report(diag::err_analyzer_checker_option_invalid_input) 3670b57cec5SDimitry Andric << FullOption << "a boolean value"; 3680b57cec5SDimitry Andric } 3690b57cec5SDimitry Andric 3705ffd83dbSDimitry Andric It.first->setValue(std::string(Option.DefaultValStr)); 3710b57cec5SDimitry Andric } 3720b57cec5SDimitry Andric return; 3730b57cec5SDimitry Andric } 3740b57cec5SDimitry Andric 3750b57cec5SDimitry Andric if (Option.OptionType == "int") { 3760b57cec5SDimitry Andric int Tmp; 3770b57cec5SDimitry Andric bool HasFailed = SuppliedValue.getAsInteger(0, Tmp); 3780b57cec5SDimitry Andric if (HasFailed) { 3790b57cec5SDimitry Andric if (AnOpts.ShouldEmitErrorsOnInvalidConfigValue) { 3800b57cec5SDimitry Andric Diags.Report(diag::err_analyzer_checker_option_invalid_input) 3810b57cec5SDimitry Andric << FullOption << "an integer value"; 3820b57cec5SDimitry Andric } 3830b57cec5SDimitry Andric 3845ffd83dbSDimitry Andric It.first->setValue(std::string(Option.DefaultValStr)); 3850b57cec5SDimitry Andric } 3860b57cec5SDimitry Andric return; 3870b57cec5SDimitry Andric } 3880b57cec5SDimitry Andric } 3890b57cec5SDimitry Andric 3900b57cec5SDimitry Andric template <class T> 3915ffd83dbSDimitry Andric static void insertOptionToCollection(StringRef FullName, T &Collection, 3925ffd83dbSDimitry Andric const CmdLineOption &Option, 3935ffd83dbSDimitry Andric AnalyzerOptions &AnOpts, 3945ffd83dbSDimitry Andric DiagnosticsEngine &Diags) { 3950b57cec5SDimitry Andric auto It = binaryFind(Collection, FullName); 3960b57cec5SDimitry Andric assert(It != Collection.end() && 3970b57cec5SDimitry Andric "Failed to find the checker while attempting to add a command line " 3980b57cec5SDimitry Andric "option to it!"); 3990b57cec5SDimitry Andric 4000b57cec5SDimitry Andric insertAndValidate(FullName, Option, AnOpts, Diags); 4010b57cec5SDimitry Andric 4020b57cec5SDimitry Andric It->CmdLineOptions.emplace_back(Option); 4030b57cec5SDimitry Andric } 4040b57cec5SDimitry Andric 4050b57cec5SDimitry Andric void CheckerRegistry::resolveCheckerAndPackageOptions() { 4060b57cec5SDimitry Andric for (const std::pair<StringRef, CmdLineOption> &CheckerOptEntry : 4075ffd83dbSDimitry Andric Data.CheckerOptions) { 4085ffd83dbSDimitry Andric insertOptionToCollection(CheckerOptEntry.first, Data.Checkers, 4090b57cec5SDimitry Andric CheckerOptEntry.second, AnOpts, Diags); 4100b57cec5SDimitry Andric } 4110b57cec5SDimitry Andric 4120b57cec5SDimitry Andric for (const std::pair<StringRef, CmdLineOption> &PackageOptEntry : 4135ffd83dbSDimitry Andric Data.PackageOptions) { 4145ffd83dbSDimitry Andric insertOptionToCollection(PackageOptEntry.first, Data.Packages, 4150b57cec5SDimitry Andric PackageOptEntry.second, AnOpts, Diags); 4160b57cec5SDimitry Andric } 4170b57cec5SDimitry Andric } 4180b57cec5SDimitry Andric 4190b57cec5SDimitry Andric void CheckerRegistry::addPackage(StringRef FullName) { 4205ffd83dbSDimitry Andric Data.Packages.emplace_back(PackageInfo(FullName)); 4210b57cec5SDimitry Andric } 4220b57cec5SDimitry Andric 4230b57cec5SDimitry Andric void CheckerRegistry::addPackageOption(StringRef OptionType, 4240b57cec5SDimitry Andric StringRef PackageFullName, 4250b57cec5SDimitry Andric StringRef OptionName, 4260b57cec5SDimitry Andric StringRef DefaultValStr, 4270b57cec5SDimitry Andric StringRef Description, 4280b57cec5SDimitry Andric StringRef DevelopmentStatus, 4290b57cec5SDimitry Andric bool IsHidden) { 4305ffd83dbSDimitry Andric Data.PackageOptions.emplace_back( 4310b57cec5SDimitry Andric PackageFullName, CmdLineOption{OptionType, OptionName, DefaultValStr, 4320b57cec5SDimitry Andric Description, DevelopmentStatus, IsHidden}); 4330b57cec5SDimitry Andric } 4340b57cec5SDimitry Andric 4355ffd83dbSDimitry Andric void CheckerRegistry::addChecker(RegisterCheckerFn Rfn, 4360b57cec5SDimitry Andric ShouldRegisterFunction Sfn, StringRef Name, 4370b57cec5SDimitry Andric StringRef Desc, StringRef DocsUri, 4380b57cec5SDimitry Andric bool IsHidden) { 4395ffd83dbSDimitry Andric Data.Checkers.emplace_back(Rfn, Sfn, Name, Desc, DocsUri, IsHidden); 4400b57cec5SDimitry Andric 4410b57cec5SDimitry Andric // Record the presence of the checker in its packages. 4420b57cec5SDimitry Andric StringRef PackageName, LeafName; 4430b57cec5SDimitry Andric std::tie(PackageName, LeafName) = Name.rsplit(PackageSeparator); 4440b57cec5SDimitry Andric while (!LeafName.empty()) { 4455ffd83dbSDimitry Andric Data.PackageSizes[PackageName] += 1; 4460b57cec5SDimitry Andric std::tie(PackageName, LeafName) = PackageName.rsplit(PackageSeparator); 4470b57cec5SDimitry Andric } 4480b57cec5SDimitry Andric } 4490b57cec5SDimitry Andric 4500b57cec5SDimitry Andric void CheckerRegistry::addCheckerOption(StringRef OptionType, 4510b57cec5SDimitry Andric StringRef CheckerFullName, 4520b57cec5SDimitry Andric StringRef OptionName, 4530b57cec5SDimitry Andric StringRef DefaultValStr, 4540b57cec5SDimitry Andric StringRef Description, 4550b57cec5SDimitry Andric StringRef DevelopmentStatus, 4560b57cec5SDimitry Andric bool IsHidden) { 4575ffd83dbSDimitry Andric Data.CheckerOptions.emplace_back( 4580b57cec5SDimitry Andric CheckerFullName, CmdLineOption{OptionType, OptionName, DefaultValStr, 4590b57cec5SDimitry Andric Description, DevelopmentStatus, IsHidden}); 4600b57cec5SDimitry Andric } 4610b57cec5SDimitry Andric 4620b57cec5SDimitry Andric void CheckerRegistry::initializeManager(CheckerManager &CheckerMgr) const { 4630b57cec5SDimitry Andric // Initialize the CheckerManager with all enabled checkers. 4645ffd83dbSDimitry Andric for (const auto *Checker : Data.EnabledCheckers) { 465a7dea167SDimitry Andric CheckerMgr.setCurrentCheckerName(CheckerNameRef(Checker->FullName)); 4660b57cec5SDimitry Andric Checker->Initialize(CheckerMgr); 4670b57cec5SDimitry Andric } 4680b57cec5SDimitry Andric } 4690b57cec5SDimitry Andric 4705ffd83dbSDimitry Andric static void isOptionContainedIn(const CmdLineOptionList &OptionList, 4715ffd83dbSDimitry Andric StringRef SuppliedChecker, 4725ffd83dbSDimitry Andric StringRef SuppliedOption, 4735ffd83dbSDimitry Andric const AnalyzerOptions &AnOpts, 4745ffd83dbSDimitry Andric DiagnosticsEngine &Diags) { 4750b57cec5SDimitry Andric 4760b57cec5SDimitry Andric if (!AnOpts.ShouldEmitErrorsOnInvalidConfigValue) 4770b57cec5SDimitry Andric return; 4780b57cec5SDimitry Andric 4790b57cec5SDimitry Andric auto SameOptName = [SuppliedOption](const CmdLineOption &Opt) { 4800b57cec5SDimitry Andric return Opt.OptionName == SuppliedOption; 4810b57cec5SDimitry Andric }; 4820b57cec5SDimitry Andric 483*81ad6265SDimitry Andric if (llvm::none_of(OptionList, SameOptName)) { 4840b57cec5SDimitry Andric Diags.Report(diag::err_analyzer_checker_option_unknown) 4850b57cec5SDimitry Andric << SuppliedChecker << SuppliedOption; 4860b57cec5SDimitry Andric return; 4870b57cec5SDimitry Andric } 4880b57cec5SDimitry Andric } 4890b57cec5SDimitry Andric 4900b57cec5SDimitry Andric void CheckerRegistry::validateCheckerOptions() const { 4910b57cec5SDimitry Andric for (const auto &Config : AnOpts.Config) { 4920b57cec5SDimitry Andric 493a7dea167SDimitry Andric StringRef SuppliedCheckerOrPackage; 4940b57cec5SDimitry Andric StringRef SuppliedOption; 495a7dea167SDimitry Andric std::tie(SuppliedCheckerOrPackage, SuppliedOption) = 496a7dea167SDimitry Andric Config.getKey().split(':'); 4970b57cec5SDimitry Andric 4980b57cec5SDimitry Andric if (SuppliedOption.empty()) 4990b57cec5SDimitry Andric continue; 5000b57cec5SDimitry Andric 5010b57cec5SDimitry Andric // AnalyzerOptions' config table contains the user input, so an entry could 5020b57cec5SDimitry Andric // look like this: 5030b57cec5SDimitry Andric // 5040b57cec5SDimitry Andric // cor:NoFalsePositives=true 5050b57cec5SDimitry Andric // 5060b57cec5SDimitry Andric // Since lower_bound would look for the first element *not less* than "cor", 5070b57cec5SDimitry Andric // it would return with an iterator to the first checker in the core, so we 5080b57cec5SDimitry Andric // we really have to use find here, which uses operator==. 509a7dea167SDimitry Andric auto CheckerIt = 5105ffd83dbSDimitry Andric llvm::find(Data.Checkers, CheckerInfo(SuppliedCheckerOrPackage)); 5115ffd83dbSDimitry Andric if (CheckerIt != Data.Checkers.end()) { 512a7dea167SDimitry Andric isOptionContainedIn(CheckerIt->CmdLineOptions, SuppliedCheckerOrPackage, 5130b57cec5SDimitry Andric SuppliedOption, AnOpts, Diags); 5140b57cec5SDimitry Andric continue; 5150b57cec5SDimitry Andric } 5160b57cec5SDimitry Andric 5175ffd83dbSDimitry Andric const auto *PackageIt = 5185ffd83dbSDimitry Andric llvm::find(Data.Packages, PackageInfo(SuppliedCheckerOrPackage)); 5195ffd83dbSDimitry Andric if (PackageIt != Data.Packages.end()) { 520a7dea167SDimitry Andric isOptionContainedIn(PackageIt->CmdLineOptions, SuppliedCheckerOrPackage, 5210b57cec5SDimitry Andric SuppliedOption, AnOpts, Diags); 5220b57cec5SDimitry Andric continue; 5230b57cec5SDimitry Andric } 5240b57cec5SDimitry Andric 525a7dea167SDimitry Andric Diags.Report(diag::err_unknown_analyzer_checker_or_package) 526a7dea167SDimitry Andric << SuppliedCheckerOrPackage; 5270b57cec5SDimitry Andric } 5280b57cec5SDimitry Andric } 5290b57cec5SDimitry Andric 530