CheckerRegistry.cpp revision 6bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89
158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)//===--- CheckerRegistry.cpp - Maintains all available checkers -*- C++ -*-===//
258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)//
358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)//                     The LLVM Compiler Infrastructure
458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)//
558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// This file is distributed under the University of Illinois Open Source
658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// License. See LICENSE.TXT for details.
758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)//
858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)//===----------------------------------------------------------------------===//
958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
1058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "clang/StaticAnalyzer/Core/CheckerRegistry.h"
11a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "clang/StaticAnalyzer/Core/CheckerOptInfo.h"
12a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "llvm/ADT/SetVector.h"
13a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "llvm/Support/raw_ostream.h"
1458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
1558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)using namespace clang;
1658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)using namespace ento;
1758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
1858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)static const char PackageSeparator = '.';
1958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)typedef llvm::SetVector<const CheckerRegistry::CheckerInfo *> CheckerInfoSet;
2058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
2158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
2258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)static bool checkerNameLT(const CheckerRegistry::CheckerInfo &a,
2358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                          const CheckerRegistry::CheckerInfo &b) {
2458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return a.FullName < b.FullName;
2558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
2658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
2758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)static bool isInPackage(const CheckerRegistry::CheckerInfo &checker,
2858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                        StringRef packageName) {
2958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Does the checker's full name have the package as a prefix?
3058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (!checker.FullName.startswith(packageName))
3158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return false;
3258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
3358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Is the package actually just the name of a specific checker?
3458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (checker.FullName.size() == packageName.size())
3558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return true;
3658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
3758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Is the checker in the package (or a subpackage)?
3858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (checker.FullName[packageName.size()] == PackageSeparator)
3958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return true;
4058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
4158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return false;
4258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
4358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
4458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)static void collectCheckers(const CheckerRegistry::CheckerInfoList &checkers,
4558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                            const llvm::StringMap<size_t> &packageSizes,
4658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                            CheckerOptInfo &opt, CheckerInfoSet &collected) {
4758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Use a binary search to find the possible start of the package.
4858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  CheckerRegistry::CheckerInfo packageInfo(nullptr, opt.getName(), "");
4958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  CheckerRegistry::CheckerInfoList::const_iterator e = checkers.end();
5058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  CheckerRegistry::CheckerInfoList::const_iterator i =
5158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    std::lower_bound(checkers.begin(), e, packageInfo, checkerNameLT);
5258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
5358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // If we didn't even find a possible package, give up.
5458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (i == e)
5558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return;
5658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
5758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // If what we found doesn't actually start the package, give up.
5858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (!isInPackage(*i, opt.getName()))
5958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return;
6058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
6158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // There is at least one checker in the package; claim the option.
6258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  opt.claim();
6358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
6458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // See how large the package is.
6558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // If the package doesn't exist, assume the option refers to a single checker.
6658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  size_t size = 1;
6758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  llvm::StringMap<size_t>::const_iterator packageSize =
6858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    packageSizes.find(opt.getName());
6958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (packageSize != packageSizes.end())
7058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    size = packageSize->getValue();
7158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
7258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Step through all the checkers in the package.
7358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  for (e = i+size; i != e; ++i) {
7458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (opt.isEnabled())
7558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      collected.insert(&*i);
7658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    else
7758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      collected.remove(&*i);
7858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
7958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
8058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
8158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void CheckerRegistry::addChecker(InitializationFunction fn, StringRef name,
8258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                 StringRef desc) {
8358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  Checkers.push_back(CheckerInfo(fn, name, desc));
8458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
8558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Record the presence of the checker in its packages.
8658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  StringRef packageName, leafName;
8758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  std::tie(packageName, leafName) = name.rsplit(PackageSeparator);
8858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  while (!leafName.empty()) {
8958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    Packages[packageName] += 1;
9058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    std::tie(packageName, leafName) = packageName.rsplit(PackageSeparator);
9168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
9258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
9368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
9468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void CheckerRegistry::initializeManager(CheckerManager &checkerMgr,
9568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                  SmallVectorImpl<CheckerOptInfo> &opts) const {
9658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Sort checkers for efficient collection.
9768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  std::sort(Checkers.begin(), Checkers.end(), checkerNameLT);
9868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
9968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // Collect checkers enabled by the options.
10058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  CheckerInfoSet enabledCheckers;
10168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  for (SmallVectorImpl<CheckerOptInfo>::iterator
10268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)         i = opts.begin(), e = opts.end(); i != e; ++i) {
10368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    collectCheckers(Checkers, Packages, *i, enabledCheckers);
10458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
10568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
10668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // Initialize the CheckerManager with all enabled checkers.
10768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  for (CheckerInfoSet::iterator
10858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)         i = enabledCheckers.begin(), e = enabledCheckers.end(); i != e; ++i) {
10968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    checkerMgr.setCurrentCheckName(CheckName((*i)->FullName));
11068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    (*i)->Initialize(checkerMgr);
11168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
11258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
11368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
11468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void CheckerRegistry::printHelp(raw_ostream &out,
11568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                size_t maxNameChars) const {
11658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // FIXME: Alphabetical sort puts 'experimental' in the middle.
11768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // Would it be better to name it '~experimental' or something else
11868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // that's ASCIIbetically last?
11958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  std::sort(Checkers.begin(), Checkers.end(), checkerNameLT);
12058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
12158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // FIXME: Print available packages.
122
123  out << "CHECKERS:\n";
124
125  // Find the maximum option length.
126  size_t optionFieldWidth = 0;
127  for (CheckerInfoList::const_iterator i = Checkers.begin(), e = Checkers.end();
128       i != e; ++i) {
129    // Limit the amount of padding we are willing to give up for alignment.
130    //   Package.Name     Description  [Hidden]
131    size_t nameLength = i->FullName.size();
132    if (nameLength <= maxNameChars)
133      optionFieldWidth = std::max(optionFieldWidth, nameLength);
134  }
135
136  const size_t initialPad = 2;
137  for (CheckerInfoList::const_iterator i = Checkers.begin(), e = Checkers.end();
138       i != e; ++i) {
139    out.indent(initialPad) << i->FullName;
140
141    int pad = optionFieldWidth - i->FullName.size();
142
143    // Break on long option names.
144    if (pad < 0) {
145      out << '\n';
146      pad = optionFieldWidth + initialPad;
147    }
148    out.indent(pad + 2) << i->Desc;
149
150    out << '\n';
151  }
152}
153