blob: c0d5d1bdc33c3cbd347cc05644a104405a0edc1d [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
48using CheckerNameLT = FullNameLT<CheckerRegistry::CheckerInfo>;
49} // end of anonymous namespace
Kristof Umann3daa2452019-01-26 16:35:33 +000050
Kristof Umann640f7b52019-04-18 17:34:45 +000051template <class CheckerOrPackageInfoList>
52static
53 typename std::conditional<std::is_const<CheckerOrPackageInfoList>::value,
54 typename CheckerOrPackageInfoList::const_iterator,
55 typename CheckerOrPackageInfoList::iterator>::type
56 binaryFind(CheckerOrPackageInfoList &Collection, StringRef FullName) {
57
58 using CheckerOrPackage = typename CheckerOrPackageInfoList::value_type;
59 using CheckerOrPackageFullNameLT = FullNameLT<CheckerOrPackage>;
60
61 assert(std::is_sorted(Collection.begin(), Collection.end(),
62 CheckerOrPackageFullNameLT{}) &&
63 "In order to efficiently gather checkers/packages, this function "
64 "expects them to be already sorted!");
65
66 typename CheckerOrPackageInfoList::value_type Info(FullName);
67
68 return llvm::lower_bound(
69 Collection, Info,
70 FullNameLT<typename CheckerOrPackageInfoList::value_type>{});
71}
72
Kristof Umann3daa2452019-01-26 16:35:33 +000073static constexpr char PackageSeparator = '.';
74
Kristof Umannb9bc7ec2019-04-18 15:19:16 +000075static bool isInPackage(const CheckerRegistry::CheckerInfo &Checker,
76 StringRef PackageName) {
Kristof Umann3daa2452019-01-26 16:35:33 +000077 // Does the checker's full name have the package as a prefix?
Kristof Umannb9bc7ec2019-04-18 15:19:16 +000078 if (!Checker.FullName.startswith(PackageName))
Kristof Umann3daa2452019-01-26 16:35:33 +000079 return false;
80
81 // Is the package actually just the name of a specific checker?
Kristof Umannb9bc7ec2019-04-18 15:19:16 +000082 if (Checker.FullName.size() == PackageName.size())
Kristof Umann3daa2452019-01-26 16:35:33 +000083 return true;
84
85 // Is the checker in the package (or a subpackage)?
Kristof Umannb9bc7ec2019-04-18 15:19:16 +000086 if (Checker.FullName[PackageName.size()] == PackageSeparator)
Kristof Umann3daa2452019-01-26 16:35:33 +000087 return true;
88
89 return false;
90}
91
92CheckerRegistry::CheckerInfoListRange
93CheckerRegistry::getMutableCheckersForCmdLineArg(StringRef CmdLineArg) {
Kristof Umann640f7b52019-04-18 17:34:45 +000094 auto It = binaryFind(Checkers, CmdLineArg);
Kristof Umann3daa2452019-01-26 16:35:33 +000095
Kristof Umannb9bc7ec2019-04-18 15:19:16 +000096 if (!isInPackage(*It, CmdLineArg))
Kristof Umanna57d4ea2019-04-18 17:32:51 +000097 return {Checkers.end(), Checkers.end()};
Kristof Umann3daa2452019-01-26 16:35:33 +000098
99 // See how large the package is.
100 // If the package doesn't exist, assume the option refers to a single
101 // checker.
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000102 size_t Size = 1;
103 llvm::StringMap<size_t>::const_iterator PackageSize =
104 PackageSizes.find(CmdLineArg);
Kristof Umann3daa2452019-01-26 16:35:33 +0000105
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000106 if (PackageSize != PackageSizes.end())
107 Size = PackageSize->getValue();
Kristof Umann3daa2452019-01-26 16:35:33 +0000108
Kristof Umanna57d4ea2019-04-18 17:32:51 +0000109 return {It, It + Size};
Kristof Umann3daa2452019-01-26 16:35:33 +0000110}
111
Kristof Umann98217ad2019-01-26 17:27:40 +0000112CheckerRegistry::CheckerRegistry(
Kristof Umanna57d4ea2019-04-18 17:32:51 +0000113 ArrayRef<std::string> Plugins, DiagnosticsEngine &Diags,
114 AnalyzerOptions &AnOpts, const LangOptions &LangOpts,
115 ArrayRef<std::function<void(CheckerRegistry &)>> CheckerRegistrationFns)
116 : Diags(Diags), AnOpts(AnOpts), LangOpts(LangOpts) {
Kristof Umann058a7a42019-01-26 14:23:08 +0000117
Kristof Umann3daa2452019-01-26 16:35:33 +0000118 // Register builtin checkers.
Kristof Umannb0be2ab2018-12-15 18:11:49 +0000119#define GET_CHECKERS
Aaron Ballman2f234cb2018-12-20 20:20:20 +0000120#define CHECKER(FULLNAME, CLASS, HELPTEXT, DOC_URI) \
Kristof Umann058a7a42019-01-26 14:23:08 +0000121 addChecker(register##CLASS, shouldRegister##CLASS, FULLNAME, HELPTEXT, \
122 DOC_URI);
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000123
Kristof Umannb0be2ab2018-12-15 18:11:49 +0000124#include "clang/StaticAnalyzer/Checkers/Checkers.inc"
125#undef CHECKER
126#undef GET_CHECKERS
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000127#undef PACKAGE
128#undef GET_PACKAGES
Kristof Umannb0be2ab2018-12-15 18:11:49 +0000129
Kristof Umann3daa2452019-01-26 16:35:33 +0000130 // Register checkers from plugins.
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000131 for (const std::string &Plugin : Plugins) {
Kristof Umannb0be2ab2018-12-15 18:11:49 +0000132 // Get access to the plugin.
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000133 std::string ErrorMsg;
134 DynamicLibrary Lib =
135 DynamicLibrary::getPermanentLibrary(Plugin.c_str(), &ErrorMsg);
136 if (!Lib.isValid()) {
137 Diags.Report(diag::err_fe_unable_to_load_plugin) << Plugin << ErrorMsg;
Kristof Umannb0be2ab2018-12-15 18:11:49 +0000138 continue;
139 }
140
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000141 // See if its compatible with this build of clang.
142 const char *PluginAPIVersion = static_cast<const char *>(
143 Lib.getAddressOfSymbol("clang_analyzerAPIVersionString"));
144
145 if (!isCompatibleAPIVersion(PluginAPIVersion)) {
Kristof Umannb0be2ab2018-12-15 18:11:49 +0000146 Diags.Report(diag::warn_incompatible_analyzer_plugin_api)
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000147 << llvm::sys::path::filename(Plugin);
Kristof Umannb0be2ab2018-12-15 18:11:49 +0000148 Diags.Report(diag::note_incompatible_analyzer_plugin_api)
Kristof Umanna57d4ea2019-04-18 17:32:51 +0000149 << CLANG_ANALYZER_API_VERSION_STRING << PluginAPIVersion;
Kristof Umannb0be2ab2018-12-15 18:11:49 +0000150 continue;
151 }
152
153 // Register its checkers.
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000154 RegisterCheckersFn RegisterPluginCheckers =
Kristof Umanna57d4ea2019-04-18 17:32:51 +0000155 reinterpret_cast<RegisterCheckersFn>(
156 Lib.getAddressOfSymbol("clang_registerCheckers"));
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000157 if (RegisterPluginCheckers)
158 RegisterPluginCheckers(*this);
Kristof Umannb0be2ab2018-12-15 18:11:49 +0000159 }
Jordy Rose59cce712011-08-16 21:24:21 +0000160
Kristof Umann98217ad2019-01-26 17:27:40 +0000161 // Register statically linked checkers, that aren't generated from the tblgen
Kristof Umanna57d4ea2019-04-18 17:32:51 +0000162 // file, but rather passed their registry function as a parameter in
163 // checkerRegistrationFns.
Kristof Umann98217ad2019-01-26 17:27:40 +0000164
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000165 for (const auto &Fn : CheckerRegistrationFns)
Kristof Umann98217ad2019-01-26 17:27:40 +0000166 Fn(*this);
167
Kristof Umann3daa2452019-01-26 16:35:33 +0000168 // Sort checkers for efficient collection.
169 // FIXME: Alphabetical sort puts 'experimental' in the middle.
170 // Would it be better to name it '~experimental' or something else
171 // that's ASCIIbetically last?
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000172 llvm::sort(Checkers, CheckerNameLT{});
Kristof Umann45beaa02018-11-18 12:47:03 +0000173
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000174#define GET_CHECKER_DEPENDENCIES
175
176#define CHECKER_DEPENDENCY(FULLNAME, DEPENDENCY) \
177 addDependency(FULLNAME, DEPENDENCY);
178
179#include "clang/StaticAnalyzer/Checkers/Checkers.inc"
180#undef CHECKER_DEPENDENCY
181#undef GET_CHECKER_DEPENDENCIES
182
Kristof Umann3daa2452019-01-26 16:35:33 +0000183 // Parse '-analyzer-checker' and '-analyzer-disable-checker' options from the
184 // command line.
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000185 for (const std::pair<std::string, bool> &Opt : AnOpts.CheckersControlList) {
186 CheckerInfoListRange CheckerForCmdLineArg =
Kristof Umanna57d4ea2019-04-18 17:32:51 +0000187 getMutableCheckersForCmdLineArg(Opt.first);
Jordy Rose59cce712011-08-16 21:24:21 +0000188
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000189 if (CheckerForCmdLineArg.begin() == CheckerForCmdLineArg.end()) {
190 Diags.Report(diag::err_unknown_analyzer_checker) << Opt.first;
Kristof Umann3daa2452019-01-26 16:35:33 +0000191 Diags.Report(diag::note_suggest_disabling_all_checkers);
192 }
Jordy Rose59cce712011-08-16 21:24:21 +0000193
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000194 for (CheckerInfo &checker : CheckerForCmdLineArg) {
Kristof Umanna57d4ea2019-04-18 17:32:51 +0000195 checker.State = Opt.second ? StateFromCmdLine::State_Enabled
196 : StateFromCmdLine::State_Disabled;
Kristof Umann3daa2452019-01-26 16:35:33 +0000197 }
198 }
Jordy Rose59cce712011-08-16 21:24:21 +0000199}
200
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000201/// Collects dependencies in \p ret, returns false on failure.
Kristof Umanna57d4ea2019-04-18 17:32:51 +0000202static bool
203collectDependenciesImpl(const CheckerRegistry::ConstCheckerInfoList &Deps,
204 const LangOptions &LO,
205 CheckerRegistry::CheckerInfoSet &Ret);
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000206
207/// Collects dependenies in \p enabledCheckers. Return None on failure.
208LLVM_NODISCARD
Kristof Umanna57d4ea2019-04-18 17:32:51 +0000209static llvm::Optional<CheckerRegistry::CheckerInfoSet>
210collectDependencies(const CheckerRegistry::CheckerInfo &checker,
211 const LangOptions &LO) {
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000212
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000213 CheckerRegistry::CheckerInfoSet Ret;
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000214 // Add dependencies to the enabled checkers only if all of them can be
215 // enabled.
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000216 if (!collectDependenciesImpl(checker.Dependencies, LO, Ret))
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000217 return None;
218
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000219 return Ret;
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000220}
221
Kristof Umanna57d4ea2019-04-18 17:32:51 +0000222static bool
223collectDependenciesImpl(const CheckerRegistry::ConstCheckerInfoList &Deps,
224 const LangOptions &LO,
225 CheckerRegistry::CheckerInfoSet &Ret) {
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000226
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000227 for (const CheckerRegistry::CheckerInfo *Dependency : Deps) {
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000228
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000229 if (Dependency->isDisabled(LO))
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000230 return false;
231
232 // Collect dependencies recursively.
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000233 if (!collectDependenciesImpl(Dependency->Dependencies, LO, Ret))
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000234 return false;
235
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000236 Ret.insert(Dependency);
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000237 }
238
239 return true;
240}
241
Kristof Umanndd9c86e2019-01-26 15:59:21 +0000242CheckerRegistry::CheckerInfoSet CheckerRegistry::getEnabledCheckers() const {
Jordy Rose59cce712011-08-16 21:24:21 +0000243
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000244 CheckerInfoSet EnabledCheckers;
Jordy Rose59cce712011-08-16 21:24:21 +0000245
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000246 for (const CheckerInfo &Checker : Checkers) {
247 if (!Checker.isEnabled(LangOpts))
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000248 continue;
249
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000250 // Recursively enable its dependencies.
251 llvm::Optional<CheckerInfoSet> Deps =
252 collectDependencies(Checker, LangOpts);
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000253
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000254 if (!Deps) {
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000255 // If we failed to enable any of the dependencies, don't enable this
256 // checker.
257 continue;
258 }
259
260 // Note that set_union also preserves the order of insertion.
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000261 EnabledCheckers.set_union(*Deps);
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000262
263 // Enable the checker.
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000264 EnabledCheckers.insert(&Checker);
Kristof Umannf282d272018-12-15 15:44:05 +0000265 }
266
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000267 return EnabledCheckers;
Jordy Rose59cce712011-08-16 21:24:21 +0000268}
269
Kristof Umann058a7a42019-01-26 14:23:08 +0000270void CheckerRegistry::addChecker(InitializationFunction Rfn,
271 ShouldRegisterFunction Sfn, StringRef Name,
Aaron Ballman2f234cb2018-12-20 20:20:20 +0000272 StringRef Desc, StringRef DocsUri) {
Kristof Umann058a7a42019-01-26 14:23:08 +0000273 Checkers.emplace_back(Rfn, Sfn, Name, Desc, DocsUri);
Jordy Rose59cce712011-08-16 21:24:21 +0000274
275 // Record the presence of the checker in its packages.
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000276 StringRef PackageName, LeafName;
277 std::tie(PackageName, LeafName) = Name.rsplit(PackageSeparator);
278 while (!LeafName.empty()) {
279 PackageSizes[PackageName] += 1;
280 std::tie(PackageName, LeafName) = PackageName.rsplit(PackageSeparator);
Jordy Rose59cce712011-08-16 21:24:21 +0000281 }
282}
283
Kristof Umann640f7b52019-04-18 17:34:45 +0000284void CheckerRegistry::addDependency(StringRef FullName, StringRef Dependency) {
285 auto CheckerIt = binaryFind(Checkers, FullName);
286 assert(CheckerIt != Checkers.end() && CheckerIt->FullName == FullName &&
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000287 "Failed to find the checker while attempting to set up its "
288 "dependencies!");
289
Kristof Umann640f7b52019-04-18 17:34:45 +0000290 auto DependencyIt = binaryFind(Checkers, Dependency);
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000291 assert(DependencyIt != Checkers.end() &&
Kristof Umann640f7b52019-04-18 17:34:45 +0000292 DependencyIt->FullName == Dependency &&
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000293 "Failed to find the dependency of a checker!");
294
Kristof Umann640f7b52019-04-18 17:34:45 +0000295 CheckerIt->Dependencies.emplace_back(&*DependencyIt);
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000296}
297
298void CheckerRegistry::initializeManager(CheckerManager &CheckerMgr) const {
Jordy Rose59cce712011-08-16 21:24:21 +0000299 // Collect checkers enabled by the options.
Kristof Umanndd9c86e2019-01-26 15:59:21 +0000300 CheckerInfoSet enabledCheckers = getEnabledCheckers();
Jordy Rose59cce712011-08-16 21:24:21 +0000301
302 // Initialize the CheckerManager with all enabled checkers.
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000303 for (const auto *Checker : enabledCheckers) {
304 CheckerMgr.setCurrentCheckName(CheckName(Checker->FullName));
305 Checker->Initialize(CheckerMgr);
Jordy Rose59cce712011-08-16 21:24:21 +0000306 }
307}
308
Kristof Umanndd9c86e2019-01-26 15:59:21 +0000309void CheckerRegistry::validateCheckerOptions() const {
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000310 for (const auto &Config : AnOpts.Config) {
311 size_t Pos = Config.getKey().find(':');
312 if (Pos == StringRef::npos)
Gabor Horvathfc4c4d42015-07-09 21:43:45 +0000313 continue;
314
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000315 bool HasChecker = false;
316 StringRef CheckerName = Config.getKey().substr(0, Pos);
317 for (const auto &Checker : Checkers) {
318 if (Checker.FullName.startswith(CheckerName) &&
319 (Checker.FullName.size() == Pos || Checker.FullName[Pos] == '.')) {
320 HasChecker = true;
Gabor Horvathfc4c4d42015-07-09 21:43:45 +0000321 break;
322 }
323 }
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000324 if (!HasChecker)
325 Diags.Report(diag::err_unknown_analyzer_checker) << CheckerName;
Gabor Horvathfc4c4d42015-07-09 21:43:45 +0000326 }
327}
328
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000329void CheckerRegistry::printCheckerWithDescList(raw_ostream &Out,
330 size_t MaxNameChars) const {
Jordy Rose59cce712011-08-16 21:24:21 +0000331 // FIXME: Print available packages.
332
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000333 Out << "CHECKERS:\n";
Jordy Rose59cce712011-08-16 21:24:21 +0000334
335 // Find the maximum option length.
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000336 size_t OptionFieldWidth = 0;
337 for (const auto &Checker : Checkers) {
Jordy Rose59cce712011-08-16 21:24:21 +0000338 // Limit the amount of padding we are willing to give up for alignment.
339 // Package.Name Description [Hidden]
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000340 size_t NameLength = Checker.FullName.size();
341 if (NameLength <= MaxNameChars)
342 OptionFieldWidth = std::max(OptionFieldWidth, NameLength);
Jordy Rose59cce712011-08-16 21:24:21 +0000343 }
344
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000345 const size_t InitialPad = 2;
346 for (const auto &Checker : Checkers) {
347 Out.indent(InitialPad) << Checker.FullName;
Jordy Rose59cce712011-08-16 21:24:21 +0000348
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000349 int Pad = OptionFieldWidth - Checker.FullName.size();
Jordy Rose59cce712011-08-16 21:24:21 +0000350
351 // Break on long option names.
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000352 if (Pad < 0) {
353 Out << '\n';
354 Pad = OptionFieldWidth + InitialPad;
Jordy Rose59cce712011-08-16 21:24:21 +0000355 }
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000356 Out.indent(Pad + 2) << Checker.Desc;
Jordy Rose59cce712011-08-16 21:24:21 +0000357
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000358 Out << '\n';
Jordy Rose59cce712011-08-16 21:24:21 +0000359 }
360}
Gabor Horvathc4309902016-08-08 13:41:04 +0000361
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000362void CheckerRegistry::printEnabledCheckerList(raw_ostream &Out) const {
Gabor Horvathc4309902016-08-08 13:41:04 +0000363 // Collect checkers enabled by the options.
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000364 CheckerInfoSet EnabledCheckers = getEnabledCheckers();
Gabor Horvathc4309902016-08-08 13:41:04 +0000365
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000366 for (const auto *i : EnabledCheckers)
367 Out << i->FullName << '\n';
Gabor Horvathc4309902016-08-08 13:41:04 +0000368}