CheckerRegistry.cpp 22 KB

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