blob: 7eef09b883357ce7fba136521a5c5c14545ada98 [file] [log] [blame]
Eugene Zelenko88f40cf2018-04-03 21:31:50 +00001//===- CheckerRegistry.cpp - Maintains all available checkers -------------===//
Jordy Rose59cce712011-08-16 21:24:21 +00002//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Jordy Rose59cce712011-08-16 21:24:21 +00006//
7//===----------------------------------------------------------------------===//
8
Kristof Umann76a21502018-12-15 16:23:51 +00009#include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h"
Gabor Horvathfc4c4d42015-07-09 21:43:45 +000010#include "clang/Basic/Diagnostic.h"
Eugene Zelenko88f40cf2018-04-03 21:31:50 +000011#include "clang/Basic/LLVM.h"
Kristof Umannb0be2ab2018-12-15 18:11:49 +000012#include "clang/Frontend/FrontendDiagnostic.h"
13#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
Gabor Horvathfc4c4d42015-07-09 21:43:45 +000014#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
Kristof Umanna57d4ea2019-04-18 17:32:51 +000015#include "clang/StaticAnalyzer/Core/CheckerManager.h"
Eugene Zelenko88f40cf2018-04-03 21:31:50 +000016#include "llvm/ADT/STLExtras.h"
Anna Zaks30373152011-12-15 01:36:04 +000017#include "llvm/ADT/SetVector.h"
Eugene Zelenko88f40cf2018-04-03 21:31:50 +000018#include "llvm/ADT/StringMap.h"
19#include "llvm/ADT/StringRef.h"
Kristof Umannb0be2ab2018-12-15 18:11:49 +000020#include "llvm/Support/DynamicLibrary.h"
21#include "llvm/Support/Path.h"
Benjamin Kramer444a1302012-12-01 17:12:56 +000022#include "llvm/Support/raw_ostream.h"
Eugene Zelenko88f40cf2018-04-03 21:31:50 +000023#include <algorithm>
Jordy Rose59cce712011-08-16 21:24:21 +000024
25using namespace clang;
26using namespace ento;
Kristof Umannb0be2ab2018-12-15 18:11:49 +000027using llvm::sys::DynamicLibrary;
28
29using RegisterCheckersFn = void (*)(CheckerRegistry &);
30
Kristof Umannb9bc7ec2019-04-18 15:19:16 +000031static bool isCompatibleAPIVersion(const char *VersionString) {
32 // If the version string is null, its not an analyzer plugin.
33 if (!VersionString)
Kristof Umannb0be2ab2018-12-15 18:11:49 +000034 return false;
35
36 // For now, none of the static analyzer API is considered stable.
37 // Versions must match exactly.
Kristof Umannb9bc7ec2019-04-18 15:19:16 +000038 return strcmp(VersionString, CLANG_ANALYZER_API_VERSION_STRING) == 0;
Kristof Umannb0be2ab2018-12-15 18:11:49 +000039}
40
Kristof Umannb9bc7ec2019-04-18 15:19:16 +000041namespace {
Kristof Umanna57d4ea2019-04-18 17:32:51 +000042template <class T> struct FullNameLT {
Kristof Umannb9bc7ec2019-04-18 15:19:16 +000043 bool operator()(const T &Lhs, const T &Rhs) {
44 return Lhs.FullName < Rhs.FullName;
45 }
46};
47
Kristof Umannb4788b22019-04-19 12:32:10 +000048using PackageNameLT = FullNameLT<CheckerRegistry::PackageInfo>;
Kristof Umannb9bc7ec2019-04-18 15:19:16 +000049using CheckerNameLT = FullNameLT<CheckerRegistry::CheckerInfo>;
50} // end of anonymous namespace
Kristof Umann3daa2452019-01-26 16:35:33 +000051
Kristof Umann640f7b52019-04-18 17:34:45 +000052template <class CheckerOrPackageInfoList>
53static
54 typename std::conditional<std::is_const<CheckerOrPackageInfoList>::value,
55 typename CheckerOrPackageInfoList::const_iterator,
56 typename CheckerOrPackageInfoList::iterator>::type
57 binaryFind(CheckerOrPackageInfoList &Collection, StringRef FullName) {
58
59 using CheckerOrPackage = typename CheckerOrPackageInfoList::value_type;
60 using CheckerOrPackageFullNameLT = FullNameLT<CheckerOrPackage>;
61
62 assert(std::is_sorted(Collection.begin(), Collection.end(),
63 CheckerOrPackageFullNameLT{}) &&
64 "In order to efficiently gather checkers/packages, this function "
65 "expects them to be already sorted!");
66
Fangrui Song92063352019-04-19 01:54:36 +000067 return llvm::lower_bound(Collection, CheckerOrPackage(FullName),
68 CheckerOrPackageFullNameLT{});
Kristof Umann640f7b52019-04-18 17:34:45 +000069}
70
Kristof Umann3daa2452019-01-26 16:35:33 +000071static constexpr char PackageSeparator = '.';
72
Kristof Umannb9bc7ec2019-04-18 15:19:16 +000073static bool isInPackage(const CheckerRegistry::CheckerInfo &Checker,
74 StringRef PackageName) {
Kristof Umann3daa2452019-01-26 16:35:33 +000075 // Does the checker's full name have the package as a prefix?
Kristof Umannb9bc7ec2019-04-18 15:19:16 +000076 if (!Checker.FullName.startswith(PackageName))
Kristof Umann3daa2452019-01-26 16:35:33 +000077 return false;
78
79 // Is the package actually just the name of a specific checker?
Kristof Umannb9bc7ec2019-04-18 15:19:16 +000080 if (Checker.FullName.size() == PackageName.size())
Kristof Umann3daa2452019-01-26 16:35:33 +000081 return true;
82
83 // Is the checker in the package (or a subpackage)?
Kristof Umannb9bc7ec2019-04-18 15:19:16 +000084 if (Checker.FullName[PackageName.size()] == PackageSeparator)
Kristof Umann3daa2452019-01-26 16:35:33 +000085 return true;
86
87 return false;
88}
89
90CheckerRegistry::CheckerInfoListRange
91CheckerRegistry::getMutableCheckersForCmdLineArg(StringRef CmdLineArg) {
Kristof Umann640f7b52019-04-18 17:34:45 +000092 auto It = binaryFind(Checkers, CmdLineArg);
Kristof Umann3daa2452019-01-26 16:35:33 +000093
Kristof Umannb9bc7ec2019-04-18 15:19:16 +000094 if (!isInPackage(*It, CmdLineArg))
Kristof Umanna57d4ea2019-04-18 17:32:51 +000095 return {Checkers.end(), Checkers.end()};
Kristof Umann3daa2452019-01-26 16:35:33 +000096
97 // See how large the package is.
98 // If the package doesn't exist, assume the option refers to a single
99 // checker.
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000100 size_t Size = 1;
101 llvm::StringMap<size_t>::const_iterator PackageSize =
102 PackageSizes.find(CmdLineArg);
Kristof Umann3daa2452019-01-26 16:35:33 +0000103
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000104 if (PackageSize != PackageSizes.end())
105 Size = PackageSize->getValue();
Kristof Umann3daa2452019-01-26 16:35:33 +0000106
Kristof Umanna57d4ea2019-04-18 17:32:51 +0000107 return {It, It + Size};
Kristof Umann3daa2452019-01-26 16:35:33 +0000108}
109
Kristof Umann98217ad2019-01-26 17:27:40 +0000110CheckerRegistry::CheckerRegistry(
Kristof Umanna57d4ea2019-04-18 17:32:51 +0000111 ArrayRef<std::string> Plugins, DiagnosticsEngine &Diags,
112 AnalyzerOptions &AnOpts, const LangOptions &LangOpts,
113 ArrayRef<std::function<void(CheckerRegistry &)>> CheckerRegistrationFns)
114 : Diags(Diags), AnOpts(AnOpts), LangOpts(LangOpts) {
Kristof Umann058a7a42019-01-26 14:23:08 +0000115
Kristof Umann3daa2452019-01-26 16:35:33 +0000116 // Register builtin checkers.
Kristof Umannb0be2ab2018-12-15 18:11:49 +0000117#define GET_CHECKERS
Kristof Umann9f7fc982019-05-01 19:56:47 +0000118#define CHECKER(FULLNAME, CLASS, HELPTEXT, DOC_URI, IS_HIDDEN) \
Kristof Umann058a7a42019-01-26 14:23:08 +0000119 addChecker(register##CLASS, shouldRegister##CLASS, FULLNAME, HELPTEXT, \
Kristof Umann9f7fc982019-05-01 19:56:47 +0000120 DOC_URI, IS_HIDDEN);
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000121
Kristof Umannb4788b22019-04-19 12:32:10 +0000122#define GET_PACKAGES
123#define PACKAGE(FULLNAME) addPackage(FULLNAME);
124
Kristof Umannb0be2ab2018-12-15 18:11:49 +0000125#include "clang/StaticAnalyzer/Checkers/Checkers.inc"
126#undef CHECKER
127#undef GET_CHECKERS
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000128#undef PACKAGE
129#undef GET_PACKAGES
Kristof Umannb0be2ab2018-12-15 18:11:49 +0000130
Kristof Umann3daa2452019-01-26 16:35:33 +0000131 // Register checkers from plugins.
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000132 for (const std::string &Plugin : Plugins) {
Kristof Umannb0be2ab2018-12-15 18:11:49 +0000133 // Get access to the plugin.
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000134 std::string ErrorMsg;
135 DynamicLibrary Lib =
136 DynamicLibrary::getPermanentLibrary(Plugin.c_str(), &ErrorMsg);
137 if (!Lib.isValid()) {
138 Diags.Report(diag::err_fe_unable_to_load_plugin) << Plugin << ErrorMsg;
Kristof Umannb0be2ab2018-12-15 18:11:49 +0000139 continue;
140 }
141
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000142 // See if its compatible with this build of clang.
143 const char *PluginAPIVersion = static_cast<const char *>(
144 Lib.getAddressOfSymbol("clang_analyzerAPIVersionString"));
145
146 if (!isCompatibleAPIVersion(PluginAPIVersion)) {
Kristof Umannb0be2ab2018-12-15 18:11:49 +0000147 Diags.Report(diag::warn_incompatible_analyzer_plugin_api)
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000148 << llvm::sys::path::filename(Plugin);
Kristof Umannb0be2ab2018-12-15 18:11:49 +0000149 Diags.Report(diag::note_incompatible_analyzer_plugin_api)
Kristof Umanna57d4ea2019-04-18 17:32:51 +0000150 << CLANG_ANALYZER_API_VERSION_STRING << PluginAPIVersion;
Kristof Umannb0be2ab2018-12-15 18:11:49 +0000151 continue;
152 }
153
154 // Register its checkers.
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000155 RegisterCheckersFn RegisterPluginCheckers =
Kristof Umanna57d4ea2019-04-18 17:32:51 +0000156 reinterpret_cast<RegisterCheckersFn>(
157 Lib.getAddressOfSymbol("clang_registerCheckers"));
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000158 if (RegisterPluginCheckers)
159 RegisterPluginCheckers(*this);
Kristof Umannb0be2ab2018-12-15 18:11:49 +0000160 }
Jordy Rose59cce712011-08-16 21:24:21 +0000161
Kristof Umann98217ad2019-01-26 17:27:40 +0000162 // Register statically linked checkers, that aren't generated from the tblgen
Kristof Umanna57d4ea2019-04-18 17:32:51 +0000163 // file, but rather passed their registry function as a parameter in
164 // checkerRegistrationFns.
Kristof Umann98217ad2019-01-26 17:27:40 +0000165
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000166 for (const auto &Fn : CheckerRegistrationFns)
Kristof Umann98217ad2019-01-26 17:27:40 +0000167 Fn(*this);
168
Kristof Umann3daa2452019-01-26 16:35:33 +0000169 // Sort checkers for efficient collection.
170 // FIXME: Alphabetical sort puts 'experimental' in the middle.
171 // Would it be better to name it '~experimental' or something else
172 // that's ASCIIbetically last?
Kristof Umannb4788b22019-04-19 12:32:10 +0000173 llvm::sort(Packages, PackageNameLT{});
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000174 llvm::sort(Checkers, CheckerNameLT{});
Kristof Umann45beaa02018-11-18 12:47:03 +0000175
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000176#define GET_CHECKER_DEPENDENCIES
177
178#define CHECKER_DEPENDENCY(FULLNAME, DEPENDENCY) \
179 addDependency(FULLNAME, DEPENDENCY);
180
Kristof Umannb4788b22019-04-19 12:32:10 +0000181#define GET_CHECKER_OPTIONS
182#define CHECKER_OPTION(TYPE, FULLNAME, CMDFLAG, DESC, DEFAULT_VAL) \
183 addCheckerOption(TYPE, FULLNAME, CMDFLAG, DEFAULT_VAL, DESC);
184
185#define GET_PACKAGE_OPTIONS
186#define PACKAGE_OPTION(TYPE, FULLNAME, CMDFLAG, DESC, DEFAULT_VAL) \
187 addPackageOption(TYPE, FULLNAME, CMDFLAG, DEFAULT_VAL, DESC);
188
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000189#include "clang/StaticAnalyzer/Checkers/Checkers.inc"
190#undef CHECKER_DEPENDENCY
191#undef GET_CHECKER_DEPENDENCIES
Kristof Umannb4788b22019-04-19 12:32:10 +0000192#undef CHECKER_OPTION
193#undef GET_CHECKER_OPTIONS
194#undef PACKAGE_OPTION
195#undef GET_PACKAGE_OPTIONS
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000196
Kristof Umanncd3f1472019-04-19 11:01:35 +0000197 resolveDependencies();
Kristof Umannb4788b22019-04-19 12:32:10 +0000198 resolveCheckerAndPackageOptions();
Kristof Umanncd3f1472019-04-19 11:01:35 +0000199
Kristof Umann3daa2452019-01-26 16:35:33 +0000200 // Parse '-analyzer-checker' and '-analyzer-disable-checker' options from the
201 // command line.
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000202 for (const std::pair<std::string, bool> &Opt : AnOpts.CheckersControlList) {
203 CheckerInfoListRange CheckerForCmdLineArg =
Kristof Umanna57d4ea2019-04-18 17:32:51 +0000204 getMutableCheckersForCmdLineArg(Opt.first);
Jordy Rose59cce712011-08-16 21:24:21 +0000205
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000206 if (CheckerForCmdLineArg.begin() == CheckerForCmdLineArg.end()) {
207 Diags.Report(diag::err_unknown_analyzer_checker) << Opt.first;
Kristof Umann3daa2452019-01-26 16:35:33 +0000208 Diags.Report(diag::note_suggest_disabling_all_checkers);
209 }
Jordy Rose59cce712011-08-16 21:24:21 +0000210
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000211 for (CheckerInfo &checker : CheckerForCmdLineArg) {
Kristof Umanna57d4ea2019-04-18 17:32:51 +0000212 checker.State = Opt.second ? StateFromCmdLine::State_Enabled
213 : StateFromCmdLine::State_Disabled;
Kristof Umann3daa2452019-01-26 16:35:33 +0000214 }
215 }
Jordy Rose59cce712011-08-16 21:24:21 +0000216}
217
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000218/// Collects dependencies in \p ret, returns false on failure.
Kristof Umanna57d4ea2019-04-18 17:32:51 +0000219static bool
220collectDependenciesImpl(const CheckerRegistry::ConstCheckerInfoList &Deps,
221 const LangOptions &LO,
222 CheckerRegistry::CheckerInfoSet &Ret);
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000223
224/// Collects dependenies in \p enabledCheckers. Return None on failure.
225LLVM_NODISCARD
Kristof Umanna57d4ea2019-04-18 17:32:51 +0000226static llvm::Optional<CheckerRegistry::CheckerInfoSet>
227collectDependencies(const CheckerRegistry::CheckerInfo &checker,
228 const LangOptions &LO) {
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000229
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000230 CheckerRegistry::CheckerInfoSet Ret;
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000231 // Add dependencies to the enabled checkers only if all of them can be
232 // enabled.
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000233 if (!collectDependenciesImpl(checker.Dependencies, LO, Ret))
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000234 return None;
235
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000236 return Ret;
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000237}
238
Kristof Umanna57d4ea2019-04-18 17:32:51 +0000239static bool
240collectDependenciesImpl(const CheckerRegistry::ConstCheckerInfoList &Deps,
241 const LangOptions &LO,
242 CheckerRegistry::CheckerInfoSet &Ret) {
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000243
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000244 for (const CheckerRegistry::CheckerInfo *Dependency : Deps) {
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000245
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000246 if (Dependency->isDisabled(LO))
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000247 return false;
248
249 // Collect dependencies recursively.
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000250 if (!collectDependenciesImpl(Dependency->Dependencies, LO, Ret))
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000251 return false;
252
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000253 Ret.insert(Dependency);
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000254 }
255
256 return true;
257}
258
Kristof Umanndd9c86e2019-01-26 15:59:21 +0000259CheckerRegistry::CheckerInfoSet CheckerRegistry::getEnabledCheckers() const {
Jordy Rose59cce712011-08-16 21:24:21 +0000260
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000261 CheckerInfoSet EnabledCheckers;
Jordy Rose59cce712011-08-16 21:24:21 +0000262
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000263 for (const CheckerInfo &Checker : Checkers) {
264 if (!Checker.isEnabled(LangOpts))
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000265 continue;
266
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000267 // Recursively enable its dependencies.
268 llvm::Optional<CheckerInfoSet> Deps =
269 collectDependencies(Checker, LangOpts);
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000270
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000271 if (!Deps) {
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000272 // If we failed to enable any of the dependencies, don't enable this
273 // checker.
274 continue;
275 }
276
277 // Note that set_union also preserves the order of insertion.
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000278 EnabledCheckers.set_union(*Deps);
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000279
280 // Enable the checker.
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000281 EnabledCheckers.insert(&Checker);
Kristof Umannf282d272018-12-15 15:44:05 +0000282 }
283
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000284 return EnabledCheckers;
Jordy Rose59cce712011-08-16 21:24:21 +0000285}
286
Kristof Umanncd3f1472019-04-19 11:01:35 +0000287void CheckerRegistry::resolveDependencies() {
288 for (const std::pair<StringRef, StringRef> &Entry : Dependencies) {
289 auto CheckerIt = binaryFind(Checkers, Entry.first);
290 assert(CheckerIt != Checkers.end() && CheckerIt->FullName == Entry.first &&
291 "Failed to find the checker while attempting to set up its "
292 "dependencies!");
293
294 auto DependencyIt = binaryFind(Checkers, Entry.second);
295 assert(DependencyIt != Checkers.end() &&
296 DependencyIt->FullName == Entry.second &&
297 "Failed to find the dependency of a checker!");
298
299 CheckerIt->Dependencies.emplace_back(&*DependencyIt);
300 }
301
302 Dependencies.clear();
303}
304
Kristof Umann640f7b52019-04-18 17:34:45 +0000305void CheckerRegistry::addDependency(StringRef FullName, StringRef Dependency) {
Kristof Umanncd3f1472019-04-19 11:01:35 +0000306 Dependencies.emplace_back(FullName, Dependency);
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000307}
308
Kristof Umannb4788b22019-04-19 12:32:10 +0000309template <class T>
310static void
311insertOptionToCollection(StringRef FullName, T &Collection,
Kristof Umann30b23072019-05-17 09:29:44 +0000312 const CheckerRegistry::CmdLineOption &Option,
313 AnalyzerOptions &AnOpts) {
Kristof Umannb4788b22019-04-19 12:32:10 +0000314 auto It = binaryFind(Collection, FullName);
315 assert(It != Collection.end() &&
316 "Failed to find the checker while attempting to add a command line "
317 "option to it!");
318
Kristof Umann30b23072019-05-17 09:29:44 +0000319 AnOpts.Config.insert(
320 {(FullName + ":" + Option.OptionName).str(), Option.DefaultValStr});
321
322 It->CmdLineOptions.emplace_back(Option);
Kristof Umannb4788b22019-04-19 12:32:10 +0000323}
324
325void CheckerRegistry::resolveCheckerAndPackageOptions() {
326 for (const std::pair<StringRef, CmdLineOption> &CheckerOptEntry :
327 CheckerOptions) {
328 insertOptionToCollection(CheckerOptEntry.first, Checkers,
Kristof Umann30b23072019-05-17 09:29:44 +0000329 CheckerOptEntry.second, AnOpts);
Kristof Umannb4788b22019-04-19 12:32:10 +0000330 }
331 CheckerOptions.clear();
332
333 for (const std::pair<StringRef, CmdLineOption> &PackageOptEntry :
334 PackageOptions) {
335 insertOptionToCollection(PackageOptEntry.first, Checkers,
Kristof Umann30b23072019-05-17 09:29:44 +0000336 PackageOptEntry.second, AnOpts);
Kristof Umannb4788b22019-04-19 12:32:10 +0000337 }
338 PackageOptions.clear();
339}
340
341void CheckerRegistry::addPackage(StringRef FullName) {
342 Packages.emplace_back(PackageInfo(FullName));
343}
344
345void CheckerRegistry::addPackageOption(StringRef OptionType,
346 StringRef PackageFullName,
347 StringRef OptionName,
348 StringRef DefaultValStr,
349 StringRef Description) {
350 PackageOptions.emplace_back(
351 PackageFullName,
352 CmdLineOption{OptionType, OptionName, DefaultValStr, Description});
353}
354
355void CheckerRegistry::addChecker(InitializationFunction Rfn,
356 ShouldRegisterFunction Sfn, StringRef Name,
Kristof Umann9f7fc982019-05-01 19:56:47 +0000357 StringRef Desc, StringRef DocsUri,
358 bool IsHidden) {
359 Checkers.emplace_back(Rfn, Sfn, Name, Desc, DocsUri, IsHidden);
Kristof Umannb4788b22019-04-19 12:32:10 +0000360
361 // Record the presence of the checker in its packages.
362 StringRef PackageName, LeafName;
363 std::tie(PackageName, LeafName) = Name.rsplit(PackageSeparator);
364 while (!LeafName.empty()) {
365 PackageSizes[PackageName] += 1;
366 std::tie(PackageName, LeafName) = PackageName.rsplit(PackageSeparator);
367 }
368}
369
370void CheckerRegistry::addCheckerOption(StringRef OptionType,
371 StringRef CheckerFullName,
372 StringRef OptionName,
373 StringRef DefaultValStr,
374 StringRef Description) {
375 CheckerOptions.emplace_back(
376 CheckerFullName,
377 CmdLineOption{OptionType, OptionName, DefaultValStr, Description});
378}
379
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000380void CheckerRegistry::initializeManager(CheckerManager &CheckerMgr) const {
Jordy Rose59cce712011-08-16 21:24:21 +0000381 // Collect checkers enabled by the options.
Kristof Umanndd9c86e2019-01-26 15:59:21 +0000382 CheckerInfoSet enabledCheckers = getEnabledCheckers();
Jordy Rose59cce712011-08-16 21:24:21 +0000383
384 // Initialize the CheckerManager with all enabled checkers.
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000385 for (const auto *Checker : enabledCheckers) {
386 CheckerMgr.setCurrentCheckName(CheckName(Checker->FullName));
387 Checker->Initialize(CheckerMgr);
Jordy Rose59cce712011-08-16 21:24:21 +0000388 }
389}
390
Kristof Umanndd9c86e2019-01-26 15:59:21 +0000391void CheckerRegistry::validateCheckerOptions() const {
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000392 for (const auto &Config : AnOpts.Config) {
393 size_t Pos = Config.getKey().find(':');
394 if (Pos == StringRef::npos)
Gabor Horvathfc4c4d42015-07-09 21:43:45 +0000395 continue;
396
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000397 bool HasChecker = false;
398 StringRef CheckerName = Config.getKey().substr(0, Pos);
399 for (const auto &Checker : Checkers) {
400 if (Checker.FullName.startswith(CheckerName) &&
401 (Checker.FullName.size() == Pos || Checker.FullName[Pos] == '.')) {
402 HasChecker = true;
Gabor Horvathfc4c4d42015-07-09 21:43:45 +0000403 break;
404 }
405 }
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000406 if (!HasChecker)
407 Diags.Report(diag::err_unknown_analyzer_checker) << CheckerName;
Gabor Horvathfc4c4d42015-07-09 21:43:45 +0000408 }
409}
410
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000411void CheckerRegistry::printCheckerWithDescList(raw_ostream &Out,
412 size_t MaxNameChars) const {
Jordy Rose59cce712011-08-16 21:24:21 +0000413 // FIXME: Print available packages.
414
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000415 Out << "CHECKERS:\n";
Jordy Rose59cce712011-08-16 21:24:21 +0000416
417 // Find the maximum option length.
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000418 size_t OptionFieldWidth = 0;
419 for (const auto &Checker : Checkers) {
Jordy Rose59cce712011-08-16 21:24:21 +0000420 // Limit the amount of padding we are willing to give up for alignment.
421 // Package.Name Description [Hidden]
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000422 size_t NameLength = Checker.FullName.size();
423 if (NameLength <= MaxNameChars)
424 OptionFieldWidth = std::max(OptionFieldWidth, NameLength);
Jordy Rose59cce712011-08-16 21:24:21 +0000425 }
426
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000427 const size_t InitialPad = 2;
428 for (const auto &Checker : Checkers) {
Kristof Umann9f7fc982019-05-01 19:56:47 +0000429 if (!AnOpts.ShowCheckerHelpHidden && Checker.IsHidden)
430 continue;
431
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000432 Out.indent(InitialPad) << Checker.FullName;
Jordy Rose59cce712011-08-16 21:24:21 +0000433
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000434 int Pad = OptionFieldWidth - Checker.FullName.size();
Jordy Rose59cce712011-08-16 21:24:21 +0000435
436 // Break on long option names.
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000437 if (Pad < 0) {
438 Out << '\n';
439 Pad = OptionFieldWidth + InitialPad;
Jordy Rose59cce712011-08-16 21:24:21 +0000440 }
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000441 Out.indent(Pad + 2) << Checker.Desc;
Jordy Rose59cce712011-08-16 21:24:21 +0000442
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000443 Out << '\n';
Jordy Rose59cce712011-08-16 21:24:21 +0000444 }
445}
Gabor Horvathc4309902016-08-08 13:41:04 +0000446
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000447void CheckerRegistry::printEnabledCheckerList(raw_ostream &Out) const {
Gabor Horvathc4309902016-08-08 13:41:04 +0000448 // Collect checkers enabled by the options.
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000449 CheckerInfoSet EnabledCheckers = getEnabledCheckers();
Gabor Horvathc4309902016-08-08 13:41:04 +0000450
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000451 for (const auto *i : EnabledCheckers)
452 Out << i->FullName << '\n';
Gabor Horvathc4309902016-08-08 13:41:04 +0000453}