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/StringMap.h" 190b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h" 200b57cec5SDimitry Andric #include "llvm/Support/DynamicLibrary.h" 210b57cec5SDimitry Andric #include "llvm/Support/Path.h" 220b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 230b57cec5SDimitry Andric #include <algorithm> 240b57cec5SDimitry Andric 250b57cec5SDimitry Andric using namespace clang; 260b57cec5SDimitry Andric using namespace ento; 275ffd83dbSDimitry Andric using namespace checker_registry; 280b57cec5SDimitry Andric using llvm::sys::DynamicLibrary; 290b57cec5SDimitry Andric 305ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 315ffd83dbSDimitry Andric // Utilities. 325ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 330b57cec5SDimitry Andric 340b57cec5SDimitry Andric static bool isCompatibleAPIVersion(const char *VersionString) { 350b57cec5SDimitry Andric // If the version string is null, its not an analyzer plugin. 360b57cec5SDimitry Andric if (!VersionString) 370b57cec5SDimitry Andric return false; 380b57cec5SDimitry Andric 390b57cec5SDimitry Andric // For now, none of the static analyzer API is considered stable. 400b57cec5SDimitry Andric // Versions must match exactly. 410b57cec5SDimitry Andric return strcmp(VersionString, CLANG_ANALYZER_API_VERSION_STRING) == 0; 420b57cec5SDimitry Andric } 430b57cec5SDimitry Andric 440b57cec5SDimitry Andric static constexpr char PackageSeparator = '.'; 450b57cec5SDimitry Andric 465ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 475ffd83dbSDimitry Andric // Methods of CheckerRegistry. 485ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 490b57cec5SDimitry Andric 500b57cec5SDimitry Andric CheckerRegistry::CheckerRegistry( 515ffd83dbSDimitry Andric CheckerRegistryData &Data, ArrayRef<std::string> Plugins, 525ffd83dbSDimitry Andric DiagnosticsEngine &Diags, AnalyzerOptions &AnOpts, 530b57cec5SDimitry Andric ArrayRef<std::function<void(CheckerRegistry &)>> CheckerRegistrationFns) 545ffd83dbSDimitry Andric : Data(Data), Diags(Diags), AnOpts(AnOpts) { 550b57cec5SDimitry Andric 560b57cec5SDimitry Andric // Register builtin checkers. 570b57cec5SDimitry Andric #define GET_CHECKERS 580b57cec5SDimitry Andric #define CHECKER(FULLNAME, CLASS, HELPTEXT, DOC_URI, IS_HIDDEN) \ 590b57cec5SDimitry Andric addChecker(register##CLASS, shouldRegister##CLASS, FULLNAME, HELPTEXT, \ 600b57cec5SDimitry Andric DOC_URI, IS_HIDDEN); 610b57cec5SDimitry Andric 620b57cec5SDimitry Andric #define GET_PACKAGES 630b57cec5SDimitry Andric #define PACKAGE(FULLNAME) addPackage(FULLNAME); 640b57cec5SDimitry Andric 650b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Checkers/Checkers.inc" 660b57cec5SDimitry Andric #undef CHECKER 670b57cec5SDimitry Andric #undef GET_CHECKERS 680b57cec5SDimitry Andric #undef PACKAGE 690b57cec5SDimitry Andric #undef GET_PACKAGES 700b57cec5SDimitry Andric 710b57cec5SDimitry Andric // Register checkers from plugins. 720b57cec5SDimitry Andric for (const std::string &Plugin : Plugins) { 730b57cec5SDimitry Andric // Get access to the plugin. 740b57cec5SDimitry Andric std::string ErrorMsg; 750b57cec5SDimitry Andric DynamicLibrary Lib = 760b57cec5SDimitry Andric DynamicLibrary::getPermanentLibrary(Plugin.c_str(), &ErrorMsg); 770b57cec5SDimitry Andric if (!Lib.isValid()) { 780b57cec5SDimitry Andric Diags.Report(diag::err_fe_unable_to_load_plugin) << Plugin << ErrorMsg; 790b57cec5SDimitry Andric continue; 800b57cec5SDimitry Andric } 810b57cec5SDimitry Andric 820b57cec5SDimitry Andric // See if its compatible with this build of clang. 830b57cec5SDimitry Andric const char *PluginAPIVersion = static_cast<const char *>( 840b57cec5SDimitry Andric Lib.getAddressOfSymbol("clang_analyzerAPIVersionString")); 850b57cec5SDimitry Andric 860b57cec5SDimitry Andric if (!isCompatibleAPIVersion(PluginAPIVersion)) { 870b57cec5SDimitry Andric Diags.Report(diag::warn_incompatible_analyzer_plugin_api) 880b57cec5SDimitry Andric << llvm::sys::path::filename(Plugin); 890b57cec5SDimitry Andric Diags.Report(diag::note_incompatible_analyzer_plugin_api) 900b57cec5SDimitry Andric << CLANG_ANALYZER_API_VERSION_STRING << PluginAPIVersion; 910b57cec5SDimitry Andric continue; 920b57cec5SDimitry Andric } 930b57cec5SDimitry Andric 945ffd83dbSDimitry Andric using RegisterPluginCheckerFn = void (*)(CheckerRegistry &); 950b57cec5SDimitry Andric // Register its checkers. 965ffd83dbSDimitry Andric RegisterPluginCheckerFn RegisterPluginCheckers = 975ffd83dbSDimitry Andric reinterpret_cast<RegisterPluginCheckerFn>( 980b57cec5SDimitry Andric Lib.getAddressOfSymbol("clang_registerCheckers")); 990b57cec5SDimitry Andric if (RegisterPluginCheckers) 1000b57cec5SDimitry Andric RegisterPluginCheckers(*this); 1010b57cec5SDimitry Andric } 1020b57cec5SDimitry Andric 1030b57cec5SDimitry Andric // Register statically linked checkers, that aren't generated from the tblgen 1040b57cec5SDimitry Andric // file, but rather passed their registry function as a parameter in 1050b57cec5SDimitry Andric // checkerRegistrationFns. 1060b57cec5SDimitry Andric 1070b57cec5SDimitry Andric for (const auto &Fn : CheckerRegistrationFns) 1080b57cec5SDimitry Andric Fn(*this); 1090b57cec5SDimitry Andric 1100b57cec5SDimitry Andric // Sort checkers for efficient collection. 1110b57cec5SDimitry Andric // FIXME: Alphabetical sort puts 'experimental' in the middle. 1120b57cec5SDimitry Andric // Would it be better to name it '~experimental' or something else 1130b57cec5SDimitry Andric // that's ASCIIbetically last? 1145ffd83dbSDimitry Andric llvm::sort(Data.Packages, checker_registry::PackageNameLT{}); 1155ffd83dbSDimitry Andric llvm::sort(Data.Checkers, checker_registry::CheckerNameLT{}); 1160b57cec5SDimitry Andric 1170b57cec5SDimitry Andric #define GET_CHECKER_DEPENDENCIES 1180b57cec5SDimitry Andric 1190b57cec5SDimitry Andric #define CHECKER_DEPENDENCY(FULLNAME, DEPENDENCY) \ 1200b57cec5SDimitry Andric addDependency(FULLNAME, DEPENDENCY); 1210b57cec5SDimitry Andric 1225ffd83dbSDimitry Andric #define GET_CHECKER_WEAK_DEPENDENCIES 1235ffd83dbSDimitry Andric 1245ffd83dbSDimitry Andric #define CHECKER_WEAK_DEPENDENCY(FULLNAME, DEPENDENCY) \ 1255ffd83dbSDimitry Andric addWeakDependency(FULLNAME, DEPENDENCY); 1265ffd83dbSDimitry Andric 1270b57cec5SDimitry Andric #define GET_CHECKER_OPTIONS 1285ffd83dbSDimitry Andric #define CHECKER_OPTION(TYPE, FULLNAME, CMDFLAG, DESC, DEFAULT_VAL, \ 1295ffd83dbSDimitry Andric DEVELOPMENT_STATUS, IS_HIDDEN) \ 1305ffd83dbSDimitry Andric addCheckerOption(TYPE, FULLNAME, CMDFLAG, DEFAULT_VAL, DESC, \ 1315ffd83dbSDimitry Andric DEVELOPMENT_STATUS, IS_HIDDEN); 1320b57cec5SDimitry Andric 1330b57cec5SDimitry Andric #define GET_PACKAGE_OPTIONS 1345ffd83dbSDimitry Andric #define PACKAGE_OPTION(TYPE, FULLNAME, CMDFLAG, DESC, DEFAULT_VAL, \ 1355ffd83dbSDimitry Andric DEVELOPMENT_STATUS, IS_HIDDEN) \ 1365ffd83dbSDimitry Andric addPackageOption(TYPE, FULLNAME, CMDFLAG, DEFAULT_VAL, DESC, \ 1375ffd83dbSDimitry Andric DEVELOPMENT_STATUS, IS_HIDDEN); 1380b57cec5SDimitry Andric 1390b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Checkers/Checkers.inc" 1400b57cec5SDimitry Andric #undef CHECKER_DEPENDENCY 1410b57cec5SDimitry Andric #undef GET_CHECKER_DEPENDENCIES 1425ffd83dbSDimitry Andric #undef CHECKER_WEAK_DEPENDENCY 1435ffd83dbSDimitry Andric #undef GET_CHECKER_WEAK_DEPENDENCIES 1440b57cec5SDimitry Andric #undef CHECKER_OPTION 1450b57cec5SDimitry Andric #undef GET_CHECKER_OPTIONS 1460b57cec5SDimitry Andric #undef PACKAGE_OPTION 1470b57cec5SDimitry Andric #undef GET_PACKAGE_OPTIONS 1480b57cec5SDimitry Andric 1495ffd83dbSDimitry Andric resolveDependencies<true>(); 1505ffd83dbSDimitry Andric resolveDependencies<false>(); 1515ffd83dbSDimitry Andric 1525ffd83dbSDimitry Andric #ifndef NDEBUG 1535ffd83dbSDimitry Andric for (auto &DepPair : Data.Dependencies) { 1545ffd83dbSDimitry Andric for (auto &WeakDepPair : Data.WeakDependencies) { 1555ffd83dbSDimitry Andric // Some assertions to enforce that strong dependencies are relations in 1565ffd83dbSDimitry Andric // between purely modeling checkers, and weak dependencies are about 1575ffd83dbSDimitry Andric // diagnostics. 1585ffd83dbSDimitry Andric assert(WeakDepPair != DepPair && 1595ffd83dbSDimitry Andric "A checker cannot strong and weak depend on the same checker!"); 1605ffd83dbSDimitry Andric assert(WeakDepPair.first != DepPair.second && 1615ffd83dbSDimitry Andric "A strong dependency mustn't have weak dependencies!"); 1625ffd83dbSDimitry Andric assert(WeakDepPair.second != DepPair.second && 1635ffd83dbSDimitry Andric "A strong dependency mustn't be a weak dependency as well!"); 1645ffd83dbSDimitry Andric } 1655ffd83dbSDimitry Andric } 1665ffd83dbSDimitry Andric #endif 1675ffd83dbSDimitry Andric 1680b57cec5SDimitry Andric resolveCheckerAndPackageOptions(); 1690b57cec5SDimitry Andric 1700b57cec5SDimitry Andric // Parse '-analyzer-checker' and '-analyzer-disable-checker' options from the 1710b57cec5SDimitry Andric // command line. 172a7dea167SDimitry Andric for (const std::pair<std::string, bool> &Opt : AnOpts.CheckersAndPackages) { 1730b57cec5SDimitry Andric CheckerInfoListRange CheckerForCmdLineArg = 1745ffd83dbSDimitry Andric Data.getMutableCheckersForCmdLineArg(Opt.first); 1750b57cec5SDimitry Andric 1760b57cec5SDimitry Andric if (CheckerForCmdLineArg.begin() == CheckerForCmdLineArg.end()) { 177a7dea167SDimitry Andric Diags.Report(diag::err_unknown_analyzer_checker_or_package) << Opt.first; 1780b57cec5SDimitry Andric Diags.Report(diag::note_suggest_disabling_all_checkers); 1790b57cec5SDimitry Andric } 1800b57cec5SDimitry Andric 1810b57cec5SDimitry Andric for (CheckerInfo &checker : CheckerForCmdLineArg) { 1820b57cec5SDimitry Andric checker.State = Opt.second ? StateFromCmdLine::State_Enabled 1830b57cec5SDimitry Andric : StateFromCmdLine::State_Disabled; 1840b57cec5SDimitry Andric } 1850b57cec5SDimitry Andric } 1865ffd83dbSDimitry Andric validateCheckerOptions(); 1870b57cec5SDimitry Andric } 1880b57cec5SDimitry Andric 1895ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 1905ffd83dbSDimitry Andric // Dependency resolving. 1915ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 1920b57cec5SDimitry Andric 1935ffd83dbSDimitry Andric template <typename IsEnabledFn> 1945ffd83dbSDimitry Andric static bool collectStrongDependencies(const ConstCheckerInfoList &Deps, 1955ffd83dbSDimitry Andric const CheckerManager &Mgr, 1965ffd83dbSDimitry Andric CheckerInfoSet &Ret, 1975ffd83dbSDimitry Andric IsEnabledFn IsEnabled); 1980b57cec5SDimitry Andric 1995ffd83dbSDimitry Andric /// Collects weak dependencies in \p enabledData.Checkers. 2005ffd83dbSDimitry Andric template <typename IsEnabledFn> 2015ffd83dbSDimitry Andric static void collectWeakDependencies(const ConstCheckerInfoList &Deps, 2025ffd83dbSDimitry Andric const CheckerManager &Mgr, 2035ffd83dbSDimitry Andric CheckerInfoSet &Ret, IsEnabledFn IsEnabled); 2040b57cec5SDimitry Andric 2055ffd83dbSDimitry Andric void CheckerRegistry::initializeRegistry(const CheckerManager &Mgr) { 2065ffd83dbSDimitry Andric // First, we calculate the list of enabled checkers as specified by the 2075ffd83dbSDimitry Andric // invocation. Weak dependencies will not enable their unspecified strong 2085ffd83dbSDimitry Andric // depenencies, but its only after resolving strong dependencies for all 2095ffd83dbSDimitry Andric // checkers when we know whether they will be enabled. 2105ffd83dbSDimitry Andric CheckerInfoSet Tmp; 2115ffd83dbSDimitry Andric auto IsEnabledFromCmdLine = [&](const CheckerInfo *Checker) { 2125ffd83dbSDimitry Andric return !Checker->isDisabled(Mgr); 2135ffd83dbSDimitry Andric }; 2145ffd83dbSDimitry Andric for (const CheckerInfo &Checker : Data.Checkers) { 2155ffd83dbSDimitry Andric if (!Checker.isEnabled(Mgr)) 2160b57cec5SDimitry Andric continue; 2170b57cec5SDimitry Andric 2185ffd83dbSDimitry Andric CheckerInfoSet Deps; 2195ffd83dbSDimitry Andric if (!collectStrongDependencies(Checker.Dependencies, Mgr, Deps, 2205ffd83dbSDimitry Andric IsEnabledFromCmdLine)) { 2215ffd83dbSDimitry Andric // If we failed to enable any of the dependencies, don't enable this 2225ffd83dbSDimitry Andric // checker. 2235ffd83dbSDimitry Andric continue; 2245ffd83dbSDimitry Andric } 2250b57cec5SDimitry Andric 2265ffd83dbSDimitry Andric Tmp.insert(Deps.begin(), Deps.end()); 2275ffd83dbSDimitry Andric 2285ffd83dbSDimitry Andric // Enable the checker. 2295ffd83dbSDimitry Andric Tmp.insert(&Checker); 2305ffd83dbSDimitry Andric } 2315ffd83dbSDimitry Andric 2325ffd83dbSDimitry Andric // Calculate enabled checkers with the correct registration order. As this is 2335ffd83dbSDimitry Andric // done recursively, its arguably cheaper, but for sure less error prone to 2345ffd83dbSDimitry Andric // recalculate from scratch. 2355ffd83dbSDimitry Andric auto IsEnabled = [&](const CheckerInfo *Checker) { 23606c3fb27SDimitry Andric return Tmp.contains(Checker); 2375ffd83dbSDimitry Andric }; 2385ffd83dbSDimitry Andric for (const CheckerInfo &Checker : Data.Checkers) { 2395ffd83dbSDimitry Andric if (!Checker.isEnabled(Mgr)) 2405ffd83dbSDimitry Andric continue; 2415ffd83dbSDimitry Andric 2425ffd83dbSDimitry Andric CheckerInfoSet Deps; 2435ffd83dbSDimitry Andric 2445ffd83dbSDimitry Andric collectWeakDependencies(Checker.WeakDependencies, Mgr, Deps, IsEnabled); 2455ffd83dbSDimitry Andric 2465ffd83dbSDimitry Andric if (!collectStrongDependencies(Checker.Dependencies, Mgr, Deps, 2475ffd83dbSDimitry Andric IsEnabledFromCmdLine)) { 2480b57cec5SDimitry Andric // If we failed to enable any of the dependencies, don't enable this 2490b57cec5SDimitry Andric // checker. 2500b57cec5SDimitry Andric continue; 2510b57cec5SDimitry Andric } 2520b57cec5SDimitry Andric 2530b57cec5SDimitry Andric // Note that set_union also preserves the order of insertion. 2545ffd83dbSDimitry Andric Data.EnabledCheckers.set_union(Deps); 2555ffd83dbSDimitry Andric Data.EnabledCheckers.insert(&Checker); 2565ffd83dbSDimitry Andric } 2570b57cec5SDimitry Andric } 2580b57cec5SDimitry Andric 2595ffd83dbSDimitry Andric template <typename IsEnabledFn> 2605ffd83dbSDimitry Andric static bool collectStrongDependencies(const ConstCheckerInfoList &Deps, 2615ffd83dbSDimitry Andric const CheckerManager &Mgr, 2625ffd83dbSDimitry Andric CheckerInfoSet &Ret, 2635ffd83dbSDimitry Andric IsEnabledFn IsEnabled) { 2645ffd83dbSDimitry Andric 2655ffd83dbSDimitry Andric for (const CheckerInfo *Dependency : Deps) { 2665ffd83dbSDimitry Andric if (!IsEnabled(Dependency)) 2675ffd83dbSDimitry Andric return false; 2685ffd83dbSDimitry Andric 2695ffd83dbSDimitry Andric // Collect dependencies recursively. 2705ffd83dbSDimitry Andric if (!collectStrongDependencies(Dependency->Dependencies, Mgr, Ret, 2715ffd83dbSDimitry Andric IsEnabled)) 2725ffd83dbSDimitry Andric return false; 2735ffd83dbSDimitry Andric Ret.insert(Dependency); 2740b57cec5SDimitry Andric } 2750b57cec5SDimitry Andric 2765ffd83dbSDimitry Andric return true; 2775ffd83dbSDimitry Andric } 2785ffd83dbSDimitry Andric 2795ffd83dbSDimitry Andric template <typename IsEnabledFn> 2805ffd83dbSDimitry Andric static void collectWeakDependencies(const ConstCheckerInfoList &WeakDeps, 2815ffd83dbSDimitry Andric const CheckerManager &Mgr, 2825ffd83dbSDimitry Andric CheckerInfoSet &Ret, 2835ffd83dbSDimitry Andric IsEnabledFn IsEnabled) { 2845ffd83dbSDimitry Andric 2855ffd83dbSDimitry Andric for (const CheckerInfo *Dependency : WeakDeps) { 2865ffd83dbSDimitry Andric // Don't enable this checker if strong dependencies are unsatisfied, but 2875ffd83dbSDimitry Andric // assume that weak dependencies are transitive. 2885ffd83dbSDimitry Andric collectWeakDependencies(Dependency->WeakDependencies, Mgr, Ret, IsEnabled); 2895ffd83dbSDimitry Andric 2905ffd83dbSDimitry Andric if (IsEnabled(Dependency) && 2915ffd83dbSDimitry Andric collectStrongDependencies(Dependency->Dependencies, Mgr, Ret, 2925ffd83dbSDimitry Andric IsEnabled)) 2935ffd83dbSDimitry Andric Ret.insert(Dependency); 2945ffd83dbSDimitry Andric } 2955ffd83dbSDimitry Andric } 2965ffd83dbSDimitry Andric 2975ffd83dbSDimitry Andric template <bool IsWeak> void CheckerRegistry::resolveDependencies() { 2985ffd83dbSDimitry Andric for (const std::pair<StringRef, StringRef> &Entry : 2995ffd83dbSDimitry Andric (IsWeak ? Data.WeakDependencies : Data.Dependencies)) { 3005ffd83dbSDimitry Andric 3015ffd83dbSDimitry Andric auto CheckerIt = binaryFind(Data.Checkers, Entry.first); 3025ffd83dbSDimitry Andric assert(CheckerIt != Data.Checkers.end() && 3035ffd83dbSDimitry Andric CheckerIt->FullName == Entry.first && 3040b57cec5SDimitry Andric "Failed to find the checker while attempting to set up its " 3050b57cec5SDimitry Andric "dependencies!"); 3060b57cec5SDimitry Andric 3075ffd83dbSDimitry Andric auto DependencyIt = binaryFind(Data.Checkers, Entry.second); 3085ffd83dbSDimitry Andric assert(DependencyIt != Data.Checkers.end() && 3090b57cec5SDimitry Andric DependencyIt->FullName == Entry.second && 3100b57cec5SDimitry Andric "Failed to find the dependency of a checker!"); 3110b57cec5SDimitry Andric 3125ffd83dbSDimitry Andric // We do allow diagnostics from unit test/example dependency checkers. 313*5f757f3fSDimitry Andric assert((DependencyIt->FullName.starts_with("test") || 314*5f757f3fSDimitry Andric DependencyIt->FullName.starts_with("example") || IsWeak || 3155ffd83dbSDimitry Andric DependencyIt->IsHidden) && 3165ffd83dbSDimitry Andric "Strong dependencies are modeling checkers, and as such " 3175ffd83dbSDimitry Andric "non-user facing! Mark them hidden in Checkers.td!"); 3185ffd83dbSDimitry Andric 3195ffd83dbSDimitry Andric if (IsWeak) 3205ffd83dbSDimitry Andric CheckerIt->WeakDependencies.emplace_back(&*DependencyIt); 3215ffd83dbSDimitry Andric else 3220b57cec5SDimitry Andric CheckerIt->Dependencies.emplace_back(&*DependencyIt); 3230b57cec5SDimitry Andric } 3240b57cec5SDimitry Andric } 3250b57cec5SDimitry Andric 3260b57cec5SDimitry Andric void CheckerRegistry::addDependency(StringRef FullName, StringRef Dependency) { 3275ffd83dbSDimitry Andric Data.Dependencies.emplace_back(FullName, Dependency); 3280b57cec5SDimitry Andric } 3290b57cec5SDimitry Andric 3305ffd83dbSDimitry Andric void CheckerRegistry::addWeakDependency(StringRef FullName, 3315ffd83dbSDimitry Andric StringRef Dependency) { 3325ffd83dbSDimitry Andric Data.WeakDependencies.emplace_back(FullName, Dependency); 3335ffd83dbSDimitry Andric } 3345ffd83dbSDimitry Andric 3355ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 3365ffd83dbSDimitry Andric // Checker option resolving and validating. 3375ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 3385ffd83dbSDimitry Andric 3390b57cec5SDimitry Andric /// Insert the checker/package option to AnalyzerOptions' config table, and 3400b57cec5SDimitry Andric /// validate it, if the user supplied it on the command line. 3415ffd83dbSDimitry Andric static void insertAndValidate(StringRef FullName, const CmdLineOption &Option, 3420b57cec5SDimitry Andric AnalyzerOptions &AnOpts, 3430b57cec5SDimitry Andric DiagnosticsEngine &Diags) { 3440b57cec5SDimitry Andric 3450b57cec5SDimitry Andric std::string FullOption = (FullName + ":" + Option.OptionName).str(); 3460b57cec5SDimitry Andric 3475ffd83dbSDimitry Andric auto It = 3485ffd83dbSDimitry Andric AnOpts.Config.insert({FullOption, std::string(Option.DefaultValStr)}); 3490b57cec5SDimitry Andric 3500b57cec5SDimitry Andric // Insertation was successful -- CmdLineOption's constructor will validate 3510b57cec5SDimitry Andric // whether values received from plugins or TableGen files are correct. 3520b57cec5SDimitry Andric if (It.second) 3530b57cec5SDimitry Andric return; 3540b57cec5SDimitry Andric 3550b57cec5SDimitry Andric // Insertion failed, the user supplied this package/checker option on the 3560b57cec5SDimitry Andric // command line. If the supplied value is invalid, we'll restore the option 3570b57cec5SDimitry Andric // to it's default value, and if we're in non-compatibility mode, we'll also 3580b57cec5SDimitry Andric // emit an error. 3590b57cec5SDimitry Andric 3600b57cec5SDimitry Andric StringRef SuppliedValue = It.first->getValue(); 3610b57cec5SDimitry Andric 3620b57cec5SDimitry Andric if (Option.OptionType == "bool") { 3630b57cec5SDimitry Andric if (SuppliedValue != "true" && SuppliedValue != "false") { 3640b57cec5SDimitry Andric if (AnOpts.ShouldEmitErrorsOnInvalidConfigValue) { 3650b57cec5SDimitry Andric Diags.Report(diag::err_analyzer_checker_option_invalid_input) 3660b57cec5SDimitry Andric << FullOption << "a boolean value"; 3670b57cec5SDimitry Andric } 3680b57cec5SDimitry Andric 3695ffd83dbSDimitry Andric It.first->setValue(std::string(Option.DefaultValStr)); 3700b57cec5SDimitry Andric } 3710b57cec5SDimitry Andric return; 3720b57cec5SDimitry Andric } 3730b57cec5SDimitry Andric 3740b57cec5SDimitry Andric if (Option.OptionType == "int") { 3750b57cec5SDimitry Andric int Tmp; 3760b57cec5SDimitry Andric bool HasFailed = SuppliedValue.getAsInteger(0, Tmp); 3770b57cec5SDimitry Andric if (HasFailed) { 3780b57cec5SDimitry Andric if (AnOpts.ShouldEmitErrorsOnInvalidConfigValue) { 3790b57cec5SDimitry Andric Diags.Report(diag::err_analyzer_checker_option_invalid_input) 3800b57cec5SDimitry Andric << FullOption << "an integer value"; 3810b57cec5SDimitry Andric } 3820b57cec5SDimitry Andric 3835ffd83dbSDimitry Andric It.first->setValue(std::string(Option.DefaultValStr)); 3840b57cec5SDimitry Andric } 3850b57cec5SDimitry Andric return; 3860b57cec5SDimitry Andric } 3870b57cec5SDimitry Andric } 3880b57cec5SDimitry Andric 3890b57cec5SDimitry Andric template <class T> 3905ffd83dbSDimitry Andric static void insertOptionToCollection(StringRef FullName, T &Collection, 3915ffd83dbSDimitry Andric const CmdLineOption &Option, 3925ffd83dbSDimitry Andric AnalyzerOptions &AnOpts, 3935ffd83dbSDimitry Andric DiagnosticsEngine &Diags) { 3940b57cec5SDimitry Andric auto It = binaryFind(Collection, FullName); 3950b57cec5SDimitry Andric assert(It != Collection.end() && 3960b57cec5SDimitry Andric "Failed to find the checker while attempting to add a command line " 3970b57cec5SDimitry Andric "option to it!"); 3980b57cec5SDimitry Andric 3990b57cec5SDimitry Andric insertAndValidate(FullName, Option, AnOpts, Diags); 4000b57cec5SDimitry Andric 4010b57cec5SDimitry Andric It->CmdLineOptions.emplace_back(Option); 4020b57cec5SDimitry Andric } 4030b57cec5SDimitry Andric 4040b57cec5SDimitry Andric void CheckerRegistry::resolveCheckerAndPackageOptions() { 4050b57cec5SDimitry Andric for (const std::pair<StringRef, CmdLineOption> &CheckerOptEntry : 4065ffd83dbSDimitry Andric Data.CheckerOptions) { 4075ffd83dbSDimitry Andric insertOptionToCollection(CheckerOptEntry.first, Data.Checkers, 4080b57cec5SDimitry Andric CheckerOptEntry.second, AnOpts, Diags); 4090b57cec5SDimitry Andric } 4100b57cec5SDimitry Andric 4110b57cec5SDimitry Andric for (const std::pair<StringRef, CmdLineOption> &PackageOptEntry : 4125ffd83dbSDimitry Andric Data.PackageOptions) { 4135ffd83dbSDimitry Andric insertOptionToCollection(PackageOptEntry.first, Data.Packages, 4140b57cec5SDimitry Andric PackageOptEntry.second, AnOpts, Diags); 4150b57cec5SDimitry Andric } 4160b57cec5SDimitry Andric } 4170b57cec5SDimitry Andric 4180b57cec5SDimitry Andric void CheckerRegistry::addPackage(StringRef FullName) { 4195ffd83dbSDimitry Andric Data.Packages.emplace_back(PackageInfo(FullName)); 4200b57cec5SDimitry Andric } 4210b57cec5SDimitry Andric 4220b57cec5SDimitry Andric void CheckerRegistry::addPackageOption(StringRef OptionType, 4230b57cec5SDimitry Andric StringRef PackageFullName, 4240b57cec5SDimitry Andric StringRef OptionName, 4250b57cec5SDimitry Andric StringRef DefaultValStr, 4260b57cec5SDimitry Andric StringRef Description, 4270b57cec5SDimitry Andric StringRef DevelopmentStatus, 4280b57cec5SDimitry Andric bool IsHidden) { 4295ffd83dbSDimitry Andric Data.PackageOptions.emplace_back( 4300b57cec5SDimitry Andric PackageFullName, CmdLineOption{OptionType, OptionName, DefaultValStr, 4310b57cec5SDimitry Andric Description, DevelopmentStatus, IsHidden}); 4320b57cec5SDimitry Andric } 4330b57cec5SDimitry Andric 4345ffd83dbSDimitry Andric void CheckerRegistry::addChecker(RegisterCheckerFn Rfn, 4350b57cec5SDimitry Andric ShouldRegisterFunction Sfn, StringRef Name, 4360b57cec5SDimitry Andric StringRef Desc, StringRef DocsUri, 4370b57cec5SDimitry Andric bool IsHidden) { 4385ffd83dbSDimitry Andric Data.Checkers.emplace_back(Rfn, Sfn, Name, Desc, DocsUri, IsHidden); 4390b57cec5SDimitry Andric 4400b57cec5SDimitry Andric // Record the presence of the checker in its packages. 4410b57cec5SDimitry Andric StringRef PackageName, LeafName; 4420b57cec5SDimitry Andric std::tie(PackageName, LeafName) = Name.rsplit(PackageSeparator); 4430b57cec5SDimitry Andric while (!LeafName.empty()) { 4445ffd83dbSDimitry Andric Data.PackageSizes[PackageName] += 1; 4450b57cec5SDimitry Andric std::tie(PackageName, LeafName) = PackageName.rsplit(PackageSeparator); 4460b57cec5SDimitry Andric } 4470b57cec5SDimitry Andric } 4480b57cec5SDimitry Andric 4490b57cec5SDimitry Andric void CheckerRegistry::addCheckerOption(StringRef OptionType, 4500b57cec5SDimitry Andric StringRef CheckerFullName, 4510b57cec5SDimitry Andric StringRef OptionName, 4520b57cec5SDimitry Andric StringRef DefaultValStr, 4530b57cec5SDimitry Andric StringRef Description, 4540b57cec5SDimitry Andric StringRef DevelopmentStatus, 4550b57cec5SDimitry Andric bool IsHidden) { 4565ffd83dbSDimitry Andric Data.CheckerOptions.emplace_back( 4570b57cec5SDimitry Andric CheckerFullName, CmdLineOption{OptionType, OptionName, DefaultValStr, 4580b57cec5SDimitry Andric Description, DevelopmentStatus, IsHidden}); 4590b57cec5SDimitry Andric } 4600b57cec5SDimitry Andric 4610b57cec5SDimitry Andric void CheckerRegistry::initializeManager(CheckerManager &CheckerMgr) const { 4620b57cec5SDimitry Andric // Initialize the CheckerManager with all enabled checkers. 4635ffd83dbSDimitry Andric for (const auto *Checker : Data.EnabledCheckers) { 464a7dea167SDimitry Andric CheckerMgr.setCurrentCheckerName(CheckerNameRef(Checker->FullName)); 4650b57cec5SDimitry Andric Checker->Initialize(CheckerMgr); 4660b57cec5SDimitry Andric } 4670b57cec5SDimitry Andric } 4680b57cec5SDimitry Andric 4695ffd83dbSDimitry Andric static void isOptionContainedIn(const CmdLineOptionList &OptionList, 4705ffd83dbSDimitry Andric StringRef SuppliedChecker, 4715ffd83dbSDimitry Andric StringRef SuppliedOption, 4725ffd83dbSDimitry Andric const AnalyzerOptions &AnOpts, 4735ffd83dbSDimitry Andric DiagnosticsEngine &Diags) { 4740b57cec5SDimitry Andric 4750b57cec5SDimitry Andric if (!AnOpts.ShouldEmitErrorsOnInvalidConfigValue) 4760b57cec5SDimitry Andric return; 4770b57cec5SDimitry Andric 4780b57cec5SDimitry Andric auto SameOptName = [SuppliedOption](const CmdLineOption &Opt) { 4790b57cec5SDimitry Andric return Opt.OptionName == SuppliedOption; 4800b57cec5SDimitry Andric }; 4810b57cec5SDimitry Andric 48281ad6265SDimitry Andric if (llvm::none_of(OptionList, SameOptName)) { 4830b57cec5SDimitry Andric Diags.Report(diag::err_analyzer_checker_option_unknown) 4840b57cec5SDimitry Andric << SuppliedChecker << SuppliedOption; 4850b57cec5SDimitry Andric return; 4860b57cec5SDimitry Andric } 4870b57cec5SDimitry Andric } 4880b57cec5SDimitry Andric 4890b57cec5SDimitry Andric void CheckerRegistry::validateCheckerOptions() const { 4900b57cec5SDimitry Andric for (const auto &Config : AnOpts.Config) { 4910b57cec5SDimitry Andric 492a7dea167SDimitry Andric StringRef SuppliedCheckerOrPackage; 4930b57cec5SDimitry Andric StringRef SuppliedOption; 494a7dea167SDimitry Andric std::tie(SuppliedCheckerOrPackage, SuppliedOption) = 495a7dea167SDimitry Andric Config.getKey().split(':'); 4960b57cec5SDimitry Andric 4970b57cec5SDimitry Andric if (SuppliedOption.empty()) 4980b57cec5SDimitry Andric continue; 4990b57cec5SDimitry Andric 5000b57cec5SDimitry Andric // AnalyzerOptions' config table contains the user input, so an entry could 5010b57cec5SDimitry Andric // look like this: 5020b57cec5SDimitry Andric // 5030b57cec5SDimitry Andric // cor:NoFalsePositives=true 5040b57cec5SDimitry Andric // 5050b57cec5SDimitry Andric // Since lower_bound would look for the first element *not less* than "cor", 5060b57cec5SDimitry Andric // it would return with an iterator to the first checker in the core, so we 5070b57cec5SDimitry Andric // we really have to use find here, which uses operator==. 508a7dea167SDimitry Andric auto CheckerIt = 5095ffd83dbSDimitry Andric llvm::find(Data.Checkers, CheckerInfo(SuppliedCheckerOrPackage)); 5105ffd83dbSDimitry Andric if (CheckerIt != Data.Checkers.end()) { 511a7dea167SDimitry Andric isOptionContainedIn(CheckerIt->CmdLineOptions, SuppliedCheckerOrPackage, 5120b57cec5SDimitry Andric SuppliedOption, AnOpts, Diags); 5130b57cec5SDimitry Andric continue; 5140b57cec5SDimitry Andric } 5150b57cec5SDimitry Andric 5165ffd83dbSDimitry Andric const auto *PackageIt = 5175ffd83dbSDimitry Andric llvm::find(Data.Packages, PackageInfo(SuppliedCheckerOrPackage)); 5185ffd83dbSDimitry Andric if (PackageIt != Data.Packages.end()) { 519a7dea167SDimitry Andric isOptionContainedIn(PackageIt->CmdLineOptions, SuppliedCheckerOrPackage, 5200b57cec5SDimitry Andric SuppliedOption, AnOpts, Diags); 5210b57cec5SDimitry Andric continue; 5220b57cec5SDimitry Andric } 5230b57cec5SDimitry Andric 524a7dea167SDimitry Andric Diags.Report(diag::err_unknown_analyzer_checker_or_package) 525a7dea167SDimitry Andric << SuppliedCheckerOrPackage; 5260b57cec5SDimitry Andric } 5270b57cec5SDimitry Andric } 528