blob: b164d4143892ca471c45312d33d139788033997b [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
51static constexpr char PackageSeparator = '.';
52
Kristof Umannb9bc7ec2019-04-18 15:19:16 +000053static bool isInPackage(const CheckerRegistry::CheckerInfo &Checker,
54 StringRef PackageName) {
Kristof Umann3daa2452019-01-26 16:35:33 +000055 // Does the checker's full name have the package as a prefix?
Kristof Umannb9bc7ec2019-04-18 15:19:16 +000056 if (!Checker.FullName.startswith(PackageName))
Kristof Umann3daa2452019-01-26 16:35:33 +000057 return false;
58
59 // Is the package actually just the name of a specific checker?
Kristof Umannb9bc7ec2019-04-18 15:19:16 +000060 if (Checker.FullName.size() == PackageName.size())
Kristof Umann3daa2452019-01-26 16:35:33 +000061 return true;
62
63 // Is the checker in the package (or a subpackage)?
Kristof Umannb9bc7ec2019-04-18 15:19:16 +000064 if (Checker.FullName[PackageName.size()] == PackageSeparator)
Kristof Umann3daa2452019-01-26 16:35:33 +000065 return true;
66
67 return false;
68}
69
70CheckerRegistry::CheckerInfoListRange
71CheckerRegistry::getMutableCheckersForCmdLineArg(StringRef CmdLineArg) {
72
Kristof Umannb9bc7ec2019-04-18 15:19:16 +000073 assert(std::is_sorted(Checkers.begin(), Checkers.end(), CheckerNameLT{}) &&
Kristof Umann3daa2452019-01-26 16:35:33 +000074 "In order to efficiently gather checkers, this function expects them "
75 "to be already sorted!");
76
77 // Use a binary search to find the possible start of the package.
Kristof Umanna57d4ea2019-04-18 17:32:51 +000078 CheckerRegistry::CheckerInfo PackageInfo(nullptr, nullptr, CmdLineArg, "",
79 "");
80 auto It = std::lower_bound(Checkers.begin(), Checkers.end(), PackageInfo,
81 CheckerNameLT{});
Kristof Umann3daa2452019-01-26 16:35:33 +000082
Kristof Umannb9bc7ec2019-04-18 15:19:16 +000083 if (!isInPackage(*It, CmdLineArg))
Kristof Umanna57d4ea2019-04-18 17:32:51 +000084 return {Checkers.end(), Checkers.end()};
Kristof Umann3daa2452019-01-26 16:35:33 +000085
86 // See how large the package is.
87 // If the package doesn't exist, assume the option refers to a single
88 // checker.
Kristof Umannb9bc7ec2019-04-18 15:19:16 +000089 size_t Size = 1;
90 llvm::StringMap<size_t>::const_iterator PackageSize =
91 PackageSizes.find(CmdLineArg);
Kristof Umann3daa2452019-01-26 16:35:33 +000092
Kristof Umannb9bc7ec2019-04-18 15:19:16 +000093 if (PackageSize != PackageSizes.end())
94 Size = PackageSize->getValue();
Kristof Umann3daa2452019-01-26 16:35:33 +000095
Kristof Umanna57d4ea2019-04-18 17:32:51 +000096 return {It, It + Size};
Kristof Umann3daa2452019-01-26 16:35:33 +000097}
98
Kristof Umann98217ad2019-01-26 17:27:40 +000099CheckerRegistry::CheckerRegistry(
Kristof Umanna57d4ea2019-04-18 17:32:51 +0000100 ArrayRef<std::string> Plugins, DiagnosticsEngine &Diags,
101 AnalyzerOptions &AnOpts, const LangOptions &LangOpts,
102 ArrayRef<std::function<void(CheckerRegistry &)>> CheckerRegistrationFns)
103 : Diags(Diags), AnOpts(AnOpts), LangOpts(LangOpts) {
Kristof Umann058a7a42019-01-26 14:23:08 +0000104
Kristof Umann3daa2452019-01-26 16:35:33 +0000105 // Register builtin checkers.
Kristof Umannb0be2ab2018-12-15 18:11:49 +0000106#define GET_CHECKERS
Aaron Ballman2f234cb2018-12-20 20:20:20 +0000107#define CHECKER(FULLNAME, CLASS, HELPTEXT, DOC_URI) \
Kristof Umann058a7a42019-01-26 14:23:08 +0000108 addChecker(register##CLASS, shouldRegister##CLASS, FULLNAME, HELPTEXT, \
109 DOC_URI);
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000110
Kristof Umannb0be2ab2018-12-15 18:11:49 +0000111#include "clang/StaticAnalyzer/Checkers/Checkers.inc"
112#undef CHECKER
113#undef GET_CHECKERS
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000114#undef PACKAGE
115#undef GET_PACKAGES
Kristof Umannb0be2ab2018-12-15 18:11:49 +0000116
Kristof Umann3daa2452019-01-26 16:35:33 +0000117 // Register checkers from plugins.
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000118 for (const std::string &Plugin : Plugins) {
Kristof Umannb0be2ab2018-12-15 18:11:49 +0000119 // Get access to the plugin.
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000120 std::string ErrorMsg;
121 DynamicLibrary Lib =
122 DynamicLibrary::getPermanentLibrary(Plugin.c_str(), &ErrorMsg);
123 if (!Lib.isValid()) {
124 Diags.Report(diag::err_fe_unable_to_load_plugin) << Plugin << ErrorMsg;
Kristof Umannb0be2ab2018-12-15 18:11:49 +0000125 continue;
126 }
127
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000128 // See if its compatible with this build of clang.
129 const char *PluginAPIVersion = static_cast<const char *>(
130 Lib.getAddressOfSymbol("clang_analyzerAPIVersionString"));
131
132 if (!isCompatibleAPIVersion(PluginAPIVersion)) {
Kristof Umannb0be2ab2018-12-15 18:11:49 +0000133 Diags.Report(diag::warn_incompatible_analyzer_plugin_api)
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000134 << llvm::sys::path::filename(Plugin);
Kristof Umannb0be2ab2018-12-15 18:11:49 +0000135 Diags.Report(diag::note_incompatible_analyzer_plugin_api)
Kristof Umanna57d4ea2019-04-18 17:32:51 +0000136 << CLANG_ANALYZER_API_VERSION_STRING << PluginAPIVersion;
Kristof Umannb0be2ab2018-12-15 18:11:49 +0000137 continue;
138 }
139
140 // Register its checkers.
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000141 RegisterCheckersFn RegisterPluginCheckers =
Kristof Umanna57d4ea2019-04-18 17:32:51 +0000142 reinterpret_cast<RegisterCheckersFn>(
143 Lib.getAddressOfSymbol("clang_registerCheckers"));
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000144 if (RegisterPluginCheckers)
145 RegisterPluginCheckers(*this);
Kristof Umannb0be2ab2018-12-15 18:11:49 +0000146 }
Jordy Rose59cce712011-08-16 21:24:21 +0000147
Kristof Umann98217ad2019-01-26 17:27:40 +0000148 // Register statically linked checkers, that aren't generated from the tblgen
Kristof Umanna57d4ea2019-04-18 17:32:51 +0000149 // file, but rather passed their registry function as a parameter in
150 // checkerRegistrationFns.
Kristof Umann98217ad2019-01-26 17:27:40 +0000151
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000152 for (const auto &Fn : CheckerRegistrationFns)
Kristof Umann98217ad2019-01-26 17:27:40 +0000153 Fn(*this);
154
Kristof Umann3daa2452019-01-26 16:35:33 +0000155 // Sort checkers for efficient collection.
156 // FIXME: Alphabetical sort puts 'experimental' in the middle.
157 // Would it be better to name it '~experimental' or something else
158 // that's ASCIIbetically last?
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000159 llvm::sort(Checkers, CheckerNameLT{});
Kristof Umann45beaa02018-11-18 12:47:03 +0000160
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000161#define GET_CHECKER_DEPENDENCIES
162
163#define CHECKER_DEPENDENCY(FULLNAME, DEPENDENCY) \
164 addDependency(FULLNAME, DEPENDENCY);
165
166#include "clang/StaticAnalyzer/Checkers/Checkers.inc"
167#undef CHECKER_DEPENDENCY
168#undef GET_CHECKER_DEPENDENCIES
169
Kristof Umann3daa2452019-01-26 16:35:33 +0000170 // Parse '-analyzer-checker' and '-analyzer-disable-checker' options from the
171 // command line.
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000172 for (const std::pair<std::string, bool> &Opt : AnOpts.CheckersControlList) {
173 CheckerInfoListRange CheckerForCmdLineArg =
Kristof Umanna57d4ea2019-04-18 17:32:51 +0000174 getMutableCheckersForCmdLineArg(Opt.first);
Jordy Rose59cce712011-08-16 21:24:21 +0000175
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000176 if (CheckerForCmdLineArg.begin() == CheckerForCmdLineArg.end()) {
177 Diags.Report(diag::err_unknown_analyzer_checker) << Opt.first;
Kristof Umann3daa2452019-01-26 16:35:33 +0000178 Diags.Report(diag::note_suggest_disabling_all_checkers);
179 }
Jordy Rose59cce712011-08-16 21:24:21 +0000180
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000181 for (CheckerInfo &checker : CheckerForCmdLineArg) {
Kristof Umanna57d4ea2019-04-18 17:32:51 +0000182 checker.State = Opt.second ? StateFromCmdLine::State_Enabled
183 : StateFromCmdLine::State_Disabled;
Kristof Umann3daa2452019-01-26 16:35:33 +0000184 }
185 }
Jordy Rose59cce712011-08-16 21:24:21 +0000186}
187
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000188/// Collects dependencies in \p ret, returns false on failure.
Kristof Umanna57d4ea2019-04-18 17:32:51 +0000189static bool
190collectDependenciesImpl(const CheckerRegistry::ConstCheckerInfoList &Deps,
191 const LangOptions &LO,
192 CheckerRegistry::CheckerInfoSet &Ret);
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000193
194/// Collects dependenies in \p enabledCheckers. Return None on failure.
195LLVM_NODISCARD
Kristof Umanna57d4ea2019-04-18 17:32:51 +0000196static llvm::Optional<CheckerRegistry::CheckerInfoSet>
197collectDependencies(const CheckerRegistry::CheckerInfo &checker,
198 const LangOptions &LO) {
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000199
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000200 CheckerRegistry::CheckerInfoSet Ret;
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000201 // Add dependencies to the enabled checkers only if all of them can be
202 // enabled.
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000203 if (!collectDependenciesImpl(checker.Dependencies, LO, Ret))
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000204 return None;
205
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000206 return Ret;
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000207}
208
Kristof Umanna57d4ea2019-04-18 17:32:51 +0000209static bool
210collectDependenciesImpl(const CheckerRegistry::ConstCheckerInfoList &Deps,
211 const LangOptions &LO,
212 CheckerRegistry::CheckerInfoSet &Ret) {
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000213
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000214 for (const CheckerRegistry::CheckerInfo *Dependency : Deps) {
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000215
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000216 if (Dependency->isDisabled(LO))
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000217 return false;
218
219 // Collect dependencies recursively.
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000220 if (!collectDependenciesImpl(Dependency->Dependencies, LO, Ret))
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000221 return false;
222
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000223 Ret.insert(Dependency);
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000224 }
225
226 return true;
227}
228
Kristof Umanndd9c86e2019-01-26 15:59:21 +0000229CheckerRegistry::CheckerInfoSet CheckerRegistry::getEnabledCheckers() const {
Jordy Rose59cce712011-08-16 21:24:21 +0000230
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000231 CheckerInfoSet EnabledCheckers;
Jordy Rose59cce712011-08-16 21:24:21 +0000232
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000233 for (const CheckerInfo &Checker : Checkers) {
234 if (!Checker.isEnabled(LangOpts))
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000235 continue;
236
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000237 // Recursively enable its dependencies.
238 llvm::Optional<CheckerInfoSet> Deps =
239 collectDependencies(Checker, LangOpts);
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000240
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000241 if (!Deps) {
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000242 // If we failed to enable any of the dependencies, don't enable this
243 // checker.
244 continue;
245 }
246
247 // Note that set_union also preserves the order of insertion.
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000248 EnabledCheckers.set_union(*Deps);
Kristof Umann8fd74eb2019-01-26 20:06:54 +0000249
250 // Enable the checker.
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000251 EnabledCheckers.insert(&Checker);
Kristof Umannf282d272018-12-15 15:44:05 +0000252 }
253
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000254 return EnabledCheckers;
Jordy Rose59cce712011-08-16 21:24:21 +0000255}
256
Kristof Umann058a7a42019-01-26 14:23:08 +0000257void CheckerRegistry::addChecker(InitializationFunction Rfn,
258 ShouldRegisterFunction Sfn, StringRef Name,
Aaron Ballman2f234cb2018-12-20 20:20:20 +0000259 StringRef Desc, StringRef DocsUri) {
Kristof Umann058a7a42019-01-26 14:23:08 +0000260 Checkers.emplace_back(Rfn, Sfn, Name, Desc, DocsUri);
Jordy Rose59cce712011-08-16 21:24:21 +0000261
262 // Record the presence of the checker in its packages.
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000263 StringRef PackageName, LeafName;
264 std::tie(PackageName, LeafName) = Name.rsplit(PackageSeparator);
265 while (!LeafName.empty()) {
266 PackageSizes[PackageName] += 1;
267 std::tie(PackageName, LeafName) = PackageName.rsplit(PackageSeparator);
Jordy Rose59cce712011-08-16 21:24:21 +0000268 }
269}
270
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000271void CheckerRegistry::addDependency(StringRef FullName, StringRef dependency) {
Kristof Umanna57d4ea2019-04-18 17:32:51 +0000272 auto CheckerThatNeedsDeps = [&FullName](const CheckerInfo &Chk) {
273 return Chk.FullName == FullName;
274 };
275 auto Dependency = [&dependency](const CheckerInfo &Chk) {
276 return Chk.FullName == dependency;
277 };
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000278
279 auto CheckerIt = llvm::find_if(Checkers, CheckerThatNeedsDeps);
280 assert(CheckerIt != Checkers.end() &&
281 "Failed to find the checker while attempting to set up its "
282 "dependencies!");
283
284 auto DependencyIt = llvm::find_if(Checkers, Dependency);
285 assert(DependencyIt != Checkers.end() &&
286 "Failed to find the dependency of a checker!");
287
288 CheckerIt->Dependencies.push_back(&*DependencyIt);
289}
290
291void CheckerRegistry::initializeManager(CheckerManager &CheckerMgr) const {
Jordy Rose59cce712011-08-16 21:24:21 +0000292 // Collect checkers enabled by the options.
Kristof Umanndd9c86e2019-01-26 15:59:21 +0000293 CheckerInfoSet enabledCheckers = getEnabledCheckers();
Jordy Rose59cce712011-08-16 21:24:21 +0000294
295 // Initialize the CheckerManager with all enabled checkers.
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000296 for (const auto *Checker : enabledCheckers) {
297 CheckerMgr.setCurrentCheckName(CheckName(Checker->FullName));
298 Checker->Initialize(CheckerMgr);
Jordy Rose59cce712011-08-16 21:24:21 +0000299 }
300}
301
Kristof Umanndd9c86e2019-01-26 15:59:21 +0000302void CheckerRegistry::validateCheckerOptions() const {
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000303 for (const auto &Config : AnOpts.Config) {
304 size_t Pos = Config.getKey().find(':');
305 if (Pos == StringRef::npos)
Gabor Horvathfc4c4d42015-07-09 21:43:45 +0000306 continue;
307
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000308 bool HasChecker = false;
309 StringRef CheckerName = Config.getKey().substr(0, Pos);
310 for (const auto &Checker : Checkers) {
311 if (Checker.FullName.startswith(CheckerName) &&
312 (Checker.FullName.size() == Pos || Checker.FullName[Pos] == '.')) {
313 HasChecker = true;
Gabor Horvathfc4c4d42015-07-09 21:43:45 +0000314 break;
315 }
316 }
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000317 if (!HasChecker)
318 Diags.Report(diag::err_unknown_analyzer_checker) << CheckerName;
Gabor Horvathfc4c4d42015-07-09 21:43:45 +0000319 }
320}
321
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000322void CheckerRegistry::printCheckerWithDescList(raw_ostream &Out,
323 size_t MaxNameChars) const {
Jordy Rose59cce712011-08-16 21:24:21 +0000324 // FIXME: Print available packages.
325
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000326 Out << "CHECKERS:\n";
Jordy Rose59cce712011-08-16 21:24:21 +0000327
328 // Find the maximum option length.
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000329 size_t OptionFieldWidth = 0;
330 for (const auto &Checker : Checkers) {
Jordy Rose59cce712011-08-16 21:24:21 +0000331 // Limit the amount of padding we are willing to give up for alignment.
332 // Package.Name Description [Hidden]
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000333 size_t NameLength = Checker.FullName.size();
334 if (NameLength <= MaxNameChars)
335 OptionFieldWidth = std::max(OptionFieldWidth, NameLength);
Jordy Rose59cce712011-08-16 21:24:21 +0000336 }
337
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000338 const size_t InitialPad = 2;
339 for (const auto &Checker : Checkers) {
340 Out.indent(InitialPad) << Checker.FullName;
Jordy Rose59cce712011-08-16 21:24:21 +0000341
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000342 int Pad = OptionFieldWidth - Checker.FullName.size();
Jordy Rose59cce712011-08-16 21:24:21 +0000343
344 // Break on long option names.
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000345 if (Pad < 0) {
346 Out << '\n';
347 Pad = OptionFieldWidth + InitialPad;
Jordy Rose59cce712011-08-16 21:24:21 +0000348 }
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000349 Out.indent(Pad + 2) << Checker.Desc;
Jordy Rose59cce712011-08-16 21:24:21 +0000350
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000351 Out << '\n';
Jordy Rose59cce712011-08-16 21:24:21 +0000352 }
353}
Gabor Horvathc4309902016-08-08 13:41:04 +0000354
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000355void CheckerRegistry::printEnabledCheckerList(raw_ostream &Out) const {
Gabor Horvathc4309902016-08-08 13:41:04 +0000356 // Collect checkers enabled by the options.
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000357 CheckerInfoSet EnabledCheckers = getEnabledCheckers();
Gabor Horvathc4309902016-08-08 13:41:04 +0000358
Kristof Umannb9bc7ec2019-04-18 15:19:16 +0000359 for (const auto *i : EnabledCheckers)
360 Out << i->FullName << '\n';
Gabor Horvathc4309902016-08-08 13:41:04 +0000361}