[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
diff --git a/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/lib/FrontendTool/ExecuteCompilerInvocation.cpp
index 1d10b24..ed08192 100644
--- a/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ b/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -125,12 +125,6 @@
     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 @@
         << 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 33d2c31..d8e982b 100644
--- a/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ b/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -22,7 +22,7 @@
   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 0000000..77a5a72
--- /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 a6286cb..0000000
--- 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 f6c8011..0000000
--- 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 5524b0f..289ce8d 100644
--- a/lib/StaticAnalyzer/Checkers/ClangSACheckers.h
+++ b/lib/StaticAnalyzer/Checkers/ClangSACheckers.h
@@ -19,6 +19,7 @@
 
 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 7baf52d..5b31d33 100644
--- a/lib/StaticAnalyzer/Core/CMakeLists.txt
+++ b/lib/StaticAnalyzer/Core/CMakeLists.txt
@@ -16,6 +16,7 @@
   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 729e4cb..bcba98f 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 @@
 }
 
 // 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 0000000..13401ac
--- /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 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';
+  }
+}
diff --git a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
index 18a946c..24f19cd 100644
--- a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
+++ b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
@@ -66,6 +66,7 @@
   const Preprocessor &PP;
   const std::string OutDir;
   AnalyzerOptions Opts;
+  ArrayRef<std::string> Plugins;
 
   // PD is owned by AnalysisManager.
   PathDiagnosticClient *PD;
@@ -78,9 +79,9 @@
 
   AnalysisConsumer(const Preprocessor& pp,
                    const std::string& outdir,
-                   const AnalyzerOptions& opts)
-    : Ctx(0), PP(pp), OutDir(outdir),
-      Opts(opts), PD(0) {
+                   const AnalyzerOptions& opts,
+                   ArrayRef<std::string> plugins)
+    : Ctx(0), PP(pp), OutDir(outdir), Opts(opts), Plugins(plugins), PD(0) {
     DigestAnalyzerOptions();
   }
 
@@ -143,8 +144,8 @@
 
   virtual void Initialize(ASTContext &Context) {
     Ctx = &Context;
-    checkerMgr.reset(registerCheckers(Opts, PP.getLangOptions(),
-                                      PP.getDiagnostics()));
+    checkerMgr.reset(createCheckerManager(Opts, PP.getLangOptions(), Plugins,
+                                          PP.getDiagnostics()));
     Mgr.reset(new AnalysisManager(*Ctx, PP.getDiagnostics(),
                                   PP.getLangOptions(), PD,
                                   CreateStoreMgr, CreateConstraintMgr,
@@ -366,14 +367,13 @@
 //===----------------------------------------------------------------------===//
 
 ASTConsumer* ento::CreateAnalysisConsumer(const Preprocessor& pp,
-                                           const std::string& OutDir,
-                                           const AnalyzerOptions& Opts) {
-  llvm::OwningPtr<AnalysisConsumer> C(new AnalysisConsumer(pp, OutDir, Opts));
-
-  // Last, disable the effects of '-Werror' when using the AnalysisConsumer.
+                                          const std::string& outDir,
+                                          const AnalyzerOptions& opts,
+                                          ArrayRef<std::string> plugins) {
+  // Disable the effects of '-Werror' when using the AnalysisConsumer.
   pp.getDiagnostics().setWarningsAsErrors(false);
 
-  return C.take();
+  return new AnalysisConsumer(pp, outDir, opts, plugins);
 }
 
 //===----------------------------------------------------------------------===//
diff --git a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.h b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.h
index 646fe97..0265517 100644
--- a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.h
+++ b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.h
@@ -15,6 +15,7 @@
 #ifndef LLVM_CLANG_GR_ANALYSISCONSUMER_H
 #define LLVM_CLANG_GR_ANALYSISCONSUMER_H
 
+#include "clang/Basic/LLVM.h"
 #include <string>
 
 namespace clang {
@@ -32,7 +33,8 @@
 /// options.)
 ASTConsumer* CreateAnalysisConsumer(const Preprocessor &pp,
                                     const std::string &output,
-                                    const AnalyzerOptions& Opts);
+                                    const AnalyzerOptions& opts,
+                                    ArrayRef<std::string> plugins);
 
 } // end GR namespace
 
diff --git a/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp b/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp
index 29c1cd1..8ed74a2 100644
--- a/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp
+++ b/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp
@@ -13,9 +13,10 @@
 
 #include "clang/StaticAnalyzer/Frontend/CheckerRegistration.h"
 #include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
-#include "../Checkers/ClangSACheckerProvider.h"
+#include "clang/StaticAnalyzer/Checkers/ClangCheckers.h"
 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
-#include "clang/StaticAnalyzer/Core/CheckerProvider.h"
+#include "clang/StaticAnalyzer/Core/CheckerOptInfo.h"
+#include "clang/StaticAnalyzer/Core/CheckerRegistry.h"
 #include "clang/Frontend/AnalyzerOptions.h"
 #include "clang/Frontend/FrontendDiagnostic.h"
 #include "clang/Basic/Diagnostic.h"
@@ -26,9 +27,17 @@
 using namespace clang;
 using namespace ento;
 
-CheckerManager *ento::registerCheckers(const AnalyzerOptions &opts,
-                                       const LangOptions &langOpts,
-                                       Diagnostic &diags) {
+static void registerCheckers(CheckerRegistry &registry,
+                             ArrayRef<std::string> plugins) {
+  registerBuiltinCheckers(registry);
+
+  // FIXME: register plugins.
+}
+
+CheckerManager *ento::createCheckerManager(const AnalyzerOptions &opts,
+                                           const LangOptions &langOpts,
+                                           ArrayRef<std::string> plugins,
+                                           Diagnostic &diags) {
   llvm::OwningPtr<CheckerManager> checkerMgr(new CheckerManager(langOpts));
 
   SmallVector<CheckerOptInfo, 8> checkerOpts;
@@ -37,11 +46,9 @@
     checkerOpts.push_back(CheckerOptInfo(opt.first.c_str(), opt.second));
   }
 
-  llvm::OwningPtr<CheckerProvider> provider(createClangSACheckerProvider());
-  provider->registerCheckers(*checkerMgr,
-                             checkerOpts.data(), checkerOpts.size());
-
-  // FIXME: Load CheckerProviders from plugins.
+  CheckerRegistry allCheckers;
+  registerCheckers(allCheckers, plugins);
+  allCheckers.initializeManager(*checkerMgr, checkerOpts);
 
   checkerMgr->finishedCheckerRegistration();
 
@@ -54,12 +61,11 @@
   return checkerMgr.take();
 }
 
-void ento::printCheckerHelp(raw_ostream &OS) {
-  OS << "OVERVIEW: Clang Static Analyzer Checkers List\n";
-  OS << '\n';
+void ento::printCheckerHelp(raw_ostream &out, ArrayRef<std::string> plugins) {
+  out << "OVERVIEW: Clang Static Analyzer Checkers List\n\n";
+  out << "USAGE: -analyzer-checker <CHECKER or PACKAGE,...>\n\n";
 
-  llvm::OwningPtr<CheckerProvider> provider(createClangSACheckerProvider());
-  provider->printHelp(OS);
-
-  // FIXME: Load CheckerProviders from plugins.
+  CheckerRegistry allCheckers;
+  registerCheckers(allCheckers, plugins);
+  allCheckers.printHelp(out);
 }
diff --git a/lib/StaticAnalyzer/Frontend/FrontendActions.cpp b/lib/StaticAnalyzer/Frontend/FrontendActions.cpp
index eeb7800..85a18ec 100644
--- a/lib/StaticAnalyzer/Frontend/FrontendActions.cpp
+++ b/lib/StaticAnalyzer/Frontend/FrontendActions.cpp
@@ -17,6 +17,7 @@
                                                StringRef InFile) {
   return CreateAnalysisConsumer(CI.getPreprocessor(),
                                 CI.getFrontendOpts().OutputFile,
-                                CI.getAnalyzerOpts());
+                                CI.getAnalyzerOpts(),
+                                CI.getFrontendOpts().Plugins);
 }