Files
llvm-project/clang/lib/StaticAnalyzer/Core/CheckerRegistry.cpp
Benjamin Kramer 7ec12c928a Revert my patches which removed Diagnostic.h includes by moving some operator overloads out of line.
This seems to negatively affect compile time onsome ObjC tests
(which use a lot of partial diagnostics I assume). I have to come
up with a way to keep them inline without including Diagnostic.h
everywhere. Now adding a new diagnostic requires a full rebuild
of e.g. the static analyzer which doesn't even use those diagnostics.

This reverts commit 6496bd10dc3a6d5e3266348f08b6e35f8184bc99.
This reverts commit 7af19b817ba964ac560b50c1ed6183235f699789.
This reverts commit fdd15602a42bbe26185978ef1e17019f6d969aa7.
This reverts commit 00bd44d5677783527d7517c1ffe45e4d75a0f56f.
This reverts commit ef9b60ffed980864a8db26ad30344be429e58ff5.

llvm-svn: 150006
2012-02-07 22:29:24 +00:00

151 lines
5.1 KiB
C++

//===--- CheckerRegistry.cpp - Maintains all available checkers -*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Core/CheckerRegistry.h"
#include "clang/StaticAnalyzer/Core/CheckerOptInfo.h"
#include "llvm/ADT/SetVector.h"
using namespace clang;
using namespace ento;
static const char PackageSeparator = '.';
typedef llvm::SetVector<const CheckerRegistry::CheckerInfo *> CheckerInfoSet;
static bool checkerNameLT(const CheckerRegistry::CheckerInfo &a,
const CheckerRegistry::CheckerInfo &b) {
return a.FullName < b.FullName;
}
static bool isInPackage(const CheckerRegistry::CheckerInfo &checker,
StringRef packageName) {
// Does the checker's full name have the package as a prefix?
if (!checker.FullName.startswith(packageName))
return false;
// Is the package actually just the name of a specific checker?
if (checker.FullName.size() == packageName.size())
return true;
// Is the checker in the package (or a subpackage)?
if (checker.FullName[packageName.size()] == PackageSeparator)
return true;
return false;
}
static void collectCheckers(const CheckerRegistry::CheckerInfoList &checkers,
const llvm::StringMap<size_t> &packageSizes,
CheckerOptInfo &opt, CheckerInfoSet &collected) {
// Use a binary search to find the possible start of the package.
CheckerRegistry::CheckerInfo packageInfo(NULL, opt.getName(), "");
CheckerRegistry::CheckerInfoList::const_iterator e = checkers.end();
CheckerRegistry::CheckerInfoList::const_iterator i =
std::lower_bound(checkers.begin(), e, packageInfo, checkerNameLT);
// If we didn't even find a possible package, give up.
if (i == e)
return;
// If what we found doesn't actually start the package, give up.
if (!isInPackage(*i, opt.getName()))
return;
// There is at least one checker in the package; claim the option.
opt.claim();
// See how large the package is.
// If the package doesn't exist, assume the option refers to a single checker.
size_t size = 1;
llvm::StringMap<size_t>::const_iterator packageSize =
packageSizes.find(opt.getName());
if (packageSize != packageSizes.end())
size = packageSize->getValue();
// Step through all the checkers in the package.
for (e = i+size; i != e; ++i) {
if (opt.isEnabled())
collected.insert(&*i);
else
collected.remove(&*i);
}
}
void CheckerRegistry::addChecker(InitializationFunction fn, StringRef name,
StringRef desc) {
Checkers.push_back(CheckerInfo(fn, name, desc));
// Record the presence of the checker in its packages.
StringRef packageName, leafName;
llvm::tie(packageName, leafName) = name.rsplit(PackageSeparator);
while (!leafName.empty()) {
Packages[packageName] += 1;
llvm::tie(packageName, leafName) = packageName.rsplit(PackageSeparator);
}
}
void CheckerRegistry::initializeManager(CheckerManager &checkerMgr,
SmallVectorImpl<CheckerOptInfo> &opts) const {
// Sort checkers for efficient collection.
std::sort(Checkers.begin(), Checkers.end(), checkerNameLT);
// Collect checkers enabled by the options.
CheckerInfoSet enabledCheckers;
for (SmallVectorImpl<CheckerOptInfo>::iterator
i = opts.begin(), e = opts.end(); i != e; ++i) {
collectCheckers(Checkers, Packages, *i, enabledCheckers);
}
// Initialize the CheckerManager with all enabled checkers.
for (CheckerInfoSet::iterator
i = enabledCheckers.begin(), e = enabledCheckers.end(); i != e; ++i) {
(*i)->Initialize(checkerMgr);
}
}
void CheckerRegistry::printHelp(llvm::raw_ostream &out,
size_t maxNameChars) const {
// FIXME: Alphabetical sort puts 'experimental' in the middle.
// Would it be better to name it '~experimental' or something else
// that's ASCIIbetically last?
std::sort(Checkers.begin(), Checkers.end(), checkerNameLT);
// FIXME: Print available packages.
out << "CHECKERS:\n";
// Find the maximum option length.
size_t optionFieldWidth = 0;
for (CheckerInfoList::const_iterator i = Checkers.begin(), e = Checkers.end();
i != e; ++i) {
// Limit the amount of padding we are willing to give up for alignment.
// Package.Name Description [Hidden]
size_t nameLength = i->FullName.size();
if (nameLength <= maxNameChars)
optionFieldWidth = std::max(optionFieldWidth, nameLength);
}
const size_t initialPad = 2;
for (CheckerInfoList::const_iterator i = Checkers.begin(), e = Checkers.end();
i != e; ++i) {
out.indent(initialPad) << i->FullName;
int pad = optionFieldWidth - i->FullName.size();
// Break on long option names.
if (pad < 0) {
out << '\n';
pad = optionFieldWidth + initialPad;
}
out.indent(pad + 2) << i->Desc;
out << '\n';
}
}