https://github.com/ilovepi updated 
https://github.com/llvm/llvm-project/pull/170219

>From a81102bd098882ecadbe895b9cd4132d1fc58c4f Mon Sep 17 00:00:00 2001
From: Paul Kirth <[email protected]>
Date: Fri, 21 Nov 2025 14:26:36 -0800
Subject: [PATCH] [clang-doc] Use DiagnosticsEngine to handle diagnostic output

Right now we use a combination of outs() and errs() to handle tool
output. Instead, we can use existing diagnostic support in clang and
LLVM to ensure our tool has a consistent behavior with other tools.
---
 clang-tools-extra/clang-doc/BitcodeReader.cpp |  25 ++--
 clang-tools-extra/clang-doc/BitcodeReader.h   |   4 +-
 clang-tools-extra/clang-doc/BitcodeWriter.cpp |   4 +-
 clang-tools-extra/clang-doc/BitcodeWriter.h   |   5 +-
 clang-tools-extra/clang-doc/Generators.cpp    |   9 +-
 .../clang-doc/HTMLMustacheGenerator.cpp       |   1 +
 clang-tools-extra/clang-doc/Mapper.cpp        |   4 +-
 .../clang-doc/Representation.cpp              |   7 +-
 clang-tools-extra/clang-doc/Representation.h  |  14 +-
 clang-tools-extra/clang-doc/Serialize.cpp     |  19 +--
 clang-tools-extra/clang-doc/Serialize.h       |   2 +-
 .../clang-doc/tool/ClangDocMain.cpp           |  72 ++++++----
 .../unittests/clang-doc/BitcodeTest.cpp       |  86 ++++++------
 .../unittests/clang-doc/ClangDocTest.cpp      |  15 +++
 .../unittests/clang-doc/ClangDocTest.h        |  17 +++
 .../unittests/clang-doc/HTMLGeneratorTest.cpp |  49 ++++---
 .../clang-doc/HTMLMustacheGeneratorTest.cpp   |  35 +++--
 .../unittests/clang-doc/JSONGeneratorTest.cpp |  10 +-
 .../unittests/clang-doc/MDGeneratorTest.cpp   |  22 ++--
 .../unittests/clang-doc/MergeTest.cpp         |  10 +-
 .../unittests/clang-doc/SerializeTest.cpp     | 124 ++++++++++--------
 .../unittests/clang-doc/YAMLGeneratorTest.cpp |  30 +++--
 22 files changed, 344 insertions(+), 220 deletions(-)

diff --git a/clang-tools-extra/clang-doc/BitcodeReader.cpp 
b/clang-tools-extra/clang-doc/BitcodeReader.cpp
index dd5bbcd998784..e096264d929c7 100644
--- a/clang-tools-extra/clang-doc/BitcodeReader.cpp
+++ b/clang-tools-extra/clang-doc/BitcodeReader.cpp
@@ -8,6 +8,7 @@
 
 #include "BitcodeReader.h"
 #include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/TimeProfiler.h"
 #include "llvm/Support/raw_ostream.h"
 #include <optional>
@@ -15,6 +16,8 @@
 namespace clang {
 namespace doc {
 
+static llvm::ExitOnError ExitOnErr("clang-doc error: ");
+
 using Record = llvm::SmallVector<uint64_t, 1024>;
 
 // This implements decode for SmallString.
@@ -716,8 +719,8 @@ llvm::Error addReference(FriendInfo *Friend, Reference &&R, 
FieldId F) {
 
 template <typename T, typename ChildInfoType>
 static void addChild(T I, ChildInfoType &&R) {
-  llvm::errs() << "invalid child type for info";
-  exit(1);
+  ExitOnErr(llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                    "invalid child type for info"));
 }
 
 // Namespace children:
@@ -766,8 +769,9 @@ template <> void addChild(BaseRecordInfo *I, FunctionInfo 
&&R) {
 // parameters) or TemplateSpecializationInfo (for the specialization's
 // parameters).
 template <typename T> static void addTemplateParam(T I, TemplateParamInfo &&P) 
{
-  llvm::errs() << "invalid container for template parameter";
-  exit(1);
+  ExitOnErr(
+      llvm::createStringError(llvm::inconvertibleErrorCode(),
+                              "invalid container for template parameter"));
 }
 template <> void addTemplateParam(TemplateInfo *I, TemplateParamInfo &&P) {
   I->Params.emplace_back(std::move(P));
@@ -779,8 +783,8 @@ void addTemplateParam(TemplateSpecializationInfo *I, 
TemplateParamInfo &&P) {
 
 // Template info. These apply to either records or functions.
 template <typename T> static void addTemplate(T I, TemplateInfo &&P) {
-  llvm::errs() << "invalid container for template info";
-  exit(1);
+  ExitOnErr(llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                    "invalid container for template info"));
 }
 template <> void addTemplate(RecordInfo *I, TemplateInfo &&P) {
   I->Template.emplace(std::move(P));
@@ -798,8 +802,9 @@ template <> void addTemplate(FriendInfo *I, TemplateInfo 
&&P) {
 // Template specializations go only into template records.
 template <typename T>
 static void addTemplateSpecialization(T I, TemplateSpecializationInfo &&TSI) {
-  llvm::errs() << "invalid container for template specialization info";
-  exit(1);
+  ExitOnErr(llvm::createStringError(
+      llvm::inconvertibleErrorCode(),
+      "invalid container for template specialization info"));
 }
 template <>
 void addTemplateSpecialization(TemplateInfo *I,
@@ -808,8 +813,8 @@ void addTemplateSpecialization(TemplateInfo *I,
 }
 
 template <typename T> static void addConstraint(T I, ConstraintInfo &&C) {
-  llvm::errs() << "invalid container for constraint info";
-  exit(1);
+  ExitOnErr(llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                    "invalid container for constraint info"));
 }
 template <> void addConstraint(TemplateInfo *I, ConstraintInfo &&C) {
   I->Constraints.emplace_back(std::move(C));
diff --git a/clang-tools-extra/clang-doc/BitcodeReader.h 
b/clang-tools-extra/clang-doc/BitcodeReader.h
index d51ac8bb83311..86d6f76998926 100644
--- a/clang-tools-extra/clang-doc/BitcodeReader.h
+++ b/clang-tools-extra/clang-doc/BitcodeReader.h
@@ -27,7 +27,8 @@ namespace doc {
 // Class to read bitstream into an InfoSet collection
 class ClangDocBitcodeReader {
 public:
-  ClangDocBitcodeReader(llvm::BitstreamCursor &Stream) : Stream(Stream) {}
+  ClangDocBitcodeReader(llvm::BitstreamCursor &Stream, DiagnosticsEngine 
&Diags)
+      : Stream(Stream), Diags(Diags) {}
 
   // Main entry point, calls readBlock to read each block in the given stream.
   llvm::Expected<std::vector<std::unique_ptr<Info>>> readBitcode();
@@ -72,6 +73,7 @@ class ClangDocBitcodeReader {
   llvm::BitstreamCursor &Stream;
   std::optional<llvm::BitstreamBlockInfo> BlockInfo;
   FieldId CurrentReferenceField;
+  DiagnosticsEngine &Diags;
 };
 
 } // namespace doc
diff --git a/clang-tools-extra/clang-doc/BitcodeWriter.cpp 
b/clang-tools-extra/clang-doc/BitcodeWriter.cpp
index 3a7ac6e2abcdd..650501d1d7606 100644
--- a/clang-tools-extra/clang-doc/BitcodeWriter.cpp
+++ b/clang-tools-extra/clang-doc/BitcodeWriter.cpp
@@ -769,7 +769,9 @@ bool ClangDocBitcodeWriter::dispatchInfoForWrite(Info *I) {
     emitBlock(*static_cast<FriendInfo *>(I));
     break;
   case InfoType::IT_default:
-    llvm::errs() << "Unexpected info, unable to write.\n";
+    unsigned ID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
+                                        "Unexpected info, unable to write.");
+    Diags.Report(ID);
     return true;
   }
   return false;
diff --git a/clang-tools-extra/clang-doc/BitcodeWriter.h 
b/clang-tools-extra/clang-doc/BitcodeWriter.h
index 9c1b6abe983bb..6d1b9e9a7ebf2 100644
--- a/clang-tools-extra/clang-doc/BitcodeWriter.h
+++ b/clang-tools-extra/clang-doc/BitcodeWriter.h
@@ -16,6 +16,7 @@
 #define LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_BITCODEWRITER_H
 
 #include "Representation.h"
+#include "clang/Basic/Diagnostic.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/Bitstream/BitstreamWriter.h"
 #include <vector>
@@ -175,7 +176,8 @@ enum class FieldId {
 
 class ClangDocBitcodeWriter {
 public:
-  ClangDocBitcodeWriter(llvm::BitstreamWriter &Stream) : Stream(Stream) {
+  ClangDocBitcodeWriter(llvm::BitstreamWriter &Stream, DiagnosticsEngine 
&Diags)
+      : Stream(Stream), Diags(Diags) {
     emitHeader();
     emitBlockInfoBlock();
     emitVersionBlock();
@@ -260,6 +262,7 @@ class ClangDocBitcodeWriter {
   SmallVector<uint32_t, BitCodeConstants::RecordSize> Record;
   llvm::BitstreamWriter &Stream;
   AbbreviationMap Abbrevs;
+  DiagnosticsEngine &Diags;
 };
 
 } // namespace doc
diff --git a/clang-tools-extra/clang-doc/Generators.cpp 
b/clang-tools-extra/clang-doc/Generators.cpp
index 667e5d5a318f0..c5adbb27113ba 100644
--- a/clang-tools-extra/clang-doc/Generators.cpp
+++ b/clang-tools-extra/clang-doc/Generators.cpp
@@ -121,10 +121,11 @@ Error MustacheGenerator::generateDocumentation(
 
       auto File = MemoryBuffer::getFile(Path);
       if (EC = File.getError(); EC) {
-        // TODO: Buffer errors to report later, look into using Clang
-        // diagnostics.
-        llvm::errs() << "Failed to open file: " << Path << " " << EC.message()
-                     << '\n';
+        unsigned ID = CDCtx.Diags.getCustomDiagID(DiagnosticsEngine::Warning,
+                                                  "Failed to open file: %0 
%1");
+        CDCtx.Diags.Report(ID) << Path << EC.message();
+        JSONIter.increment(EC);
+        continue;
       }
 
       auto Parsed = json::parse((*File)->getBuffer());
diff --git a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp 
b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
index c09f908c7eb22..d33b77feb84be 100644
--- a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
+++ b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
@@ -15,6 +15,7 @@
 #include "Generators.h"
 #include "Representation.h"
 #include "support/File.h"
+#include "clang/Basic/Diagnostic.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/Path.h"
 
diff --git a/clang-tools-extra/clang-doc/Mapper.cpp 
b/clang-tools-extra/clang-doc/Mapper.cpp
index 497b80cf97463..24e798af52e62 100644
--- a/clang-tools-extra/clang-doc/Mapper.cpp
+++ b/clang-tools-extra/clang-doc/Mapper.cpp
@@ -95,10 +95,10 @@ bool MapASTVisitor::mapDecl(const T *D, bool IsDefinition) {
     // this decl for some reason (e.g. we're only reporting public decls).
     if (Child)
       CDCtx.ECtx->reportResult(llvm::toHex(llvm::toStringRef(Child->USR)),
-                               serialize::serialize(Child));
+                               serialize::serialize(Child, CDCtx.Diags));
     if (Parent)
       CDCtx.ECtx->reportResult(llvm::toHex(llvm::toStringRef(Parent->USR)),
-                               serialize::serialize(Parent));
+                               serialize::serialize(Parent, CDCtx.Diags));
   }
   return true;
 }
diff --git a/clang-tools-extra/clang-doc/Representation.cpp 
b/clang-tools-extra/clang-doc/Representation.cpp
index 929112f01fb43..ffa0eaa5a0a38 100644
--- a/clang-tools-extra/clang-doc/Representation.cpp
+++ b/clang-tools-extra/clang-doc/Representation.cpp
@@ -481,10 +481,11 @@ 
ClangDocContext::ClangDocContext(tooling::ExecutionContext *ECtx,
                                  StringRef RepositoryUrl,
                                  StringRef RepositoryLinePrefix, StringRef 
Base,
                                  std::vector<std::string> UserStylesheets,
+                                 clang::DiagnosticsEngine &Diags,
                                  bool FTimeTrace)
-    : ECtx(ECtx), ProjectName(ProjectName), PublicOnly(PublicOnly),
-      FTimeTrace(FTimeTrace), OutDirectory(OutDirectory),
-      UserStylesheets(UserStylesheets), Base(Base) {
+    : ECtx(ECtx), ProjectName(ProjectName), OutDirectory(OutDirectory),
+      SourceRoot(std::string(SourceRoot)), UserStylesheets(UserStylesheets),
+      Base(Base), Diags(Diags), PublicOnly(PublicOnly), FTimeTrace(FTimeTrace) 
{
   llvm::SmallString<128> SourceRootDir(SourceRoot);
   if (SourceRoot.empty())
     // If no SourceRoot was provided the current path is used as the default
diff --git a/clang-tools-extra/clang-doc/Representation.h 
b/clang-tools-extra/clang-doc/Representation.h
index 1ae067f736476..8eba7e82c7aed 100644
--- a/clang-tools-extra/clang-doc/Representation.h
+++ b/clang-tools-extra/clang-doc/Representation.h
@@ -15,6 +15,7 @@
 #define LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_REPRESENTATION_H
 
 #include "clang/AST/Type.h"
+#include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/Specifiers.h"
 #include "clang/Tooling/Execution.h"
 #include "llvm/ADT/SmallVector.h"
@@ -598,17 +599,13 @@ llvm::Expected<std::unique_ptr<Info>>
 mergeInfos(std::vector<std::unique_ptr<Info>> &Values);
 
 struct ClangDocContext {
-  ClangDocContext() = default;
   ClangDocContext(tooling::ExecutionContext *ECtx, StringRef ProjectName,
                   bool PublicOnly, StringRef OutDirectory, StringRef 
SourceRoot,
                   StringRef RepositoryUrl, StringRef RepositoryCodeLinePrefix,
                   StringRef Base, std::vector<std::string> UserStylesheets,
-                  bool FTimeTrace = false);
+                  clang::DiagnosticsEngine &Diags, bool FTimeTrace = false);
   tooling::ExecutionContext *ECtx;
-  std::string ProjectName; // Name of project clang-doc is documenting.
-  bool PublicOnly; // Indicates if only public declarations are documented.
-  bool FTimeTrace; // Indicates if ftime trace is turned on
-  int Granularity; // Granularity of ftime trace
+  std::string ProjectName;  // Name of project clang-doc is documenting.
   std::string OutDirectory; // Directory for outputting generated files.
   std::string SourceRoot;   // Directory where processed files are stored. 
Links
                             // to definition locations will only be generated 
if
@@ -627,7 +624,12 @@ struct ClangDocContext {
   // Maps mustache template types to specific mustache template files.
   // Ex.    comment-template -> /path/to/comment-template.mustache
   llvm::StringMap<std::string> MustacheTemplates;
+  // A pointer to a DiagnosticsEngine for error reporting.
+  clang::DiagnosticsEngine &Diags;
   Index Idx;
+  int Granularity; // Granularity of ftime trace
+  bool PublicOnly; // Indicates if only public declarations are documented.
+  bool FTimeTrace; // Indicates if ftime trace is turned on
 };
 
 } // namespace doc
diff --git a/clang-tools-extra/clang-doc/Serialize.cpp 
b/clang-tools-extra/clang-doc/Serialize.cpp
index e1d60570da4ca..29f8faf94713d 100644
--- a/clang-tools-extra/clang-doc/Serialize.cpp
+++ b/clang-tools-extra/clang-doc/Serialize.cpp
@@ -337,28 +337,29 @@ static std::string getSourceCode(const Decl *D, const 
SourceRange &R) {
       .str();
 }
 
-template <typename T> static std::string serialize(T &I) {
+template <typename T>
+static std::string serialize(T &I, DiagnosticsEngine &Diags) {
   SmallString<2048> Buffer;
   llvm::BitstreamWriter Stream(Buffer);
-  ClangDocBitcodeWriter Writer(Stream);
+  ClangDocBitcodeWriter Writer(Stream, Diags);
   Writer.emitBlock(I);
   return Buffer.str().str();
 }
 
-std::string serialize(std::unique_ptr<Info> &I) {
+std::string serialize(std::unique_ptr<Info> &I, DiagnosticsEngine &Diags) {
   switch (I->IT) {
   case InfoType::IT_namespace:
-    return serialize(*static_cast<NamespaceInfo *>(I.get()));
+    return serialize(*static_cast<NamespaceInfo *>(I.get()), Diags);
   case InfoType::IT_record:
-    return serialize(*static_cast<RecordInfo *>(I.get()));
+    return serialize(*static_cast<RecordInfo *>(I.get()), Diags);
   case InfoType::IT_enum:
-    return serialize(*static_cast<EnumInfo *>(I.get()));
+    return serialize(*static_cast<EnumInfo *>(I.get()), Diags);
   case InfoType::IT_function:
-    return serialize(*static_cast<FunctionInfo *>(I.get()));
+    return serialize(*static_cast<FunctionInfo *>(I.get()), Diags);
   case InfoType::IT_concept:
-    return serialize(*static_cast<ConceptInfo *>(I.get()));
+    return serialize(*static_cast<ConceptInfo *>(I.get()), Diags);
   case InfoType::IT_variable:
-    return serialize(*static_cast<VarInfo *>(I.get()));
+    return serialize(*static_cast<VarInfo *>(I.get()), Diags);
   case InfoType::IT_friend:
   case InfoType::IT_typedef:
   case InfoType::IT_default:
diff --git a/clang-tools-extra/clang-doc/Serialize.h 
b/clang-tools-extra/clang-doc/Serialize.h
index 30ed836d57de3..cfba5c987c237 100644
--- a/clang-tools-extra/clang-doc/Serialize.h
+++ b/clang-tools-extra/clang-doc/Serialize.h
@@ -80,7 +80,7 @@ emitInfo(const VarDecl *D, const FullComment *FC, const 
Location &Loc,
 // memory (vs storing USRs directly).
 SymbolID hashUSR(llvm::StringRef USR);
 
-std::string serialize(std::unique_ptr<Info> &I);
+std::string serialize(std::unique_ptr<Info> &I, DiagnosticsEngine &Diags);
 
 } // namespace serialize
 } // namespace doc
diff --git a/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp 
b/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
index 62fa6a17df2ee..d8469bdc69818 100644
--- a/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
+++ b/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
@@ -22,6 +22,9 @@
 #include "Generators.h"
 #include "Representation.h"
 #include "support/Utils.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
 #include "clang/Tooling/AllTUsExecution.h"
 #include "clang/Tooling/CommonOptionsParser.h"
 #include "clang/Tooling/Execution.h"
@@ -206,9 +209,12 @@ static llvm::Error getDefaultAssetFiles(const char *Argv0,
 static llvm::Error getHtmlAssetFiles(const char *Argv0,
                                      clang::doc::ClangDocContext &CDCtx) {
   if (!UserAssetPath.empty() &&
-      !llvm::sys::fs::is_directory(std::string(UserAssetPath)))
-    llvm::outs() << "Asset path supply is not a directory: " << UserAssetPath
-                 << " falling back to default\n";
+      !llvm::sys::fs::is_directory(std::string(UserAssetPath))) {
+    unsigned ID = CDCtx.Diags.getCustomDiagID(
+        DiagnosticsEngine::Warning,
+        "Asset path supply is not a directory: %0 falling back to default");
+    CDCtx.Diags.Report(ID) << UserAssetPath;
+  }
   if (llvm::sys::fs::is_directory(std::string(UserAssetPath)))
     return getAssetFiles(CDCtx);
   return getDefaultAssetFiles(Argv0, CDCtx);
@@ -217,9 +223,12 @@ static llvm::Error getHtmlAssetFiles(const char *Argv0,
 static llvm::Error getMustacheHtmlFiles(const char *Argv0,
                                         clang::doc::ClangDocContext &CDCtx) {
   bool IsDir = llvm::sys::fs::is_directory(UserAssetPath);
-  if (!UserAssetPath.empty() && !IsDir)
-    llvm::outs() << "Asset path supply is not a directory: " << UserAssetPath
-                 << " falling back to default\n";
+  if (!UserAssetPath.empty() && !IsDir) {
+    unsigned ID = CDCtx.Diags.getCustomDiagID(
+        DiagnosticsEngine::Note,
+        "Asset path supply is not a directory: %0 falling back to default");
+    CDCtx.Diags.Report(ID) << UserAssetPath;
+  }
   if (IsDir) {
     getMustacheHtmlFiles(UserAssetPath, CDCtx);
     return llvm::Error::success();
@@ -255,13 +264,16 @@ sortUsrToInfo(llvm::StringMap<std::unique_ptr<doc::Info>> 
&USRToInfo) {
   }
 }
 
-static llvm::Error handleMappingFailures(llvm::Error Err) {
+static llvm::Error handleMappingFailures(DiagnosticsEngine &Diags,
+                                         llvm::Error Err) {
   if (!Err)
     return llvm::Error::success();
   if (IgnoreMappingFailures) {
-    llvm::errs() << "Error mapping decls in files. Clang-doc will ignore these 
"
-                    "files and continue:\n"
-                 << toString(std::move(Err)) << "\n";
+    unsigned ID = Diags.getCustomDiagID(
+        DiagnosticsEngine::Warning,
+        "Error mapping decls in files. Clang-doc will ignore these files and "
+        "continue:\n%0");
+    Diags.Report(ID) << toString(std::move(Err));
     return llvm::Error::success();
   }
   return Err;
@@ -313,17 +325,16 @@ Example usage for a project using a compile commands 
database:
                                     tooling::ArgumentInsertPosition::END),
           ArgAdjuster);
 
-    clang::doc::ClangDocContext CDCtx = {
-        Executor->getExecutionContext(),
-        ProjectName,
-        PublicOnly,
-        OutDirectory,
-        SourceRoot,
-        RepositoryUrl,
-        RepositoryCodeLinePrefix,
-        BaseDirectory,
-        {UserStylesheets.begin(), UserStylesheets.end()},
-        FTimeTrace};
+    auto DiagOpts = std::make_unique<DiagnosticOptions>();
+    TextDiagnosticPrinter *DiagClient =
+        new TextDiagnosticPrinter(llvm::errs(), *DiagOpts);
+    IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+    DiagnosticsEngine Diags(DiagID, *DiagOpts, DiagClient);
+
+    clang::doc::ClangDocContext CDCtx(
+        Executor->getExecutionContext(), ProjectName, PublicOnly, OutDirectory,
+        SourceRoot, RepositoryUrl, RepositoryCodeLinePrefix, BaseDirectory,
+        {UserStylesheets.begin(), UserStylesheets.end()}, Diags, FTimeTrace);
 
     if (Format == "html") {
       ExitOnErr(getHtmlAssetFiles(argv[0], CDCtx));
@@ -335,6 +346,7 @@ Example usage for a project using a compile commands 
database:
     // Mapping phase
     llvm::outs() << "Mapping decls...\n";
     ExitOnErr(handleMappingFailures(
+        Diags,
         Executor->execute(doc::newMapperActionFactory(CDCtx), ArgAdjuster)));
     llvm::timeTraceProfilerEnd();
 
@@ -360,13 +372,18 @@ Example usage for a project using a compile commands 
database:
     std::atomic<bool> Error;
     Error = false;
     llvm::sys::Mutex IndexMutex;
+    llvm::sys::Mutex DiagMutex;
+    unsigned DiagIDBitcodeReading = Diags.getCustomDiagID(
+        DiagnosticsEngine::Error, "error reading bitcode: %0");
+    unsigned DiagIDBitcodeMerging = Diags.getCustomDiagID(
+        DiagnosticsEngine::Error, "error merging bitcode: %0");
     // ExecutorConcurrency is a flag exposed by AllTUsExecution.h
     llvm::DefaultThreadPool Pool(
         llvm::hardware_concurrency(ExecutorConcurrency));
     {
       llvm::TimeTraceScope TS("Reduce");
       for (auto &Group : USRToBitcode) {
-        Pool.async([&]() { // time trace decoding bitcode
+        Pool.async([&, &Diags = Diags]() { // time trace decoding bitcode
           if (FTimeTrace)
             llvm::timeTraceProfilerInitialize(200, "clang-doc");
 
@@ -375,10 +392,13 @@ Example usage for a project using a compile commands 
database:
             llvm::TimeTraceScope Red("decoding bitcode");
             for (auto &Bitcode : Group.getValue()) {
               llvm::BitstreamCursor Stream(Bitcode);
-              doc::ClangDocBitcodeReader Reader(Stream);
+              doc::ClangDocBitcodeReader Reader(Stream, Diags);
               auto ReadInfos = Reader.readBitcode();
               if (!ReadInfos) {
-                llvm::errs() << toString(ReadInfos.takeError()) << "\n";
+                std::lock_guard<llvm::sys::Mutex> Guard(DiagMutex);
+
+                Diags.Report(DiagIDBitcodeReading)
+                    << toString(ReadInfos.takeError());
                 Error = true;
                 return;
               }
@@ -394,7 +414,9 @@ Example usage for a project using a compile commands 
database:
             auto ExpReduced = doc::mergeInfos(Infos);
 
             if (!ExpReduced) {
-              llvm::errs() << llvm::toString(ExpReduced.takeError());
+              std::lock_guard<llvm::sys::Mutex> Guard(DiagMutex);
+              Diags.Report(DiagIDBitcodeMerging)
+                  << toString(ExpReduced.takeError());
               return;
             }
             Reduced = std::move(*ExpReduced);
diff --git a/clang-tools-extra/unittests/clang-doc/BitcodeTest.cpp 
b/clang-tools-extra/unittests/clang-doc/BitcodeTest.cpp
index d88b0c91bb9a9..918c7b3eca879 100644
--- a/clang-tools-extra/unittests/clang-doc/BitcodeTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/BitcodeTest.cpp
@@ -10,6 +10,8 @@
 #include "BitcodeWriter.h"
 #include "ClangDocTest.h"
 #include "Representation.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticOptions.h"
 #include "llvm/Bitstream/BitstreamReader.h"
 #include "llvm/Bitstream/BitstreamWriter.h"
 #include "gtest/gtest.h"
@@ -17,41 +19,42 @@
 namespace clang {
 namespace doc {
 
-template <typename T> static std::string writeInfo(T &I) {
+template <typename T>
+static std::string writeInfo(T &I, DiagnosticsEngine &Diags) {
   SmallString<2048> Buffer;
   llvm::BitstreamWriter Stream(Buffer);
-  ClangDocBitcodeWriter Writer(Stream);
+  ClangDocBitcodeWriter Writer(Stream, Diags);
   Writer.emitBlock(I);
   return Buffer.str().str();
 }
 
-static std::string writeInfo(Info *I) {
+static std::string writeInfo(Info *I, DiagnosticsEngine &Diags) {
   switch (I->IT) {
   case InfoType::IT_namespace:
-    return writeInfo(*static_cast<NamespaceInfo *>(I));
+    return writeInfo(*static_cast<NamespaceInfo *>(I), Diags);
   case InfoType::IT_record:
-    return writeInfo(*static_cast<RecordInfo *>(I));
+    return writeInfo(*static_cast<RecordInfo *>(I), Diags);
   case InfoType::IT_enum:
-    return writeInfo(*static_cast<EnumInfo *>(I));
+    return writeInfo(*static_cast<EnumInfo *>(I), Diags);
   case InfoType::IT_function:
-    return writeInfo(*static_cast<FunctionInfo *>(I));
+    return writeInfo(*static_cast<FunctionInfo *>(I), Diags);
   case InfoType::IT_typedef:
-    return writeInfo(*static_cast<TypedefInfo *>(I));
+    return writeInfo(*static_cast<TypedefInfo *>(I), Diags);
   case InfoType::IT_concept:
-    return writeInfo(*static_cast<ConceptInfo *>(I));
+    return writeInfo(*static_cast<ConceptInfo *>(I), Diags);
   case InfoType::IT_variable:
-    return writeInfo(*static_cast<VarInfo *>(I));
+    return writeInfo(*static_cast<VarInfo *>(I), Diags);
   case InfoType::IT_friend:
-    return writeInfo(*static_cast<FriendInfo *>(I));
+    return writeInfo(*static_cast<FriendInfo *>(I), Diags);
   case InfoType::IT_default:
     return "";
   }
 }
 
-static std::vector<std::unique_ptr<Info>> readInfo(StringRef Bitcode,
-                                                   size_t NumInfos) {
+static std::vector<std::unique_ptr<Info>>
+readInfo(StringRef Bitcode, size_t NumInfos, DiagnosticsEngine &Diags) {
   llvm::BitstreamCursor Stream(Bitcode);
-  doc::ClangDocBitcodeReader Reader(Stream);
+  doc::ClangDocBitcodeReader Reader(Stream, Diags);
   auto Infos = Reader.readBitcode();
 
   // Check that there was no error in the read.
@@ -60,7 +63,9 @@ static std::vector<std::unique_ptr<Info>> readInfo(StringRef 
Bitcode,
   return std::move(Infos.get());
 }
 
-TEST(BitcodeTest, emitNamespaceInfoBitcode) {
+class BitcodeTest : public ClangDocContextTest {};
+
+TEST_F(BitcodeTest, emitNamespaceInfoBitcode) {
   NamespaceInfo I;
   I.Name = "r";
   I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
@@ -71,14 +76,15 @@ TEST(BitcodeTest, emitNamespaceInfoBitcode) {
   I.Children.Functions.emplace_back();
   I.Children.Enums.emplace_back();
 
-  std::string WriteResult = writeInfo(&I);
+  std::string WriteResult = writeInfo(&I, this->Diags);
   EXPECT_TRUE(WriteResult.size() > 0);
-  std::vector<std::unique_ptr<Info>> ReadResults = readInfo(WriteResult, 1);
+  std::vector<std::unique_ptr<Info>> ReadResults =
+      readInfo(WriteResult, 1, this->Diags);
 
   CheckNamespaceInfo(&I, InfoAsNamespace(ReadResults[0].get()));
 }
 
-TEST(BitcodeTest, emitRecordInfoBitcode) {
+TEST_F(BitcodeTest, emitRecordInfoBitcode) {
   RecordInfo I;
   I.Name = "r";
   I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
@@ -113,14 +119,15 @@ TEST(BitcodeTest, emitRecordInfoBitcode) {
   I.Children.Functions.emplace_back();
   I.Children.Enums.emplace_back();
 
-  std::string WriteResult = writeInfo(&I);
+  std::string WriteResult = writeInfo(&I, this->Diags);
   EXPECT_TRUE(WriteResult.size() > 0);
-  std::vector<std::unique_ptr<Info>> ReadResults = readInfo(WriteResult, 1);
+  std::vector<std::unique_ptr<Info>> ReadResults =
+      readInfo(WriteResult, 1, this->Diags);
 
   CheckRecordInfo(&I, InfoAsRecord(ReadResults[0].get()));
 }
 
-TEST(BitcodeTest, emitFunctionInfoBitcode) {
+TEST_F(BitcodeTest, emitFunctionInfoBitcode) {
   FunctionInfo I;
   I.Name = "f";
   I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
@@ -133,14 +140,15 @@ TEST(BitcodeTest, emitFunctionInfoBitcode) {
 
   I.Access = AccessSpecifier::AS_none;
 
-  std::string WriteResult = writeInfo(&I);
+  std::string WriteResult = writeInfo(&I, this->Diags);
   EXPECT_TRUE(WriteResult.size() > 0);
-  std::vector<std::unique_ptr<Info>> ReadResults = readInfo(WriteResult, 1);
+  std::vector<std::unique_ptr<Info>> ReadResults =
+      readInfo(WriteResult, 1, this->Diags);
 
   CheckFunctionInfo(&I, InfoAsFunction(ReadResults[0].get()));
 }
 
-TEST(BitcodeTest, emitMethodInfoBitcode) {
+TEST_F(BitcodeTest, emitMethodInfoBitcode) {
   FunctionInfo I;
   I.Name = "f";
   I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
@@ -155,14 +163,15 @@ TEST(BitcodeTest, emitMethodInfoBitcode) {
 
   I.Access = AccessSpecifier::AS_public;
 
-  std::string WriteResult = writeInfo(&I);
+  std::string WriteResult = writeInfo(&I, this->Diags);
   EXPECT_TRUE(WriteResult.size() > 0);
-  std::vector<std::unique_ptr<Info>> ReadResults = readInfo(WriteResult, 1);
+  std::vector<std::unique_ptr<Info>> ReadResults =
+      readInfo(WriteResult, 1, this->Diags);
 
   CheckFunctionInfo(&I, InfoAsFunction(ReadResults[0].get()));
 }
 
-TEST(BitcodeTest, emitEnumInfoBitcode) {
+TEST_F(BitcodeTest, emitEnumInfoBitcode) {
   EnumInfo I;
   I.Name = "e";
   I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
@@ -173,14 +182,15 @@ TEST(BitcodeTest, emitEnumInfoBitcode) {
   I.Members.emplace_back("X");
   I.Scoped = true;
 
-  std::string WriteResult = writeInfo(&I);
+  std::string WriteResult = writeInfo(&I, this->Diags);
   EXPECT_TRUE(WriteResult.size() > 0);
-  std::vector<std::unique_ptr<Info>> ReadResults = readInfo(WriteResult, 1);
+  std::vector<std::unique_ptr<Info>> ReadResults =
+      readInfo(WriteResult, 1, this->Diags);
 
   CheckEnumInfo(&I, InfoAsEnum(ReadResults[0].get()));
 }
 
-TEST(BitcodeTest, emitTypedefInfoBitcode) {
+TEST_F(BitcodeTest, emitTypedefInfoBitcode) {
   TypedefInfo I;
   I.Name = "MyInt";
   I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
@@ -200,9 +210,10 @@ TEST(BitcodeTest, emitTypedefInfoBitcode) {
 
   I.Description.emplace_back(std::move(Top));
 
-  std::string WriteResult = writeInfo(&I);
+  std::string WriteResult = writeInfo(&I, this->Diags);
   EXPECT_TRUE(WriteResult.size() > 0);
-  std::vector<std::unique_ptr<Info>> ReadResults = readInfo(WriteResult, 1);
+  std::vector<std::unique_ptr<Info>> ReadResults =
+      readInfo(WriteResult, 1, this->Diags);
 
   CheckTypedefInfo(&I, InfoAsTypedef(ReadResults[0].get()));
 
@@ -212,13 +223,13 @@ TEST(BitcodeTest, emitTypedefInfoBitcode) {
   I2.IsUsing = false;
   I2.Underlying = TypeInfo("int");
 
-  WriteResult = writeInfo(&I2);
+  WriteResult = writeInfo(&I2, this->Diags);
   EXPECT_TRUE(WriteResult.size() > 0);
-  ReadResults = readInfo(WriteResult, 1);
+  ReadResults = readInfo(WriteResult, 1, this->Diags);
   CheckTypedefInfo(&I2, InfoAsTypedef(ReadResults[0].get()));
 }
 
-TEST(SerializeTest, emitInfoWithCommentBitcode) {
+TEST_F(BitcodeTest, emitInfoWithCommentBitcode) {
   FunctionInfo F;
   F.Name = "F";
   F.ReturnType = TypeInfo("void");
@@ -329,9 +340,10 @@ TEST(SerializeTest, emitInfoWithCommentBitcode) {
 
   F.Description.emplace_back(std::move(Top));
 
-  std::string WriteResult = writeInfo(&F);
+  std::string WriteResult = writeInfo(&F, this->Diags);
   EXPECT_TRUE(WriteResult.size() > 0);
-  std::vector<std::unique_ptr<Info>> ReadResults = readInfo(WriteResult, 1);
+  std::vector<std::unique_ptr<Info>> ReadResults =
+      readInfo(WriteResult, 1, this->Diags);
 
   CheckFunctionInfo(&F, InfoAsFunction(ReadResults[0].get()));
 }
diff --git a/clang-tools-extra/unittests/clang-doc/ClangDocTest.cpp 
b/clang-tools-extra/unittests/clang-doc/ClangDocTest.cpp
index f408c91077f6b..73891abd53f99 100644
--- a/clang-tools-extra/unittests/clang-doc/ClangDocTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/ClangDocTest.cpp
@@ -9,11 +9,26 @@
 #include "ClangDocTest.h"
 #include "Representation.h"
 #include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Basic/DiagnosticOptions.h"
 #include "gtest/gtest.h"
 
 namespace clang {
 namespace doc {
 
+ClangDocContextTest::ClangDocContextTest()
+    : DiagID(new DiagnosticIDs()),
+      Diags(DiagID, DiagOpts, new IgnoringDiagConsumer()) {}
+
+ClangDocContextTest::~ClangDocContextTest() = default;
+
+ClangDocContext ClangDocContextTest::getClangDocContext(
+    std::vector<std::string> UserStylesheets, StringRef RepositoryUrl,
+    StringRef RepositoryLinePrefix, StringRef Base) {
+  return ClangDocContext(nullptr, "test-project", false, "", "", RepositoryUrl,
+                         RepositoryLinePrefix, Base, UserStylesheets, Diags,
+                         false);
+}
+
 NamespaceInfo *InfoAsNamespace(Info *I) {
   assert(I->IT == InfoType::IT_namespace);
   return static_cast<NamespaceInfo *>(I);
diff --git a/clang-tools-extra/unittests/clang-doc/ClangDocTest.h 
b/clang-tools-extra/unittests/clang-doc/ClangDocTest.h
index 2e189caa48650..2875cf1cb2d6a 100644
--- a/clang-tools-extra/unittests/clang-doc/ClangDocTest.h
+++ b/clang-tools-extra/unittests/clang-doc/ClangDocTest.h
@@ -12,6 +12,8 @@
 #include "ClangDocTest.h"
 #include "Representation.h"
 #include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticOptions.h"
 #include "gtest/gtest.h"
 
 namespace clang {
@@ -49,6 +51,21 @@ void CheckBaseRecordInfo(BaseRecordInfo *Expected, 
BaseRecordInfo *Actual);
 
 void CheckIndex(Index &Expected, Index &Actual);
 
+class ClangDocContextTest : public ::testing::Test {
+protected:
+  ClangDocContextTest();
+  ~ClangDocContextTest() override;
+
+  ClangDocContext
+  getClangDocContext(std::vector<std::string> UserStylesheets = {},
+                     StringRef RepositoryUrl = "",
+                     StringRef RepositoryLinePrefix = "", StringRef Base = "");
+
+  DiagnosticOptions DiagOpts;
+  llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
+  DiagnosticsEngine Diags;
+};
+
 } // namespace doc
 } // namespace clang
 
diff --git a/clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp 
b/clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp
index 143414354d36c..2fe443d9db5c5 100644
--- a/clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp
@@ -25,21 +25,32 @@ static std::unique_ptr<Generator> getHTMLGenerator() {
   return std::move(G.get());
 }
 
-static ClangDocContext
-getClangDocContext(std::vector<std::string> UserStylesheets = {},
-                   StringRef RepositoryUrl = "",
-                   StringRef RepositoryLinePrefix = "", StringRef Base = "") {
-  ClangDocContext CDCtx{
-      {},   "test-project", {}, {}, {}, RepositoryUrl, RepositoryLinePrefix,
-      Base, UserStylesheets};
-  CDCtx.UserStylesheets.insert(
-      CDCtx.UserStylesheets.begin(),
-      "../share/clang/clang-doc-default-stylesheet.css");
-  CDCtx.JsScripts.emplace_back("index.js");
-  return CDCtx;
-}
-
-TEST(HTMLGeneratorTest, emitNamespaceHTML) {
+class HTMLGeneratorTest : public ClangDocContextTest {
+protected:
+  ClangDocContext
+  getClangDocContext(std::vector<std::string> UserStylesheets = {},
+                     StringRef RepositoryUrl = "",
+                     StringRef RepositoryLinePrefix = "", StringRef Base = "") 
{
+    ClangDocContext CDCtx{nullptr,
+                          "test-project",
+                          false,
+                          "",
+                          "",
+                          RepositoryUrl,
+                          RepositoryLinePrefix,
+                          Base,
+                          UserStylesheets,
+                          Diags,
+                          false};
+    CDCtx.UserStylesheets.insert(
+        CDCtx.UserStylesheets.begin(),
+        "../share/clang/clang-doc-default-stylesheet.css");
+    CDCtx.JsScripts.emplace_back("index.js");
+    return CDCtx;
+  }
+};
+
+TEST_F(HTMLGeneratorTest, emitNamespaceHTML) {
   NamespaceInfo I;
   I.Name = "Namespace";
   I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
@@ -150,7 +161,7 @@ TEST(HTMLGeneratorTest, emitNamespaceHTML) {
   EXPECT_EQ(Expected, Actual.str());
 }
 
-TEST(HTMLGeneratorTest, emitRecordHTML) {
+TEST_F(HTMLGeneratorTest, emitRecordHTML) {
   RecordInfo I;
   I.Name = "r";
   I.Path = "X/Y/Z";
@@ -278,7 +289,7 @@ TEST(HTMLGeneratorTest, emitRecordHTML) {
   EXPECT_EQ(Expected, Actual.str());
 }
 
-TEST(HTMLGeneratorTest, emitFunctionHTML) {
+TEST_F(HTMLGeneratorTest, emitFunctionHTML) {
   FunctionInfo I;
   I.Name = "f";
   I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
@@ -338,7 +349,7 @@ TEST(HTMLGeneratorTest, emitFunctionHTML) {
   EXPECT_EQ(Expected, Actual.str());
 }
 
-TEST(HTMLGeneratorTest, emitEnumHTML) {
+TEST_F(HTMLGeneratorTest, emitEnumHTML) {
   EnumInfo I;
   I.Name = "e";
   I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
@@ -397,7 +408,7 @@ TEST(HTMLGeneratorTest, emitEnumHTML) {
   EXPECT_EQ(Expected, Actual.str());
 }
 
-TEST(HTMLGeneratorTest, emitCommentHTML) {
+TEST_F(HTMLGeneratorTest, emitCommentHTML) {
   FunctionInfo I;
   I.Name = "f";
   I.DefLoc = Location(10, 10, "test.cpp", true);
diff --git 
a/clang-tools-extra/unittests/clang-doc/HTMLMustacheGeneratorTest.cpp 
b/clang-tools-extra/unittests/clang-doc/HTMLMustacheGeneratorTest.cpp
index c7ac387ecf7c3..7bbd299d7b59c 100644
--- a/clang-tools-extra/unittests/clang-doc/HTMLMustacheGeneratorTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/HTMLMustacheGeneratorTest.cpp
@@ -34,19 +34,30 @@ static std::unique_ptr<Generator> 
getHTMLMustacheGenerator() {
   return std::move(G.get());
 }
 
-static ClangDocContext
-getClangDocContext(std::vector<std::string> UserStylesheets = {},
-                   StringRef RepositoryUrl = "",
-                   StringRef RepositoryLinePrefix = "", StringRef Base = "") {
-  ClangDocContext CDCtx{
-      {},   "test-project", {}, {}, {}, RepositoryUrl, RepositoryLinePrefix,
-      Base, UserStylesheets};
-  CDCtx.UserStylesheets.insert(CDCtx.UserStylesheets.begin(), "");
-  CDCtx.JsScripts.emplace_back("");
-  return CDCtx;
-}
+class HTMLMustacheGeneratorTest : public ClangDocContextTest {
+protected:
+  ClangDocContext
+  getClangDocContext(std::vector<std::string> UserStylesheets = {},
+                     StringRef RepositoryUrl = "",
+                     StringRef RepositoryLinePrefix = "", StringRef Base = "") 
{
+    ClangDocContext CDCtx{nullptr,
+                          "test-project",
+                          false,
+                          "",
+                          "",
+                          RepositoryUrl,
+                          RepositoryLinePrefix,
+                          Base,
+                          UserStylesheets,
+                          Diags,
+                          false};
+    CDCtx.UserStylesheets.insert(CDCtx.UserStylesheets.begin(), "");
+    CDCtx.JsScripts.emplace_back("");
+    return CDCtx;
+  }
+};
 
-TEST(HTMLMustacheGeneratorTest, createResources) {
+TEST_F(HTMLMustacheGeneratorTest, createResources) {
   auto G = getHTMLMustacheGenerator();
   ASSERT_THAT(G, NotNull()) << "Could not find HTMLMustacheGenerator";
   ClangDocContext CDCtx = getClangDocContext();
diff --git a/clang-tools-extra/unittests/clang-doc/JSONGeneratorTest.cpp 
b/clang-tools-extra/unittests/clang-doc/JSONGeneratorTest.cpp
index 2706a5145ebfd..bd437553961f6 100644
--- a/clang-tools-extra/unittests/clang-doc/JSONGeneratorTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/JSONGeneratorTest.cpp
@@ -13,7 +13,9 @@ static std::unique_ptr<Generator> getJSONGenerator() {
   return std::move(G.get());
 }
 
-TEST(JSONGeneratorTest, emitRecordJSON) {
+class JSONGeneratorTest : public ClangDocContextTest {};
+
+TEST_F(JSONGeneratorTest, emitRecordJSON) {
   RecordInfo I;
   I.Name = "Foo";
   I.IsTypeDef = false;
@@ -55,7 +57,7 @@ TEST(JSONGeneratorTest, emitRecordJSON) {
   assert(G);
   std::string Buffer;
   llvm::raw_string_ostream Actual(Buffer);
-  auto Err = G->generateDocForInfo(&I, Actual, ClangDocContext());
+  auto Err = G->generateDocForInfo(&I, Actual, getClangDocContext());
   assert(!Err);
   std::string Expected = R"raw({
   "Bases": [
@@ -186,7 +188,7 @@ TEST(JSONGeneratorTest, emitRecordJSON) {
   EXPECT_EQ(Expected, Actual.str());
 }
 
-TEST(JSONGeneratorTest, emitNamespaceJSON) {
+TEST_F(JSONGeneratorTest, emitNamespaceJSON) {
   NamespaceInfo I;
   I.Name = "Namespace";
   I.Path = "path/to/A";
@@ -208,7 +210,7 @@ TEST(JSONGeneratorTest, emitNamespaceJSON) {
   assert(G);
   std::string Buffer;
   llvm::raw_string_ostream Actual(Buffer);
-  auto Err = G->generateDocForInfo(&I, Actual, ClangDocContext());
+  auto Err = G->generateDocForInfo(&I, Actual, getClangDocContext());
   assert(!Err);
   std::string Expected = R"raw({
   "Enums": [
diff --git a/clang-tools-extra/unittests/clang-doc/MDGeneratorTest.cpp 
b/clang-tools-extra/unittests/clang-doc/MDGeneratorTest.cpp
index f4c69cf868a1f..b44b09b28e90f 100644
--- a/clang-tools-extra/unittests/clang-doc/MDGeneratorTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/MDGeneratorTest.cpp
@@ -21,7 +21,9 @@ static std::unique_ptr<Generator> getMDGenerator() {
   return std::move(G.get());
 }
 
-TEST(MDGeneratorTest, emitNamespaceMD) {
+class MDGeneratorTest : public ClangDocContextTest {};
+
+TEST_F(MDGeneratorTest, emitNamespaceMD) {
   NamespaceInfo I;
   I.Name = "Namespace";
   I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
@@ -39,7 +41,7 @@ TEST(MDGeneratorTest, emitNamespaceMD) {
   assert(G);
   std::string Buffer;
   llvm::raw_string_ostream Actual(Buffer);
-  auto Err = G->generateDocForInfo(&I, Actual, ClangDocContext());
+  auto Err = G->generateDocForInfo(&I, Actual, getClangDocContext());
   assert(!Err);
   std::string Expected = R"raw(# namespace Namespace
 
@@ -77,7 +79,7 @@ TEST(MDGeneratorTest, emitNamespaceMD) {
   EXPECT_EQ(Expected, Actual.str());
 }
 
-TEST(MDGeneratorTest, emitRecordMD) {
+TEST_F(MDGeneratorTest, emitRecordMD) {
   RecordInfo I;
   I.Name = "r";
   I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
@@ -100,7 +102,7 @@ TEST(MDGeneratorTest, emitRecordMD) {
   assert(G);
   std::string Buffer;
   llvm::raw_string_ostream Actual(Buffer);
-  auto Err = G->generateDocForInfo(&I, Actual, ClangDocContext());
+  auto Err = G->generateDocForInfo(&I, Actual, getClangDocContext());
   assert(!Err);
   std::string Expected = R"raw(# class r
 
@@ -144,7 +146,7 @@ ChildStruct
   EXPECT_EQ(Expected, Actual.str());
 }
 
-TEST(MDGeneratorTest, emitFunctionMD) {
+TEST_F(MDGeneratorTest, emitFunctionMD) {
   FunctionInfo I;
   I.Name = "f";
   I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
@@ -163,7 +165,7 @@ TEST(MDGeneratorTest, emitFunctionMD) {
   assert(G);
   std::string Buffer;
   llvm::raw_string_ostream Actual(Buffer);
-  auto Err = G->generateDocForInfo(&I, Actual, ClangDocContext());
+  auto Err = G->generateDocForInfo(&I, Actual, getClangDocContext());
   assert(!Err);
   std::string Expected = R"raw(### f
 
@@ -176,7 +178,7 @@ TEST(MDGeneratorTest, emitFunctionMD) {
   EXPECT_EQ(Expected, Actual.str());
 }
 
-TEST(MDGeneratorTest, emitEnumMD) {
+TEST_F(MDGeneratorTest, emitEnumMD) {
   EnumInfo I;
   I.Name = "e";
   I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
@@ -191,7 +193,7 @@ TEST(MDGeneratorTest, emitEnumMD) {
   assert(G);
   std::string Buffer;
   llvm::raw_string_ostream Actual(Buffer);
-  auto Err = G->generateDocForInfo(&I, Actual, ClangDocContext());
+  auto Err = G->generateDocForInfo(&I, Actual, getClangDocContext());
   assert(!Err);
   std::string Expected = R"raw(| enum class e |
 
@@ -207,7 +209,7 @@ TEST(MDGeneratorTest, emitEnumMD) {
   EXPECT_EQ(Expected, Actual.str());
 }
 
-TEST(MDGeneratorTest, emitCommentMD) {
+TEST_F(MDGeneratorTest, emitCommentMD) {
   FunctionInfo I;
   I.Name = "f";
 
@@ -325,7 +327,7 @@ TEST(MDGeneratorTest, emitCommentMD) {
   assert(G);
   std::string Buffer;
   llvm::raw_string_ostream Actual(Buffer);
-  auto Err = G->generateDocForInfo(&I, Actual, ClangDocContext());
+  auto Err = G->generateDocForInfo(&I, Actual, getClangDocContext());
   assert(!Err);
   std::string Expected =
       R"raw(### f
diff --git a/clang-tools-extra/unittests/clang-doc/MergeTest.cpp 
b/clang-tools-extra/unittests/clang-doc/MergeTest.cpp
index ade744e58ab0d..6bffd98d3e4e8 100644
--- a/clang-tools-extra/unittests/clang-doc/MergeTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/MergeTest.cpp
@@ -13,7 +13,9 @@
 namespace clang {
 namespace doc {
 
-TEST(MergeTest, mergeNamespaceInfos) {
+class MergeTest : public ClangDocContextTest {};
+
+TEST_F(MergeTest, mergeNamespaceInfos) {
   NamespaceInfo One;
   One.Name = "Namespace";
   One.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
@@ -75,7 +77,7 @@ TEST(MergeTest, mergeNamespaceInfos) {
                      InfoAsNamespace(Actual.get().get()));
 }
 
-TEST(MergeTest, mergeRecordInfos) {
+TEST_F(MergeTest, mergeRecordInfos) {
   RecordInfo One;
   One.Name = "r";
   One.IsTypeDef = true;
@@ -153,7 +155,7 @@ TEST(MergeTest, mergeRecordInfos) {
                   InfoAsRecord(Actual.get().get()));
 }
 
-TEST(MergeTest, mergeFunctionInfos) {
+TEST_F(MergeTest, mergeFunctionInfos) {
   FunctionInfo One;
   One.Name = "f";
   One.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
@@ -228,7 +230,7 @@ TEST(MergeTest, mergeFunctionInfos) {
                     InfoAsFunction(Actual.get().get()));
 }
 
-TEST(MergeTest, mergeEnumInfos) {
+TEST_F(MergeTest, mergeEnumInfos) {
   EnumInfo One;
   One.Name = "e";
   One.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
diff --git a/clang-tools-extra/unittests/clang-doc/SerializeTest.cpp 
b/clang-tools-extra/unittests/clang-doc/SerializeTest.cpp
index 6d5e7da689c5c..f59ea02f9e1a3 100644
--- a/clang-tools-extra/unittests/clang-doc/SerializeTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/SerializeTest.cpp
@@ -16,6 +16,8 @@
 namespace clang {
 namespace doc {
 
+class SerializeTest : public ClangDocContextTest {};
+
 class ClangDocSerializeTestVisitor
     : public RecursiveASTVisitor<ClangDocSerializeTestVisitor> {
 
@@ -32,7 +34,8 @@ class ClangDocSerializeTestVisitor
   }
 
 public:
-  ClangDocSerializeTestVisitor(EmittedInfoList &EmittedInfos, bool Public)
+  ClangDocSerializeTestVisitor(EmittedInfoList &EmittedInfos, bool Public,
+                               DiagnosticsEngine &Diags)
       : EmittedInfos(EmittedInfos), Public(Public) {}
 
   template <typename T> bool mapDecl(const T *D) {
@@ -49,7 +52,7 @@ class ClangDocSerializeTestVisitor
 
   bool VisitFunctionDecl(const FunctionDecl *D) {
     // Don't visit CXXMethodDecls twice
-    if (dyn_cast<CXXMethodDecl>(D))
+    if (isa<CXXMethodDecl>(D))
       return true;
     return mapDecl(D);
   }
@@ -65,21 +68,24 @@ class ClangDocSerializeTestVisitor
   bool VisitTypeAliasDecl(const TypeAliasDecl *D) { return mapDecl(D); }
 };
 
-void ExtractInfosFromCode(StringRef Code, size_t NumExpectedInfos, bool Public,
-                          EmittedInfoList &EmittedInfos) {
+static void extractInfosFromCode(StringRef Code, size_t NumExpectedInfos,
+                                 bool Public, EmittedInfoList &EmittedInfos,
+                                 DiagnosticsEngine &Diags) {
   auto ASTUnit = clang::tooling::buildASTFromCode(Code);
-  auto TU = ASTUnit->getASTContext().getTranslationUnitDecl();
-  ClangDocSerializeTestVisitor Visitor(EmittedInfos, Public);
+  TranslationUnitDecl *TU = ASTUnit->getASTContext().getTranslationUnitDecl();
+  ClangDocSerializeTestVisitor Visitor(EmittedInfos, Public, Diags);
   Visitor.TraverseTranslationUnitDecl(TU);
   ASSERT_EQ(NumExpectedInfos, EmittedInfos.size());
 }
 
-void ExtractInfosFromCodeWithArgs(StringRef Code, size_t NumExpectedInfos,
-                                  bool Public, EmittedInfoList &EmittedInfos,
-                                  std::vector<std::string> &Args) {
+static void extractInfosFromCodeWithArgs(StringRef Code,
+                                         size_t NumExpectedInfos, bool Public,
+                                         EmittedInfoList &EmittedInfos,
+                                         std::vector<std::string> &Args,
+                                         DiagnosticsEngine &Diags) {
   auto ASTUnit = clang::tooling::buildASTFromCodeWithArgs(Code, Args);
-  auto TU = ASTUnit->getASTContext().getTranslationUnitDecl();
-  ClangDocSerializeTestVisitor Visitor(EmittedInfos, Public);
+  TranslationUnitDecl *TU = ASTUnit->getASTContext().getTranslationUnitDecl();
+  ClangDocSerializeTestVisitor Visitor(EmittedInfos, Public, Diags);
   Visitor.TraverseTranslationUnitDecl(TU);
   ASSERT_EQ(NumExpectedInfos, EmittedInfos.size());
 }
@@ -105,10 +111,10 @@ CommentInfo MakeOneLineCommentInfo(const std::string 
&Text) {
 */
 
 // Test serialization of namespace declarations.
-TEST(SerializeTest, emitNamespaceInfo) {
+TEST_F(SerializeTest, emitNamespaceInfo) {
   EmittedInfoList Infos;
-  ExtractInfosFromCode("namespace A { namespace B { void f() {} } }", 5,
-                       /*Public=*/false, Infos);
+  extractInfosFromCode("namespace A { namespace B { void f() {} } }", 5,
+                       /*Public=*/false, Infos, this->Diags);
 
   NamespaceInfo *A = InfoAsNamespace(Infos[0].get());
   NamespaceInfo ExpectedA(EmptySID, "A");
@@ -132,9 +138,10 @@ TEST(SerializeTest, emitNamespaceInfo) {
   CheckNamespaceInfo(&ExpectedBWithFunction, BWithFunction);
 }
 
-TEST(SerializeTest, emitAnonymousNamespaceInfo) {
+TEST_F(SerializeTest, emitAnonymousNamespaceInfo) {
   EmittedInfoList Infos;
-  ExtractInfosFromCode("namespace { }", 2, /*Public=*/false, Infos);
+  extractInfosFromCode("namespace { }", 2, /*Public=*/false, Infos,
+                       this->Diags);
 
   NamespaceInfo *A = InfoAsNamespace(Infos[0].get());
   NamespaceInfo ExpectedA(EmptySID);
@@ -142,10 +149,9 @@ TEST(SerializeTest, emitAnonymousNamespaceInfo) {
   CheckNamespaceInfo(&ExpectedA, A);
 }
 
-// Test serialization of record declarations.
-TEST(SerializeTest, emitRecordInfo) {
+TEST_F(SerializeTest, emitRecordInfo) {
   EmittedInfoList Infos;
-  ExtractInfosFromCode(R"raw(class E {
+  extractInfosFromCode(R"raw(class E {
 public:
   E() {}
 
@@ -161,7 +167,7 @@ struct F {
 template <>
 void F<int>::TemplateMethod();
 typedef struct {} G;)raw",
-                       10, /*Public=*/false, Infos);
+                       10, /*Public=*/false, Infos, this->Diags);
 
   RecordInfo *E = InfoAsRecord(Infos[0].get());
   RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace");
@@ -259,10 +265,10 @@ typedef struct {} G;)raw",
 }
 
 // Test serialization of enum declarations.
-TEST(SerializeTest, emitEnumInfo) {
+TEST_F(SerializeTest, emitEnumInfo) {
   EmittedInfoList Infos;
-  ExtractInfosFromCode("enum E { X, Y }; enum class G { A, B };", 2,
-                       /*Public=*/false, Infos);
+  extractInfosFromCode("enum E { X, Y }; enum class G { A, B };", 2,
+                       /*Public=*/false, Infos, this->Diags);
 
   NamespaceInfo *NamespaceWithEnum = InfoAsNamespace(Infos[0].get());
   NamespaceInfo ExpectedNamespaceWithEnum(EmptySID);
@@ -286,9 +292,9 @@ TEST(SerializeTest, emitEnumInfo) {
   CheckNamespaceInfo(&ExpectedNamespaceWithScopedEnum, 
NamespaceWithScopedEnum);
 }
 
-TEST(SerializeTest, emitUndefinedRecordInfo) {
+TEST_F(SerializeTest, emitUndefinedRecordInfo) {
   EmittedInfoList Infos;
-  ExtractInfosFromCode("class E;", 2, /*Public=*/false, Infos);
+  extractInfosFromCode("class E;", 2, /*Public=*/false, Infos, this->Diags);
 
   RecordInfo *E = InfoAsRecord(Infos[0].get());
   RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace");
@@ -299,9 +305,10 @@ TEST(SerializeTest, emitUndefinedRecordInfo) {
   CheckRecordInfo(&ExpectedE, E);
 }
 
-TEST(SerializeTest, emitRecordMemberInfo) {
+TEST_F(SerializeTest, emitRecordMemberInfo) {
   EmittedInfoList Infos;
-  ExtractInfosFromCode("struct E { int I; };", 2, /*Public=*/false, Infos);
+  extractInfosFromCode("struct E { int I; };", 2, /*Public=*/false, Infos,
+                       this->Diags);
 
   RecordInfo *E = InfoAsRecord(Infos[0].get());
   RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace");
@@ -314,9 +321,10 @@ TEST(SerializeTest, emitRecordMemberInfo) {
   CheckRecordInfo(&ExpectedE, E);
 }
 
-TEST(SerializeTest, emitInternalRecordInfo) {
+TEST_F(SerializeTest, emitInternalRecordInfo) {
   EmittedInfoList Infos;
-  ExtractInfosFromCode("class E { class G {}; };", 4, /*Public=*/false, Infos);
+  extractInfosFromCode("class E { class G {}; };", 4, /*Public=*/false, Infos,
+                       this->Diags);
 
   RecordInfo *E = InfoAsRecord(Infos[0].get());
   RecordInfo ExpectedE(EmptySID, /*Name=*/"E", /*Path=*/"GlobalNamespace");
@@ -338,15 +346,16 @@ TEST(SerializeTest, emitInternalRecordInfo) {
   CheckRecordInfo(&ExpectedG, G);
 }
 
-TEST(SerializeTest, emitPublicAnonymousNamespaceInfo) {
+TEST_F(SerializeTest, emitPublicAnonymousNamespaceInfo) {
   EmittedInfoList Infos;
-  ExtractInfosFromCode("namespace { class A; }", 0, /*Public=*/true, Infos);
+  extractInfosFromCode("namespace { class A; }", 0, /*Public=*/true, Infos,
+                       this->Diags);
 }
 
-TEST(SerializeTest, emitPublicFunctionInternalInfo) {
+TEST_F(SerializeTest, emitPublicFunctionInternalInfo) {
   EmittedInfoList Infos;
-  ExtractInfosFromCode("int F() { class G {}; return 0; };", 1, 
/*Public=*/true,
-                       Infos);
+  extractInfosFromCode("int F() { class G {}; return 0; };", 1, 
/*Public=*/true,
+                       Infos, this->Diags);
 
   NamespaceInfo *BWithFunction = InfoAsNamespace(Infos[0].get());
   NamespaceInfo ExpectedBWithFunction(EmptySID);
@@ -359,9 +368,10 @@ TEST(SerializeTest, emitPublicFunctionInternalInfo) {
   CheckNamespaceInfo(&ExpectedBWithFunction, BWithFunction);
 }
 
-TEST(SerializeTest, emitInlinedFunctionInfo) {
+TEST_F(SerializeTest, emitInlinedFunctionInfo) {
   EmittedInfoList Infos;
-  ExtractInfosFromCode("inline void F(int I) { };", 1, /*Public=*/true, Infos);
+  extractInfosFromCode("inline void F(int I) { };", 1, /*Public=*/true, Infos,
+                       this->Diags);
 
   NamespaceInfo *BWithFunction = InfoAsNamespace(Infos[0].get());
   NamespaceInfo ExpectedBWithFunction(EmptySID);
@@ -375,16 +385,16 @@ TEST(SerializeTest, emitInlinedFunctionInfo) {
   CheckNamespaceInfo(&ExpectedBWithFunction, BWithFunction);
 }
 
-TEST(SerializeTest, emitInheritedRecordInfo) {
+TEST_F(SerializeTest, emitInheritedRecordInfo) {
   EmittedInfoList Infos;
-  ExtractInfosFromCode(R"raw(class F { protected: void set(int N); };
+  extractInfosFromCode(R"raw(class F { protected: void set(int N); };
 class G { public: int get() { return 1; } protected: int I; };
 class E : public F, virtual private G {};
 class H : private E {};
 template <typename T>
 class I {} ;
 class J : public I<int> {} ;)raw",
-                       14, /*Public=*/false, Infos);
+                       14, /*Public=*/false, Infos, this->Diags);
 
   RecordInfo *F = InfoAsRecord(Infos[0].get());
   RecordInfo ExpectedF(EmptySID, /*Name=*/"F", /*Path=*/"GlobalNamespace");
@@ -517,15 +527,15 @@ class J : public I<int> {} ;)raw",
   CheckRecordInfo(&ExpectedJ, J);
 }
 
-TEST(SerializeTest, emitModulePublicLFunctions) {
+TEST_F(SerializeTest, emitModulePublicLFunctions) {
   EmittedInfoList Infos;
   std::vector<std::string> Args;
   Args.push_back("-fmodules-ts");
-  ExtractInfosFromCodeWithArgs(R"raw(export module M;
+  extractInfosFromCodeWithArgs(R"raw(export module M;
 int moduleFunction(int x, double d = 3.2 - 1.0);
 static int staticModuleFunction(int x);
 export double exportedModuleFunction(double y);)raw",
-                               2, /*Public=*/true, Infos, Args);
+                               2, /*Public=*/true, Infos, Args, this->Diags);
 
   NamespaceInfo *BWithFunction = InfoAsNamespace(Infos[0].get());
   NamespaceInfo ExpectedBWithFunction(EmptySID);
@@ -555,10 +565,10 @@ export double exportedModuleFunction(double y);)raw",
 }
 
 // Test serialization of child records in namespaces and other records
-TEST(SerializeTest, emitChildRecords) {
+TEST_F(SerializeTest, emitChildRecords) {
   EmittedInfoList Infos;
-  ExtractInfosFromCode("class A { class B {}; }; namespace { class C {}; } ", 
8,
-                       /*Public=*/false, Infos);
+  extractInfosFromCode("class A { class B {}; }; namespace { class C {}; } ", 
8,
+                       /*Public=*/false, Infos, this->Diags);
 
   NamespaceInfo *ParentA = InfoAsNamespace(Infos[1].get());
   NamespaceInfo ExpectedParentA(EmptySID);
@@ -582,10 +592,10 @@ TEST(SerializeTest, emitChildRecords) {
 }
 
 // Test serialization of child namespaces
-TEST(SerializeTest, emitChildNamespaces) {
+TEST_F(SerializeTest, emitChildNamespaces) {
   EmittedInfoList Infos;
-  ExtractInfosFromCode("namespace A { namespace B { } }", 4, /*Public=*/false,
-                       Infos);
+  extractInfosFromCode("namespace A { namespace B { } }", 4, /*Public=*/false,
+                       Infos, this->Diags);
 
   NamespaceInfo *ParentA = InfoAsNamespace(Infos[1].get());
   NamespaceInfo ExpectedParentA(EmptySID);
@@ -600,10 +610,10 @@ TEST(SerializeTest, emitChildNamespaces) {
   CheckNamespaceInfo(&ExpectedParentB, ParentB);
 }
 
-TEST(SerializeTests, emitTypedefs) {
+TEST_F(SerializeTest, emitTypedefs) {
   EmittedInfoList Infos;
-  ExtractInfosFromCode("typedef int MyInt; using MyDouble = double;", 2,
-                       /*Public=*/false, Infos);
+  extractInfosFromCode("typedef int MyInt; using MyDouble = double;", 2,
+                       /*Public=*/false, Infos, this->Diags);
 
   // First info will be the global namespace with the typedef in it.
   NamespaceInfo *GlobalNS1 = InfoAsNamespace(Infos[0].get());
@@ -627,13 +637,13 @@ TEST(SerializeTests, emitTypedefs) {
   EXPECT_EQ("double", SecondTD.Underlying.Type.Name);
 }
 
-TEST(SerializeTests, emitFunctionTemplate) {
+TEST_F(SerializeTest, emitFunctionTemplate) {
   EmittedInfoList Infos;
   // A template and a specialization.
-  ExtractInfosFromCode("template<typename T = int> bool GetFoo(T);\n"
+  extractInfosFromCode("template<typename T = int> bool GetFoo(T);\n"
                        "template<> bool GetFoo<bool>(bool);",
                        2,
-                       /*Public=*/false, Infos);
+                       /*Public=*/false, Infos, this->Diags);
 
   // First info will be the global namespace.
   NamespaceInfo *GlobalNS1 = InfoAsNamespace(Infos[0].get());
@@ -669,18 +679,18 @@ TEST(SerializeTests, emitFunctionTemplate) {
   EXPECT_EQ("bool", Func2.ReturnType.Type.Name);
 }
 
-TEST(SerializeTests, emitClassTemplate) {
+TEST_F(SerializeTest, emitClassTemplate) {
   EmittedInfoList Infos;
   // This will generate 2x the number of infos: each Record will be followed by
   // a copy of the global namespace containing it (this test checks the data
   // pre-merge).
-  ExtractInfosFromCode(
+  extractInfosFromCode(
       "template<int I> class MyTemplate { int i[I]; };\n"
       "template<> class MyTemplate<0> {};\n"
       "template<typename T, int U = 1> class OtherTemplate {};\n"
       "template<int U> class OtherTemplate<MyTemplate<0>, U> {};",
       8,
-      /*Public=*/false, Infos);
+      /*Public=*/false, Infos, this->Diags);
 
   // First record.
   const RecordInfo *Rec1 = InfoAsRecord(Infos[0].get());
diff --git a/clang-tools-extra/unittests/clang-doc/YAMLGeneratorTest.cpp 
b/clang-tools-extra/unittests/clang-doc/YAMLGeneratorTest.cpp
index a9e7c6413cf13..db62c9246ceb4 100644
--- a/clang-tools-extra/unittests/clang-doc/YAMLGeneratorTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/YAMLGeneratorTest.cpp
@@ -22,7 +22,9 @@ static std::unique_ptr<Generator> getYAMLGenerator() {
   return std::move(G.get());
 }
 
-TEST(YAMLGeneratorTest, emitNamespaceYAML) {
+class YAMLGeneratorTest : public ClangDocContextTest {};
+
+TEST_F(YAMLGeneratorTest, emitNamespaceYAML) {
   NamespaceInfo I;
   I.Name = "Namespace";
   I.Path = "path/to/A";
@@ -44,7 +46,7 @@ TEST(YAMLGeneratorTest, emitNamespaceYAML) {
   assert(G);
   std::string Buffer;
   llvm::raw_string_ostream Actual(Buffer);
-  auto Err = G->generateDocForInfo(&I, Actual, ClangDocContext());
+  auto Err = G->generateDocForInfo(&I, Actual, getClangDocContext());
   assert(!Err);
   std::string Expected =
       R"raw(---
@@ -77,7 +79,7 @@ Path:            'path/to/A'
   EXPECT_EQ(Expected, Actual.str());
 }
 
-TEST(YAMLGeneratorTest, emitRecordYAML) {
+TEST_F(YAMLGeneratorTest, emitRecordYAML) {
   RecordInfo I;
   I.Name = "r";
   I.Path = "path/to/A";
@@ -124,7 +126,7 @@ TEST(YAMLGeneratorTest, emitRecordYAML) {
   assert(G);
   std::string Buffer;
   llvm::raw_string_ostream Actual(Buffer);
-  auto Err = G->generateDocForInfo(&I, Actual, ClangDocContext());
+  auto Err = G->generateDocForInfo(&I, Actual, getClangDocContext());
   assert(!Err);
   std::string Expected =
       R"raw(---
@@ -202,7 +204,7 @@ IsTypeDef:       true
   EXPECT_EQ(Expected, Actual.str());
 }
 
-TEST(YAMLGeneratorTest, emitFunctionYAML) {
+TEST_F(YAMLGeneratorTest, emitFunctionYAML) {
   FunctionInfo I;
   I.Name = "f";
   I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
@@ -223,7 +225,7 @@ TEST(YAMLGeneratorTest, emitFunctionYAML) {
   assert(G);
   std::string Buffer;
   llvm::raw_string_ostream Actual(Buffer);
-  auto Err = G->generateDocForInfo(&I, Actual, ClangDocContext());
+  auto Err = G->generateDocForInfo(&I, Actual, getClangDocContext());
   assert(!Err);
   std::string Expected =
       R"raw(---
@@ -267,7 +269,7 @@ IsMethod:        true
 // namespace A {
 // enum e { X };
 // }
-TEST(YAMLGeneratorTest, emitSimpleEnumYAML) {
+TEST_F(YAMLGeneratorTest, emitSimpleEnumYAML) {
   EnumInfo I;
   I.Name = "e";
   I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
@@ -282,7 +284,7 @@ TEST(YAMLGeneratorTest, emitSimpleEnumYAML) {
   assert(G);
   std::string Buffer;
   llvm::raw_string_ostream Actual(Buffer);
-  auto Err = G->generateDocForInfo(&I, Actual, ClangDocContext());
+  auto Err = G->generateDocForInfo(&I, Actual, getClangDocContext());
   assert(!Err);
   std::string Expected =
       R"raw(---
@@ -308,7 +310,7 @@ Name:            'e'
 
 // Tests the equivalent of:
 // enum class e : short { X = FOO_BAR + 2 };
-TEST(YAMLGeneratorTest, enumTypedScopedEnumYAML) {
+TEST_F(YAMLGeneratorTest, enumTypedScopedEnumYAML) {
   EnumInfo I;
   I.Name = "e";
 
@@ -320,7 +322,7 @@ TEST(YAMLGeneratorTest, enumTypedScopedEnumYAML) {
   assert(G);
   std::string Buffer;
   llvm::raw_string_ostream Actual(Buffer);
-  auto Err = G->generateDocForInfo(&I, Actual, ClangDocContext());
+  auto Err = G->generateDocForInfo(&I, Actual, getClangDocContext());
   assert(!Err);
   std::string Expected =
       R"raw(---
@@ -340,7 +342,7 @@ Scoped:          true
   EXPECT_EQ(Expected, Actual.str());
 }
 
-TEST(YAMLGeneratorTest, enumTypedefYAML) {
+TEST_F(YAMLGeneratorTest, enumTypedefYAML) {
   TypedefInfo I;
   I.Name = "MyUsing";
   I.Underlying = TypeInfo("int");
@@ -350,7 +352,7 @@ TEST(YAMLGeneratorTest, enumTypedefYAML) {
   assert(G);
   std::string Buffer;
   llvm::raw_string_ostream Actual(Buffer);
-  auto Err = G->generateDocForInfo(&I, Actual, ClangDocContext());
+  auto Err = G->generateDocForInfo(&I, Actual, getClangDocContext());
   assert(!Err);
   std::string Expected =
       R"raw(---
@@ -365,7 +367,7 @@ IsUsing:         true
   EXPECT_EQ(Expected, Actual.str());
 }
 
-TEST(YAMLGeneratorTest, emitCommentYAML) {
+TEST_F(YAMLGeneratorTest, emitCommentYAML) {
   FunctionInfo I;
   I.Name = "f";
   I.DefLoc = Location(10, 10, "test.cpp");
@@ -482,7 +484,7 @@ TEST(YAMLGeneratorTest, emitCommentYAML) {
   assert(G);
   std::string Buffer;
   llvm::raw_string_ostream Actual(Buffer);
-  auto Err = G->generateDocForInfo(&I, Actual, ClangDocContext());
+  auto Err = G->generateDocForInfo(&I, Actual, getClangDocContext());
   assert(!Err);
   std::string Expected =
       R"raw(---

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to