Skip to content

[clang-doc] Adds a mustache backend #133161

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 25 commits into
base: main
Choose a base branch
from

Conversation

PeterChou1
Copy link
Contributor

No description provided.

Copy link

⚠️ C/C++ code formatter, clang-format found issues in your code. ⚠️

You can test this locally with the following command:
git-clang-format --diff 2d1517d257fcbd0c9bce14badc7646e94d81ea2b 9dbd1b84d501db2619b716a029e612bca60eef5f --extensions h,cpp -- clang-tools-extra/clang-doc/FileHelpersClangDoc.cpp clang-tools-extra/clang-doc/FileHelpersClangDoc.h clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp llvm/tools/mustache/mustache.cpp clang-tools-extra/clang-doc/Generators.cpp clang-tools-extra/clang-doc/HTMLGenerator.cpp clang-tools-extra/clang-doc/Representation.cpp clang-tools-extra/clang-doc/Representation.h clang-tools-extra/clang-doc/Serialize.cpp clang-tools-extra/clang-doc/Serialize.h clang-tools-extra/clang-doc/tool/ClangDocMain.cpp clang-tools-extra/test/clang-doc/Inputs/basic-project/include/Shape.h
View the diff from clang-format here.
diff --git a/clang-tools-extra/clang-doc/FileHelpersClangDoc.cpp b/clang-tools-extra/clang-doc/FileHelpersClangDoc.cpp
index 50209cfac1..704adcf689 100644
--- a/clang-tools-extra/clang-doc/FileHelpersClangDoc.cpp
+++ b/clang-tools-extra/clang-doc/FileHelpersClangDoc.cpp
@@ -12,8 +12,7 @@
 namespace clang {
 namespace doc {
 
-llvm::Error
-copyFile(llvm::StringRef FilePath, llvm::StringRef OutDirectory) {
+llvm::Error copyFile(llvm::StringRef FilePath, llvm::StringRef OutDirectory) {
   llvm::SmallString<128> PathWrite;
   llvm::sys::path::native(OutDirectory, PathWrite);
   llvm::sys::path::append(PathWrite, llvm::sys::path::filename(FilePath));
@@ -30,14 +29,13 @@ copyFile(llvm::StringRef FilePath, llvm::StringRef OutDirectory) {
   return llvm::Error::success();
 }
 
-
 llvm::SmallString<128> computeRelativePath(llvm::StringRef Destination,
-                                                  llvm::StringRef Origin) {
+                                           llvm::StringRef Origin) {
   // If Origin is empty, the relative path to the Destination is its complete
   // path.
   if (Origin.empty())
     return Destination;
-  
+
   // The relative path is an empty path if both directories are the same.
   if (Destination == Origin)
     return {};
diff --git a/clang-tools-extra/clang-doc/FileHelpersClangDoc.h b/clang-tools-extra/clang-doc/FileHelpersClangDoc.h
index 9072a7bd08..997bbea63d 100644
--- a/clang-tools-extra/clang-doc/FileHelpersClangDoc.h
+++ b/clang-tools-extra/clang-doc/FileHelpersClangDoc.h
@@ -14,11 +14,10 @@
 namespace clang {
 namespace doc {
 
-llvm::Error 
-copyFile(llvm::StringRef FilePath, llvm::StringRef OutDirectory);
+llvm::Error copyFile(llvm::StringRef FilePath, llvm::StringRef OutDirectory);
 
-llvm::SmallString<128> 
-computeRelativePath(llvm::StringRef Destination,llvm::StringRef Origin);
+llvm::SmallString<128> computeRelativePath(llvm::StringRef Destination,
+                                           llvm::StringRef Origin);
 
 } // namespace doc
 } // namespace clang
diff --git a/clang-tools-extra/clang-doc/HTMLGenerator.cpp b/clang-tools-extra/clang-doc/HTMLGenerator.cpp
index 6b0efc9d4f..1f9b53b0c7 100644
--- a/clang-tools-extra/clang-doc/HTMLGenerator.cpp
+++ b/clang-tools-extra/clang-doc/HTMLGenerator.cpp
@@ -512,8 +512,8 @@ writeFileDefinition(const Location &L,
           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));
+  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.
   // FIXME: we probably should have a configuration setting for line number
@@ -1146,8 +1146,7 @@ static llvm::Error genIndex(const ClangDocContext &CDCtx) {
   return llvm::Error::success();
 }
 
-static llvm::Error 
-copyFile(StringRef FilePath, StringRef OutDirectory) {
+static llvm::Error copyFile(StringRef FilePath, StringRef OutDirectory) {
   llvm::SmallString<128> PathWrite;
   llvm::sys::path::native(OutDirectory, PathWrite);
   llvm::sys::path::append(PathWrite, llvm::sys::path::filename(FilePath));
diff --git a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
index 1f96202f1f..67f37a2bbe 100644
--- a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
+++ b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
@@ -5,9 +5,9 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
+#include "FileHelpersClangDoc.h"
 #include "Generators.h"
 #include "Representation.h"
-#include "FileHelpersClangDoc.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/Mustache.h"
 
@@ -18,7 +18,6 @@ using namespace llvm::mustache;
 namespace clang {
 namespace doc {
 
-
 class MustacheHTMLGenerator : public Generator {
 public:
   static const char *Format;
@@ -28,16 +27,15 @@ public:
   llvm::Error createResources(ClangDocContext &CDCtx) override;
   llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS,
                                  const ClangDocContext &CDCtx) override;
-  
 };
 
 class MustacheTemplateFile : public Template {
 public:
-  static ErrorOr<std::unique_ptr<MustacheTemplateFile>> createMustacheFile
-      (StringRef FileName) {
+  static ErrorOr<std::unique_ptr<MustacheTemplateFile>>
+  createMustacheFile(StringRef FileName) {
     ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrError =
         MemoryBuffer::getFile(FileName);
-    
+
     if (auto EC = BufferOrError.getError()) {
       return EC;
     }
@@ -45,7 +43,7 @@ public:
     llvm::StringRef FileContent = Buffer->getBuffer();
     return std::make_unique<MustacheTemplateFile>(FileContent);
   }
-  
+
   Error registerPartialFile(StringRef Name, StringRef FileName) {
     ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrError =
         MemoryBuffer::getFile(FileName);
@@ -64,11 +62,10 @@ static std::unique_ptr<MustacheTemplateFile> NamespaceTemplate = nullptr;
 
 static std::unique_ptr<MustacheTemplateFile> RecordTemplate = nullptr;
 
-
-llvm::Error setupTemplate(
-    std::unique_ptr<MustacheTemplateFile> &Template,
-    StringRef TemplatePath,
-    std::vector<std::pair<StringRef, StringRef>> Partials) {
+llvm::Error
+setupTemplate(std::unique_ptr<MustacheTemplateFile> &Template,
+              StringRef TemplatePath,
+              std::vector<std::pair<StringRef, StringRef>> Partials) {
   auto T = MustacheTemplateFile::createMustacheFile(TemplatePath);
   if (auto EC = T.getError())
     return llvm::createFileError("cannot open file", EC);
@@ -81,8 +78,7 @@ llvm::Error setupTemplate(
   return llvm::Error::success();
 }
 
-llvm::Error 
-setupTemplateFiles(const clang::doc::ClangDocContext &CDCtx) {
+llvm::Error setupTemplateFiles(const clang::doc::ClangDocContext &CDCtx) {
   auto NamespaceFilePath = CDCtx.MustacheTemplates.lookup("namespace-template");
   auto ClassFilePath = CDCtx.MustacheTemplates.lookup("class-template");
   auto CommentFilePath = CDCtx.MustacheTemplates.lookup("comments-template");
@@ -91,26 +87,23 @@ setupTemplateFiles(const clang::doc::ClangDocContext &CDCtx) {
   std::vector<std::pair<StringRef, StringRef>> Partials = {
       {"Comments", CommentFilePath},
       {"FunctionPartial", FunctionFilePath},
-      {"EnumPartial", EnumFilePath}
-  };
-  
+      {"EnumPartial", EnumFilePath}};
+
   auto Err = setupTemplate(NamespaceTemplate, NamespaceFilePath, Partials);
   if (Err)
     return Err;
-  
+
   Err = setupTemplate(RecordTemplate, ClassFilePath, Partials);
-  
+
   if (Err)
     return Err;
-  
+
   return llvm::Error::success();
 }
 
-
-llvm::Error 
-MustacheHTMLGenerator::generateDocs(llvm::StringRef RootDir, 
-                                    llvm::StringMap<std::unique_ptr<doc::Info>> Infos, 
-                                    const clang::doc::ClangDocContext &CDCtx) {
+llvm::Error MustacheHTMLGenerator::generateDocs(
+    llvm::StringRef RootDir, llvm::StringMap<std::unique_ptr<doc::Info>> Infos,
+    const clang::doc::ClangDocContext &CDCtx) {
   if (auto Err = setupTemplateFiles(CDCtx))
     return Err;
   // Track which directories we already tried to create.
@@ -119,7 +112,7 @@ MustacheHTMLGenerator::generateDocs(llvm::StringRef RootDir,
   llvm::StringMap<std::vector<doc::Info *>> FileToInfos;
   for (const auto &Group : Infos) {
     doc::Info *Info = Group.getValue().get();
-    
+
     llvm::SmallString<128> Path;
     llvm::sys::path::native(RootDir, Path);
     llvm::sys::path::append(Path, Info->getRelativeFilePath(""));
@@ -134,7 +127,7 @@ MustacheHTMLGenerator::generateDocs(llvm::StringRef RootDir,
     llvm::sys::path::append(Path, Info->getFileBaseName() + ".html");
     FileToInfos[Path].push_back(Info);
   }
-  
+
   for (const auto &Group : FileToInfos) {
     std::error_code FileErr;
     llvm::raw_fd_ostream InfoOS(Group.getKey(), FileErr,
@@ -142,7 +135,7 @@ MustacheHTMLGenerator::generateDocs(llvm::StringRef RootDir,
     if (FileErr)
       return llvm::createStringError(FileErr, "Error opening file '%s'",
                                      Group.getKey().str().c_str());
-    
+
     for (const auto &Info : Group.getValue()) {
       if (llvm::Error Err = generateDocForInfo(Info, InfoOS, CDCtx))
         return Err;
@@ -151,12 +144,12 @@ MustacheHTMLGenerator::generateDocs(llvm::StringRef RootDir,
   return llvm::Error::success();
 }
 
-Value extractValue(const Location &L, 
+Value extractValue(const Location &L,
                    std::optional<StringRef> RepositoryUrl = std::nullopt) {
   Object Obj = Object();
   Obj.insert({"LineNumber", L.LineNumber});
   Obj.insert({"Filename", L.Filename});
-  
+
   if (!L.IsFileInRootDir || !RepositoryUrl) {
     return Obj;
   }
@@ -164,7 +157,7 @@ Value extractValue(const Location &L,
   llvm::sys::path::append(FileURL, llvm::sys::path::Style::posix, L.Filename);
   FileURL += "#" + std::to_string(L.LineNumber);
   Obj.insert({"FileURL", FileURL});
-  
+
   return Obj;
 }
 
@@ -180,7 +173,6 @@ Value extractValue(const Reference &I, StringRef CurrentDirectory) {
   return Obj;
 }
 
-
 Value extractValue(const TypedefInfo &I) {
   // Not Supported
   return nullptr;
@@ -189,17 +181,17 @@ Value extractValue(const TypedefInfo &I) {
 Value extractValue(const CommentInfo &I) {
   Object Obj = Object();
   Value Child = Object();
-  
+
   if (I.Kind == "FullComment") {
     Value ChildArr = Array();
-    for (const auto& C: I.Children)
+    for (const auto &C : I.Children)
       ChildArr.getAsArray()->emplace_back(extractValue(*C));
     Child.getAsObject()->insert({"Children", ChildArr});
     Obj.insert({"FullComment", Child});
   }
   if (I.Kind == "ParagraphComment") {
     Value ChildArr = Array();
-    for (const auto& C: I.Children)
+    for (const auto &C : I.Children)
       ChildArr.getAsArray()->emplace_back(extractValue(*C));
     Child.getAsObject()->insert({"Children", ChildArr});
     Obj.insert({"ParagraphComment", Child});
@@ -207,14 +199,14 @@ Value extractValue(const CommentInfo &I) {
   if (I.Kind == "BlockCommandComment") {
     Child.getAsObject()->insert({"Command", I.Name});
     Value ChildArr = Array();
-    for (const auto& C: I.Children)
+    for (const auto &C : I.Children)
       ChildArr.getAsArray()->emplace_back(extractValue(*C));
     Child.getAsObject()->insert({"Children", ChildArr});
     Obj.insert({"BlockCommandComment", Child});
   }
   if (I.Kind == "TextComment")
     Obj.insert({"TextComment", I.Text});
-  
+
   return Obj;
 }
 
@@ -225,30 +217,30 @@ Value extractValue(const FunctionInfo &I, StringRef ParentInfoDir,
   Obj.insert({"ID", llvm::toHex(llvm::toStringRef(I.USR))});
   Obj.insert({"Access", getAccessSpelling(I.Access).str()});
   Obj.insert({"ReturnType", extractValue(I.ReturnType.Type, ParentInfoDir)});
-  
+
   Value ParamArr = Array();
   for (const auto Val : llvm::enumerate(I.Params)) {
     Value V = Object();
     V.getAsObject()->insert({"Name", Val.value().Name});
     V.getAsObject()->insert({"Type", Val.value().Type.Name});
-    V.getAsObject()->insert({"End",  Val.index() + 1 == I.Params.size()});
+    V.getAsObject()->insert({"End", Val.index() + 1 == I.Params.size()});
     ParamArr.getAsArray()->emplace_back(V);
   }
   Obj.insert({"Params", ParamArr});
-  
+
   if (!I.Description.empty()) {
     Value ArrDesc = Array();
-    for (const CommentInfo& Child : I.Description) 
+    for (const CommentInfo &Child : I.Description)
       ArrDesc.getAsArray()->emplace_back(extractValue(Child));
     Obj.insert({"FunctionComments", ArrDesc});
   }
   if (I.DefLoc.has_value()) {
     Location L = *I.DefLoc;
     if (CDCtx.RepositoryUrl.has_value())
-      Obj.insert({"Location", extractValue(L,
-                                           StringRef{*CDCtx.RepositoryUrl})});
+      Obj.insert(
+          {"Location", extractValue(L, StringRef{*CDCtx.RepositoryUrl})});
     else
-      Obj.insert({"Location", extractValue(L)});  
+      Obj.insert({"Location", extractValue(L)});
   }
   return Obj;
 }
@@ -264,66 +256,66 @@ Value extractValue(const EnumInfo &I, const ClangDocContext &CDCtx) {
   Obj.insert({"HasComment", HasComment});
   Obj.insert({"ID", llvm::toHex(llvm::toStringRef(I.USR))});
   Value Arr = Array();
-  for (const EnumValueInfo& M: I.Members) {
+  for (const EnumValueInfo &M : I.Members) {
     Value EnumValue = Object();
     EnumValue.getAsObject()->insert({"Name", M.Name});
     if (!M.ValueExpr.empty())
       EnumValue.getAsObject()->insert({"ValueExpr", M.ValueExpr});
     else
       EnumValue.getAsObject()->insert({"Value", M.Value});
-    
+
     if (!M.Description.empty()) {
       Value ArrDesc = Array();
-      for (const CommentInfo& Child : M.Description) 
+      for (const CommentInfo &Child : M.Description)
         ArrDesc.getAsArray()->emplace_back(extractValue(Child));
       EnumValue.getAsObject()->insert({"EnumValueComments", ArrDesc});
     }
     Arr.getAsArray()->emplace_back(EnumValue);
   }
   Obj.insert({"EnumValues", Arr});
-  
+
   if (!I.Description.empty()) {
     Value ArrDesc = Array();
-    for (const CommentInfo& Child : I.Description) 
+    for (const CommentInfo &Child : I.Description)
       ArrDesc.getAsArray()->emplace_back(extractValue(Child));
     Obj.insert({"EnumComments", ArrDesc});
   }
-  
+
   if (I.DefLoc.has_value()) {
     Location L = *I.DefLoc;
     if (CDCtx.RepositoryUrl.has_value())
-      Obj.insert({"Location", extractValue(L,
-                                           StringRef{*CDCtx.RepositoryUrl})});
+      Obj.insert(
+          {"Location", extractValue(L, StringRef{*CDCtx.RepositoryUrl})});
     else
-      Obj.insert({"Location", extractValue(L)});  
+      Obj.insert({"Location", extractValue(L)});
   }
-  
+
   return Obj;
 }
 
-void extractScopeChildren(const ScopeChildren &S, Object &Obj, 
+void extractScopeChildren(const ScopeChildren &S, Object &Obj,
                           StringRef ParentInfoDir,
                           const ClangDocContext &CDCtx) {
   Value ArrNamespace = Array();
-  for (const Reference& Child : S.Namespaces)
+  for (const Reference &Child : S.Namespaces)
     ArrNamespace.getAsArray()->emplace_back(extractValue(Child, ParentInfoDir));
-  
+
   if (!ArrNamespace.getAsArray()->empty())
     Obj.insert({"Namespace", Object{{"Links", ArrNamespace}}});
-  
+
   Value ArrRecord = Array();
-  for (const Reference& Child : S.Records)
+  for (const Reference &Child : S.Records)
     ArrRecord.getAsArray()->emplace_back(extractValue(Child, ParentInfoDir));
-  
+
   if (!ArrRecord.getAsArray()->empty())
     Obj.insert({"Record", Object{{"Links", ArrRecord}}});
-  
+
   Value ArrFunction = Array();
   Value PublicFunction = Array();
   Value ProtectedFunction = Array();
   Value PrivateFunction = Array();
-  
-  for (const FunctionInfo& Child : S.Functions) {
+
+  for (const FunctionInfo &Child : S.Functions) {
     Value F = extractValue(Child, ParentInfoDir, CDCtx);
     AccessSpecifier Access = Child.Access;
     if (Access == AccessSpecifier::AS_public)
@@ -332,30 +324,29 @@ void extractScopeChildren(const ScopeChildren &S, Object &Obj,
       ProtectedFunction.getAsArray()->emplace_back(F);
     else
       ArrFunction.getAsArray()->emplace_back(F);
-  }  
+  }
   if (!ArrFunction.getAsArray()->empty())
     Obj.insert({"Function", Object{{"Obj", ArrFunction}}});
-  
+
   if (!PublicFunction.getAsArray()->empty())
     Obj.insert({"PublicFunction", Object{{"Obj", PublicFunction}}});
-  
+
   if (!ProtectedFunction.getAsArray()->empty())
     Obj.insert({"ProtectedFunction", Object{{"Obj", ProtectedFunction}}});
-  
-  
+
   Value ArrEnum = Array();
-  for (const EnumInfo& Child : S.Enums)
+  for (const EnumInfo &Child : S.Enums)
     ArrEnum.getAsArray()->emplace_back(extractValue(Child, CDCtx));
-  
+
   if (!ArrEnum.getAsArray()->empty())
-    Obj.insert({"Enums", Object{{"Obj", ArrEnum }}});
-  
+    Obj.insert({"Enums", Object{{"Obj", ArrEnum}}});
+
   Value ArrTypedefs = Array();
-  for (const TypedefInfo& Child : S.Typedefs) 
+  for (const TypedefInfo &Child : S.Typedefs)
     ArrTypedefs.getAsArray()->emplace_back(extractValue(Child));
-  
+
   if (!ArrTypedefs.getAsArray()->empty())
-    Obj.insert({"Typedefs", Object{{"Obj", ArrTypedefs }}});
+    Obj.insert({"Typedefs", Object{{"Obj", ArrTypedefs}}});
 }
 
 Value extractValue(const NamespaceInfo &I, const ClangDocContext &CDCtx) {
@@ -364,17 +355,17 @@ Value extractValue(const NamespaceInfo &I, const ClangDocContext &CDCtx) {
   if (I.Name.str() == "")
     InfoTitle = "Global Namespace";
   else
-    InfoTitle = ("namespace " + I.Name).str();  
-  
+    InfoTitle = ("namespace " + I.Name).str();
+
   StringRef BasePath = I.getRelativeFilePath("");
   NamespaceValue.insert({"NamespaceTitle", InfoTitle});
   NamespaceValue.insert({"NamespacePath", I.getRelativeFilePath("")});
-  
+
   if (!I.Description.empty()) {
     Value ArrDesc = Array();
-    for (const CommentInfo& Child : I.Description) 
+    for (const CommentInfo &Child : I.Description)
       ArrDesc.getAsArray()->emplace_back(extractValue(Child));
-    NamespaceValue.insert({"NamespaceComments", ArrDesc });
+    NamespaceValue.insert({"NamespaceComments", ArrDesc});
   }
   extractScopeChildren(I.Children, NamespaceValue, BasePath, CDCtx);
   return NamespaceValue;
@@ -382,42 +373,42 @@ Value extractValue(const NamespaceInfo &I, const ClangDocContext &CDCtx) {
 
 Value extractValue(const RecordInfo &I, const ClangDocContext &CDCtx) {
   Object RecordValue = Object();
-  
+
   if (!I.Description.empty()) {
     Value ArrDesc = Array();
-    for (const CommentInfo& Child : I.Description) 
+    for (const CommentInfo &Child : I.Description)
       ArrDesc.getAsArray()->emplace_back(extractValue(Child));
-    RecordValue.insert({"RecordComments", ArrDesc });
+    RecordValue.insert({"RecordComments", ArrDesc});
   }
   RecordValue.insert({"Name", I.Name});
   RecordValue.insert({"FullName", I.FullName});
   RecordValue.insert({"RecordType", getTagType(I.TagType)});
-  
+
   if (I.DefLoc.has_value()) {
     Location L = *I.DefLoc;
     if (CDCtx.RepositoryUrl.has_value())
-      RecordValue.insert({"Location", extractValue(L,
-                                                   StringRef{*CDCtx.RepositoryUrl})});
+      RecordValue.insert(
+          {"Location", extractValue(L, StringRef{*CDCtx.RepositoryUrl})});
     else
-      RecordValue.insert({"Location", extractValue(L)});  
+      RecordValue.insert({"Location", extractValue(L)});
   }
-  
+
   StringRef BasePath = I.getRelativeFilePath("");
   extractScopeChildren(I.Children, RecordValue, BasePath, CDCtx);
   Value PublicMembers = Array();
   Value ProtectedMembers = Array();
   Value PrivateMembers = Array();
-  for (const MemberTypeInfo &Member : I.Members ) {
+  for (const MemberTypeInfo &Member : I.Members) {
     Value MemberValue = Object();
     MemberValue.getAsObject()->insert({"Name", Member.Name});
     MemberValue.getAsObject()->insert({"Type", Member.Type.Name});
     if (!Member.Description.empty()) {
       Value ArrDesc = Array();
-      for (const CommentInfo& Child : Member.Description) 
+      for (const CommentInfo &Child : Member.Description)
         ArrDesc.getAsArray()->emplace_back(extractValue(Child));
-      MemberValue.getAsObject()->insert({"MemberComments", ArrDesc });
+      MemberValue.getAsObject()->insert({"MemberComments", ArrDesc});
     }
-    
+
     if (Member.Access == AccessSpecifier::AS_public)
       PublicMembers.getAsArray()->emplace_back(MemberValue);
     else if (Member.Access == AccessSpecifier::AS_protected)
@@ -431,7 +422,7 @@ Value extractValue(const RecordInfo &I, const ClangDocContext &CDCtx) {
     RecordValue.insert({"ProtectedMembers", Object{{"Obj", ProtectedMembers}}});
   if (!PrivateMembers.getAsArray()->empty())
     RecordValue.insert({"PrivateMembers", Object{{"Obj", PrivateMembers}}});
-  
+
   return RecordValue;
 }
 
@@ -440,7 +431,7 @@ void setupTemplateValue(const ClangDocContext &CDCtx, Value &V, Info *I) {
   Value StylesheetArr = Array();
   auto InfoPath = I->getRelativeFilePath("");
   SmallString<128> RelativePath = computeRelativePath("", InfoPath);
-  for (const auto &FilePath  : CDCtx.UserStylesheets) {
+  for (const auto &FilePath : CDCtx.UserStylesheets) {
     SmallString<128> StylesheetPath = RelativePath;
     llvm::sys::path::append(StylesheetPath,
                             llvm::sys::path::filename(FilePath));
@@ -448,7 +439,7 @@ void setupTemplateValue(const ClangDocContext &CDCtx, Value &V, Info *I) {
     StylesheetArr.getAsArray()->emplace_back(StylesheetPath);
   }
   V.getAsObject()->insert({"Stylesheets", StylesheetArr});
-  
+
   Value ScriptArr = Array();
   for (auto Script : CDCtx.JsScripts) {
     SmallString<128> JsPath = RelativePath;
@@ -457,7 +448,6 @@ void setupTemplateValue(const ClangDocContext &CDCtx, Value &V, Info *I) {
   }
   V.getAsObject()->insert({"Scripts", ScriptArr});
 }
- 
 
 llvm::Error
 MustacheHTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
@@ -474,10 +464,10 @@ MustacheHTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS,
     setupTemplateValue(CDCtx, V, I);
     // Serialize the JSON value to the output stream in a readable format.
     llvm::outs() << "Visit: " << I->Name << "\n";
-    //llvm::outs() << llvm::formatv("{0:2}", V) << "\n";
+    // llvm::outs() << llvm::formatv("{0:2}", V) << "\n";
     llvm::outs() << RecordTemplate->render(V);
     break;
-  }  
+  }
   case InfoType::IT_enum:
     llvm::outs() << "IT_enum\n";
     break;
@@ -511,9 +501,8 @@ llvm::Error MustacheHTMLGenerator::createResources(ClangDocContext &CDCtx) {
 
 const char *MustacheHTMLGenerator::Format = "mhtml";
 
-
-static GeneratorRegistry::Add<MustacheHTMLGenerator> MHTML(MustacheHTMLGenerator::Format,
-                                                           "Generator for mustache HTML output.");
+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.
diff --git a/clang-tools-extra/clang-doc/Representation.h b/clang-tools-extra/clang-doc/Representation.h
index 84a647cbe8..f6dc323187 100644
--- a/clang-tools-extra/clang-doc/Representation.h
+++ b/clang-tools-extra/clang-doc/Representation.h
@@ -62,10 +62,10 @@ struct CommentInfo {
 
   SmallString<16>
       Kind; // Kind of comment (FullComment, ParagraphComment, TextComment,
-                             // InlineCommandComment, HTMLStartTagComment, HTMLEndTagComment,
-                             // BlockCommandComment, ParamCommandComment,
-                             // TParamCommandComment, VerbatimBlockComment,
-                             // VerbatimBlockLineComment, VerbatimLineComment).
+            // InlineCommandComment, HTMLStartTagComment, HTMLEndTagComment,
+            // BlockCommandComment, ParamCommandComment,
+            // TParamCommandComment, VerbatimBlockComment,
+            // VerbatimBlockLineComment, VerbatimLineComment).
   SmallString<64> Text;      // Text of the comment.
   SmallString<16> Name;      // Name of the comment (for Verbatim and HTML).
   SmallString<8> Direction;  // Parameter direction (for (T)ParamCommand).
@@ -73,7 +73,7 @@ struct CommentInfo {
   SmallString<16> CloseName; // Closing tag name (for VerbatimBlock).
   bool SelfClosing = false;  // Indicates if tag is self-closing (for HTML).
   bool Explicit = false; // Indicates if the direction of a param is explicit
-                             // (for (T)ParamCommand).
+                         // (for (T)ParamCommand).
   llvm::SmallVector<SmallString<16>, 4>
       AttrKeys; // List of attribute keys (for HTML).
   llvm::SmallVector<SmallString<16>, 4>
@@ -113,8 +113,7 @@ struct Reference {
   llvm::SmallString<16> getFileBaseName() const;
 
   SymbolID USR = SymbolID(); // Unique identifier for referenced decl
-  
-  
+
   // Name of type (possibly unresolved). Not including namespaces or template
   // parameters (so for a std::vector<int> this would be "vector"). See also
   // QualName.
@@ -153,9 +152,9 @@ struct ScopeChildren {
 
 // A base struct for TypeInfos
 struct TypeInfo {
-  
+
   TypeInfo() = default;
-  
+
   TypeInfo(const Reference &R) : Type(R) {}
 
   // Convenience constructor for when there is no symbol ID or info type
@@ -164,9 +163,9 @@ struct TypeInfo {
       : Type(SymbolID(), Name, InfoType::IT_default, Name, Path) {}
 
   bool operator==(const TypeInfo &Other) const { return Type == Other.Type; }
-  
+
   Reference Type; // Referenced type in this info.
-  
+
   bool IsTemplate = false;
   bool IsBuiltIn = false;
 };
@@ -215,7 +214,6 @@ struct FieldTypeInfo : public TypeInfo {
     return std::tie(Type, Name, DefaultValue) ==
            std::tie(Other.Type, Other.Name, Other.DefaultValue);
   }
-  
 
   SmallString<16> Name; // Name associated with this info.
 
@@ -245,14 +243,10 @@ struct MemberTypeInfo : public FieldTypeInfo {
 };
 
 struct Location {
-  Location(int StartLineNumber = 0, 
-           int EndLineNumber = 0,
-           StringRef Filename = StringRef(),
-           bool IsFileInRootDir = false)
-      : StartLineNumber(StartLineNumber),
-        EndLineNumber(EndLineNumber),
-        Filename(Filename),
-        IsFileInRootDir(IsFileInRootDir) {}
+  Location(int StartLineNumber = 0, int EndLineNumber = 0,
+           StringRef Filename = StringRef(), bool IsFileInRootDir = false)
+      : StartLineNumber(StartLineNumber), EndLineNumber(EndLineNumber),
+        Filename(Filename), IsFileInRootDir(IsFileInRootDir) {}
 
   bool operator==(const Location &Other) const {
     return std::tie(StartLineNumber, EndLineNumber, Filename) ==
@@ -371,7 +365,7 @@ struct FunctionInfo : public SymbolInfo {
   // Full qualified name of this function, including namespaces and template
   // specializations.
   SmallString<16> FullName;
-  
+
   // Function Prototype
   SmallString<256> ProtoType;
 
@@ -394,7 +388,7 @@ struct RecordInfo : public SymbolInfo {
   // Full qualified name of this record, including namespaces and template
   // specializations.
   SmallString<16> FullName;
-  
+
   // When present, this record is a template or specialization.
   std::optional<TemplateInfo> Template;
 
@@ -434,8 +428,8 @@ struct TypedefInfo : public SymbolInfo {
   // False means it's a C-style typedef:
   //   typedef std::vector<int> MyVector;
   bool IsUsing = false;
-  
-  std::vector<CommentInfo> Description; 
+
+  std::vector<CommentInfo> Description;
 };
 
 struct BaseRecordInfo : public RecordInfo {
@@ -473,9 +467,9 @@ struct EnumValueInfo {
   // Stores the user-supplied initialization expression for this enumeration
   // constant. This will be empty for implicit enumeration values.
   SmallString<16> ValueExpr;
-  
+
   /// Comment description of this field.
-  std::vector<CommentInfo> Description; 
+  std::vector<CommentInfo> Description;
 };
 
 // TODO: Expand to allow for documenting templating.
diff --git a/clang-tools-extra/clang-doc/Serialize.cpp b/clang-tools-extra/clang-doc/Serialize.cpp
index d4d1436646..c2ba7a3a16 100644
--- a/clang-tools-extra/clang-doc/Serialize.cpp
+++ b/clang-tools-extra/clang-doc/Serialize.cpp
@@ -8,10 +8,10 @@
 
 #include "Serialize.h"
 #include "BitcodeWriter.h"
+#include "clang/AST/Attr.h"
 #include "clang/AST/Comment.h"
 #include "clang/Index/USRGeneration.h"
 #include "clang/Lex/Lexer.h"
-#include "clang/AST/Attr.h"
 #include "llvm/ADT/Hashing.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/Support/SHA1.h"
@@ -33,10 +33,10 @@ populateParentNamespaces(llvm::SmallVector<Reference, 4> &Namespaces,
 
 static void populateMemberTypeInfo(MemberTypeInfo &I, const FieldDecl *D);
 
-void getTemplateParameters(const TemplateParameterList *TemplateParams, 
+void getTemplateParameters(const TemplateParameterList *TemplateParams,
                            llvm::raw_ostream &Stream) {
   Stream << "template <";
-  
+
   for (unsigned i = 0; i < TemplateParams->size(); ++i) {
     if (i > 0) {
       Stream << ", ";
@@ -53,13 +53,15 @@ void getTemplateParameters(const TemplateParameterList *TemplateParams,
         Stream << "...";
       }
       Stream << " " << TTP->getNameAsString();
-    } else if (const auto *NTTP = llvm::dyn_cast<NonTypeTemplateParmDecl>(Param)) {
+    } else if (const auto *NTTP =
+                   llvm::dyn_cast<NonTypeTemplateParmDecl>(Param)) {
       NTTP->getType().print(Stream, NTTP->getASTContext().getPrintingPolicy());
       if (NTTP->isParameterPack()) {
         Stream << "...";
       }
       Stream << " " << NTTP->getNameAsString();
-    } else if (const auto *TTPD = llvm::dyn_cast<TemplateTemplateParmDecl>(Param)) {
+    } else if (const auto *TTPD =
+                   llvm::dyn_cast<TemplateTemplateParmDecl>(Param)) {
       Stream << "template <";
       getTemplateParameters(TTPD->getTemplateParameters(), Stream);
       Stream << "> class " << TTPD->getNameAsString();
@@ -69,12 +71,12 @@ void getTemplateParameters(const TemplateParameterList *TemplateParams,
   Stream << "> ";
 }
 
-// Extract the full function prototype from a FunctionDecl including 
+// Extract the full function prototype from a FunctionDecl including
 // Full Decl
 llvm::SmallString<256> getFunctionPrototype(const FunctionDecl *FuncDecl) {
-  llvm::SmallString<256> Result; 
+  llvm::SmallString<256> Result;
   llvm::raw_svector_ostream Stream(Result);
-  const ASTContext& Ctx = FuncDecl->getASTContext();
+  const ASTContext &Ctx = FuncDecl->getASTContext();
   const auto *Method = llvm::dyn_cast<CXXMethodDecl>(FuncDecl);
   // If it's a templated function, handle the template parameters
   if (const auto *TmplDecl = FuncDecl->getDescribedTemplate()) {
@@ -82,8 +84,7 @@ llvm::SmallString<256> getFunctionPrototype(const FunctionDecl *FuncDecl) {
   }
   // If it's a virtual method
   if (Method) {
-    if (Method->isVirtual())
-    {
+    if (Method->isVirtual()) {
       Stream << "virtual ";
     }
   }
@@ -135,7 +136,7 @@ llvm::SmallString<256> getFunctionPrototype(const FunctionDecl *FuncDecl) {
       Stream << " final";
     if (Method->isConst())
       Stream << " const";
-    if (Method->isPureVirtual()) 
+    if (Method->isPureVirtual())
       Stream << " = 0";
   }
   return Result; // Convert SmallString to std::string for return
@@ -144,7 +145,7 @@ llvm::SmallString<256> getFunctionPrototype(const FunctionDecl *FuncDecl) {
 llvm::SmallString<16> getTypeDefDecl(const TypedefDecl *TypeDef) {
   llvm::SmallString<16> Result;
   llvm::raw_svector_ostream Stream(Result);
-  const ASTContext& Ctx = TypeDef->getASTContext();
+  const ASTContext &Ctx = TypeDef->getASTContext();
   Stream << "typedef ";
   QualType Q = TypeDef->getUnderlyingType();
   Q.print(Stream, Ctx.getPrintingPolicy());
@@ -155,16 +156,14 @@ llvm::SmallString<16> getTypeDefDecl(const TypedefDecl *TypeDef) {
 llvm::SmallString<16> getTypeAlias(const TypeAliasDecl *Alias) {
   llvm::SmallString<16> Result;
   llvm::raw_svector_ostream Stream(Result);
-  const ASTContext& Ctx = Alias->getASTContext();
+  const ASTContext &Ctx = Alias->getASTContext();
   if (const auto *TmplDecl = Alias->getDescribedTemplate()) {
     getTemplateParameters(TmplDecl->getTemplateParameters(), Stream);
   }
-  Stream << "using " 
-         << Alias->getNameAsString() 
-         << " = ";
+  Stream << "using " << Alias->getNameAsString() << " = ";
   QualType Q = Alias->getUnderlyingType();
   Q.print(Stream, Ctx.getPrintingPolicy());
-  
+
   return Result;
 }
 
@@ -181,7 +180,8 @@ llvm::SmallString<16> getRecordPrototype(const CXXRecordDecl *CXXRD) {
     OS << "template <";
     bool FirstParam = true;
     for (const auto *Param : *TD->getTemplateParameters()) {
-      if (!FirstParam) OS << ", ";
+      if (!FirstParam)
+        OS << ", ";
       Param->print(OS, Policy);
       FirstParam = false;
     }
@@ -199,8 +199,10 @@ llvm::SmallString<16> getRecordPrototype(const CXXRecordDecl *CXXRD) {
     OS << " : ";
     bool FirstBase = true;
     for (const auto &Base : CXXRD->bases()) {
-      if (!FirstBase) OS << ", ";
-      if (Base.isVirtual()) OS << "virtual ";
+      if (!FirstBase)
+        OS << ", ";
+      if (Base.isVirtual())
+        OS << "virtual ";
       OS << getAccessSpelling(Base.getAccessSpecifier()) << " ";
       OS << Base.getType().getAsString(Policy);
       FirstBase = false;
@@ -209,7 +211,6 @@ llvm::SmallString<16> getRecordPrototype(const CXXRecordDecl *CXXRD) {
   return Result;
 }
 
-
 // A function to extract the appropriate relative path for a given info's
 // documentation. The path returned is a composite of the parent namespaces.
 //
@@ -406,7 +407,8 @@ static QualType getBaseQualType(const QualType &T) {
   QualType QT = T;
   // Get the base type of the QualType
   // eg. int* -> int, int& -> int, const int -> int
-  bool Modified = true;  // Track whether we've modified `qt` in this loop iteration
+  bool Modified =
+      true; // Track whether we've modified `qt` in this loop iteration
   while (Modified) {
     Modified = false;
     // If it's a reference type, strip the reference
@@ -418,8 +420,8 @@ static QualType getBaseQualType(const QualType &T) {
     else if (QT->isPointerType()) {
       QT = QT->getPointeeType();
       Modified = true;
-    }
-    else if (const auto *ElaboratedType = QT->getAs<clang::ElaboratedType>()) {
+    } else if (const auto *ElaboratedType =
+                   QT->getAs<clang::ElaboratedType>()) {
       QT = ElaboratedType->desugar();
       Modified = true;
     }
@@ -427,12 +429,11 @@ static QualType getBaseQualType(const QualType &T) {
     else if (QT.hasQualifiers()) {
       QT = QT.getUnqualifiedType();
       Modified = true;
-    }
-    else if (const auto *TypedefType = QT->getAs<clang::TypedefType>()) {
+    } else if (const auto *TypedefType = QT->getAs<clang::TypedefType>()) {
       return QT;
     }
   }
-  
+
   return QT;
 }
 
@@ -458,7 +459,7 @@ TypeInfo getTypeInfoForType(const QualType &T) {
     IT = InfoType::IT_record;
   else
     IT = InfoType::IT_default;
-  
+
   Reference R = Reference(getUSRForDecl(TD), TD->getNameAsString(), IT,
                           T.getAsString(), getInfoRelativePath(TD));
   TypeInfo TI = TypeInfo(R);
@@ -471,8 +472,7 @@ static bool isPublic(const clang::AccessSpecifier AS,
                      const clang::Linkage Link) {
   if (AS == clang::AccessSpecifier::AS_private)
     return false;
-  if ((Link == clang::Linkage::Module) ||
-      (Link == clang::Linkage::External))
+  if ((Link == clang::Linkage::Module) || (Link == clang::Linkage::External))
     return true;
   return false; // otherwise, linkage is some form of internal linkage
 }
@@ -638,7 +638,7 @@ static void parseBases(RecordInfo &I, const CXXRecordDecl *D) {
   // Don't parse bases if this isn't a definition.
   if (!D->isThisDeclarationADefinition())
     return;
-  
+
   for (const CXXBaseSpecifier &B : D->bases()) {
     if (B.isVirtual())
       continue;
@@ -739,8 +739,7 @@ static void populateInfo(Info &I, const T *D, const FullComment *C,
 
 template <typename T>
 static void populateSymbolInfo(SymbolInfo &I, const T *D, const FullComment *C,
-                               Location Loc,
-                               bool &IsInAnonymousNamespace) {
+                               Location Loc, bool &IsInAnonymousNamespace) {
   populateInfo(I, D, C, IsInAnonymousNamespace);
   if (D->isThisDeclarationADefinition())
     I.DefLoc = Loc;
@@ -749,8 +748,7 @@ static void populateSymbolInfo(SymbolInfo &I, const T *D, const FullComment *C,
 }
 
 static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D,
-                                 const FullComment *FC, 
-                                 Location Loc,
+                                 const FullComment *FC, Location Loc,
                                  bool &IsInAnonymousNamespace) {
   populateSymbolInfo(I, D, FC, Loc, IsInAnonymousNamespace);
   I.ReturnType = getTypeInfoForType(D->getReturnType());
@@ -851,7 +849,7 @@ parseBases(RecordInfo &I, const CXXRecordDecl *D, bool IsFileInRootDir,
 }
 
 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
-emitInfo(const NamespaceDecl *D, const FullComment *FC, Location Loc, 
+emitInfo(const NamespaceDecl *D, const FullComment *FC, Location Loc,
          bool PublicOnly) {
   auto I = std::make_unique<NamespaceInfo>();
   bool IsInAnonymousNamespace = false;
@@ -872,14 +870,14 @@ emitInfo(const NamespaceDecl *D, const FullComment *FC, Location Loc,
 }
 
 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
-emitInfo(const RecordDecl *D, const FullComment *FC, 
-         Location Loc, bool PublicOnly) {
+emitInfo(const RecordDecl *D, const FullComment *FC, Location Loc,
+         bool PublicOnly) {
   auto I = std::make_unique<RecordInfo>();
   bool IsInAnonymousNamespace = false;
   populateSymbolInfo(*I, D, FC, Loc, IsInAnonymousNamespace);
   if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
     return {};
-  
+
   I->TagType = D->getTagKind();
   parseFields(*I, D, PublicOnly);
   if (const auto *C = dyn_cast<CXXRecordDecl>(D)) {
@@ -940,8 +938,8 @@ emitInfo(const RecordDecl *D, const FullComment *FC,
 }
 
 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
-emitInfo(const FunctionDecl *D, const FullComment *FC,
-         Location Loc, bool PublicOnly) {
+emitInfo(const FunctionDecl *D, const FullComment *FC, Location Loc,
+         bool PublicOnly) {
   FunctionInfo Func;
   bool IsInAnonymousNamespace = false;
   populateFunctionInfo(Func, D, FC, Loc, IsInAnonymousNamespace);
@@ -954,8 +952,8 @@ emitInfo(const FunctionDecl *D, const FullComment *FC,
 }
 
 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
-emitInfo(const CXXMethodDecl *D, const FullComment *FC,
-         Location Loc, bool PublicOnly) {
+emitInfo(const CXXMethodDecl *D, const FullComment *FC, Location Loc,
+         bool PublicOnly) {
   FunctionInfo Func;
   bool IsInAnonymousNamespace = false;
   populateFunctionInfo(Func, D, FC, Loc, IsInAnonymousNamespace);
@@ -982,21 +980,21 @@ emitInfo(const CXXMethodDecl *D, const FullComment *FC,
 }
 
 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
-emitInfo(const TypedefDecl *D, const FullComment *FC, Location Loc, 
+emitInfo(const TypedefDecl *D, const FullComment *FC, Location Loc,
          bool PublicOnly) {
-  
+
   TypedefInfo Info;
-  ASTContext& Context = D->getASTContext();
+  ASTContext &Context = D->getASTContext();
   bool IsInAnonymousNamespace = false;
   populateInfo(Info, D, FC, IsInAnonymousNamespace);
-  
+
   if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
     return {};
-  
+
   Info.DefLoc = Loc;
   Info.Underlying = getTypeInfoForType(D->getUnderlyingType());
   Info.TypeDeclaration = getTypeDefDecl(D);
-  
+
   if (Info.Underlying.Type.Name.empty()) {
     // Typedef for an unnamed type. This is like "typedef struct { } Foo;"
     // The record serializer explicitly checks for this syntax and constructs
@@ -1018,10 +1016,10 @@ emitInfo(const TypedefDecl *D, const FullComment *FC, Location Loc,
 // A type alias is a C++ "using" declaration for a type. It gets mapped to a
 // TypedefInfo with the IsUsing flag set.
 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
-emitInfo(const TypeAliasDecl *D, const FullComment *FC, 
-         Location Loc, bool PublicOnly) {
+emitInfo(const TypeAliasDecl *D, const FullComment *FC, Location Loc,
+         bool PublicOnly) {
   TypedefInfo Info;
-  ASTContext& Context = D->getASTContext();
+  ASTContext &Context = D->getASTContext();
   bool IsInAnonymousNamespace = false;
   populateInfo(Info, D, FC, IsInAnonymousNamespace);
   if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
@@ -1031,7 +1029,7 @@ emitInfo(const TypeAliasDecl *D, const FullComment *FC,
   Info.Underlying = getTypeInfoForType(D->getUnderlyingType());
   Info.TypeDeclaration = getTypeAlias(D);
   Info.IsUsing = true;
-  
+
   if (RawComment *Comment = D->getASTContext().getRawCommentForDeclNoCache(D)) {
     Comment->setAttached();
     if (comments::FullComment *Fc = Comment->parse(Context, nullptr, D)) {
@@ -1044,12 +1042,12 @@ emitInfo(const TypeAliasDecl *D, const FullComment *FC,
 }
 
 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
-emitInfo(const EnumDecl *D, const FullComment *FC, Location Loc, 
+emitInfo(const EnumDecl *D, const FullComment *FC, Location Loc,
          bool PublicOnly) {
   EnumInfo Enum;
   bool IsInAnonymousNamespace = false;
   populateSymbolInfo(Enum, D, FC, Loc, IsInAnonymousNamespace);
-  
+
   if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
     return {};
 
diff --git a/clang-tools-extra/clang-doc/Serialize.h b/clang-tools-extra/clang-doc/Serialize.h
index 8874299e9a..bdf969aa56 100644
--- a/clang-tools-extra/clang-doc/Serialize.h
+++ b/clang-tools-extra/clang-doc/Serialize.h
@@ -37,31 +37,31 @@ namespace serialize {
 // its parent scope. For NamespaceDecl and RecordDecl both elements are not
 // nullptr.
 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
-emitInfo(const NamespaceDecl *D, const FullComment *FC, Location Loc, 
+emitInfo(const NamespaceDecl *D, const FullComment *FC, Location Loc,
          bool PublicOnly);
 
 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
-emitInfo(const RecordDecl *D, const FullComment *FC, Location Loc, 
+emitInfo(const RecordDecl *D, const FullComment *FC, Location Loc,
          bool PublicOnly);
 
 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
-emitInfo(const EnumDecl *D, const FullComment *FC, Location Loc, 
+emitInfo(const EnumDecl *D, const FullComment *FC, Location Loc,
          bool PublicOnly);
 
 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
-emitInfo(const FunctionDecl *D, const FullComment *FC, Location Loc, 
+emitInfo(const FunctionDecl *D, const FullComment *FC, Location Loc,
          bool PublicOnly);
 
 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
-emitInfo(const CXXMethodDecl *D, const FullComment *FC, Location Loc, 
+emitInfo(const CXXMethodDecl *D, const FullComment *FC, Location Loc,
          bool PublicOnly);
 
 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
-emitInfo(const TypedefDecl *D, const FullComment *FC, Location Loc, 
+emitInfo(const TypedefDecl *D, const FullComment *FC, Location Loc,
          bool PublicOnly);
 
 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
-emitInfo(const TypeAliasDecl *D, const FullComment *FC, Location Loc, 
+emitInfo(const TypeAliasDecl *D, const FullComment *FC, Location Loc,
          bool PublicOnly);
 
 // Function to hash a given USR value for storage.
diff --git a/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp b/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
index 0bde27eb2a..688d856d7c 100644
--- a/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
+++ b/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp
@@ -99,12 +99,7 @@ URL of repository that hosts code.
 Used for links to definition locations.)"),
                   llvm::cl::cat(ClangDocCategory));
 
-enum OutputFormatTy {
-  md,
-  yaml,
-  html,
-  mhtml
-};
+enum OutputFormatTy { md, yaml, html, mhtml };
 
 static llvm::cl::opt<OutputFormatTy>
     FormatEnum("format", llvm::cl::desc("Format for outputted docs."),
@@ -163,15 +158,14 @@ llvm::Error getAssetFiles(clang::doc::ClangDocContext &CDCtx) {
   return llvm::Error::success();
 }
 
-llvm::SmallString<128> appendPathNative(llvm::SmallString<128> Path, 
-                                    llvm::StringRef Asset) {
+llvm::SmallString<128> appendPathNative(llvm::SmallString<128> Path,
+                                        llvm::StringRef Asset) {
   llvm::SmallString<128> Default;
   llvm::sys::path::native(Path, Default);
   llvm::sys::path::append(Default, Asset);
   return Default;
 }
 
-
 llvm::Error getDefaultAssetFiles(const char *Argv0,
                                  clang::doc::ClangDocContext &CDCtx) {
   void *MainAddr = (void *)(intptr_t)getExecutablePath;
@@ -184,8 +178,7 @@ llvm::Error getDefaultAssetFiles(const char *Argv0,
   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");
+  llvm::SmallString<128> IndexJS = appendPathNative(AssetsPath, "index.js");
 
   if (!llvm::sys::fs::is_regular_file(IndexJS))
     return llvm::createStringError(llvm::inconvertibleErrorCode(),
@@ -216,7 +209,6 @@ llvm::Error getHtmlAssetFiles(const char *Argv0,
   return getDefaultAssetFiles(Argv0, CDCtx);
 }
 
-
 llvm::Error getMustacheHtmlFiles(const char *Argv0,
                                  clang::doc::ClangDocContext &CDCtx) {
   if (!UserAssetPath.empty() &&
@@ -225,45 +217,43 @@ llvm::Error getMustacheHtmlFiles(const char *Argv0,
                  << " falling back to default\n";
   if (llvm::sys::fs::is_directory(std::string(UserAssetPath)))
     return getAssetFiles(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-mustache.css");
-  llvm::SmallString<128> NamespaceTemplate 
-      = appendPathNative(AssetsPath, "namespace-template.mustache");
-  llvm::SmallString<128> ClassTemplate
-      = appendPathNative(AssetsPath, "class-template.mustache");
-  llvm::SmallString<128> EnumTemplate
-      = appendPathNative(AssetsPath, "enum-template.mustache");
-  llvm::SmallString<128> FunctionTemplate
-      = appendPathNative(AssetsPath, "function-template.mustache");
-  llvm::SmallString<128> CommentTemplate
-      = appendPathNative(AssetsPath, "comments-template.mustache");
-  llvm::SmallString<128> IndexJS
-      = appendPathNative(AssetsPath, "mustache-index.js");
-  
+
+  llvm::SmallString<128> DefaultStylesheet =
+      appendPathNative(AssetsPath, "clang-doc-mustache.css");
+  llvm::SmallString<128> NamespaceTemplate =
+      appendPathNative(AssetsPath, "namespace-template.mustache");
+  llvm::SmallString<128> ClassTemplate =
+      appendPathNative(AssetsPath, "class-template.mustache");
+  llvm::SmallString<128> EnumTemplate =
+      appendPathNative(AssetsPath, "enum-template.mustache");
+  llvm::SmallString<128> FunctionTemplate =
+      appendPathNative(AssetsPath, "function-template.mustache");
+  llvm::SmallString<128> CommentTemplate =
+      appendPathNative(AssetsPath, "comments-template.mustache");
+  llvm::SmallString<128> IndexJS =
+      appendPathNative(AssetsPath, "mustache-index.js");
+
   CDCtx.JsScripts.insert(CDCtx.JsScripts.begin(), IndexJS.c_str());
   CDCtx.UserStylesheets.insert(CDCtx.UserStylesheets.begin(),
                                std::string(DefaultStylesheet));
-  CDCtx.MustacheTemplates.insert({"namespace-template", 
-                                  NamespaceTemplate.c_str()});
-  CDCtx.MustacheTemplates.insert({"class-template",
-                                  ClassTemplate.c_str()});
-  CDCtx.MustacheTemplates.insert({"enum-template",
-                                  EnumTemplate.c_str()});
-  CDCtx.MustacheTemplates.insert({"function-template",
-                                  FunctionTemplate.c_str()});
-  CDCtx.MustacheTemplates.insert({"comments-template", 
-                                  CommentTemplate.c_str()});
-  
+  CDCtx.MustacheTemplates.insert(
+      {"namespace-template", NamespaceTemplate.c_str()});
+  CDCtx.MustacheTemplates.insert({"class-template", ClassTemplate.c_str()});
+  CDCtx.MustacheTemplates.insert({"enum-template", EnumTemplate.c_str()});
+  CDCtx.MustacheTemplates.insert(
+      {"function-template", FunctionTemplate.c_str()});
+  CDCtx.MustacheTemplates.insert(
+      {"comments-template", CommentTemplate.c_str()});
+
   return llvm::Error::success();
 }
 
@@ -339,7 +329,7 @@ Example usage for a project using a compile commands database:
       return 1;
     }
   }
-  
+
   if (Format == "mhtml") {
     if (auto Err = getMustacheHtmlFiles(argv[0], CDCtx)) {
       llvm::errs() << toString(std::move(Err)) << "\n";

@PeterChou1 PeterChou1 changed the title Clang doc mustache rebase [clang-doc] Adds a mustache backend Mar 27, 2025
Copy link
Contributor

@ilovepi ilovepi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know you're planing to split this up, but here's some preliminary feedback.

Comment on lines +22 to +24
std::error_code OK;
std::error_code FileErr = llvm::sys::fs::copy_file(PathRead, PathWrite);
if (FileErr != OK) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
std::error_code OK;
std::error_code FileErr = llvm::sys::fs::copy_file(PathRead, PathWrite);
if (FileErr != OK) {
std::error_code FileErr = llvm::sys::fs::copy_file(PathRead, PathWrite);
if (FileErr) {

Comment on lines +34 to +35
llvm::SmallString<128> computeRelativePath(llvm::StringRef Destination,
llvm::StringRef Origin) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should drop this in favor of std::filesystem::relative()?

@@ -0,0 +1,26 @@
//===-- FileHelpersClangDoc.h --- File Helpers -------------------*- C++-*-===//
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably putting this in clang-doc/support/File.h is a bit more typical. At the least the file shouldn't have helper in the name, and probably doesn't need ClangDoc in it either.

@@ -379,7 +394,7 @@ struct RecordInfo : public SymbolInfo {
// Full qualified name of this record, including namespaces and template
// specializations.
SmallString<16> FullName;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: empty space. the newline is fine though.

Comment on lines -415 to +432

// Inidicates if this is a new C++ "using"-style typedef:
// Underlying type declaration
SmallString<16> TypeDeclaration;
// Indicates if this is a new C++ "using"-style typedef:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use consistent spacing. If you find the file is already inconsistent, then lets make a PR to fix that first.

@@ -359,6 +371,9 @@ struct FunctionInfo : public SymbolInfo {
// Full qualified name of this function, including namespaces and template
// specializations.
SmallString<16> FullName;

// Function Prototype
SmallString<256> ProtoType;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why 256? you realize that allocates a 256 byte buffer in this struct, right? Do we expect to use many of them? Do you have a feeling for the typical size of the Prototype? like what's the median size in say LLVM? what about 90th percentile? I have a feeling there is a better default that won't use so much space.

Also, I have a felling the layout will be kind of odd right now. You can try adding -Wpadding to the clang-doc build to see if there's a better layout for these internal types.

Comment on lines -458 to +478

std::vector<CommentInfo> Description; /// Comment description of this field.

/// Comment description of this field.
std::vector<CommentInfo> Description;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets try to keep cleanups like this in their own PRs. The same goes for any other changes that can be done independently of adding Mustache support.

Comment on lines +84 to +89
if (Method) {
if (Method->isVirtual())
{
Stream << "virtual ";
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (Method) {
if (Method->isVirtual())
{
Stream << "virtual ";
}
}
if (Method && Method->isVirtual()){
Stream << "virtual ";
}

Comment on lines +112 to +116
const Expr *DefaultArg = ParamDecl->getDefaultArg();
if (DefaultArg) {
Stream << " = ";
DefaultArg->printPretty(Stream, nullptr, Ctx.getPrintingPolicy());
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DefaultArg only gets used in the conditional. you can use

if(const Expr* DefaultArg = ...){ ... }


// Extract the full function prototype from a FunctionDecl including
// Full Decl
llvm::SmallString<256> getFunctionPrototype(const FunctionDecl *FuncDecl) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How much does this output differ from PrintName() or getNameForDiagnostic()? I'm wondering if we need a custom thing here since we have the FunctionDecl.

https://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html#af40656355e6d13ca9d7de07340b1b46c

Copy link
Contributor

@ilovepi ilovepi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having very repetitive code is a pervasive problem throughout clang-doc, but I still feel like there's quite a lot in the generator code.

I'm also wondering if its the best idea to generate for each info serially. I don't want to try and change that right now, but in general, is it possible to use a thread pool to get some parallelism as we're processing each Info? or is that fundamentally incompatible with what we're doing?

setupTemplateValue(CDCtx, V, I);
// Serialize the JSON value to the output stream in a readable format.
llvm::outs() << "Visit: " << I->Name << "\n";
//llvm::outs() << llvm::formatv("{0:2}", V) << "\n";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Debugging leftover?

Value V = extractValue(*static_cast<clang::doc::RecordInfo *>(I), CDCtx);
setupTemplateValue(CDCtx, V, I);
// Serialize the JSON value to the output stream in a readable format.
llvm::outs() << "Visit: " << I->Name << "\n";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Won't this be pretty verbose? Should this be wrapped in LLVM_DEBUG or something instead?

// Serialize the JSON value to the output stream in a readable format.
llvm::outs() << "Visit: " << I->Name << "\n";
//llvm::outs() << llvm::formatv("{0:2}", V) << "\n";
llvm::outs() << RecordTemplate->render(V);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be OS instead of llvm::outs()? Not sure why we'd want to render the template to standard output...

else if (Access == AccessSpecifier::AS_protected)
ProtectedFunction.getAsArray()->emplace_back(F);
else
ArrFunction.getAsArray()->emplace_back(F);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see you using ArrFunction.getAsArray() a lot. We should probably cache a reference to it.

return Obj;
}

Value extractValue(const EnumInfo &I, const ClangDocContext &CDCtx) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is an llvm::json::Value then lets keep at least the json:: prefix. Value is a very overloaded term in LLVM.

Comment on lines +294 to +298
if (CDCtx.RepositoryUrl.has_value())
Obj.insert({"Location", extractValue(L,
StringRef{*CDCtx.RepositoryUrl})});
else
Obj.insert({"Location", extractValue(L)});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably a bit nicer to use .value_or(), right?

Comment on lines +247 to +251
if (CDCtx.RepositoryUrl.has_value())
Obj.insert({"Location", extractValue(L,
StringRef{*CDCtx.RepositoryUrl})});
else
Obj.insert({"Location", extractValue(L)});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

value_or()

ilovepi added a commit that referenced this pull request May 7, 2025
Originally part of #133161. This patch adds preliminary tracking
for of TypeInfo, by tracking if the type is a builtin or template.

The new functionality is not yet exercised.

Co-authored-by: Peter Chou <[email protected]>
GeorgeARM pushed a commit to GeorgeARM/llvm-project that referenced this pull request May 7, 2025
…8058)

Split from llvm#133161. This patch allows Typedefs to now track both their
declarations and full descriptions. Subsequent patches will leverage the
additional fields in the representation.

Co-authored-by: Peter Chou <[email protected]>
GeorgeARM pushed a commit to GeorgeARM/llvm-project that referenced this pull request May 7, 2025
This patch adds the various assets used with the HTML Mustache backend.
This includes templates for a variety of different language constructs,
as well as the CSS. Split from llvm#133161.

Co-authored-by: Peter Chou <[email protected]>
ilovepi added a commit that referenced this pull request May 7, 2025
Originally part of #133161. This patch adds preliminary tracking
for of TypeInfo, by tracking if the type is a builtin or template.

The new functionality is not yet exercised.

Co-authored-by: Peter Chou <[email protected]>
ilovepi added a commit that referenced this pull request May 7, 2025
Originally part of #133161. This patch adds preliminary tracking
for of TypeInfo, by tracking if the type is a builtin or template.

The new functionality is not yet exercised.

Co-authored-by: Peter Chou <[email protected]>
ilovepi added a commit that referenced this pull request May 9, 2025
Originally part of #133161. This patch adds preliminary tracking
for of TypeInfo, by tracking if the type is a builtin or template.

The new functionality is not yet exercised.

Co-authored-by: Peter Chou <[email protected]>
ilovepi added a commit that referenced this pull request May 10, 2025
Originally part of #133161. This patch adds preliminary tracking
for of TypeInfo, by tracking if the type is a builtin or template.

The new functionality is not yet exercised.

Co-authored-by: Peter Chou <[email protected]>
ilovepi added a commit that referenced this pull request May 12, 2025
Originally part of #133161. This patch adds preliminary tracking
for of TypeInfo, by tracking if the type is a builtin or template.

The new functionality is not yet exercised.

Co-authored-by: Peter Chou <[email protected]>
ilovepi added a commit that referenced this pull request May 13, 2025
Split from #133161. This patch adds HTMLMustacheGenerator.cpp, and
the most basic class defintion for the generator. Future patches will
add functionality.

Co-authored-by: Peter Chou <[email protected]>
ilovepi added a commit that referenced this pull request May 13, 2025
Split from #133161. This patch fills in the implementation for a number
of the MustacheHTMLGenerator methods. Many of these APIs are just
stubbed out, and will have their implementation filled in by later
patches.

Co-authored-by: Peter Chou <[email protected]>
ilovepi added a commit that referenced this pull request May 13, 2025
This patch adds or fills in some helper functions related to template
setup when initializing the mustache backend. It was split from #133161.

Co-authored-by: Peter Chou <[email protected]>
ilovepi added a commit that referenced this pull request May 13, 2025
Split from #133161. This patch provides the implementation of a number
of extractValue overloads used with the different types of Info.

The new helper functions extract the relevant information from the
different *Infos and inserts them into the correct fields of the JSON
values that will be used with the specific Mustache templates, which
will land separately.

Co-authored-by: Peter Chou <[email protected]>
ilovepi added a commit that referenced this pull request May 13, 2025
This patch implements the business logic for setupTemplateValue, which
was split from #133161. The implementation configures the relative path
relationships between the various HTML components, and prepares them
prior to their use in the generator.

Co-authored-by: Peter Chou <[email protected]>
ilovepi added a commit that referenced this pull request May 13, 2025
This patch updates Serialize.cpp to serialize more data about C++
templates, which are supported by the new mustache HTML template.
Split from #133161.

Co-authored-by: Peter Chou <[email protected]>
ilovepi added a commit that referenced this pull request May 13, 2025
This patch adds a command line option and enables the Mustache template
HTML backend. This allows users to use the new, more flexible templates
over the old and cumbersome HTML output. Split from #133161.

Co-authored-by: Peter Chou <[email protected]>
ilovepi added a commit that referenced this pull request May 13, 2025
Originally part of #133161. This patch adds preliminary tracking
for of TypeInfo, by tracking if the type is a builtin or template.

The new functionality is not yet exercised.

Co-authored-by: Peter Chou <[email protected]>
ilovepi added a commit that referenced this pull request May 13, 2025
Originally part of #133161. This patch adds preliminary tracking
for of TypeInfo, by tracking if the type is a builtin or template.

The new functionality is not yet exercised.

Co-authored-by: Peter Chou <[email protected]>
ilovepi added a commit that referenced this pull request May 13, 2025
Originally part of #133161. This patch adds preliminary tracking
for of TypeInfo, by tracking if the type is a builtin or template.

The new functionality is not yet exercised.

Co-authored-by: Peter Chou <[email protected]>
ilovepi added a commit that referenced this pull request May 16, 2025
Originally part of #133161. This patch adds preliminary tracking
for of TypeInfo, by tracking if the type is a builtin or template.

The new functionality is not yet exercised.

Co-authored-by: Peter Chou <[email protected]>
ilovepi added a commit that referenced this pull request May 17, 2025
Originally part of #133161. This patch adds preliminary tracking
for of TypeInfo, by tracking if the type is a builtin or template.

The new functionality is not yet exercised.

Co-authored-by: Peter Chou <[email protected]>
ilovepi added a commit that referenced this pull request May 17, 2025
Split from #133161. This patch fills in the implementation for a number
of the MustacheHTMLGenerator methods. Many of these APIs are just
stubbed out, and will have their implementation filled in by later
patches.

Co-authored-by: Peter Chou <[email protected]>
ilovepi added a commit that referenced this pull request May 17, 2025
This patch adds or fills in some helper functions related to template
setup when initializing the mustache backend. It was split from #133161.

Co-authored-by: Peter Chou <[email protected]>
ilovepi added a commit that referenced this pull request May 17, 2025
Split from #133161. This patch provides the implementation of a number
of extractValue overloads used with the different types of Info.

The new helper functions extract the relevant information from the
different *Infos and inserts them into the correct fields of the JSON
values that will be used with the specific Mustache templates, which
will land separately.

Co-authored-by: Peter Chou <[email protected]>
ilovepi added a commit that referenced this pull request May 17, 2025
This patch implements the business logic for setupTemplateValue, which
was split from #133161. The implementation configures the relative path
relationships between the various HTML components, and prepares them
prior to their use in the generator.

Co-authored-by: Peter Chou <[email protected]>
ilovepi added a commit that referenced this pull request May 17, 2025
This patch updates Serialize.cpp to serialize more data about C++
templates, which are supported by the new mustache HTML template.
Split from #133161.

Co-authored-by: Peter Chou <[email protected]>
ilovepi added a commit that referenced this pull request May 17, 2025
This patch adds a command line option and enables the Mustache template
HTML backend. This allows users to use the new, more flexible templates
over the old and cumbersome HTML output. Split from #133161.

Co-authored-by: Peter Chou <[email protected]>
ilovepi added a commit that referenced this pull request May 17, 2025
Originally part of #133161. This patch adds preliminary tracking
for of TypeInfo, by tracking if the type is a builtin or template.

The new functionality is not yet exercised.

Co-authored-by: Peter Chou <[email protected]>
ilovepi added a commit that referenced this pull request May 17, 2025
Originally part of #133161. This patch adds preliminary tracking
for of TypeInfo, by tracking if the type is a builtin or template.

The new functionality is not yet exercised.

Co-authored-by: Peter Chou <[email protected]>
ilovepi added a commit that referenced this pull request May 20, 2025
Originally part of #133161. This patch adds preliminary tracking
for of TypeInfo, by tracking if the type is a builtin or template.

The new functionality is not yet exercised.

Co-authored-by: Peter Chou <[email protected]>
ilovepi added a commit that referenced this pull request May 20, 2025
Originally part of #133161. This patch adds preliminary tracking
for of TypeInfo, by tracking if the type is a builtin or template.

The new functionality is not yet exercised.

Co-authored-by: Peter Chou <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants