[llvm-branch-commits] [clang-tools-extra] [clang-doc] Replace HTML generation with Mustache backend (PR #170199)

Erick Velez via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Thu Dec 4 09:30:58 PST 2025


https://github.com/evelez7 updated https://github.com/llvm/llvm-project/pull/170199

>From 1287215bf87e5c589df1a3348d8484c6c004aaa9 Mon Sep 17 00:00:00 2001
From: Erick Velez <erickvelez7 at gmail.com>
Date: Tue, 25 Nov 2025 13:36:00 -0800
Subject: [PATCH 1/3] [clang-doc] Add Mustache output to conversion function
 test

---
 clang-tools-extra/test/clang-doc/conversion_function.cpp | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/clang-tools-extra/test/clang-doc/conversion_function.cpp b/clang-tools-extra/test/clang-doc/conversion_function.cpp
index 0200a578219ee..7b1039e9857e8 100644
--- a/clang-tools-extra/test/clang-doc/conversion_function.cpp
+++ b/clang-tools-extra/test/clang-doc/conversion_function.cpp
@@ -6,6 +6,9 @@
 // RUN: clang-doc --format=html --output=%t --executor=standalone %s 
 // RUN: FileCheck %s < %t/GlobalNamespace/MyStruct.html --check-prefix=CHECK-HTML
 
+// RUN: clang-doc --format=mustache --output=%t --executor=standalone %s 
+// RUN: FileCheck %s < %t/html/GlobalNamespace/_ZTV8MyStruct.html --check-prefix=CHECK-MUSTACHE
+
 template <typename T>
 struct MyStruct {
   operator T();
@@ -16,3 +19,7 @@ struct MyStruct {
 
 // CHECK-HTML: <h3 id="{{[0-9A-F]*}}">operator T</h3>
 // CHECK-HTML: <p>public T operator T()</p>
+
+// CHECK-MUSTACHE: <div id="{{([0-9A-F]{40})}}">
+// CHECK-MUSTACHE:     <pre><code class="language-cpp code-clang-doc">T operator T ()</code></pre>
+// CHECK-MUSTACHE: </div>

>From 214764006f1f53b31b643a3d40ede855248d788c Mon Sep 17 00:00:00 2001
From: Erick Velez <erickvelez7 at gmail.com>
Date: Tue, 25 Nov 2025 14:49:50 -0800
Subject: [PATCH 2/3] [clang-doc] Add Mustache output to comment in macros test

---
 .../test/clang-doc/comments-in-macros.cpp         | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/clang-tools-extra/test/clang-doc/comments-in-macros.cpp b/clang-tools-extra/test/clang-doc/comments-in-macros.cpp
index 0c70fadb7f9ac..94cccd1110158 100644
--- a/clang-tools-extra/test/clang-doc/comments-in-macros.cpp
+++ b/clang-tools-extra/test/clang-doc/comments-in-macros.cpp
@@ -9,6 +9,10 @@
 // RUN: FileCheck %s < %t/GlobalNamespace/MyClass.html --check-prefix=HTML-MYCLASS-LINE
 // RUN: FileCheck %s < %t/GlobalNamespace/MyClass.html --check-prefix=HTML-MYCLASS
 
+// RUN: clang-doc --format=mustache --doxygen --output=%t --executor=standalone %s
+// RUN: FileCheck %s < %t/html/GlobalNamespace/_ZTV7MyClass.html --check-prefix=MUSTACHE-MYCLASS-LINE
+// RUN: FileCheck %s < %t/html/GlobalNamespace/_ZTV7MyClass.html --check-prefix=MUSTACHE-MYCLASS
+
 #define DECLARE_METHODS                                           \
     /**   							  
      * @brief Declare a method to calculate the sum of two numbers
@@ -25,11 +29,18 @@
 // HTML-MYCLASS: <div>brief</div>
 // HTML-MYCLASS: <p> Declare a method to calculate the sum of two numbers</p>
 
+// MUSTACHE-MYCLASS: <pre><code class="language-cpp code-clang-doc">int Add (int a, int b)</code></pre>
+// MUSTACHE-MYCLASS: <div>
+// MUSTACHE-MYCLASS:     <div>
+// MUSTACHE-MYCLASS:         <p> Declare a method to calculate the sum of two numbers</p>
+// MUSTACHE-MYCLASS:     </div>
+
 
 class MyClass {
 public:
-// MD-MYCLASS-LINE: *Defined at {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}comments-in-macros.cpp#[[@LINE+2]]*
-// HTML-MYCLASS-LINE: <p>Defined at line [[@LINE+1]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}comments-in-macros.cpp</p>
+// MD-MYCLASS-LINE: *Defined at {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}comments-in-macros.cpp#[[@LINE+3]]*
+// HTML-MYCLASS-LINE: <p>Defined at line [[@LINE+2]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}comments-in-macros.cpp</p>
+// MUSTACHE-MYCLASS-LINE: <p>Defined at line [[@LINE-4]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}comments-in-macros.cpp</p>
     DECLARE_METHODS
 };
 

>From 631b7f8e58cf74df6413e3b7eedd4ceb9a22f154 Mon Sep 17 00:00:00 2001
From: Erick Velez <erickvelez7 at gmail.com>
Date: Tue, 25 Nov 2025 14:57:25 -0800
Subject: [PATCH 3/3] [clang-doc] Default to Mustache HTML generation

---
 clang-tools-extra/clang-doc/CMakeLists.txt    |    1 -
 clang-tools-extra/clang-doc/Generators.cpp    |    2 -
 clang-tools-extra/clang-doc/Generators.h      |    1 -
 clang-tools-extra/clang-doc/HTMLGenerator.cpp | 1214 ++---------------
 .../clang-doc/HTMLMustacheGenerator.cpp       |  178 ---
 clang-tools-extra/clang-doc/support/Utils.cpp |    3 +-
 clang-tools-extra/clang-doc/support/Utils.h   |    4 +-
 .../clang-doc/tool/ClangDocMain.cpp           |   87 +-
 .../test/clang-doc/DR-131697.cpp              |    1 -
 clang-tools-extra/test/clang-doc/assets.cpp   |   25 +-
 .../clang-doc/basic-project.mustache.test     |    2 +-
 .../test/clang-doc/basic-project.test         |  267 ----
 .../test/clang-doc/comments-in-macros.cpp     |   26 +-
 .../test/clang-doc/conversion_function.cpp    |   14 +-
 clang-tools-extra/test/clang-doc/enum.cpp     |  306 ++---
 .../test/clang-doc/long-name.cpp              |    2 +-
 .../test/clang-doc/mustache-index.cpp         |    2 +-
 .../clang-doc/mustache-separate-namespace.cpp |    2 +-
 .../test/clang-doc/namespace.cpp              |  327 ++---
 .../test/clang-doc/test-path-abs.cpp          |    7 -
 .../unittests/clang-doc/CMakeLists.txt        |    1 -
 .../unittests/clang-doc/HTMLGeneratorTest.cpp |  479 +------
 .../clang-doc/HTMLMustacheGeneratorTest.cpp   |   55 -
 23 files changed, 384 insertions(+), 2622 deletions(-)
 delete mode 100644 clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
 delete mode 100644 clang-tools-extra/test/clang-doc/test-path-abs.cpp
 delete mode 100644 clang-tools-extra/unittests/clang-doc/HTMLMustacheGeneratorTest.cpp

diff --git a/clang-tools-extra/clang-doc/CMakeLists.txt b/clang-tools-extra/clang-doc/CMakeLists.txt
index 5989e5fe60cf3..7a375d7cd0524 100644
--- a/clang-tools-extra/clang-doc/CMakeLists.txt
+++ b/clang-tools-extra/clang-doc/CMakeLists.txt
@@ -16,7 +16,6 @@ add_clang_library(clangDoc STATIC
   Representation.cpp
   Serialize.cpp
   YAMLGenerator.cpp
-  HTMLMustacheGenerator.cpp
   JSONGenerator.cpp
 
   DEPENDS
diff --git a/clang-tools-extra/clang-doc/Generators.cpp b/clang-tools-extra/clang-doc/Generators.cpp
index 5d76901b95833..d836e195289f6 100644
--- a/clang-tools-extra/clang-doc/Generators.cpp
+++ b/clang-tools-extra/clang-doc/Generators.cpp
@@ -239,8 +239,6 @@ void Generator::addInfoToIndex(Index &Idx, const doc::Info *Info) {
 [[maybe_unused]] static int YAMLGeneratorAnchorDest = YAMLGeneratorAnchorSource;
 [[maybe_unused]] static int MDGeneratorAnchorDest = MDGeneratorAnchorSource;
 [[maybe_unused]] static int HTMLGeneratorAnchorDest = HTMLGeneratorAnchorSource;
-[[maybe_unused]] static int MHTMLGeneratorAnchorDest =
-    MHTMLGeneratorAnchorSource;
 [[maybe_unused]] static int JSONGeneratorAnchorDest = JSONGeneratorAnchorSource;
 } // namespace doc
 } // namespace clang
diff --git a/clang-tools-extra/clang-doc/Generators.h b/clang-tools-extra/clang-doc/Generators.h
index 847722646b029..a50f1ac25eda9 100644
--- a/clang-tools-extra/clang-doc/Generators.h
+++ b/clang-tools-extra/clang-doc/Generators.h
@@ -137,7 +137,6 @@ struct MustacheGenerator : public Generator {
 extern volatile int YAMLGeneratorAnchorSource;
 extern volatile int MDGeneratorAnchorSource;
 extern volatile int HTMLGeneratorAnchorSource;
-extern volatile int MHTMLGeneratorAnchorSource;
 extern volatile int JSONGeneratorAnchorSource;
 
 } // namespace doc
diff --git a/clang-tools-extra/clang-doc/HTMLGenerator.cpp b/clang-tools-extra/clang-doc/HTMLGenerator.cpp
index 7c8c16b8e8aca..9b8f53e44901f 100644
--- a/clang-tools-extra/clang-doc/HTMLGenerator.cpp
+++ b/clang-tools-extra/clang-doc/HTMLGenerator.cpp
@@ -1,1149 +1,173 @@
-//===-- HTMLGenerator.cpp - HTML Generator ----------------------*- C++ -*-===//
+///===----------------------------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains the implementation of the HTMLGenerator class,
+/// which is Clang-Doc generator for HTML using Mustache templates.
+///
+//===----------------------------------------------------------------------===//
 
 #include "Generators.h"
 #include "Representation.h"
 #include "support/File.h"
-#include "clang/Basic/Version.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/StringSet.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/JSON.h"
+#include "llvm/Support/Error.h"
 #include "llvm/Support/Path.h"
-#include "llvm/Support/raw_ostream.h"
-#include <algorithm>
-#include <optional>
-#include <string>
 
 using namespace llvm;
+using namespace llvm::json;
+using namespace llvm::mustache;
 
 namespace clang {
 namespace doc {
 
-namespace {
-
-class HTMLTag {
-public:
-  // Any other tag can be added if required
-  enum TagType {
-    TAG_A,
-    TAG_DIV,
-    TAG_FOOTER,
-    TAG_H1,
-    TAG_H2,
-    TAG_H3,
-    TAG_HEADER,
-    TAG_LI,
-    TAG_LINK,
-    TAG_MAIN,
-    TAG_META,
-    TAG_OL,
-    TAG_P,
-    TAG_SCRIPT,
-    TAG_SPAN,
-    TAG_TITLE,
-    TAG_UL,
-    TAG_TABLE,
-    TAG_THEAD,
-    TAG_TBODY,
-    TAG_TR,
-    TAG_TD,
-    TAG_TH
-  };
-
-  HTMLTag() = default;
-  constexpr HTMLTag(TagType Value) : Value(Value) {}
-
-  operator TagType() const { return Value; }
-  operator bool() = delete;
-
-  bool isSelfClosing() const;
-  StringRef toString() const;
-
-private:
-  TagType Value;
-};
-
-enum NodeType {
-  NODE_TEXT,
-  NODE_TAG,
-};
-
-struct HTMLNode {
-  HTMLNode(NodeType Type) : Type(Type) {}
-  virtual ~HTMLNode() = default;
-
-  virtual void render(llvm::raw_ostream &OS, int IndentationLevel) = 0;
-  NodeType Type; // Type of node
-};
-
-struct TextNode : public HTMLNode {
-  TextNode(const Twine &Text)
-      : HTMLNode(NodeType::NODE_TEXT), Text(Text.str()) {}
-
-  std::string Text; // Content of node
-  void render(llvm::raw_ostream &OS, int IndentationLevel) override;
-};
-
-struct TagNode : public HTMLNode {
-  TagNode(HTMLTag Tag) : HTMLNode(NodeType::NODE_TAG), Tag(Tag) {}
-  TagNode(HTMLTag Tag, const Twine &Text) : TagNode(Tag) {
-    Children.emplace_back(std::make_unique<TextNode>(Text.str()));
-  }
-
-  HTMLTag Tag; // Name of HTML Tag (p, div, h1)
-  std::vector<std::unique_ptr<HTMLNode>> Children; // List of child nodes
-  std::vector<std::pair<std::string, std::string>>
-      Attributes; // List of key-value attributes for tag
-
-  void render(llvm::raw_ostream &OS, int IndentationLevel) override;
-};
-
-struct HTMLFile {
-  std::vector<std::unique_ptr<HTMLNode>> Children; // List of child nodes
-  void render(llvm::raw_ostream &OS) {
-    OS << "<!DOCTYPE html>\n";
-    for (const auto &C : Children) {
-      C->render(OS, 0);
-      OS << "\n";
-    }
-  }
-};
-
-} // namespace
-
-bool HTMLTag::isSelfClosing() const {
-  switch (Value) {
-  case HTMLTag::TAG_META:
-  case HTMLTag::TAG_LINK:
-    return true;
-  case HTMLTag::TAG_A:
-  case HTMLTag::TAG_DIV:
-  case HTMLTag::TAG_FOOTER:
-  case HTMLTag::TAG_H1:
-  case HTMLTag::TAG_H2:
-  case HTMLTag::TAG_H3:
-  case HTMLTag::TAG_HEADER:
-  case HTMLTag::TAG_LI:
-  case HTMLTag::TAG_MAIN:
-  case HTMLTag::TAG_OL:
-  case HTMLTag::TAG_P:
-  case HTMLTag::TAG_SCRIPT:
-  case HTMLTag::TAG_SPAN:
-  case HTMLTag::TAG_TITLE:
-  case HTMLTag::TAG_UL:
-  case HTMLTag::TAG_TABLE:
-  case HTMLTag::TAG_THEAD:
-  case HTMLTag::TAG_TBODY:
-  case HTMLTag::TAG_TR:
-  case HTMLTag::TAG_TD:
-  case HTMLTag::TAG_TH:
-    return false;
-  }
-  llvm_unreachable("Unhandled HTMLTag::TagType");
-}
-
-StringRef HTMLTag::toString() const {
-  switch (Value) {
-  case HTMLTag::TAG_A:
-    return "a";
-  case HTMLTag::TAG_DIV:
-    return "div";
-  case HTMLTag::TAG_FOOTER:
-    return "footer";
-  case HTMLTag::TAG_H1:
-    return "h1";
-  case HTMLTag::TAG_H2:
-    return "h2";
-  case HTMLTag::TAG_H3:
-    return "h3";
-  case HTMLTag::TAG_HEADER:
-    return "header";
-  case HTMLTag::TAG_LI:
-    return "li";
-  case HTMLTag::TAG_LINK:
-    return "link";
-  case HTMLTag::TAG_MAIN:
-    return "main";
-  case HTMLTag::TAG_META:
-    return "meta";
-  case HTMLTag::TAG_OL:
-    return "ol";
-  case HTMLTag::TAG_P:
-    return "p";
-  case HTMLTag::TAG_SCRIPT:
-    return "script";
-  case HTMLTag::TAG_SPAN:
-    return "span";
-  case HTMLTag::TAG_TITLE:
-    return "title";
-  case HTMLTag::TAG_UL:
-    return "ul";
-  case HTMLTag::TAG_TABLE:
-    return "table";
-  case HTMLTag::TAG_THEAD:
-    return "thead";
-  case HTMLTag::TAG_TBODY:
-    return "tbody";
-  case HTMLTag::TAG_TR:
-    return "tr";
-  case HTMLTag::TAG_TD:
-    return "td";
-  case HTMLTag::TAG_TH:
-    return "th";
-  }
-  llvm_unreachable("Unhandled HTMLTag::TagType");
-}
-
-void TextNode::render(llvm::raw_ostream &OS, int IndentationLevel) {
-  OS.indent(IndentationLevel * 2);
-  printHTMLEscaped(Text, OS);
-}
-
-void TagNode::render(llvm::raw_ostream &OS, int IndentationLevel) {
-  // Children nodes are rendered in the same line if all of them are text nodes
-  bool InlineChildren = true;
-  for (const auto &C : Children)
-    if (C->Type == NodeType::NODE_TAG) {
-      InlineChildren = false;
-      break;
-    }
-  OS.indent(IndentationLevel * 2);
-  OS << "<" << Tag.toString();
-  for (const auto &A : Attributes)
-    OS << " " << A.first << "=\"" << A.second << "\"";
-  if (Tag.isSelfClosing()) {
-    OS << "/>";
-    return;
-  }
-  OS << ">";
-  if (!InlineChildren)
-    OS << "\n";
-  bool NewLineRendered = true;
-  for (const auto &C : Children) {
-    int ChildrenIndentation =
-        InlineChildren || !NewLineRendered ? 0 : IndentationLevel + 1;
-    C->render(OS, ChildrenIndentation);
-    if (!InlineChildren && (C == Children.back() ||
-                            (C->Type != NodeType::NODE_TEXT ||
-                             (&C + 1)->get()->Type != NodeType::NODE_TEXT))) {
-      OS << "\n";
-      NewLineRendered = true;
-    } else
-      NewLineRendered = false;
-  }
-  if (!InlineChildren)
-    OS.indent(IndentationLevel * 2);
-  OS << "</" << Tag.toString() << ">";
-}
-
-template <typename Derived, typename Base,
-          typename = std::enable_if<std::is_base_of<Derived, Base>::value>>
-static void appendVector(std::vector<Derived> &&New,
-                         std::vector<Base> &Original) {
-  std::move(New.begin(), New.end(), std::back_inserter(Original));
-}
-
-// HTML generation
-
-static std::vector<std::unique_ptr<TagNode>>
-genStylesheetsHTML(StringRef InfoPath, const ClangDocContext &CDCtx) {
-  std::vector<std::unique_ptr<TagNode>> Out;
-  for (const auto &FilePath : CDCtx.UserStylesheets) {
-    auto LinkNode = std::make_unique<TagNode>(HTMLTag::TAG_LINK);
-    LinkNode->Attributes.emplace_back("rel", "stylesheet");
-    SmallString<128> StylesheetPath = computeRelativePath("", InfoPath);
-    llvm::sys::path::append(StylesheetPath,
-                            llvm::sys::path::filename(FilePath));
-    // Paths in HTML must be in posix-style
-    llvm::sys::path::native(StylesheetPath, llvm::sys::path::Style::posix);
-    LinkNode->Attributes.emplace_back("href", std::string(StylesheetPath));
-    Out.emplace_back(std::move(LinkNode));
-  }
-  return Out;
-}
-
-static std::vector<std::unique_ptr<TagNode>>
-genJsScriptsHTML(StringRef InfoPath, const ClangDocContext &CDCtx) {
-  std::vector<std::unique_ptr<TagNode>> Out;
-
-  // index_json.js is part of every generated HTML file
-  SmallString<128> IndexJSONPath = computeRelativePath("", InfoPath);
-  auto IndexJSONNode = std::make_unique<TagNode>(HTMLTag::TAG_SCRIPT);
-  llvm::sys::path::append(IndexJSONPath, "index_json.js");
-  llvm::sys::path::native(IndexJSONPath, llvm::sys::path::Style::posix);
-  IndexJSONNode->Attributes.emplace_back("src", std::string(IndexJSONPath));
-  Out.emplace_back(std::move(IndexJSONNode));
-
-  for (const auto &FilePath : CDCtx.JsScripts) {
-    SmallString<128> ScriptPath = computeRelativePath("", InfoPath);
-    auto ScriptNode = std::make_unique<TagNode>(HTMLTag::TAG_SCRIPT);
-    llvm::sys::path::append(ScriptPath, llvm::sys::path::filename(FilePath));
-    // Paths in HTML must be in posix-style
-    llvm::sys::path::native(ScriptPath, llvm::sys::path::Style::posix);
-    ScriptNode->Attributes.emplace_back("src", std::string(ScriptPath));
-    Out.emplace_back(std::move(ScriptNode));
-  }
-  return Out;
-}
-
-static std::unique_ptr<TagNode> genLink(const Twine &Text, const Twine &Link) {
-  auto LinkNode = std::make_unique<TagNode>(HTMLTag::TAG_A, Text);
-  LinkNode->Attributes.emplace_back("href", Link.str());
-  return LinkNode;
-}
-
-static std::unique_ptr<HTMLNode>
-genReference(const Reference &Type, StringRef CurrentDirectory,
-             std::optional<StringRef> JumpToSection = std::nullopt) {
-  if (Type.Path.empty()) {
-    if (!JumpToSection)
-      return std::make_unique<TextNode>(Type.Name);
-    return genLink(Type.Name, "#" + *JumpToSection);
-  }
-  llvm::SmallString<64> Path = Type.getRelativeFilePath(CurrentDirectory);
-  llvm::sys::path::append(Path, Type.getFileBaseName() + ".html");
-
-  // Paths in HTML must be in posix-style
-  llvm::sys::path::native(Path, llvm::sys::path::Style::posix);
-  if (JumpToSection)
-    Path += ("#" + *JumpToSection).str();
-  return genLink(Type.Name, Path);
-}
-
-static std::vector<std::unique_ptr<HTMLNode>>
-genReferenceList(const llvm::SmallVectorImpl<Reference> &Refs,
-                 const StringRef &CurrentDirectory) {
-  std::vector<std::unique_ptr<HTMLNode>> Out;
-  for (const auto &R : Refs) {
-    if (&R != Refs.begin())
-      Out.emplace_back(std::make_unique<TextNode>(", "));
-    Out.emplace_back(genReference(R, CurrentDirectory));
-  }
-  return Out;
-}
-
-static std::vector<std::unique_ptr<TagNode>>
-genHTML(const EnumInfo &I, const ClangDocContext &CDCtx);
-static std::vector<std::unique_ptr<TagNode>>
-genHTML(const FunctionInfo &I, const ClangDocContext &CDCtx,
-        StringRef ParentInfoDir);
-static std::unique_ptr<TagNode> genHTML(const std::vector<CommentInfo> &C);
-
-static std::vector<std::unique_ptr<TagNode>>
-genEnumsBlock(const std::vector<EnumInfo> &Enums,
-              const ClangDocContext &CDCtx) {
-  if (Enums.empty())
-    return {};
-
-  std::vector<std::unique_ptr<TagNode>> Out;
-  Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_H2, "Enums"));
-  Out.back()->Attributes.emplace_back("id", "Enums");
-  Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_DIV));
-  auto &DivBody = Out.back();
-  for (const auto &E : Enums) {
-    std::vector<std::unique_ptr<TagNode>> Nodes = genHTML(E, CDCtx);
-    appendVector(std::move(Nodes), DivBody->Children);
-  }
-  return Out;
-}
-
-static std::unique_ptr<TagNode>
-genEnumMembersBlock(const llvm::SmallVector<EnumValueInfo, 4> &Members) {
-  if (Members.empty())
-    return nullptr;
-
-  auto List = std::make_unique<TagNode>(HTMLTag::TAG_TBODY);
-
-  for (const auto &M : Members) {
-    auto TRNode = std::make_unique<TagNode>(HTMLTag::TAG_TR);
-    TRNode->Children.emplace_back(
-        std::make_unique<TagNode>(HTMLTag::TAG_TD, M.Name));
-    // Use user supplied value if it exists, otherwise use the value
-    if (!M.ValueExpr.empty()) {
-      TRNode->Children.emplace_back(
-          std::make_unique<TagNode>(HTMLTag::TAG_TD, M.ValueExpr));
-    } else {
-      TRNode->Children.emplace_back(
-          std::make_unique<TagNode>(HTMLTag::TAG_TD, M.Value));
-    }
-    if (!M.Description.empty()) {
-      auto TD = std::make_unique<TagNode>(HTMLTag::TAG_TD);
-      TD->Children.emplace_back(genHTML(M.Description));
-      TRNode->Children.emplace_back(std::move(TD));
-    }
-    List->Children.emplace_back(std::move(TRNode));
-  }
-  return List;
-}
-
-static std::vector<std::unique_ptr<TagNode>>
-genFunctionsBlock(const std::vector<FunctionInfo> &Functions,
-                  const ClangDocContext &CDCtx, StringRef ParentInfoDir) {
-  if (Functions.empty())
-    return {};
-
-  std::vector<std::unique_ptr<TagNode>> Out;
-  Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_H2, "Functions"));
-  Out.back()->Attributes.emplace_back("id", "Functions");
-  Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_DIV));
-  auto &DivBody = Out.back();
-  for (const auto &F : Functions) {
-    std::vector<std::unique_ptr<TagNode>> Nodes =
-        genHTML(F, CDCtx, ParentInfoDir);
-    appendVector(std::move(Nodes), DivBody->Children);
-  }
-  return Out;
-}
-
-static std::vector<std::unique_ptr<TagNode>>
-genRecordMembersBlock(const llvm::SmallVector<MemberTypeInfo, 4> &Members,
-                      StringRef ParentInfoDir) {
-  if (Members.empty())
-    return {};
-
-  std::vector<std::unique_ptr<TagNode>> Out;
-  Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_H2, "Members"));
-  Out.back()->Attributes.emplace_back("id", "Members");
-  Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_UL));
-  auto &ULBody = Out.back();
-  for (const auto &M : Members) {
-    StringRef Access = getAccessSpelling(M.Access);
-    auto LIBody = std::make_unique<TagNode>(HTMLTag::TAG_LI);
-    auto MemberDecl = std::make_unique<TagNode>(HTMLTag::TAG_DIV);
-    if (!Access.empty())
-      MemberDecl->Children.emplace_back(
-          std::make_unique<TextNode>(Access + " "));
-    if (M.IsStatic)
-      MemberDecl->Children.emplace_back(std::make_unique<TextNode>("static "));
-    MemberDecl->Children.emplace_back(genReference(M.Type, ParentInfoDir));
-    MemberDecl->Children.emplace_back(std::make_unique<TextNode>(" " + M.Name));
-    if (!M.Description.empty())
-      LIBody->Children.emplace_back(genHTML(M.Description));
-    LIBody->Children.emplace_back(std::move(MemberDecl));
-    ULBody->Children.emplace_back(std::move(LIBody));
-  }
-  return Out;
-}
-
-static std::vector<std::unique_ptr<TagNode>>
-genReferencesBlock(const std::vector<Reference> &References,
-                   llvm::StringRef Title, StringRef ParentPath) {
-  if (References.empty())
-    return {};
-
-  std::vector<std::unique_ptr<TagNode>> Out;
-  Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_H2, Title));
-  Out.back()->Attributes.emplace_back("id", std::string(Title));
-  Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_UL));
-  auto &ULBody = Out.back();
-  for (const auto &R : References) {
-    auto LiNode = std::make_unique<TagNode>(HTMLTag::TAG_LI);
-    LiNode->Children.emplace_back(genReference(R, ParentPath));
-    ULBody->Children.emplace_back(std::move(LiNode));
-  }
-  return Out;
-}
-static std::unique_ptr<TagNode> writeSourceFileRef(const ClangDocContext &CDCtx,
-                                                   const Location &L) {
-
-  if (!L.IsFileInRootDir && !CDCtx.RepositoryUrl)
-    return std::make_unique<TagNode>(
-        HTMLTag::TAG_P, "Defined at line " + std::to_string(L.StartLineNumber) +
-                            " of file " + L.Filename);
-
-  SmallString<128> FileURL(CDCtx.RepositoryUrl.value_or(""));
-  llvm::sys::path::append(
-      FileURL, llvm::sys::path::Style::posix,
-      // If we're on Windows, the file name will be in the wrong format, and
-      // append won't convert the full path being appended to the correct
-      // format, so we need to do that here.
-      llvm::sys::path::convert_to_slash(
-          L.Filename,
-          // The style here is the current style of the path, not the one we're
-          // targeting. If the string is already in the posix style, it will do
-          // nothing.
-          llvm::sys::path::Style::windows));
-  auto Node = std::make_unique<TagNode>(HTMLTag::TAG_P);
-  Node->Children.emplace_back(std::make_unique<TextNode>("Defined at line "));
-  auto LocNumberNode = std::make_unique<TagNode>(
-      HTMLTag::TAG_A, std::to_string(L.StartLineNumber));
-  // The links to a specific line in the source code use the github /
-  // googlesource notation so it won't work for all hosting pages.
-  LocNumberNode->Attributes.emplace_back(
-      "href",
-      formatv("{0}#{1}{2}", FileURL, CDCtx.RepositoryLinePrefix.value_or(""),
-              L.StartLineNumber));
-  Node->Children.emplace_back(std::move(LocNumberNode));
-  Node->Children.emplace_back(std::make_unique<TextNode>(" of file "));
-  auto LocFileNode = std::make_unique<TagNode>(
-      HTMLTag::TAG_A, llvm::sys::path::filename(FileURL));
-  LocFileNode->Attributes.emplace_back("href", std::string(FileURL));
-  Node->Children.emplace_back(std::move(LocFileNode));
-  return Node;
-}
-
-static void maybeWriteSourceFileRef(std::vector<std::unique_ptr<TagNode>> &Out,
-                                    const ClangDocContext &CDCtx,
-                                    const std::optional<Location> &DefLoc) {
-  if (DefLoc)
-    Out.emplace_back(writeSourceFileRef(CDCtx, *DefLoc));
-}
-
-static std::vector<std::unique_ptr<TagNode>>
-genHTML(const Index &Index, StringRef InfoPath, bool IsOutermostList);
-
-// Generates a list of child nodes for the HTML head tag
-// It contains a meta node, link nodes to import CSS files, and script nodes to
-// import JS files
-static std::vector<std::unique_ptr<TagNode>>
-genFileHeadNodes(StringRef Title, StringRef InfoPath,
-                 const ClangDocContext &CDCtx) {
-  std::vector<std::unique_ptr<TagNode>> Out;
-  auto MetaNode = std::make_unique<TagNode>(HTMLTag::TAG_META);
-  MetaNode->Attributes.emplace_back("charset", "utf-8");
-  Out.emplace_back(std::move(MetaNode));
-  Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_TITLE, Title));
-  std::vector<std::unique_ptr<TagNode>> StylesheetsNodes =
-      genStylesheetsHTML(InfoPath, CDCtx);
-  appendVector(std::move(StylesheetsNodes), Out);
-  std::vector<std::unique_ptr<TagNode>> JsNodes =
-      genJsScriptsHTML(InfoPath, CDCtx);
-  appendVector(std::move(JsNodes), Out);
-  return Out;
-}
-
-// Generates a header HTML node that can be used for any file
-// It contains the project name
-static std::unique_ptr<TagNode> genFileHeaderNode(StringRef ProjectName) {
-  auto HeaderNode = std::make_unique<TagNode>(HTMLTag::TAG_HEADER, ProjectName);
-  HeaderNode->Attributes.emplace_back("id", "project-title");
-  return HeaderNode;
-}
-
-// Generates a main HTML node that has all the main content of an info file
-// It contains both indexes and the info's documented information
-// This function should only be used for the info files (not for the file that
-// only has the general index)
-static std::unique_ptr<TagNode> genInfoFileMainNode(
-    StringRef InfoPath,
-    std::vector<std::unique_ptr<TagNode>> &MainContentInnerNodes,
-    const Index &InfoIndex) {
-  auto MainNode = std::make_unique<TagNode>(HTMLTag::TAG_MAIN);
-
-  auto LeftSidebarNode = std::make_unique<TagNode>(HTMLTag::TAG_DIV);
-  LeftSidebarNode->Attributes.emplace_back("id", "sidebar-left");
-  LeftSidebarNode->Attributes.emplace_back("path", std::string(InfoPath));
-  LeftSidebarNode->Attributes.emplace_back(
-      "class", "col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left");
-
-  auto MainContentNode = std::make_unique<TagNode>(HTMLTag::TAG_DIV);
-  MainContentNode->Attributes.emplace_back("id", "main-content");
-  MainContentNode->Attributes.emplace_back(
-      "class", "col-xs-12 col-sm-9 col-md-8 main-content");
-  appendVector(std::move(MainContentInnerNodes), MainContentNode->Children);
-
-  auto RightSidebarNode = std::make_unique<TagNode>(HTMLTag::TAG_DIV);
-  RightSidebarNode->Attributes.emplace_back("id", "sidebar-right");
-  RightSidebarNode->Attributes.emplace_back(
-      "class", "col-xs-6 col-sm-6 col-md-2 sidebar sidebar-offcanvas-right");
-  std::vector<std::unique_ptr<TagNode>> InfoIndexHTML =
-      genHTML(InfoIndex, InfoPath, true);
-  appendVector(std::move(InfoIndexHTML), RightSidebarNode->Children);
-
-  MainNode->Children.emplace_back(std::move(LeftSidebarNode));
-  MainNode->Children.emplace_back(std::move(MainContentNode));
-  MainNode->Children.emplace_back(std::move(RightSidebarNode));
-
-  return MainNode;
-}
-
-// Generates a footer HTML node that can be used for any file
-// It contains clang-doc's version
-static std::unique_ptr<TagNode> genFileFooterNode() {
-  auto FooterNode = std::make_unique<TagNode>(HTMLTag::TAG_FOOTER);
-  auto SpanNode = std::make_unique<TagNode>(
-      HTMLTag::TAG_SPAN, clang::getClangToolFullVersion("clang-doc"));
-  SpanNode->Attributes.emplace_back("class", "no-break");
-  FooterNode->Children.emplace_back(std::move(SpanNode));
-  return FooterNode;
-}
-
-// Generates a complete HTMLFile for an Info
-static HTMLFile
-genInfoFile(StringRef Title, StringRef InfoPath,
-            std::vector<std::unique_ptr<TagNode>> &MainContentNodes,
-            const Index &InfoIndex, const ClangDocContext &CDCtx) {
-  HTMLFile F;
-
-  std::vector<std::unique_ptr<TagNode>> HeadNodes =
-      genFileHeadNodes(Title, InfoPath, CDCtx);
-  std::unique_ptr<TagNode> HeaderNode = genFileHeaderNode(CDCtx.ProjectName);
-  std::unique_ptr<TagNode> MainNode =
-      genInfoFileMainNode(InfoPath, MainContentNodes, InfoIndex);
-  std::unique_ptr<TagNode> FooterNode = genFileFooterNode();
-
-  appendVector(std::move(HeadNodes), F.Children);
-  F.Children.emplace_back(std::move(HeaderNode));
-  F.Children.emplace_back(std::move(MainNode));
-  F.Children.emplace_back(std::move(FooterNode));
-
-  return F;
-}
-
-template <typename T,
-          typename = std::enable_if<std::is_base_of<T, Info>::value>>
-static Index genInfoIndexItem(const std::vector<T> &Infos, StringRef Title) {
-  Index Idx(Title, Title);
-  for (const auto &C : Infos)
-    Idx.Children.emplace_back(C.extractName(),
-                              llvm::toHex(llvm::toStringRef(C.USR)));
-  return Idx;
-}
-
-static std::vector<std::unique_ptr<TagNode>>
-genHTML(const Index &Index, StringRef InfoPath, bool IsOutermostList) {
-  std::vector<std::unique_ptr<TagNode>> Out;
-  if (!Index.Name.empty()) {
-    Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_SPAN));
-    auto &SpanBody = Out.back();
-    if (!Index.JumpToSection)
-      SpanBody->Children.emplace_back(genReference(Index, InfoPath));
-    else
-      SpanBody->Children.emplace_back(
-          genReference(Index, InfoPath, Index.JumpToSection->str()));
-  }
-  if (Index.Children.empty())
-    return Out;
-  // Only the outermost list should use ol, the others should use ul
-  HTMLTag ListHTMLTag = IsOutermostList ? HTMLTag::TAG_OL : HTMLTag::TAG_UL;
-  Out.emplace_back(std::make_unique<TagNode>(ListHTMLTag));
-  const auto &UlBody = Out.back();
-  for (const auto &C : Index.Children) {
-    auto LiBody = std::make_unique<TagNode>(HTMLTag::TAG_LI);
-    std::vector<std::unique_ptr<TagNode>> Nodes = genHTML(C, InfoPath, false);
-    appendVector(std::move(Nodes), LiBody->Children);
-    UlBody->Children.emplace_back(std::move(LiBody));
-  }
-  return Out;
-}
-
-static std::unique_ptr<HTMLNode> genHTML(const CommentInfo &I) {
-  switch (I.Kind) {
-  case CommentKind::CK_FullComment: {
-    auto FullComment = std::make_unique<TagNode>(HTMLTag::TAG_DIV);
-    for (const auto &Child : I.Children) {
-      std::unique_ptr<HTMLNode> Node = genHTML(*Child);
-      if (Node)
-        FullComment->Children.emplace_back(std::move(Node));
-    }
-    return std::move(FullComment);
-  }
-
-  case CommentKind::CK_ParagraphComment: {
-    auto ParagraphComment = std::make_unique<TagNode>(HTMLTag::TAG_P);
-    for (const auto &Child : I.Children) {
-      std::unique_ptr<HTMLNode> Node = genHTML(*Child);
-      if (Node)
-        ParagraphComment->Children.emplace_back(std::move(Node));
-    }
-    if (ParagraphComment->Children.empty())
-      return nullptr;
-    return std::move(ParagraphComment);
-  }
-
-  case CommentKind::CK_BlockCommandComment: {
-    auto BlockComment = std::make_unique<TagNode>(HTMLTag::TAG_DIV);
-    BlockComment->Children.emplace_back(
-        std::make_unique<TagNode>(HTMLTag::TAG_DIV, I.Name));
-    for (const auto &Child : I.Children) {
-      std::unique_ptr<HTMLNode> Node = genHTML(*Child);
-      if (Node)
-        BlockComment->Children.emplace_back(std::move(Node));
-    }
-    if (BlockComment->Children.empty())
-      return nullptr;
-    return std::move(BlockComment);
-  }
-
-  case CommentKind::CK_TextComment: {
-    if (I.Text.empty())
-      return nullptr;
-    return std::make_unique<TextNode>(I.Text);
-  }
-
-  // For now, return nullptr for unsupported comment kinds
-  case CommentKind::CK_InlineCommandComment:
-  case CommentKind::CK_HTMLStartTagComment:
-  case CommentKind::CK_HTMLEndTagComment:
-  case CommentKind::CK_ParamCommandComment:
-  case CommentKind::CK_TParamCommandComment:
-  case CommentKind::CK_VerbatimBlockComment:
-  case CommentKind::CK_VerbatimBlockLineComment:
-  case CommentKind::CK_VerbatimLineComment:
-  case CommentKind::CK_Unknown:
-    return nullptr;
-  }
-  llvm_unreachable("Unhandled CommentKind");
-}
-
-static std::unique_ptr<TagNode> genHTML(const std::vector<CommentInfo> &C) {
-  auto CommentBlock = std::make_unique<TagNode>(HTMLTag::TAG_DIV);
-  for (const auto &Child : C) {
-    if (std::unique_ptr<HTMLNode> Node = genHTML(Child))
-      CommentBlock->Children.emplace_back(std::move(Node));
-  }
-  return CommentBlock;
-}
-
-static std::vector<std::unique_ptr<TagNode>>
-genHTML(const EnumInfo &I, const ClangDocContext &CDCtx) {
-  std::vector<std::unique_ptr<TagNode>> Out;
-  std::string EnumType = I.Scoped ? "enum class " : "enum ";
-  // Determine if enum members have comments attached
-  bool HasComments = llvm::any_of(
-      I.Members, [](const EnumValueInfo &M) { return !M.Description.empty(); });
-  std::unique_ptr<TagNode> Table =
-      std::make_unique<TagNode>(HTMLTag::TAG_TABLE);
-  std::unique_ptr<TagNode> THead =
-      std::make_unique<TagNode>(HTMLTag::TAG_THEAD);
-  std::unique_ptr<TagNode> TRow = std::make_unique<TagNode>(HTMLTag::TAG_TR);
-  std::unique_ptr<TagNode> TD =
-      std::make_unique<TagNode>(HTMLTag::TAG_TH, EnumType + I.Name);
-  // Span 3 columns if enum has comments
-  TD->Attributes.emplace_back("colspan", HasComments ? "3" : "2");
-
-  Table->Attributes.emplace_back("id", llvm::toHex(llvm::toStringRef(I.USR)));
-  TRow->Children.emplace_back(std::move(TD));
-  THead->Children.emplace_back(std::move(TRow));
-  Table->Children.emplace_back(std::move(THead));
-
-  if (std::unique_ptr<TagNode> Node = genEnumMembersBlock(I.Members))
-    Table->Children.emplace_back(std::move(Node));
-
-  Out.emplace_back(std::move(Table));
-
-  maybeWriteSourceFileRef(Out, CDCtx, I.DefLoc);
-
-  if (!I.Description.empty())
-    Out.emplace_back(genHTML(I.Description));
-
-  return Out;
-}
-
-static std::vector<std::unique_ptr<TagNode>>
-genHTML(const FunctionInfo &I, const ClangDocContext &CDCtx,
-        StringRef ParentInfoDir) {
-  std::vector<std::unique_ptr<TagNode>> Out;
-  Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_H3, I.Name));
-  // USR is used as id for functions instead of name to disambiguate function
-  // overloads.
-  Out.back()->Attributes.emplace_back("id",
-                                      llvm::toHex(llvm::toStringRef(I.USR)));
-
-  Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_P));
-  auto &FunctionHeader = Out.back();
-
-  std::string Access = getAccessSpelling(I.Access).str();
-  if (Access != "")
-    FunctionHeader->Children.emplace_back(
-        std::make_unique<TextNode>(Access + " "));
-  if (I.IsStatic)
-    FunctionHeader->Children.emplace_back(
-        std::make_unique<TextNode>("static "));
-  if (I.ReturnType.Type.Name != "") {
-    FunctionHeader->Children.emplace_back(
-        genReference(I.ReturnType.Type, ParentInfoDir));
-    FunctionHeader->Children.emplace_back(std::make_unique<TextNode>(" "));
-  }
-  FunctionHeader->Children.emplace_back(
-      std::make_unique<TextNode>(I.Name + "("));
-
-  for (const auto &P : I.Params) {
-    if (&P != I.Params.begin())
-      FunctionHeader->Children.emplace_back(std::make_unique<TextNode>(", "));
-    FunctionHeader->Children.emplace_back(genReference(P.Type, ParentInfoDir));
-    FunctionHeader->Children.emplace_back(
-        std::make_unique<TextNode>(" " + P.Name));
-  }
-  FunctionHeader->Children.emplace_back(std::make_unique<TextNode>(")"));
-
-  maybeWriteSourceFileRef(Out, CDCtx, I.DefLoc);
-
-  if (!I.Description.empty())
-    Out.emplace_back(genHTML(I.Description));
-
-  return Out;
-}
-
-static std::vector<std::unique_ptr<TagNode>>
-genHTML(const NamespaceInfo &I, Index &InfoIndex, const ClangDocContext &CDCtx,
-        std::string &InfoTitle) {
-  std::vector<std::unique_ptr<TagNode>> Out;
-  if (I.Name.str() == "")
-    InfoTitle = "Global Namespace";
-  else
-    InfoTitle = ("namespace " + I.Name).str();
+static std::unique_ptr<MustacheTemplateFile> NamespaceTemplate = nullptr;
 
-  Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_H1, InfoTitle));
+static std::unique_ptr<MustacheTemplateFile> RecordTemplate = nullptr;
 
-  if (!I.Description.empty())
-    Out.emplace_back(genHTML(I.Description));
-
-  llvm::SmallString<64> BasePath = I.getRelativeFilePath("");
-
-  std::vector<std::unique_ptr<TagNode>> ChildNamespaces =
-      genReferencesBlock(I.Children.Namespaces, "Namespaces", BasePath);
-  appendVector(std::move(ChildNamespaces), Out);
-  std::vector<std::unique_ptr<TagNode>> ChildRecords =
-      genReferencesBlock(I.Children.Records, "Records", BasePath);
-  appendVector(std::move(ChildRecords), Out);
-
-  std::vector<std::unique_ptr<TagNode>> ChildFunctions =
-      genFunctionsBlock(I.Children.Functions, CDCtx, BasePath);
-  appendVector(std::move(ChildFunctions), Out);
-  std::vector<std::unique_ptr<TagNode>> ChildEnums =
-      genEnumsBlock(I.Children.Enums, CDCtx);
-  appendVector(std::move(ChildEnums), Out);
-
-  if (!I.Children.Namespaces.empty())
-    InfoIndex.Children.emplace_back("Namespaces", "Namespaces");
-  if (!I.Children.Records.empty())
-    InfoIndex.Children.emplace_back("Records", "Records");
-  if (!I.Children.Functions.empty())
-    InfoIndex.Children.emplace_back(
-        genInfoIndexItem(I.Children.Functions, "Functions"));
-  if (!I.Children.Enums.empty())
-    InfoIndex.Children.emplace_back(
-        genInfoIndexItem(I.Children.Enums, "Enums"));
-
-  return Out;
-}
-
-static std::vector<std::unique_ptr<TagNode>>
-genHTML(const RecordInfo &I, Index &InfoIndex, const ClangDocContext &CDCtx,
-        std::string &InfoTitle) {
-  std::vector<std::unique_ptr<TagNode>> Out;
-  InfoTitle = (getTagType(I.TagType) + " " + I.Name).str();
-  Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_H1, InfoTitle));
-
-  maybeWriteSourceFileRef(Out, CDCtx, I.DefLoc);
-
-  if (!I.Description.empty())
-    Out.emplace_back(genHTML(I.Description));
-
-  std::vector<std::unique_ptr<HTMLNode>> Parents =
-      genReferenceList(I.Parents, I.Path);
-  std::vector<std::unique_ptr<HTMLNode>> VParents =
-      genReferenceList(I.VirtualParents, I.Path);
-  if (!Parents.empty() || !VParents.empty()) {
-    Out.emplace_back(std::make_unique<TagNode>(HTMLTag::TAG_P));
-    auto &PBody = Out.back();
-    PBody->Children.emplace_back(std::make_unique<TextNode>("Inherits from "));
-    if (Parents.empty())
-      appendVector(std::move(VParents), PBody->Children);
-    else if (VParents.empty())
-      appendVector(std::move(Parents), PBody->Children);
-    else {
-      appendVector(std::move(Parents), PBody->Children);
-      PBody->Children.emplace_back(std::make_unique<TextNode>(", "));
-      appendVector(std::move(VParents), PBody->Children);
-    }
-  }
-
-  std::vector<std::unique_ptr<TagNode>> Members =
-      genRecordMembersBlock(I.Members, I.Path);
-  appendVector(std::move(Members), Out);
-  std::vector<std::unique_ptr<TagNode>> ChildRecords =
-      genReferencesBlock(I.Children.Records, "Records", I.Path);
-  appendVector(std::move(ChildRecords), Out);
-
-  std::vector<std::unique_ptr<TagNode>> ChildFunctions =
-      genFunctionsBlock(I.Children.Functions, CDCtx, I.Path);
-  appendVector(std::move(ChildFunctions), Out);
-  std::vector<std::unique_ptr<TagNode>> ChildEnums =
-      genEnumsBlock(I.Children.Enums, CDCtx);
-  appendVector(std::move(ChildEnums), Out);
-
-  if (!I.Members.empty())
-    InfoIndex.Children.emplace_back("Members", "Members");
-  if (!I.Children.Records.empty())
-    InfoIndex.Children.emplace_back("Records", "Records");
-  if (!I.Children.Functions.empty())
-    InfoIndex.Children.emplace_back(
-        genInfoIndexItem(I.Children.Functions, "Functions"));
-  if (!I.Children.Enums.empty())
-    InfoIndex.Children.emplace_back(
-        genInfoIndexItem(I.Children.Enums, "Enums"));
-
-  return Out;
-}
-
-static std::vector<std::unique_ptr<TagNode>>
-genHTML(const TypedefInfo &I, const ClangDocContext &CDCtx,
-        std::string &InfoTitle) {
-  // TODO support typedefs in HTML.
-  return {};
-}
-
-/// Generator for HTML documentation.
-class HTMLGenerator : public Generator {
+class HTMLGenerator : public MustacheGenerator {
 public:
   static const char *Format;
-
+  Error createResources(ClangDocContext &CDCtx) override;
+  Error generateDocForInfo(Info *I, raw_ostream &OS,
+                           const ClangDocContext &CDCtx) override;
+  Error setupTemplateFiles(const ClangDocContext &CDCtx) override;
+  Error generateDocForJSON(json::Value &JSON, raw_fd_ostream &OS,
+                           const ClangDocContext &CDCtx, StringRef ObjTypeStr,
+                           StringRef RelativeRootPath) override;
+  // Populates templates with CSS stylesheets, JS scripts paths.
+  Error setupTemplateResources(const ClangDocContext &CDCtx, json::Value &V,
+                               SmallString<128> RelativeRootPath);
   llvm::Error generateDocumentation(
       StringRef RootDir, llvm::StringMap<std::unique_ptr<doc::Info>> Infos,
       const ClangDocContext &CDCtx, std::string DirName) override;
-  llvm::Error createResources(ClangDocContext &CDCtx) override;
-  llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS,
-                                 const ClangDocContext &CDCtx) override;
 };
 
-const char *HTMLGenerator::Format = "html";
-
-llvm::Error HTMLGenerator::generateDocumentation(
-    StringRef RootDir, llvm::StringMap<std::unique_ptr<doc::Info>> Infos,
-    const ClangDocContext &CDCtx, std::string DirName) {
-  // Track which directories we already tried to create.
-  llvm::StringSet<> CreatedDirs;
+Error HTMLGenerator::setupTemplateFiles(const ClangDocContext &CDCtx) {
+  // Template files need to use the native path when they're opened,
+  // but have to be used in POSIX style when used in HTML.
+  auto ConvertToNative = [](std::string &&Path) -> std::string {
+    SmallString<128> PathBuf(Path);
+    llvm::sys::path::native(PathBuf);
+    return PathBuf.str().str();
+  };
 
-  // Collect all output by file name and create the nexessary directories.
-  llvm::StringMap<std::vector<doc::Info *>> FileToInfos;
-  for (const auto &Group : Infos) {
-    doc::Info *Info = Group.getValue().get();
+  std::string NamespaceFilePath =
+      ConvertToNative(CDCtx.MustacheTemplates.lookup("namespace-template"));
+  std::string ClassFilePath =
+      ConvertToNative(CDCtx.MustacheTemplates.lookup("class-template"));
+  std::string CommentFilePath =
+      ConvertToNative(CDCtx.MustacheTemplates.lookup("comment-template"));
+  std::string FunctionFilePath =
+      ConvertToNative(CDCtx.MustacheTemplates.lookup("function-template"));
+  std::string EnumFilePath =
+      ConvertToNative(CDCtx.MustacheTemplates.lookup("enum-template"));
+  std::vector<std::pair<StringRef, StringRef>> Partials = {
+      {"Comments", CommentFilePath},
+      {"FunctionPartial", FunctionFilePath},
+      {"EnumPartial", EnumFilePath}};
+
+  if (Error Err = setupTemplate(NamespaceTemplate, NamespaceFilePath, Partials))
+    return Err;
 
-    llvm::SmallString<128> Path;
-    llvm::sys::path::native(RootDir, Path);
-    llvm::sys::path::append(Path, Info->getRelativeFilePath(""));
-    if (!CreatedDirs.contains(Path)) {
-      if (std::error_code Err = llvm::sys::fs::create_directories(Path);
-          Err != std::error_code()) {
-        return llvm::createStringError(Err, "Failed to create directory '%s'.",
-                                       Path.c_str());
-      }
-      CreatedDirs.insert(Path);
-    }
+  if (Error Err = setupTemplate(RecordTemplate, ClassFilePath, Partials))
+    return Err;
 
-    llvm::sys::path::append(Path, Info->getFileBaseName() + ".html");
-    FileToInfos[Path].push_back(Info);
-  }
+  return Error::success();
+}
 
-  for (const auto &Group : FileToInfos) {
-    std::error_code FileErr;
-    llvm::raw_fd_ostream InfoOS(Group.getKey(), FileErr,
-                                llvm::sys::fs::OF_Text);
-    if (FileErr) {
-      return llvm::createStringError(FileErr, "Error opening file '%s'",
-                                     Group.getKey().str().c_str());
-    }
+Error HTMLGenerator::setupTemplateResources(const ClangDocContext &CDCtx,
+                                            json::Value &V,
+                                            SmallString<128> RelativeRootPath) {
+  V.getAsObject()->insert({"ProjectName", CDCtx.ProjectName});
+  json::Value StylesheetArr = Array();
+  sys::path::native(RelativeRootPath, sys::path::Style::posix);
 
-    // TODO: https://github.com/llvm/llvm-project/issues/59073
-    // If there are multiple Infos for this file name (for example, template
-    // specializations), this will generate multiple complete web pages (with
-    // <DOCTYPE> and <title>, etc.) concatenated together. This generator needs
-    // some refactoring to be able to output the headers separately from the
-    // contents.
-    for (const auto &Info : Group.getValue()) {
-      if (llvm::Error Err = generateDocForInfo(Info, InfoOS, CDCtx)) {
-        return Err;
-      }
-    }
+  auto *SSA = StylesheetArr.getAsArray();
+  SSA->reserve(CDCtx.UserStylesheets.size());
+  for (const auto &FilePath : CDCtx.UserStylesheets) {
+    SmallString<128> StylesheetPath = RelativeRootPath;
+    sys::path::append(StylesheetPath, sys::path::Style::posix,
+                      sys::path::filename(FilePath));
+    SSA->emplace_back(StylesheetPath);
+  }
+  V.getAsObject()->insert({"Stylesheets", StylesheetArr});
+
+  json::Value ScriptArr = Array();
+  auto *SCA = ScriptArr.getAsArray();
+  SCA->reserve(CDCtx.JsScripts.size());
+  for (auto Script : CDCtx.JsScripts) {
+    SmallString<128> JsPath = RelativeRootPath;
+    sys::path::append(JsPath, sys::path::Style::posix,
+                      sys::path::filename(Script));
+    SCA->emplace_back(JsPath);
+  }
+  V.getAsObject()->insert({"Scripts", ScriptArr});
+  return Error::success();
+}
+
+Error HTMLGenerator::generateDocForJSON(json::Value &JSON, raw_fd_ostream &OS,
+                                        const ClangDocContext &CDCtx,
+                                        StringRef ObjTypeStr,
+                                        StringRef RelativeRootPath) {
+  if (ObjTypeStr == "namespace") {
+    if (auto Err = setupTemplateResources(CDCtx, JSON, RelativeRootPath))
+      return Err;
+    assert(NamespaceTemplate && "NamespaceTemplate is nullptr.");
+    NamespaceTemplate->render(JSON, OS);
+  } else if (ObjTypeStr == "record") {
+    if (auto Err = setupTemplateResources(CDCtx, JSON, RelativeRootPath))
+      return Err;
+    assert(RecordTemplate && "RecordTemplate is nullptr.");
+    RecordTemplate->render(JSON, OS);
   }
-
-  return llvm::Error::success();
+  return Error::success();
 }
 
-llvm::Error HTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
-                                              const ClangDocContext &CDCtx) {
-  std::string InfoTitle;
-  std::vector<std::unique_ptr<TagNode>> MainContentNodes;
-  Index InfoIndex;
+Error HTMLGenerator::generateDocForInfo(Info *I, raw_ostream &OS,
+                                        const ClangDocContext &CDCtx) {
   switch (I->IT) {
-  case InfoType::IT_namespace:
-    MainContentNodes = genHTML(*static_cast<clang::doc::NamespaceInfo *>(I),
-                               InfoIndex, CDCtx, InfoTitle);
-    break;
-  case InfoType::IT_record:
-    MainContentNodes = genHTML(*static_cast<clang::doc::RecordInfo *>(I),
-                               InfoIndex, CDCtx, InfoTitle);
-    break;
   case InfoType::IT_enum:
-    MainContentNodes = genHTML(*static_cast<clang::doc::EnumInfo *>(I), CDCtx);
-    break;
   case InfoType::IT_function:
-    MainContentNodes =
-        genHTML(*static_cast<clang::doc::FunctionInfo *>(I), CDCtx, "");
-    break;
   case InfoType::IT_typedef:
-    MainContentNodes =
-        genHTML(*static_cast<clang::doc::TypedefInfo *>(I), CDCtx, InfoTitle);
-    break;
-  case InfoType::IT_concept:
-  case InfoType::IT_variable:
-  case InfoType::IT_friend:
-    break;
-  case InfoType::IT_default:
-    return llvm::createStringError(llvm::inconvertibleErrorCode(),
-                                   "unexpected info type");
-  }
-
-  HTMLFile F = genInfoFile(InfoTitle, I->getRelativeFilePath(""),
-                           MainContentNodes, InfoIndex, CDCtx);
-  F.render(OS);
-
-  return llvm::Error::success();
-}
-
-static std::string getRefType(InfoType IT) {
-  switch (IT) {
-  case InfoType::IT_default:
-    return "default";
   case InfoType::IT_namespace:
-    return "namespace";
   case InfoType::IT_record:
-    return "record";
-  case InfoType::IT_function:
-    return "function";
-  case InfoType::IT_enum:
-    return "enum";
-  case InfoType::IT_typedef:
-    return "typedef";
   case InfoType::IT_concept:
-    return "concept";
   case InfoType::IT_variable:
-    return "variable";
   case InfoType::IT_friend:
-    return "friend";
-  }
-  llvm_unreachable("Unknown InfoType");
-}
-
-static llvm::Error serializeIndex(ClangDocContext &CDCtx) {
-  std::error_code OK;
-  std::error_code FileErr;
-  llvm::SmallString<128> FilePath;
-  llvm::sys::path::native(CDCtx.OutDirectory, FilePath);
-  llvm::sys::path::append(FilePath, "index_json.js");
-  llvm::raw_fd_ostream OS(FilePath, FileErr, llvm::sys::fs::OF_Text);
-  if (FileErr != OK) {
-    return llvm::createStringError(llvm::inconvertibleErrorCode(),
-                                   "error creating index file: " +
-                                       FileErr.message());
-  }
-  llvm::SmallString<128> RootPath(CDCtx.OutDirectory);
-  if (llvm::sys::path::is_relative(RootPath)) {
-    llvm::sys::fs::make_absolute(RootPath);
+    break;
+  case InfoType::IT_default:
+    return createStringError(inconvertibleErrorCode(), "unexpected InfoType");
   }
-  // Replace the escaped characters with a forward slash. It shouldn't matter
-  // when rendering the webpage in a web browser. This helps to prevent the
-  // JavaScript from escaping characters incorrectly, and introducing  bad paths
-  // in the URLs.
-  std::string RootPathEscaped = RootPath.str().str();
-  llvm::replace(RootPathEscaped, '\\', '/');
-  OS << "var RootPath = \"" << RootPathEscaped << "\";\n";
-
-  llvm::SmallString<128> Base(CDCtx.Base);
-  std::string BaseEscaped = Base.str().str();
-  llvm::replace(BaseEscaped, '\\', '/');
-  OS << "var Base = \"" << BaseEscaped << "\";\n";
-
-  CDCtx.Idx.sort();
-  llvm::json::OStream J(OS, 2);
-  std::function<void(Index)> IndexToJSON = [&](const Index &I) {
-    J.object([&] {
-      J.attribute("USR", toHex(llvm::toStringRef(I.USR)));
-      J.attribute("Name", I.Name);
-      J.attribute("RefType", getRefType(I.RefType));
-      J.attribute("Path", I.getRelativeFilePath(""));
-      J.attributeArray("Children", [&] {
-        for (const Index &C : I.Children)
-          IndexToJSON(C);
-      });
-    });
-  };
-  OS << "async function LoadIndex() {\nreturn";
-  IndexToJSON(CDCtx.Idx);
-  OS << ";\n}";
-  return llvm::Error::success();
+  return Error::success();
 }
 
-// Generates a main HTML node that has the main content of the file that shows
-// only the general index
-// It contains the general index with links to all the generated files
-static std::unique_ptr<TagNode> genIndexFileMainNode() {
-  auto MainNode = std::make_unique<TagNode>(HTMLTag::TAG_MAIN);
-
-  auto LeftSidebarNode = std::make_unique<TagNode>(HTMLTag::TAG_DIV);
-  LeftSidebarNode->Attributes.emplace_back("id", "sidebar-left");
-  LeftSidebarNode->Attributes.emplace_back("path", "");
-  LeftSidebarNode->Attributes.emplace_back(
-      "class", "col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left");
-  LeftSidebarNode->Attributes.emplace_back("style", "flex: 0 100%;");
-
-  MainNode->Children.emplace_back(std::move(LeftSidebarNode));
-
-  return MainNode;
+Error HTMLGenerator::createResources(ClangDocContext &CDCtx) {
+  std::string ResourcePath(CDCtx.OutDirectory + "/html");
+  for (const auto &FilePath : CDCtx.UserStylesheets)
+    if (Error Err = copyFile(FilePath, ResourcePath))
+      return Err;
+  for (const auto &FilePath : CDCtx.JsScripts)
+    if (Error Err = copyFile(FilePath, ResourcePath))
+      return Err;
+  return Error::success();
 }
 
-static llvm::Error genIndex(const ClangDocContext &CDCtx) {
-  std::error_code FileErr, OK;
-  llvm::SmallString<128> IndexPath;
-  llvm::sys::path::native(CDCtx.OutDirectory, IndexPath);
-  llvm::sys::path::append(IndexPath, "index.html");
-  llvm::raw_fd_ostream IndexOS(IndexPath, FileErr, llvm::sys::fs::OF_Text);
-  if (FileErr != OK) {
-    return llvm::createStringError(llvm::inconvertibleErrorCode(),
-                                   "error creating main index: " +
-                                       FileErr.message());
-  }
-
-  HTMLFile F;
-
-  std::vector<std::unique_ptr<TagNode>> HeadNodes =
-      genFileHeadNodes("Index", "", CDCtx);
-  std::unique_ptr<TagNode> HeaderNode = genFileHeaderNode(CDCtx.ProjectName);
-  std::unique_ptr<TagNode> MainNode = genIndexFileMainNode();
-  std::unique_ptr<TagNode> FooterNode = genFileFooterNode();
-
-  appendVector(std::move(HeadNodes), F.Children);
-  F.Children.emplace_back(std::move(HeaderNode));
-  F.Children.emplace_back(std::move(MainNode));
-  F.Children.emplace_back(std::move(FooterNode));
-
-  F.render(IndexOS);
-
-  return llvm::Error::success();
+Error HTMLGenerator::generateDocumentation(
+    StringRef RootDir, llvm::StringMap<std::unique_ptr<doc::Info>> Infos,
+    const ClangDocContext &CDCtx, std::string DirName) {
+  return MustacheGenerator::generateDocumentation(RootDir, std::move(Infos),
+                                                  CDCtx, "html");
 }
 
-llvm::Error HTMLGenerator::createResources(ClangDocContext &CDCtx) {
-  auto Err = serializeIndex(CDCtx);
-  if (Err)
-    return Err;
-  Err = genIndex(CDCtx);
-  if (Err)
-    return Err;
-
-  for (const auto &FilePath : CDCtx.UserStylesheets) {
-    Err = copyFile(FilePath, CDCtx.OutDirectory);
-    if (Err)
-      return Err;
-  }
-  for (const auto &FilePath : CDCtx.JsScripts) {
-    Err = copyFile(FilePath, CDCtx.OutDirectory);
-    if (Err)
-      return Err;
-  }
-  return llvm::Error::success();
-}
+const char *HTMLGenerator::Format = "html";
 
-static GeneratorRegistry::Add<HTMLGenerator> HTML(HTMLGenerator::Format,
-                                                  "Generator for HTML output.");
+static GeneratorRegistry::Add<HTMLGenerator>
+    HTML(HTMLGenerator::Format, "Generator for mustache HTML output.");
 
 // This anchor is used to force the linker to link in the generated object
 // file and thus register the generator.
diff --git a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
deleted file mode 100644
index c09f908c7eb22..0000000000000
--- a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
+++ /dev/null
@@ -1,178 +0,0 @@
-///===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file
-/// This file contains the implementation of the MustacheHTMLGenerator class,
-/// which is Clang-Doc generator for HTML using Mustache templates.
-///
-//===----------------------------------------------------------------------===//
-
-#include "Generators.h"
-#include "Representation.h"
-#include "support/File.h"
-#include "llvm/Support/Error.h"
-#include "llvm/Support/Path.h"
-
-using namespace llvm;
-using namespace llvm::json;
-using namespace llvm::mustache;
-
-namespace clang {
-namespace doc {
-
-static std::unique_ptr<MustacheTemplateFile> NamespaceTemplate = nullptr;
-
-static std::unique_ptr<MustacheTemplateFile> RecordTemplate = nullptr;
-
-class MustacheHTMLGenerator : public MustacheGenerator {
-public:
-  static const char *Format;
-  Error createResources(ClangDocContext &CDCtx) override;
-  Error generateDocForInfo(Info *I, raw_ostream &OS,
-                           const ClangDocContext &CDCtx) override;
-  Error setupTemplateFiles(const ClangDocContext &CDCtx) override;
-  Error generateDocForJSON(json::Value &JSON, raw_fd_ostream &OS,
-                           const ClangDocContext &CDCtx, StringRef ObjTypeStr,
-                           StringRef RelativeRootPath) override;
-  // Populates templates with CSS stylesheets, JS scripts paths.
-  Error setupTemplateResources(const ClangDocContext &CDCtx, json::Value &V,
-                               SmallString<128> RelativeRootPath);
-  llvm::Error generateDocumentation(
-      StringRef RootDir, llvm::StringMap<std::unique_ptr<doc::Info>> Infos,
-      const ClangDocContext &CDCtx, std::string DirName) override;
-};
-
-Error MustacheHTMLGenerator::setupTemplateFiles(const ClangDocContext &CDCtx) {
-  // Template files need to use the native path when they're opened,
-  // but have to be used in POSIX style when used in HTML.
-  auto ConvertToNative = [](std::string &&Path) -> std::string {
-    SmallString<128> PathBuf(Path);
-    llvm::sys::path::native(PathBuf);
-    return PathBuf.str().str();
-  };
-
-  std::string NamespaceFilePath =
-      ConvertToNative(CDCtx.MustacheTemplates.lookup("namespace-template"));
-  std::string ClassFilePath =
-      ConvertToNative(CDCtx.MustacheTemplates.lookup("class-template"));
-  std::string CommentFilePath =
-      ConvertToNative(CDCtx.MustacheTemplates.lookup("comment-template"));
-  std::string FunctionFilePath =
-      ConvertToNative(CDCtx.MustacheTemplates.lookup("function-template"));
-  std::string EnumFilePath =
-      ConvertToNative(CDCtx.MustacheTemplates.lookup("enum-template"));
-  std::vector<std::pair<StringRef, StringRef>> Partials = {
-      {"Comments", CommentFilePath},
-      {"FunctionPartial", FunctionFilePath},
-      {"EnumPartial", EnumFilePath}};
-
-  if (Error Err = setupTemplate(NamespaceTemplate, NamespaceFilePath, Partials))
-    return Err;
-
-  if (Error Err = setupTemplate(RecordTemplate, ClassFilePath, Partials))
-    return Err;
-
-  return Error::success();
-}
-
-Error MustacheHTMLGenerator::setupTemplateResources(
-    const ClangDocContext &CDCtx, json::Value &V,
-    SmallString<128> RelativeRootPath) {
-  V.getAsObject()->insert({"ProjectName", CDCtx.ProjectName});
-  json::Value StylesheetArr = Array();
-  sys::path::native(RelativeRootPath, sys::path::Style::posix);
-
-  auto *SSA = StylesheetArr.getAsArray();
-  SSA->reserve(CDCtx.UserStylesheets.size());
-  for (const auto &FilePath : CDCtx.UserStylesheets) {
-    SmallString<128> StylesheetPath = RelativeRootPath;
-    sys::path::append(StylesheetPath, sys::path::Style::posix,
-                      sys::path::filename(FilePath));
-    SSA->emplace_back(StylesheetPath);
-  }
-  V.getAsObject()->insert({"Stylesheets", StylesheetArr});
-
-  json::Value ScriptArr = Array();
-  auto *SCA = ScriptArr.getAsArray();
-  SCA->reserve(CDCtx.JsScripts.size());
-  for (auto Script : CDCtx.JsScripts) {
-    SmallString<128> JsPath = RelativeRootPath;
-    sys::path::append(JsPath, sys::path::Style::posix,
-                      sys::path::filename(Script));
-    SCA->emplace_back(JsPath);
-  }
-  V.getAsObject()->insert({"Scripts", ScriptArr});
-  return Error::success();
-}
-
-Error MustacheHTMLGenerator::generateDocForJSON(json::Value &JSON,
-                                                raw_fd_ostream &OS,
-                                                const ClangDocContext &CDCtx,
-                                                StringRef ObjTypeStr,
-                                                StringRef RelativeRootPath) {
-  if (ObjTypeStr == "namespace") {
-    if (auto Err = setupTemplateResources(CDCtx, JSON, RelativeRootPath))
-      return Err;
-    assert(NamespaceTemplate && "NamespaceTemplate is nullptr.");
-    NamespaceTemplate->render(JSON, OS);
-  } else if (ObjTypeStr == "record") {
-    if (auto Err = setupTemplateResources(CDCtx, JSON, RelativeRootPath))
-      return Err;
-    assert(RecordTemplate && "RecordTemplate is nullptr.");
-    RecordTemplate->render(JSON, OS);
-  }
-  return Error::success();
-}
-
-Error MustacheHTMLGenerator::generateDocForInfo(Info *I, raw_ostream &OS,
-                                                const ClangDocContext &CDCtx) {
-  switch (I->IT) {
-  case InfoType::IT_enum:
-  case InfoType::IT_function:
-  case InfoType::IT_typedef:
-  case InfoType::IT_namespace:
-  case InfoType::IT_record:
-  case InfoType::IT_concept:
-  case InfoType::IT_variable:
-  case InfoType::IT_friend:
-    break;
-  case InfoType::IT_default:
-    return createStringError(inconvertibleErrorCode(), "unexpected InfoType");
-  }
-  return Error::success();
-}
-
-Error MustacheHTMLGenerator::createResources(ClangDocContext &CDCtx) {
-  std::string ResourcePath(CDCtx.OutDirectory + "/html");
-  for (const auto &FilePath : CDCtx.UserStylesheets)
-    if (Error Err = copyFile(FilePath, ResourcePath))
-      return Err;
-  for (const auto &FilePath : CDCtx.JsScripts)
-    if (Error Err = copyFile(FilePath, ResourcePath))
-      return Err;
-  return Error::success();
-}
-
-Error MustacheHTMLGenerator::generateDocumentation(
-    StringRef RootDir, llvm::StringMap<std::unique_ptr<doc::Info>> Infos,
-    const ClangDocContext &CDCtx, std::string DirName) {
-  return MustacheGenerator::generateDocumentation(RootDir, std::move(Infos),
-                                                  CDCtx, "html");
-}
-
-const char *MustacheHTMLGenerator::Format = "mustache";
-
-static GeneratorRegistry::Add<MustacheHTMLGenerator>
-    MHTML(MustacheHTMLGenerator::Format, "Generator for mustache HTML output.");
-
-// This anchor is used to force the linker to link in the generated object
-// file and thus register the generator.
-volatile int MHTMLGeneratorAnchorSource = 0;
-
-} // namespace doc
-} // namespace clang
diff --git a/clang-tools-extra/clang-doc/support/Utils.cpp b/clang-tools-extra/clang-doc/support/Utils.cpp
index 897a7ad0adb79..f410bfcf956d4 100644
--- a/clang-tools-extra/clang-doc/support/Utils.cpp
+++ b/clang-tools-extra/clang-doc/support/Utils.cpp
@@ -28,8 +28,7 @@ SmallString<128> appendPathPosix(StringRef Base, StringRef Path) {
   return Default;
 }
 
-void getMustacheHtmlFiles(StringRef AssetsPath,
-                          clang::doc::ClangDocContext &CDCtx) {
+void getHtmlFiles(StringRef AssetsPath, clang::doc::ClangDocContext &CDCtx) {
   assert(!AssetsPath.empty());
   assert(sys::fs::is_directory(AssetsPath));
 
diff --git a/clang-tools-extra/clang-doc/support/Utils.h b/clang-tools-extra/clang-doc/support/Utils.h
index 8161c37503f81..f4ed9ec42dce4 100644
--- a/clang-tools-extra/clang-doc/support/Utils.h
+++ b/clang-tools-extra/clang-doc/support/Utils.h
@@ -20,7 +20,7 @@ llvm::SmallString<128> appendPathNative(llvm::StringRef Base,
 llvm::SmallString<128> appendPathPosix(llvm::StringRef Base,
                                        llvm::StringRef Path);
 
-void getMustacheHtmlFiles(llvm::StringRef AssetsPath,
-                          clang::doc::ClangDocContext &CDCtx);
+void getHtmlFiles(llvm::StringRef AssetsPath,
+                  clang::doc::ClangDocContext &CDCtx);
 
 #endif
diff --git a/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp b/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
index 8de7c8ad6f000..86fbb17a5f6a3 100644
--- a/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
+++ b/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
@@ -108,21 +108,20 @@ Turn on time profiler. Generates clang-doc-tracing.json)"),
                                       llvm::cl::init(false),
                                       llvm::cl::cat(ClangDocCategory));
 
-enum OutputFormatTy { md, yaml, html, mustache, json };
-
-static llvm::cl::opt<OutputFormatTy> FormatEnum(
-    "format", llvm::cl::desc("Format for outputted docs."),
-    llvm::cl::values(clEnumValN(OutputFormatTy::yaml, "yaml",
-                                "Documentation in YAML format."),
-                     clEnumValN(OutputFormatTy::md, "md",
-                                "Documentation in MD format."),
-                     clEnumValN(OutputFormatTy::html, "html",
-                                "Documentation in HTML format."),
-                     clEnumValN(OutputFormatTy::mustache, "mustache",
-                                "Documentation in mustache HTML format"),
-                     clEnumValN(OutputFormatTy::json, "json",
-                                "Documentation in JSON format")),
-    llvm::cl::init(OutputFormatTy::yaml), llvm::cl::cat(ClangDocCategory));
+enum OutputFormatTy { md, yaml, html, json };
+
+static llvm::cl::opt<OutputFormatTy>
+    FormatEnum("format", llvm::cl::desc("Format for outputted docs."),
+               llvm::cl::values(clEnumValN(OutputFormatTy::yaml, "yaml",
+                                           "Documentation in YAML format."),
+                                clEnumValN(OutputFormatTy::md, "md",
+                                           "Documentation in MD format."),
+                                clEnumValN(OutputFormatTy::html, "html",
+                                           "Documentation in HTML format."),
+                                clEnumValN(OutputFormatTy::json, "json",
+                                           "Documentation in JSON format")),
+               llvm::cl::init(OutputFormatTy::yaml),
+               llvm::cl::cat(ClangDocCategory));
 
 static llvm::ExitOnError ExitOnErr;
 
@@ -134,8 +133,6 @@ static std::string getFormatString() {
     return "md";
   case OutputFormatTy::html:
     return "html";
-  case OutputFormatTy::mustache:
-    return "mustache";
   case OutputFormatTy::json:
     return "json";
   }
@@ -172,51 +169,8 @@ static llvm::Error getAssetFiles(clang::doc::ClangDocContext &CDCtx) {
   return llvm::Error::success();
 }
 
-static llvm::Error getDefaultAssetFiles(const char *Argv0,
-                                        clang::doc::ClangDocContext &CDCtx) {
-  void *MainAddr = (void *)(intptr_t)getExecutablePath;
-  std::string ClangDocPath = getExecutablePath(Argv0, MainAddr);
-  llvm::SmallString<128> NativeClangDocPath;
-  llvm::sys::path::native(ClangDocPath, NativeClangDocPath);
-
-  llvm::SmallString<128> AssetsPath;
-  AssetsPath = llvm::sys::path::parent_path(NativeClangDocPath);
-  llvm::sys::path::append(AssetsPath, "..", "share", "clang-doc");
-  llvm::SmallString<128> DefaultStylesheet =
-      appendPathNative(AssetsPath, "clang-doc-default-stylesheet.css");
-  llvm::SmallString<128> IndexJS = appendPathNative(AssetsPath, "index.js");
-
-  if (!llvm::sys::fs::is_regular_file(IndexJS))
-    return llvm::createStringError(llvm::inconvertibleErrorCode(),
-                                   "default index.js file missing at " +
-                                       IndexJS + "\n");
-
-  if (!llvm::sys::fs::is_regular_file(DefaultStylesheet))
-    return llvm::createStringError(
-        llvm::inconvertibleErrorCode(),
-        "default clang-doc-default-stylesheet.css file missing at " +
-            DefaultStylesheet + "\n");
-
-  CDCtx.UserStylesheets.insert(CDCtx.UserStylesheets.begin(),
-                               std::string(DefaultStylesheet));
-  CDCtx.JsScripts.emplace_back(IndexJS.str());
-
-  return llvm::Error::success();
-}
-
-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";
-  if (llvm::sys::fs::is_directory(std::string(UserAssetPath)))
-    return getAssetFiles(CDCtx);
-  return getDefaultAssetFiles(Argv0, CDCtx);
-}
-
-static llvm::Error getMustacheHtmlFiles(const char *Argv0,
-                                        clang::doc::ClangDocContext &CDCtx) {
+static llvm::Error getHtmlFiles(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
@@ -234,7 +188,7 @@ static llvm::Error getMustacheHtmlFiles(const char *Argv0,
   AssetsPath = llvm::sys::path::parent_path(NativeClangDocPath);
   llvm::sys::path::append(AssetsPath, "..", "share", "clang-doc");
 
-  getMustacheHtmlFiles(AssetsPath, CDCtx);
+  getHtmlFiles(AssetsPath, CDCtx);
 
   return llvm::Error::success();
 }
@@ -326,11 +280,8 @@ Example usage for a project using a compile commands database:
         {UserStylesheets.begin(), UserStylesheets.end()},
         FTimeTrace};
 
-    if (Format == "html") {
-      ExitOnErr(getHtmlAssetFiles(argv[0], CDCtx));
-    } else if (Format == "mustache") {
-      ExitOnErr(getMustacheHtmlFiles(argv[0], CDCtx));
-    }
+    if (Format == "html")
+      ExitOnErr(getHtmlFiles(argv[0], CDCtx));
 
     llvm::timeTraceProfilerBegin("Executor Launch", "total runtime");
     // Mapping phase
diff --git a/clang-tools-extra/test/clang-doc/DR-131697.cpp b/clang-tools-extra/test/clang-doc/DR-131697.cpp
index 06168e6642f62..9025bbf910813 100644
--- a/clang-tools-extra/test/clang-doc/DR-131697.cpp
+++ b/clang-tools-extra/test/clang-doc/DR-131697.cpp
@@ -1,7 +1,6 @@
 // RUN: rm -rf %t && mkdir -p %t
 // RUN: split-file %s %t
 // RUN: clang-doc -format=html %t/compile_commands.json %t/main.cpp
-// RUN: clang-doc -format=mustache %t/compile_commands.json %t/main.cpp
 
 //--- main.cpp
 
diff --git a/clang-tools-extra/test/clang-doc/assets.cpp b/clang-tools-extra/test/clang-doc/assets.cpp
index 00d0d32213965..65565bbf4296d 100644
--- a/clang-tools-extra/test/clang-doc/assets.cpp
+++ b/clang-tools-extra/test/clang-doc/assets.cpp
@@ -1,32 +1,11 @@
 // RUN: rm -rf %t && mkdir %t
 // RUN: clang-doc --format=html --output=%t --asset=%S/Inputs/test-assets --executor=standalone %s --base base_dir
-// RUN: clang-doc --format=mustache --output=%t --asset=%S/Inputs/test-assets --executor=standalone %s --base base_dir
-// RUN: FileCheck %s -input-file=%t/index.html -check-prefix=INDEX
-// RUN: FileCheck %s -input-file=%t/test.css -check-prefix=CSS
-// RUN: FileCheck %s -input-file=%t/test.js -check-prefix=JS
+// RUN: FileCheck %s -input-file=%t/html/test.css -check-prefix=CSS
+// RUN: FileCheck %s -input-file=%t/html/test.js -check-prefix=JS
 
-// RUN: FileCheck %s -input-file=%t/html/test.css -check-prefix=MUSTACHE-CSS
-// RUN: FileCheck %s -input-file=%t/html/test.js -check-prefix=MUSTACHE-JS
-
-// INDEX: <!DOCTYPE html>
-// INDEX-NEXT: <meta charset="utf-8"/>
-// INDEX-NEXT: <title>Index</title>
-// INDEX-NEXT: <link rel="stylesheet" href="test.css"/>
-// INDEX-NEXT: <script src="index_json.js"></script>
-// INDEX-NEXT: <script src="test.js"></script>
-// INDEX-NEXT: <header id="project-title"></header>
-// INDEX-NEXT: <main>
-// INDEX-NEXT:   <div id="sidebar-left" path="" class="col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left" style="flex: 0 100%;"></div>
-// INDEX-NEXT: </main>
 
 // CSS: body {
 // CSS-NEXT:     padding: 0;
 // CSS-NEXT: }
 
-// MUSTACHE-CSS: body {
-// MUSTACHE-CSS-NEXT:     padding: 0;
-// MUSTACHE-CSS-NEXT: }
-
 // JS: console.log("Hello, world!");
-
-// MUSTACHE-JS: console.log("Hello, world!");
diff --git a/clang-tools-extra/test/clang-doc/basic-project.mustache.test b/clang-tools-extra/test/clang-doc/basic-project.mustache.test
index 9f7de6e689313..282ca73384c3f 100644
--- a/clang-tools-extra/test/clang-doc/basic-project.mustache.test
+++ b/clang-tools-extra/test/clang-doc/basic-project.mustache.test
@@ -1,7 +1,7 @@
 // RUN: rm -rf %t && mkdir -p %t/docs %t/build
 // RUN: sed 's|$test_dir|%/S|g' %S/Inputs/basic-project/database_template.json > %t/build/compile_commands.json
 
-// RUN: clang-doc --format=mustache --output=%t/docs --executor=all-TUs %t/build/compile_commands.json
+// RUN: clang-doc --format=html --output=%t/docs --executor=all-TUs %t/build/compile_commands.json
 // RUN: FileCheck %s -input-file=%t/docs/html/GlobalNamespace/_ZTV5Shape.html -check-prefix=HTML-SHAPE
 // RUN: FileCheck %s -input-file=%t/docs/html/GlobalNamespace/_ZTV10Calculator.html -check-prefix=HTML-CALC
 // RUN: FileCheck %s -input-file=%t/docs/html/GlobalNamespace/_ZTV9Rectangle.html -check-prefix=HTML-RECTANGLE
diff --git a/clang-tools-extra/test/clang-doc/basic-project.test b/clang-tools-extra/test/clang-doc/basic-project.test
index 9c1ed29973d79..9220dc6974508 100644
--- a/clang-tools-extra/test/clang-doc/basic-project.test
+++ b/clang-tools-extra/test/clang-doc/basic-project.test
@@ -1,31 +1,6 @@
 // RUN: rm -rf %t && mkdir -p %t/docs %t/build
 // RUN: sed 's|$test_dir|%/S|g' %S/Inputs/basic-project/database_template.json > %t/build/compile_commands.json
 
-// RUN: clang-doc --format=html --output=%t/docs --executor=all-TUs %t/build/compile_commands.json
-// RUN: FileCheck %s -input-file=%t/docs/index_json.js -check-prefix=JSON-INDEX
-// RUN: FileCheck %s -input-file=%t/docs/GlobalNamespace/Shape.html -check-prefix=HTML-SHAPE
-// RUN: FileCheck %s -input-file=%t/docs/GlobalNamespace/Calculator.html -check-prefix=HTML-CALC
-// RUN: FileCheck %s -input-file=%t/docs/GlobalNamespace/Rectangle.html -check-prefix=HTML-RECTANGLE
-// RUN: FileCheck %s -input-file=%t/docs/GlobalNamespace/Circle.html -check-prefix=HTML-CIRCLE
-
-// RUN: clang-doc --format=html --output=%t/docs-with-prefix --executor=all-TUs %t/build/compile_commands.json --repository=https://repository.com --repository-line-prefix=L
-// RUN: FileCheck %s -input-file=%t/docs-with-prefix/GlobalNamespace/Shape.html -check-prefixes=HTML-SHAPE,SHAPE-LINE-PREFIX
-// RUN: FileCheck %s -input-file=%t/docs-with-prefix/GlobalNamespace/Calculator.html -check-prefixes=HTML-CALC,CALC-LINE-PREFIX
-// RUN: FileCheck %s -input-file=%t/docs-with-prefix/GlobalNamespace/Rectangle.html -check-prefixes=HTML-RECTANGLE,RECTANGLE-LINE-PREFIX
-// RUN: FileCheck %s -input-file=%t/docs-with-prefix/GlobalNamespace/Circle.html -check-prefixes=HTML-CIRCLE,CIRCLE-LINE-PREFIX
-
-// RUN: FileCheck %s -input-file=%t/docs/GlobalNamespace/Shape.html -check-prefixes=HTML-SHAPE,SHAPE-NO-REPOSITORY
-// RUN: FileCheck %s -input-file=%t/docs/GlobalNamespace/Calculator.html -check-prefixes=HTML-CALC,CALC-NO-REPOSITORY
-// RUN: FileCheck %s -input-file=%t/docs/GlobalNamespace/Rectangle.html -check-prefixes=HTML-RECTANGLE,RECTANGLE-NO-REPOSITORY
-// RUN: FileCheck %s -input-file=%t/docs/GlobalNamespace/Circle.html -check-prefixes=HTML-CIRCLE,CIRCLE-NO-REPOSITORY
-
-// RUN: clang-doc --format=html --output=%t/docs --executor=all-TUs %t/build/compile_commands.json --repository=https://repository.com
-// RUN: FileCheck %s -input-file=%t/docs/index_json.js -check-prefixes=JSON-INDEX
-// RUN: FileCheck %s -input-file=%t/docs/GlobalNamespace/Shape.html -check-prefixes=HTML-SHAPE,SHAPE-REPOSITORY
-// RUN: FileCheck %s -input-file=%t/docs/GlobalNamespace/Calculator.html -check-prefixes=HTML-CALC,CALC-REPOSITORY
-// RUN: FileCheck %s -input-file=%t/docs/GlobalNamespace/Rectangle.html -check-prefixes=HTML-RECTANGLE,RECTANGLE-REPOSITORY
-// RUN: FileCheck %s -input-file=%t/docs/GlobalNamespace/Circle.html -check-prefixes=HTML-CIRCLE,CIRCLE-REPOSITORY
-
 // RUN: clang-doc --format=md --output=%t/docs --executor=all-TUs %t/build/compile_commands.json
 // RUN: FileCheck %s -input-file=%t/docs/all_files.md -check-prefixes=MD-ALL-FILES
 // RUN: FileCheck %s -input-file=%t/docs/index.md -check-prefixes=MD-INDEX
@@ -81,248 +56,6 @@
 // JSON-INDEX-NEXT: };
 // JSON-INDEX-NEXT: }
 
-//      HTML-SHAPE: <h1>class Shape</h1>
-//   SHAPE-NO-REPOSITORY: <p>Defined at line 8 of file .{{.}}include{{.}}Shape.h</p>
-//      SHAPE-REPOSITORY: <p>
-// SHAPE-REPOSITORY-NEXT: Defined at line
-// SHAPE-REPOSITORY-NEXT: <a href="https://repository.com/./include/Shape.h#8">8</a>
-//     SHAPE-LINE-PREFIX: <a href="https://repository.com/./include/Shape.h#L8">8</a>
-// SHAPE-REPOSITORY-NEXT: of file
-// SHAPE-REPOSITORY-NEXT: <a href="https://repository.com/./include/Shape.h">Shape.h</a>
-// SHAPE-REPOSITORY-NEXT: </p>
-//      HTML-SHAPE: <div>brief</div>
-//      HTML-SHAPE: <p> Abstract base class for shapes.</p>
-//      HTML-SHAPE: <p> Provides a common interface for different types of shapes.</p>
-//      HTML-SHAPE: <h2 id="Functions">Functions</h2>
-//      HTML-SHAPE: <h3 id="{{([0-9A-F]{40})}}">area</h3>
-//      HTML-SHAPE: <p>public double area()</p>
-//      HTML-SHAPE: <div>brief</div>
-//      HTML-SHAPE: <p> Calculates the area of the shape.</p>
-//      HTML-SHAPE: <h3 id="{{([0-9A-F]{40})}}">perimeter</h3>
-//      HTML-SHAPE: <p>public double perimeter()</p>
-//      HTML-SHAPE: <div>brief</div>
-//      HTML-SHAPE: <p> Calculates the perimeter of the shape.</p>
-//      HTML-SHAPE: <div>return</div>
-//      HTML-SHAPE: <p> double The perimeter of the shape.</p>
-//      HTML-SHAPE: <h3 id="{{([0-9A-F]{40})}}">~Shape</h3>
-//      HTML-SHAPE: <p>public void ~Shape()</p>
-
-//   SHAPE-NO-REPOSITORY: Defined at line 13 of file .{{.}}include{{.}}Shape.h
-//      SHAPE-REPOSITORY: Defined at line 
-// SHAPE-REPOSITORY-NEXT: <a href="https://repository.com/./include/Shape.h#13">13</a>
-//     SHAPE-LINE-PREFIX: <a href="https://repository.com/./include/Shape.h#L13">13</a>
-// SHAPE-REPOSITORY-NEXT: of file 
-// SHAPE-REPOSITORY-NEXT: <a href="https://repository.com/./include/Shape.h">Shape.h</a>
-
-//      HTML-SHAPE: <div>brief</div>
-//      HTML-SHAPE: <p> Virtual destructor.</p>
-
-//      HTML-CALC: <h1>class Calculator</h1>
-// CALC-NO-REPOSITORY: <p>Defined at line 8 of file .{{.}}include{{.}}Calculator.h</p>
-//      CALC-REPOSITORY: <p>
-// CALC-REPOSITORY-NEXT: Defined at line 
-// CALC-REPOSITORY-NEXT: <a href="https://repository.com/./include/Calculator.h#8">8</a>
-//     CALC-LINE-PREFIX: <a href="https://repository.com/./include/Calculator.h#L8">8</a>
-// CALC-REPOSITORY-NEXT: of file 
-// CALC-REPOSITORY-NEXT: <a href="https://repository.com/./include/Calculator.h">Calculator.h</a>
-// CALC-REPOSITORY-NEXT: </p>
-//      HTML-CALC: <div>brief</div>
-//      HTML-CALC: <p> A simple calculator class.</p>
-//      HTML-CALC: <p> Provides basic arithmetic operations.</p>
-
-//      HTML-CALC: <h2 id="Members">Members</h2>
-//      HTML-CALC: <div>brief</div>
-//      HTML-CALC: <p> Holds a public value.</p>
-//      HTML-CALC: <div>public int public_val</div>
-//      HTML-CALC: <div>brief</div>
-//      HTML-CALC: <p> A static value.</p>
-//      HTML-CALC: <div>public static const int static_val</div>
-
-//      HTML-CALC: <h2 id="Functions">Functions</h2>
-//      HTML-CALC: <h3 id="{{([0-9A-F]{40})}}">add</h3>
-//      HTML-CALC: <p>public int add(int a, int b)</p>
-//   CALC-NO-REPOSITORY: Defined at line 3 of file .{{.}}src{{.}}Calculator.cpp
-//      CALC-REPOSITORY: Defined at line 
-// CALC-REPOSITORY-NEXT: <a href="https://repository.com/./src/Calculator.cpp#3">3</a>
-//     CALC-LINE-PREFIX: <a href="https://repository.com/./src/Calculator.cpp#L3">3</a>
-// CALC-REPOSITORY-NEXT: of file 
-// CALC-REPOSITORY-NEXT: <a href="https://repository.com/./src/Calculator.cpp">Calculator.cpp</a>
-
-//      HTML-CALC: <div>brief</div>
-//      HTML-CALC: <p> Adds two integers.</p>
-//      HTML-CALC: <div>return</div>
-//      HTML-CALC: <p> int The sum of a and b.</p>
-//      HTML-CALC: <h3 id="{{([0-9A-F]{40})}}">subtract</h3>
-//      HTML-CALC: <p>public int subtract(int a, int b)</p>
-//   CALC-NO-REPOSITORY: Defined at line 7 of file .{{.}}src{{.}}Calculator.cpp
-//      CALC-REPOSITORY: Defined at line 
-// CALC-REPOSITORY-NEXT: <a href="https://repository.com/./src/Calculator.cpp#7">7</a>
-//     CALC-LINE-PREFIX: <a href="https://repository.com/./src/Calculator.cpp#L7">7</a>
-// CALC-REPOSITORY-NEXT: of file 
-// CALC-REPOSITORY-NEXT: <a href="https://repository.com/./src/Calculator.cpp">Calculator.cpp</a>
-
-//      HTML-CALC: <div>brief</div>
-//      HTML-CALC: <p> Subtracts the second integer from the first.</p>
-//      HTML-CALC: <div>return</div>
-//      HTML-CALC: <p> int The result of a - b.</p>
-//      HTML-CALC: <h3 id="{{([0-9A-F]{40})}}">multiply</h3>
-//      HTML-CALC: <p>public int multiply(int a, int b)</p>
-//   CALC-NO-REPOSITORY: Defined at line 11 of file .{{.}}src{{.}}Calculator.cpp
-//      CALC-REPOSITORY: Defined at line 
-// CALC-REPOSITORY-NEXT: <a href="https://repository.com/./src/Calculator.cpp#11">11</a>
-//     CALC-LINE-PREFIX: <a href="https://repository.com/./src/Calculator.cpp#L11">11</a>
-// CALC-REPOSITORY-NEXT: of file 
-// CALC-REPOSITORY-NEXT: <a href="https://repository.com/./src/Calculator.cpp">Calculator.cpp</a>
-
-//      HTML-CALC: <div>brief</div>
-//      HTML-CALC: <p> Multiplies two integers.</p>
-//      HTML-CALC: <div>return</div>
-//      HTML-CALC: <p> int The product of a and b.</p>
-//      HTML-CALC: <h3 id="{{([0-9A-F]{40})}}">divide</h3>
-//      HTML-CALC: <p>public double divide(int a, int b)</p>
-//   CALC-NO-REPOSITORY: Defined at line 15 of file .{{.}}src{{.}}Calculator.cpp
-//      CALC-REPOSITORY: Defined at line 
-// CALC-REPOSITORY-NEXT: <a href="https://repository.com/./src/Calculator.cpp#15">15</a>
-//     CALC-LINE-PREFIX: <a href="https://repository.com/./src/Calculator.cpp#L15">15</a>
-// CALC-REPOSITORY-NEXT: of file 
-// CALC-REPOSITORY-NEXT: <a href="https://repository.com/./src/Calculator.cpp">Calculator.cpp</a>
-
-//      HTML-CALC: <div>brief</div>
-//      HTML-CALC: <p> Divides the first integer by the second.</p>
-//      HTML-CALC: <div>return</div>
-//      HTML-CALC: <p> double The result of a / b.</p>
-//      HTML-CALC: <div>throw</div>
-//      HTML-CALC: <p>if b is zero.</p>
-
-//      HTML-CALC: <p>public static int mod(int a, int b)</p>
-//   CALC-NO-REPOSITORY: Defined at line 54 of file .{{.}}include{{.}}Calculator.h
-//      CALC-REPOSITORY: Defined at line 
-// CALC-REPOSITORY-NEXT: <a href="https://repository.com/./include/Calculator.h#54">54</a>
-//     CALC-LINE-PREFIX: <a href="https://repository.com/./include/Calculator.h#L54">54</a>
-// CALC-REPOSITORY-NEXT: of file 
-// CALC-REPOSITORY-NEXT: <a href="https://repository.com/./include/Calculator.h">Calculator.h</a>
-//      HTML-CALC: <div>brief</div>
-//      HTML-CALC: <p> Performs the mod operation on integers.</p>
-//      HTML-CALC: <div>return</div>
-//      HTML-CALC: <p> The result of a % b.</p>
-
-//      HTML-RECTANGLE: <h1>class Rectangle</h1>
-// RECTANGLE-NO-REPOSITORY: <p>Defined at line 10 of file .{{.}}include{{.}}Rectangle.h</p>
-//      RECTANGLE-REPOSITORY: <p>
-// RECTANGLE-REPOSITORY-NEXT: Defined at line
-// RECTANGLE-REPOSITORY-NEXT: <a href="https://repository.com/./include/Rectangle.h#10">10</a>
-//     RECTANGLE-LINE-PREFIX: <a href="https://repository.com/./include/Rectangle.h#L10">10</a>
-// RECTANGLE-REPOSITORY-NEXT: of file 
-// RECTANGLE-REPOSITORY-NEXT: <a href="https://repository.com/./include/Rectangle.h">Rectangle.h</a>
-// RECTANGLE-REPOSITORY-NEXT: </p>
-
-//      HTML-RECTANGLE: <p> Represents a rectangle with a given width and height.</p>
-//      HTML-RECTANGLE: <p>
-//      HTML-RECTANGLE:   Inherits from
-//      HTML-RECTANGLE:   <a href="Shape.html">Shape</a>
-//      HTML-RECTANGLE: </p>
-//      HTML-RECTANGLE: <h2 id="Members">Members</h2>
-//      HTML-RECTANGLE: <p> Width of the rectangle.</p>
-//      HTML-RECTANGLE: <div>private double width_</div>
-//      HTML-RECTANGLE: <p> Height of the rectangle.</p>
-//      HTML-RECTANGLE: <div>private double height_</div>
-//      HTML-RECTANGLE: <h2 id="Functions">Functions</h2>
-//      HTML-RECTANGLE: <h3 id="{{([0-9A-F]{40})}}">Rectangle</h3>
-//      HTML-RECTANGLE: <p>public void Rectangle(double width, double height)</p>
-//   RECTANGLE-NO-REPOSITORY: Defined at line 3 of file .{{.}}src{{.}}Rectangle.cpp
-//      RECTANGLE-REPOSITORY: Defined at line
-// RECTANGLE-REPOSITORY-NEXT: <a href="https://repository.com/./src/Rectangle.cpp#3">3</a>
-//     RECTANGLE-LINE-PREFIX: <a href="https://repository.com/./src/Rectangle.cpp#L3">3</a>
-// RECTANGLE-REPOSITORY-NEXT: of file 
-// RECTANGLE-REPOSITORY-NEXT: <a href="https://repository.com/./src/Rectangle.cpp">Rectangle.cpp</a>
-
-//      HTML-RECTANGLE: <div>brief</div>
-//      HTML-RECTANGLE: <p> Constructs a new Rectangle object.</p>
-//      HTML-RECTANGLE: <h3 id="{{([0-9A-F]{40})}}">area</h3>
-//      HTML-RECTANGLE: <p>public double area()</p>
-//   RECTANGLE-NO-REPOSITORY: Defined at line 6 of file .{{.}}src{{.}}Rectangle.cpp
-//      RECTANGLE-REPOSITORY: Defined at line
-// RECTANGLE-REPOSITORY-NEXT: <a href="https://repository.com/./src/Rectangle.cpp#6">6</a>
-//     RECTANGLE-LINE-PREFIX: <a href="https://repository.com/./src/Rectangle.cpp#L6">6</a>
-// RECTANGLE-REPOSITORY-NEXT: of file 
-// RECTANGLE-REPOSITORY-NEXT: <a href="https://repository.com/./src/Rectangle.cpp">Rectangle.cpp</a>
-
-//      HTML-RECTANGLE: <div>brief</div>
-//      HTML-RECTANGLE: <p> Calculates the area of the rectangle.</p>
-//      HTML-RECTANGLE: <div>return</div>
-//      HTML-RECTANGLE: <p> double The area of the rectangle.</p>
-//      HTML-RECTANGLE: <h3 id="{{([0-9A-F]{40})}}">perimeter</h3>
-//      HTML-RECTANGLE: <p>public double perimeter()</p>
-//   RECTANGLE-NO-REPOSITORY: Defined at line 10 of file .{{.}}src{{.}}Rectangle.cpp
-//      RECTANGLE-REPOSITORY: Defined at line
-// RECTANGLE-REPOSITORY-NEXT: <a href="https://repository.com/./src/Rectangle.cpp#10">10</a>
-// RECTANGLE-LINE-PREFIX: <a href="https://repository.com/./src/Rectangle.cpp#L10">10</a>
-// RECTANGLE-REPOSITORY-NEXT: of file 
-// RECTANGLE-REPOSITORY-NEXT: <a href="https://repository.com/./src/Rectangle.cpp">Rectangle.cpp</a>
-//      HTML-RECTANGLE: <div>brief</div>
-//      HTML-RECTANGLE: <p> Calculates the perimeter of the rectangle.</p>
-//      HTML-RECTANGLE: <div>return</div>
-//      HTML-RECTANGLE: <p> double The perimeter of the rectangle.</p>
-
-//      HTML-CIRCLE: <h1>class Circle</h1>
-// CIRCLE-NO-REPOSITORY: <p>Defined at line 10 of file .{{.}}include{{.}}Circle.h</p>
-//      CIRCLE-REPOSITORY: <p>
-// CIRCLE-REPOSITORY-NEXT: Defined at line 
-// CIRCLE-REPOSITORY-NEXT: <a href="https://repository.com/./include/Circle.h#10">10</a>
-//     CIRCLE-LINE-PREFIX: <a href="https://repository.com/./include/Circle.h#L10">10</a>
-// CIRCLE-REPOSITORY-NEXT: of file 
-// CIRCLE-REPOSITORY-NEXT: <a href="https://repository.com/./include/Circle.h">Circle.h</a>
-// CIRCLE-REPOSITORY-NEXT: </p>
-
-//      HTML-CIRCLE: <div>brief</div>
-//      HTML-CIRCLE: <p> Circle class derived from Shape.</p>
-//      HTML-CIRCLE: <p> Represents a circle with a given radius.</p>
-//      HTML-CIRCLE: <p>
-//      HTML-CIRCLE:   Inherits from
-//      HTML-CIRCLE:   <a href="Shape.html">Shape</a>
-//      HTML-CIRCLE: </p>
-//      HTML-CIRCLE: <h2 id="Members">Members</h2>
-//      HTML-CIRCLE: <p> Radius of the circle.</p>
-//      HTML-CIRCLE: <div>private double radius_</div>
-//      HTML-CIRCLE: <h2 id="Functions">Functions</h2>
-//      HTML-CIRCLE: <h3 id="{{([0-9A-F]{40})}}">Circle</h3>
-//      HTML-CIRCLE: <p>public void Circle(double radius)</p>
-//   CIRCLE-NO-REPOSITORY: Defined at line 3 of file .{{.}}src{{.}}Circle.cpp
-//      CIRCLE-REPOSITORY: Defined at line 
-// CIRCLE-REPOSITORY-NEXT: <a href="https://repository.com/./src/Circle.cpp#3">3</a>
-//     CIRCLE-LINE-PREFIX: <a href="https://repository.com/./src/Circle.cpp#L3">3</a>
-// CIRCLE-REPOSITORY-NEXT:  of file 
-// CIRCLE-REPOSITORY-NEXT: <a href="https://repository.com/./src/Circle.cpp">Circle.cpp</a>
-
-//      HTML-CIRCLE: <div>brief</div>
-//      HTML-CIRCLE: <p> Constructs a new Circle object.</p>
-//      HTML-CIRCLE: <h3 id="{{([0-9A-F]{40})}}">area</h3>
-//      HTML-CIRCLE: <p>public double area()</p>
-//   CIRCLE-NO-REPOSITORY: Defined at line 5 of file .{{.}}src{{.}}Circle.cpp
-//      CIRCLE-REPOSITORY: Defined at line 
-// CIRCLE-REPOSITORY-NEXT: <a href="https://repository.com/./src/Circle.cpp#5">5</a>
-//     CIRCLE-LINE-PREFIX: <a href="https://repository.com/./src/Circle.cpp#L5">5</a>
-// CIRCLE-REPOSITORY-NEXT:  of file 
-// CIRCLE-REPOSITORY-NEXT: <a href="https://repository.com/./src/Circle.cpp">Circle.cpp</a>
-
-//      HTML-CIRCLE: <div>brief</div>
-//      HTML-CIRCLE: <p> Calculates the area of the circle.</p>
-//      HTML-CIRCLE: <div>return</div>
-//      HTML-CIRCLE: <p> double The area of the circle.</p>
-//      HTML-CIRCLE: <h3 id="{{([0-9A-F]{40})}}">perimeter</h3>
-//      HTML-CIRCLE: <p>public double perimeter()</p>
-//   CIRCLE-NO-REPOSITORY: Defined at line  9 of file .{{.}}src{{.}}Circle.cpp
-//      CIRCLE-REPOSITORY: Defined at line 
-// CIRCLE-REPOSITORY-NEXT: <a href="https://repository.com/./src/Circle.cpp#9">9</a>
-//     CIRCLE-LINE-PREFIX: <a href="https://repository.com/./src/Circle.cpp#L9">9</a>
-// CIRCLE-REPOSITORY-NEXT:  of file 
-// CIRCLE-REPOSITORY-NEXT: <a href="https://repository.com/./src/Circle.cpp">Circle.cpp</a>
-
-//      HTML-CIRCLE: <div>brief</div>
-//      HTML-CIRCLE: <p> Calculates the perimeter of the circle.</p>
-//      HTML-CIRCLE: <div>return</div>
-//      HTML-CIRCLE: <p> double The perimeter of the circle.</p>
-
 // MD-CALC: # class Calculator
 // MD-CALC: *Defined at .{{[\/]}}include{{[\/]}}Calculator.h#8*
 // MD-CALC: **brief** A simple calculator class.
diff --git a/clang-tools-extra/test/clang-doc/comments-in-macros.cpp b/clang-tools-extra/test/clang-doc/comments-in-macros.cpp
index 94cccd1110158..bc0ec46b72a05 100644
--- a/clang-tools-extra/test/clang-doc/comments-in-macros.cpp
+++ b/clang-tools-extra/test/clang-doc/comments-in-macros.cpp
@@ -6,12 +6,8 @@
 // RUN: FileCheck %s < %t/GlobalNamespace/MyClass.md --check-prefix=MD-MYCLASS
 
 // RUN: clang-doc --format=html --doxygen --output=%t --executor=standalone %s
-// RUN: FileCheck %s < %t/GlobalNamespace/MyClass.html --check-prefix=HTML-MYCLASS-LINE
-// RUN: FileCheck %s < %t/GlobalNamespace/MyClass.html --check-prefix=HTML-MYCLASS
-
-// RUN: clang-doc --format=mustache --doxygen --output=%t --executor=standalone %s
-// RUN: FileCheck %s < %t/html/GlobalNamespace/_ZTV7MyClass.html --check-prefix=MUSTACHE-MYCLASS-LINE
-// RUN: FileCheck %s < %t/html/GlobalNamespace/_ZTV7MyClass.html --check-prefix=MUSTACHE-MYCLASS
+// RUN: FileCheck %s < %t/html/GlobalNamespace/_ZTV7MyClass.html --check-prefix=HTML-MYCLASS-LINE
+// RUN: FileCheck %s < %t/html/GlobalNamespace/_ZTV7MyClass.html --check-prefix=HTML-MYCLASS
 
 #define DECLARE_METHODS                                           \
     /**   							  
@@ -25,22 +21,18 @@
 // MD-MYCLASS: *public int Add(int a, int b)*
 // MD-MYCLASS: **brief** Declare a method to calculate the sum of two numbers
 
-// HTML-MYCLASS: <p>public int Add(int a, int b)</p>
-// HTML-MYCLASS: <div>brief</div>
-// HTML-MYCLASS: <p> Declare a method to calculate the sum of two numbers</p>
 
-// MUSTACHE-MYCLASS: <pre><code class="language-cpp code-clang-doc">int Add (int a, int b)</code></pre>
-// MUSTACHE-MYCLASS: <div>
-// MUSTACHE-MYCLASS:     <div>
-// MUSTACHE-MYCLASS:         <p> Declare a method to calculate the sum of two numbers</p>
-// MUSTACHE-MYCLASS:     </div>
+// HTML-MYCLASS: <pre><code class="language-cpp code-clang-doc">int Add (int a, int b)</code></pre>
+// HTML-MYCLASS: <div>
+// HTML-MYCLASS:     <div>
+// HTML-MYCLASS:         <p> Declare a method to calculate the sum of two numbers</p>
+// HTML-MYCLASS:     </div>
 
 
 class MyClass {
 public:
-// MD-MYCLASS-LINE: *Defined at {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}comments-in-macros.cpp#[[@LINE+3]]*
-// HTML-MYCLASS-LINE: <p>Defined at line [[@LINE+2]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}comments-in-macros.cpp</p>
-// MUSTACHE-MYCLASS-LINE: <p>Defined at line [[@LINE-4]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}comments-in-macros.cpp</p>
+// MD-MYCLASS-LINE: *Defined at {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}comments-in-macros.cpp#[[@LINE-2]]*
+// HTML-MYCLASS-LINE: <p>Defined at line [[@LINE-3]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}comments-in-macros.cpp</p>
     DECLARE_METHODS
 };
 
diff --git a/clang-tools-extra/test/clang-doc/conversion_function.cpp b/clang-tools-extra/test/clang-doc/conversion_function.cpp
index 7b1039e9857e8..63df5d6f50d39 100644
--- a/clang-tools-extra/test/clang-doc/conversion_function.cpp
+++ b/clang-tools-extra/test/clang-doc/conversion_function.cpp
@@ -4,10 +4,7 @@
 // RUN: find %t/ -regex ".*/[0-9A-F]*.yaml" -exec cat {} ";" | FileCheck %s --check-prefix=CHECK-YAML
 
 // RUN: clang-doc --format=html --output=%t --executor=standalone %s 
-// RUN: FileCheck %s < %t/GlobalNamespace/MyStruct.html --check-prefix=CHECK-HTML
-
-// RUN: clang-doc --format=mustache --output=%t --executor=standalone %s 
-// RUN: FileCheck %s < %t/html/GlobalNamespace/_ZTV8MyStruct.html --check-prefix=CHECK-MUSTACHE
+// RUN: FileCheck %s < %t/html/GlobalNamespace/_ZTV8MyStruct.html --check-prefix=CHECK-HTML
 
 template <typename T>
 struct MyStruct {
@@ -17,9 +14,6 @@ struct MyStruct {
 // Output correct conversion names.
 // CHECK-YAML:         Name:            'operator T'
 
-// CHECK-HTML: <h3 id="{{[0-9A-F]*}}">operator T</h3>
-// CHECK-HTML: <p>public T operator T()</p>
-
-// CHECK-MUSTACHE: <div id="{{([0-9A-F]{40})}}">
-// CHECK-MUSTACHE:     <pre><code class="language-cpp code-clang-doc">T operator T ()</code></pre>
-// CHECK-MUSTACHE: </div>
+// CHECK-HTML: <div id="{{([0-9A-F]{40})}}">
+// CHECK-HTML:     <pre><code class="language-cpp code-clang-doc">T operator T ()</code></pre>
+// CHECK-HTML: </div>
diff --git a/clang-tools-extra/test/clang-doc/enum.cpp b/clang-tools-extra/test/clang-doc/enum.cpp
index 3ba834e0b2e70..bb0d51fc3b36c 100644
--- a/clang-tools-extra/test/clang-doc/enum.cpp
+++ b/clang-tools-extra/test/clang-doc/enum.cpp
@@ -1,19 +1,12 @@
 // RUN: rm -rf %t && mkdir -p %t
 // RUN: clang-doc --format=html --doxygen --output=%t --executor=standalone %s
 // RUN: clang-doc --format=md --doxygen --output=%t --executor=standalone %s
-// RUN: clang-doc --format=mustache --doxygen --output=%t --executor=standalone %s
-// RUN: FileCheck %s < %t/GlobalNamespace/index.html --check-prefix=HTML-INDEX-LINE
-// RUN: FileCheck %s < %t/GlobalNamespace/index.html --check-prefix=HTML-INDEX
-// RUN: FileCheck %s < %t/GlobalNamespace/Animals.html --check-prefix=HTML-ANIMAL-LINE
-// RUN: FileCheck %s < %t/GlobalNamespace/Animals.html --check-prefix=HTML-ANIMAL
-// RUN: FileCheck %s < %t/Vehicles/index.html --check-prefix=HTML-VEHICLES-LINE
-// RUN: FileCheck %s < %t/Vehicles/index.html --check-prefix=HTML-VEHICLES
-// RUN: FileCheck %s < %t/html/GlobalNamespace/index.html --check-prefix=MUSTACHE-INDEX-LINE
-// RUN: FileCheck %s < %t/html/GlobalNamespace/index.html --check-prefix=MUSTACHE-INDEX
-// RUN: FileCheck %s < %t/html/GlobalNamespace/_ZTV7Animals.html --check-prefix=MUSTACHE-ANIMAL-LINE
-// RUN: FileCheck %s < %t/html/GlobalNamespace/_ZTV7Animals.html --check-prefix=MUSTACHE-ANIMAL
-// RUN: FileCheck %s < %t/html/Vehicles/index.html --check-prefix=MUSTACHE-VEHICLES-LINE
-// RUN: FileCheck %s < %t/html/Vehicles/index.html --check-prefix=MUSTACHE-VEHICLES
+// RUN: FileCheck %s < %t/html/GlobalNamespace/index.html --check-prefix=HTML-INDEX-LINE
+// RUN: FileCheck %s < %t/html/GlobalNamespace/index.html --check-prefix=HTML-INDEX
+// RUN: FileCheck %s < %t/html/GlobalNamespace/_ZTV7Animals.html --check-prefix=HTML-ANIMAL-LINE
+// RUN: FileCheck %s < %t/html/GlobalNamespace/_ZTV7Animals.html --check-prefix=HTML-ANIMAL
+// RUN: FileCheck %s < %t/html/Vehicles/index.html --check-prefix=HTML-VEHICLES-LINE
+// RUN: FileCheck %s < %t/html/Vehicles/index.html --check-prefix=HTML-VEHICLES
 // RUN: FileCheck %s < %t/GlobalNamespace/index.md --check-prefix=MD-INDEX-LINE
 // RUN: FileCheck %s < %t/GlobalNamespace/index.md --check-prefix=MD-INDEX
 // RUN: FileCheck %s < %t/GlobalNamespace/Animals.md --check-prefix=MD-ANIMAL-LINE
@@ -28,8 +21,7 @@
  */
 enum Color {
   // MD-INDEX-LINE: *Defined at {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp#[[@LINE-1]]*
-  // HTML-INDEX-LINE: <p>Defined at line [[@LINE-2]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
-  // MUSTACHE-INDEX-LINE-NOT: <p>Defined at line [[@LINE-2]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
+  // HTML-INDEX-LINE-NOT: <p>Defined at line [[@LINE-2]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
   Red,   ///< Comment 1
   Green, ///< Comment 2
   Blue   ///< Comment 3
@@ -43,48 +35,36 @@ enum Color {
 // MD-INDEX: | Blue |
 // MD-INDEX: **brief** For specifying RGB colors
 
-// HTML-INDEX: <th colspan="3">enum Color</th>
-// HTML-INDEX: <td>Red</td>
-// HTML-INDEX: <td>0</td>
-// HTML-INDEX: <p> Comment 1</p>
-// HTML-INDEX: <td>Green</td>
-// HTML-INDEX: <td>1</td>
-// HTML-INDEX: <p> Comment 2</p>
-// HTML-INDEX: <td>Blue</td>
-// HTML-INDEX: <td>2</td>
-// HTML-INDEX: <p> Comment 3</p>
-
-// MUSTACHE-INDEX:     <div>
-// MUSTACHE-INDEX:         <pre><code class="language-cpp code-clang-doc">enum Color</code></pre>
-// MUSTACHE-INDEX:     </div>
-// MUSTACHE-INDEX:     <table class="table-wrapper">
-// MUSTACHE-INDEX:         <tbody>
-// MUSTACHE-INDEX:             <tr>
-// MUSTACHE-INDEX:                 <th>Name</th>
-// MUSTACHE-INDEX:                 <th>Value</th>
-// MUSTACHE-INDEX:             </tr>
-// MUSTACHE-INDEX:             <tr>
-// MUSTACHE-INDEX:                 <td>Red</td>
-// MUSTACHE-INDEX:                 <td>0</td>
-// MUSTACHE-INDEX:             </tr>
-// MUSTACHE-INDEX:             <tr>
-// MUSTACHE-INDEX:                 <td>Green</td>
-// MUSTACHE-INDEX:                 <td>1</td>
-// MUSTACHE-INDEX:             </tr>
-// MUSTACHE-INDEX:             <tr>
-// MUSTACHE-INDEX:                 <td>Blue</td>
-// MUSTACHE-INDEX:                 <td>2</td>
-// MUSTACHE-INDEX:             </tr>
-// MUSTACHE-INDEX:         </tbody>
-// MUSTACHE-INDEX:     </table>
+// HTML-INDEX:     <div>
+// HTML-INDEX:         <pre><code class="language-cpp code-clang-doc">enum Color</code></pre>
+// HTML-INDEX:     </div>
+// HTML-INDEX:     <table class="table-wrapper">
+// HTML-INDEX:         <tbody>
+// HTML-INDEX:             <tr>
+// HTML-INDEX:                 <th>Name</th>
+// HTML-INDEX:                 <th>Value</th>
+// HTML-INDEX:             </tr>
+// HTML-INDEX:             <tr>
+// HTML-INDEX:                 <td>Red</td>
+// HTML-INDEX:                 <td>0</td>
+// HTML-INDEX:             </tr>
+// HTML-INDEX:             <tr>
+// HTML-INDEX:                 <td>Green</td>
+// HTML-INDEX:                 <td>1</td>
+// HTML-INDEX:             </tr>
+// HTML-INDEX:             <tr>
+// HTML-INDEX:                 <td>Blue</td>
+// HTML-INDEX:                 <td>2</td>
+// HTML-INDEX:             </tr>
+// HTML-INDEX:         </tbody>
+// HTML-INDEX:     </table>
 
 /**
  * @brief Shape Types
  */
 enum class Shapes {
   // MD-INDEX-LINE: *Defined at {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp#[[@LINE-1]]*
-  // HTML-INDEX-LINE: <p>Defined at line [[@LINE-2]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
-  // MUSTACHE-INDEX-LINE-NOT: <p>Defined at line [[@LINE-2]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
+  // HTML-INDEX-LINE-NOT: <p>Defined at line [[@LINE-2]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
 
   /// Comment 1
   Circle,
@@ -100,86 +80,60 @@ enum class Shapes {
 // MD-INDEX: | Triangle |
 // MD-INDEX: **brief** Shape Types
 
-// HTML-INDEX: <th colspan="3">enum class Shapes</th>
-// HTML-INDEX: <td>Circle</td>
-// HTML-INDEX: <td>0</td>
-// HTML-INDEX: <p> Comment 1</p>
-// HTML-INDEX: <td>Rectangle</td>
-// HTML-INDEX: <td>1</td>
-// HTML-INDEX: <p> Comment 2</p>
-// HTML-INDEX: <td>Triangle</td>
-// HTML-INDEX: <td>2</td>
-// HTML-INDEX: <p> Comment 3</p>
-
 // COM: FIXME: Serialize "enum class" in template
-// MUSTACHE-INDEX:     <div>
-// MUSTACHE-INDEX:         <pre><code class="language-cpp code-clang-doc">enum Shapes</code></pre>
-// MUSTACHE-INDEX:     </div>
-// MUSTACHE-INDEX:     <table class="table-wrapper">
-// MUSTACHE-INDEX:         <tbody>
-// MUSTACHE-INDEX:             <tr>
-// MUSTACHE-INDEX:                 <th>Name</th>
-// MUSTACHE-INDEX:                 <th>Value</th>
-// MUSTACHE-INDEX:             </tr>
-// MUSTACHE-INDEX:             <tr>
-// MUSTACHE-INDEX:                 <td>Circle</td>
-// MUSTACHE-INDEX:                 <td>0</td>
-// MUSTACHE-INDEX:             </tr>
-// MUSTACHE-INDEX:             <tr>
-// MUSTACHE-INDEX:                 <td>Rectangle</td>
-// MUSTACHE-INDEX:                 <td>1</td>
-// MUSTACHE-INDEX:             </tr>
-// MUSTACHE-INDEX:             <tr>
-// MUSTACHE-INDEX:                 <td>Triangle</td>
-// MUSTACHE-INDEX:                 <td>2</td>
-// MUSTACHE-INDEX:             </tr>
-// MUSTACHE-INDEX:         </tbody>
-// MUSTACHE-INDEX:     </table>
+// HTML-INDEX:     <div>
+// HTML-INDEX:         <pre><code class="language-cpp code-clang-doc">enum Shapes</code></pre>
+// HTML-INDEX:     </div>
+// HTML-INDEX:     <table class="table-wrapper">
+// HTML-INDEX:         <tbody>
+// HTML-INDEX:             <tr>
+// HTML-INDEX:                 <th>Name</th>
+// HTML-INDEX:                 <th>Value</th>
+// HTML-INDEX:             </tr>
+// HTML-INDEX:             <tr>
+// HTML-INDEX:                 <td>Circle</td>
+// HTML-INDEX:                 <td>0</td>
+// HTML-INDEX:             </tr>
+// HTML-INDEX:             <tr>
+// HTML-INDEX:                 <td>Rectangle</td>
+// HTML-INDEX:                 <td>1</td>
+// HTML-INDEX:             </tr>
+// HTML-INDEX:             <tr>
+// HTML-INDEX:                 <td>Triangle</td>
+// HTML-INDEX:                 <td>2</td>
+// HTML-INDEX:             </tr>
+// HTML-INDEX:         </tbody>
+// HTML-INDEX:     </table>
 
 // COM: FIXME: Add enums declared inside of classes to class template
 class Animals {
   // MD-ANIMAL-LINE: *Defined at {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp#[[@LINE-1]]*
   // HTML-ANIMAL-LINE: <p>Defined at line [[@LINE-2]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
-  // MUSTACHE-ANIMAL-LINE: <p>Defined at line [[@LINE-3]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
 public:
   /**
    * @brief specify what animal the class is
    */
   enum AnimalType {
     // MD-ANIMAL-LINE: *Defined at {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp#[[@LINE-1]]*
-    // HTML-ANIMAL-LINE: <p>Defined at line [[@LINE-2]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
-    // MUSTACHE-ANIMAL-LINE-NOT: <p>Defined at line [[@LINE-2]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
+    // HTML-ANIMAL-LINE-NOT: <p>Defined at line [[@LINE-2]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
     Dog,   ///< Man's best friend
     Cat,   ///< Man's other best friend
     Iguana ///< A lizard
   };
 };
 
-// HTML-ANIMAL: <h1>class Animals</h1>
-// HTML-ANIMAL: <h2 id="Enums">Enums</h2>
-// HTML-ANIMAL: <th colspan="3">enum AnimalType</th>
-// HTML-ANIMAL: <td>Dog</td>
-// HTML-ANIMAL: <td>0</td>
-// HTML-ANIMAL: <p> Man's best friend</p>
-// HTML-ANIMAL: <td>Cat</td>
-// HTML-ANIMAL: <td>1</td>
-// HTML-ANIMAL: <p> Man's other best friend</p>
-// HTML-ANIMAL: <td>Iguana</td>
-// HTML-ANIMAL: <td>2</td>
-// HTML-ANIMAL: <p> A lizard</p>
-
-// MUSTACHE-ANIMAL-NOT: <h1>class Animals</h1>
-// MUSTACHE-ANIMAL-NOT: <h2 id="Enums">Enums</h2>
-// MUSTACHE-ANIMAL-NOT: <th colspan="3">enum AnimalType</th>
-// MUSTACHE-ANIMAL-NOT: <td>Dog</td>
-// MUSTACHE-ANIMAL-NOT: <td>0</td>
-// MUSTACHE-ANIMAL-NOT: <p> Man's best friend</p>
-// MUSTACHE-ANIMAL-NOT: <td>Cat</td>
-// MUSTACHE-ANIMAL-NOT: <td>1</td>
-// MUSTACHE-ANIMAL-NOT: <p> Man's other best friend</p>
-// MUSTACHE-ANIMAL-NOT: <td>Iguana</td>
-// MUSTACHE-ANIMAL-NOT: <td>2</td>
-// MUSTACHE-ANIMAL-NOT: <p> A lizard</p>
+// HTML-ANIMAL-NOT: <h1>class Animals</h1>
+// HTML-ANIMAL-NOT: <h2 id="Enums">Enums</h2>
+// HTML-ANIMAL-NOT: <th colspan="3">enum AnimalType</th>
+// HTML-ANIMAL-NOT: <td>Dog</td>
+// HTML-ANIMAL-NOT: <td>0</td>
+// HTML-ANIMAL-NOT: <p> Man's best friend</p>
+// HTML-ANIMAL-NOT: <td>Cat</td>
+// HTML-ANIMAL-NOT: <td>1</td>
+// HTML-ANIMAL-NOT: <p> Man's other best friend</p>
+// HTML-ANIMAL-NOT: <td>Iguana</td>
+// HTML-ANIMAL-NOT: <td>2</td>
+// HTML-ANIMAL-NOT: <p> A lizard</p>
 
 // MD-ANIMAL: # class Animals
 // MD-ANIMAL: ## Enums
@@ -196,8 +150,7 @@ namespace Vehicles {
  */
 enum Car {
   // MD-VEHICLES-LINE: *Defined at {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp#[[@LINE-1]]*
-  // HTML-VEHICLES-LINE: <p>Defined at line [[@LINE-2]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
-  // MUSTACHE-VEHICLES-LINE: Defined at line [[@LINE-3]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp
+  // HTML-VEHICLES-LINE: Defined at line [[@LINE-2]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp
 
   Sedan,    ///< Comment 1
   SUV,      ///< Comment 2
@@ -216,48 +169,33 @@ enum Car {
 // MD-VEHICLES: | Hatchback |
 // MD-VEHICLES: **brief** specify type of car
 
-// HTML-VEHICLES: <h1>namespace Vehicles</h1>
-// HTML-VEHICLES: <th colspan="3">enum Car</th>
-// HTML-VEHICLES: <td>Sedan</td>
-// HTML-VEHICLES: <td>0</td>
-// HTML-VEHICLES: <p> Comment 1</p>
-// HTML-VEHICLES: <td>SUV</td>
-// HTML-VEHICLES: <td>1</td>
-// HTML-VEHICLES: <p> Comment 2</p>
-// HTML-VEHICLES: <td>Pickup</td>
-// HTML-VEHICLES: <td>2</td>
-// HTML-VEHICLES: <p> Comment 3</p>
-// HTML-VEHICLES: <td>Hatchback</td>
-// HTML-VEHICLES: <td>3</td>
-// HTML-VEHICLES: <p> Comment 4</p>
-
-// MUSTACHE-VEHICLES:     <div>
-// MUSTACHE-VEHICLES:         <pre><code class="language-cpp code-clang-doc">enum Car</code></pre>
-// MUSTACHE-VEHICLES:      </div>
-// MUSTACHE-VEHICLES:      <table class="table-wrapper">
-// MUSTACHE-VEHICLES:          <tbody>
-// MUSTACHE-VEHICLES:              <tr>
-// MUSTACHE-VEHICLES:                  <th>Name</th>
-// MUSTACHE-VEHICLES:                  <th>Value</th>
-// MUSTACHE-VEHICLES:              </tr>
-// MUSTACHE-VEHICLES:              <tr>
-// MUSTACHE-VEHICLES:                  <td>Sedan</td>
-// MUSTACHE-VEHICLES:                  <td>0</td>
-// MUSTACHE-VEHICLES:              </tr>
-// MUSTACHE-VEHICLES:              <tr>
-// MUSTACHE-VEHICLES:                  <td>SUV</td>
-// MUSTACHE-VEHICLES:                  <td>1</td>
-// MUSTACHE-VEHICLES:              </tr>
-// MUSTACHE-VEHICLES:              <tr>
-// MUSTACHE-VEHICLES:                  <td>Pickup</td>
-// MUSTACHE-VEHICLES:                  <td>2</td>
-// MUSTACHE-VEHICLES:              </tr>
-// MUSTACHE-VEHICLES:              <tr>
-// MUSTACHE-VEHICLES:                  <td>Hatchback</td>
-// MUSTACHE-VEHICLES:                  <td>3</td>
-// MUSTACHE-VEHICLES:              </tr>
-// MUSTACHE-VEHICLES:          </tbody>
-// MUSTACHE-VEHICLES:      </table>
+// HTML-VEHICLES:     <div>
+// HTML-VEHICLES:         <pre><code class="language-cpp code-clang-doc">enum Car</code></pre>
+// HTML-VEHICLES:      </div>
+// HTML-VEHICLES:      <table class="table-wrapper">
+// HTML-VEHICLES:          <tbody>
+// HTML-VEHICLES:              <tr>
+// HTML-VEHICLES:                  <th>Name</th>
+// HTML-VEHICLES:                  <th>Value</th>
+// HTML-VEHICLES:              </tr>
+// HTML-VEHICLES:              <tr>
+// HTML-VEHICLES:                  <td>Sedan</td>
+// HTML-VEHICLES:                  <td>0</td>
+// HTML-VEHICLES:              </tr>
+// HTML-VEHICLES:              <tr>
+// HTML-VEHICLES:                  <td>SUV</td>
+// HTML-VEHICLES:                  <td>1</td>
+// HTML-VEHICLES:              </tr>
+// HTML-VEHICLES:              <tr>
+// HTML-VEHICLES:                  <td>Pickup</td>
+// HTML-VEHICLES:                  <td>2</td>
+// HTML-VEHICLES:              </tr>
+// HTML-VEHICLES:              <tr>
+// HTML-VEHICLES:                  <td>Hatchback</td>
+// HTML-VEHICLES:                  <td>3</td>
+// HTML-VEHICLES:              </tr>
+// HTML-VEHICLES:          </tbody>
+// HTML-VEHICLES:      </table>
 
 enum ColorUserSpecified {
   RedUserSpecified = 'A',
@@ -271,34 +209,26 @@ enum ColorUserSpecified {
 // MD-INDEX: | GreenUserSpecified |
 // MD-INDEX: | BlueUserSpecified |
 
-// HTML-INDEX: <th colspan="2">enum ColorUserSpecified</th>
-// HTML-INDEX: <td>RedUserSpecified</td>
-// HTML-INDEX: <td>'A'</td>
-// HTML-INDEX: <td>GreenUserSpecified</td>
-// HTML-INDEX: <td>2</td>
-// HTML-INDEX: <td>BlueUserSpecified</td>
-// HTML-INDEX: <td>'C'</td>
-
-// MUSTACHE-INDEX:     <div>
-// MUSTACHE-INDEX:         <pre><code class="language-cpp code-clang-doc">enum ColorUserSpecified</code></pre>
-// MUSTACHE-INDEX:     </div>
-// MUSTACHE-INDEX:     <table class="table-wrapper">
-// MUSTACHE-INDEX:         <tbody>
-// MUSTACHE-INDEX:             <tr>
-// MUSTACHE-INDEX:                 <th>Name</th>
-// MUSTACHE-INDEX:                 <th>Value</th>
-// MUSTACHE-INDEX:             </tr>
-// MUSTACHE-INDEX:             <tr>
-// MUSTACHE-INDEX:                 <td>RedUserSpecified</td>
-// MUSTACHE-INDEX:                 <td>'A'</td>
-// MUSTACHE-INDEX:             </tr>
-// MUSTACHE-INDEX:             <tr>
-// MUSTACHE-INDEX:                 <td>GreenUserSpecified</td>
-// MUSTACHE-INDEX:                 <td>2</td>
-// MUSTACHE-INDEX:             </tr>
-// MUSTACHE-INDEX:             <tr>
-// MUSTACHE-INDEX:                 <td>BlueUserSpecified</td>
-// MUSTACHE-INDEX:                 <td>'C'</td>
-// MUSTACHE-INDEX:             </tr>
-// MUSTACHE-INDEX:         </tbody>
-// MUSTACHE-INDEX:     </table>
+// HTML-INDEX:     <div>
+// HTML-INDEX:         <pre><code class="language-cpp code-clang-doc">enum ColorUserSpecified</code></pre>
+// HTML-INDEX:     </div>
+// HTML-INDEX:     <table class="table-wrapper">
+// HTML-INDEX:         <tbody>
+// HTML-INDEX:             <tr>
+// HTML-INDEX:                 <th>Name</th>
+// HTML-INDEX:                 <th>Value</th>
+// HTML-INDEX:             </tr>
+// HTML-INDEX:             <tr>
+// HTML-INDEX:                 <td>RedUserSpecified</td>
+// HTML-INDEX:                 <td>'A'</td>
+// HTML-INDEX:             </tr>
+// HTML-INDEX:             <tr>
+// HTML-INDEX:                 <td>GreenUserSpecified</td>
+// HTML-INDEX:                 <td>2</td>
+// HTML-INDEX:             </tr>
+// HTML-INDEX:             <tr>
+// HTML-INDEX:                 <td>BlueUserSpecified</td>
+// HTML-INDEX:                 <td>'C'</td>
+// HTML-INDEX:             </tr>
+// HTML-INDEX:         </tbody>
+// HTML-INDEX:     </table>
diff --git a/clang-tools-extra/test/clang-doc/long-name.cpp b/clang-tools-extra/test/clang-doc/long-name.cpp
index 77e50b1553ad5..e4a5e29f973d5 100644
--- a/clang-tools-extra/test/clang-doc/long-name.cpp
+++ b/clang-tools-extra/test/clang-doc/long-name.cpp
@@ -1,7 +1,7 @@
 // FIXME: This test seems to break on windows, so disable it for now.
 // UNSUPPORTED: system-windows
 // RUN: rm -rf %t && mkdir -p %t
-// RUN: clang-doc --output=%t --format=mustache --executor=standalone %s
+// RUN: clang-doc --output=%t --format=html --executor=standalone %s
 // RUN: ls %t/json/GlobalNamespace | FileCheck %s -check-prefix=CHECK-JSON
 // RUN: ls %t/html/GlobalNamespace | FileCheck %s -check-prefix=CHECK-HTML
 
diff --git a/clang-tools-extra/test/clang-doc/mustache-index.cpp b/clang-tools-extra/test/clang-doc/mustache-index.cpp
index 709cc82bf85bb..0aa6e21c37cac 100644
--- a/clang-tools-extra/test/clang-doc/mustache-index.cpp
+++ b/clang-tools-extra/test/clang-doc/mustache-index.cpp
@@ -1,5 +1,5 @@
 // RUN: rm -rf %t && mkdir -p %t
-// RUN: clang-doc --format=mustache --output=%t --executor=standalone %s 
+// RUN: clang-doc --format=html --output=%t --executor=standalone %s 
 // RUN: FileCheck %s < %t/html/GlobalNamespace/index.html
 
 enum Color {
diff --git a/clang-tools-extra/test/clang-doc/mustache-separate-namespace.cpp b/clang-tools-extra/test/clang-doc/mustache-separate-namespace.cpp
index dfc81df134596..add8a221feb40 100644
--- a/clang-tools-extra/test/clang-doc/mustache-separate-namespace.cpp
+++ b/clang-tools-extra/test/clang-doc/mustache-separate-namespace.cpp
@@ -1,5 +1,5 @@
 // RUN: rm -rf %t && mkdir -p %t
-// RUN: clang-doc --format=mustache --output=%t --executor=standalone %s 
+// RUN: clang-doc --format=html --output=%t --executor=standalone %s 
 // RUN: FileCheck %s < %t/html/MyNamespace/index.html
 // RUN: FileCheck %s < %t/html/GlobalNamespace/index.html --check-prefix=CHECK-GLOBAL
 
diff --git a/clang-tools-extra/test/clang-doc/namespace.cpp b/clang-tools-extra/test/clang-doc/namespace.cpp
index adf7ab7d946ab..029f9974e775e 100644
--- a/clang-tools-extra/test/clang-doc/namespace.cpp
+++ b/clang-tools-extra/test/clang-doc/namespace.cpp
@@ -1,24 +1,6 @@
 // RUN: rm -rf %t && mkdir -p %t
 // RUN: clang-doc --format=html --output=%t --executor=standalone %s
 // RUN: clang-doc --format=md --output=%t --executor=standalone %s
-// RUN: clang-doc --format=mustache --output=%t --executor=standalone %s
-// RUN: FileCheck %s < %t/index_json.js -check-prefix=JSON-INDEX
-// RUN: FileCheck %s < %t/@nonymous_namespace/AnonClass.html -check-prefix=HTML-ANON-CLASS-LINE
-// RUN: FileCheck %s < %t/@nonymous_namespace/AnonClass.html -check-prefix=HTML-ANON-CLASS
-// RUN: FileCheck %s < %t/@nonymous_namespace/index.html -check-prefix=HTML-ANON-INDEX-LINE
-// RUN: FileCheck %s < %t/@nonymous_namespace/index.html -check-prefix=HTML-ANON-INDEX
-// RUN: FileCheck %s < %t/AnotherNamespace/ClassInAnotherNamespace.html -check-prefix=HTML-ANOTHER-CLASS-LINE
-// RUN: FileCheck %s < %t/AnotherNamespace/ClassInAnotherNamespace.html -check-prefix=HTML-ANOTHER-CLASS
-// RUN: FileCheck %s < %t/AnotherNamespace/index.html -check-prefix=HTML-ANOTHER-INDEX-LINE
-// RUN: FileCheck %s < %t/AnotherNamespace/index.html -check-prefix=HTML-ANOTHER-INDEX
-// RUN: FileCheck %s < %t/PrimaryNamespace/NestedNamespace/ClassInNestedNamespace.html -check-prefix=HTML-NESTED-CLASS-LINE
-// RUN: FileCheck %s < %t/PrimaryNamespace/NestedNamespace/ClassInNestedNamespace.html -check-prefix=HTML-NESTED-CLASS
-// RUN: FileCheck %s < %t/PrimaryNamespace/NestedNamespace/index.html -check-prefix=HTML-NESTED-INDEX-LINE
-// RUN: FileCheck %s < %t/PrimaryNamespace/NestedNamespace/index.html -check-prefix=HTML-NESTED-INDEX
-// RUN: FileCheck %s < %t/PrimaryNamespace/index.html -check-prefix=HTML-PRIMARY-INDEX-LINE
-// RUN: FileCheck %s < %t/PrimaryNamespace/index.html -check-prefix=HTML-PRIMARY-INDEX
-// RUN: FileCheck %s < %t/PrimaryNamespace/ClassInPrimaryNamespace.html -check-prefix=HTML-PRIMARY-CLASS-LINE
-// RUN: FileCheck %s < %t/PrimaryNamespace/ClassInPrimaryNamespace.html -check-prefix=HTML-PRIMARY-CLASS
 // RUN: FileCheck %s < %t/@nonymous_namespace/AnonClass.md -check-prefix=MD-ANON-CLASS-LINE
 // RUN: FileCheck %s < %t/@nonymous_namespace/AnonClass.md -check-prefix=MD-ANON-CLASS
 // RUN: FileCheck %s < %t/@nonymous_namespace/index.md -check-prefix=MD-ANON-INDEX-LINE
@@ -35,26 +17,26 @@
 // RUN: FileCheck %s < %t/PrimaryNamespace/index.md -check-prefix=MD-PRIMARY-INDEX
 // RUN: FileCheck %s < %t/PrimaryNamespace/ClassInPrimaryNamespace.md -check-prefix=MD-PRIMARY-CLASS-LINE
 // RUN: FileCheck %s < %t/PrimaryNamespace/ClassInPrimaryNamespace.md -check-prefix=MD-PRIMARY-CLASS
-// RUN: FileCheck %s < %t/GlobalNamespace/index.html -check-prefix=HTML-GLOBAL-INDEX
+// RUN: FileCheck %s < %t/html/GlobalNamespace/index.html -check-prefix=HTML-GLOBAL-INDEX
 // RUN: FileCheck %s < %t/GlobalNamespace/index.md -check-prefix=MD-GLOBAL-INDEX
 // RUN: FileCheck %s < %t/all_files.md -check-prefix=MD-ALL-FILES
 // RUN: FileCheck %s < %t/index.md -check-prefix=MD-INDEX
-// RUN: FileCheck %s < %t/html/@nonymous_namespace/_ZTVN12_GLOBAL__N_19AnonClassE.html -check-prefix=MUSTACHE-ANON-CLASS-LINE
-// RUN: FileCheck %s < %t/html/@nonymous_namespace/_ZTVN12_GLOBAL__N_19AnonClassE.html -check-prefix=MUSTACHE-ANON-CLASS
-// RUN: FileCheck %s < %t/html/@nonymous_namespace/index.html -check-prefix=MUSTACHE-ANON-INDEX-LINE
-// RUN: FileCheck %s < %t/html/@nonymous_namespace/index.html -check-prefix=MUSTACHE-ANON-INDEX
-// RUN: FileCheck %s < %t/html/AnotherNamespace/_ZTVN16AnotherNamespace23ClassInAnotherNamespaceE.html -check-prefix=MUSTACHE-ANOTHER-CLASS-LINE
-// RUN: FileCheck %s < %t/html/AnotherNamespace/_ZTVN16AnotherNamespace23ClassInAnotherNamespaceE.html -check-prefix=MUSTACHE-ANOTHER-CLASS
-// RUN: FileCheck %s < %t/html/AnotherNamespace/index.html -check-prefix=MUSTACHE-ANOTHER-INDEX-LINE
-// RUN: FileCheck %s < %t/html/AnotherNamespace/index.html -check-prefix=MUSTACHE-ANOTHER-INDEX
-// RUN: FileCheck %s < %t/html/PrimaryNamespace/NestedNamespace/_ZTVN16PrimaryNamespace15NestedNamespace22ClassInNestedNamespaceE.html -check-prefix=MUSTACHE-NESTED-CLASS-LINE
-// RUN: FileCheck %s < %t/html/PrimaryNamespace/NestedNamespace/_ZTVN16PrimaryNamespace15NestedNamespace22ClassInNestedNamespaceE.html -check-prefix=MUSTACHE-NESTED-CLASS
-// RUN: FileCheck %s < %t/html/PrimaryNamespace/NestedNamespace/index.html -check-prefix=MUSTACHE-NESTED-INDEX-LINE
-// RUN: FileCheck %s < %t/html/PrimaryNamespace/NestedNamespace/index.html -check-prefix=MUSTACHE-NESTED-INDEX
-// RUN: FileCheck %s < %t/html/PrimaryNamespace/index.html -check-prefix=MUSTACHE-PRIMARY-INDEX-LINE
-// RUN: FileCheck %s < %t/html/PrimaryNamespace/index.html -check-prefix=MUSTACHE-PRIMARY-INDEX
-// RUN: FileCheck %s < %t/html/PrimaryNamespace/_ZTVN16PrimaryNamespace23ClassInPrimaryNamespaceE.html -check-prefix=MUSTACHE-PRIMARY-CLASS-LINE
-// RUN: FileCheck %s < %t/html/PrimaryNamespace/_ZTVN16PrimaryNamespace23ClassInPrimaryNamespaceE.html -check-prefix=MUSTACHE-PRIMARY-CLASS
+// RUN: FileCheck %s < %t/html/@nonymous_namespace/_ZTVN12_GLOBAL__N_19AnonClassE.html -check-prefix=HTML-ANON-CLASS-LINE
+// RUN: FileCheck %s < %t/html/@nonymous_namespace/_ZTVN12_GLOBAL__N_19AnonClassE.html -check-prefix=HTML-ANON-CLASS
+// RUN: FileCheck %s < %t/html/@nonymous_namespace/index.html -check-prefix=HTML-ANON-INDEX-LINE
+// RUN: FileCheck %s < %t/html/@nonymous_namespace/index.html -check-prefix=HTML-ANON-INDEX
+// RUN: FileCheck %s < %t/html/AnotherNamespace/_ZTVN16AnotherNamespace23ClassInAnotherNamespaceE.html -check-prefix=HTML-ANOTHER-CLASS-LINE
+// RUN: FileCheck %s < %t/html/AnotherNamespace/_ZTVN16AnotherNamespace23ClassInAnotherNamespaceE.html -check-prefix=HTML-ANOTHER-CLASS
+// RUN: FileCheck %s < %t/html/AnotherNamespace/index.html -check-prefix=HTML-ANOTHER-INDEX-LINE
+// RUN: FileCheck %s < %t/html/AnotherNamespace/index.html -check-prefix=HTML-ANOTHER-INDEX
+// RUN: FileCheck %s < %t/html/PrimaryNamespace/NestedNamespace/_ZTVN16PrimaryNamespace15NestedNamespace22ClassInNestedNamespaceE.html -check-prefix=HTML-NESTED-CLASS-LINE
+// RUN: FileCheck %s < %t/html/PrimaryNamespace/NestedNamespace/_ZTVN16PrimaryNamespace15NestedNamespace22ClassInNestedNamespaceE.html -check-prefix=HTML-NESTED-CLASS
+// RUN: FileCheck %s < %t/html/PrimaryNamespace/NestedNamespace/index.html -check-prefix=HTML-NESTED-INDEX-LINE
+// RUN: FileCheck %s < %t/html/PrimaryNamespace/NestedNamespace/index.html -check-prefix=HTML-NESTED-INDEX
+// RUN: FileCheck %s < %t/html/PrimaryNamespace/index.html -check-prefix=HTML-PRIMARY-INDEX-LINE
+// RUN: FileCheck %s < %t/html/PrimaryNamespace/index.html -check-prefix=HTML-PRIMARY-INDEX
+// RUN: FileCheck %s < %t/html/PrimaryNamespace/_ZTVN16PrimaryNamespace23ClassInPrimaryNamespaceE.html -check-prefix=HTML-PRIMARY-CLASS-LINE
+// RUN: FileCheck %s < %t/html/PrimaryNamespace/_ZTVN16PrimaryNamespace23ClassInPrimaryNamespaceE.html -check-prefix=HTML-PRIMARY-CLASS
 
 // COM: FIXME: Add global functions to the namespace template
 // COM: FIXME: Add namespaces to the namespace template
@@ -63,17 +45,14 @@
 namespace {
 void anonFunction() {}
 // MD-ANON-INDEX-LINE: *Defined at {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}namespace.cpp#[[@LINE-1]]*
-// HTML-ANON-INDEX-LINE: <p>Defined at line [[@LINE-2]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}namespace.cpp</p>
-// MUSTACHE-ANON-INDEX-LINE-NOT: <p>Defined at line [[@LINE-2]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}namespace.cpp</p>
+// HTML-ANON-INDEX-LINE-NOT: <p>Defined at line [[@LINE-2]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}namespace.cpp</p>
 
 class AnonClass {};
 // MD-ANON-CLASS-LINE: *Defined at {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}namespace.cpp#[[@LINE-1]]*
 // HTML-ANON-CLASS-LINE: <p>Defined at line [[@LINE-2]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}namespace.cpp</p>
-// MUSTACHE-ANON-CLASS-LINE: <p>Defined at line [[@LINE-3]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}namespace.cpp</p>
 
 // MD-ANON-CLASS: # class AnonClass
-// HTML-ANON-CLASS: <h1>class AnonClass</h1>
-// MUSTACHE-ANON-CLASS: <h1 class="hero__title-large">class AnonClass</h1>
+// HTML-ANON-CLASS: <h1 class="hero__title-large">class AnonClass</h1>
 } // namespace
 
 // MD-ANON-INDEX: # namespace @nonymous_namespace
@@ -84,69 +63,51 @@ class AnonClass {};
 // MD-ANON-INDEX: ### anonFunction
 // MD-ANON-INDEX: *void anonFunction()*
 
-// HTML-ANON-INDEX: <h1>namespace @nonymous_namespace</h1>
-// HTML-ANON-INDEX: <p> Anonymous Namespace</p>
-// HTML-ANON-INDEX: <h2 id="Records">Records</h2>
-// HTML-ANON-INDEX: <a href="AnonClass.html">AnonClass</a>
-// HTML-ANON-INDEX: <h2 id="Functions">Functions</h2>
-// HTML-ANON-INDEX: <h3 id="{{([0-9A-F]{40})}}">anonFunction</h3>
-// HTML-ANON-INDEX: <p>void anonFunction()</p>
-
-// MUSTACHE-ANON-INDEX: <h2> @nonymous_namespace</h2>
-// MUSTACHE-ANON-INDEX:     <h2>Inner Classes</h2>
-// MUSTACHE-ANON-INDEX:         <ul class="class-container">
-// MUSTACHE-ANON-INDEX:             <li id="{{([0-9A-F]{40})}}" style="max-height: 40px;">
-// MUSTACHE-ANON-INDEX:                 <a href="_ZTVN12_GLOBAL__N_19AnonClassE.html">
-// MUSTACHE-ANON-INDEX:                     <pre><code class="language-cpp code-clang-doc">class AnonClass</code></pre>
-// MUSTACHE-ANON-INDEX:                 </a>
-// MUSTACHE-ANON-INDEX:             </li>
-// MUSTACHE-ANON-INDEX-NOT: <h2 id="Functions">Functions</h2>
-// MUSTACHE-ANON-INDEX-NOT: <h3 id="{{([0-9A-F]{40})}}">anonFunction</h3>
-// MUSTACHE-ANON-INDEX-NOT: <p>void anonFunction()</p>
+// HTML-ANON-INDEX: <h2> @nonymous_namespace</h2>
+// HTML-ANON-INDEX:     <h2>Inner Classes</h2>
+// HTML-ANON-INDEX:         <ul class="class-container">
+// HTML-ANON-INDEX:             <li id="{{([0-9A-F]{40})}}" style="max-height: 40px;">
+// HTML-ANON-INDEX:                 <a href="_ZTVN12_GLOBAL__N_19AnonClassE.html">
+// HTML-ANON-INDEX:                     <pre><code class="language-cpp code-clang-doc">class AnonClass</code></pre>
+// HTML-ANON-INDEX:                 </a>
+// HTML-ANON-INDEX:             </li>
+// HTML-ANON-INDEX-NOT: <h2 id="Functions">Functions</h2>
+// HTML-ANON-INDEX-NOT: <h3 id="{{([0-9A-F]{40})}}">anonFunction</h3>
+// HTML-ANON-INDEX-NOT: <p>void anonFunction()</p>
 
 // Primary Namespace
 namespace PrimaryNamespace {
 // Function in PrimaryNamespace
 void functionInPrimaryNamespace() {}
 // MD-PRIMARY-INDEX-LINE: *Defined at {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}namespace.cpp#[[@LINE-1]]*
-// HTML-PRIMARY-INDEX-LINE: <p>Defined at line [[@LINE-2]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}namespace.cpp</p>
-// MUSTACHE-PRIMARY-INDEX-LINE-NOT: <p>Defined at line [[@LINE-3]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}namespace.cpp</p>
+// HTML-PRIMARY-INDEX-LINE-NOT: <p>Defined at line [[@LINE-2]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}namespace.cpp</p>
 
 // Class in PrimaryNamespace
 class ClassInPrimaryNamespace {};
 // MD-PRIMARY-CLASS-LINE: *Defined at {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}namespace.cpp#[[@LINE-1]]*
 // HTML-PRIMARY-CLASS-LINE: <p>Defined at line [[@LINE-2]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}namespace.cpp</p>
-// MUSTACHE-PRIMARY-CLASS-LINE: <p>Defined at line [[@LINE-3]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}namespace.cpp</p>
 
 // MD-PRIMARY-CLASS: # class ClassInPrimaryNamespace
 // MD-PRIMARY-CLASS: Class in PrimaryNamespace
 
-// HTML-PRIMARY-CLASS: <h1>class ClassInPrimaryNamespace</h1>
-// HTML-PRIMARY-CLASS: <p> Class in PrimaryNamespace</p>
-
-// MUSTACHE-PRIMARY-CLASS: <h1 class="hero__title-large">class ClassInPrimaryNamespace</h1>
+// HTML-PRIMARY-CLASS: <h1 class="hero__title-large">class ClassInPrimaryNamespace</h1>
 
 // Nested namespace
 namespace NestedNamespace {
 // Function in NestedNamespace
 void functionInNestedNamespace() {}
 // MD-NESTED-INDEX-LINE: *Defined at {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}namespace.cpp#[[@LINE-1]]*
-// HTML-NESTED-INDEX-LINE: <p>Defined at line [[@LINE-2]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}namespace.cpp</p>
-// MUSTACHE-NESTED-INDEX-LINE-NOT: <p>Defined at line [[@LINE-3]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}namespace.cpp</p>
+// HTML-NESTED-INDEX-LINE-NOT: <p>Defined at line [[@LINE-2]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}namespace.cpp</p>
 
 // Class in NestedNamespace
 class ClassInNestedNamespace {};
 // MD-NESTED-CLASS-LINE: *Defined at {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}namespace.cpp#[[@LINE-1]]*
 // HTML-NESTED-CLASS-LINE: <p>Defined at line [[@LINE-2]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}namespace.cpp</p>
-// MUSTACHE-NESTED-CLASS-LINE: <p>Defined at line [[@LINE-3]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}namespace.cpp</p>
 
 // MD-NESTED-CLASS: # class ClassInNestedNamespace
 // MD-NESTED-CLASS: Class in NestedNamespace
 
-// HTML-NESTED-CLASS: <h1>class ClassInNestedNamespace</h1>
-// HTML-NESTED-CLASS: <p> Class in NestedNamespace</p>
-
-// MUSTACHE-NESTED-CLASS: <h1 class="hero__title-large">class ClassInNestedNamespace</h1>
+// HTML-NESTED-CLASS: <h1 class="hero__title-large">class ClassInNestedNamespace</h1>
 } // namespace NestedNamespace
 
 // MD-NESTED-INDEX: # namespace NestedNamespace
@@ -158,28 +119,19 @@ class ClassInNestedNamespace {};
 // MD-NESTED-INDEX: *void functionInNestedNamespace()*
 // MD-NESTED-INDEX: Function in NestedNamespace
 
-// HTML-NESTED-INDEX: <h1>namespace NestedNamespace</h1>
-// HTML-NESTED-INDEX: <p> Nested namespace</p>
-// HTML-NESTED-INDEX: <h2 id="Records">Records</h2>
-// HTML-NESTED-INDEX: <a href="ClassInNestedNamespace.html">ClassInNestedNamespace</a>
-// HTML-NESTED-INDEX: <h2 id="Functions">Functions</h2>
-// HTML-NESTED-INDEX: <h3 id="{{([0-9A-F]{40})}}">functionInNestedNamespace</h3>
-// HTML-NESTED-INDEX: <p>void functionInNestedNamespace()</p>
-// HTML-NESTED-INDEX: <p> Function in NestedNamespace</p>
-
-// MUSTACHE-NESTED-INDEX: <h2> NestedNamespace</h2>
-// MUSTACHE-NESTED-INDEX:     <h2>Inner Classes</h2>
-// MUSTACHE-NESTED-INDEX:     <ul class="class-container">
-// MUSTACHE-NESTED-INDEX:         <li id="{{([0-9A-F]{40})}}" style="max-height: 40px;">
-// MUSTACHE-NESTED-INDEX:             <a href="_ZTVN16PrimaryNamespace15NestedNamespace22ClassInNestedNamespaceE.html">
-// MUSTACHE-NESTED-INDEX:                 <pre><code class="language-cpp code-clang-doc">class ClassInNestedNamespace</code></pre>
-// MUSTACHE-NESTED-INDEX:             </a>
-// MUSTACHE-NESTED-INDEX:         </li>
-// MUSTACHE-NESTED-INDEX:     </ul>
-// MUSTACHE-NESTED-INDEX-NOT: <h2 id="Functions">Functions</h2>
-// MUSTACHE-NESTED-INDEX-NOT: <h3 id="{{([0-9A-F]{40})}}">functionInNestedNamespace</h3>
-// MUSTACHE-NESTED-INDEX-NOT: <p>void functionInNestedNamespace()</p>
-// MUSTACHE-NESTED-INDEX-NOT: <p> Function in NestedNamespace</p>
+// HTML-NESTED-INDEX: <h2> NestedNamespace</h2>
+// HTML-NESTED-INDEX:     <h2>Inner Classes</h2>
+// HTML-NESTED-INDEX:     <ul class="class-container">
+// HTML-NESTED-INDEX:         <li id="{{([0-9A-F]{40})}}" style="max-height: 40px;">
+// HTML-NESTED-INDEX:             <a href="_ZTVN16PrimaryNamespace15NestedNamespace22ClassInNestedNamespaceE.html">
+// HTML-NESTED-INDEX:                 <pre><code class="language-cpp code-clang-doc">class ClassInNestedNamespace</code></pre>
+// HTML-NESTED-INDEX:             </a>
+// HTML-NESTED-INDEX:         </li>
+// HTML-NESTED-INDEX:     </ul>
+// HTML-NESTED-INDEX-NOT: <h2 id="Functions">Functions</h2>
+// HTML-NESTED-INDEX-NOT: <h3 id="{{([0-9A-F]{40})}}">functionInNestedNamespace</h3>
+// HTML-NESTED-INDEX-NOT: <p>void functionInNestedNamespace()</p>
+// HTML-NESTED-INDEX-NOT: <p> Function in NestedNamespace</p>
 } // namespace PrimaryNamespace
 
 // MD-PRIMARY-INDEX: # namespace PrimaryNamespace
@@ -193,54 +145,38 @@ class ClassInNestedNamespace {};
 // MD-PRIMARY-INDEX: *void functionInPrimaryNamespace()*
 // MD-PRIMARY-INDEX:  Function in PrimaryNamespace
 
-// HTML-PRIMARY-INDEX: <h1>namespace PrimaryNamespace</h1>
-// HTML-PRIMARY-INDEX: <p> Primary Namespace</p>
-// HTML-PRIMARY-INDEX: <h2 id="Namespaces">Namespaces</h2>
-// HTML-PRIMARY-INDEX: <a href="NestedNamespace{{[\/]}}index.html">NestedNamespace</a>
-// HTML-PRIMARY-INDEX: <h2 id="Records">Records</h2>
-// HTML-PRIMARY-INDEX: <a href="ClassInPrimaryNamespace.html">ClassInPrimaryNamespace</a>
-// HTML-PRIMARY-INDEX: <h2 id="Functions">Functions</h2>
-// HTML-PRIMARY-INDEX: <h3 id="{{([0-9A-F]{40})}}">functionInPrimaryNamespace</h3>
-// HTML-PRIMARY-INDEX: <p>void functionInPrimaryNamespace()</p>
-// HTML-PRIMARY-INDEX: <p> Function in PrimaryNamespace</p>
-
-// MUSTACHE-PRIMARY-INDEX: <h2> PrimaryNamespace</h2>
-// MUSTACHE-PRIMARY-INDEX-NOT: <h2 id="Namespaces">Namespaces</h2>
-// MUSTACHE-PRIMARY-INDEX-NOT: <a href="NestedNamespace{{[\/]}}index.html">NestedNamespace</a>
-// MUSTACHE-PRIMARY-INDEX      <h2>Inner Classes</h2>
-// MUSTACHE-PRIMARY-INDEX          <ul class="class-container">
-// MUSTACHE-PRIMARY-INDEX              <li id="{{([0-9A-F]{40})}}" style="max-height: 40px;">
-// MUSTACHE-PRIMARY-INDEX                  <a href="_ZTVN16PrimaryNamespace23ClassInPrimaryNamespaceE.html">
-// MUSTACHE-PRIMARY-INDEX                      <pre><code class="language-cpp code-clang-doc">class ClassInPrimaryNamespace</code></pre>
-// MUSTACHE-PRIMARY-INDEX                  </a>
-// MUSTACHE-PRIMARY-INDEX              </li>
-// MUSTACHE-PRIMARY-INDEX          </ul>
-// MUSTACHE-PRIMARY-INDEX-NOT: <h2 id="Functions">Functions</h2>
-// MUSTACHE-PRIMARY-INDEX-NOT: <h3 id="{{([0-9A-F]{40})}}">functionInPrimaryNamespace</h3>
-// MUSTACHE-PRIMARY-INDEX-NOT: <p>void functionInPrimaryNamespace()</p>
-// MUSTACHE-PRIMARY-INDEX-NOT: <p> Function in PrimaryNamespace</p>
+// HTML-PRIMARY-INDEX: <h2> PrimaryNamespace</h2>
+// HTML-PRIMARY-INDEX-NOT: <h2 id="Namespaces">Namespaces</h2>
+// HTML-PRIMARY-INDEX-NOT: <a href="NestedNamespace{{[\/]}}index.html">NestedNamespace</a>
+// HTML-PRIMARY-INDEX      <h2>Inner Classes</h2>
+// HTML-PRIMARY-INDEX          <ul class="class-container">
+// HTML-PRIMARY-INDEX              <li id="{{([0-9A-F]{40})}}" style="max-height: 40px;">
+// HTML-PRIMARY-INDEX                  <a href="_ZTVN16PrimaryNamespace23ClassInPrimaryNamespaceE.html">
+// HTML-PRIMARY-INDEX                      <pre><code class="language-cpp code-clang-doc">class ClassInPrimaryNamespace</code></pre>
+// HTML-PRIMARY-INDEX                  </a>
+// HTML-PRIMARY-INDEX              </li>
+// HTML-PRIMARY-INDEX          </ul>
+// HTML-PRIMARY-INDEX-NOT: <h2 id="Functions">Functions</h2>
+// HTML-PRIMARY-INDEX-NOT: <h3 id="{{([0-9A-F]{40})}}">functionInPrimaryNamespace</h3>
+// HTML-PRIMARY-INDEX-NOT: <p>void functionInPrimaryNamespace()</p>
+// HTML-PRIMARY-INDEX-NOT: <p> Function in PrimaryNamespace</p>
 
 // AnotherNamespace
 namespace AnotherNamespace {
 // Function in AnotherNamespace
 void functionInAnotherNamespace() {}
 // MD-ANOTHER-INDEX-LINE: *Defined at {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}namespace.cpp#[[@LINE-1]]*
-// HTML-ANOTHER-INDEX-LINE: <p>Defined at line [[@LINE-2]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}namespace.cpp</p>
-// MUSTACHE-ANOTHER-INDEX-LINE-NOT: <p>Defined at line [[@LINE-2]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}namespace.cpp</p>
+// HTML-ANOTHER-INDEX-LINE-NOT: <p>Defined at line [[@LINE-2]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}namespace.cpp</p>
 
 // Class in AnotherNamespace
 class ClassInAnotherNamespace {};
 // MD-ANOTHER-CLASS-LINE: *Defined at {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}namespace.cpp#[[@LINE-1]]*
 // HTML-ANOTHER-CLASS-LINE: <p>Defined at line [[@LINE-2]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}namespace.cpp</p>
-// MUSTACHE-ANOTHER-CLASS-LINE: <p>Defined at line [[@LINE-3]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}namespace.cpp</p>
 
 // MD-ANOTHER-CLASS: # class ClassInAnotherNamespace
 // MD-ANOTHER-CLASS:  Class in AnotherNamespace
 
-// HTML-ANOTHER-CLASS: <h1>class ClassInAnotherNamespace</h1>
-// HTML-ANOTHER-CLASS: <p> Class in AnotherNamespace</p>
-
-// MUSTACHE-ANOTHER-CLASS: <h1 class="hero__title-large">class ClassInAnotherNamespace</h1>
+// HTML-ANOTHER-CLASS: <h1 class="hero__title-large">class ClassInAnotherNamespace</h1>
 
 } // namespace AnotherNamespace
 
@@ -253,120 +189,27 @@ class ClassInAnotherNamespace {};
 // MD-ANOTHER-INDEX: *void functionInAnotherNamespace()*
 // MD-ANOTHER-INDEX: Function in AnotherNamespace
 
-// HTML-ANOTHER-INDEX: <h1>namespace AnotherNamespace</h1>
-// HTML-ANOTHER-INDEX: <p> AnotherNamespace</p>
-// HTML-ANOTHER-INDEX: <h2 id="Records">Records</h2>
-// HTML-ANOTHER-INDEX: <a href="ClassInAnotherNamespace.html">ClassInAnotherNamespace</a>
-// HTML-ANOTHER-INDEX: <h2 id="Functions">Functions</h2>
-// HTML-ANOTHER-INDEX: <h3 id="{{([0-9A-F]{40})}}">functionInAnotherNamespace</h3>
-// HTML-ANOTHER-INDEX: <p>void functionInAnotherNamespace()</p>
-// HTML-ANOTHER-INDEX: <p> Function in AnotherNamespace</p>
-
-// MUSTACHE-ANOTHER-INDEX: <h2> AnotherNamespace</h2>
-// MUSTACHE-ANOTHER-INDEX:     <h2>Inner Classes</h2>
-// MUSTACHE-ANOTHER-INDEX:     <ul class="class-container">
-// MUSTACHE-ANOTHER-INDEX:         <li id="{{([0-9A-F]{40})}}" style="max-height: 40px;">
-// MUSTACHE-ANOTHER-INDEX:             <a href="_ZTVN16AnotherNamespace23ClassInAnotherNamespaceE.html">
-// MUSTACHE-ANOTHER-INDEX:                 <pre><code class="language-cpp code-clang-doc">class ClassInAnotherNamespace</code></pre>
-// MUSTACHE-ANOTHER-INDEX:             </a>
-// MUSTACHE-ANOTHER-INDEX:         </li>
-// MUSTACHE-ANOTHER-INDEX:     </ul>
-// MUSTACHE-ANOTHER-INDEX-NOT: <h2 id="Functions">Functions</h2>
-// MUSTACHE-ANOTHER-INDEX-NOT: <h3 id="{{([0-9A-F]{40})}}">functionInAnotherNamespace</h3>
-// MUSTACHE-ANOTHER-INDEX-NOT: <p>void functionInAnotherNamespace()</p>
-// MUSTACHE-ANOTHER-INDEX-NOT: <p> Function in AnotherNamespace</p>
-
-// JSON-INDEX: async function LoadIndex() {
-// JSON-INDEX-NEXT: return{
-// JSON-INDEX-NEXT:   "USR": "{{([0-9A-F]{40})}}",
-// JSON-INDEX-NEXT:   "Name": "",
-// JSON-INDEX-NEXT:   "RefType": "default",
-// JSON-INDEX-NEXT:   "Path": "",
-// JSON-INDEX-NEXT:   "Children": [
-// JSON-INDEX-NEXT:     {
-// JSON-INDEX-NEXT:       "USR": "{{([0-9A-F]{40})}}",
-// JSON-INDEX-NEXT:       "Name": "@nonymous_namespace",
-// JSON-INDEX-NEXT:       "RefType": "namespace",
-// JSON-INDEX-NEXT:       "Path": "@nonymous_namespace",
-// JSON-INDEX-NEXT:       "Children": [
-// JSON-INDEX-NEXT:         {
-// JSON-INDEX-NEXT:           "USR": "{{([0-9A-F]{40})}}",
-// JSON-INDEX-NEXT:           "Name": "AnonClass",
-// JSON-INDEX-NEXT:           "RefType": "record",
-// JSON-INDEX-NEXT:           "Path": "@nonymous_namespace",
-// JSON-INDEX-NEXT:           "Children": []
-// JSON-INDEX-NEXT:         }
-// JSON-INDEX-NEXT:       ]
-// JSON-INDEX-NEXT:     },
-// JSON-INDEX-NEXT:     {
-// JSON-INDEX-NEXT:       "USR": "{{([0-9A-F]{40})}}",
-// JSON-INDEX-NEXT:       "Name": "AnotherNamespace",
-// JSON-INDEX-NEXT:       "RefType": "namespace",
-// JSON-INDEX-NEXT:       "Path": "AnotherNamespace",
-// JSON-INDEX-NEXT:       "Children": [
-// JSON-INDEX-NEXT:         {
-// JSON-INDEX-NEXT:           "USR": "{{([0-9A-F]{40})}}",
-// JSON-INDEX-NEXT:           "Name": "ClassInAnotherNamespace",
-// JSON-INDEX-NEXT:           "RefType": "record",
-// JSON-INDEX-NEXT:           "Path": "AnotherNamespace",
-// JSON-INDEX-NEXT:           "Children": []
-// JSON-INDEX-NEXT:         }
-// JSON-INDEX-NEXT:       ]
-// JSON-INDEX-NEXT:     },
-// JSON-INDEX-NEXT:     {
-// JSON-INDEX-NEXT:       "USR": "{{([0-9A-F]{40})}}",
-// JSON-INDEX-NEXT:       "Name": "GlobalNamespace",
-// JSON-INDEX-NEXT:       "RefType": "namespace",
-// JSON-INDEX-NEXT:       "Path": "GlobalNamespace",
-// JSON-INDEX-NEXT:       "Children": []
-// JSON-INDEX-NEXT:     },
-// JSON-INDEX-NEXT:     {
-// JSON-INDEX-NEXT:       "USR": "{{([0-9A-F]{40})}}",
-// JSON-INDEX-NEXT:       "Name": "PrimaryNamespace",
-// JSON-INDEX-NEXT:       "RefType": "namespace",
-// JSON-INDEX-NEXT:       "Path": "PrimaryNamespace",
-// JSON-INDEX-NEXT:       "Children": [
-// JSON-INDEX-NEXT:         {
-// JSON-INDEX-NEXT:           "USR": "{{([0-9A-F]{40})}}",
-// JSON-INDEX-NEXT:           "Name": "ClassInPrimaryNamespace",
-// JSON-INDEX-NEXT:           "RefType": "record",
-// JSON-INDEX-NEXT:           "Path": "PrimaryNamespace",
-// JSON-INDEX-NEXT:           "Children": []
-// JSON-INDEX-NEXT:         },
-// JSON-INDEX-NEXT:         {
-// JSON-INDEX-NEXT:           "USR": "{{([0-9A-F]{40})}}",
-// JSON-INDEX-NEXT:           "Name": "NestedNamespace",
-// JSON-INDEX-NEXT:           "RefType": "namespace",
-// JSON-INDEX-NEXT:           "Path": "PrimaryNamespace{{[\/]+}}NestedNamespace",
-// JSON-INDEX-NEXT:           "Children": [
-// JSON-INDEX-NEXT:             {
-// JSON-INDEX-NEXT:               "USR": "{{([0-9A-F]{40})}}",
-// JSON-INDEX-NEXT:               "Name": "ClassInNestedNamespace",
-// JSON-INDEX-NEXT:               "RefType": "record",
-// JSON-INDEX-NEXT:               "Path": "PrimaryNamespace{{[\/]+}}NestedNamespace",
-// JSON-INDEX-NEXT:               "Children": []
-// JSON-INDEX-NEXT:             }
-// JSON-INDEX-NEXT:           ]
-// JSON-INDEX-NEXT:         }
-// JSON-INDEX-NEXT:       ]
-// JSON-INDEX-NEXT:     }
-// JSON-INDEX-NEXT:   ]
-// JSON-INDEX-NEXT: };
-// JSON-INDEX-NEXT: }
-
-// HTML-GLOBAL-INDEX: <div id="main-content" class="col-xs-12 col-sm-9 col-md-8 main-content">
-// HTML-GLOBAL-INDEX: <h1>Global Namespace</h1>
-// HTML-GLOBAL-INDEX: <h2 id="Namespaces">Namespaces</h2>
-// HTML-GLOBAL-INDEX: <li>@nonymous_namespace</li>
-// HTML-GLOBAL-INDEX: <li>AnotherNamespace</li>
-// HTML-GLOBAL-INDEX: <li>PrimaryNamespace</li>
-
-// MUSTACHE-GLOBAL-INDEX: <div id="main-content" class="col-xs-12 col-sm-9 col-md-8 main-content">
-// MUSTACHE-GLOBAL-INDEX: <h1>Global Namespace</h1>
-// MUSTACHE-GLOBAL-INDEX: <h2 id="Namespaces">Namespaces</h2>
-// MUSTACHE-GLOBAL-INDEX: <li>@nonymous_namespace</li>
-// MUSTACHE-GLOBAL-INDEX: <li>AnotherNamespace</li>
-// MUSTACHE-GLOBAL-INDEX: <li>PrimaryNamespace</li>
+// HTML-ANOTHER-INDEX: <h2> AnotherNamespace</h2>
+// HTML-ANOTHER-INDEX:     <h2>Inner Classes</h2>
+// HTML-ANOTHER-INDEX:     <ul class="class-container">
+// HTML-ANOTHER-INDEX:         <li id="{{([0-9A-F]{40})}}" style="max-height: 40px;">
+// HTML-ANOTHER-INDEX:             <a href="_ZTVN16AnotherNamespace23ClassInAnotherNamespaceE.html">
+// HTML-ANOTHER-INDEX:                 <pre><code class="language-cpp code-clang-doc">class ClassInAnotherNamespace</code></pre>
+// HTML-ANOTHER-INDEX:             </a>
+// HTML-ANOTHER-INDEX:         </li>
+// HTML-ANOTHER-INDEX:     </ul>
+// HTML-ANOTHER-INDEX-NOT: <h2 id="Functions">Functions</h2>
+// HTML-ANOTHER-INDEX-NOT: <h3 id="{{([0-9A-F]{40})}}">functionInAnotherNamespace</h3>
+// HTML-ANOTHER-INDEX-NOT: <p>void functionInAnotherNamespace()</p>
+// HTML-ANOTHER-INDEX-NOT: <p> Function in AnotherNamespace</p>
+
+// COM: FIXME: Add namespaces to namespace template
+// HTML-GLOBAL-INDEX-NOT: <div id="main-content" class="col-xs-12 col-sm-9 col-md-8 main-content">
+// HTML-GLOBAL-INDEX-NOT: <h1>Global Namespace</h1>
+// HTML-GLOBAL-INDEX-NOT: <h2 id="Namespaces">Namespaces</h2>
+// HTML-GLOBAL-INDEX-NOT: <li>@nonymous_namespace</li>
+// HTML-GLOBAL-INDEX-NOT: <li>AnotherNamespace</li>
+// HTML-GLOBAL-INDEX-NOT: <li>PrimaryNamespace</li>
 
 // MD-GLOBAL-INDEX: # Global Namespace
 // MD-GLOBAL-INDEX: ## Namespaces
diff --git a/clang-tools-extra/test/clang-doc/test-path-abs.cpp b/clang-tools-extra/test/clang-doc/test-path-abs.cpp
deleted file mode 100644
index 8875a3a73ab7e..0000000000000
--- a/clang-tools-extra/test/clang-doc/test-path-abs.cpp
+++ /dev/null
@@ -1,7 +0,0 @@
-// RUN: rm -rf %t && mkdir -p %t
-// RUN: clang-doc --format=html --executor=standalone %s --output=%t --base base_dir
-// RUN: FileCheck %s -input-file=%t/index_json.js  -check-prefix=JSON-INDEX
-
-// JSON-INDEX: var RootPath = "{{.*}}test-path-abs.cpp.tmp";
-// JSON-INDEX-NEXT: var Base = "base_dir";
-
diff --git a/clang-tools-extra/unittests/clang-doc/CMakeLists.txt b/clang-tools-extra/unittests/clang-doc/CMakeLists.txt
index 18166acf9bbca..01b34ec9a791e 100644
--- a/clang-tools-extra/unittests/clang-doc/CMakeLists.txt
+++ b/clang-tools-extra/unittests/clang-doc/CMakeLists.txt
@@ -26,7 +26,6 @@ add_extra_unittest(ClangDocTests
   ClangDocTest.cpp
   GeneratorTest.cpp
   HTMLGeneratorTest.cpp
-  HTMLMustacheGeneratorTest.cpp
   MDGeneratorTest.cpp
   MergeTest.cpp
   SerializeTest.cpp
diff --git a/clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp b/clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp
index 143414354d36c..10bb715f7f7f3 100644
--- a/clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp
@@ -1,4 +1,4 @@
-//===-- clang-doc/HTMLGeneratorTest.cpp -----------------------------------===//
+//===-- clang-doc/HTMLGeneratorTest.cpp ---------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -9,17 +9,26 @@
 #include "ClangDocTest.h"
 #include "Generators.h"
 #include "Representation.h"
+#include "config.h"
+#include "support/Utils.h"
 #include "clang/Basic/Version.h"
+#include "llvm/Testing/Support/Error.h"
+#include "gmock/gmock.h"
 #include "gtest/gtest.h"
 
-namespace clang {
-namespace doc {
+using namespace llvm;
+using namespace testing;
+using namespace clang;
+using namespace clang::doc;
 
-static const std::string ClangDocVersion =
-    clang::getClangToolFullVersion("clang-doc");
+// FIXME: Don't enable unit tests that can read files. Remove once we can use
+// lit to test these properties.
+#define ENABLE_LOCAL_TEST 0
+
+static const std::string ClangDocVersion = getClangToolFullVersion("clang-doc");
 
 static std::unique_ptr<Generator> getHTMLGenerator() {
-  auto G = doc::findGeneratorByName("html");
+  auto G = findGeneratorByName("html");
   if (!G)
     return nullptr;
   return std::move(G.get());
@@ -32,461 +41,15 @@ getClangDocContext(std::vector<std::string> UserStylesheets = {},
   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");
+  CDCtx.UserStylesheets.insert(CDCtx.UserStylesheets.begin(), "");
+  CDCtx.JsScripts.emplace_back("");
   return CDCtx;
 }
 
-TEST(HTMLGeneratorTest, emitNamespaceHTML) {
-  NamespaceInfo I;
-  I.Name = "Namespace";
-  I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
-
-  I.Children.Namespaces.emplace_back(EmptySID, "ChildNamespace",
-                                     InfoType::IT_namespace,
-                                     "Namespace::ChildNamespace", "Namespace");
-  I.Children.Records.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record,
-                                  "Namespace::ChildStruct", "Namespace");
-  I.Children.Functions.emplace_back();
-  I.Children.Functions.back().Access = AccessSpecifier::AS_none;
-  I.Children.Functions.back().Name = "OneFunction";
-  I.Children.Enums.emplace_back();
-  I.Children.Enums.back().Name = "OneEnum";
-
-  auto G = getHTMLGenerator();
-  assert(G);
-  std::string Buffer;
-  llvm::raw_string_ostream Actual(Buffer);
-  ClangDocContext CDCtx = getClangDocContext({"user-provided-stylesheet.css"});
-  auto Err = G->generateDocForInfo(&I, Actual, CDCtx);
-  assert(!Err);
-  std::string Expected = R"raw(<!DOCTYPE html>
-<meta charset="utf-8"/>
-<title>namespace Namespace</title>
-<link rel="stylesheet" href="../clang-doc-default-stylesheet.css"/>
-<link rel="stylesheet" href="../user-provided-stylesheet.css"/>
-<script src="../index_json.js"></script>
-<script src="../index.js"></script>
-<header id="project-title">test-project</header>
-<main>
-  <div id="sidebar-left" path="Namespace" class="col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left"></div>
-  <div id="main-content" class="col-xs-12 col-sm-9 col-md-8 main-content">
-    <h1>namespace Namespace</h1>
-    <h2 id="Namespaces">Namespaces</h2>
-    <ul>
-      <li>
-        <a href="ChildNamespace/index.html">ChildNamespace</a>
-      </li>
-    </ul>
-    <h2 id="Records">Records</h2>
-    <ul>
-      <li>
-        <a href="ChildStruct.html">ChildStruct</a>
-      </li>
-    </ul>
-    <h2 id="Functions">Functions</h2>
-    <div>
-      <h3 id="0000000000000000000000000000000000000000">OneFunction</h3>
-      <p>OneFunction()</p>
-    </div>
-    <h2 id="Enums">Enums</h2>
-    <div>
-      <table id="0000000000000000000000000000000000000000">
-        <thead>
-          <tr>
-            <th colspan="2">enum OneEnum</th>
-          </tr>
-        </thead>
-      </table>
-    </div>
-  </div>
-  <div id="sidebar-right" class="col-xs-6 col-sm-6 col-md-2 sidebar sidebar-offcanvas-right">
-    <ol>
-      <li>
-        <span>
-          <a href="#Namespaces">Namespaces</a>
-        </span>
-      </li>
-      <li>
-        <span>
-          <a href="#Records">Records</a>
-        </span>
-      </li>
-      <li>
-        <span>
-          <a href="#Functions">Functions</a>
-        </span>
-        <ul>
-          <li>
-            <span>
-              <a href="#0000000000000000000000000000000000000000">OneFunction</a>
-            </span>
-          </li>
-        </ul>
-      </li>
-      <li>
-        <span>
-          <a href="#Enums">Enums</a>
-        </span>
-        <ul>
-          <li>
-            <span>
-              <a href="#0000000000000000000000000000000000000000">OneEnum</a>
-            </span>
-          </li>
-        </ul>
-      </li>
-    </ol>
-  </div>
-</main>
-<footer>
-  <span class="no-break">)raw" +
-                         ClangDocVersion + R"raw(</span>
-</footer>
-)raw";
-
-  EXPECT_EQ(Expected, Actual.str());
-}
-
-TEST(HTMLGeneratorTest, emitRecordHTML) {
-  RecordInfo I;
-  I.Name = "r";
-  I.Path = "X/Y/Z";
-  I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
-
-  I.DefLoc = Location(10, 10, "dir/test.cpp", true);
-  I.Loc.emplace_back(12, 12, "test.cpp");
-
-  SmallString<16> PathTo;
-  llvm::sys::path::native("path/to", PathTo);
-  I.Members.emplace_back(TypeInfo("int"), "X", AccessSpecifier::AS_private);
-  I.TagType = TagTypeKind::Class;
-  I.Parents.emplace_back(EmptySID, "F", InfoType::IT_record, "F", PathTo);
-  I.VirtualParents.emplace_back(EmptySID, "G", InfoType::IT_record);
-
-  I.Children.Records.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record,
-                                  "X::Y::Z::r::ChildStruct", "X/Y/Z/r");
-  I.Children.Functions.emplace_back();
-  I.Children.Functions.back().Name = "OneFunction";
-  I.Children.Enums.emplace_back();
-  I.Children.Enums.back().Name = "OneEnum";
-
-  auto G = getHTMLGenerator();
-  assert(G);
-  std::string Buffer;
-  llvm::raw_string_ostream Actual(Buffer);
-  ClangDocContext CDCtx = getClangDocContext({}, "http://www.repository.com");
-  auto Err = G->generateDocForInfo(&I, Actual, CDCtx);
-  assert(!Err);
-  std::string Expected = R"raw(<!DOCTYPE html>
-<meta charset="utf-8"/>
-<title>class r</title>
-<link rel="stylesheet" href="../../../clang-doc-default-stylesheet.css"/>
-<script src="../../../index_json.js"></script>
-<script src="../../../index.js"></script>
-<header id="project-title">test-project</header>
-<main>
-  <div id="sidebar-left" path="X/Y/Z" class="col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left"></div>
-  <div id="main-content" class="col-xs-12 col-sm-9 col-md-8 main-content">
-    <h1>class r</h1>
-    <p>
-      Defined at line 
-      <a href="http://www.repository.com/dir/test.cpp#10">10</a>
-       of file 
-      <a href="http://www.repository.com/dir/test.cpp">test.cpp</a>
-    </p>
-    <p>
-      Inherits from 
-      <a href="../../../path/to/F.html">F</a>
-      , G
-    </p>
-    <h2 id="Members">Members</h2>
-    <ul>
-      <li>
-        <div>private int X</div>
-      </li>
-    </ul>
-    <h2 id="Records">Records</h2>
-    <ul>
-      <li>
-        <a href="../../../X/Y/Z/r/ChildStruct.html">ChildStruct</a>
-      </li>
-    </ul>
-    <h2 id="Functions">Functions</h2>
-    <div>
-      <h3 id="0000000000000000000000000000000000000000">OneFunction</h3>
-      <p>public OneFunction()</p>
-    </div>
-    <h2 id="Enums">Enums</h2>
-    <div>
-      <table id="0000000000000000000000000000000000000000">
-        <thead>
-          <tr>
-            <th colspan="2">enum OneEnum</th>
-          </tr>
-        </thead>
-      </table>
-    </div>
-  </div>
-  <div id="sidebar-right" class="col-xs-6 col-sm-6 col-md-2 sidebar sidebar-offcanvas-right">
-    <ol>
-      <li>
-        <span>
-          <a href="#Members">Members</a>
-        </span>
-      </li>
-      <li>
-        <span>
-          <a href="#Records">Records</a>
-        </span>
-      </li>
-      <li>
-        <span>
-          <a href="#Functions">Functions</a>
-        </span>
-        <ul>
-          <li>
-            <span>
-              <a href="#0000000000000000000000000000000000000000">OneFunction</a>
-            </span>
-          </li>
-        </ul>
-      </li>
-      <li>
-        <span>
-          <a href="#Enums">Enums</a>
-        </span>
-        <ul>
-          <li>
-            <span>
-              <a href="#0000000000000000000000000000000000000000">OneEnum</a>
-            </span>
-          </li>
-        </ul>
-      </li>
-    </ol>
-  </div>
-</main>
-<footer>
-  <span class="no-break">)raw" +
-                         ClangDocVersion + R"raw(</span>
-</footer>
-)raw";
-
-  EXPECT_EQ(Expected, Actual.str());
-}
-
-TEST(HTMLGeneratorTest, emitFunctionHTML) {
-  FunctionInfo I;
-  I.Name = "f";
-  I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
-
-  I.DefLoc = Location(10, 10, "dir/test.cpp", true);
-  I.Loc.emplace_back(12, 12, "test.cpp");
-
-  I.Access = AccessSpecifier::AS_none;
-
-  SmallString<16> PathTo;
-  llvm::sys::path::native("path/to", PathTo);
-  I.ReturnType = TypeInfo(
-      Reference(EmptySID, "float", InfoType::IT_default, "float", PathTo));
-  I.Params.emplace_back(TypeInfo("int", PathTo), "P");
-  I.IsMethod = true;
-  I.Parent = Reference(EmptySID, "Parent", InfoType::IT_record);
-
+TEST(HTMLGeneratorTest, createResources) {
   auto G = getHTMLGenerator();
-  assert(G);
-  std::string Buffer;
-  llvm::raw_string_ostream Actual(Buffer);
-  ClangDocContext CDCtx = getClangDocContext({}, "https://www.repository.com");
-  auto Err = G->generateDocForInfo(&I, Actual, CDCtx);
-  assert(!Err);
-  std::string Expected = R"raw(<!DOCTYPE html>
-<meta charset="utf-8"/>
-<title></title>
-<link rel="stylesheet" href="clang-doc-default-stylesheet.css"/>
-<script src="index_json.js"></script>
-<script src="index.js"></script>
-<header id="project-title">test-project</header>
-<main>
-  <div id="sidebar-left" path="" class="col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left"></div>
-  <div id="main-content" class="col-xs-12 col-sm-9 col-md-8 main-content">
-    <h3 id="0000000000000000000000000000000000000000">f</h3>
-    <p>
-      <a href="path/to/float.html">float</a>
-       f(
-      <a href="path/to/int.html">int</a>
-       P)
-    </p>
-    <p>
-      Defined at line 
-      <a href="https://www.repository.com/dir/test.cpp#10">10</a>
-       of file 
-      <a href="https://www.repository.com/dir/test.cpp">test.cpp</a>
-    </p>
-  </div>
-  <div id="sidebar-right" class="col-xs-6 col-sm-6 col-md-2 sidebar sidebar-offcanvas-right"></div>
-</main>
-<footer>
-  <span class="no-break">)raw" +
-                         ClangDocVersion + R"raw(</span>
-</footer>
-)raw";
-
-  EXPECT_EQ(Expected, Actual.str());
-}
-
-TEST(HTMLGeneratorTest, emitEnumHTML) {
-  EnumInfo I;
-  I.Name = "e";
-  I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
-
-  I.DefLoc = Location(10, 10, "test.cpp", true);
-  I.Loc.emplace_back(12, 12, "test.cpp");
-
-  I.Members.emplace_back("X");
-  I.Scoped = true;
-
-  auto G = getHTMLGenerator();
-  assert(G);
-  std::string Buffer;
-  llvm::raw_string_ostream Actual(Buffer);
-  ClangDocContext CDCtx = getClangDocContext({}, "www.repository.com");
-  auto Err = G->generateDocForInfo(&I, Actual, CDCtx);
-  assert(!Err);
-  std::string Expected = R"raw(<!DOCTYPE html>
-<meta charset="utf-8"/>
-<title></title>
-<link rel="stylesheet" href="clang-doc-default-stylesheet.css"/>
-<script src="index_json.js"></script>
-<script src="index.js"></script>
-<header id="project-title">test-project</header>
-<main>
-  <div id="sidebar-left" path="" class="col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left"></div>
-  <div id="main-content" class="col-xs-12 col-sm-9 col-md-8 main-content">
-    <table id="0000000000000000000000000000000000000000">
-      <thead>
-        <tr>
-          <th colspan="2">enum class e</th>
-        </tr>
-      </thead>
-      <tbody>
-        <tr>
-          <td>X</td>
-          <td>0</td>
-        </tr>
-      </tbody>
-    </table>
-    <p>
-      Defined at line 
-      <a href="https://www.repository.com/test.cpp#10">10</a>
-       of file 
-      <a href="https://www.repository.com/test.cpp">test.cpp</a>
-    </p>
-  </div>
-  <div id="sidebar-right" class="col-xs-6 col-sm-6 col-md-2 sidebar sidebar-offcanvas-right"></div>
-</main>
-<footer>
-  <span class="no-break">)raw" +
-                         ClangDocVersion + R"raw(</span>
-</footer>
-)raw";
-
-  EXPECT_EQ(Expected, Actual.str());
-}
-
-TEST(HTMLGeneratorTest, emitCommentHTML) {
-  FunctionInfo I;
-  I.Name = "f";
-  I.DefLoc = Location(10, 10, "test.cpp", true);
-  I.ReturnType = TypeInfo("void");
-  I.Params.emplace_back(TypeInfo("int"), "I");
-  I.Params.emplace_back(TypeInfo("int"), "J");
-  I.Access = AccessSpecifier::AS_none;
-
-  CommentInfo Top;
-  Top.Kind = CommentKind::CK_FullComment;
-
-  Top.Children.emplace_back(std::make_unique<CommentInfo>());
-  CommentInfo *BlankLine = Top.Children.back().get();
-  BlankLine->Kind = CommentKind::CK_ParagraphComment;
-  BlankLine->Children.emplace_back(std::make_unique<CommentInfo>());
-  BlankLine->Children.back()->Kind = CommentKind::CK_TextComment;
-
-  Top.Children.emplace_back(std::make_unique<CommentInfo>());
-  CommentInfo *Brief = Top.Children.back().get();
-  Brief->Kind = CommentKind::CK_ParagraphComment;
-  Brief->Children.emplace_back(std::make_unique<CommentInfo>());
-  Brief->Children.back()->Kind = CommentKind::CK_TextComment;
-  Brief->Children.back()->Name = "ParagraphComment";
-  Brief->Children.back()->Text = " Brief description.";
-
-  Top.Children.emplace_back(std::make_unique<CommentInfo>());
-  CommentInfo *Extended = Top.Children.back().get();
-  Extended->Kind = CommentKind::CK_ParagraphComment;
-  Extended->Children.emplace_back(std::make_unique<CommentInfo>());
-  Extended->Children.back()->Kind = CommentKind::CK_TextComment;
-  Extended->Children.back()->Text = " Extended description that";
-  Extended->Children.emplace_back(std::make_unique<CommentInfo>());
-  Extended->Children.back()->Kind = CommentKind::CK_TextComment;
-  Extended->Children.back()->Text = " continues onto the next line.";
-
-  Top.Children.emplace_back(std::make_unique<CommentInfo>());
-  CommentInfo *Entities = Top.Children.back().get();
-  Entities->Kind = CommentKind::CK_ParagraphComment;
-  Entities->Children.emplace_back(std::make_unique<CommentInfo>());
-  Entities->Children.back()->Kind = CommentKind::CK_TextComment;
-  Entities->Children.back()->Name = "ParagraphComment";
-  Entities->Children.back()->Text =
-      " Comment with html entities: &, <, >, \", \'.";
-
-  I.Description.emplace_back(std::move(Top));
-
-  auto G = getHTMLGenerator();
-  assert(G);
-  std::string Buffer;
-  llvm::raw_string_ostream Actual(Buffer);
+  ASSERT_THAT(G, NotNull()) << "Could not find HTMLGenerator";
   ClangDocContext CDCtx = getClangDocContext();
-  auto Err = G->generateDocForInfo(&I, Actual, CDCtx);
-  assert(!Err);
-  std::string Expected = R"raw(<!DOCTYPE html>
-<meta charset="utf-8"/>
-<title></title>
-<link rel="stylesheet" href="clang-doc-default-stylesheet.css"/>
-<script src="index_json.js"></script>
-<script src="index.js"></script>
-<header id="project-title">test-project</header>
-<main>
-  <div id="sidebar-left" path="" class="col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left"></div>
-  <div id="main-content" class="col-xs-12 col-sm-9 col-md-8 main-content">
-    <h3 id="0000000000000000000000000000000000000000">f</h3>
-    <p>void f(int I, int J)</p>
-    <p>
-      Defined at line 
-      <a href="test.cpp#10">10</a>
-       of file 
-      <a href="test.cpp">test.cpp</a>
-    </p>
-    <div>
-      <div>
-        <p> Brief description.</p>
-        <p> Extended description that continues onto the next line.</p>
-        <p> Comment with html entities: &, <, >, ", '.</p>
-      </div>
-    </div>
-  </div>
-  <div id="sidebar-right" class="col-xs-6 col-sm-6 col-md-2 sidebar sidebar-offcanvas-right"></div>
-</main>
-<footer>
-  <span class="no-break">)raw" +
-                         ClangDocVersion + R"raw(</span>
-</footer>
-)raw";
-
-  EXPECT_EQ(Expected, Actual.str());
+  EXPECT_THAT_ERROR(G->createResources(CDCtx), Failed())
+      << "Empty UserStylesheets or JsScripts should fail!";
 }
-
-} // namespace doc
-} // namespace clang
diff --git a/clang-tools-extra/unittests/clang-doc/HTMLMustacheGeneratorTest.cpp b/clang-tools-extra/unittests/clang-doc/HTMLMustacheGeneratorTest.cpp
deleted file mode 100644
index c7ac387ecf7c3..0000000000000
--- a/clang-tools-extra/unittests/clang-doc/HTMLMustacheGeneratorTest.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-//===-- clang-doc/HTMLMustacheGeneratorTest.cpp ---------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "ClangDocTest.h"
-#include "Generators.h"
-#include "Representation.h"
-#include "config.h"
-#include "support/Utils.h"
-#include "clang/Basic/Version.h"
-#include "llvm/Testing/Support/Error.h"
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-
-using namespace llvm;
-using namespace testing;
-using namespace clang;
-using namespace clang::doc;
-
-// FIXME: Don't enable unit tests that can read files. Remove once we can use
-// lit to test these properties.
-#define ENABLE_LOCAL_TEST 0
-
-static const std::string ClangDocVersion = getClangToolFullVersion("clang-doc");
-
-static std::unique_ptr<Generator> getHTMLMustacheGenerator() {
-  auto G = findGeneratorByName("mustache");
-  if (!G)
-    return nullptr;
-  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;
-}
-
-TEST(HTMLMustacheGeneratorTest, createResources) {
-  auto G = getHTMLMustacheGenerator();
-  ASSERT_THAT(G, NotNull()) << "Could not find HTMLMustacheGenerator";
-  ClangDocContext CDCtx = getClangDocContext();
-  EXPECT_THAT_ERROR(G->createResources(CDCtx), Failed())
-      << "Empty UserStylesheets or JsScripts should fail!";
-}



More information about the llvm-branch-commits mailing list