xref: /freebsd/contrib/llvm-project/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp (revision 81ad626541db97eb356e2c1d4a20eb2a26a766ab)
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