clang API Documentation

CheckerRegistry.cpp
Go to the documentation of this file.
00001 //===--- CheckerRegistry.cpp - Maintains all available checkers -*- C++ -*-===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 
00010 #include "clang/StaticAnalyzer/Core/CheckerRegistry.h"
00011 #include "clang/StaticAnalyzer/Core/CheckerOptInfo.h"
00012 #include "llvm/ADT/SetVector.h"
00013 
00014 using namespace clang;
00015 using namespace ento;
00016 
00017 static const char PackageSeparator = '.';
00018 typedef llvm::SetVector<const CheckerRegistry::CheckerInfo *> CheckerInfoSet;
00019 
00020 
00021 static bool checkerNameLT(const CheckerRegistry::CheckerInfo &a,
00022                           const CheckerRegistry::CheckerInfo &b) {
00023   return a.FullName < b.FullName;
00024 }
00025 
00026 static bool isInPackage(const CheckerRegistry::CheckerInfo &checker,
00027                         StringRef packageName) {
00028   // Does the checker's full name have the package as a prefix?
00029   if (!checker.FullName.startswith(packageName))
00030     return false;
00031 
00032   // Is the package actually just the name of a specific checker?
00033   if (checker.FullName.size() == packageName.size())
00034     return true;
00035 
00036   // Is the checker in the package (or a subpackage)?
00037   if (checker.FullName[packageName.size()] == PackageSeparator)
00038     return true;
00039 
00040   return false;
00041 }
00042 
00043 static void collectCheckers(const CheckerRegistry::CheckerInfoList &checkers,
00044                             const llvm::StringMap<size_t> &packageSizes,
00045                             CheckerOptInfo &opt, CheckerInfoSet &collected) {
00046   // Use a binary search to find the possible start of the package.
00047   CheckerRegistry::CheckerInfo packageInfo(NULL, opt.getName(), "");
00048   CheckerRegistry::CheckerInfoList::const_iterator e = checkers.end();
00049   CheckerRegistry::CheckerInfoList::const_iterator i =
00050     std::lower_bound(checkers.begin(), e, packageInfo, checkerNameLT);
00051 
00052   // If we didn't even find a possible package, give up.
00053   if (i == e)
00054     return;
00055 
00056   // If what we found doesn't actually start the package, give up.
00057   if (!isInPackage(*i, opt.getName()))
00058     return;
00059 
00060   // There is at least one checker in the package; claim the option.
00061   opt.claim();
00062 
00063   // See how large the package is.
00064   // If the package doesn't exist, assume the option refers to a single checker.
00065   size_t size = 1;
00066   llvm::StringMap<size_t>::const_iterator packageSize =
00067     packageSizes.find(opt.getName());
00068   if (packageSize != packageSizes.end())
00069     size = packageSize->getValue();
00070 
00071   // Step through all the checkers in the package.
00072   for (e = i+size; i != e; ++i) {
00073     if (opt.isEnabled())
00074       collected.insert(&*i);
00075     else
00076       collected.remove(&*i);
00077   }
00078 }
00079 
00080 void CheckerRegistry::addChecker(InitializationFunction fn, StringRef name,
00081                                  StringRef desc) {
00082   Checkers.push_back(CheckerInfo(fn, name, desc));
00083 
00084   // Record the presence of the checker in its packages.
00085   StringRef packageName, leafName;
00086   llvm::tie(packageName, leafName) = name.rsplit(PackageSeparator);
00087   while (!leafName.empty()) {
00088     Packages[packageName] += 1;
00089     llvm::tie(packageName, leafName) = packageName.rsplit(PackageSeparator);
00090   }
00091 }
00092 
00093 void CheckerRegistry::initializeManager(CheckerManager &checkerMgr, 
00094                                   SmallVectorImpl<CheckerOptInfo> &opts) const {
00095   // Sort checkers for efficient collection.
00096   std::sort(Checkers.begin(), Checkers.end(), checkerNameLT);
00097 
00098   // Collect checkers enabled by the options.
00099   CheckerInfoSet enabledCheckers;
00100   for (SmallVectorImpl<CheckerOptInfo>::iterator
00101          i = opts.begin(), e = opts.end(); i != e; ++i) {
00102     collectCheckers(Checkers, Packages, *i, enabledCheckers);
00103   }
00104 
00105   // Initialize the CheckerManager with all enabled checkers.
00106   for (CheckerInfoSet::iterator
00107          i = enabledCheckers.begin(), e = enabledCheckers.end(); i != e; ++i) {
00108     (*i)->Initialize(checkerMgr);
00109   }
00110 }
00111 
00112 void CheckerRegistry::printHelp(llvm::raw_ostream &out,
00113                                 size_t maxNameChars) const {
00114   // FIXME: Alphabetical sort puts 'experimental' in the middle.
00115   // Would it be better to name it '~experimental' or something else
00116   // that's ASCIIbetically last?
00117   std::sort(Checkers.begin(), Checkers.end(), checkerNameLT);
00118 
00119   // FIXME: Print available packages.
00120 
00121   out << "CHECKERS:\n";
00122 
00123   // Find the maximum option length.
00124   size_t optionFieldWidth = 0;
00125   for (CheckerInfoList::const_iterator i = Checkers.begin(), e = Checkers.end();
00126        i != e; ++i) {
00127     // Limit the amount of padding we are willing to give up for alignment.
00128     //   Package.Name     Description  [Hidden]
00129     size_t nameLength = i->FullName.size();
00130     if (nameLength <= maxNameChars)
00131       optionFieldWidth = std::max(optionFieldWidth, nameLength);
00132   }
00133 
00134   const size_t initialPad = 2;
00135   for (CheckerInfoList::const_iterator i = Checkers.begin(), e = Checkers.end();
00136        i != e; ++i) {
00137     out.indent(initialPad) << i->FullName;
00138 
00139     int pad = optionFieldWidth - i->FullName.size();
00140 
00141     // Break on long option names.
00142     if (pad < 0) {
00143       out << '\n';
00144       pad = optionFieldWidth + initialPad;
00145     }
00146     out.indent(pad + 2) << i->Desc;
00147 
00148     out << '\n';
00149   }
00150 }