[analyzer][NFC] Move the data structures from CheckerRegistry to the Core library

If you were around the analyzer for a while now, you must've seen a lot of
patches that awkwardly puts code from one library to the other:

* D75360 moves the constructors of CheckerManager, which lies in the Core
  library, to the Frontend library. Most the patch itself was a struggle along
  the library lines.
* D78126 had to be reverted because dependency information would be utilized
  in the Core library, but the actual data lied in the frontend.
  D78126#inline-751477 touches on this issue as well.

This stems from the often mentioned problem: the Frontend library depends on
Core and Checkers, Checkers depends on Core. The checker registry functions
(`registerMallocChecker`, etc) lie in the Checkers library in order to keep each
checker its own module. What this implies is that checker registration cannot
take place in the Core, but the Core might still want to use the data that
results from it (which checker/package is enabled, dependencies, etc).

D54436 was the patch that initiated this. Back in the days when CheckerRegistry
was super dumb and buggy, it implemented a non-documented solution to this
problem by keeping the data in the Core, and leaving the logic in the Frontend.
At the time when the patch landed, the merger to the Frontend made sense,
because the data hadn't been utilized anywhere, and the whole workaround without
any documentation made little sense to me.

So, lets put the data back where it belongs, in the Core library. This patch
introduces `CheckerRegistryData`, and turns `CheckerRegistry` into a short lived
wrapper around this data that implements the logic of checker registration. The
data is tied to CheckerManager because it is required to parse it.

Side note: I can't help but cringe at the fact how ridiculously awkward the
library lines are. I feel like I'm thinking too much inside the box, but I guess
this is just the price of keeping the checkers so modularized.

Differential Revision: https://reviews.llvm.org/D82585
diff --git a/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h b/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h
index 1f3c6a1..d2f71ba 100644
--- a/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h
+++ b/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h
@@ -43,6 +43,7 @@
 class CheckerBase;
 class CheckerContext;
 class CheckerRegistry;
+struct CheckerRegistryData;
 class ExplodedGraph;
 class ExplodedNode;
 class ExplodedNodeSet;
@@ -130,7 +131,7 @@
   const Preprocessor *PP = nullptr;
   CheckerNameRef CurrentCheckerName;
   DiagnosticsEngine &Diags;
-  std::unique_ptr<CheckerRegistry> Registry;
+  std::unique_ptr<CheckerRegistryData> RegistryData;
 
 public:
   // These constructors are defined in the Frontend library, because
@@ -152,8 +153,8 @@
       : CheckerManager(Context, AOptions, PP, {}, {}) {}
 
   /// Constructs a CheckerManager without requiring an AST. No checker
-  /// registration will take place. Only useful for retrieving the
-  /// CheckerRegistry and print for help flags where the AST is unavalaible.
+  /// registration will take place. Only useful when one needs to print the
+  /// help flags through CheckerRegistryData, and the AST is unavalaible.
   CheckerManager(AnalyzerOptions &AOptions, const LangOptions &LangOpts,
                  DiagnosticsEngine &Diags, ArrayRef<std::string> plugins);
 
@@ -172,7 +173,9 @@
     assert(PP);
     return *PP;
   }
-  const CheckerRegistry &getCheckerRegistry() const { return *Registry; }
+  const CheckerRegistryData &getCheckerRegistryData() const {
+    return *RegistryData;
+  }
   DiagnosticsEngine &getDiagnostics() const { return Diags; }
   ASTContext &getASTContext() const {
     assert(Context);
diff --git a/clang/include/clang/StaticAnalyzer/Core/CheckerRegistryData.h b/clang/include/clang/StaticAnalyzer/Core/CheckerRegistryData.h
new file mode 100644
index 0000000..e7a7671
--- /dev/null
+++ b/clang/include/clang/StaticAnalyzer/Core/CheckerRegistryData.h
@@ -0,0 +1,226 @@
+//===- CheckerRegistryData.h ------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the data structures to which the TableGen file Checkers.td
+// maps to, as well as what was parsed from the the specific invocation (whether
+// a checker/package is enabled, their options values, etc).
+//
+// The parsing of the invocation is done by CheckerRegistry, which is found in
+// the Frontend library. This allows the Core and Checkers libraries to utilize
+// this information, such as enforcing rules on checker dependency bug emission,
+// ensuring all checker options were queried, etc.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_CHECKERREGISTRYDATA_H
+#define LLVM_CLANG_STATICANALYZER_CORE_CHECKERREGISTRYDATA_H
+
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/SetVector.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace clang {
+
+class AnalyzerOptions;
+
+namespace ento {
+
+class CheckerManager;
+
+/// Initialization functions perform any necessary setup for a checker.
+/// They should include a call to CheckerManager::registerChecker.
+using RegisterCheckerFn = void (*)(CheckerManager &);
+using ShouldRegisterFunction = bool (*)(const CheckerManager &);
+
+/// Specifies a command line option. It may either belong to a checker or a
+/// package.
+struct CmdLineOption {
+  StringRef OptionType;
+  StringRef OptionName;
+  StringRef DefaultValStr;
+  StringRef Description;
+  StringRef DevelopmentStatus;
+  bool IsHidden;
+
+  CmdLineOption(StringRef OptionType, StringRef OptionName,
+                StringRef DefaultValStr, StringRef Description,
+                StringRef DevelopmentStatus, bool IsHidden)
+      : OptionType(OptionType), OptionName(OptionName),
+        DefaultValStr(DefaultValStr), Description(Description),
+        DevelopmentStatus(DevelopmentStatus), IsHidden(IsHidden) {
+
+    assert((OptionType == "bool" || OptionType == "string" ||
+            OptionType == "int") &&
+           "Unknown command line option type!");
+
+    assert((OptionType != "bool" ||
+            (DefaultValStr == "true" || DefaultValStr == "false")) &&
+           "Invalid value for boolean command line option! Maybe incorrect "
+           "parameters to the addCheckerOption or addPackageOption method?");
+
+    int Tmp;
+    assert((OptionType != "int" || !DefaultValStr.getAsInteger(0, Tmp)) &&
+           "Invalid value for integer command line option! Maybe incorrect "
+           "parameters to the addCheckerOption or addPackageOption method?");
+    (void)Tmp;
+
+    assert((DevelopmentStatus == "alpha" || DevelopmentStatus == "beta" ||
+            DevelopmentStatus == "released") &&
+           "Invalid development status!");
+  }
+
+  LLVM_DUMP_METHOD void dump() const { dumpToStream(llvm::errs()); }
+  LLVM_DUMP_METHOD void dumpToStream(llvm::raw_ostream &Out) const;
+};
+
+using CmdLineOptionList = llvm::SmallVector<CmdLineOption, 0>;
+
+struct CheckerInfo;
+
+using CheckerInfoList = std::vector<CheckerInfo>;
+using CheckerInfoListRange = llvm::iterator_range<CheckerInfoList::iterator>;
+using ConstCheckerInfoList = llvm::SmallVector<const CheckerInfo *, 0>;
+using CheckerInfoSet = llvm::SetVector<const CheckerInfo *>;
+
+/// Specifies a checker. Note that this isn't what we call a checker object,
+/// it merely contains everything required to create one.
+struct CheckerInfo {
+  enum class StateFromCmdLine {
+    // This checker wasn't explicitly enabled or disabled.
+    State_Unspecified,
+    // This checker was explicitly disabled.
+    State_Disabled,
+    // This checker was explicitly enabled.
+    State_Enabled
+  };
+
+  RegisterCheckerFn Initialize = nullptr;
+  ShouldRegisterFunction ShouldRegister = nullptr;
+  StringRef FullName;
+  StringRef Desc;
+  StringRef DocumentationUri;
+  CmdLineOptionList CmdLineOptions;
+  bool IsHidden = false;
+  StateFromCmdLine State = StateFromCmdLine::State_Unspecified;
+
+  ConstCheckerInfoList Dependencies;
+  ConstCheckerInfoList WeakDependencies;
+
+  bool isEnabled(const CheckerManager &mgr) const {
+    return State == StateFromCmdLine::State_Enabled && ShouldRegister(mgr);
+  }
+
+  bool isDisabled(const CheckerManager &mgr) const {
+    return State == StateFromCmdLine::State_Disabled || !ShouldRegister(mgr);
+  }
+
+  // Since each checker must have a different full name, we can identify
+  // CheckerInfo objects by them.
+  bool operator==(const CheckerInfo &Rhs) const {
+    return FullName == Rhs.FullName;
+  }
+
+  CheckerInfo(RegisterCheckerFn Fn, ShouldRegisterFunction sfn, StringRef Name,
+              StringRef Desc, StringRef DocsUri, bool IsHidden)
+      : Initialize(Fn), ShouldRegister(sfn), FullName(Name), Desc(Desc),
+        DocumentationUri(DocsUri), IsHidden(IsHidden) {}
+
+  // Used for lower_bound.
+  explicit CheckerInfo(StringRef FullName) : FullName(FullName) {}
+
+  LLVM_DUMP_METHOD void dump() const { dumpToStream(llvm::errs()); }
+  LLVM_DUMP_METHOD void dumpToStream(llvm::raw_ostream &Out) const;
+};
+
+using StateFromCmdLine = CheckerInfo::StateFromCmdLine;
+
+/// Specifies a package. Each package option is implicitly an option for all
+/// checkers within the package.
+struct PackageInfo {
+  StringRef FullName;
+  CmdLineOptionList CmdLineOptions;
+
+  // Since each package must have a different full name, we can identify
+  // CheckerInfo objects by them.
+  bool operator==(const PackageInfo &Rhs) const {
+    return FullName == Rhs.FullName;
+  }
+
+  explicit PackageInfo(StringRef FullName) : FullName(FullName) {}
+
+  LLVM_DUMP_METHOD void dump() const { dumpToStream(llvm::errs()); }
+  LLVM_DUMP_METHOD void dumpToStream(llvm::raw_ostream &Out) const;
+};
+
+using PackageInfoList = llvm::SmallVector<PackageInfo, 0>;
+
+namespace checker_registry {
+
+template <class T> struct FullNameLT {
+  bool operator()(const T &Lhs, const T &Rhs) {
+    return Lhs.FullName < Rhs.FullName;
+  }
+};
+
+using PackageNameLT = FullNameLT<PackageInfo>;
+using CheckerNameLT = FullNameLT<CheckerInfo>;
+
+template <class CheckerOrPackageInfoList>
+std::conditional_t<std::is_const<CheckerOrPackageInfoList>::value,
+                   typename CheckerOrPackageInfoList::const_iterator,
+                   typename CheckerOrPackageInfoList::iterator>
+binaryFind(CheckerOrPackageInfoList &Collection, StringRef FullName) {
+
+  using CheckerOrPackage = typename CheckerOrPackageInfoList::value_type;
+  using CheckerOrPackageFullNameLT = FullNameLT<CheckerOrPackage>;
+
+  assert(llvm::is_sorted(Collection, CheckerOrPackageFullNameLT{}) &&
+         "In order to efficiently gather checkers/packages, this function "
+         "expects them to be already sorted!");
+
+  return llvm::lower_bound(Collection, CheckerOrPackage(FullName),
+                           CheckerOrPackageFullNameLT{});
+}
+} // namespace checker_registry
+
+struct CheckerRegistryData {
+public:
+  CheckerInfoSet EnabledCheckers;
+
+  CheckerInfoList Checkers;
+  PackageInfoList Packages;
+  /// Used for counting how many checkers belong to a certain package in the
+  /// \c Checkers field. For convenience purposes.
+  llvm::StringMap<size_t> PackageSizes;
+
+  /// Contains all (FullName, CmdLineOption) pairs. Similarly to dependencies,
+  /// we only modify the actual CheckerInfo and PackageInfo objects once all
+  /// of them have been added.
+  llvm::SmallVector<std::pair<StringRef, CmdLineOption>, 0> PackageOptions;
+  llvm::SmallVector<std::pair<StringRef, CmdLineOption>, 0> CheckerOptions;
+
+  llvm::SmallVector<std::pair<StringRef, StringRef>, 0> Dependencies;
+  llvm::SmallVector<std::pair<StringRef, StringRef>, 0> WeakDependencies;
+
+  CheckerInfoListRange getMutableCheckersForCmdLineArg(StringRef CmdLineArg);
+
+  /// Prints the name and description of all checkers in this registry.
+  /// This output is not intended to be machine-parseable.
+  void printCheckerWithDescList(const AnalyzerOptions &AnOpts, raw_ostream &Out,
+                                size_t MaxNameChars = 30) const;
+  void printEnabledCheckerList(raw_ostream &Out) const;
+  void printCheckerOptionList(const AnalyzerOptions &AnOpts,
+                              raw_ostream &Out) const;
+};
+
+} // namespace ento
+} // namespace clang
+
+#endif // LLVM_CLANG_STATICANALYZER_CORE_CHECKERREGISTRYDATA_H
diff --git a/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h b/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h
index 7b72fae..43dbfb1 100644
--- a/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h
+++ b/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h
@@ -5,17 +5,22 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
+//
+// Contains the logic for parsing the TableGen file Checkers.td, and parsing the
+// specific invocation of the analyzer (which checker/package is enabled, values
+// of their options, etc). This is in the frontend library because checker
+// registry functions are called from here but are defined in the dependent
+// library libStaticAnalyzerCheckers, but the actual data structure that holds
+// the parsed information is in the Core library.
+//
+//===----------------------------------------------------------------------===//
 
-#ifndef LLVM_CLANG_STATICANALYZER_CORE_CHECKERREGISTRY_H
-#define LLVM_CLANG_STATICANALYZER_CORE_CHECKERREGISTRY_H
+#ifndef LLVM_CLANG_STATICANALYZER_FRONTEND_CHECKERREGISTRY_H
+#define LLVM_CLANG_STATICANALYZER_FRONTEND_CHECKERREGISTRY_H
 
 #include "clang/Basic/LLVM.h"
-#include "llvm/ADT/SetVector.h"
-#include "llvm/ADT/StringMap.h"
+#include "clang/StaticAnalyzer/Core/CheckerRegistryData.h"
 #include "llvm/ADT/StringRef.h"
-#include "llvm/Support/raw_ostream.h"
-#include <cstddef>
-#include <vector>
 
 // FIXME: move this information to an HTML file in docs/.
 // At the very least, a checker plugin is a dynamic library that exports
@@ -83,143 +88,16 @@
 /// "core.builtin", or the full name "core.builtin.NoReturnFunctionChecker".
 class CheckerRegistry {
 public:
-  CheckerRegistry(ArrayRef<std::string> plugins, DiagnosticsEngine &diags,
-                  AnalyzerOptions &AnOpts,
+  CheckerRegistry(CheckerRegistryData &Data, ArrayRef<std::string> Plugins,
+                  DiagnosticsEngine &Diags, AnalyzerOptions &AnOpts,
                   ArrayRef<std::function<void(CheckerRegistry &)>>
-                      checkerRegistrationFns = {});
+                      CheckerRegistrationFns = {});
 
   /// Collects all enabled checkers in the field EnabledCheckers. It preserves
   /// the order of insertion, as dependencies have to be enabled before the
   /// checkers that depend on them.
   void initializeRegistry(const CheckerManager &Mgr);
 
-  /// Initialization functions perform any necessary setup for a checker.
-  /// They should include a call to CheckerManager::registerChecker.
-  using InitializationFunction = void (*)(CheckerManager &);
-  using ShouldRegisterFunction = bool (*)(const CheckerManager &);
-
-  /// Specifies a command line option. It may either belong to a checker or a
-  /// package.
-  struct CmdLineOption {
-    StringRef OptionType;
-    StringRef OptionName;
-    StringRef DefaultValStr;
-    StringRef Description;
-    StringRef DevelopmentStatus;
-    bool IsHidden;
-
-    CmdLineOption(StringRef OptionType, StringRef OptionName,
-                  StringRef DefaultValStr, StringRef Description,
-                  StringRef DevelopmentStatus, bool IsHidden)
-        : OptionType(OptionType), OptionName(OptionName),
-          DefaultValStr(DefaultValStr), Description(Description),
-          DevelopmentStatus(DevelopmentStatus), IsHidden(IsHidden) {
-
-      assert((OptionType == "bool" || OptionType == "string" ||
-              OptionType == "int") &&
-             "Unknown command line option type!");
-
-      assert((OptionType != "bool" ||
-              (DefaultValStr == "true" || DefaultValStr == "false")) &&
-             "Invalid value for boolean command line option! Maybe incorrect "
-             "parameters to the addCheckerOption or addPackageOption method?");
-
-      int Tmp;
-      assert((OptionType != "int" || !DefaultValStr.getAsInteger(0, Tmp)) &&
-             "Invalid value for integer command line option! Maybe incorrect "
-             "parameters to the addCheckerOption or addPackageOption method?");
-      (void)Tmp;
-
-      assert((DevelopmentStatus == "alpha" || DevelopmentStatus == "beta" ||
-              DevelopmentStatus == "released") &&
-             "Invalid development status!");
-    }
-
-    LLVM_DUMP_METHOD void dump() const { dumpToStream(llvm::errs()); }
-    LLVM_DUMP_METHOD void dumpToStream(llvm::raw_ostream &Out) const;
-  };
-
-  using CmdLineOptionList = llvm::SmallVector<CmdLineOption, 0>;
-
-  struct CheckerInfo;
-
-  using CheckerInfoList = std::vector<CheckerInfo>;
-  using CheckerInfoListRange = llvm::iterator_range<CheckerInfoList::iterator>;
-  using ConstCheckerInfoList = llvm::SmallVector<const CheckerInfo *, 0>;
-  using CheckerInfoSet = llvm::SetVector<const CheckerInfo *>;
-
-  /// Specifies a checker. Note that this isn't what we call a checker object,
-  /// it merely contains everything required to create one.
-  struct CheckerInfo {
-    enum class StateFromCmdLine {
-      // This checker wasn't explicitly enabled or disabled.
-      State_Unspecified,
-      // This checker was explicitly disabled.
-      State_Disabled,
-      // This checker was explicitly enabled.
-      State_Enabled
-    };
-
-    InitializationFunction Initialize = nullptr;
-    ShouldRegisterFunction ShouldRegister = nullptr;
-    StringRef FullName;
-    StringRef Desc;
-    StringRef DocumentationUri;
-    CmdLineOptionList CmdLineOptions;
-    bool IsHidden = false;
-    StateFromCmdLine State = StateFromCmdLine::State_Unspecified;
-
-    ConstCheckerInfoList Dependencies;
-    ConstCheckerInfoList WeakDependencies;
-
-    bool isEnabled(const CheckerManager &mgr) const {
-      return State == StateFromCmdLine::State_Enabled && ShouldRegister(mgr);
-    }
-
-    bool isDisabled(const CheckerManager &mgr) const {
-      return State == StateFromCmdLine::State_Disabled || !ShouldRegister(mgr);
-    }
-
-    // Since each checker must have a different full name, we can identify
-    // CheckerInfo objects by them.
-    bool operator==(const CheckerInfo &Rhs) const {
-      return FullName == Rhs.FullName;
-    }
-
-    CheckerInfo(InitializationFunction Fn, ShouldRegisterFunction sfn,
-                StringRef Name, StringRef Desc, StringRef DocsUri,
-                bool IsHidden)
-        : Initialize(Fn), ShouldRegister(sfn), FullName(Name), Desc(Desc),
-          DocumentationUri(DocsUri), IsHidden(IsHidden) {}
-
-    // Used for lower_bound.
-    explicit CheckerInfo(StringRef FullName) : FullName(FullName) {}
-
-    LLVM_DUMP_METHOD void dump() const { dumpToStream(llvm::errs()); }
-    LLVM_DUMP_METHOD void dumpToStream(llvm::raw_ostream &Out) const;
-  };
-
-  using StateFromCmdLine = CheckerInfo::StateFromCmdLine;
-
-  /// Specifies a package. Each package option is implicitly an option for all
-  /// checkers within the package.
-  struct PackageInfo {
-    StringRef FullName;
-    CmdLineOptionList CmdLineOptions;
-
-    // Since each package must have a different full name, we can identify
-    // CheckerInfo objects by them.
-    bool operator==(const PackageInfo &Rhs) const {
-      return FullName == Rhs.FullName;
-    }
-
-    explicit PackageInfo(StringRef FullName) : FullName(FullName) {}
-
-    LLVM_DUMP_METHOD void dump() const { dumpToStream(llvm::errs()); }
-    LLVM_DUMP_METHOD void dumpToStream(llvm::raw_ostream &Out) const;
-  };
-
-  using PackageInfoList = llvm::SmallVector<PackageInfo, 0>;
 
 private:
   /// Default initialization function for checkers -- since CheckerManager
@@ -237,7 +115,7 @@
 public:
   /// Adds a checker to the registry. Use this non-templated overload when your
   /// checker requires custom initialization.
-  void addChecker(InitializationFunction Fn, ShouldRegisterFunction sfn,
+  void addChecker(RegisterCheckerFn Fn, ShouldRegisterFunction sfn,
                   StringRef FullName, StringRef Desc, StringRef DocsUri,
                   bool IsHidden);
 
@@ -305,46 +183,17 @@
   /// Check if every option corresponds to a specific checker or package.
   void validateCheckerOptions() const;
 
-  /// Prints the name and description of all checkers in this registry.
-  /// This output is not intended to be machine-parseable.
-  void printCheckerWithDescList(raw_ostream &Out,
-                                size_t MaxNameChars = 30) const;
-  void printEnabledCheckerList(raw_ostream &Out) const;
-  void printCheckerOptionList(raw_ostream &Out) const;
-
 private:
-  /// Return an iterator range of mutable CheckerInfos \p CmdLineArg applies to.
-  /// For example, it'll return the checkers for the core package, if
-  /// \p CmdLineArg is "core".
-  CheckerInfoListRange getMutableCheckersForCmdLineArg(StringRef CmdLineArg);
-
-  CheckerInfoList Checkers;
-  PackageInfoList Packages;
-  /// Used for couting how many checkers belong to a certain package in the
-  /// \c Checkers field. For convenience purposes.
-  llvm::StringMap<size_t> PackageSizes;
-
-  /// Contains all (Dependendent checker, Dependency) pairs. We need this, as
-  /// we'll resolve dependencies after all checkers were added first.
-  llvm::SmallVector<std::pair<StringRef, StringRef>, 0> Dependencies;
-  llvm::SmallVector<std::pair<StringRef, StringRef>, 0> WeakDependencies;
-
   template <bool IsWeak> void resolveDependencies();
-
-  /// Contains all (FullName, CmdLineOption) pairs. Similarly to dependencies,
-  /// we only modify the actual CheckerInfo and PackageInfo objects once all
-  /// of them have been added.
-  llvm::SmallVector<std::pair<StringRef, CmdLineOption>, 0> PackageOptions;
-  llvm::SmallVector<std::pair<StringRef, CmdLineOption>, 0> CheckerOptions;
-
   void resolveCheckerAndPackageOptions();
 
+  CheckerRegistryData &Data;
+
   DiagnosticsEngine &Diags;
   AnalyzerOptions &AnOpts;
-  CheckerInfoSet EnabledCheckers;
 };
 
 } // namespace ento
 } // namespace clang
 
-#endif // LLVM_CLANG_STATICANALYZER_CORE_CHECKERREGISTRY_H
+#endif // LLVM_CLANG_STATICANALYZER_FRONTEND_CHECKERREGISTRY_H
diff --git a/clang/lib/StaticAnalyzer/Core/CMakeLists.txt b/clang/lib/StaticAnalyzer/Core/CMakeLists.txt
index 192185b..f2329ae 100644
--- a/clang/lib/StaticAnalyzer/Core/CMakeLists.txt
+++ b/clang/lib/StaticAnalyzer/Core/CMakeLists.txt
@@ -16,6 +16,7 @@
   CheckerContext.cpp
   CheckerHelpers.cpp
   CheckerManager.cpp
+  CheckerRegistryData.cpp
   CommonBugCategories.cpp
   ConstraintManager.cpp
   CoreEngine.cpp
diff --git a/clang/lib/StaticAnalyzer/Core/CheckerRegistryData.cpp b/clang/lib/StaticAnalyzer/Core/CheckerRegistryData.cpp
new file mode 100644
index 0000000..7d5bfb2
--- /dev/null
+++ b/clang/lib/StaticAnalyzer/Core/CheckerRegistryData.cpp
@@ -0,0 +1,233 @@
+//===- CheckerRegistry.h - Maintains all available checkers -----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Core/CheckerRegistryData.h"
+#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
+#include "llvm/ADT/Twine.h"
+#include <map>
+
+using namespace clang;
+using namespace ento;
+
+//===----------------------------------------------------------------------===//
+// Methods of CmdLineOption, PackageInfo and CheckerInfo.
+//===----------------------------------------------------------------------===//
+
+LLVM_DUMP_METHOD void
+CmdLineOption::dumpToStream(llvm::raw_ostream &Out) const {
+  // The description can be just checked in Checkers.inc, the point here is to
+  // debug whether we succeeded in parsing it.
+  Out << OptionName << " (" << OptionType << ", "
+      << (IsHidden ? "hidden, " : "") << DevelopmentStatus << ") default: \""
+      << DefaultValStr;
+}
+
+static StringRef toString(StateFromCmdLine Kind) {
+  switch (Kind) {
+  case StateFromCmdLine::State_Disabled:
+    return "Disabled";
+  case StateFromCmdLine::State_Enabled:
+    return "Enabled";
+  case StateFromCmdLine::State_Unspecified:
+    return "Unspecified";
+  }
+  llvm_unreachable("Unhandled StateFromCmdLine enum");
+}
+
+LLVM_DUMP_METHOD void CheckerInfo::dumpToStream(llvm::raw_ostream &Out) const {
+  // The description can be just checked in Checkers.inc, the point here is to
+  // debug whether we succeeded in parsing it. Same with documentation uri.
+  Out << FullName << " (" << toString(State) << (IsHidden ? ", hidden" : "")
+      << ")\n";
+  Out << "  Options:\n";
+  for (const CmdLineOption &Option : CmdLineOptions) {
+    Out << "    ";
+    Option.dumpToStream(Out);
+    Out << '\n';
+  }
+  Out << "  Dependencies:\n";
+  for (const CheckerInfo *Dependency : Dependencies) {
+    Out << "  " << Dependency->FullName << '\n';
+  }
+  Out << "  Weak dependencies:\n";
+  for (const CheckerInfo *Dependency : WeakDependencies) {
+    Out << "    " << Dependency->FullName << '\n';
+  }
+}
+
+LLVM_DUMP_METHOD void PackageInfo::dumpToStream(llvm::raw_ostream &Out) const {
+  Out << FullName << "\n";
+  Out << "  Options:\n";
+  for (const CmdLineOption &Option : CmdLineOptions) {
+    Out << "    ";
+    Option.dumpToStream(Out);
+    Out << '\n';
+  }
+}
+
+static constexpr char PackageSeparator = '.';
+
+static bool isInPackage(const 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;
+}
+
+CheckerInfoListRange
+CheckerRegistryData::getMutableCheckersForCmdLineArg(StringRef CmdLineArg) {
+  auto It = checker_registry::binaryFind(Checkers, CmdLineArg);
+
+  if (!isInPackage(*It, CmdLineArg))
+    return {Checkers.end(), Checkers.end()};
+
+  // 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(CmdLineArg);
+
+  if (PackageSize != PackageSizes.end())
+    Size = PackageSize->getValue();
+
+  return {It, It + Size};
+}
+//===----------------------------------------------------------------------===//
+// Printing functions.
+//===----------------------------------------------------------------------===//
+
+void CheckerRegistryData::printCheckerWithDescList(
+    const AnalyzerOptions &AnOpts, raw_ostream &Out,
+    size_t MaxNameChars) const {
+  // FIXME: Print available packages.
+
+  Out << "CHECKERS:\n";
+
+  // Find the maximum option length.
+  size_t OptionFieldWidth = 0;
+  for (const auto &Checker : Checkers) {
+    // Limit the amount of padding we are willing to give up for alignment.
+    //   Package.Name     Description  [Hidden]
+    size_t NameLength = Checker.FullName.size();
+    if (NameLength <= MaxNameChars)
+      OptionFieldWidth = std::max(OptionFieldWidth, NameLength);
+  }
+
+  const size_t InitialPad = 2;
+
+  auto Print = [=](llvm::raw_ostream &Out, const CheckerInfo &Checker,
+                   StringRef Description) {
+    AnalyzerOptions::printFormattedEntry(Out, {Checker.FullName, Description},
+                                         InitialPad, OptionFieldWidth);
+    Out << '\n';
+  };
+
+  for (const auto &Checker : Checkers) {
+    // The order of this if branches is significant, we wouldn't like to display
+    // developer checkers even in the alpha output. For example,
+    // alpha.cplusplus.IteratorModeling is a modeling checker, hence it's hidden
+    // by default, and users (even when the user is a developer of an alpha
+    // checker) shouldn't normally tinker with whether they should be enabled.
+
+    if (Checker.IsHidden) {
+      if (AnOpts.ShowCheckerHelpDeveloper)
+        Print(Out, Checker, Checker.Desc);
+      continue;
+    }
+
+    if (Checker.FullName.startswith("alpha")) {
+      if (AnOpts.ShowCheckerHelpAlpha)
+        Print(Out, Checker,
+              ("(Enable only for development!) " + Checker.Desc).str());
+      continue;
+    }
+
+    if (AnOpts.ShowCheckerHelp)
+      Print(Out, Checker, Checker.Desc);
+  }
+}
+
+void CheckerRegistryData::printEnabledCheckerList(raw_ostream &Out) const {
+  for (const auto *i : EnabledCheckers)
+    Out << i->FullName << '\n';
+}
+
+void CheckerRegistryData::printCheckerOptionList(const AnalyzerOptions &AnOpts,
+                                                 raw_ostream &Out) const {
+  Out << "OVERVIEW: Clang Static Analyzer Checker and Package Option List\n\n";
+  Out << "USAGE: -analyzer-config <OPTION1=VALUE,OPTION2=VALUE,...>\n\n";
+  Out << "       -analyzer-config OPTION1=VALUE, -analyzer-config "
+         "OPTION2=VALUE, ...\n\n";
+  Out << "OPTIONS:\n\n";
+
+  // It's usually ill-advised to use multimap, but clang will terminate after
+  // this function.
+  std::multimap<StringRef, const CmdLineOption &> OptionMap;
+
+  for (const CheckerInfo &Checker : Checkers) {
+    for (const CmdLineOption &Option : Checker.CmdLineOptions) {
+      OptionMap.insert({Checker.FullName, Option});
+    }
+  }
+
+  for (const PackageInfo &Package : Packages) {
+    for (const CmdLineOption &Option : Package.CmdLineOptions) {
+      OptionMap.insert({Package.FullName, Option});
+    }
+  }
+
+  auto Print = [](llvm::raw_ostream &Out, StringRef FullOption,
+                  StringRef Desc) {
+    AnalyzerOptions::printFormattedEntry(Out, {FullOption, Desc},
+                                         /*InitialPad*/ 2,
+                                         /*EntryWidth*/ 50,
+                                         /*MinLineWidth*/ 90);
+    Out << "\n\n";
+  };
+  for (const std::pair<const StringRef, const CmdLineOption &> &Entry :
+       OptionMap) {
+    const CmdLineOption &Option = Entry.second;
+    std::string FullOption = (Entry.first + ":" + Option.OptionName).str();
+
+    std::string Desc =
+        ("(" + Option.OptionType + ") " + Option.Description + " (default: " +
+         (Option.DefaultValStr.empty() ? "\"\"" : Option.DefaultValStr) + ")")
+            .str();
+
+    // The list of these if branches is significant, we wouldn't like to
+    // display hidden alpha checker options for
+    // -analyzer-checker-option-help-alpha.
+
+    if (Option.IsHidden) {
+      if (AnOpts.ShowCheckerOptionDeveloperList)
+        Print(Out, FullOption, Desc);
+      continue;
+    }
+
+    if (Option.DevelopmentStatus == "alpha" ||
+        Entry.first.startswith("alpha")) {
+      if (AnOpts.ShowCheckerOptionAlphaList)
+        Print(Out, FullOption,
+              llvm::Twine("(Enable only for development!) " + Desc).str());
+      continue;
+    }
+
+    if (AnOpts.ShowCheckerOptionList)
+      Print(Out, FullOption, Desc);
+  }
+}
diff --git a/clang/lib/StaticAnalyzer/Core/Environment.cpp b/clang/lib/StaticAnalyzer/Core/Environment.cpp
index 1ccf4c6..9e6d79b 100644
--- a/clang/lib/StaticAnalyzer/Core/Environment.cpp
+++ b/clang/lib/StaticAnalyzer/Core/Environment.cpp
@@ -183,12 +183,18 @@
              F.getTreeFactory());
 
   // Iterate over the block-expr bindings.
-  for (Environment::iterator I = Env.begin(), E = Env.end();
-       I != E; ++I) {
+  for (Environment::iterator I = Env.begin(), E = Env.end(); I != E; ++I) {
     const EnvironmentEntry &BlkExpr = I.getKey();
     const SVal &X = I.getData();
 
-    if (SymReaper.isLive(BlkExpr.getStmt(), BlkExpr.getLocationContext())) {
+    const bool IsBlkExprLive =
+        SymReaper.isLive(BlkExpr.getStmt(), BlkExpr.getLocationContext());
+
+    assert((isa<Expr>(BlkExpr.getStmt()) || !IsBlkExprLive) &&
+           "Only Exprs can be live, LivenessAnalysis argues about the liveness "
+           "of *values*!");
+
+    if (IsBlkExprLive) {
       // Copy the binding to the new map.
       EBMapRef = EBMapRef.add(BlkExpr, X);
 
diff --git a/clang/lib/StaticAnalyzer/Frontend/AnalyzerHelpFlags.cpp b/clang/lib/StaticAnalyzer/Frontend/AnalyzerHelpFlags.cpp
index d589e69..eb6014a 100644
--- a/clang/lib/StaticAnalyzer/Frontend/AnalyzerHelpFlags.cpp
+++ b/clang/lib/StaticAnalyzer/Frontend/AnalyzerHelpFlags.cpp
@@ -33,7 +33,8 @@
       *CI.getAnalyzerOpts(), CI.getLangOpts(), CI.getDiagnostics(),
       CI.getFrontendOpts().Plugins);
 
-  CheckerMgr->getCheckerRegistry().printCheckerWithDescList(out);
+  CheckerMgr->getCheckerRegistryData().printCheckerWithDescList(
+      *CI.getAnalyzerOpts(), out);
 }
 
 void ento::printEnabledCheckerList(raw_ostream &out, CompilerInstance &CI) {
@@ -43,7 +44,7 @@
       *CI.getAnalyzerOpts(), CI.getLangOpts(), CI.getDiagnostics(),
       CI.getFrontendOpts().Plugins);
 
-  CheckerMgr->getCheckerRegistry().printEnabledCheckerList(out);
+  CheckerMgr->getCheckerRegistryData().printEnabledCheckerList(out);
 }
 
 void ento::printCheckerConfigList(raw_ostream &out, CompilerInstance &CI) {
@@ -52,7 +53,8 @@
       *CI.getAnalyzerOpts(), CI.getLangOpts(), CI.getDiagnostics(),
       CI.getFrontendOpts().Plugins);
 
-  CheckerMgr->getCheckerRegistry().printCheckerOptionList(out);
+  CheckerMgr->getCheckerRegistryData().printCheckerOptionList(
+      *CI.getAnalyzerOpts(), out);
 }
 
 void ento::printAnalyzerConfigList(raw_ostream &out) {
diff --git a/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp b/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp
index e690ed8..a688205 100644
--- a/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp
+++ b/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp
@@ -25,14 +25,13 @@
 
 using namespace clang;
 using namespace ento;
+using namespace checker_registry;
 using llvm::sys::DynamicLibrary;
 
 //===----------------------------------------------------------------------===//
 // Utilities.
 //===----------------------------------------------------------------------===//
 
-using RegisterCheckersFn = void (*)(CheckerRegistry &);
-
 static bool isCompatibleAPIVersion(const char *VersionString) {
   // If the version string is null, its not an analyzer plugin.
   if (!VersionString)
@@ -43,140 +42,17 @@
   return strcmp(VersionString, CLANG_ANALYZER_API_VERSION_STRING) == 0;
 }
 
-namespace {
-template <class T> struct FullNameLT {
-  bool operator()(const T &Lhs, const T &Rhs) {
-    return Lhs.FullName < Rhs.FullName;
-  }
-};
-
-using PackageNameLT = FullNameLT<CheckerRegistry::PackageInfo>;
-using CheckerNameLT = FullNameLT<CheckerRegistry::CheckerInfo>;
-} // end of anonymous namespace
-
-template <class CheckerOrPackageInfoList>
-static std::conditional_t<std::is_const<CheckerOrPackageInfoList>::value,
-                          typename CheckerOrPackageInfoList::const_iterator,
-                          typename CheckerOrPackageInfoList::iterator>
-binaryFind(CheckerOrPackageInfoList &Collection, StringRef FullName) {
-
-  using CheckerOrPackage = typename CheckerOrPackageInfoList::value_type;
-  using CheckerOrPackageFullNameLT = FullNameLT<CheckerOrPackage>;
-
-  assert(llvm::is_sorted(Collection, CheckerOrPackageFullNameLT{}) &&
-         "In order to efficiently gather checkers/packages, this function "
-         "expects them to be already sorted!");
-
-  return llvm::lower_bound(Collection, CheckerOrPackage(FullName),
-                           CheckerOrPackageFullNameLT{});
-}
-
 static constexpr char PackageSeparator = '.';
 
-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;
-}
-
-//===----------------------------------------------------------------------===//
-// Methods of CmdLineOption, PackageInfo and CheckerInfo.
-//===----------------------------------------------------------------------===//
-
-LLVM_DUMP_METHOD void
-CheckerRegistry::CmdLineOption::dumpToStream(llvm::raw_ostream &Out) const {
-  // The description can be just checked in Checkers.inc, the point here is to
-  // debug whether we succeeded in parsing it.
-  Out << OptionName << " (" << OptionType << ", "
-      << (IsHidden ? "hidden, " : "") << DevelopmentStatus << ") default: \""
-      << DefaultValStr;
-}
-
-static StringRef toString(CheckerRegistry::StateFromCmdLine Kind) {
-  switch (Kind) {
-  case CheckerRegistry::StateFromCmdLine::State_Disabled:
-    return "Disabled";
-  case CheckerRegistry::StateFromCmdLine::State_Enabled:
-    return "Enabled";
-  case CheckerRegistry::StateFromCmdLine::State_Unspecified:
-    return "Unspecified";
-  }
-  llvm_unreachable("Unhandled CheckerRegistry::StateFromCmdLine enum");
-}
-
-LLVM_DUMP_METHOD void
-CheckerRegistry::CheckerInfo::dumpToStream(llvm::raw_ostream &Out) const {
-  // The description can be just checked in Checkers.inc, the point here is to
-  // debug whether we succeeded in parsing it. Same with documentation uri.
-  Out << FullName << " (" << toString(State) << (IsHidden ? ", hidden" : "")
-      << ")\n";
-  Out << "  Options:\n";
-  for (const CmdLineOption &Option : CmdLineOptions) {
-    Out << "    ";
-    Option.dumpToStream(Out);
-    Out << '\n';
-  }
-  Out << "  Dependencies:\n";
-  for (const CheckerInfo *Dependency : Dependencies) {
-    Out << "  " << Dependency->FullName << '\n';
-  }
-  Out << "  Weak dependencies:\n";
-  for (const CheckerInfo *Dependency : WeakDependencies) {
-    Out << "    " << Dependency->FullName << '\n';
-  }
-}
-
-LLVM_DUMP_METHOD void
-CheckerRegistry::PackageInfo::dumpToStream(llvm::raw_ostream &Out) const {
-  Out << FullName << "\n";
-  Out << "  Options:\n";
-  for (const CmdLineOption &Option : CmdLineOptions) {
-    Out << "    ";
-    Option.dumpToStream(Out);
-    Out << '\n';
-  }
-}
-
 //===----------------------------------------------------------------------===//
 // Methods of CheckerRegistry.
 //===----------------------------------------------------------------------===//
 
-CheckerRegistry::CheckerInfoListRange
-CheckerRegistry::getMutableCheckersForCmdLineArg(StringRef CmdLineArg) {
-  auto It = binaryFind(Checkers, CmdLineArg);
-
-  if (!isInPackage(*It, CmdLineArg))
-    return {Checkers.end(), Checkers.end()};
-
-  // 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(CmdLineArg);
-
-  if (PackageSize != PackageSizes.end())
-    Size = PackageSize->getValue();
-
-  return {It, It + Size};
-}
-
 CheckerRegistry::CheckerRegistry(
-    ArrayRef<std::string> Plugins, DiagnosticsEngine &Diags,
-    AnalyzerOptions &AnOpts,
+    CheckerRegistryData &Data, ArrayRef<std::string> Plugins,
+    DiagnosticsEngine &Diags, AnalyzerOptions &AnOpts,
     ArrayRef<std::function<void(CheckerRegistry &)>> CheckerRegistrationFns)
-    : Diags(Diags), AnOpts(AnOpts) {
+    : Data(Data), Diags(Diags), AnOpts(AnOpts) {
 
   // Register builtin checkers.
 #define GET_CHECKERS
@@ -216,9 +92,10 @@
       continue;
     }
 
+    using RegisterPluginCheckerFn = void (*)(CheckerRegistry &);
     // Register its checkers.
-    RegisterCheckersFn RegisterPluginCheckers =
-        reinterpret_cast<RegisterCheckersFn>(
+    RegisterPluginCheckerFn RegisterPluginCheckers =
+        reinterpret_cast<RegisterPluginCheckerFn>(
             Lib.getAddressOfSymbol("clang_registerCheckers"));
     if (RegisterPluginCheckers)
       RegisterPluginCheckers(*this);
@@ -235,8 +112,8 @@
   // FIXME: Alphabetical sort puts 'experimental' in the middle.
   // Would it be better to name it '~experimental' or something else
   // that's ASCIIbetically last?
-  llvm::sort(Packages, PackageNameLT{});
-  llvm::sort(Checkers, CheckerNameLT{});
+  llvm::sort(Data.Packages, checker_registry::PackageNameLT{});
+  llvm::sort(Data.Checkers, checker_registry::CheckerNameLT{});
 
 #define GET_CHECKER_DEPENDENCIES
 
@@ -274,8 +151,8 @@
   resolveDependencies<false>();
 
 #ifndef NDEBUG
-  for (auto &DepPair : Dependencies) {
-    for (auto &WeakDepPair : WeakDependencies) {
+  for (auto &DepPair : Data.Dependencies) {
+    for (auto &WeakDepPair : Data.WeakDependencies) {
       // Some assertions to enforce that strong dependencies are relations in
       // between purely modeling checkers, and weak dependencies are about
       // diagnostics.
@@ -295,7 +172,7 @@
   // command line.
   for (const std::pair<std::string, bool> &Opt : AnOpts.CheckersAndPackages) {
     CheckerInfoListRange CheckerForCmdLineArg =
-        getMutableCheckersForCmdLineArg(Opt.first);
+        Data.getMutableCheckersForCmdLineArg(Opt.first);
 
     if (CheckerForCmdLineArg.begin() == CheckerForCmdLineArg.end()) {
       Diags.Report(diag::err_unknown_analyzer_checker_or_package) << Opt.first;
@@ -315,19 +192,16 @@
 //===----------------------------------------------------------------------===//
 
 template <typename IsEnabledFn>
-static bool
-collectStrongDependencies(const CheckerRegistry::ConstCheckerInfoList &Deps,
-                          const CheckerManager &Mgr,
-                          CheckerRegistry::CheckerInfoSet &Ret,
-                          IsEnabledFn IsEnabled);
+static bool collectStrongDependencies(const ConstCheckerInfoList &Deps,
+                                      const CheckerManager &Mgr,
+                                      CheckerInfoSet &Ret,
+                                      IsEnabledFn IsEnabled);
 
-/// Collects weak dependencies in \p enabledCheckers.
+/// Collects weak dependencies in \p enabledData.Checkers.
 template <typename IsEnabledFn>
-static void
-collectWeakDependencies(const CheckerRegistry::ConstCheckerInfoList &Deps,
-                        const CheckerManager &Mgr,
-                        CheckerRegistry::CheckerInfoSet &Ret,
-                        IsEnabledFn IsEnabled);
+static void collectWeakDependencies(const ConstCheckerInfoList &Deps,
+                                    const CheckerManager &Mgr,
+                                    CheckerInfoSet &Ret, IsEnabledFn IsEnabled);
 
 void CheckerRegistry::initializeRegistry(const CheckerManager &Mgr) {
   // First, we calculate the list of enabled checkers as specified by the
@@ -338,7 +212,7 @@
   auto IsEnabledFromCmdLine = [&](const CheckerInfo *Checker) {
     return !Checker->isDisabled(Mgr);
   };
-  for (const CheckerInfo &Checker : Checkers) {
+  for (const CheckerInfo &Checker : Data.Checkers) {
     if (!Checker.isEnabled(Mgr))
       continue;
 
@@ -362,7 +236,7 @@
   auto IsEnabled = [&](const CheckerInfo *Checker) {
     return llvm::is_contained(Tmp, Checker);
   };
-  for (const CheckerInfo &Checker : Checkers) {
+  for (const CheckerInfo &Checker : Data.Checkers) {
     if (!Checker.isEnabled(Mgr))
       continue;
 
@@ -378,19 +252,18 @@
     }
 
     // Note that set_union also preserves the order of insertion.
-    EnabledCheckers.set_union(Deps);
-    EnabledCheckers.insert(&Checker);
+    Data.EnabledCheckers.set_union(Deps);
+    Data.EnabledCheckers.insert(&Checker);
   }
 }
 
 template <typename IsEnabledFn>
-static bool
-collectStrongDependencies(const CheckerRegistry::ConstCheckerInfoList &Deps,
-                          const CheckerManager &Mgr,
-                          CheckerRegistry::CheckerInfoSet &Ret,
-                          IsEnabledFn IsEnabled) {
+static bool collectStrongDependencies(const ConstCheckerInfoList &Deps,
+                                      const CheckerManager &Mgr,
+                                      CheckerInfoSet &Ret,
+                                      IsEnabledFn IsEnabled) {
 
-  for (const CheckerRegistry::CheckerInfo *Dependency : Deps) {
+  for (const CheckerInfo *Dependency : Deps) {
     if (!IsEnabled(Dependency))
       return false;
 
@@ -405,13 +278,12 @@
 }
 
 template <typename IsEnabledFn>
-static void
-collectWeakDependencies(const CheckerRegistry::ConstCheckerInfoList &WeakDeps,
-                        const CheckerManager &Mgr,
-                        CheckerRegistry::CheckerInfoSet &Ret,
-                        IsEnabledFn IsEnabled) {
+static void collectWeakDependencies(const ConstCheckerInfoList &WeakDeps,
+                                    const CheckerManager &Mgr,
+                                    CheckerInfoSet &Ret,
+                                    IsEnabledFn IsEnabled) {
 
-  for (const CheckerRegistry::CheckerInfo *Dependency : WeakDeps) {
+  for (const CheckerInfo *Dependency : WeakDeps) {
     // Don't enable this checker if strong dependencies are unsatisfied, but
     // assume that weak dependencies are transitive.
     collectWeakDependencies(Dependency->WeakDependencies, Mgr, Ret, IsEnabled);
@@ -425,15 +297,16 @@
 
 template <bool IsWeak> void CheckerRegistry::resolveDependencies() {
   for (const std::pair<StringRef, StringRef> &Entry :
-       (IsWeak ? WeakDependencies : Dependencies)) {
+       (IsWeak ? Data.WeakDependencies : Data.Dependencies)) {
 
-    auto CheckerIt = binaryFind(Checkers, Entry.first);
-    assert(CheckerIt != Checkers.end() && CheckerIt->FullName == Entry.first &&
+    auto CheckerIt = binaryFind(Data.Checkers, Entry.first);
+    assert(CheckerIt != Data.Checkers.end() &&
+           CheckerIt->FullName == Entry.first &&
            "Failed to find the checker while attempting to set up its "
            "dependencies!");
 
-    auto DependencyIt = binaryFind(Checkers, Entry.second);
-    assert(DependencyIt != Checkers.end() &&
+    auto DependencyIt = binaryFind(Data.Checkers, Entry.second);
+    assert(DependencyIt != Data.Checkers.end() &&
            DependencyIt->FullName == Entry.second &&
            "Failed to find the dependency of a checker!");
 
@@ -445,12 +318,12 @@
 }
 
 void CheckerRegistry::addDependency(StringRef FullName, StringRef Dependency) {
-  Dependencies.emplace_back(FullName, Dependency);
+  Data.Dependencies.emplace_back(FullName, Dependency);
 }
 
 void CheckerRegistry::addWeakDependency(StringRef FullName,
                                         StringRef Dependency) {
-  WeakDependencies.emplace_back(FullName, Dependency);
+  Data.WeakDependencies.emplace_back(FullName, Dependency);
 }
 
 //===----------------------------------------------------------------------===//
@@ -459,8 +332,7 @@
 
 /// Insert the checker/package option to AnalyzerOptions' config table, and
 /// validate it, if the user supplied it on the command line.
-static void insertAndValidate(StringRef FullName,
-                              const CheckerRegistry::CmdLineOption &Option,
+static void insertAndValidate(StringRef FullName, const CmdLineOption &Option,
                               AnalyzerOptions &AnOpts,
                               DiagnosticsEngine &Diags) {
 
@@ -509,10 +381,10 @@
 }
 
 template <class T>
-static void
-insertOptionToCollection(StringRef FullName, T &Collection,
-                         const CheckerRegistry::CmdLineOption &Option,
-                         AnalyzerOptions &AnOpts, DiagnosticsEngine &Diags) {
+static void insertOptionToCollection(StringRef FullName, T &Collection,
+                                     const CmdLineOption &Option,
+                                     AnalyzerOptions &AnOpts,
+                                     DiagnosticsEngine &Diags) {
   auto It = binaryFind(Collection, FullName);
   assert(It != Collection.end() &&
          "Failed to find the checker while attempting to add a command line "
@@ -525,20 +397,20 @@
 
 void CheckerRegistry::resolveCheckerAndPackageOptions() {
   for (const std::pair<StringRef, CmdLineOption> &CheckerOptEntry :
-       CheckerOptions) {
-    insertOptionToCollection(CheckerOptEntry.first, Checkers,
+       Data.CheckerOptions) {
+    insertOptionToCollection(CheckerOptEntry.first, Data.Checkers,
                              CheckerOptEntry.second, AnOpts, Diags);
   }
 
   for (const std::pair<StringRef, CmdLineOption> &PackageOptEntry :
-       PackageOptions) {
-    insertOptionToCollection(PackageOptEntry.first, Packages,
+       Data.PackageOptions) {
+    insertOptionToCollection(PackageOptEntry.first, Data.Packages,
                              PackageOptEntry.second, AnOpts, Diags);
   }
 }
 
 void CheckerRegistry::addPackage(StringRef FullName) {
-  Packages.emplace_back(PackageInfo(FullName));
+  Data.Packages.emplace_back(PackageInfo(FullName));
 }
 
 void CheckerRegistry::addPackageOption(StringRef OptionType,
@@ -548,22 +420,22 @@
                                        StringRef Description,
                                        StringRef DevelopmentStatus,
                                        bool IsHidden) {
-  PackageOptions.emplace_back(
+  Data.PackageOptions.emplace_back(
       PackageFullName, CmdLineOption{OptionType, OptionName, DefaultValStr,
                                      Description, DevelopmentStatus, IsHidden});
 }
 
-void CheckerRegistry::addChecker(InitializationFunction Rfn,
+void CheckerRegistry::addChecker(RegisterCheckerFn Rfn,
                                  ShouldRegisterFunction Sfn, StringRef Name,
                                  StringRef Desc, StringRef DocsUri,
                                  bool IsHidden) {
-  Checkers.emplace_back(Rfn, Sfn, Name, Desc, DocsUri, IsHidden);
+  Data.Checkers.emplace_back(Rfn, Sfn, Name, Desc, DocsUri, IsHidden);
 
   // Record the presence of the checker in its packages.
   StringRef PackageName, LeafName;
   std::tie(PackageName, LeafName) = Name.rsplit(PackageSeparator);
   while (!LeafName.empty()) {
-    PackageSizes[PackageName] += 1;
+    Data.PackageSizes[PackageName] += 1;
     std::tie(PackageName, LeafName) = PackageName.rsplit(PackageSeparator);
   }
 }
@@ -575,29 +447,28 @@
                                        StringRef Description,
                                        StringRef DevelopmentStatus,
                                        bool IsHidden) {
-  CheckerOptions.emplace_back(
+  Data.CheckerOptions.emplace_back(
       CheckerFullName, CmdLineOption{OptionType, OptionName, DefaultValStr,
                                      Description, DevelopmentStatus, IsHidden});
 }
 
 void CheckerRegistry::initializeManager(CheckerManager &CheckerMgr) const {
   // Initialize the CheckerManager with all enabled checkers.
-  for (const auto *Checker : EnabledCheckers) {
+  for (const auto *Checker : Data.EnabledCheckers) {
     CheckerMgr.setCurrentCheckerName(CheckerNameRef(Checker->FullName));
     Checker->Initialize(CheckerMgr);
   }
 }
 
-static void
-isOptionContainedIn(const CheckerRegistry::CmdLineOptionList &OptionList,
-                    StringRef SuppliedChecker, StringRef SuppliedOption,
-                    const AnalyzerOptions &AnOpts, DiagnosticsEngine &Diags) {
+static void isOptionContainedIn(const CmdLineOptionList &OptionList,
+                                StringRef SuppliedChecker,
+                                StringRef SuppliedOption,
+                                const AnalyzerOptions &AnOpts,
+                                DiagnosticsEngine &Diags) {
 
   if (!AnOpts.ShouldEmitErrorsOnInvalidConfigValue)
     return;
 
-  using CmdLineOption = CheckerRegistry::CmdLineOption;
-
   auto SameOptName = [SuppliedOption](const CmdLineOption &Opt) {
     return Opt.OptionName == SuppliedOption;
   };
@@ -631,16 +502,16 @@
     // it would return with an iterator to the first checker in the core, so we
     // we really have to use find here, which uses operator==.
     auto CheckerIt =
-        llvm::find(Checkers, CheckerInfo(SuppliedCheckerOrPackage));
-    if (CheckerIt != Checkers.end()) {
+        llvm::find(Data.Checkers, CheckerInfo(SuppliedCheckerOrPackage));
+    if (CheckerIt != Data.Checkers.end()) {
       isOptionContainedIn(CheckerIt->CmdLineOptions, SuppliedCheckerOrPackage,
                           SuppliedOption, AnOpts, Diags);
       continue;
     }
 
     const auto *PackageIt =
-        llvm::find(Packages, PackageInfo(SuppliedCheckerOrPackage));
-    if (PackageIt != Packages.end()) {
+        llvm::find(Data.Packages, PackageInfo(SuppliedCheckerOrPackage));
+    if (PackageIt != Data.Packages.end()) {
       isOptionContainedIn(PackageIt->CmdLineOptions, SuppliedCheckerOrPackage,
                           SuppliedOption, AnOpts, Diags);
       continue;
@@ -651,122 +522,3 @@
   }
 }
 
-//===----------------------------------------------------------------------===//
-// Printing functions.
-//===----------------------------------------------------------------------===//
-
-void CheckerRegistry::printCheckerWithDescList(raw_ostream &Out,
-                                               size_t MaxNameChars) const {
-  // FIXME: Print available packages.
-
-  Out << "CHECKERS:\n";
-
-  // Find the maximum option length.
-  size_t OptionFieldWidth = 0;
-  for (const auto &Checker : Checkers) {
-    // Limit the amount of padding we are willing to give up for alignment.
-    //   Package.Name     Description  [Hidden]
-    size_t NameLength = Checker.FullName.size();
-    if (NameLength <= MaxNameChars)
-      OptionFieldWidth = std::max(OptionFieldWidth, NameLength);
-  }
-
-  const size_t InitialPad = 2;
-
-  auto Print = [=](llvm::raw_ostream &Out, const CheckerInfo &Checker,
-                   StringRef Description) {
-    AnalyzerOptions::printFormattedEntry(Out, {Checker.FullName, Description},
-                                         InitialPad, OptionFieldWidth);
-    Out << '\n';
-  };
-
-  for (const auto &Checker : Checkers) {
-    // The order of this if branches is significant, we wouldn't like to display
-    // developer checkers even in the alpha output. For example,
-    // alpha.cplusplus.IteratorModeling is a modeling checker, hence it's hidden
-    // by default, and users (even when the user is a developer of an alpha
-    // checker) shouldn't normally tinker with whether they should be enabled.
-
-    if (Checker.IsHidden) {
-      if (AnOpts.ShowCheckerHelpDeveloper)
-        Print(Out, Checker, Checker.Desc);
-      continue;
-    }
-
-    if (Checker.FullName.startswith("alpha")) {
-      if (AnOpts.ShowCheckerHelpAlpha)
-        Print(Out, Checker,
-              ("(Enable only for development!) " + Checker.Desc).str());
-      continue;
-    }
-
-    if (AnOpts.ShowCheckerHelp)
-        Print(Out, Checker, Checker.Desc);
-  }
-}
-
-void CheckerRegistry::printEnabledCheckerList(raw_ostream &Out) const {
-  for (const auto *i : EnabledCheckers)
-    Out << i->FullName << '\n';
-}
-
-void CheckerRegistry::printCheckerOptionList(raw_ostream &Out) const {
-  Out << "OVERVIEW: Clang Static Analyzer Checker and Package Option List\n\n";
-  Out << "USAGE: -analyzer-config <OPTION1=VALUE,OPTION2=VALUE,...>\n\n";
-  Out << "       -analyzer-config OPTION1=VALUE, -analyzer-config "
-         "OPTION2=VALUE, ...\n\n";
-  Out << "OPTIONS:\n\n";
-
-  std::multimap<StringRef, const CmdLineOption &> OptionMap;
-
-  for (const CheckerInfo &Checker : Checkers) {
-    for (const CmdLineOption &Option : Checker.CmdLineOptions) {
-      OptionMap.insert({Checker.FullName, Option});
-    }
-  }
-
-  for (const PackageInfo &Package : Packages) {
-    for (const CmdLineOption &Option : Package.CmdLineOptions) {
-      OptionMap.insert({Package.FullName, Option});
-    }
-  }
-
-  auto Print = [] (llvm::raw_ostream &Out, StringRef FullOption, StringRef Desc) {
-    AnalyzerOptions::printFormattedEntry(Out, {FullOption, Desc},
-                                         /*InitialPad*/ 2,
-                                         /*EntryWidth*/ 50,
-                                         /*MinLineWidth*/ 90);
-    Out << "\n\n";
-  };
-  for (const std::pair<const StringRef, const CmdLineOption &> &Entry :
-       OptionMap) {
-    const CmdLineOption &Option = Entry.second;
-    std::string FullOption = (Entry.first + ":" + Option.OptionName).str();
-
-    std::string Desc =
-        ("(" + Option.OptionType + ") " + Option.Description + " (default: " +
-         (Option.DefaultValStr.empty() ? "\"\"" : Option.DefaultValStr) + ")")
-            .str();
-
-    // The list of these if branches is significant, we wouldn't like to
-    // display hidden alpha checker options for
-    // -analyzer-checker-option-help-alpha.
-
-    if (Option.IsHidden) {
-      if (AnOpts.ShowCheckerOptionDeveloperList)
-        Print(Out, FullOption, Desc);
-      continue;
-    }
-
-    if (Option.DevelopmentStatus == "alpha" ||
-        Entry.first.startswith("alpha")) {
-      if (AnOpts.ShowCheckerOptionAlphaList)
-        Print(Out, FullOption,
-              llvm::Twine("(Enable only for development!) " + Desc).str());
-      continue;
-    }
-
-    if (AnOpts.ShowCheckerOptionList)
-      Print(Out, FullOption, Desc);
-  }
-}
diff --git a/clang/lib/StaticAnalyzer/Frontend/CreateCheckerManager.cpp b/clang/lib/StaticAnalyzer/Frontend/CreateCheckerManager.cpp
index 140f807..21a6078 100644
--- a/clang/lib/StaticAnalyzer/Frontend/CreateCheckerManager.cpp
+++ b/clang/lib/StaticAnalyzer/Frontend/CreateCheckerManager.cpp
@@ -23,11 +23,11 @@
     ArrayRef<std::function<void(CheckerRegistry &)>> checkerRegistrationFns)
     : Context(&Context), LangOpts(Context.getLangOpts()), AOptions(AOptions),
       PP(&PP), Diags(Context.getDiagnostics()),
-      Registry(
-          std::make_unique<CheckerRegistry>(plugins, Context.getDiagnostics(),
-                                            AOptions, checkerRegistrationFns)) {
-  Registry->initializeRegistry(*this);
-  Registry->initializeManager(*this);
+      RegistryData(std::make_unique<CheckerRegistryData>()) {
+  CheckerRegistry Registry(*RegistryData, plugins, Context.getDiagnostics(),
+                           AOptions, checkerRegistrationFns);
+  Registry.initializeRegistry(*this);
+  Registry.initializeManager(*this);
   finishedCheckerRegistration();
 }
 
@@ -36,8 +36,9 @@
                                DiagnosticsEngine &Diags,
                                ArrayRef<std::string> plugins)
     : LangOpts(LangOpts), AOptions(AOptions), Diags(Diags),
-      Registry(std::make_unique<CheckerRegistry>(plugins, Diags, AOptions)) {
-  Registry->initializeRegistry(*this);
+      RegistryData(std::make_unique<CheckerRegistryData>()) {
+  CheckerRegistry Registry(*RegistryData, plugins, Diags, AOptions, {});
+  Registry.initializeRegistry(*this);
 }
 
 CheckerManager::~CheckerManager() {
diff --git a/clang/unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp b/clang/unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp
index 30a4efc..c7c7595 100644
--- a/clang/unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp
+++ b/clang/unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp
@@ -11,6 +11,7 @@
 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
 #include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/CheckerRegistryData.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
 #include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"
@@ -100,7 +101,7 @@
     llvm::raw_svector_ostream OS(Buf);
     C.getAnalysisManager()
         .getCheckerManager()
-        ->getCheckerRegistry()
+        ->getCheckerRegistryData()
         .printEnabledCheckerList(OS);
     // Strip a newline off.
     auto R =