CheckerRegistry.cpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. //===--- CheckerRegistry.cpp - Maintains all available checkers -*- C++ -*-===//
  2. //
  3. // The LLVM Compiler Infrastructure
  4. //
  5. // This file is distributed under the University of Illinois Open Source
  6. // License. See LICENSE.TXT for details.
  7. //
  8. //===----------------------------------------------------------------------===//
  9. #include "clang/StaticAnalyzer/Core/CheckerRegistry.h"
  10. #include "clang/Basic/Diagnostic.h"
  11. #include "clang/Frontend/FrontendDiagnostic.h"
  12. #include "clang/StaticAnalyzer/Core/CheckerOptInfo.h"
  13. #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
  14. #include "llvm/ADT/SetVector.h"
  15. #include "llvm/Support/raw_ostream.h"
  16. using namespace clang;
  17. using namespace ento;
  18. static const char PackageSeparator = '.';
  19. typedef llvm::SetVector<const CheckerRegistry::CheckerInfo *> CheckerInfoSet;
  20. static bool checkerNameLT(const CheckerRegistry::CheckerInfo &a,
  21. const CheckerRegistry::CheckerInfo &b) {
  22. return a.FullName < b.FullName;
  23. }
  24. static bool isInPackage(const CheckerRegistry::CheckerInfo &checker,
  25. StringRef packageName) {
  26. // Does the checker's full name have the package as a prefix?
  27. if (!checker.FullName.startswith(packageName))
  28. return false;
  29. // Is the package actually just the name of a specific checker?
  30. if (checker.FullName.size() == packageName.size())
  31. return true;
  32. // Is the checker in the package (or a subpackage)?
  33. if (checker.FullName[packageName.size()] == PackageSeparator)
  34. return true;
  35. return false;
  36. }
  37. static void collectCheckers(const CheckerRegistry::CheckerInfoList &checkers,
  38. const llvm::StringMap<size_t> &packageSizes,
  39. CheckerOptInfo &opt, CheckerInfoSet &collected) {
  40. // Use a binary search to find the possible start of the package.
  41. CheckerRegistry::CheckerInfo packageInfo(nullptr, opt.getName(), "");
  42. CheckerRegistry::CheckerInfoList::const_iterator e = checkers.end();
  43. CheckerRegistry::CheckerInfoList::const_iterator i =
  44. std::lower_bound(checkers.begin(), e, packageInfo, checkerNameLT);
  45. // If we didn't even find a possible package, give up.
  46. if (i == e)
  47. return;
  48. // If what we found doesn't actually start the package, give up.
  49. if (!isInPackage(*i, opt.getName()))
  50. return;
  51. // There is at least one checker in the package; claim the option.
  52. opt.claim();
  53. // See how large the package is.
  54. // If the package doesn't exist, assume the option refers to a single checker.
  55. size_t size = 1;
  56. llvm::StringMap<size_t>::const_iterator packageSize =
  57. packageSizes.find(opt.getName());
  58. if (packageSize != packageSizes.end())
  59. size = packageSize->getValue();
  60. // Step through all the checkers in the package.
  61. for (e = i+size; i != e; ++i) {
  62. if (opt.isEnabled())
  63. collected.insert(&*i);
  64. else
  65. collected.remove(&*i);
  66. }
  67. }
  68. void CheckerRegistry::addChecker(InitializationFunction fn, StringRef name,
  69. StringRef desc) {
  70. Checkers.push_back(CheckerInfo(fn, name, desc));
  71. // Record the presence of the checker in its packages.
  72. StringRef packageName, leafName;
  73. std::tie(packageName, leafName) = name.rsplit(PackageSeparator);
  74. while (!leafName.empty()) {
  75. Packages[packageName] += 1;
  76. std::tie(packageName, leafName) = packageName.rsplit(PackageSeparator);
  77. }
  78. }
  79. void CheckerRegistry::initializeManager(CheckerManager &checkerMgr,
  80. SmallVectorImpl<CheckerOptInfo> &opts) const {
  81. // Sort checkers for efficient collection.
  82. std::sort(Checkers.begin(), Checkers.end(), checkerNameLT);
  83. // Collect checkers enabled by the options.
  84. CheckerInfoSet enabledCheckers;
  85. for (SmallVectorImpl<CheckerOptInfo>::iterator
  86. i = opts.begin(), e = opts.end(); i != e; ++i) {
  87. collectCheckers(Checkers, Packages, *i, enabledCheckers);
  88. }
  89. // Initialize the CheckerManager with all enabled checkers.
  90. for (CheckerInfoSet::iterator
  91. i = enabledCheckers.begin(), e = enabledCheckers.end(); i != e; ++i) {
  92. checkerMgr.setCurrentCheckName(CheckName((*i)->FullName));
  93. (*i)->Initialize(checkerMgr);
  94. }
  95. }
  96. void CheckerRegistry::validateCheckerOptions(const AnalyzerOptions &opts,
  97. DiagnosticsEngine &diags) const {
  98. for (auto &config : opts.Config) {
  99. size_t pos = config.getKey().find(':');
  100. if (pos == StringRef::npos)
  101. continue;
  102. bool hasChecker = false;
  103. StringRef checkerName = config.getKey().substr(0, pos);
  104. for (auto &checker : Checkers) {
  105. if (checker.FullName.startswith(checkerName) &&
  106. (checker.FullName.size() == pos || checker.FullName[pos] == '.')) {
  107. hasChecker = true;
  108. break;
  109. }
  110. }
  111. if (!hasChecker) {
  112. diags.Report(diag::err_unknown_analyzer_checker) << checkerName;
  113. }
  114. }
  115. }
  116. void CheckerRegistry::printHelp(raw_ostream &out,
  117. size_t maxNameChars) const {
  118. // FIXME: Alphabetical sort puts 'experimental' in the middle.
  119. // Would it be better to name it '~experimental' or something else
  120. // that's ASCIIbetically last?
  121. std::sort(Checkers.begin(), Checkers.end(), checkerNameLT);
  122. // FIXME: Print available packages.
  123. out << "CHECKERS:\n";
  124. // Find the maximum option length.
  125. size_t optionFieldWidth = 0;
  126. for (CheckerInfoList::const_iterator i = Checkers.begin(), e = Checkers.end();
  127. i != e; ++i) {
  128. // Limit the amount of padding we are willing to give up for alignment.
  129. // Package.Name Description [Hidden]
  130. size_t nameLength = i->FullName.size();
  131. if (nameLength <= maxNameChars)
  132. optionFieldWidth = std::max(optionFieldWidth, nameLength);
  133. }
  134. const size_t initialPad = 2;
  135. for (CheckerInfoList::const_iterator i = Checkers.begin(), e = Checkers.end();
  136. i != e; ++i) {
  137. out.indent(initialPad) << i->FullName;
  138. int pad = optionFieldWidth - i->FullName.size();
  139. // Break on long option names.
  140. if (pad < 0) {
  141. out << '\n';
  142. pad = optionFieldWidth + initialPad;
  143. }
  144. out.indent(pad + 2) << i->Desc;
  145. out << '\n';
  146. }
  147. }