diff options
author | Jordy Rose <jediknil@belkadan.com> | 2011-08-16 21:24:21 +0000 |
---|---|---|
committer | Jordy Rose <jediknil@belkadan.com> | 2011-08-16 21:24:21 +0000 |
commit | 08b86531ade68727c56918f162816075b87c864a (patch) | |
tree | 04cee48aa5c701bc2c897758ce1a392101a2147c | |
parent | fe88395e1594783831472ceefd5a91a71a3b9e1d (diff) |
[analyzer] Overhaul of checker registration in preparation for basic plugin support. Removes support for checker groups (we can add them back in later if we decide they are still useful), and -analyzer-checker-help output is a little worse for the time being (no packages).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@137758 91177308-0d34-0410-b5e6-96231b3b80d8
19 files changed, 402 insertions, 419 deletions
diff --git a/include/clang/StaticAnalyzer/Checkers/ClangCheckers.h b/include/clang/StaticAnalyzer/Checkers/ClangCheckers.h new file mode 100644 index 0000000000..cf0a30a73d --- /dev/null +++ b/include/clang/StaticAnalyzer/Checkers/ClangCheckers.h @@ -0,0 +1,22 @@ +//===--- ClangCheckers.h - Provides builtin checkers ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CHECKERS_CLANGCHECKERS_H +#define LLVM_CLANG_STATICANALYZER_CHECKERS_CLANGCHECKERS_H + +namespace clang { +namespace ento { +class CheckerRegistry; + +void registerBuiltinCheckers(CheckerRegistry ®istry); + +} // end namespace ento +} // end namespace clang + +#endif diff --git a/include/clang/StaticAnalyzer/Core/CheckerOptInfo.h b/include/clang/StaticAnalyzer/Core/CheckerOptInfo.h new file mode 100644 index 0000000000..76f98a8cda --- /dev/null +++ b/include/clang/StaticAnalyzer/Core/CheckerOptInfo.h @@ -0,0 +1,78 @@ +//===--- CheckerOptInfo.h - Specifies which checkers to use -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CORE_CHECKEROPTINFO_H +#define LLVM_CLANG_STATICANALYZER_CORE_CHECKEROPTINFO_H + +#include "clang/Basic/LLVM.h" + +namespace clang { +namespace ento { + +class CheckerOptInfo { + StringRef Name; + bool Enable; + bool Claimed; + +public: + CheckerOptInfo(StringRef name, bool enable) + : Name(name), Enable(enable), Claimed(false) { } + + StringRef getName() const { return Name; } + bool isEnabled() const { return Enable; } + bool isDisabled() const { return !isEnabled(); } + + bool isClaimed() const { return Claimed; } + bool isUnclaimed() const { return !isClaimed(); } + void claim() { Claimed = true; } +}; + +} // end namespace ento +} // end namespace clang + +#endif +//===--- CheckerOptInfo.h - Specifies which checkers to use -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CORE_CHECKEROPTINFO_H +#define LLVM_CLANG_STATICANALYZER_CORE_CHECKEROPTINFO_H + +#include "clang/Basic/LLVM.h" + +namespace clang { +namespace ento { + +class CheckerOptInfo { + StringRef Name; + bool Enable; + bool Claimed; + +public: + CheckerOptInfo(StringRef name, bool enable) + : Name(name), Enable(enable), Claimed(false) { } + + StringRef getName() const { return Name; } + bool isEnabled() const { return Enable; } + bool isDisabled() const { return !isEnabled(); } + + bool isClaimed() const { return Claimed; } + bool isUnclaimed() const { return !isClaimed(); } + void claim() { Claimed = true; } +}; + +} // end namespace ento +} // end namespace clang + +#endif diff --git a/include/clang/StaticAnalyzer/Core/CheckerProvider.h b/include/clang/StaticAnalyzer/Core/CheckerProvider.h deleted file mode 100644 index 86d05430a6..0000000000 --- a/include/clang/StaticAnalyzer/Core/CheckerProvider.h +++ /dev/null @@ -1,55 +0,0 @@ -//===--- CheckerProvider.h - Static Analyzer Checkers Provider --*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Defines the Static Analyzer Checker Provider. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_SA_CORE_CHECKERPROVIDER_H -#define LLVM_CLANG_SA_CORE_CHECKERPROVIDER_H - -#include "clang/Basic/LLVM.h" -#include "llvm/ADT/StringRef.h" - -namespace clang { - -namespace ento { - class CheckerManager; - -class CheckerOptInfo { - const char *Name; - bool Enable; - bool Claimed; - -public: - CheckerOptInfo(const char *name, bool enable) - : Name(name), Enable(enable), Claimed(false) { } - - const char *getName() const { return Name; } - bool isEnabled() const { return Enable; } - bool isDisabled() const { return !isEnabled(); } - - bool isClaimed() const { return Claimed; } - bool isUnclaimed() const { return !isClaimed(); } - void claim() { Claimed = true; } -}; - -class CheckerProvider { -public: - virtual ~CheckerProvider(); - virtual void registerCheckers(CheckerManager &checkerMgr, - CheckerOptInfo *checkOpts, unsigned numCheckOpts) = 0; - virtual void printHelp(raw_ostream &OS) = 0; -}; - -} // end ento namespace - -} // end clang namespace - -#endif diff --git a/include/clang/StaticAnalyzer/Core/CheckerRegistry.h b/include/clang/StaticAnalyzer/Core/CheckerRegistry.h new file mode 100644 index 0000000000..16f98cf7ce --- /dev/null +++ b/include/clang/StaticAnalyzer/Core/CheckerRegistry.h @@ -0,0 +1,63 @@ +//===--- CheckerRegistry.h - 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. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CORE_CHECKERREGISTRY_H +#define LLVM_CLANG_STATICANALYZER_CORE_CHECKERREGISTRY_H + +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/Basic/LLVM.h" +#include <vector> + +namespace clang { +namespace ento { + +class CheckerOptInfo; + +class CheckerRegistry { +public: + typedef void (*InitializationFunction)(CheckerManager &); + struct CheckerInfo { + InitializationFunction Initialize; + StringRef FullName; + StringRef Desc; + + CheckerInfo(InitializationFunction fn, StringRef name, StringRef desc) + : Initialize(fn), FullName(name), Desc(desc) {} + }; + + typedef std::vector<CheckerInfo> CheckerInfoList; + +private: + template <typename T> + static void initializeManager(CheckerManager &mgr) { + mgr.registerChecker<T>(); + } + +public: + void addChecker(InitializationFunction fn, StringRef fullName, + StringRef desc); + + template <class T> + void addChecker(StringRef fullName, StringRef desc) { + addChecker(&initializeManager<T>, fullName, desc); + } + + void initializeManager(CheckerManager &mgr, + SmallVectorImpl<CheckerOptInfo> &opts) const; + void printHelp(raw_ostream &out, size_t maxNameChars = 30) const ; + +private: + mutable CheckerInfoList Checkers; + mutable llvm::StringMap<size_t> Packages; +}; + +} // end namespace ento +} // end namespace clang + +#endif diff --git a/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h b/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h index 9d6298f36e..d662e2cb98 100644 --- a/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h +++ b/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h @@ -1,4 +1,4 @@ -//===-- CheckerRegistration.h - Checker Registration Function-------*- C++ -*-===// +//===-- CheckerRegistration.h - Checker Registration Function ---*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -10,6 +10,9 @@ #ifndef LLVM_CLANG_SA_FRONTEND_CHECKERREGISTRATION_H #define LLVM_CLANG_SA_FRONTEND_CHECKERREGISTRATION_H +#include "clang/Basic/LLVM.h" +#include <string> + namespace clang { class AnalyzerOptions; class LangOptions; @@ -18,9 +21,10 @@ namespace clang { namespace ento { class CheckerManager; -CheckerManager *registerCheckers(const AnalyzerOptions &opts, - const LangOptions &langOpts, - Diagnostic &diags); +CheckerManager *createCheckerManager(const AnalyzerOptions &opts, + const LangOptions &langOpts, + ArrayRef<std::string> plugins, + Diagnostic &diags); } // end ento namespace diff --git a/include/clang/StaticAnalyzer/Frontend/FrontendActions.h b/include/clang/StaticAnalyzer/Frontend/FrontendActions.h index f9cd0f1977..838ac92553 100644 --- a/include/clang/StaticAnalyzer/Frontend/FrontendActions.h +++ b/include/clang/StaticAnalyzer/Frontend/FrontendActions.h @@ -26,7 +26,7 @@ protected: StringRef InFile); }; -void printCheckerHelp(raw_ostream &OS); +void printCheckerHelp(raw_ostream &OS, ArrayRef<std::string> plugins); } // end GR namespace diff --git a/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/lib/FrontendTool/ExecuteCompilerInvocation.cpp index 1d10b241ab..ed081923f3 100644 --- a/lib/FrontendTool/ExecuteCompilerInvocation.cpp +++ b/lib/FrontendTool/ExecuteCompilerInvocation.cpp @@ -125,12 +125,6 @@ bool clang::ExecuteCompilerInvocation(CompilerInstance *Clang) { return 0; } - // Honor -analyzer-checker-help. - if (Clang->getAnalyzerOpts().ShowCheckerHelp) { - ento::printCheckerHelp(llvm::outs()); - return 0; - } - // Honor -version. // // FIXME: Use a better -version message? @@ -162,6 +156,13 @@ bool clang::ExecuteCompilerInvocation(CompilerInstance *Clang) { << Path << Error; } + // Honor -analyzer-checker-help. + // This should happen AFTER plugins have been loaded! + if (Clang->getAnalyzerOpts().ShowCheckerHelp) { + ento::printCheckerHelp(llvm::outs(), Clang->getFrontendOpts().Plugins); + return 0; + } + // If there were errors in processing arguments, don't do anything else. bool Success = false; if (!Clang->getDiagnostics().hasErrorOccurred()) { diff --git a/lib/StaticAnalyzer/Checkers/CMakeLists.txt b/lib/StaticAnalyzer/Checkers/CMakeLists.txt index 33d2c31fa0..d8e982bd69 100644 --- a/lib/StaticAnalyzer/Checkers/CMakeLists.txt +++ b/lib/StaticAnalyzer/Checkers/CMakeLists.txt @@ -22,7 +22,7 @@ add_clang_library(clangStaticAnalyzerCheckers CheckSecuritySyntaxOnly.cpp CheckSizeofPointer.cpp ChrootChecker.cpp - ClangSACheckerProvider.cpp + ClangCheckers.cpp DeadStoresChecker.cpp DebugCheckers.cpp DereferenceChecker.cpp diff --git a/lib/StaticAnalyzer/Checkers/ClangCheckers.cpp b/lib/StaticAnalyzer/Checkers/ClangCheckers.cpp new file mode 100644 index 0000000000..77a5a72264 --- /dev/null +++ b/lib/StaticAnalyzer/Checkers/ClangCheckers.cpp @@ -0,0 +1,32 @@ +//===--- ClangCheckers.h - Provides builtin 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/Checkers/ClangCheckers.h" +#include "clang/StaticAnalyzer/Core/CheckerRegistry.h" + +// FIXME: This is only necessary as long as there are checker registration +// functions that do additional work besides mgr.registerChecker<CLASS>(). +// The only checkers that currently do this are: +// - NSAutoreleasePoolChecker +// - NSErrorChecker +// - ObjCAtSyncChecker +// It's probably worth including this information in Checkers.td to minimize +// boilerplate code. +#include "ClangSACheckers.h" + +using namespace clang; +using namespace ento; + +void ento::registerBuiltinCheckers(CheckerRegistry ®istry) { +#define GET_CHECKERS +#define CHECKER(FULLNAME,CLASS,DESCFILE,HELPTEXT,GROUPINDEX,HIDDEN) \ + registry.addChecker(register##CLASS, FULLNAME, HELPTEXT); +#include "Checkers.inc" +#undef GET_CHECKERS +} diff --git a/lib/StaticAnalyzer/Checkers/ClangSACheckerProvider.cpp b/lib/StaticAnalyzer/Checkers/ClangSACheckerProvider.cpp deleted file mode 100644 index a6286cbd7b..0000000000 --- a/lib/StaticAnalyzer/Checkers/ClangSACheckerProvider.cpp +++ /dev/null @@ -1,289 +0,0 @@ -//===--- ClangSACheckerProvider.cpp - Clang SA Checkers Provider ----------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Defines the CheckerProvider for the checkers defined in -// libclangStaticAnalyzerCheckers. -// -//===----------------------------------------------------------------------===// - -#include "ClangSACheckerProvider.h" -#include "ClangSACheckers.h" -#include "clang/StaticAnalyzer/Core/CheckerManager.h" -#include "clang/StaticAnalyzer/Core/CheckerProvider.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/ADT/DenseSet.h" -#include "map" - -using namespace clang; -using namespace ento; - -namespace { - -/// \brief Provider for all the checkers in libclangStaticAnalyzerCheckers. -class ClangSACheckerProvider : public CheckerProvider { -public: - virtual void registerCheckers(CheckerManager &checkerMgr, - CheckerOptInfo *checkOpts, unsigned numCheckOpts); - virtual void printHelp(raw_ostream &OS); -}; - -} - -CheckerProvider *ento::createClangSACheckerProvider() { - return new ClangSACheckerProvider(); -} - -namespace { - -struct StaticCheckerInfoRec { - const char *FullName; - void (*RegFunc)(CheckerManager &mgr); - const char *HelpText; - int GroupIndex; - bool Hidden; -}; - -struct StaticPackageInfoRec { - const char *FullName; - int GroupIndex; - bool Hidden; -}; - -struct StaticGroupInfoRec { - const char *FullName; -}; - -} // end anonymous namespace. - -static const StaticPackageInfoRec StaticPackageInfo[] = { -#define GET_PACKAGES -#define PACKAGE(FULLNAME, GROUPINDEX, HIDDEN) \ - { FULLNAME, GROUPINDEX, HIDDEN }, -#include "Checkers.inc" - { 0, -1, 0 } -#undef PACKAGE -#undef GET_PACKAGES -}; - -static const unsigned NumPackages = sizeof(StaticPackageInfo) - / sizeof(StaticPackageInfoRec) - 1; - -static const StaticGroupInfoRec StaticGroupInfo[] = { -#define GET_GROUPS -#define GROUP(FULLNAME) \ - { FULLNAME }, -#include "Checkers.inc" - { 0 } -#undef GROUP -#undef GET_GROUPS -}; - -static const unsigned NumGroups = sizeof(StaticGroupInfo) - / sizeof(StaticGroupInfoRec) - 1; - -static const StaticCheckerInfoRec StaticCheckerInfo[] = { -#define GET_CHECKERS -#define CHECKER(FULLNAME,CLASS,DESCFILE,HELPTEXT,GROUPINDEX,HIDDEN) \ - { FULLNAME, register##CLASS, HELPTEXT, GROUPINDEX, HIDDEN }, -#include "Checkers.inc" - { 0, 0, 0, -1, 0} -#undef CHECKER -#undef GET_CHECKERS -}; - -static const unsigned NumCheckers = sizeof(StaticCheckerInfo) - / sizeof(StaticCheckerInfoRec) - 1; - -namespace { - -struct CheckNameOption { - const char *Name; - const short *Members; - const short *SubGroups; - bool Hidden; -}; - -} // end anonymous namespace. - -#define GET_MEMBER_ARRAYS -#include "Checkers.inc" -#undef GET_MEMBER_ARRAYS - -// The table of check name options, sorted by name for fast binary lookup. -static const CheckNameOption CheckNameTable[] = { -#define GET_CHECKNAME_TABLE -#include "Checkers.inc" -#undef GET_CHECKNAME_TABLE -}; -static const size_t - CheckNameTableSize = sizeof(CheckNameTable) / sizeof(CheckNameTable[0]); - -static bool CheckNameOptionCompare(const CheckNameOption &LHS, - const CheckNameOption &RHS) { - return strcmp(LHS.Name, RHS.Name) < 0; -} - -static void collectCheckers(const CheckNameOption *checkName, - bool enable, - llvm::DenseSet<const StaticCheckerInfoRec *> &checkers, - bool collectHidden) { - if (checkName->Hidden && !collectHidden) - return; - - if (const short *member = checkName->Members) { - if (enable) { - for (; *member != -1; ++member) - if (collectHidden || !StaticCheckerInfo[*member].Hidden) - checkers.insert(&StaticCheckerInfo[*member]); - } else { - for (; *member != -1; ++member) - checkers.erase(&StaticCheckerInfo[*member]); - } - } - - // Enable/disable all subgroups along with this one. - if (const short *subGroups = checkName->SubGroups) { - for (; *subGroups != -1; ++subGroups) { - const CheckNameOption *sub = &CheckNameTable[*subGroups]; - collectCheckers(sub, enable, checkers, collectHidden && !sub->Hidden); - } - } -} - -static void collectCheckers(CheckerOptInfo &opt, - llvm::DenseSet<const StaticCheckerInfoRec *> &checkers) { - const char *optName = opt.getName(); - CheckNameOption key = { optName, 0, 0, false }; - const CheckNameOption *found = - std::lower_bound(CheckNameTable, CheckNameTable + CheckNameTableSize, key, - CheckNameOptionCompare); - if (found == CheckNameTable + CheckNameTableSize || - strcmp(found->Name, optName) != 0) - return; // Check name not found. - - opt.claim(); - collectCheckers(found, opt.isEnabled(), checkers, /*collectHidden=*/true); -} - -void ClangSACheckerProvider::registerCheckers(CheckerManager &checkerMgr, - CheckerOptInfo *checkOpts, unsigned numCheckOpts) { - llvm::DenseSet<const StaticCheckerInfoRec *> enabledCheckers; - for (unsigned i = 0; i != numCheckOpts; ++i) - collectCheckers(checkOpts[i], enabledCheckers); - for (llvm::DenseSet<const StaticCheckerInfoRec *>::iterator - I = enabledCheckers.begin(), E = enabledCheckers.end(); I != E; ++I) { - (*I)->RegFunc(checkerMgr); - } -} - -//===----------------------------------------------------------------------===// -// Printing Help. -//===----------------------------------------------------------------------===// - -static void printPackageOption(raw_ostream &OS) { - // Find the maximum option length. - unsigned OptionFieldWidth = 0; - for (unsigned i = 0; i != NumPackages; ++i) { - // Limit the amount of padding we are willing to give up for alignment. - unsigned Length = strlen(StaticPackageInfo[i].FullName); - if (Length <= 30) - OptionFieldWidth = std::max(OptionFieldWidth, Length); - } - - const unsigned InitialPad = 2; - for (unsigned i = 0; i != NumPackages; ++i) { - const StaticPackageInfoRec &package = StaticPackageInfo[i]; - const std::string &Option = package.FullName; - int Pad = OptionFieldWidth - int(Option.size()); - OS.indent(InitialPad) << Option; - - if (package.GroupIndex != -1 || package.Hidden) { - // Break on long option names. - if (Pad < 0) { - OS << "\n"; - Pad = OptionFieldWidth + InitialPad; - } - OS.indent(Pad + 1) << "["; - if (package.GroupIndex != -1) { - OS << "Group=" << StaticGroupInfo[package.GroupIndex].FullName; - if (package.Hidden) - OS << ", "; - } - if (package.Hidden) - OS << "Hidden"; - OS << "]"; - } - - OS << "\n"; - } -} - -typedef std::map<std::string, const StaticCheckerInfoRec *> SortedCheckers; - -static void printCheckerOption(raw_ostream &OS,SortedCheckers &checkers) { - // Find the maximum option length. - unsigned OptionFieldWidth = 0; - for (SortedCheckers::iterator - I = checkers.begin(), E = checkers.end(); I != E; ++I) { - // Limit the amount of padding we are willing to give up for alignment. - unsigned Length = strlen(I->second->FullName); - if (Length <= 30) - OptionFieldWidth = std::max(OptionFieldWidth, Length); - } - - const unsigned InitialPad = 2; - for (SortedCheckers::iterator - I = checkers.begin(), E = checkers.end(); I != E; ++I) { - const std::string &Option = I->first; - const StaticCheckerInfoRec &checker = *I->second; - int Pad = OptionFieldWidth - int(Option.size()); - OS.indent(InitialPad) << Option; - - // Break on long option names. - if (Pad < 0) { - OS << "\n"; - Pad = OptionFieldWidth + InitialPad; - } - OS.indent(Pad + 1) << checker.HelpText; - - if (checker.GroupIndex != -1 || checker.Hidden) { - OS << " ["; - if (checker.GroupIndex != -1) { - OS << "Group=" << StaticGroupInfo[checker.GroupIndex].FullName; - if (checker.Hidden) - OS << ", "; - } - if (checker.Hidden) - OS << "Hidden"; - OS << "]"; - } - - OS << "\n"; - } -} - -void ClangSACheckerProvider::printHelp(raw_ostream &OS) { - OS << "USAGE: -analyzer-checker <CHECKER or PACKAGE or GROUP,...>\n"; - - OS << "\nGROUPS:\n"; - for (unsigned i = 0; i != NumGroups; ++i) - OS.indent(2) << StaticGroupInfo[i].FullName << "\n"; - - OS << "\nPACKAGES:\n"; - printPackageOption(OS); - - OS << "\nCHECKERS:\n"; - - // Sort checkers according to their full name. - SortedCheckers checkers; - for (unsigned i = 0; i != NumCheckers; ++i) - checkers[StaticCheckerInfo[i].FullName] = &StaticCheckerInfo[i]; - - printCheckerOption(OS, checkers); -} diff --git a/lib/StaticAnalyzer/Checkers/ClangSACheckerProvider.h b/lib/StaticAnalyzer/Checkers/ClangSACheckerProvider.h deleted file mode 100644 index f6c80119fd..0000000000 --- a/lib/StaticAnalyzer/Checkers/ClangSACheckerProvider.h +++ /dev/null @@ -1,29 +0,0 @@ -//===--- ClangSACheckerProvider.h - Clang SA Checkers Provider --*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Defines the entry point for creating the provider for the checkers defined -// in libclangStaticAnalyzerCheckers. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_SA_CHECKERS_CLANGSACHECKERPROVIDER_H -#define LLVM_CLANG_SA_CHECKERS_CLANGSACHECKERPROVIDER_H - -namespace clang { - -namespace ento { - class CheckerProvider; - -CheckerProvider *createClangSACheckerProvider(); - -} // end ento namespace - -} // end clang namespace - -#endif diff --git a/lib/StaticAnalyzer/Checkers/ClangSACheckers.h b/lib/StaticAnalyzer/Checkers/ClangSACheckers.h index 5524b0f532..289ce8d8c3 100644 --- a/lib/StaticAnalyzer/Checkers/ClangSACheckers.h +++ b/lib/StaticAnalyzer/Checkers/ClangSACheckers.h @@ -19,6 +19,7 @@ namespace clang { namespace ento { class CheckerManager; +class CheckerRegistry; #define GET_CHECKERS #define CHECKER(FULLNAME,CLASS,CXXFILE,HELPTEXT,GROUPINDEX,HIDDEN) \ diff --git a/lib/StaticAnalyzer/Core/CMakeLists.txt b/lib/StaticAnalyzer/Core/CMakeLists.txt index 7baf52da8c..5b31d33976 100644 --- a/lib/StaticAnalyzer/Core/CMakeLists.txt +++ b/lib/StaticAnalyzer/Core/CMakeLists.txt @@ -16,6 +16,7 @@ add_clang_library(clangStaticAnalyzerCore CheckerContext.cpp CheckerHelpers.cpp CheckerManager.cpp + CheckerRegistry.cpp CoreEngine.cpp Environment.cpp ExplodedGraph.cpp diff --git a/lib/StaticAnalyzer/Core/CheckerManager.cpp b/lib/StaticAnalyzer/Core/CheckerManager.cpp index 729e4cb17c..bcba98fb3a 100644 --- a/lib/StaticAnalyzer/Core/CheckerManager.cpp +++ b/lib/StaticAnalyzer/Core/CheckerManager.cpp @@ -12,7 +12,6 @@ //===----------------------------------------------------------------------===// #include "clang/StaticAnalyzer/Core/CheckerManager.h" -#include "clang/StaticAnalyzer/Core/CheckerProvider.h" #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/Analysis/ProgramPoint.h" @@ -543,7 +542,4 @@ CheckerManager::~CheckerManager() { } // Anchor for the vtable. -CheckerProvider::~CheckerProvider() { } - -// Anchor for the vtable. GraphExpander::~GraphExpander() { } diff --git a/lib/StaticAnalyzer/Core/CheckerRegistry.cpp b/lib/StaticAnalyzer/Core/CheckerRegistry.cpp new file mode 100644 index 0000000000..13401acf3d --- /dev/null +++ b/lib/StaticAnalyzer/Core/CheckerRegistry.cpp @@ -0,0 +1,149 @@ +//===--- 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" + +using namespace clang; +using namespace ento; + +static const char PackageSeparator = '.'; +typedef llvm::DenseSet<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.erase(&*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 optionFi |