1 //===- CheckerRegistry.cpp - Maintains all available checkers -------------===//
2 //
3 // 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
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h"
10 #include "clang/Basic/Diagnostic.h"
11 #include "clang/Basic/LLVM.h"
12 #include "clang/Driver/DriverDiagnostic.h"
13 #include "clang/Frontend/FrontendDiagnostic.h"
14 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
15 #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
16 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
17 #include "llvm/ADT/STLExtras.h"
18 #include "llvm/ADT/SetVector.h"
19 #include "llvm/ADT/StringMap.h"
20 #include "llvm/ADT/StringRef.h"
21 #include "llvm/Support/DynamicLibrary.h"
22 #include "llvm/Support/Path.h"
23 #include "llvm/Support/raw_ostream.h"
24 #include <algorithm>
25
26 using namespace clang;
27 using namespace ento;
28 using llvm::sys::DynamicLibrary;
29
30 using RegisterCheckersFn = void (*)(CheckerRegistry &);
31
isCompatibleAPIVersion(const char * VersionString)32 static bool isCompatibleAPIVersion(const char *VersionString) {
33 // If the version string is null, its not an analyzer plugin.
34 if (!VersionString)
35 return false;
36
37 // For now, none of the static analyzer API is considered stable.
38 // Versions must match exactly.
39 return strcmp(VersionString, CLANG_ANALYZER_API_VERSION_STRING) == 0;
40 }
41
42 namespace {
43 template <class T> struct FullNameLT {
operator ()__anond4f778640111::FullNameLT44 bool operator()(const T &Lhs, const T &Rhs) {
45 return Lhs.FullName < Rhs.FullName;
46 }
47 };
48
49 using PackageNameLT = FullNameLT<CheckerRegistry::PackageInfo>;
50 using CheckerNameLT = FullNameLT<CheckerRegistry::CheckerInfo>;
51 } // end of anonymous namespace
52
53 template <class CheckerOrPackageInfoList>
54 static
55 typename std::conditional<std::is_const<CheckerOrPackageInfoList>::value,
56 typename CheckerOrPackageInfoList::const_iterator,
57 typename CheckerOrPackageInfoList::iterator>::type
binaryFind(CheckerOrPackageInfoList & Collection,StringRef FullName)58 binaryFind(CheckerOrPackageInfoList &Collection, StringRef FullName) {
59
60 using CheckerOrPackage = typename CheckerOrPackageInfoList::value_type;
61 using CheckerOrPackageFullNameLT = FullNameLT<CheckerOrPackage>;
62
63 assert(std::is_sorted(Collection.begin(), Collection.end(),
64 CheckerOrPackageFullNameLT{}) &&
65 "In order to efficiently gather checkers/packages, this function "
66 "expects them to be already sorted!");
67
68 return llvm::lower_bound(Collection, CheckerOrPackage(FullName),
69 CheckerOrPackageFullNameLT{});
70 }
71
72 static constexpr char PackageSeparator = '.';
73
isInPackage(const CheckerRegistry::CheckerInfo & Checker,StringRef PackageName)74 static bool isInPackage(const CheckerRegistry::CheckerInfo &Checker,
75 StringRef PackageName) {
76 // Does the checker's full name have the package as a prefix?
77 if (!Checker.FullName.startswith(PackageName))
78 return false;
79
80 // Is the package actually just the name of a specific checker?
81 if (Checker.FullName.size() == PackageName.size())
82 return true;
83
84 // Is the checker in the package (or a subpackage)?
85 if (Checker.FullName[PackageName.size()] == PackageSeparator)
86 return true;
87
88 return false;
89 }
90
91 CheckerRegistry::CheckerInfoListRange
getMutableCheckersForCmdLineArg(StringRef CmdLineArg)92 CheckerRegistry::getMutableCheckersForCmdLineArg(StringRef CmdLineArg) {
93 auto It = binaryFind(Checkers, CmdLineArg);
94
95 if (!isInPackage(*It, CmdLineArg))
96 return {Checkers.end(), Checkers.end()};
97
98 // See how large the package is.
99 // If the package doesn't exist, assume the option refers to a single
100 // checker.
101 size_t Size = 1;
102 llvm::StringMap<size_t>::const_iterator PackageSize =
103 PackageSizes.find(CmdLineArg);
104
105 if (PackageSize != PackageSizes.end())
106 Size = PackageSize->getValue();
107
108 return {It, It + Size};
109 }
110
CheckerRegistry(ArrayRef<std::string> Plugins,DiagnosticsEngine & Diags,AnalyzerOptions & AnOpts,const LangOptions & LangOpts,ArrayRef<std::function<void (CheckerRegistry &)>> CheckerRegistrationFns)111 CheckerRegistry::CheckerRegistry(
112 ArrayRef<std::string> Plugins, DiagnosticsEngine &Diags,
113 AnalyzerOptions &AnOpts, const LangOptions &LangOpts,
114 ArrayRef<std::function<void(CheckerRegistry &)>> CheckerRegistrationFns)
115 : Diags(Diags), AnOpts(AnOpts), LangOpts(LangOpts) {
116
117 // Register builtin checkers.
118 #define GET_CHECKERS
119 #define CHECKER(FULLNAME, CLASS, HELPTEXT, DOC_URI, IS_HIDDEN) \
120 addChecker(register##CLASS, shouldRegister##CLASS, FULLNAME, HELPTEXT, \
121 DOC_URI, IS_HIDDEN);
122
123 #define GET_PACKAGES
124 #define PACKAGE(FULLNAME) addPackage(FULLNAME);
125
126 #include "clang/StaticAnalyzer/Checkers/Checkers.inc"
127 #undef CHECKER
128 #undef GET_CHECKERS
129 #undef PACKAGE
130 #undef GET_PACKAGES
131
132 // Register checkers from plugins.
133 for (const std::string &Plugin : Plugins) {
134 // Get access to the plugin.
135 std::string ErrorMsg;
136 DynamicLibrary Lib =
137 DynamicLibrary::getPermanentLibrary(Plugin.c_str(), &ErrorMsg);
138 if (!Lib.isValid()) {
139 Diags.Report(diag::err_fe_unable_to_load_plugin) << Plugin << ErrorMsg;
140 continue;
141 }
142
143 // See if its compatible with this build of clang.
144 const char *PluginAPIVersion = static_cast<const char *>(
145 Lib.getAddressOfSymbol("clang_analyzerAPIVersionString"));
146
147 if (!isCompatibleAPIVersion(PluginAPIVersion)) {
148 Diags.Report(diag::warn_incompatible_analyzer_plugin_api)
149 << llvm::sys::path::filename(Plugin);
150 Diags.Report(diag::note_incompatible_analyzer_plugin_api)
151 << CLANG_ANALYZER_API_VERSION_STRING << PluginAPIVersion;
152 continue;
153 }
154
155 // Register its checkers.
156 RegisterCheckersFn RegisterPluginCheckers =
157 reinterpret_cast<RegisterCheckersFn>(
158 Lib.getAddressOfSymbol("clang_registerCheckers"));
159 if (RegisterPluginCheckers)
160 RegisterPluginCheckers(*this);
161 }
162
163 // Register statically linked checkers, that aren't generated from the tblgen
164 // file, but rather passed their registry function as a parameter in
165 // checkerRegistrationFns.
166
167 for (const auto &Fn : CheckerRegistrationFns)
168 Fn(*this);
169
170 // Sort checkers for efficient collection.
171 // FIXME: Alphabetical sort puts 'experimental' in the middle.
172 // Would it be better to name it '~experimental' or something else
173 // that's ASCIIbetically last?
174 llvm::sort(Packages, PackageNameLT{});
175 llvm::sort(Checkers, CheckerNameLT{});
176
177 #define GET_CHECKER_DEPENDENCIES
178
179 #define CHECKER_DEPENDENCY(FULLNAME, DEPENDENCY) \
180 addDependency(FULLNAME, DEPENDENCY);
181
182 #define GET_CHECKER_OPTIONS
183 #define CHECKER_OPTION(TYPE, FULLNAME, CMDFLAG, DESC, DEFAULT_VAL, DEVELOPMENT_STATUS, IS_HIDDEN) \
184 addCheckerOption(TYPE, FULLNAME, CMDFLAG, DEFAULT_VAL, DESC, DEVELOPMENT_STATUS, IS_HIDDEN);
185
186 #define GET_PACKAGE_OPTIONS
187 #define PACKAGE_OPTION(TYPE, FULLNAME, CMDFLAG, DESC, DEFAULT_VAL, DEVELOPMENT_STATUS, IS_HIDDEN) \
188 addPackageOption(TYPE, FULLNAME, CMDFLAG, DEFAULT_VAL, DESC, DEVELOPMENT_STATUS, IS_HIDDEN);
189
190 #include "clang/StaticAnalyzer/Checkers/Checkers.inc"
191 #undef CHECKER_DEPENDENCY
192 #undef GET_CHECKER_DEPENDENCIES
193 #undef CHECKER_OPTION
194 #undef GET_CHECKER_OPTIONS
195 #undef PACKAGE_OPTION
196 #undef GET_PACKAGE_OPTIONS
197
198 resolveDependencies();
199 resolveCheckerAndPackageOptions();
200
201 // Parse '-analyzer-checker' and '-analyzer-disable-checker' options from the
202 // command line.
203 for (const std::pair<std::string, bool> &Opt : AnOpts.CheckersControlList) {
204 CheckerInfoListRange CheckerForCmdLineArg =
205 getMutableCheckersForCmdLineArg(Opt.first);
206
207 if (CheckerForCmdLineArg.begin() == CheckerForCmdLineArg.end()) {
208 Diags.Report(diag::err_unknown_analyzer_checker) << Opt.first;
209 Diags.Report(diag::note_suggest_disabling_all_checkers);
210 }
211
212 for (CheckerInfo &checker : CheckerForCmdLineArg) {
213 checker.State = Opt.second ? StateFromCmdLine::State_Enabled
214 : StateFromCmdLine::State_Disabled;
215 }
216 }
217 }
218
219 /// Collects dependencies in \p ret, returns false on failure.
220 static bool
221 collectDependenciesImpl(const CheckerRegistry::ConstCheckerInfoList &Deps,
222 const LangOptions &LO,
223 CheckerRegistry::CheckerInfoSet &Ret);
224
225 /// Collects dependenies in \p enabledCheckers. Return None on failure.
226 LLVM_NODISCARD
227 static llvm::Optional<CheckerRegistry::CheckerInfoSet>
collectDependencies(const CheckerRegistry::CheckerInfo & checker,const LangOptions & LO)228 collectDependencies(const CheckerRegistry::CheckerInfo &checker,
229 const LangOptions &LO) {
230
231 CheckerRegistry::CheckerInfoSet Ret;
232 // Add dependencies to the enabled checkers only if all of them can be
233 // enabled.
234 if (!collectDependenciesImpl(checker.Dependencies, LO, Ret))
235 return None;
236
237 return Ret;
238 }
239
240 static bool
collectDependenciesImpl(const CheckerRegistry::ConstCheckerInfoList & Deps,const LangOptions & LO,CheckerRegistry::CheckerInfoSet & Ret)241 collectDependenciesImpl(const CheckerRegistry::ConstCheckerInfoList &Deps,
242 const LangOptions &LO,
243 CheckerRegistry::CheckerInfoSet &Ret) {
244
245 for (const CheckerRegistry::CheckerInfo *Dependency : Deps) {
246
247 if (Dependency->isDisabled(LO))
248 return false;
249
250 // Collect dependencies recursively.
251 if (!collectDependenciesImpl(Dependency->Dependencies, LO, Ret))
252 return false;
253
254 Ret.insert(Dependency);
255 }
256
257 return true;
258 }
259
getEnabledCheckers() const260 CheckerRegistry::CheckerInfoSet CheckerRegistry::getEnabledCheckers() const {
261
262 CheckerInfoSet EnabledCheckers;
263
264 for (const CheckerInfo &Checker : Checkers) {
265 if (!Checker.isEnabled(LangOpts))
266 continue;
267
268 // Recursively enable its dependencies.
269 llvm::Optional<CheckerInfoSet> Deps =
270 collectDependencies(Checker, LangOpts);
271
272 if (!Deps) {
273 // If we failed to enable any of the dependencies, don't enable this
274 // checker.
275 continue;
276 }
277
278 // Note that set_union also preserves the order of insertion.
279 EnabledCheckers.set_union(*Deps);
280
281 // Enable the checker.
282 EnabledCheckers.insert(&Checker);
283 }
284
285 return EnabledCheckers;
286 }
287
resolveDependencies()288 void CheckerRegistry::resolveDependencies() {
289 for (const std::pair<StringRef, StringRef> &Entry : Dependencies) {
290 auto CheckerIt = binaryFind(Checkers, Entry.first);
291 assert(CheckerIt != Checkers.end() && CheckerIt->FullName == Entry.first &&
292 "Failed to find the checker while attempting to set up its "
293 "dependencies!");
294
295 auto DependencyIt = binaryFind(Checkers, Entry.second);
296 assert(DependencyIt != Checkers.end() &&
297 DependencyIt->FullName == Entry.second &&
298 "Failed to find the dependency of a checker!");
299
300 CheckerIt->Dependencies.emplace_back(&*DependencyIt);
301 }
302
303 Dependencies.clear();
304 }
305
addDependency(StringRef FullName,StringRef Dependency)306 void CheckerRegistry::addDependency(StringRef FullName, StringRef Dependency) {
307 Dependencies.emplace_back(FullName, Dependency);
308 }
309
310 /// Insert the checker/package option to AnalyzerOptions' config table, and
311 /// validate it, if the user supplied it on the command line.
insertAndValidate(StringRef FullName,const CheckerRegistry::CmdLineOption & Option,AnalyzerOptions & AnOpts,DiagnosticsEngine & Diags)312 static void insertAndValidate(StringRef FullName,
313 const CheckerRegistry::CmdLineOption &Option,
314 AnalyzerOptions &AnOpts,
315 DiagnosticsEngine &Diags) {
316
317 std::string FullOption = (FullName + ":" + Option.OptionName).str();
318
319 auto It = AnOpts.Config.insert({FullOption, Option.DefaultValStr});
320
321 // Insertation was successful -- CmdLineOption's constructor will validate
322 // whether values received from plugins or TableGen files are correct.
323 if (It.second)
324 return;
325
326 // Insertion failed, the user supplied this package/checker option on the
327 // command line. If the supplied value is invalid, we'll restore the option
328 // to it's default value, and if we're in non-compatibility mode, we'll also
329 // emit an error.
330
331 StringRef SuppliedValue = It.first->getValue();
332
333 if (Option.OptionType == "bool") {
334 if (SuppliedValue != "true" && SuppliedValue != "false") {
335 if (AnOpts.ShouldEmitErrorsOnInvalidConfigValue) {
336 Diags.Report(diag::err_analyzer_checker_option_invalid_input)
337 << FullOption << "a boolean value";
338 }
339
340 It.first->setValue(Option.DefaultValStr);
341 }
342 return;
343 }
344
345 if (Option.OptionType == "int") {
346 int Tmp;
347 bool HasFailed = SuppliedValue.getAsInteger(0, Tmp);
348 if (HasFailed) {
349 if (AnOpts.ShouldEmitErrorsOnInvalidConfigValue) {
350 Diags.Report(diag::err_analyzer_checker_option_invalid_input)
351 << FullOption << "an integer value";
352 }
353
354 It.first->setValue(Option.DefaultValStr);
355 }
356 return;
357 }
358 }
359
360 template <class T>
361 static void
insertOptionToCollection(StringRef FullName,T & Collection,const CheckerRegistry::CmdLineOption & Option,AnalyzerOptions & AnOpts,DiagnosticsEngine & Diags)362 insertOptionToCollection(StringRef FullName, T &Collection,
363 const CheckerRegistry::CmdLineOption &Option,
364 AnalyzerOptions &AnOpts, DiagnosticsEngine &Diags) {
365 auto It = binaryFind(Collection, FullName);
366 assert(It != Collection.end() &&
367 "Failed to find the checker while attempting to add a command line "
368 "option to it!");
369
370 insertAndValidate(FullName, Option, AnOpts, Diags);
371
372 It->CmdLineOptions.emplace_back(Option);
373 }
374
resolveCheckerAndPackageOptions()375 void CheckerRegistry::resolveCheckerAndPackageOptions() {
376 for (const std::pair<StringRef, CmdLineOption> &CheckerOptEntry :
377 CheckerOptions) {
378 insertOptionToCollection(CheckerOptEntry.first, Checkers,
379 CheckerOptEntry.second, AnOpts, Diags);
380 }
381 CheckerOptions.clear();
382
383 for (const std::pair<StringRef, CmdLineOption> &PackageOptEntry :
384 PackageOptions) {
385 insertOptionToCollection(PackageOptEntry.first, Packages,
386 PackageOptEntry.second, AnOpts, Diags);
387 }
388 PackageOptions.clear();
389 }
390
addPackage(StringRef FullName)391 void CheckerRegistry::addPackage(StringRef FullName) {
392 Packages.emplace_back(PackageInfo(FullName));
393 }
394
addPackageOption(StringRef OptionType,StringRef PackageFullName,StringRef OptionName,StringRef DefaultValStr,StringRef Description,StringRef DevelopmentStatus,bool IsHidden)395 void CheckerRegistry::addPackageOption(StringRef OptionType,
396 StringRef PackageFullName,
397 StringRef OptionName,
398 StringRef DefaultValStr,
399 StringRef Description,
400 StringRef DevelopmentStatus,
401 bool IsHidden) {
402 PackageOptions.emplace_back(
403 PackageFullName, CmdLineOption{OptionType, OptionName, DefaultValStr,
404 Description, DevelopmentStatus, IsHidden});
405 }
406
addChecker(InitializationFunction Rfn,ShouldRegisterFunction Sfn,StringRef Name,StringRef Desc,StringRef DocsUri,bool IsHidden)407 void CheckerRegistry::addChecker(InitializationFunction Rfn,
408 ShouldRegisterFunction Sfn, StringRef Name,
409 StringRef Desc, StringRef DocsUri,
410 bool IsHidden) {
411 Checkers.emplace_back(Rfn, Sfn, Name, Desc, DocsUri, IsHidden);
412
413 // Record the presence of the checker in its packages.
414 StringRef PackageName, LeafName;
415 std::tie(PackageName, LeafName) = Name.rsplit(PackageSeparator);
416 while (!LeafName.empty()) {
417 PackageSizes[PackageName] += 1;
418 std::tie(PackageName, LeafName) = PackageName.rsplit(PackageSeparator);
419 }
420 }
421
addCheckerOption(StringRef OptionType,StringRef CheckerFullName,StringRef OptionName,StringRef DefaultValStr,StringRef Description,StringRef DevelopmentStatus,bool IsHidden)422 void CheckerRegistry::addCheckerOption(StringRef OptionType,
423 StringRef CheckerFullName,
424 StringRef OptionName,
425 StringRef DefaultValStr,
426 StringRef Description,
427 StringRef DevelopmentStatus,
428 bool IsHidden) {
429 CheckerOptions.emplace_back(
430 CheckerFullName, CmdLineOption{OptionType, OptionName, DefaultValStr,
431 Description, DevelopmentStatus, IsHidden});
432 }
433
initializeManager(CheckerManager & CheckerMgr) const434 void CheckerRegistry::initializeManager(CheckerManager &CheckerMgr) const {
435 // Collect checkers enabled by the options.
436 CheckerInfoSet enabledCheckers = getEnabledCheckers();
437
438 // Initialize the CheckerManager with all enabled checkers.
439 for (const auto *Checker : enabledCheckers) {
440 CheckerMgr.setCurrentCheckName(CheckName(Checker->FullName));
441 Checker->Initialize(CheckerMgr);
442 }
443 }
444
445 static void
isOptionContainedIn(const CheckerRegistry::CmdLineOptionList & OptionList,StringRef SuppliedChecker,StringRef SuppliedOption,const AnalyzerOptions & AnOpts,DiagnosticsEngine & Diags)446 isOptionContainedIn(const CheckerRegistry::CmdLineOptionList &OptionList,
447 StringRef SuppliedChecker, StringRef SuppliedOption,
448 const AnalyzerOptions &AnOpts, DiagnosticsEngine &Diags) {
449
450 if (!AnOpts.ShouldEmitErrorsOnInvalidConfigValue)
451 return;
452
453 using CmdLineOption = CheckerRegistry::CmdLineOption;
454
455 auto SameOptName = [SuppliedOption](const CmdLineOption &Opt) {
456 return Opt.OptionName == SuppliedOption;
457 };
458
459 auto OptionIt = llvm::find_if(OptionList, SameOptName);
460
461 if (OptionIt == OptionList.end()) {
462 Diags.Report(diag::err_analyzer_checker_option_unknown)
463 << SuppliedChecker << SuppliedOption;
464 return;
465 }
466 }
467
validateCheckerOptions() const468 void CheckerRegistry::validateCheckerOptions() const {
469 for (const auto &Config : AnOpts.Config) {
470
471 StringRef SuppliedChecker;
472 StringRef SuppliedOption;
473 std::tie(SuppliedChecker, SuppliedOption) = Config.getKey().split(':');
474
475 if (SuppliedOption.empty())
476 continue;
477
478 // AnalyzerOptions' config table contains the user input, so an entry could
479 // look like this:
480 //
481 // cor:NoFalsePositives=true
482 //
483 // Since lower_bound would look for the first element *not less* than "cor",
484 // it would return with an iterator to the first checker in the core, so we
485 // we really have to use find here, which uses operator==.
486 auto CheckerIt = llvm::find(Checkers, CheckerInfo(SuppliedChecker));
487 if (CheckerIt != Checkers.end()) {
488 isOptionContainedIn(CheckerIt->CmdLineOptions, SuppliedChecker,
489 SuppliedOption, AnOpts, Diags);
490 continue;
491 }
492
493 auto PackageIt = llvm::find(Packages, PackageInfo(SuppliedChecker));
494 if (PackageIt != Packages.end()) {
495 isOptionContainedIn(PackageIt->CmdLineOptions, SuppliedChecker,
496 SuppliedOption, AnOpts, Diags);
497 continue;
498 }
499
500 Diags.Report(diag::err_unknown_analyzer_checker) << SuppliedChecker;
501 }
502 }
503
printCheckerWithDescList(raw_ostream & Out,size_t MaxNameChars) const504 void CheckerRegistry::printCheckerWithDescList(raw_ostream &Out,
505 size_t MaxNameChars) const {
506 // FIXME: Print available packages.
507
508 Out << "CHECKERS:\n";
509
510 // Find the maximum option length.
511 size_t OptionFieldWidth = 0;
512 for (const auto &Checker : Checkers) {
513 // Limit the amount of padding we are willing to give up for alignment.
514 // Package.Name Description [Hidden]
515 size_t NameLength = Checker.FullName.size();
516 if (NameLength <= MaxNameChars)
517 OptionFieldWidth = std::max(OptionFieldWidth, NameLength);
518 }
519
520 const size_t InitialPad = 2;
521
522 auto Print = [=](llvm::raw_ostream &Out, const CheckerInfo &Checker,
523 StringRef Description) {
524 AnalyzerOptions::printFormattedEntry(Out, {Checker.FullName, Description},
525 InitialPad, OptionFieldWidth);
526 Out << '\n';
527 };
528
529 for (const auto &Checker : Checkers) {
530 // The order of this if branches is significant, we wouldn't like to display
531 // developer checkers even in the alpha output. For example,
532 // alpha.cplusplus.IteratorModeling is a modeling checker, hence it's hidden
533 // by default, and users (even when the user is a developer of an alpha
534 // checker) shouldn't normally tinker with whether they should be enabled.
535
536 if (Checker.IsHidden) {
537 if (AnOpts.ShowCheckerHelpDeveloper)
538 Print(Out, Checker, Checker.Desc);
539 continue;
540 }
541
542 if (Checker.FullName.startswith("alpha")) {
543 if (AnOpts.ShowCheckerHelpAlpha)
544 Print(Out, Checker,
545 ("(Enable only for development!) " + Checker.Desc).str());
546 continue;
547 }
548
549 if (AnOpts.ShowCheckerHelp)
550 Print(Out, Checker, Checker.Desc);
551 }
552 }
553
printEnabledCheckerList(raw_ostream & Out) const554 void CheckerRegistry::printEnabledCheckerList(raw_ostream &Out) const {
555 // Collect checkers enabled by the options.
556 CheckerInfoSet EnabledCheckers = getEnabledCheckers();
557
558 for (const auto *i : EnabledCheckers)
559 Out << i->FullName << '\n';
560 }
561
printCheckerOptionList(raw_ostream & Out) const562 void CheckerRegistry::printCheckerOptionList(raw_ostream &Out) const {
563 Out << "OVERVIEW: Clang Static Analyzer Checker and Package Option List\n\n";
564 Out << "USAGE: -analyzer-config <OPTION1=VALUE,OPTION2=VALUE,...>\n\n";
565 Out << " -analyzer-config OPTION1=VALUE, -analyzer-config "
566 "OPTION2=VALUE, ...\n\n";
567 Out << "OPTIONS:\n\n";
568
569 std::multimap<StringRef, const CmdLineOption &> OptionMap;
570
571 for (const CheckerInfo &Checker : Checkers) {
572 for (const CmdLineOption &Option : Checker.CmdLineOptions) {
573 OptionMap.insert({Checker.FullName, Option});
574 }
575 }
576
577 for (const PackageInfo &Package : Packages) {
578 for (const CmdLineOption &Option : Package.CmdLineOptions) {
579 OptionMap.insert({Package.FullName, Option});
580 }
581 }
582
583 auto Print = [] (llvm::raw_ostream &Out, StringRef FullOption, StringRef Desc) {
584 AnalyzerOptions::printFormattedEntry(Out, {FullOption, Desc},
585 /*InitialPad*/ 2,
586 /*EntryWidth*/ 50,
587 /*MinLineWidth*/ 90);
588 Out << "\n\n";
589 };
590 for (const std::pair<StringRef, const CmdLineOption &> &Entry : OptionMap) {
591 const CmdLineOption &Option = Entry.second;
592 std::string FullOption = (Entry.first + ":" + Option.OptionName).str();
593
594 std::string Desc =
595 ("(" + Option.OptionType + ") " + Option.Description + " (default: " +
596 (Option.DefaultValStr.empty() ? "\"\"" : Option.DefaultValStr) + ")")
597 .str();
598
599 // The list of these if branches is significant, we wouldn't like to
600 // display hidden alpha checker options for
601 // -analyzer-checker-option-help-alpha.
602
603 if (Option.IsHidden) {
604 if (AnOpts.ShowCheckerOptionDeveloperList)
605 Print(Out, FullOption, Desc);
606 continue;
607 }
608
609 if (Option.DevelopmentStatus == "alpha" ||
610 Entry.first.startswith("alpha")) {
611 if (AnOpts.ShowCheckerOptionAlphaList)
612 Print(Out, FullOption,
613 llvm::Twine("(Enable only for development!) " + Desc).str());
614 continue;
615 }
616
617 if (AnOpts.ShowCheckerOptionList)
618 Print(Out, FullOption, Desc);
619 }
620 }
621