CheckerRegistryData.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. //===- CheckerRegistry.h - Maintains all available checkers -----*- C++ -*-===//
  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/Core/CheckerRegistryData.h"
  9. #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
  10. #include "llvm/ADT/Twine.h"
  11. #include <map>
  12. using namespace clang;
  13. using namespace ento;
  14. //===----------------------------------------------------------------------===//
  15. // Methods of CmdLineOption, PackageInfo and CheckerInfo.
  16. //===----------------------------------------------------------------------===//
  17. LLVM_DUMP_METHOD void CmdLineOption::dump() const {
  18. dumpToStream(llvm::errs());
  19. }
  20. LLVM_DUMP_METHOD void
  21. CmdLineOption::dumpToStream(llvm::raw_ostream &Out) const {
  22. // The description can be just checked in Checkers.inc, the point here is to
  23. // debug whether we succeeded in parsing it.
  24. Out << OptionName << " (" << OptionType << ", "
  25. << (IsHidden ? "hidden, " : "") << DevelopmentStatus << ") default: \""
  26. << DefaultValStr;
  27. }
  28. static StringRef toString(StateFromCmdLine Kind) {
  29. switch (Kind) {
  30. case StateFromCmdLine::State_Disabled:
  31. return "Disabled";
  32. case StateFromCmdLine::State_Enabled:
  33. return "Enabled";
  34. case StateFromCmdLine::State_Unspecified:
  35. return "Unspecified";
  36. }
  37. llvm_unreachable("Unhandled StateFromCmdLine enum");
  38. }
  39. LLVM_DUMP_METHOD void CheckerInfo::dump() const { dumpToStream(llvm::errs()); }
  40. LLVM_DUMP_METHOD void CheckerInfo::dumpToStream(llvm::raw_ostream &Out) const {
  41. // The description can be just checked in Checkers.inc, the point here is to
  42. // debug whether we succeeded in parsing it. Same with documentation uri.
  43. Out << FullName << " (" << toString(State) << (IsHidden ? ", hidden" : "")
  44. << ")\n";
  45. Out << " Options:\n";
  46. for (const CmdLineOption &Option : CmdLineOptions) {
  47. Out << " ";
  48. Option.dumpToStream(Out);
  49. Out << '\n';
  50. }
  51. Out << " Dependencies:\n";
  52. for (const CheckerInfo *Dependency : Dependencies) {
  53. Out << " " << Dependency->FullName << '\n';
  54. }
  55. Out << " Weak dependencies:\n";
  56. for (const CheckerInfo *Dependency : WeakDependencies) {
  57. Out << " " << Dependency->FullName << '\n';
  58. }
  59. }
  60. LLVM_DUMP_METHOD void PackageInfo::dump() const { dumpToStream(llvm::errs()); }
  61. LLVM_DUMP_METHOD void PackageInfo::dumpToStream(llvm::raw_ostream &Out) const {
  62. Out << FullName << "\n";
  63. Out << " Options:\n";
  64. for (const CmdLineOption &Option : CmdLineOptions) {
  65. Out << " ";
  66. Option.dumpToStream(Out);
  67. Out << '\n';
  68. }
  69. }
  70. static constexpr char PackageSeparator = '.';
  71. static bool isInPackage(const CheckerInfo &Checker, StringRef PackageName) {
  72. // Does the checker's full name have the package as a prefix?
  73. if (!Checker.FullName.startswith(PackageName))
  74. return false;
  75. // Is the package actually just the name of a specific checker?
  76. if (Checker.FullName.size() == PackageName.size())
  77. return true;
  78. // Is the checker in the package (or a subpackage)?
  79. if (Checker.FullName[PackageName.size()] == PackageSeparator)
  80. return true;
  81. return false;
  82. }
  83. CheckerInfoListRange
  84. CheckerRegistryData::getMutableCheckersForCmdLineArg(StringRef CmdLineArg) {
  85. auto It = checker_registry::binaryFind(Checkers, CmdLineArg);
  86. if (!isInPackage(*It, CmdLineArg))
  87. return {Checkers.end(), Checkers.end()};
  88. // See how large the package is.
  89. // If the package doesn't exist, assume the option refers to a single
  90. // checker.
  91. size_t Size = 1;
  92. llvm::StringMap<size_t>::const_iterator PackageSize =
  93. PackageSizes.find(CmdLineArg);
  94. if (PackageSize != PackageSizes.end())
  95. Size = PackageSize->getValue();
  96. return {It, It + Size};
  97. }
  98. //===----------------------------------------------------------------------===//
  99. // Printing functions.
  100. //===----------------------------------------------------------------------===//
  101. void CheckerRegistryData::printCheckerWithDescList(
  102. const AnalyzerOptions &AnOpts, raw_ostream &Out,
  103. size_t MaxNameChars) const {
  104. // FIXME: Print available packages.
  105. Out << "CHECKERS:\n";
  106. // Find the maximum option length.
  107. size_t OptionFieldWidth = 0;
  108. for (const auto &Checker : Checkers) {
  109. // Limit the amount of padding we are willing to give up for alignment.
  110. // Package.Name Description [Hidden]
  111. size_t NameLength = Checker.FullName.size();
  112. if (NameLength <= MaxNameChars)
  113. OptionFieldWidth = std::max(OptionFieldWidth, NameLength);
  114. }
  115. const size_t InitialPad = 2;
  116. auto Print = [=](llvm::raw_ostream &Out, const CheckerInfo &Checker,
  117. StringRef Description) {
  118. AnalyzerOptions::printFormattedEntry(Out, {Checker.FullName, Description},
  119. InitialPad, OptionFieldWidth);
  120. Out << '\n';
  121. };
  122. for (const auto &Checker : Checkers) {
  123. // The order of this if branches is significant, we wouldn't like to display
  124. // developer checkers even in the alpha output. For example,
  125. // alpha.cplusplus.IteratorModeling is a modeling checker, hence it's hidden
  126. // by default, and users (even when the user is a developer of an alpha
  127. // checker) shouldn't normally tinker with whether they should be enabled.
  128. if (Checker.IsHidden) {
  129. if (AnOpts.ShowCheckerHelpDeveloper)
  130. Print(Out, Checker, Checker.Desc);
  131. continue;
  132. }
  133. if (Checker.FullName.startswith("alpha")) {
  134. if (AnOpts.ShowCheckerHelpAlpha)
  135. Print(Out, Checker,
  136. ("(Enable only for development!) " + Checker.Desc).str());
  137. continue;
  138. }
  139. if (AnOpts.ShowCheckerHelp)
  140. Print(Out, Checker, Checker.Desc);
  141. }
  142. }
  143. void CheckerRegistryData::printEnabledCheckerList(raw_ostream &Out) const {
  144. for (const auto *i : EnabledCheckers)
  145. Out << i->FullName << '\n';
  146. }
  147. void CheckerRegistryData::printCheckerOptionList(const AnalyzerOptions &AnOpts,
  148. raw_ostream &Out) const {
  149. Out << "OVERVIEW: Clang Static Analyzer Checker and Package Option List\n\n";
  150. Out << "USAGE: -analyzer-config <OPTION1=VALUE,OPTION2=VALUE,...>\n\n";
  151. Out << " -analyzer-config OPTION1=VALUE, -analyzer-config "
  152. "OPTION2=VALUE, ...\n\n";
  153. Out << "OPTIONS:\n\n";
  154. // It's usually ill-advised to use multimap, but clang will terminate after
  155. // this function.
  156. std::multimap<StringRef, const CmdLineOption &> OptionMap;
  157. for (const CheckerInfo &Checker : Checkers) {
  158. for (const CmdLineOption &Option : Checker.CmdLineOptions) {
  159. OptionMap.insert({Checker.FullName, Option});
  160. }
  161. }
  162. for (const PackageInfo &Package : Packages) {
  163. for (const CmdLineOption &Option : Package.CmdLineOptions) {
  164. OptionMap.insert({Package.FullName, Option});
  165. }
  166. }
  167. auto Print = [](llvm::raw_ostream &Out, StringRef FullOption,
  168. StringRef Desc) {
  169. AnalyzerOptions::printFormattedEntry(Out, {FullOption, Desc},
  170. /*InitialPad*/ 2,
  171. /*EntryWidth*/ 50,
  172. /*MinLineWidth*/ 90);
  173. Out << "\n\n";
  174. };
  175. for (const std::pair<const StringRef, const CmdLineOption &> &Entry :
  176. OptionMap) {
  177. const CmdLineOption &Option = Entry.second;
  178. std::string FullOption = (Entry.first + ":" + Option.OptionName).str();
  179. std::string Desc =
  180. ("(" + Option.OptionType + ") " + Option.Description + " (default: " +
  181. (Option.DefaultValStr.empty() ? "\"\"" : Option.DefaultValStr) + ")")
  182. .str();
  183. // The list of these if branches is significant, we wouldn't like to
  184. // display hidden alpha checker options for
  185. // -analyzer-checker-option-help-alpha.
  186. if (Option.IsHidden) {
  187. if (AnOpts.ShowCheckerOptionDeveloperList)
  188. Print(Out, FullOption, Desc);
  189. continue;
  190. }
  191. if (Option.DevelopmentStatus == "alpha" ||
  192. Entry.first.startswith("alpha")) {
  193. if (AnOpts.ShowCheckerOptionAlphaList)
  194. Print(Out, FullOption,
  195. llvm::Twine("(Enable only for development!) " + Desc).str());
  196. continue;
  197. }
  198. if (AnOpts.ShowCheckerOptionList)
  199. Print(Out, FullOption, Desc);
  200. }
  201. }