aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJordy Rose <jediknil@belkadan.com>2011-08-16 21:24:21 +0000
committerJordy Rose <jediknil@belkadan.com>2011-08-16 21:24:21 +0000
commit08b86531ade68727c56918f162816075b87c864a (patch)
tree04cee48aa5c701bc2c897758ce1a392101a2147c
parentfe88395e1594783831472ceefd5a91a71a3b9e1d (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
-rw-r--r--include/clang/StaticAnalyzer/Checkers/ClangCheckers.h22
-rw-r--r--include/clang/StaticAnalyzer/Core/CheckerOptInfo.h78
-rw-r--r--include/clang/StaticAnalyzer/Core/CheckerProvider.h55
-rw-r--r--include/clang/StaticAnalyzer/Core/CheckerRegistry.h63
-rw-r--r--include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h12
-rw-r--r--include/clang/StaticAnalyzer/Frontend/FrontendActions.h2
-rw-r--r--lib/FrontendTool/ExecuteCompilerInvocation.cpp13
-rw-r--r--lib/StaticAnalyzer/Checkers/CMakeLists.txt2
-rw-r--r--lib/StaticAnalyzer/Checkers/ClangCheckers.cpp32
-rw-r--r--lib/StaticAnalyzer/Checkers/ClangSACheckerProvider.cpp289
-rw-r--r--lib/StaticAnalyzer/Checkers/ClangSACheckerProvider.h29
-rw-r--r--lib/StaticAnalyzer/Checkers/ClangSACheckers.h1
-rw-r--r--lib/StaticAnalyzer/Core/CMakeLists.txt1
-rw-r--r--lib/StaticAnalyzer/Core/CheckerManager.cpp4
-rw-r--r--lib/StaticAnalyzer/Core/CheckerRegistry.cpp149
-rw-r--r--lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp22
-rw-r--r--lib/StaticAnalyzer/Frontend/AnalysisConsumer.h4
-rw-r--r--lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp40
-rw-r--r--lib/StaticAnalyzer/Frontend/FrontendActions.cpp3
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 &registry);
+
+} // 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 &registry) {
+#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