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