Home | History | Annotate | Download | only in Core
      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/StaticAnalyzer/Core/CheckerOptInfo.h"
     12 #include "llvm/ADT/SetVector.h"
     13 #include "llvm/Support/raw_ostream.h"
     14 
     15 using namespace clang;
     16 using namespace ento;
     17 
     18 static const char PackageSeparator = '.';
     19 typedef llvm::SetVector<const CheckerRegistry::CheckerInfo *> CheckerInfoSet;
     20 
     21 
     22 static bool checkerNameLT(const CheckerRegistry::CheckerInfo &a,
     23                           const CheckerRegistry::CheckerInfo &b) {
     24   return a.FullName < b.FullName;
     25 }
     26 
     27 static bool isInPackage(const CheckerRegistry::CheckerInfo &checker,
     28                         StringRef packageName) {
     29   // Does the checker's full name have the package as a prefix?
     30   if (!checker.FullName.startswith(packageName))
     31     return false;
     32 
     33   // Is the package actually just the name of a specific checker?
     34   if (checker.FullName.size() == packageName.size())
     35     return true;
     36 
     37   // Is the checker in the package (or a subpackage)?
     38   if (checker.FullName[packageName.size()] == PackageSeparator)
     39     return true;
     40 
     41   return false;
     42 }
     43 
     44 static void collectCheckers(const CheckerRegistry::CheckerInfoList &checkers,
     45                             const llvm::StringMap<size_t> &packageSizes,
     46                             CheckerOptInfo &opt, CheckerInfoSet &collected) {
     47   // Use a binary search to find the possible start of the package.
     48   CheckerRegistry::CheckerInfo packageInfo(nullptr, opt.getName(), "");
     49   CheckerRegistry::CheckerInfoList::const_iterator e = checkers.end();
     50   CheckerRegistry::CheckerInfoList::const_iterator i =
     51     std::lower_bound(checkers.begin(), e, packageInfo, checkerNameLT);
     52 
     53   // If we didn't even find a possible package, give up.
     54   if (i == e)
     55     return;
     56 
     57   // If what we found doesn't actually start the package, give up.
     58   if (!isInPackage(*i, opt.getName()))
     59     return;
     60 
     61   // There is at least one checker in the package; claim the option.
     62   opt.claim();
     63 
     64   // See how large the package is.
     65   // If the package doesn't exist, assume the option refers to a single checker.
     66   size_t size = 1;
     67   llvm::StringMap<size_t>::const_iterator packageSize =
     68     packageSizes.find(opt.getName());
     69   if (packageSize != packageSizes.end())
     70     size = packageSize->getValue();
     71 
     72   // Step through all the checkers in the package.
     73   for (e = i+size; i != e; ++i) {
     74     if (opt.isEnabled())
     75       collected.insert(&*i);
     76     else
     77       collected.remove(&*i);
     78   }
     79 }
     80 
     81 void CheckerRegistry::addChecker(InitializationFunction fn, StringRef name,
     82                                  StringRef desc) {
     83   Checkers.push_back(CheckerInfo(fn, name, desc));
     84 
     85   // Record the presence of the checker in its packages.
     86   StringRef packageName, leafName;
     87   std::tie(packageName, leafName) = name.rsplit(PackageSeparator);
     88   while (!leafName.empty()) {
     89     Packages[packageName] += 1;
     90     std::tie(packageName, leafName) = packageName.rsplit(PackageSeparator);
     91   }
     92 }
     93 
     94 void CheckerRegistry::initializeManager(CheckerManager &checkerMgr,
     95                                   SmallVectorImpl<CheckerOptInfo> &opts) const {
     96   // Sort checkers for efficient collection.
     97   std::sort(Checkers.begin(), Checkers.end(), checkerNameLT);
     98 
     99   // Collect checkers enabled by the options.
    100   CheckerInfoSet enabledCheckers;
    101   for (SmallVectorImpl<CheckerOptInfo>::iterator
    102          i = opts.begin(), e = opts.end(); i != e; ++i) {
    103     collectCheckers(Checkers, Packages, *i, enabledCheckers);
    104   }
    105 
    106   // Initialize the CheckerManager with all enabled checkers.
    107   for (CheckerInfoSet::iterator
    108          i = enabledCheckers.begin(), e = enabledCheckers.end(); i != e; ++i) {
    109     checkerMgr.setCurrentCheckName(CheckName((*i)->FullName));
    110     (*i)->Initialize(checkerMgr);
    111   }
    112 }
    113 
    114 void CheckerRegistry::printHelp(raw_ostream &out,
    115                                 size_t maxNameChars) const {
    116   // FIXME: Alphabetical sort puts 'experimental' in the middle.
    117   // Would it be better to name it '~experimental' or something else
    118   // that's ASCIIbetically last?
    119   std::sort(Checkers.begin(), Checkers.end(), checkerNameLT);
    120 
    121   // 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