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