dblaikie created this revision.
dblaikie added a reviewer: rsmith.
Herald added subscribers: cfe-commits, klimek.

This goes part-way down the path of moving the actual diagnostics out of 
Clang's Basic library into the respective libraries that use those diagnostics. 
The end goal would be that a client program calling into those libraries would 
be responsible for building the necessary table containing all diagnostics from 
all components they're calling into (so a clang refactoring tool wouldn't need 
to pull in the codegen diagnostics, for example).

But I ran out of momentum a bit & looking for some sanity 
checking/help/encouragement/direction.

The basic idea has been to make the static APIs of DiagnosticIDs non-static, 
then give DiagnosticIDs a ctor that takes the table of diagnostics - as an 
intermediate step, I've left the no-arg ctor in, and dabbled with making it a 
bool ctor just as a way to find the places that still use it and clean them up 
while leaving a handful of correct uses of DiagnosticIDs construction to flesh 
out (build the table from the desired diagnostics, etc) later.

Partly wondering if this is the right general direction, if some of these 
changes are worth committing incrementally as I plumb through DiagnosticIDs 
objects through more APIs.

I remember you, Richard, pointing out that having a generic way to build the 
diagnostics table based on each different clients needs of different subsets of 
all diagnostics wasn't going to be pretty owing to the inability to use the 
preprocessor to conditionally/dynamically #include things in different contexts 
(I'm sure I'm doing a bad job of explaining that - but I'm understanding what 
you meant, that there wouldn't be a quick few lines of "define diagnostics 
table containing these 3 subcomponents" because you'd have to include those 3 
subcomponents diagnostic tables in several different contexts to build up 
several different data structures/subtables/etc... ). & maybe I need to dig 
into that more, look at how that could end up, see if it's reasonable/good 
before doing much more here, rather than putting that off until the end.


Repository:
  rC Clang

https://reviews.llvm.org/D41357

Files:
  include/clang/ARCMigrate/ARCMT.h
  include/clang/Basic/DiagnosticIDs.h
  include/clang/CrossTU/CrossTranslationUnit.h
  include/clang/Frontend/LogDiagnosticPrinter.h
  include/clang/Frontend/SerializedDiagnosticPrinter.h
  include/clang/Frontend/TextDiagnosticPrinter.h
  lib/ARCMigrate/ARCMT.cpp
  lib/ARCMigrate/ARCMTActions.cpp
  lib/ARCMigrate/Internals.h
  lib/ARCMigrate/ObjCMT.cpp
  lib/ARCMigrate/PlistReporter.cpp
  lib/Basic/Diagnostic.cpp
  lib/Basic/DiagnosticIDs.cpp
  lib/Basic/Warnings.cpp
  lib/CrossTU/CrossTranslationUnit.cpp
  lib/Driver/Driver.cpp
  lib/Frontend/ChainedIncludesSource.cpp
  lib/Frontend/CompilerInstance.cpp
  lib/Frontend/LogDiagnosticPrinter.cpp
  lib/Frontend/SerializedDiagnosticPrinter.cpp
  lib/Frontend/TextDiagnosticPrinter.cpp
  lib/Sema/Sema.cpp
  lib/Tooling/CompilationDatabase.cpp
  lib/Tooling/Refactoring.cpp
  lib/Tooling/Tooling.cpp
  tools/arcmt-test/arcmt-test.cpp
  tools/clang-rename/ClangRename.cpp
  tools/diagtool/ListWarnings.cpp
  tools/diagtool/ShowEnabledWarnings.cpp
  tools/driver/cc1_main.cpp
  tools/driver/cc1as_main.cpp
  tools/driver/driver.cpp
  tools/libclang/ARCMigrate.cpp
  tools/libclang/CIndex.cpp
  tools/libclang/CIndexDiagnostic.cpp
  tools/libclang/CXStoredDiagnostic.cpp
  unittests/CrossTU/CrossTranslationUnitTest.cpp
  unittests/Tooling/RewriterTestContext.h

Index: unittests/Tooling/RewriterTestContext.h
===================================================================
--- unittests/Tooling/RewriterTestContext.h
+++ unittests/Tooling/RewriterTestContext.h
@@ -38,16 +38,17 @@
        : DiagOpts(new DiagnosticOptions()),
          Diagnostics(IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
                      &*DiagOpts),
-         DiagnosticPrinter(llvm::outs(), &*DiagOpts),
+         DiagnosticPrinter(llvm::outs(), Diagnostics.getDiagnosticIDs(),
+                           &*DiagOpts),
          InMemoryFileSystem(new vfs::InMemoryFileSystem),
          OverlayFileSystem(
              new vfs::OverlayFileSystem(vfs::getRealFileSystem())),
          Files(FileSystemOptions(), OverlayFileSystem),
          Sources(Diagnostics, Files), Rewrite(Sources, Options) {
-    Diagnostics.setClient(&DiagnosticPrinter, false);
-    // FIXME: To make these tests truly in-memory, we need to overlay the
-    // builtin headers.
-    OverlayFileSystem->pushOverlay(InMemoryFileSystem);
+     Diagnostics.setClient(&DiagnosticPrinter, false);
+     // FIXME: To make these tests truly in-memory, we need to overlay the
+     // builtin headers.
+     OverlayFileSystem->pushOverlay(InMemoryFileSystem);
   }
 
   ~RewriterTestContext() {}
Index: unittests/CrossTU/CrossTranslationUnitTest.cpp
===================================================================
--- unittests/CrossTU/CrossTranslationUnitTest.cpp
+++ unittests/CrossTU/CrossTranslationUnitTest.cpp
@@ -73,7 +73,9 @@
 
     // Load the definition from the AST file.
     llvm::Expected<const FunctionDecl *> NewFDorError =
-        CTU.getCrossTUDefinition(FD, "", IndexFileName);
+        CTU.getCrossTUDefinition(
+            FD, "", IndexFileName,
+            CTU.getCompilerInstance().getDiagnostics().getDiagnosticIDs());
     EXPECT_TRUE((bool)NewFDorError);
     const FunctionDecl *NewFD = *NewFDorError;
 
Index: tools/libclang/CXStoredDiagnostic.cpp
===================================================================
--- tools/libclang/CXStoredDiagnostic.cpp
+++ tools/libclang/CXStoredDiagnostic.cpp
@@ -52,7 +52,7 @@
 
 CXString CXStoredDiagnostic::getDiagnosticOption(CXString *Disable) const {
   unsigned ID = Diag.getID();
-  StringRef Option = DiagnosticIDs::getWarningOptionForDiag(ID);
+  StringRef Option = DiagnosticIDs().getWarningOptionForDiag(ID);
   if (!Option.empty()) {
     if (Disable)
       *Disable = cxstring::createDup((Twine("-Wno-") + Option).str());
@@ -69,12 +69,13 @@
 }
 
 unsigned CXStoredDiagnostic::getCategory() const {
-  return DiagnosticIDs::getCategoryNumberForDiag(Diag.getID());
+  return DiagnosticIDs().getCategoryNumberForDiag(Diag.getID());
 }
 
 CXString CXStoredDiagnostic::getCategoryText() const {
-  unsigned catID = DiagnosticIDs::getCategoryNumberForDiag(Diag.getID());
-  return cxstring::createRef(DiagnosticIDs::getCategoryNameFromID(catID));
+  DiagnosticIDs IDs;
+  unsigned catID = IDs.getCategoryNumberForDiag(Diag.getID());
+  return cxstring::createRef(IDs.getCategoryNameFromID(catID));
 }
 
 unsigned CXStoredDiagnostic::getNumRanges() const {
Index: tools/libclang/CIndexDiagnostic.cpp
===================================================================
--- tools/libclang/CIndexDiagnostic.cpp
+++ tools/libclang/CIndexDiagnostic.cpp
@@ -402,7 +402,7 @@
   
 CXString clang_getDiagnosticCategoryName(unsigned Category) {
   // Kept for backward compatibility.
-  return cxstring::createRef(DiagnosticIDs::getCategoryNameFromID(Category));
+  return cxstring::createRef(DiagnosticIDs().getCategoryNameFromID(Category));
 }
   
 CXString clang_getDiagnosticCategoryText(CXDiagnostic Diag) {
Index: tools/libclang/CIndex.cpp
===================================================================
--- tools/libclang/CIndex.cpp
+++ tools/libclang/CIndex.cpp
@@ -91,8 +91,8 @@
                                      DEnd = AU->stored_diag_end();
        D != DEnd; ++D) {
     if (D->getLevel() >= DiagnosticsEngine::Error &&
-        DiagnosticIDs::getCategoryNumberForDiag(D->getID()) ==
-            diag::DiagCat_AST_Deserialization_Issue)
+        AU->getDiagnostics().getDiagnosticIDs()->getCategoryNumberForDiag(
+            D->getID()) == diag::DiagCat_AST_Deserialization_Issue)
       return true;
   }
   return false;
Index: tools/libclang/ARCMigrate.cpp
===================================================================
--- tools/libclang/ARCMigrate.cpp
+++ tools/libclang/ARCMigrate.cpp
@@ -56,9 +56,11 @@
   }
 
   TextDiagnosticBuffer diagBuffer;
+  IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs = new DiagnosticIDs(true);
   std::unique_ptr<Remap> remap(new Remap());
 
-  bool err = arcmt::getFileRemappings(remap->Vec, migrate_dir_path,&diagBuffer);
+  bool err = arcmt::getFileRemappings(remap->Vec, migrate_dir_path, &diagBuffer,
+                                      DiagIDs);
 
   if (err) {
     if (Logging) {
Index: tools/driver/driver.cpp
===================================================================
--- tools/driver/driver.cpp
+++ tools/driver/driver.cpp
@@ -435,18 +435,18 @@
   IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts =
       CreateAndPopulateDiagOpts(argv);
 
-  TextDiagnosticPrinter *DiagClient
-    = new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
-  FixupDiagPrefixExeName(DiagClient, Path);
-
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
 
+  TextDiagnosticPrinter *DiagClient =
+      new TextDiagnosticPrinter(llvm::errs(), DiagID, &*DiagOpts);
+  FixupDiagPrefixExeName(DiagClient, Path);
+
   DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
 
   if (!DiagOpts->DiagnosticSerializationFile.empty()) {
-    auto SerializedConsumer =
-        clang::serialized_diags::create(DiagOpts->DiagnosticSerializationFile,
-                                        &*DiagOpts, /*MergeChildRecords=*/true);
+    auto SerializedConsumer = clang::serialized_diags::create(
+        DiagOpts->DiagnosticSerializationFile, &*DiagOpts, DiagID,
+        /*MergeChildRecords=*/true);
     Diags.setClient(new ChainedDiagnosticConsumer(
         Diags.takeClient(), std::move(SerializedConsumer)));
   }
Index: tools/driver/cc1as_main.cpp
===================================================================
--- tools/driver/cc1as_main.cpp
+++ tools/driver/cc1as_main.cpp
@@ -485,10 +485,10 @@
 
   // Construct our diagnostic client.
   IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
-  TextDiagnosticPrinter *DiagClient
-    = new TextDiagnosticPrinter(errs(), &*DiagOpts);
-  DiagClient->setPrefix("clang -cc1as");
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+  TextDiagnosticPrinter *DiagClient =
+      new TextDiagnosticPrinter(errs(), DiagID, &*DiagOpts);
+  DiagClient->setPrefix("clang -cc1as");
   DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
 
   // Set an error handler, so that any LLVM backend diagnostics go through our
Index: tools/driver/cc1_main.cpp
===================================================================
--- tools/driver/cc1_main.cpp
+++ tools/driver/cc1_main.cpp
@@ -13,7 +13,7 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "llvm/Option/Arg.h"
+#include "clang/Basic/AllDiagnostics.h"
 #include "clang/CodeGen/ObjectFilePCHContainerOperations.h"
 #include "clang/Config/config.h"
 #include "clang/Driver/DriverDiagnostic.h"
@@ -27,6 +27,7 @@
 #include "clang/FrontendTool/Utils.h"
 #include "llvm/ADT/Statistic.h"
 #include "llvm/LinkAllPasses.h"
+#include "llvm/Option/Arg.h"
 #include "llvm/Option/ArgList.h"
 #include "llvm/Option/OptTable.h"
 #include "llvm/Support/Compiler.h"
@@ -167,11 +168,104 @@
 static void ensureSufficientStack() {}
 #endif
 
+static const DiagnosticIDs::DiagInfoRec StaticDiagInfo[] = {
+#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR,     \
+             SHOWINSYSHEADER, CATEGORY)                                        \
+  {diag::ENUM,                                                                 \
+   DEFAULT_SEVERITY,                                                           \
+   DiagnosticIDs::CLASS,                                                       \
+   DiagnosticIDs::SFINAE,                                                      \
+   NOWERROR,                                                                   \
+   SHOWINSYSHEADER,                                                            \
+   CATEGORY,                                                                   \
+   GROUP,                                                                      \
+   STR_SIZE(DESC, uint16_t),                                                   \
+   DESC},
+#include "clang/Basic/DiagnosticCommonKinds.inc"
+
+#include "clang/Basic/DiagnosticDriverKinds.inc"
+
+#include "clang/Basic/DiagnosticFrontendKinds.inc"
+
+#include "clang/Basic/DiagnosticSerializationKinds.inc"
+
+#include "clang/Basic/DiagnosticLexKinds.inc"
+
+#include "clang/Basic/DiagnosticParseKinds.inc"
+
+#include "clang/Basic/DiagnosticASTKinds.inc"
+
+#include "clang/Basic/DiagnosticCommentKinds.inc"
+
+#include "clang/Basic/DiagnosticCrossTUKinds.inc"
+
+#include "clang/Basic/DiagnosticSemaKinds.inc"
+
+#include "clang/Basic/DiagnosticAnalysisKinds.inc"
+
+#include "clang/Basic/DiagnosticRefactoringKinds.inc"
+#undef DIAG
+};
+
+/// GetDiagInfo - Return the StaticDiagInfoRec entry for the specified DiagID,
+/// or null if the ID is invalid.
+static const DiagnosticIDs::DiagInfoRec *GetDiagInfo(unsigned DiagID) {
+  // Out of bounds diag. Can't be in the table.
+  using namespace diag;
+  if (DiagID >= DIAG_UPPER_LIMIT || DiagID <= DIAG_START_COMMON)
+    return nullptr;
+
+  // Compute the index of the requested diagnostic in the static table.
+  // 1. Add the number of diagnostics in each category preceding the
+  //    diagnostic and of the category the diagnostic is in. This gives us
+  //    the offset of the category in the table.
+  // 2. Subtract the number of IDs in each category from our ID. This gives us
+  //    the offset of the diagnostic in the category.
+  // This is cheaper than a binary search on the table as it doesn't touch
+  // memory at all.
+  unsigned Offset = 0;
+  unsigned ID = DiagID - DIAG_START_COMMON - 1;
+#define CATEGORY(NAME, PREV)                                                   \
+  if (DiagID > DIAG_START_##NAME) {                                            \
+    Offset += NUM_BUILTIN_##PREV##_DIAGNOSTICS - DIAG_START_##PREV - 1;        \
+    ID -= DIAG_START_##NAME - DIAG_START_##PREV;                               \
+  }
+  CATEGORY(DRIVER, COMMON)
+  CATEGORY(FRONTEND, DRIVER)
+  CATEGORY(SERIALIZATION, FRONTEND)
+  CATEGORY(LEX, SERIALIZATION)
+  CATEGORY(PARSE, LEX)
+  CATEGORY(AST, PARSE)
+  CATEGORY(COMMENT, AST)
+  CATEGORY(CROSSTU, COMMENT)
+  CATEGORY(SEMA, CROSSTU)
+  CATEGORY(ANALYSIS, SEMA)
+  CATEGORY(REFACTORING, ANALYSIS)
+#undef CATEGORY
+
+  auto DiagInfoArr = llvm::makeArrayRef(StaticDiagInfo);
+
+  // Avoid out of bounds reads.
+  if (ID + Offset >= DiagInfoArr.size())
+    return nullptr;
+
+  assert(ID < DiagInfoArr.size() && Offset < DiagInfoArr.size());
+
+  const auto *Found = &DiagInfoArr[ID + Offset];
+  // If the diag id doesn't match we found a different diag, abort. This can
+  // happen when this function is called with an ID that points into a hole in
+  // the diagID space.
+  if (Found->DiagID != DiagID)
+    return nullptr;
+  return Found;
+}
+
 int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
   ensureSufficientStack();
 
   std::unique_ptr<CompilerInstance> Clang(new CompilerInstance());
-  IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+  IntrusiveRefCntPtr<DiagnosticIDs> DiagID =
+      new DiagnosticIDs(StaticDiagInfo, &GetDiagInfo);
 
   // Register the support for object-file-wrapped Clang modules.
   auto PCHOps = Clang->getPCHContainerOperations();
Index: tools/diagtool/ShowEnabledWarnings.cpp
===================================================================
--- tools/diagtool/ShowEnabledWarnings.cpp
+++ tools/diagtool/ShowEnabledWarnings.cpp
@@ -54,9 +54,8 @@
 }
 
 static IntrusiveRefCntPtr<DiagnosticsEngine>
-createDiagnostics(unsigned int argc, char **argv) {
-  IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(new DiagnosticIDs());
-
+createDiagnostics(unsigned int argc, char **argv,
+                  IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs) {
   // Buffer diagnostics from argument parsing so that we can output them using a
   // well formed diagnostic object.
   TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;
@@ -101,8 +100,11 @@
     }
   }
 
+  IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(new DiagnosticIDs());
+
   // Create the diagnostic engine.
-  IntrusiveRefCntPtr<DiagnosticsEngine> Diags = createDiagnostics(argc, argv);
+  IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
+      createDiagnostics(argc, argv, DiagIDs);
   if (!Diags) {
     printUsage();
     return EXIT_FAILURE;
@@ -117,18 +119,18 @@
   for (const DiagnosticRecord &DR : getBuiltinDiagnosticsByName()) {
     unsigned DiagID = DR.DiagID;
 
-    if (DiagnosticIDs::isBuiltinNote(DiagID))
+    if (DiagIDs->isBuiltinNote(DiagID))
       continue;
 
-    if (!DiagnosticIDs::isBuiltinWarningOrExtension(DiagID))
+    if (!DiagIDs->isBuiltinWarningOrExtension(DiagID))
       continue;
 
     DiagnosticsEngine::Level DiagLevel =
       Diags->getDiagnosticLevel(DiagID, SourceLocation());
     if (DiagLevel == DiagnosticsEngine::Ignored)
       continue;
 
-    StringRef WarningOpt = DiagnosticIDs::getWarningOptionForDiag(DiagID);
+    StringRef WarningOpt = DiagIDs->getWarningOptionForDiag(DiagID);
     Active.push_back(PrettyDiag(DR.getName(), WarningOpt, DiagLevel));
   }
 
Index: tools/diagtool/ListWarnings.cpp
===================================================================
--- tools/diagtool/ListWarnings.cpp
+++ tools/diagtool/ListWarnings.cpp
@@ -52,16 +52,18 @@
   std::vector<Entry> Flagged, Unflagged;
   llvm::StringMap<std::vector<unsigned> > flagHistogram;
 
+  DiagnosticIDs IDs;
+
   for (const DiagnosticRecord &DR : getBuiltinDiagnosticsByName()) {
     const unsigned diagID = DR.DiagID;
 
-    if (DiagnosticIDs::isBuiltinNote(diagID))
+    if (IDs.isBuiltinNote(diagID))
       continue;
 
-    if (!DiagnosticIDs::isBuiltinWarningOrExtension(diagID))
+    if (!IDs.isBuiltinWarningOrExtension(diagID))
       continue;
 
-    Entry entry(DR.getName(), DiagnosticIDs::getWarningOptionForDiag(diagID));
+    Entry entry(DR.getName(), IDs.getWarningOptionForDiag(diagID));
 
     if (entry.Flag.empty())
       Unflagged.push_back(entry);
Index: tools/clang-rename/ClangRename.cpp
===================================================================
--- tools/clang-rename/ClangRename.cpp
+++ tools/clang-rename/ClangRename.cpp
@@ -213,10 +213,10 @@
     // in the same order we see them.
     LangOptions DefaultLangOptions;
     IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
-    TextDiagnosticPrinter DiagnosticPrinter(errs(), &*DiagOpts);
-    DiagnosticsEngine Diagnostics(
-        IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts,
-        &DiagnosticPrinter, false);
+    IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(new DiagnosticIDs());
+    TextDiagnosticPrinter DiagnosticPrinter(errs(), DiagIDs, &*DiagOpts);
+    DiagnosticsEngine Diagnostics(std::move(DiagIDs), &*DiagOpts,
+                                  &DiagnosticPrinter, false);
     auto &FileMgr = Tool.getFiles();
     SourceManager Sources(Diagnostics, FileMgr);
     Rewriter Rewrite(Sources, DefaultLangOptions);
Index: tools/arcmt-test/arcmt-test.cpp
===================================================================
--- tools/arcmt-test/arcmt-test.cpp
+++ tools/arcmt-test/arcmt-test.cpp
@@ -109,9 +109,9 @@
 static bool checkForMigration(StringRef resourcesPath,
                               ArrayRef<const char *> Args) {
   IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
-  DiagnosticConsumer *DiagClient =
-    new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+  DiagnosticConsumer *DiagClient =
+      new TextDiagnosticPrinter(llvm::errs(), DiagID, &*DiagOpts);
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
       new DiagnosticsEngine(DiagID, &*DiagOpts, DiagClient));
   // Chain in -verify checker, if requested.
@@ -135,7 +135,7 @@
 
   arcmt::checkForManualIssues(CI, CI.getFrontendOpts().Inputs[0],
                               std::make_shared<PCHContainerOperations>(),
-                              Diags->getClient());
+                              *Diags);
   return Diags->getClient()->getNumErrors() > 0;
 }
 
@@ -154,9 +154,9 @@
     return true;
 
   IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
-  DiagnosticConsumer *DiagClient =
-    new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+  DiagnosticConsumer *DiagClient =
+      new TextDiagnosticPrinter(llvm::errs(), DiagID, &*DiagOpts);
   IntrusiveRefCntPtr<DiagnosticsEngine> TopDiags(
       new DiagnosticsEngine(DiagID, &*DiagOpts, &*DiagClient));
 
@@ -174,7 +174,7 @@
     return false;
 
   MigrationProcess migration(origCI, std::make_shared<PCHContainerOperations>(),
-                             DiagClient);
+                             *TopDiags);
 
   std::vector<TransformFn>
     transforms = arcmt::getAllTransformations(origCI.getLangOpts()->getGC(),
Index: lib/Tooling/Tooling.cpp
===================================================================
--- lib/Tooling/Tooling.cpp
+++ lib/Tooling/Tooling.cpp
@@ -251,10 +251,10 @@
   llvm::opt::InputArgList ParsedArgs = Opts->ParseArgs(
       ArrayRef<const char *>(Argv).slice(1), MissingArgIndex, MissingArgCount);
   ParseDiagnosticArgs(*DiagOpts, ParsedArgs);
-  TextDiagnosticPrinter DiagnosticPrinter(
-      llvm::errs(), &*DiagOpts);
+  IntrusiveRefCntPtr<clang::DiagnosticIDs> DiagIDs(new DiagnosticIDs());
+  TextDiagnosticPrinter DiagnosticPrinter(llvm::errs(), DiagIDs, &*DiagOpts);
   DiagnosticsEngine Diagnostics(
-      IntrusiveRefCntPtr<clang::DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts,
+      std::move(DiagIDs), &*DiagOpts,
       DiagConsumer ? DiagConsumer : &DiagnosticPrinter, false);
 
   const std::unique_ptr<clang::driver::Driver> Driver(
Index: lib/Tooling/Refactoring.cpp
===================================================================
--- lib/Tooling/Refactoring.cpp
+++ lib/Tooling/Refactoring.cpp
@@ -41,10 +41,10 @@
 
   LangOptions DefaultLangOptions;
   IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
-  TextDiagnosticPrinter DiagnosticPrinter(llvm::errs(), &*DiagOpts);
-  DiagnosticsEngine Diagnostics(
-      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()),
-      &*DiagOpts, &DiagnosticPrinter, false);
+  IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(new DiagnosticIDs());
+  TextDiagnosticPrinter DiagnosticPrinter(llvm::errs(), DiagIDs, &*DiagOpts);
+  DiagnosticsEngine Diagnostics(std::move(DiagIDs), &*DiagOpts,
+                                &DiagnosticPrinter, false);
   SourceManager Sources(Diagnostics, getFiles());
   Rewriter Rewrite(Sources, DefaultLangOptions);
 
Index: lib/Tooling/CompilationDatabase.cpp
===================================================================
--- lib/Tooling/CompilationDatabase.cpp
+++ lib/Tooling/CompilationDatabase.cpp
@@ -221,11 +221,11 @@
                                 std::string &ErrorMsg) {
   IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
   llvm::raw_string_ostream Output(ErrorMsg);
-  TextDiagnosticPrinter DiagnosticPrinter(Output, &*DiagOpts);
+  IntrusiveRefCntPtr<clang::DiagnosticIDs> DiagIDs(new DiagnosticIDs());
+  TextDiagnosticPrinter DiagnosticPrinter(Output, DiagIDs, &*DiagOpts);
   UnusedInputDiagConsumer DiagClient(DiagnosticPrinter);
-  DiagnosticsEngine Diagnostics(
-      IntrusiveRefCntPtr<clang::DiagnosticIDs>(new DiagnosticIDs()),
-      &*DiagOpts, &DiagClient, false);
+  DiagnosticsEngine Diagnostics(std::move(DiagIDs), &*DiagOpts, &DiagClient,
+                                false);
 
   // The clang executable path isn't required since the jobs the driver builds
   // will not be executed.
Index: lib/Sema/Sema.cpp
===================================================================
--- lib/Sema/Sema.cpp
+++ lib/Sema/Sema.cpp
@@ -1191,8 +1191,8 @@
   // issue I am not seeing yet), then there should at least be a clarifying
   // comment somewhere.
   if (Optional<TemplateDeductionInfo*> Info = isSFINAEContext()) {
-    switch (DiagnosticIDs::getDiagnosticSFINAEResponse(
-              Diags.getCurrentDiagID())) {
+    switch (Diags.getDiagnosticIDs()->getDiagnosticSFINAEResponse(
+        Diags.getCurrentDiagID())) {
     case DiagnosticIDs::SFINAE_Report:
       // We'll report the diagnostic below.
       break;
@@ -1275,7 +1275,7 @@
   // that is different from the last template instantiation where
   // we emitted an error, print a template instantiation
   // backtrace.
-  if (!DiagnosticIDs::isBuiltinNote(DiagID))
+  if (!Diags.getDiagnosticIDs()->isBuiltinNote(DiagID))
     PrintContextStack();
 }
 
Index: lib/Frontend/TextDiagnosticPrinter.cpp
===================================================================
--- lib/Frontend/TextDiagnosticPrinter.cpp
+++ lib/Frontend/TextDiagnosticPrinter.cpp
@@ -22,12 +22,11 @@
 #include <algorithm>
 using namespace clang;
 
-TextDiagnosticPrinter::TextDiagnosticPrinter(raw_ostream &os,
-                                             DiagnosticOptions *diags,
-                                             bool _OwnsOutputStream)
-  : OS(os), DiagOpts(diags),
-    OwnsOutputStream(_OwnsOutputStream) {
-}
+TextDiagnosticPrinter::TextDiagnosticPrinter(
+    raw_ostream &os, IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs,
+    DiagnosticOptions *diags, bool _OwnsOutputStream)
+    : OS(os), DiagIDs(std::move(DiagIDs)), DiagOpts(diags),
+      OwnsOutputStream(_OwnsOutputStream) {}
 
 TextDiagnosticPrinter::~TextDiagnosticPrinter() {
   if (OwnsOutputStream)
@@ -52,7 +51,8 @@
 static void printDiagnosticOptions(raw_ostream &OS,
                                    DiagnosticsEngine::Level Level,
                                    const Diagnostic &Info,
-                                   const DiagnosticOptions &DiagOpts) {
+                                   const DiagnosticOptions &DiagOpts,
+                                   const DiagnosticIDs &DiagIDs) {
   bool Started = false;
   if (DiagOpts.ShowOptionNames) {
     // Handle special cases for non-warnings early.
@@ -71,13 +71,13 @@
     // flag it as such. Note that diagnostics could also have been mapped by a
     // pragma, but we don't currently have a way to distinguish this.
     if (Level == DiagnosticsEngine::Error &&
-        DiagnosticIDs::isBuiltinWarningOrExtension(Info.getID()) &&
-        !DiagnosticIDs::isDefaultMappingAsError(Info.getID())) {
+        DiagIDs.isBuiltinWarningOrExtension(Info.getID()) &&
+        !DiagIDs.isDefaultMappingAsError(Info.getID())) {
       OS << " [-Werror";
       Started = true;
     }
 
-    StringRef Opt = DiagnosticIDs::getWarningOptionForDiag(Info.getID());
+    StringRef Opt = DiagIDs.getWarningOptionForDiag(Info.getID());
     if (!Opt.empty()) {
       OS << (Started ? "," : " [")
          << (Level == DiagnosticsEngine::Remark ? "-R" : "-W") << Opt;
@@ -90,16 +90,15 @@
 
   // If the user wants to see category information, include it too.
   if (DiagOpts.ShowCategories) {
-    unsigned DiagCategory =
-      DiagnosticIDs::getCategoryNumberForDiag(Info.getID());
+    unsigned DiagCategory = DiagIDs.getCategoryNumberForDiag(Info.getID());
     if (DiagCategory) {
       OS << (Started ? "," : " [");
       Started = true;
       if (DiagOpts.ShowCategories == 1)
         OS << DiagCategory;
       else {
         assert(DiagOpts.ShowCategories == 2 && "Invalid ShowCategories value");
-        OS << DiagnosticIDs::getCategoryNameFromID(DiagCategory);
+        OS << DiagIDs.getCategoryNameFromID(DiagCategory);
       }
     }
   }
@@ -118,7 +117,7 @@
   Info.FormatDiagnostic(OutStr);
 
   llvm::raw_svector_ostream DiagMessageStream(OutStr);
-  printDiagnosticOptions(DiagMessageStream, Level, Info, *DiagOpts);
+  printDiagnosticOptions(DiagMessageStream, Level, Info, *DiagOpts, *DiagIDs);
 
   // Keeps track of the starting position of the location
   // information (e.g., "foo.c:10:4:") that precedes the error
Index: lib/Frontend/SerializedDiagnosticPrinter.cpp
===================================================================
--- lib/Frontend/SerializedDiagnosticPrinter.cpp
+++ lib/Frontend/SerializedDiagnosticPrinter.cpp
@@ -141,10 +141,12 @@
         State(std::move(State)) {}
 
 public:
-  SDiagsWriter(StringRef File, DiagnosticOptions *Diags, bool MergeChildRecords)
+  SDiagsWriter(StringRef File, DiagnosticOptions *Diags,
+               IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs,
+               bool MergeChildRecords)
       : LangOpts(nullptr), OriginalInstance(true),
         MergeChildRecords(MergeChildRecords),
-        State(std::make_shared<SharedState>(File, Diags)) {
+        State(std::make_shared<SharedState>(File, Diags, std::move(DiagIDs))) {
     if (MergeChildRecords)
       RemoveOldDiagnostics();
     EmitPreamble();
@@ -240,12 +242,14 @@
   /// \brief State that is shared among the various clones of this diagnostic
   /// consumer.
   struct SharedState {
-    SharedState(StringRef File, DiagnosticOptions *Diags)
-        : DiagOpts(Diags), Stream(Buffer), OutputFile(File.str()),
-          EmittedAnyDiagBlocks(false) {}
+    SharedState(StringRef File, DiagnosticOptions *Diags,
+                IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs)
+        : DiagOpts(Diags), DiagIDs(std::move(DiagIDs)), Stream(Buffer),
+          OutputFile(File.str()), EmittedAnyDiagBlocks(false) {}
 
     /// \brief Diagnostic options.
     IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
+    IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs;
 
     /// \brief The byte buffer for the serialized content.
     SmallString<1024> Buffer;
@@ -294,8 +298,10 @@
 namespace clang {
 namespace serialized_diags {
 std::unique_ptr<DiagnosticConsumer>
-create(StringRef OutputFile, DiagnosticOptions *Diags, bool MergeChildRecords) {
-  return llvm::make_unique<SDiagsWriter>(OutputFile, Diags, MergeChildRecords);
+create(StringRef OutputFile, DiagnosticOptions *Diags,
+       IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs, bool MergeChildRecords) {
+  return llvm::make_unique<SDiagsWriter>(OutputFile, Diags, std::move(DiagIDs),
+                                         MergeChildRecords);
 }
 
 } // end namespace serialized_diags
@@ -525,7 +531,7 @@
 
   // We use a local version of 'Record' so that we can be generating
   // another record when we lazily generate one for the category entry.
-  StringRef catName = DiagnosticIDs::getCategoryNameFromID(category);
+  StringRef catName = State->DiagIDs->getCategoryNameFromID(category);
   RecordData::value_type Record[] = {RECORD_CATEGORY, category, catName.size()};
   State->Stream.EmitRecordWithBlob(State->Abbrevs.get(RECORD_CATEGORY), Record,
                                    catName);
@@ -537,8 +543,8 @@
                                              unsigned DiagID) {
   if (DiagLevel == DiagnosticsEngine::Note)
     return 0; // No flag for notes.
-  
-  StringRef FlagName = DiagnosticIDs::getWarningOptionForDiag(DiagID);
+
+  StringRef FlagName = State->DiagIDs->getWarningOptionForDiag(DiagID);
   return getEmitDiagnosticFlag(FlagName);
 }
 
@@ -639,7 +645,7 @@
 
   if (const Diagnostic *Info = D.dyn_cast<const Diagnostic*>()) {
     // Emit the category string lazily and get the category ID.
-    unsigned DiagID = DiagnosticIDs::getCategoryNumberForDiag(Info->getID());
+    unsigned DiagID = State->DiagIDs->getCategoryNumberForDiag(Info->getID());
     Record.push_back(getEmitCategory(DiagID));
     // Emit the diagnostic flag string lazily and get the mapped ID.
     Record.push_back(getEmitDiagnosticFlag(Level, Info->getID()));
@@ -741,7 +747,7 @@
   if (!State->MetaDiagnostics) {
     IntrusiveRefCntPtr<DiagnosticIDs> IDs(new DiagnosticIDs());
     auto Client =
-        new TextDiagnosticPrinter(llvm::errs(), State->DiagOpts.get());
+        new TextDiagnosticPrinter(llvm::errs(), IDs, State->DiagOpts.get());
     State->MetaDiagnostics = llvm::make_unique<DiagnosticsEngine>(
         IDs, State->DiagOpts.get(), Client);
   }
Index: lib/Frontend/LogDiagnosticPrinter.cpp
===================================================================
--- lib/Frontend/LogDiagnosticPrinter.cpp
+++ lib/Frontend/LogDiagnosticPrinter.cpp
@@ -19,10 +19,10 @@
 using namespace markup;
 
 LogDiagnosticPrinter::LogDiagnosticPrinter(
-    raw_ostream &os, DiagnosticOptions *diags,
-    std::unique_ptr<raw_ostream> StreamOwner)
+    raw_ostream &os, IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs,
+    DiagnosticOptions *diags, std::unique_ptr<raw_ostream> StreamOwner)
     : OS(os), StreamOwner(std::move(StreamOwner)), LangOpts(nullptr),
-      DiagOpts(diags) {}
+      DiagIDs(std::move(DiagIDs)), DiagOpts(diags) {}
 
 static StringRef getLevelName(DiagnosticsEngine::Level Level) {
   switch (Level) {
@@ -130,7 +130,7 @@
   DE.DiagnosticID = Info.getID();
   DE.DiagnosticLevel = Level;
 
-  DE.WarningOption = DiagnosticIDs::getWarningOptionForDiag(DE.DiagnosticID);
+  DE.WarningOption = DiagIDs->getWarningOptionForDiag(DE.DiagnosticID);
 
   // Format the message.
   SmallString<100> MessageStr;
Index: lib/Frontend/CompilerInstance.cpp
===================================================================
--- lib/Frontend/CompilerInstance.cpp
+++ lib/Frontend/CompilerInstance.cpp
@@ -234,8 +234,8 @@
   }
 
   // Chain in the diagnostic client which will log the diagnostics.
-  auto Logger = llvm::make_unique<LogDiagnosticPrinter>(*OS, DiagOpts,
-                                                        std::move(StreamOwner));
+  auto Logger = llvm::make_unique<LogDiagnosticPrinter>(
+      *OS, Diags.getDiagnosticIDs(), DiagOpts, std::move(StreamOwner));
   if (CodeGenOpts)
     Logger->setDwarfDebugFlags(CodeGenOpts->DwarfDebugFlags);
   assert(Diags.ownsClient());
@@ -246,8 +246,8 @@
 static void SetupSerializedDiagnostics(DiagnosticOptions *DiagOpts,
                                        DiagnosticsEngine &Diags,
                                        StringRef OutputFile) {
-  auto SerializedConsumer =
-      clang::serialized_diags::create(OutputFile, DiagOpts);
+  auto SerializedConsumer = clang::serialized_diags::create(
+      OutputFile, DiagOpts, Diags.getDiagnosticIDs());
 
   if (Diags.ownsClient()) {
     Diags.setClient(new ChainedDiagnosticConsumer(
@@ -278,7 +278,7 @@
   if (Client) {
     Diags->setClient(Client, ShouldOwnClient);
   } else
-    Diags->setClient(new TextDiagnosticPrinter(llvm::errs(), Opts));
+    Diags->setClient(new TextDiagnosticPrinter(llvm::errs(), DiagID, Opts));
 
   // Chain in -verify checker, if requested.
   if (Opts->VerifyDiagnostics)
Index: lib/Frontend/ChainedIncludesSource.cpp
===================================================================
--- lib/Frontend/ChainedIncludesSource.cpp
+++ lib/Frontend/ChainedIncludesSource.cpp
@@ -139,9 +139,9 @@
     FrontendInputFile InputFile(includes[i], IK);
     CInvok->getFrontendOpts().Inputs.push_back(InputFile);
 
-    TextDiagnosticPrinter *DiagClient =
-      new TextDiagnosticPrinter(llvm::errs(), new DiagnosticOptions());
     IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+    TextDiagnosticPrinter *DiagClient = new TextDiagnosticPrinter(
+        llvm::errs(), DiagID, new DiagnosticOptions());
     IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
         new DiagnosticsEngine(DiagID, &CI.getDiagnosticOpts(), DiagClient));
 
Index: lib/Driver/Driver.cpp
===================================================================
--- lib/Driver/Driver.cpp
+++ lib/Driver/Driver.cpp
@@ -1148,11 +1148,11 @@
 
 /// PrintDiagnosticCategories - Implement the --print-diagnostic-categories
 /// option.
-static void PrintDiagnosticCategories(raw_ostream &OS) {
+static void PrintDiagnosticCategories(const DiagnosticIDs &IDs,
+                                      raw_ostream &OS) {
   // Skip the empty category.
-  for (unsigned i = 1, max = DiagnosticIDs::getNumberOfCategories(); i != max;
-       ++i)
-    OS << i << ',' << DiagnosticIDs::getCategoryNameFromID(i) << '\n';
+  for (unsigned i = 1, max = IDs.getNumberOfCategories(); i != max; ++i)
+    OS << i << ',' << IDs.getCategoryNameFromID(i) << '\n';
 }
 
 void Driver::handleAutocompletions(StringRef PassedFlags) const {
@@ -1180,7 +1180,7 @@
     // We have to query the -W flags manually as they're not in the OptTable.
     // TODO: Find a good way to add them to OptTable instead and them remove
     // this code.
-    for (StringRef S : DiagnosticIDs::getDiagnosticFlags())
+    for (StringRef S : Diags.getDiagnosticIDs()->getDiagnosticFlags())
       if (S.startswith(PassedFlags))
         SuggestedCompletions.push_back(S);
   } else {
@@ -1228,7 +1228,7 @@
   }
 
   if (C.getArgs().hasArg(options::OPT__print_diagnostic_categories)) {
-    PrintDiagnosticCategories(llvm::outs());
+    PrintDiagnosticCategories(*Diags.getDiagnosticIDs(), llvm::outs());
     return false;
   }
 
Index: lib/CrossTU/CrossTranslationUnit.cpp
===================================================================
--- lib/CrossTU/CrossTranslationUnit.cpp
+++ lib/CrossTU/CrossTranslationUnit.cpp
@@ -147,16 +147,16 @@
 }
 
 llvm::Expected<const FunctionDecl *>
-CrossTranslationUnitContext::getCrossTUDefinition(const FunctionDecl *FD,
-                                                  StringRef CrossTUDir,
-                                                  StringRef IndexName) {
+CrossTranslationUnitContext::getCrossTUDefinition(
+    const FunctionDecl *FD, StringRef CrossTUDir, StringRef IndexName,
+    const IntrusiveRefCntPtr<DiagnosticIDs> &DiagIDs) {
   assert(!FD->hasBody() && "FD has a definition in current translation unit!");
   const std::string LookupFnName = getLookupName(FD);
   if (LookupFnName.empty())
     return llvm::make_error<IndexError>(
         index_error_code::failed_to_generate_usr);
   llvm::Expected<ASTUnit *> ASTUnitOrError =
-      loadExternalAST(LookupFnName, CrossTUDir, IndexName);
+      loadExternalAST(LookupFnName, CrossTUDir, IndexName, DiagIDs);
   if (!ASTUnitOrError)
     return ASTUnitOrError.takeError();
   ASTUnit *Unit = *ASTUnitOrError;
@@ -193,7 +193,8 @@
 }
 
 llvm::Expected<ASTUnit *> CrossTranslationUnitContext::loadExternalAST(
-    StringRef LookupName, StringRef CrossTUDir, StringRef IndexName) {
+    StringRef LookupName, StringRef CrossTUDir, StringRef IndexName,
+    const IntrusiveRefCntPtr<DiagnosticIDs> &DiagIDs) {
   // FIXME: The current implementation only supports loading functions with
   //        a lookup name from a single translation unit. If multiple
   //        translation units contains functions with the same lookup name an
@@ -223,10 +224,9 @@
     if (ASTCacheEntry == FileASTUnitMap.end()) {
       IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
       TextDiagnosticPrinter *DiagClient =
-          new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
-      IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+          new TextDiagnosticPrinter(llvm::errs(), DiagIDs, &*DiagOpts);
       IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
-          new DiagnosticsEngine(DiagID, &*DiagOpts, DiagClient));
+          new DiagnosticsEngine(DiagIDs, &*DiagOpts, DiagClient));
 
       std::unique_ptr<ASTUnit> LoadedUnit(ASTUnit::LoadFromASTFile(
           ASTFileName, CI.getPCHContainerOperations()->getRawReader(),
Index: lib/Basic/Warnings.cpp
===================================================================
--- lib/Basic/Warnings.cpp
+++ lib/Basic/Warnings.cpp
@@ -35,7 +35,8 @@
 static void EmitUnknownDiagWarning(DiagnosticsEngine &Diags,
                                    diag::Flavor Flavor, StringRef Prefix,
                                    StringRef Opt) {
-  StringRef Suggestion = DiagnosticIDs::getNearestOption(Flavor, Opt);
+  StringRef Suggestion =
+      Diags.getDiagnosticIDs()->getNearestOption(Flavor, Opt);
   Diags.Report(diag::warn_unknown_diag_option)
     << (Flavor == diag::Flavor::WarningOrError ? 0 : 1) << (Prefix.str() += Opt)
     << !Suggestion.empty() << (Prefix.str() += Suggestion);
Index: lib/Basic/DiagnosticIDs.cpp
===================================================================
--- lib/Basic/DiagnosticIDs.cpp
+++ lib/Basic/DiagnosticIDs.cpp
@@ -25,83 +25,19 @@
 // Builtin Diagnostic information
 //===----------------------------------------------------------------------===//
 
-namespace {
-
-// Diagnostic classes.
-enum {
-  CLASS_NOTE       = 0x01,
-  CLASS_REMARK     = 0x02,
-  CLASS_WARNING    = 0x03,
-  CLASS_EXTENSION  = 0x04,
-  CLASS_ERROR      = 0x05
-};
-
-struct StaticDiagInfoRec {
-  uint16_t DiagID;
-  unsigned DefaultSeverity : 3;
-  unsigned Class : 3;
-  unsigned SFINAE : 2;
-  unsigned WarnNoWerror : 1;
-  unsigned WarnShowInSystemHeader : 1;
-  unsigned Category : 6;
-
-  uint16_t OptionGroupIndex;
-
-  uint16_t DescriptionLen;
-  const char *DescriptionStr;
-
-  unsigned getOptionGroupIndex() const {
-    return OptionGroupIndex;
-  }
-
-  StringRef getDescription() const {
-    return StringRef(DescriptionStr, DescriptionLen);
-  }
-
-  diag::Flavor getFlavor() const {
-    return Class == CLASS_REMARK ? diag::Flavor::Remark
-                                 : diag::Flavor::WarningOrError;
-  }
-
-  bool operator<(const StaticDiagInfoRec &RHS) const {
-    return DiagID < RHS.DiagID;
-  }
-};
-
-#define STRINGIFY_NAME(NAME) #NAME
-#define VALIDATE_DIAG_SIZE(NAME)                                               \
-  static_assert(                                                               \
-      static_cast<unsigned>(diag::NUM_BUILTIN_##NAME##_DIAGNOSTICS) <          \
-          static_cast<unsigned>(diag::DIAG_START_##NAME) +                     \
-              static_cast<unsigned>(diag::DIAG_SIZE_##NAME),                   \
-      STRINGIFY_NAME(                                                          \
-          DIAG_SIZE_##NAME) " is insufficient to contain all "                 \
-                            "diagnostics, it may need to be made larger in "   \
-                            "DiagnosticIDs.h.");
-VALIDATE_DIAG_SIZE(COMMON)
-VALIDATE_DIAG_SIZE(DRIVER)
-VALIDATE_DIAG_SIZE(FRONTEND)
-VALIDATE_DIAG_SIZE(SERIALIZATION)
-VALIDATE_DIAG_SIZE(LEX)
-VALIDATE_DIAG_SIZE(PARSE)
-VALIDATE_DIAG_SIZE(AST)
-VALIDATE_DIAG_SIZE(COMMENT)
-VALIDATE_DIAG_SIZE(SEMA)
-VALIDATE_DIAG_SIZE(ANALYSIS)
-VALIDATE_DIAG_SIZE(REFACTORING)
-#undef VALIDATE_DIAG_SIZE
-#undef STRINGIFY_NAME
-
-} // namespace anonymous
-
-static const StaticDiagInfoRec StaticDiagInfo[] = {
+static const DiagnosticIDs::DiagInfoRec StaticDiagInfo[] = {
 #define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR,     \
              SHOWINSYSHEADER, CATEGORY)                                        \
-  {                                                                            \
-    diag::ENUM, DEFAULT_SEVERITY, CLASS, DiagnosticIDs::SFINAE, NOWERROR,      \
-        SHOWINSYSHEADER, CATEGORY, GROUP, STR_SIZE(DESC, uint16_t), DESC       \
-  }                                                                            \
-  ,
+  {diag::ENUM,                                                                 \
+   DEFAULT_SEVERITY,                                                           \
+   DiagnosticIDs::CLASS,                                                       \
+   DiagnosticIDs::SFINAE,                                                      \
+   NOWERROR,                                                                   \
+   SHOWINSYSHEADER,                                                            \
+   CATEGORY,                                                                   \
+   GROUP,                                                                      \
+   STR_SIZE(DESC, uint16_t),                                                   \
+   DESC},
 #include "clang/Basic/DiagnosticCommonKinds.inc"
 #include "clang/Basic/DiagnosticDriverKinds.inc"
 #include "clang/Basic/DiagnosticFrontendKinds.inc"
@@ -121,7 +57,7 @@
 
 /// GetDiagInfo - Return the StaticDiagInfoRec entry for the specified DiagID,
 /// or null if the ID is invalid.
-static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) {
+static const DiagnosticIDs::DiagInfoRec *GetDiagInfo(unsigned DiagID) {
   // Out of bounds diag. Can't be in the table.
   using namespace diag;
   if (DiagID >= DIAG_UPPER_LIMIT || DiagID <= DIAG_START_COMMON)
@@ -161,7 +97,7 @@
 
   assert(ID < StaticDiagInfoSize && Offset < StaticDiagInfoSize);
 
-  const StaticDiagInfoRec *Found = &StaticDiagInfo[ID + Offset];
+  const auto *Found = &StaticDiagInfo[ID + Offset];
   // If the diag id doesn't match we found a different diag, abort. This can
   // happen when this function is called with an ID that points into a hole in
   // the diagID space.
@@ -174,7 +110,7 @@
   DiagnosticMapping Info = DiagnosticMapping::Make(
       diag::Severity::Fatal, /*IsUser=*/false, /*IsPragma=*/false);
 
-  if (const StaticDiagInfoRec *StaticInfo = GetDiagInfo(DiagID)) {
+  if (const auto *StaticInfo = GetDiagInfo(DiagID)) {
     Info.setSeverity((diag::Severity)StaticInfo->DefaultSeverity);
 
     if (StaticInfo->WarnNoWerror) {
@@ -189,8 +125,8 @@
 
 /// getCategoryNumberForDiag - Return the category number that a specified
 /// DiagID belongs to, or 0 if no category.
-unsigned DiagnosticIDs::getCategoryNumberForDiag(unsigned DiagID) {
-  if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
+unsigned DiagnosticIDs::getCategoryNumberForDiag(unsigned DiagID) const {
+  if (const auto *Info = ::GetDiagInfo(DiagID))
     return Info->Category;
   return 0;
 }
@@ -231,32 +167,30 @@
 };
 
 /// getNumberOfCategories - Return the number of categories
-unsigned DiagnosticIDs::getNumberOfCategories() {
+unsigned DiagnosticIDs::getNumberOfCategories() const {
   return llvm::array_lengthof(CategoryNameTable) - 1;
 }
 
 /// getCategoryNameFromID - Given a category ID, return the name of the
 /// category, an empty string if CategoryID is zero, or null if CategoryID is
 /// invalid.
-StringRef DiagnosticIDs::getCategoryNameFromID(unsigned CategoryID) {
+StringRef DiagnosticIDs::getCategoryNameFromID(unsigned CategoryID) const {
   if (CategoryID >= getNumberOfCategories())
    return StringRef();
   return CategoryNameTable[CategoryID].getName();
 }
 
-
-
 DiagnosticIDs::SFINAEResponse
-DiagnosticIDs::getDiagnosticSFINAEResponse(unsigned DiagID) {
-  if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
+DiagnosticIDs::getDiagnosticSFINAEResponse(unsigned DiagID) const {
+  if (const auto *Info = GetDiagInfo(DiagID))
     return static_cast<DiagnosticIDs::SFINAEResponse>(Info->SFINAE);
   return SFINAE_Report;
 }
 
 /// getBuiltinDiagClass - Return the class field of the diagnostic.
 ///
 static unsigned getBuiltinDiagClass(unsigned DiagID) {
-  if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
+  if (const auto *Info = GetDiagInfo(DiagID))
     return Info->Class;
   return ~0U;
 }
@@ -312,7 +246,8 @@
 // Common Diagnostic implementation
 //===----------------------------------------------------------------------===//
 
-DiagnosticIDs::DiagnosticIDs() { CustomDiagInfo = nullptr; }
+DiagnosticIDs::DiagnosticIDs(bool)
+    : DiagInfo(StaticDiagInfo), GetDiagInfo(&::GetDiagInfo) {}
 
 DiagnosticIDs::~DiagnosticIDs() {
   delete CustomDiagInfo;
@@ -335,14 +270,14 @@
 /// level of the specified diagnostic ID is a Warning or Extension.
 /// This only works on builtin diagnostics, not custom ones, and is not legal to
 /// call on NOTEs.
-bool DiagnosticIDs::isBuiltinWarningOrExtension(unsigned DiagID) {
+bool DiagnosticIDs::isBuiltinWarningOrExtension(unsigned DiagID) const {
   return DiagID < diag::DIAG_UPPER_LIMIT &&
          getBuiltinDiagClass(DiagID) != CLASS_ERROR;
 }
 
 /// \brief Determine whether the given built-in diagnostic ID is a
 /// Note.
-bool DiagnosticIDs::isBuiltinNote(unsigned DiagID) {
+bool DiagnosticIDs::isBuiltinNote(unsigned DiagID) const {
   return DiagID < diag::DIAG_UPPER_LIMIT &&
     getBuiltinDiagClass(DiagID) == CLASS_NOTE;
 }
@@ -353,7 +288,7 @@
 /// which case -pedantic enables it) or treated as a warning/error by default.
 ///
 bool DiagnosticIDs::isBuiltinExtensionDiag(unsigned DiagID,
-                                        bool &EnabledByDefault) {
+                                           bool &EnabledByDefault) const {
   if (DiagID >= diag::DIAG_UPPER_LIMIT ||
       getBuiltinDiagClass(DiagID) != CLASS_EXTENSION)
     return false;
@@ -363,7 +298,7 @@
   return true;
 }
 
-bool DiagnosticIDs::isDefaultMappingAsError(unsigned DiagID) {
+bool DiagnosticIDs::isDefaultMappingAsError(unsigned DiagID) const {
   if (DiagID >= diag::DIAG_UPPER_LIMIT)
     return false;
 
@@ -373,7 +308,7 @@
 /// getDescription - Given a diagnostic ID, return a description of the
 /// issue.
 StringRef DiagnosticIDs::getDescription(unsigned DiagID) const {
-  if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
+  if (const DiagInfoRec *Info = GetDiagInfo(DiagID))
     return Info->getDescription();
   assert(CustomDiagInfo && "Invalid CustomDiagInfo");
   return CustomDiagInfo->getDescription(DiagID);
@@ -520,13 +455,13 @@
 /// getWarningOptionForDiag - Return the lowest-level warning option that
 /// enables the specified diagnostic.  If there is no -Wfoo flag that controls
 /// the diagnostic, this returns null.
-StringRef DiagnosticIDs::getWarningOptionForDiag(unsigned DiagID) {
-  if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
+StringRef DiagnosticIDs::getWarningOptionForDiag(unsigned DiagID) const {
+  if (const DiagInfoRec *Info = GetDiagInfo(DiagID))
     return OptionTable[Info->getOptionGroupIndex()].getName();
   return StringRef();
 }
 
-std::vector<std::string> DiagnosticIDs::getDiagnosticFlags() {
+std::vector<std::string> DiagnosticIDs::getDiagnosticFlags() const {
   std::vector<std::string> Res;
   for (size_t I = 1; DiagGroupNames[I] != '\0';) {
     std::string Diag(DiagGroupNames + I + 1, DiagGroupNames[I]);
@@ -582,15 +517,15 @@
   return ::getDiagnosticsInGroup(Flavor, Found, Diags);
 }
 
-void DiagnosticIDs::getAllDiagnostics(diag::Flavor Flavor,
-                                      SmallVectorImpl<diag::kind> &Diags) {
+void DiagnosticIDs::getAllDiagnostics(
+    diag::Flavor Flavor, SmallVectorImpl<diag::kind> &Diags) const {
   for (unsigned i = 0; i != StaticDiagInfoSize; ++i)
     if (StaticDiagInfo[i].getFlavor() == Flavor)
       Diags.push_back(StaticDiagInfo[i].DiagID);
 }
 
 StringRef DiagnosticIDs::getNearestOption(diag::Flavor Flavor,
-                                          StringRef Group) {
+                                          StringRef Group) const {
   StringRef Best;
   unsigned BestDistance = Group.size() + 1; // Sanity threshold.
   for (const WarningOption &O : OptionTable) {
@@ -738,7 +673,7 @@
   return true;
 }
 
-bool DiagnosticIDs::isARCDiagnostic(unsigned DiagID) {
+bool DiagnosticIDs::isARCDiagnostic(unsigned DiagID) const {
   unsigned cat = getCategoryNumberForDiag(DiagID);
   return DiagnosticIDs::getCategoryNameFromID(cat).startswith("ARC ");
 }
Index: lib/Basic/Diagnostic.cpp
===================================================================
--- lib/Basic/Diagnostic.cpp
+++ lib/Basic/Diagnostic.cpp
@@ -364,7 +364,7 @@
                                           SourceLocation Loc) {
   // Get all the diagnostics.
   SmallVector<diag::kind, 64> AllDiags;
-  DiagnosticIDs::getAllDiagnostics(Flavor, AllDiags);
+  Diags->getAllDiagnostics(Flavor, AllDiags);
 
   // Set the mapping.
   for (diag::kind Diag : AllDiags)
Index: lib/ARCMigrate/PlistReporter.cpp
===================================================================
--- lib/ARCMigrate/PlistReporter.cpp
+++ lib/ARCMigrate/PlistReporter.cpp
@@ -34,9 +34,8 @@
 
 void arcmt::writeARCDiagsToPlist(const std::string &outPath,
                                  ArrayRef<StoredDiagnostic> diags,
-                                 SourceManager &SM,
-                                 const LangOptions &LangOpts) {
-  DiagnosticIDs DiagIDs;
+                                 SourceManager &SM, const LangOptions &LangOpts,
+                                 const DiagnosticIDs &DiagIDs) {
 
   // Build up a set of FIDs that we use by scanning the locations and
   // ranges of the diagnostics.
Index: lib/ARCMigrate/ObjCMT.cpp
===================================================================
--- lib/ARCMigrate/ObjCMT.cpp
+++ lib/ARCMigrate/ObjCMT.cpp
@@ -2222,7 +2222,7 @@
   FileManager FileMgr(FSOpts);
   RemapFileParser Parser(FileMgr);
 
-  IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+  IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs(true));
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
       new DiagnosticsEngine(DiagID, new DiagnosticOptions,
                             DiagClient, /*ShouldOwnClient=*/false));
Index: lib/ARCMigrate/Internals.h
===================================================================
--- lib/ARCMigrate/Internals.h
+++ lib/ARCMigrate/Internals.h
@@ -42,8 +42,9 @@
 };
 
 void writeARCDiagsToPlist(const std::string &outPath,
-                          ArrayRef<StoredDiagnostic> diags,
-                          SourceManager &SM, const LangOptions &LangOpts);
+                          ArrayRef<StoredDiagnostic> diags, SourceManager &SM,
+                          const LangOptions &LangOpts,
+                          const DiagnosticIDs &DiagIDs);
 
 class TransformActions {
   DiagnosticsEngine &Diags;
Index: lib/ARCMigrate/ARCMTActions.cpp
===================================================================
--- lib/ARCMigrate/ARCMTActions.cpp
+++ lib/ARCMigrate/ARCMTActions.cpp
@@ -17,7 +17,7 @@
 bool CheckAction::BeginInvocation(CompilerInstance &CI) {
   if (arcmt::checkForManualIssues(CI.getInvocation(), getCurrentInput(),
                                   CI.getPCHContainerOperations(),
-                                  CI.getDiagnostics().getClient()))
+                                  CI.getDiagnostics()))
     return false; // errors, stop the action.
 
   // We only want to see warnings reported from arcmt::checkForManualIssues.
@@ -31,17 +31,16 @@
 bool ModifyAction::BeginInvocation(CompilerInstance &CI) {
   return !arcmt::applyTransformations(CI.getInvocation(), getCurrentInput(),
                                       CI.getPCHContainerOperations(),
-                                      CI.getDiagnostics().getClient());
+                                      CI.getDiagnostics());
 }
 
 ModifyAction::ModifyAction(std::unique_ptr<FrontendAction> WrappedAction)
   : WrapperFrontendAction(std::move(WrappedAction)) {}
 
 bool MigrateAction::BeginInvocation(CompilerInstance &CI) {
   if (arcmt::migrateWithTemporaryFiles(
           CI.getInvocation(), getCurrentInput(), CI.getPCHContainerOperations(),
-          CI.getDiagnostics().getClient(), MigrateDir, EmitPremigrationARCErros,
-          PlistOut))
+          CI.getDiagnostics(), MigrateDir, EmitPremigrationARCErros, PlistOut))
     return false; // errors, stop the action.
 
   // We only want to see diagnostics emitted by migrateWithTemporaryFiles.
Index: lib/ARCMigrate/ARCMT.cpp
===================================================================
--- lib/ARCMigrate/ARCMT.cpp
+++ lib/ARCMigrate/ARCMT.cpp
@@ -132,7 +132,7 @@
 
   void HandleDiagnostic(DiagnosticsEngine::Level level,
                         const Diagnostic &Info) override {
-    if (DiagnosticIDs::isARCDiagnostic(Info.getID()) ||
+    if (Diags.getDiagnosticIDs()->isARCDiagnostic(Info.getID()) ||
         level >= DiagnosticsEngine::Error || level == DiagnosticsEngine::Note) {
       if (Info.getLocation().isValid())
         CapturedDiags.push_back(StoredDiagnostic(level, Info));
@@ -171,19 +171,18 @@
 }
 
 static CompilerInvocation *
-createInvocationForMigration(CompilerInvocation &origCI,
+createInvocationForMigration(const IntrusiveRefCntPtr<DiagnosticIDs> &DiagID,
+                             CompilerInvocation &origCI,
                              const PCHContainerReader &PCHContainerRdr) {
   std::unique_ptr<CompilerInvocation> CInvok;
   CInvok.reset(new CompilerInvocation(origCI));
   PreprocessorOptions &PPOpts = CInvok->getPreprocessorOpts();
   if (!PPOpts.ImplicitPCHInclude.empty()) {
     // We can't use a PCH because it was likely built in non-ARC mode and we
     // want to parse in ARC. Include the original header.
     FileManager FileMgr(origCI.getFileSystemOpts());
-    IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
-    IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
-        new DiagnosticsEngine(DiagID, &origCI.getDiagnosticOpts(),
-                              new IgnoringDiagConsumer()));
+    IntrusiveRefCntPtr<DiagnosticsEngine> Diags(new DiagnosticsEngine(
+        DiagID, &origCI.getDiagnosticOpts(), new IgnoringDiagConsumer()));
     std::string OriginalFile = ASTReader::getOriginalSourceFile(
         PPOpts.ImplicitPCHInclude, FileMgr, PCHContainerRdr, *Diags);
     if (!OriginalFile.empty())
@@ -220,11 +219,11 @@
 static void emitPremigrationErrors(const CapturedDiagList &arcDiags,
                                    DiagnosticOptions *diagOpts,
                                    Preprocessor &PP) {
-  TextDiagnosticPrinter printer(llvm::errs(), diagOpts);
-  IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
-  IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
-      new DiagnosticsEngine(DiagID, diagOpts, &printer,
-                            /*ShouldOwnClient=*/false));
+  TextDiagnosticPrinter printer(
+      llvm::errs(), PP.getDiagnostics().getDiagnosticIDs(), diagOpts);
+  IntrusiveRefCntPtr<DiagnosticsEngine> Diags(new DiagnosticsEngine(
+      PP.getDiagnostics().getDiagnosticIDs(), diagOpts, &printer,
+      /*ShouldOwnClient=*/false));
   Diags->setSourceManager(&PP.getSourceManager());
   
   printer.BeginSourceFile(PP.getLangOpts(), &PP);
@@ -239,7 +238,7 @@
 bool arcmt::checkForManualIssues(
     CompilerInvocation &origCI, const FrontendInputFile &Input,
     std::shared_ptr<PCHContainerOperations> PCHContainerOps,
-    DiagnosticConsumer *DiagClient, bool emitPremigrationARCErrors,
+    DiagnosticsEngine &OriginalDiags, bool emitPremigrationARCErrors,
     StringRef plistOut) {
   if (!origCI.getLangOpts()->ObjC1)
     return false;
@@ -253,18 +252,19 @@
   assert(!transforms.empty());
 
   std::unique_ptr<CompilerInvocation> CInvok;
-  CInvok.reset(
-      createInvocationForMigration(origCI, PCHContainerOps->getRawReader()));
+  CInvok.reset(createInvocationForMigration(OriginalDiags.getDiagnosticIDs(),
+                                            origCI,
+                                            PCHContainerOps->getRawReader()));
   CInvok->getFrontendOpts().Inputs.clear();
   CInvok->getFrontendOpts().Inputs.push_back(Input);
 
   CapturedDiagList capturedDiags;
 
+  auto *DiagClient = OriginalDiags.getClient();
   assert(DiagClient);
-  IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
-  IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
-      new DiagnosticsEngine(DiagID, &origCI.getDiagnosticOpts(),
-                            DiagClient, /*ShouldOwnClient=*/false));
+  IntrusiveRefCntPtr<DiagnosticsEngine> Diags(new DiagnosticsEngine(
+      OriginalDiags.getDiagnosticIDs(), &origCI.getDiagnosticOpts(), DiagClient,
+      /*ShouldOwnClient=*/false));
 
   // Filter of all diagnostics.
   CaptureDiagnosticConsumer errRec(*Diags, *DiagClient, capturedDiags);
@@ -299,8 +299,8 @@
     for (CapturedDiagList::iterator
            I = capturedDiags.begin(), E = capturedDiags.end(); I != E; ++I)
       arcDiags.push_back(*I);
-    writeARCDiagsToPlist(plistOut, arcDiags,
-                         Ctx.getSourceManager(), Ctx.getLangOpts());
+    writeARCDiagsToPlist(plistOut, arcDiags, Ctx.getSourceManager(),
+                         Ctx.getLangOpts(), *OriginalDiags.getDiagnosticIDs());
   }
 
   // After parsing of source files ended, we want to reuse the
@@ -340,25 +340,24 @@
 static bool
 applyTransforms(CompilerInvocation &origCI, const FrontendInputFile &Input,
                 std::shared_ptr<PCHContainerOperations> PCHContainerOps,
-                DiagnosticConsumer *DiagClient, StringRef outputDir,
+                DiagnosticsEngine &Diags, StringRef outputDir,
                 bool emitPremigrationARCErrors, StringRef plistOut) {
   if (!origCI.getLangOpts()->ObjC1)
     return false;
 
   LangOptions::GCMode OrigGCMode = origCI.getLangOpts()->getGC();
 
   // Make sure checking is successful first.
   CompilerInvocation CInvokForCheck(origCI);
-  if (arcmt::checkForManualIssues(CInvokForCheck, Input, PCHContainerOps,
-                                  DiagClient, emitPremigrationARCErrors,
-                                  plistOut))
+  if (arcmt::checkForManualIssues(CInvokForCheck, Input, PCHContainerOps, Diags,
+                                  emitPremigrationARCErrors, plistOut))
     return true;
 
   CompilerInvocation CInvok(origCI);
   CInvok.getFrontendOpts().Inputs.clear();
   CInvok.getFrontendOpts().Inputs.push_back(Input);
 
-  MigrationProcess migration(CInvok, PCHContainerOps, DiagClient, outputDir);
+  MigrationProcess migration(CInvok, PCHContainerOps, Diags, outputDir);
   bool NoFinalizeRemoval = origCI.getMigratorOpts().NoFinalizeRemoval;
 
   std::vector<TransformFn> transforms = arcmt::getAllTransformations(OrigGCMode,
@@ -370,46 +369,40 @@
     if (err) return true;
   }
 
-  IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
-  IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
-      new DiagnosticsEngine(DiagID, &origCI.getDiagnosticOpts(),
-                            DiagClient, /*ShouldOwnClient=*/false));
-
   if (outputDir.empty()) {
     origCI.getLangOpts()->ObjCAutoRefCount = true;
-    return migration.getRemapper().overwriteOriginal(*Diags);
+    return migration.getRemapper().overwriteOriginal(Diags);
   } else {
-    return migration.getRemapper().flushToDisk(outputDir, *Diags);
+    return migration.getRemapper().flushToDisk(outputDir, Diags);
   }
 }
 
 bool arcmt::applyTransformations(
     CompilerInvocation &origCI, const FrontendInputFile &Input,
     std::shared_ptr<PCHContainerOperations> PCHContainerOps,
-    DiagnosticConsumer *DiagClient) {
-  return applyTransforms(origCI, Input, PCHContainerOps, DiagClient,
-                         StringRef(), false, StringRef());
+    DiagnosticsEngine &Diags) {
+  return applyTransforms(origCI, Input, PCHContainerOps, Diags, StringRef(),
+                         false, StringRef());
 }
 
 bool arcmt::migrateWithTemporaryFiles(
     CompilerInvocation &origCI, const FrontendInputFile &Input,
     std::shared_ptr<PCHContainerOperations> PCHContainerOps,
-    DiagnosticConsumer *DiagClient, StringRef outputDir,
+    DiagnosticsEngine &Diags, StringRef outputDir,
     bool emitPremigrationARCErrors, StringRef plistOut) {
   assert(!outputDir.empty() && "Expected output directory path");
-  return applyTransforms(origCI, Input, PCHContainerOps, DiagClient, outputDir,
+  return applyTransforms(origCI, Input, PCHContainerOps, Diags, outputDir,
                          emitPremigrationARCErrors, plistOut);
 }
 
-bool arcmt::getFileRemappings(std::vector<std::pair<std::string,std::string> > &
-                                  remap,
-                              StringRef outputDir,
-                              DiagnosticConsumer *DiagClient) {
+bool arcmt::getFileRemappings(
+    std::vector<std::pair<std::string, std::string>> &remap,
+    StringRef outputDir, DiagnosticConsumer *DiagClient,
+    IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs) {
   assert(!outputDir.empty());
 
-  IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
-      new DiagnosticsEngine(DiagID, new DiagnosticOptions,
+      new DiagnosticsEngine(std::move(DiagIDs), new DiagnosticOptions,
                             DiagClient, /*ShouldOwnClient=*/false));
 
   FileRemapper remapper;
@@ -509,35 +502,35 @@
 MigrationProcess::MigrationProcess(
     const CompilerInvocation &CI,
     std::shared_ptr<PCHContainerOperations> PCHContainerOps,
-    DiagnosticConsumer *diagClient, StringRef outputDir)
+    DiagnosticsEngine &OriginalDiags, StringRef outputDir)
     : OrigCI(CI), PCHContainerOps(std::move(PCHContainerOps)),
-      DiagClient(diagClient), HadARCErrors(false) {
+      OriginalDiags(OriginalDiags), HadARCErrors(false) {
   if (!outputDir.empty()) {
-    IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
-    IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
-      new DiagnosticsEngine(DiagID, &CI.getDiagnosticOpts(),
-                            DiagClient, /*ShouldOwnClient=*/false));
+    IntrusiveRefCntPtr<DiagnosticsEngine> Diags(new DiagnosticsEngine(
+        OriginalDiags.getDiagnosticIDs(), &CI.getDiagnosticOpts(),
+        OriginalDiags.getClient(), /*ShouldOwnClient=*/false));
     Remapper.initFromDisk(outputDir, *Diags, /*ignoreIfFilesChanges=*/true);
   }
 }
 
 bool MigrationProcess::applyTransform(TransformFn trans,
                                       RewriteListener *listener) {
   std::unique_ptr<CompilerInvocation> CInvok;
-  CInvok.reset(
-      createInvocationForMigration(OrigCI, PCHContainerOps->getRawReader()));
+  CInvok.reset(createInvocationForMigration(OriginalDiags.getDiagnosticIDs(),
+                                            OrigCI,
+                                            PCHContainerOps->getRawReader()));
   CInvok->getDiagnosticOpts().IgnoreWarnings = true;
 
   Remapper.applyMappings(CInvok->getPreprocessorOpts());
 
   CapturedDiagList capturedDiags;
   std::vector<SourceLocation> ARCMTMacroLocs;
 
-  assert(DiagClient);
-  IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
-  IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
-      new DiagnosticsEngine(DiagID, new DiagnosticOptions,
-                            DiagClient, /*ShouldOwnClient=*/false));
+  auto *DiagClient = OriginalDiags.getClient();
+  assert(OriginalDiags.getClient());
+  IntrusiveRefCntPtr<DiagnosticsEngine> Diags(new DiagnosticsEngine(
+      OriginalDiags.getDiagnosticIDs(), new DiagnosticOptions, DiagClient,
+      /*ShouldOwnClient=*/false));
 
   // Filter of all diagnostics.
   CaptureDiagnosticConsumer errRec(*Diags, *DiagClient, capturedDiags);
Index: include/clang/Frontend/TextDiagnosticPrinter.h
===================================================================
--- include/clang/Frontend/TextDiagnosticPrinter.h
+++ include/clang/Frontend/TextDiagnosticPrinter.h
@@ -27,6 +27,7 @@
 
 class TextDiagnosticPrinter : public DiagnosticConsumer {
   raw_ostream &OS;
+  IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs;
   IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
 
   /// \brief Handle to the currently active text diagnostic emitter.
@@ -38,16 +39,20 @@
   unsigned OwnsOutputStream : 1;
 
 public:
-  TextDiagnosticPrinter(raw_ostream &os, DiagnosticOptions *diags,
+  TextDiagnosticPrinter(raw_ostream &os,
+                        IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs,
+                        DiagnosticOptions *diags,
                         bool OwnsOutputStream = false);
   ~TextDiagnosticPrinter() override;
 
   /// setPrefix - Set the diagnostic printer prefix string, which will be
   /// printed at the start of any diagnostics. If empty, no prefix string is
   /// used.
   void setPrefix(std::string Value) { Prefix = std::move(Value); }
+  const IntrusiveRefCntPtr<DiagnosticIDs> &getDiagIDs() { return DiagIDs; }
 
-  void BeginSourceFile(const LangOptions &LO, const Preprocessor *PP) override;
+  void BeginSourceFile(const LangOptions &LO,
+                       const Preprocessor *PP = nullptr) override;
   void EndSourceFile() override;
   void HandleDiagnostic(DiagnosticsEngine::Level Level,
                         const Diagnostic &Info) override;
Index: include/clang/Frontend/SerializedDiagnosticPrinter.h
===================================================================
--- include/clang/Frontend/SerializedDiagnosticPrinter.h
+++ include/clang/Frontend/SerializedDiagnosticPrinter.h
@@ -21,6 +21,7 @@
 namespace clang {
 class DiagnosticConsumer;
 class DiagnosticsEngine;
+class DiagnosticIDs;
 class DiagnosticOptions;
 
 namespace serialized_diags {
@@ -33,9 +34,10 @@
 /// This allows wrapper tools for Clang to get diagnostics from Clang
 /// (via libclang) without needing to parse Clang's command line output.
 ///
-std::unique_ptr<DiagnosticConsumer> create(StringRef OutputFile,
-                                           DiagnosticOptions *Diags,
-                                           bool MergeChildRecords = false);
+std::unique_ptr<DiagnosticConsumer>
+create(StringRef OutputFile, DiagnosticOptions *Diags,
+       IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs,
+       bool MergeChildRecords = false);
 
 } // end serialized_diags namespace
 } // end clang namespace
Index: include/clang/Frontend/LogDiagnosticPrinter.h
===================================================================
--- include/clang/Frontend/LogDiagnosticPrinter.h
+++ include/clang/Frontend/LogDiagnosticPrinter.h
@@ -52,6 +52,7 @@
   raw_ostream &OS;
   std::unique_ptr<raw_ostream> StreamOwner;
   const LangOptions *LangOpts;
+  IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs;
   IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
 
   SourceLocation LastWarningLoc;
@@ -63,7 +64,9 @@
   std::string DwarfDebugFlags;
 
 public:
-  LogDiagnosticPrinter(raw_ostream &OS, DiagnosticOptions *Diags,
+  LogDiagnosticPrinter(raw_ostream &OS,
+                       IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs,
+                       DiagnosticOptions *Diags,
                        std::unique_ptr<raw_ostream> StreamOwner);
 
   void setDwarfDebugFlags(StringRef Value) {
Index: include/clang/CrossTU/CrossTranslationUnit.h
===================================================================
--- include/clang/CrossTU/CrossTranslationUnit.h
+++ include/clang/CrossTU/CrossTranslationUnit.h
@@ -16,6 +16,7 @@
 #define LLVM_CLANG_CROSSTU_CROSSTRANSLATIONUNIT_H
 
 #include "clang/Basic/LLVM.h"
+#include "clang/Frontend/CompilerInstance.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/StringMap.h"
@@ -27,6 +28,7 @@
 class ASTImporter;
 class ASTUnit;
 class DeclContext;
+class DiagnosticIDs;
 class FunctionDecl;
 class NamedDecl;
 class TranslationUnitDecl;
@@ -108,7 +110,8 @@
   /// Note that the AST files should also be in the \p CrossTUDir.
   llvm::Expected<const FunctionDecl *>
   getCrossTUDefinition(const FunctionDecl *FD, StringRef CrossTUDir,
-                       StringRef IndexName);
+                       StringRef IndexName,
+                       const IntrusiveRefCntPtr<DiagnosticIDs> &DiagIDs);
 
   /// \brief This function loads a function definition from an external AST
   ///        file.
@@ -122,9 +125,10 @@
   /// function.
   ///
   /// Note that the AST files should also be in the \p CrossTUDir.
-  llvm::Expected<ASTUnit *> loadExternalAST(StringRef LookupName,
-                                            StringRef CrossTUDir,
-                                            StringRef IndexName);
+  llvm::Expected<ASTUnit *>
+  loadExternalAST(StringRef LookupName, StringRef CrossTUDir,
+                  StringRef IndexName,
+                  const IntrusiveRefCntPtr<DiagnosticIDs> &DiagIDs);
 
   /// \brief This function merges a definition from a separate AST Unit into
   ///        the current one which was created by the compiler instance that
@@ -139,6 +143,8 @@
   /// \brief Emit diagnostics for the user for potential configuration errors.
   void emitCrossTUDiagnostics(const IndexError &IE);
 
+  CompilerInstance &getCompilerInstance() { return CI; }
+
 private:
   ASTImporter &getOrCreateASTImporter(ASTContext &From);
   const FunctionDecl *findFunctionInDeclContext(const DeclContext *DC,
Index: include/clang/Basic/DiagnosticIDs.h
===================================================================
--- include/clang/Basic/DiagnosticIDs.h
+++ include/clang/Basic/DiagnosticIDs.h
@@ -16,6 +16,7 @@
 #define LLVM_CLANG_BASIC_DIAGNOSTICIDS_H
 
 #include "clang/Basic/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/IntrusiveRefCntPtr.h"
 #include "llvm/ADT/StringRef.h"
 #include <vector>
@@ -168,12 +169,54 @@
     Ignored, Note, Remark, Warning, Error, Fatal
   };
 
+  // Diagnostic classes.
+  enum {
+    CLASS_NOTE = 0x01,
+    CLASS_REMARK = 0x02,
+    CLASS_WARNING = 0x03,
+    CLASS_EXTENSION = 0x04,
+    CLASS_ERROR = 0x05
+  };
+
+  struct DiagInfoRec {
+    uint16_t DiagID;
+    unsigned DefaultSeverity : 3;
+    unsigned Class : 3;
+    unsigned SFINAE : 2;
+    unsigned WarnNoWerror : 1;
+    unsigned WarnShowInSystemHeader : 1;
+    unsigned Category : 6;
+
+    uint16_t OptionGroupIndex;
+
+    uint16_t DescriptionLen;
+    const char *DescriptionStr;
+
+    unsigned getOptionGroupIndex() const { return OptionGroupIndex; }
+
+    StringRef getDescription() const {
+      return StringRef(DescriptionStr, DescriptionLen);
+    }
+
+    diag::Flavor getFlavor() const {
+      return Class == CLASS_REMARK ? diag::Flavor::Remark
+                                   : diag::Flavor::WarningOrError;
+    }
+
+    bool operator<(const DiagInfoRec &RHS) const { return DiagID < RHS.DiagID; }
+  };
+
 private:
   /// \brief Information for uniquing and looking up custom diags.
-  diag::CustomDiagInfo *CustomDiagInfo;
+  diag::CustomDiagInfo *CustomDiagInfo = nullptr;
+  ArrayRef<DiagInfoRec> DiagInfo;
+  std::function<const DiagInfoRec *(unsigned)> GetDiagInfo;
 
 public:
-  DiagnosticIDs();
+  DiagnosticIDs(bool);
+  DiagnosticIDs(ArrayRef<DiagInfoRec> DiagInfo,
+                std::function<const DiagInfoRec *(unsigned)> GetDiagInfo)
+      : DiagInfo(DiagInfo), GetDiagInfo(GetDiagInfo) {}
   ~DiagnosticIDs();
 
   /// \brief Return an ID for a diagnostic with the specified format string and
@@ -199,18 +242,18 @@
   ///
   /// This only works on builtin diagnostics, not custom ones, and is not
   /// legal to call on NOTEs.
-  static bool isBuiltinWarningOrExtension(unsigned DiagID);
+  bool isBuiltinWarningOrExtension(unsigned DiagID) const;
 
   /// \brief Return true if the specified diagnostic is mapped to errors by
   /// default.
-  static bool isDefaultMappingAsError(unsigned DiagID);
+  bool isDefaultMappingAsError(unsigned DiagID) const;
 
   /// \brief Determine whether the given built-in diagnostic ID is a Note.
-  static bool isBuiltinNote(unsigned DiagID);
+  bool isBuiltinNote(unsigned DiagID) const;
 
   /// \brief Determine whether the given built-in diagnostic ID is for an
   /// extension of some sort.
-  static bool isBuiltinExtensionDiag(unsigned DiagID) {
+  bool isBuiltinExtensionDiag(unsigned DiagID) const {
     bool ignored;
     return isBuiltinExtensionDiag(DiagID, ignored);
   }
@@ -222,28 +265,27 @@
   /// diagnostic is ignored by default (in which case -pedantic enables it) or
   /// treated as a warning/error by default.
   ///
-  static bool isBuiltinExtensionDiag(unsigned DiagID, bool &EnabledByDefault);
-  
+  bool isBuiltinExtensionDiag(unsigned DiagID, bool &EnabledByDefault) const;
 
   /// \brief Return the lowest-level warning option that enables the specified
   /// diagnostic.
   ///
   /// If there is no -Wfoo flag that controls the diagnostic, this returns null.
-  static StringRef getWarningOptionForDiag(unsigned DiagID);
-  
+  StringRef getWarningOptionForDiag(unsigned DiagID) const;
+
   /// \brief Return the category number that a specified \p DiagID belongs to,
   /// or 0 if no category.
-  static unsigned getCategoryNumberForDiag(unsigned DiagID);
+  unsigned getCategoryNumberForDiag(unsigned DiagID) const;
 
   /// \brief Return the number of diagnostic categories.
-  static unsigned getNumberOfCategories();
+  unsigned getNumberOfCategories() const;
 
   /// \brief Given a category ID, return the name of the category.
-  static StringRef getCategoryNameFromID(unsigned CategoryID);
-  
+  StringRef getCategoryNameFromID(unsigned CategoryID) const;
+
   /// \brief Return true if a given diagnostic falls into an ARC diagnostic
   /// category.
-  static bool isARCDiagnostic(unsigned DiagID);
+  bool isARCDiagnostic(unsigned DiagID) const;
 
   /// \brief Enumeration describing how the emission of a diagnostic should
   /// be treated when it occurs during C++ template argument deduction.
@@ -279,14 +321,14 @@
   /// deduction fails but no diagnostic is emitted. Certain classes of
   /// errors, such as those errors that involve C++ access control,
   /// are not SFINAE errors.
-  static SFINAEResponse getDiagnosticSFINAEResponse(unsigned DiagID);
+  SFINAEResponse getDiagnosticSFINAEResponse(unsigned DiagID) const;
 
   /// \brief Get the string of all diagnostic flags.
   ///
   /// \returns A list of all diagnostics flags as they would be written in a
   /// command line invocation including their `no-` variants. For example:
   /// `{"-Wempty-body", "-Wno-empty-body", ...}`
-  static std::vector<std::string> getDiagnosticFlags();
+  std::vector<std::string> getDiagnosticFlags() const;
 
   /// \brief Get the set of all diagnostic IDs in the group with the given name.
   ///
@@ -296,12 +338,12 @@
                              SmallVectorImpl<diag::kind> &Diags) const;
 
   /// \brief Get the set of all diagnostic IDs.
-  static void getAllDiagnostics(diag::Flavor Flavor,
-                                SmallVectorImpl<diag::kind> &Diags);
+  void getAllDiagnostics(diag::Flavor Flavor,
+                         SmallVectorImpl<diag::kind> &Diags) const;
 
   /// \brief Get the diagnostic option with the closest edit distance to the
   /// given group name.
-  static StringRef getNearestOption(diag::Flavor Flavor, StringRef Group);
+  StringRef getNearestOption(diag::Flavor Flavor, StringRef Group) const;
 
 private:
   /// \brief Classify the specified diagnostic ID into a Level, consumable by
Index: include/clang/ARCMigrate/ARCMT.h
===================================================================
--- include/clang/ARCMigrate/ARCMT.h
+++ include/clang/ARCMigrate/ARCMT.h
@@ -15,12 +15,13 @@
 #include "clang/Frontend/CompilerInvocation.h"
 
 namespace clang {
-  class ASTContext;
-  class DiagnosticConsumer;
-  class PCHContainerOperations;
+class ASTContext;
+class DiagnosticConsumer;
+class DiagnosticIDs;
+class PCHContainerOperations;
 
 namespace arcmt {
-  class MigrationPass;
+class MigrationPass;
 
 /// \brief Creates an AST with the provided CompilerInvocation but with these
 /// changes:
@@ -38,56 +39,53 @@
 /// the pre-migration ARC diagnostics.
 ///
 /// \returns false if no error is produced, true otherwise.
-bool
-checkForManualIssues(CompilerInvocation &CI, const FrontendInputFile &Input,
-                     std::shared_ptr<PCHContainerOperations> PCHContainerOps,
-                     DiagnosticConsumer *DiagClient,
-                     bool emitPremigrationARCErrors = false,
-                     StringRef plistOut = StringRef());
+bool checkForManualIssues(
+    CompilerInvocation &CI, const FrontendInputFile &Input,
+    std::shared_ptr<PCHContainerOperations> PCHContainerOps,
+    DiagnosticsEngine &Diags, bool emitPremigrationARCErrors = false,
+    StringRef plistOut = StringRef());
 
 /// \brief Works similar to checkForManualIssues but instead of checking, it
 /// applies automatic modifications to source files to conform to ARC.
 ///
 /// \returns false if no error is produced, true otherwise.
-bool
-applyTransformations(CompilerInvocation &origCI,
-                     const FrontendInputFile &Input,
-                     std::shared_ptr<PCHContainerOperations> PCHContainerOps,
-                     DiagnosticConsumer *DiagClient);
+bool applyTransformations(
+    CompilerInvocation &origCI, const FrontendInputFile &Input,
+    std::shared_ptr<PCHContainerOperations> PCHContainerOps,
+    DiagnosticsEngine &Diags);
 
 /// \brief Applies automatic modifications and produces temporary files
 /// and metadata into the \p outputDir path.
 ///
 /// \param emitPremigrationARCErrors if true all ARC errors will get emitted
-/// even if the migrator can fix them, but the function will still return false
-/// if all ARC errors can be fixed.
+/// even if the migrator can fix them, but the function will still return
+/// false if all ARC errors can be fixed.
 ///
 /// \param plistOut if non-empty, it is the file path to store the plist with
 /// the pre-migration ARC diagnostics.
 ///
 /// \returns false if no error is produced, true otherwise.
 bool migrateWithTemporaryFiles(
     CompilerInvocation &origCI, const FrontendInputFile &Input,
     std::shared_ptr<PCHContainerOperations> PCHContainerOps,
-    DiagnosticConsumer *DiagClient, StringRef outputDir,
+    DiagnosticsEngine &Diags, StringRef outputDir,
     bool emitPremigrationARCErrors, StringRef plistOut);
 
 /// \brief Get the set of file remappings from the \p outputDir path that
 /// migrateWithTemporaryFiles produced.
 ///
 /// \returns false if no error is produced, true otherwise.
-bool getFileRemappings(std::vector<std::pair<std::string,std::string> > &remap,
-                       StringRef outputDir,
-                       DiagnosticConsumer *DiagClient);
+bool getFileRemappings(std::vector<std::pair<std::string, std::string>> &remap,
+                       StringRef outputDir, DiagnosticConsumer *DiagClient,
+                       IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs);
 
 /// \brief Get the set of file remappings from a list of files with remapping
 /// info.
 ///
 /// \returns false if no error is produced, true otherwise.
 bool getFileRemappingsFromFileList(
-                        std::vector<std::pair<std::string,std::string> > &remap,
-                        ArrayRef<StringRef> remapFiles,
-                        DiagnosticConsumer *DiagClient);
+    std::vector<std::pair<std::string, std::string>> &remap,
+    ArrayRef<StringRef> remapFiles, DiagnosticConsumer *DiagClient);
 
 typedef void (*TransformFn)(MigrationPass &pass);
 
@@ -97,26 +95,26 @@
 class MigrationProcess {
   CompilerInvocation OrigCI;
   std::shared_ptr<PCHContainerOperations> PCHContainerOps;
-  DiagnosticConsumer *DiagClient;
+  DiagnosticsEngine &OriginalDiags;
   FileRemapper Remapper;
 
 public:
   bool HadARCErrors;
 
   MigrationProcess(const CompilerInvocation &CI,
                    std::shared_ptr<PCHContainerOperations> PCHContainerOps,
-                   DiagnosticConsumer *diagClient,
+                   DiagnosticsEngine &OriginalDiags,
                    StringRef outputDir = StringRef());
 
   class RewriteListener {
   public:
     virtual ~RewriteListener();
 
-    virtual void start(ASTContext &Ctx) { }
-    virtual void finish() { }
+    virtual void start(ASTContext &Ctx) {}
+    virtual void finish() {}
 
-    virtual void insert(SourceLocation loc, StringRef text) { }
-    virtual void remove(CharSourceRange range) { }
+    virtual void insert(SourceLocation loc, StringRef text) {}
+    virtual void remove(CharSourceRange range) {}
   };
 
   bool applyTransform(TransformFn trans, RewriteListener *listener = nullptr);
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D41357: W... David Blaikie via Phabricator via cfe-commits

Reply via email to