https://github.com/evelez7 created 
https://github.com/llvm/llvm-project/pull/149588

None

>From 25f5252a6316a166a2b1e84dd385386638fe3ba1 Mon Sep 17 00:00:00 2001
From: Erick Velez <erickvel...@gmail.com>
Date: Fri, 18 Jul 2025 13:58:14 -0700
Subject: [PATCH] [clang-doc] refactor JSON for better Mustache compatibility

---
 clang-tools-extra/clang-doc/BitcodeReader.cpp |  2 +
 clang-tools-extra/clang-doc/BitcodeWriter.cpp |  4 +-
 clang-tools-extra/clang-doc/BitcodeWriter.h   |  1 +
 clang-tools-extra/clang-doc/JSONGenerator.cpp | 59 +++++++++++++++----
 .../clang-doc/Representation.cpp              |  2 +
 clang-tools-extra/clang-doc/Representation.h  | 10 ++++
 clang-tools-extra/clang-doc/Serialize.cpp     |  8 ++-
 .../test/clang-doc/json/class-requires.cpp    |  1 +
 .../test/clang-doc/json/class-template.cpp    |  1 +
 .../test/clang-doc/json/class.cpp             | 18 ++++++
 .../clang-doc/json/compound-constraints.cpp   |  4 ++
 .../test/clang-doc/json/concept.cpp           |  2 +
 .../test/clang-doc/json/function-requires.cpp |  7 +++
 .../test/clang-doc/json/method-template.cpp   |  2 +
 .../test/clang-doc/json/namespace.cpp         | 17 ++++++
 .../test/clang-doc/json/nested-namespace.cpp  |  4 ++
 .../unittests/clang-doc/JSONGeneratorTest.cpp | 25 ++++++++
 17 files changed, 154 insertions(+), 13 deletions(-)

diff --git a/clang-tools-extra/clang-doc/BitcodeReader.cpp 
b/clang-tools-extra/clang-doc/BitcodeReader.cpp
index dce34a8434ff8..4efbbd34730cf 100644
--- a/clang-tools-extra/clang-doc/BitcodeReader.cpp
+++ b/clang-tools-extra/clang-doc/BitcodeReader.cpp
@@ -384,6 +384,8 @@ static llvm::Error parseRecord(const Record &R, unsigned ID,
     return decodeRecord(R, I->Path, Blob);
   case REFERENCE_FIELD:
     return decodeRecord(R, F, Blob);
+  case REFERENCE_FILE:
+    return decodeRecord(R, I->DocumentationFileName, Blob);
   default:
     return llvm::createStringError(llvm::inconvertibleErrorCode(),
                                    "invalid field for Reference");
diff --git a/clang-tools-extra/clang-doc/BitcodeWriter.cpp 
b/clang-tools-extra/clang-doc/BitcodeWriter.cpp
index eed23726e17bf..e23511bf63690 100644
--- a/clang-tools-extra/clang-doc/BitcodeWriter.cpp
+++ b/clang-tools-extra/clang-doc/BitcodeWriter.cpp
@@ -210,6 +210,7 @@ static const llvm::IndexedMap<RecordIdDsc, 
RecordIdToIndexFunctor>
           {REFERENCE_TYPE, {"RefType", &genIntAbbrev}},
           {REFERENCE_PATH, {"Path", &genStringAbbrev}},
           {REFERENCE_FIELD, {"Field", &genIntAbbrev}},
+          {REFERENCE_FILE, {"File", &genStringAbbrev}},
           {TEMPLATE_PARAM_CONTENTS, {"Contents", &genStringAbbrev}},
           {TEMPLATE_SPECIALIZATION_OF,
            {"SpecializationOf", &genSymbolIdAbbrev}},
@@ -286,7 +287,7 @@ static const std::vector<std::pair<BlockId, 
std::vector<RecordId>>>
         // Reference Block
         {BI_REFERENCE_BLOCK_ID,
          {REFERENCE_USR, REFERENCE_NAME, REFERENCE_QUAL_NAME, REFERENCE_TYPE,
-          REFERENCE_PATH, REFERENCE_FIELD}},
+          REFERENCE_PATH, REFERENCE_FIELD, REFERENCE_FILE}},
         // Template Blocks.
         {BI_TEMPLATE_BLOCK_ID, {}},
         {BI_TEMPLATE_PARAM_BLOCK_ID, {TEMPLATE_PARAM_CONTENTS}},
@@ -479,6 +480,7 @@ void ClangDocBitcodeWriter::emitBlock(const Reference &R, 
FieldId Field) {
   emitRecord((unsigned)R.RefType, REFERENCE_TYPE);
   emitRecord(R.Path, REFERENCE_PATH);
   emitRecord((unsigned)Field, REFERENCE_FIELD);
+  emitRecord(R.DocumentationFileName, REFERENCE_FILE);
 }
 
 void ClangDocBitcodeWriter::emitBlock(const FriendInfo &R) {
diff --git a/clang-tools-extra/clang-doc/BitcodeWriter.h 
b/clang-tools-extra/clang-doc/BitcodeWriter.h
index 501af12582a8e..688f886b45308 100644
--- a/clang-tools-extra/clang-doc/BitcodeWriter.h
+++ b/clang-tools-extra/clang-doc/BitcodeWriter.h
@@ -140,6 +140,7 @@ enum RecordId {
   REFERENCE_TYPE,
   REFERENCE_PATH,
   REFERENCE_FIELD,
+  REFERENCE_FILE,
   TEMPLATE_PARAM_CONTENTS,
   TEMPLATE_SPECIALIZATION_OF,
   TYPEDEF_USR,
diff --git a/clang-tools-extra/clang-doc/JSONGenerator.cpp 
b/clang-tools-extra/clang-doc/JSONGenerator.cpp
index cc4c68346ec53..908e23d24d079 100644
--- a/clang-tools-extra/clang-doc/JSONGenerator.cpp
+++ b/clang-tools-extra/clang-doc/JSONGenerator.cpp
@@ -43,6 +43,30 @@ static auto SerializeReferenceLambda = [](const auto &Ref, 
Object &Object) {
   serializeReference(Ref, Object);
 };
 
+static std::string infoTypeToString(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 encountered.");
+}
+
 static json::Object
 serializeLocation(const Location &Loc,
                   const std::optional<StringRef> RepositoryUrl) {
@@ -172,6 +196,9 @@ serializeCommonAttributes(const Info &I, json::Object &Obj,
                           const std::optional<StringRef> RepositoryUrl) {
   Obj["Name"] = I.Name;
   Obj["USR"] = toHex(toStringRef(I.USR));
+  Obj["InfoType"] = infoTypeToString(I.IT);
+  if (!I.DocumentationFileName.empty())
+    Obj["DocumentationFileName"] = I.DocumentationFileName;
 
   if (!I.Path.empty())
     Obj["Path"] = I.Path;
@@ -205,6 +232,8 @@ static void serializeReference(const Reference &Ref, Object 
&ReferenceObj) {
   ReferenceObj["Name"] = Ref.Name;
   ReferenceObj["QualName"] = Ref.QualName;
   ReferenceObj["USR"] = toHex(toStringRef(Ref.USR));
+  if (!Ref.DocumentationFileName.empty())
+    ReferenceObj["DocumentationFileName"] = Ref.DocumentationFileName;
 }
 
 // Although namespaces and records both have ScopeChildren, they serialize them
@@ -217,14 +246,18 @@ serializeCommonChildren(const ScopeChildren &Children, 
json::Object &Obj,
     serializeInfo(Info, Object, RepositoryUrl);
   };
 
-  if (!Children.Enums.empty())
+  if (!Children.Enums.empty()) {
     serializeArray(Children.Enums, Obj, "Enums", SerializeInfo);
+    Obj["HasEnums"] = true;
+  }
 
   if (!Children.Typedefs.empty())
     serializeArray(Children.Typedefs, Obj, "Typedefs", SerializeInfo);
 
-  if (!Children.Records.empty())
+  if (!Children.Records.empty()) {
     serializeArray(Children.Records, Obj, "Records", SerializeReferenceLambda);
+    Obj["HasRecords"] = true;
+  }
 }
 
 template <typename Container, typename SerializationFunc>
@@ -234,10 +267,12 @@ static void serializeArray(const Container &Records, 
Object &Obj,
   json::Value RecordsArray = Array();
   auto &RecordsArrayRef = *RecordsArray.getAsArray();
   RecordsArrayRef.reserve(Records.size());
-  for (const auto &Item : Records) {
+  for (size_t Index = 0; Index < Records.size(); ++Index) {
     json::Value ItemVal = Object();
     auto &ItemObj = *ItemVal.getAsObject();
-    SerializeInfo(Item, ItemObj);
+    SerializeInfo(Records[Index], ItemObj);
+    if (Index == Records.size() - 1)
+      ItemObj["End"] = true;
     RecordsArrayRef.push_back(ItemVal);
   }
   Obj[Key] = RecordsArray;
@@ -405,8 +440,10 @@ static void serializeInfo(const RecordInfo &I, 
json::Object &Obj,
         ProtFunctionsArrayRef.push_back(FunctionVal);
     }
 
-    if (!PubFunctionsArrayRef.empty())
+    if (!PubFunctionsArrayRef.empty()) {
       Obj["PublicFunctions"] = PubFunctionsArray;
+      Obj["HasPublicFunctions"] = true;
+    }
     if (!ProtFunctionsArrayRef.empty())
       Obj["ProtectedFunctions"] = ProtFunctionsArray;
   }
@@ -429,8 +466,10 @@ static void serializeInfo(const RecordInfo &I, 
json::Object &Obj,
         ProtMembersArrayRef.push_back(MemberVal);
     }
 
-    if (!PubMembersArrayRef.empty())
+    if (!PubMembersArrayRef.empty()) {
       Obj["PublicMembers"] = PublicMembersArray;
+      Obj["HasPublicMembers"] = true;
+    }
     if (!ProtMembersArrayRef.empty())
       Obj["ProtectedMembers"] = ProtectedMembersArray;
   }
@@ -496,10 +535,7 @@ static SmallString<16> determineFileName(Info *I, 
SmallString<128> &Path) {
   SmallString<16> FileName;
   if (I->IT == InfoType::IT_record) {
     auto *RecordSymbolInfo = static_cast<SymbolInfo *>(I);
-    if (RecordSymbolInfo->MangledName.size() < 255)
-      FileName = RecordSymbolInfo->MangledName;
-    else
-      FileName = toStringRef(toHex(RecordSymbolInfo->USR));
+    FileName = RecordSymbolInfo->MangledName;
   } else if (I->IT == InfoType::IT_namespace && I->Name != "")
     // Serialize the global namespace as index.json
     FileName = I->Name;
@@ -527,7 +563,10 @@ Error JSONGenerator::generateDocs(
     }
 
     SmallString<16> FileName = determineFileName(Info, Path);
+    if (FileToInfos.contains(Path))
+      continue;
     FileToInfos[Path].push_back(Info);
+    Info->DocumentationFileName = FileName;
   }
 
   for (const auto &Group : FileToInfos) {
diff --git a/clang-tools-extra/clang-doc/Representation.cpp 
b/clang-tools-extra/clang-doc/Representation.cpp
index beaf314a04ae1..79850e1f90253 100644
--- a/clang-tools-extra/clang-doc/Representation.cpp
+++ b/clang-tools-extra/clang-doc/Representation.cpp
@@ -247,6 +247,8 @@ void Reference::merge(Reference &&Other) {
     Name = Other.Name;
   if (Path.empty())
     Path = Other.Path;
+  if (DocumentationFileName.empty())
+    DocumentationFileName = Other.DocumentationFileName;
 }
 
 bool FriendInfo::mergeable(const FriendInfo &Other) {
diff --git a/clang-tools-extra/clang-doc/Representation.h 
b/clang-tools-extra/clang-doc/Representation.h
index 23f0e90daa27f..2a75f89696b7d 100644
--- a/clang-tools-extra/clang-doc/Representation.h
+++ b/clang-tools-extra/clang-doc/Representation.h
@@ -121,6 +121,10 @@ struct Reference {
   Reference(SymbolID USR, StringRef Name, InfoType IT, StringRef QualName,
             StringRef Path = StringRef())
       : USR(USR), Name(Name), QualName(QualName), RefType(IT), Path(Path) {}
+  Reference(SymbolID USR, StringRef Name, InfoType IT, StringRef QualName,
+            StringRef Path, SmallString<16> DocumentationFileName)
+      : USR(USR), Name(Name), QualName(QualName), RefType(IT), Path(Path),
+        DocumentationFileName(DocumentationFileName) {}
 
   bool operator==(const Reference &Other) const {
     return std::tie(USR, Name, QualName, RefType) ==
@@ -155,6 +159,7 @@ struct Reference {
   // Path of directory where the clang-doc generated file will be saved
   // (possibly unresolved)
   llvm::SmallString<128> Path;
+  SmallString<16> DocumentationFileName;
 };
 
 // Holds the children of a record or namespace.
@@ -331,6 +336,11 @@ struct Info {
   llvm::SmallString<128> Path;          // Path of directory where the 
clang-doc
                                         // generated file will be saved
 
+  // The name used for the file that this info is documented in.
+  // In the JSON generator, infos are documented in files with mangled names.
+  // Thus, we keep track of the physical filename for linking purposes.
+  SmallString<16> DocumentationFileName;
+
   void mergeBase(Info &&I);
   bool mergeable(const Info &Other);
 
diff --git a/clang-tools-extra/clang-doc/Serialize.cpp 
b/clang-tools-extra/clang-doc/Serialize.cpp
index 7a0e00c6d9c2d..3e0e54bf53419 100644
--- a/clang-tools-extra/clang-doc/Serialize.cpp
+++ b/clang-tools-extra/clang-doc/Serialize.cpp
@@ -495,7 +495,8 @@ static void InsertChild(ScopeChildren &Scope, const 
NamespaceInfo &Info) {
 
 static void InsertChild(ScopeChildren &Scope, const RecordInfo &Info) {
   Scope.Records.emplace_back(Info.USR, Info.Name, InfoType::IT_record,
-                             Info.Name, getInfoRelativePath(Info.Namespace));
+                             Info.Name, getInfoRelativePath(Info.Namespace),
+                             Info.MangledName);
 }
 
 static void InsertChild(ScopeChildren &Scope, EnumInfo Info) {
@@ -777,7 +778,10 @@ static void populateSymbolInfo(SymbolInfo &I, const T *D, 
const FullComment *C,
     Mangler->mangleCXXVTable(CXXD, MangledStream);
   else
     MangledStream << D->getNameAsString();
-  I.MangledName = MangledName;
+  if (MangledName.size() > 255)
+    I.MangledName = llvm::toStringRef(llvm::toHex(I.USR));
+  else
+    I.MangledName = MangledName;
   delete Mangler;
 }
 
diff --git a/clang-tools-extra/test/clang-doc/json/class-requires.cpp 
b/clang-tools-extra/test/clang-doc/json/class-requires.cpp
index 213da93a1adfa..bf6c889849a70 100644
--- a/clang-tools-extra/test/clang-doc/json/class-requires.cpp
+++ b/clang-tools-extra/test/clang-doc/json/class-requires.cpp
@@ -20,6 +20,7 @@ struct MyClass;
 // CHECK-NEXT:  "Template": {
 // CHECK-NEXT:    "Constraints": [
 // CHECK-NEXT:      {
+// CHECK-NEXT:        "End": true,
 // CHECK-NEXT:        "Expression": "Addable<T>",
 // CHECK-NEXT:        "Name": "Addable",
 // CHECK-NEXT:        "Path": "",
diff --git a/clang-tools-extra/test/clang-doc/json/class-template.cpp 
b/clang-tools-extra/test/clang-doc/json/class-template.cpp
index 6cdc3e9175278..149248c772055 100644
--- a/clang-tools-extra/test/clang-doc/json/class-template.cpp
+++ b/clang-tools-extra/test/clang-doc/json/class-template.cpp
@@ -11,6 +11,7 @@ template<typename T> struct MyClass {
 // CHECK:         "Name": "method",
 // CHECK:         "Params": [
 // CHECK-NEXT:      {
+// CHECK-NEXT:        "End": true,
 // CHECK-NEXT:        "Name": "Param",
 // CHECK-NEXT:        "Type": "T"
 // CHECK-NEXT:      } 
diff --git a/clang-tools-extra/test/clang-doc/json/class.cpp 
b/clang-tools-extra/test/clang-doc/json/class.cpp
index d8317eafea91a..a36358982b019 100644
--- a/clang-tools-extra/test/clang-doc/json/class.cpp
+++ b/clang-tools-extra/test/clang-doc/json/class.cpp
@@ -60,8 +60,11 @@ struct MyClass {
 // CHECK-NEXT:                         "TextComment": " This is a brief 
description." 
 // CHECK-NEXT:                       }
 // CHECK:                   "Command": "brief"
+// CHECK:         "DocumentationFileName": "_ZTV7MyClass",
 // CHECK:         "Enums": [
 // CHECK-NEXT:      {
+// CHECK-NEXT:        "End": true,
+// CHECK-NEXT:        "InfoType": "enum",
 // CHECK-NEXT:        "Location": {
 // CHECK-NEXT:          "Filename": "{{.*}}class.cpp",
 // CHECK-NEXT:          "LineNumber": 17
@@ -76,6 +79,7 @@ struct MyClass {
 // CHECK-NEXT:            "Value": "1"
 // CHECK-NEXT:          },
 // CHECK-NEXT:          {
+// CHECK-NEXT:            "End": true,
 // CHECK-NEXT:            "Name": "BLUE",
 // CHECK-NEXT:            "ValueExpr": "5"
 // CHECK-NEXT:          }
@@ -94,6 +98,7 @@ struct MyClass {
 // CHECK-NEXT:        "IsClass": false,
 // CHECK-NEXT:        "Params": [
 // CHECK-NEXT:          {
+// CHECK-NEXT:            "End": true,
 // CHECK-NEXT:            "Name": "",
 // CHECK-NEXT:            "Type": "int"
 // CHECK-NEXT:          }
@@ -118,6 +123,7 @@ struct MyClass {
 // CHECK-NEXT:        }
 // CHECK-NEXT:      },
 // CHECK-NEXT:      {
+// CHECK-NEXT:        "End": true,
 // CHECK-NEXT:        "IsClass": true,
 // CHECK-NEXT:        "Reference": {
 // CHECK-NEXT:          "Name": "Foo",
@@ -129,6 +135,11 @@ struct MyClass {
 // CHECK-NEXT:    ],
 // COM:           FIXME: FullName is not emitted correctly.
 // CHECK-NEXT:    "FullName": "",
+// CHECK-NEXT:    "HasEnums": true,
+// CHECK-NEXT:    "HasPublicFunctions": true,
+// CHECK-NEXT:    "HasPublicMembers": true,
+// CHECK-NEXT:    "HasRecords": true,
+// CHECK-NEXT:    "InfoType": "record",
 // CHECK-NEXT:    "IsTypedef": false,
 // CHECK-NEXT:    "Location": {
 // CHECK-NEXT:      "Filename": "{{.*}}class.cpp",
@@ -142,6 +153,7 @@ struct MyClass {
 // CHECK-NEXT:   "Path": "GlobalNamespace",
 // CHECK-NEXT:   "ProtectedFunctions": [
 // CHECK-NEXT:     {
+// CHECK-NEXT:       "InfoType": "function",
 // CHECK-NEXT:       "IsStatic": false,
 // CHECK-NEXT:       "Name": "protectedMethod",
 // CHECK-NEXT:       "Namespace": [
@@ -166,6 +178,7 @@ struct MyClass {
 // CHECK-NEXT:    ],
 // CHECK-NEXT:    "PublicFunctions": [
 // CHECK-NEXT:      {
+// CHECK-NEXT:        "InfoType": "function",
 // CHECK-NEXT:        "IsStatic": false,
 // CHECK-NEXT:        "Name": "myMethod",
 // CHECK-NEXT:        "Namespace": [
@@ -174,6 +187,7 @@ struct MyClass {
 // CHECK-NEXT:        ],
 // CHECK-NEXT:        "Params": [
 // CHECK-NEXT:          {
+// CHECK-NEXT:            "End": true,
 // CHECK-NEXT:            "Name": "MyParam",
 // CHECK-NEXT:            "Type": "int"
 // CHECK-NEXT:          }
@@ -204,6 +218,8 @@ struct MyClass {
 // CHECK-NEXT:    ],
 // CHECK-NEXT:    "Records": [
 // CHECK-NEXT:      {
+// CHECK-NEXT:        "DocumentationFileName": "_ZTVN7MyClass11NestedClassE",
+// CHECK-NEXT:        "End": true,
 // CHECK-NEXT:        "Name": "NestedClass",
 // CHECK-NEXT:        "Path": "GlobalNamespace{{[\/]+}}MyClass",
 // CHECK-NEXT:        "QualName": "NestedClass",
@@ -213,6 +229,8 @@ struct MyClass {
 // CHECK-NEXT:    "TagType": "struct",
 // CHECK-NEXT:    "Typedefs": [
 // CHECK-NEXT:      {
+// CHECK-NEXT:        "End": true,
+// CHECK-NEXT:        "InfoType": "typedef",
 // CHECK-NEXT:        "IsUsing": false,
 // CHECK-NEXT:        "Location": {
 // CHECK-NEXT:          "Filename": "{{.*}}class.cpp",
diff --git a/clang-tools-extra/test/clang-doc/json/compound-constraints.cpp 
b/clang-tools-extra/test/clang-doc/json/compound-constraints.cpp
index 34acb6808409d..bb2b4ca770fc0 100644
--- a/clang-tools-extra/test/clang-doc/json/compound-constraints.cpp
+++ b/clang-tools-extra/test/clang-doc/json/compound-constraints.cpp
@@ -37,6 +37,7 @@ template<typename T> requires (Incrementable<T> && 
Decrementable<T>) || PreIncre
 // CHECK-NEXT:          "USR": "{{[0-9A-F]*}}"
 // CHECK-NEXT:        },
 // CHECK-NEXT:        {
+// CHECK-NEXT:          "End": true,
 // CHECK-NEXT:          "Expression": "Decrementable<T>",
 // CHECK-NEXT:          "Name": "Decrementable",
 // CHECK-NEXT:          "Path": "",
@@ -55,6 +56,7 @@ template<typename T> requires (Incrementable<T> && 
Decrementable<T>) || PreIncre
 // CHECK-NEXT:          "USR": "{{[0-9A-F]*}}"
 // CHECK-NEXT:        },
 // CHECK-NEXT:        {
+// CHECK-NEXT:          "End": true,
 // CHECK-NEXT:          "Expression": "Decrementable<T>",
 // CHECK-NEXT:          "Name": "Decrementable",
 // CHECK-NEXT:          "Path": "",
@@ -87,6 +89,7 @@ template<typename T> requires (Incrementable<T> && 
Decrementable<T>) || PreIncre
 // CHECK-NEXT:          "USR": "{{[0-9A-F]*}}"
 // CHECK-NEXT:        },
 // CHECK-NEXT:        {
+// CHECK-NEXT:          "End": true,
 // CHECK-NEXT:          "Expression": "PreDecrementable<T>",
 // CHECK-NEXT:          "Name": "PreDecrementable",
 // CHECK-NEXT:          "Path": "",
@@ -112,6 +115,7 @@ template<typename T> requires (Incrementable<T> && 
Decrementable<T>) || PreIncre
 // CHECK-NEXT:          "USR": "{{[0-9A-F]*}}"
 // CHECK-NEXT:        },
 // CHECK-NEXT:        {
+// CHECK-NEXT:          "End": true,
 // CHECK-NEXT:          "Expression": "PreIncrementable<T>",
 // CHECK-NEXT:          "Name": "PreIncrementable",
 // CHECK-NEXT:          "Path": "",
diff --git a/clang-tools-extra/test/clang-doc/json/concept.cpp 
b/clang-tools-extra/test/clang-doc/json/concept.cpp
index b946393274c85..766415bbbeecd 100644
--- a/clang-tools-extra/test/clang-doc/json/concept.cpp
+++ b/clang-tools-extra/test/clang-doc/json/concept.cpp
@@ -23,6 +23,8 @@ concept Incrementable = requires(T x) {
 // CHECK-NEXT:                      {
 // CHECK-NEXT:                        "TextComment": " Requires that T suports 
post and pre-incrementing."
 // CHECK:             ],
+// CHECK:             "End": true,
+// CHECK-NEXT:        "InfoType": "concept",
 // CHECK-NEXT:        "IsType": true,
 // CHECK-NEXT:        "Name": "Incrementable",
 // CHECK-NEXT:        "Template": {
diff --git a/clang-tools-extra/test/clang-doc/json/function-requires.cpp 
b/clang-tools-extra/test/clang-doc/json/function-requires.cpp
index 08ac4c7ed2ca3..59ed39ee61fda 100644
--- a/clang-tools-extra/test/clang-doc/json/function-requires.cpp
+++ b/clang-tools-extra/test/clang-doc/json/function-requires.cpp
@@ -14,10 +14,12 @@ template<Incrementable T> Incrementable auto incrementTwo(T 
t);
 
 // CHECK:       "Functions": [
 // CHECK-NEXT:    {
+// CHECK-NEXT:      "InfoType": "function",
 // CHECK-NEXT:      "IsStatic": false,
 // CHECK-NEXT:      "Name": "increment",
 // CHECK-NEXT:      "Params": [
 // CHECK-NEXT:        {
+// CHECK-NEXT:          "End": true,
 // CHECK-NEXT:          "Name": "t",
 // CHECK-NEXT:          "Type": "T"
 // CHECK-NEXT:        }
@@ -32,6 +34,7 @@ template<Incrementable T> Incrementable auto incrementTwo(T 
t);
 // CHECK-NEXT:      "Template": {
 // CHECK-NEXT:        "Constraints": [
 // CHECK-NEXT:          {
+// CHECK-NEXT:            "End": true,
 // CHECK-NEXT:            "Expression": "Incrementable<T>",
 // CHECK-NEXT:            "Name": "Incrementable",
 // CHECK-NEXT:            "Path": "",
@@ -46,10 +49,13 @@ template<Incrementable T> Incrementable auto incrementTwo(T 
t);
 // CHECK-NEXT:      "USR": "{{[0-9A-F]*}}" 
 // CHECK-NEXT:    },
 // CHECK-NEXT:    {
+// CHECK-NEXT:      "End": true,
+// CHECK-NEXT:      "InfoType": "function",
 // CHECK-NEXT:      "IsStatic": false,
 // CHECK-NEXT:      "Name": "incrementTwo",
 // CHECK-NEXT:      "Params": [
 // CHECK-NEXT:        {
+// CHECK-NEXT:          "End": true,
 // CHECK-NEXT:          "Name": "t",
 // CHECK-NEXT:          "Type": "T"
 // CHECK-NEXT:        }
@@ -64,6 +70,7 @@ template<Incrementable T> Incrementable auto incrementTwo(T 
t);
 // CHECK-NEXT:      "Template": {
 // CHECK-NEXT:        "Constraints": [
 // CHECK-NEXT:          {
+// CHECK-NEXT:            "End": true,
 // CHECK-NEXT:            "Expression": "Incrementable<T>",
 // CHECK-NEXT:            "Name": "Incrementable",
 // CHECK-NEXT:            "Path": "",
diff --git a/clang-tools-extra/test/clang-doc/json/method-template.cpp 
b/clang-tools-extra/test/clang-doc/json/method-template.cpp
index ac8450a72d3a7..14232d00e277a 100644
--- a/clang-tools-extra/test/clang-doc/json/method-template.cpp
+++ b/clang-tools-extra/test/clang-doc/json/method-template.cpp
@@ -9,6 +9,7 @@ struct MyClass {
 
 // CHECK:           "PublicFunctions": [
 // CHECK-NEXT:        {
+// CHECK-NEXT:          "InfoType": "function",
 // CHECK-NEXT:          "IsStatic": false,
 // CHECK-NEXT:          "Location": {
 // CHECK-NEXT:            "Filename": "{{.*}}method-template.cpp",
@@ -21,6 +22,7 @@ struct MyClass {
 // CHECK-NEXT:          ],
 // CHECK-NEXT:          "Params": [
 // CHECK-NEXT:            {
+// CHECK-NEXT:              "End": true,
 // CHECK-NEXT:              "Name": "param",
 // CHECK-NEXT:              "Type": "T"
 // CHECK-NEXT:            }
diff --git a/clang-tools-extra/test/clang-doc/json/namespace.cpp 
b/clang-tools-extra/test/clang-doc/json/namespace.cpp
index 779d7b49f5581..4b6b38869f714 100644
--- a/clang-tools-extra/test/clang-doc/json/namespace.cpp
+++ b/clang-tools-extra/test/clang-doc/json/namespace.cpp
@@ -20,8 +20,11 @@ enum Color {
 typedef int MyTypedef;
 
 // CHECK:       { 
+// CHECK-NEXT:    "DocumentationFileName": "index",
 // CHECK-NEXT:    "Enums": [
 // CHECK-NEXT:      {
+// CHECK-NEXT:        "End": true,
+// CHECK-NEXT:        "InfoType": "enum",
 // CHECK-NEXT:        "Location": {
 // CHECK-NEXT:          "Filename": "{{.*}}namespace.cpp",
 // CHECK-NEXT:          "LineNumber": 14
@@ -36,6 +39,7 @@ typedef int MyTypedef;
 // CHECK-NEXT:            "Value": "1"
 // CHECK-NEXT:          },
 // CHECK-NEXT:          {
+// CHECK-NEXT:            "End": true,
 // CHECK-NEXT:            "Name": "BLUE",
 // CHECK-NEXT:            "ValueExpr": "5"
 // CHECK-NEXT:          }
@@ -47,10 +51,13 @@ typedef int MyTypedef;
 // CHECK-NEXT:    ],
 // CHECK-NEXT:   "Functions": [
 // CHECK-NEXT:     {
+// CHECK-NEXT:       "End": true,
+// CHECK-NEXT:       "InfoType": "function",
 // CHECK-NEXT:       "IsStatic": false,
 // CHECK-NEXT:       "Name": "myFunction",
 // CHECK-NEXT:       "Params": [
 // CHECK-NEXT:         {
+// CHECK-NEXT:           "End": true,
 // CHECK-NEXT:           "Name": "Param",
 // CHECK-NEXT:           "Type": "int"
 // CHECK-NEXT:         }
@@ -65,9 +72,13 @@ typedef int MyTypedef;
 // CHECK-NEXT:       "USR": "{{[0-9A-F]*}}"
 // CHECK-NEXT:     }
 // CHECK-NEXT:   ],
+// CHECK-NEXT:   "HasEnums": true,
+// CHECK-NEXT:   "HasRecords": true,
+// CHECK-NEXT:   "InfoType": "namespace",
 // CHECK-NEXT:   "Name": "",
 // CHECK-NEXT:   "Namespaces": [
 // CHECK-NEXT:     {
+// CHECK-NEXT:       "End": true,
 // CHECK-NEXT:       "Name": "NestedNamespace",
 // CHECK-NEXT:       "Path": "",
 // CHECK-NEXT:       "QualName": "NestedNamespace",
@@ -76,6 +87,8 @@ typedef int MyTypedef;
 // CHECK-NEXT:   ],
 // CHECK-NEXT:   "Records": [
 // CHECK-NEXT:     {
+// CHECK-NEXT:       "DocumentationFileName": "_ZTV7MyClass",
+// CHECK-NEXT:       "End": true,
 // CHECK-NEXT:       "Name": "MyClass",
 // CHECK-NEXT:       "Path": "GlobalNamespace",
 // CHECK-NEXT:       "QualName": "MyClass",
@@ -84,6 +97,8 @@ typedef int MyTypedef;
 // CHECK-NEXT:   ],
 // CHECK-NEXT:   "Typedefs": [
 // CHECK-NEXT:    {
+// CHECK-NEXT:      "End": true,
+// CHECK-NEXT:      "InfoType": "typedef",
 // CHECK-NEXT:      "IsUsing": false,
 // CHECK-NEXT:      "Location": {
 // CHECK-NEXT:        "Filename": "{{.*}}namespace.cpp",
@@ -104,6 +119,8 @@ typedef int MyTypedef;
 // CHECK-NEXT:    "USR": "0000000000000000000000000000000000000000"
 // CHECK-NEXT:   "Variables": [
 // CHECK-NEXT:     {
+// CHECK-NEXT:       "End": true,
+// CHECK-NEXT:       "InfoType": "variable",
 // CHECK-NEXT:       "IsStatic": true,
 // CHECK-NEXT:       "Location": {
 // CHECK-NEXT:         "Filename": "{{.*}}namespace.cpp",
diff --git a/clang-tools-extra/test/clang-doc/json/nested-namespace.cpp 
b/clang-tools-extra/test/clang-doc/json/nested-namespace.cpp
index 54f95c4d041ca..255e540bd6c7c 100644
--- a/clang-tools-extra/test/clang-doc/json/nested-namespace.cpp
+++ b/clang-tools-extra/test/clang-doc/json/nested-namespace.cpp
@@ -12,6 +12,8 @@ namespace nested {
 
 // NESTED:       "Variables": [
 // NESTED-NEXT:    {
+// NESTED-NEXT:      "End": true,
+// NESTED-NEXT:      "InfoType": "variable",
 // NESTED-NEXT:      "IsStatic": false,
 // NESTED-NEXT:      "Location": {
 // NESTED-NEXT:        "Filename": "{{.*}}nested-namespace.cpp",
@@ -24,6 +26,8 @@ namespace nested {
 
 // INNER:       "Variables": [
 // INNER-NEXT:    {
+// INNER-NEXT:      "End": true,
+// INNER-NEXT:      "InfoType": "variable",
 // INNER-NEXT:      "IsStatic": false,
 // INNER-NEXT:      "Location": {
 // INNER-NEXT:        "Filename": "{{.*}}nested-namespace.cpp",
diff --git a/clang-tools-extra/unittests/clang-doc/JSONGeneratorTest.cpp 
b/clang-tools-extra/unittests/clang-doc/JSONGeneratorTest.cpp
index 5927235b3bd93..07c761fcd0685 100644
--- a/clang-tools-extra/unittests/clang-doc/JSONGeneratorTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/JSONGeneratorTest.cpp
@@ -63,7 +63,11 @@ TEST(JSONGeneratorTest, emitRecordJSON) {
   "Bases": [
     {
       "Access": "public",
+      "End": true,
       "FullName": "",
+      "HasPublicFunctions": true,
+      "HasPublicMembers": true,
+      "InfoType": "record",
       "IsParent": true,
       "IsTypedef": false,
       "IsVirtual": true,
@@ -72,6 +76,7 @@ TEST(JSONGeneratorTest, emitRecordJSON) {
       "Path": "path/to/F",
       "PublicFunctions": [
         {
+          "InfoType": "function",
           "IsStatic": false,
           "Name": "InheritedFunctionOne",
           "ReturnType": {
@@ -96,8 +101,11 @@ TEST(JSONGeneratorTest, emitRecordJSON) {
   ],
   "Enums": [
     {
+      "End": true,
+      "InfoType": "enum",
       "Members": [
         {
+          "End": true,
           "Name": "RED",
           "Value": "0"
         }
@@ -108,6 +116,10 @@ TEST(JSONGeneratorTest, emitRecordJSON) {
     }
   ],
   "FullName": "",
+  "HasEnums": true,
+  "HasPublicFunctions": true,
+  "HasRecords": true,
+  "InfoType": "record",
   "IsTypedef": false,
   "Location": {
     "Filename": "main.cpp",
@@ -120,6 +132,7 @@ TEST(JSONGeneratorTest, emitRecordJSON) {
   ],
   "Parents": [
     {
+      "End": true,
       "Name": "F",
       "Path": "",
       "QualName": "",
@@ -135,6 +148,7 @@ TEST(JSONGeneratorTest, emitRecordJSON) {
   ],
   "PublicFunctions": [
     {
+      "InfoType": "function",
       "IsStatic": false,
       "Name": "OneFunction",
       "ReturnType": {
@@ -149,6 +163,7 @@ TEST(JSONGeneratorTest, emitRecordJSON) {
   ],
   "Records": [
     {
+      "End": true,
       "Name": "ChildStruct",
       "Path": "path/to/A/r",
       "QualName": "path::to::A::r::ChildStruct",
@@ -164,6 +179,7 @@ TEST(JSONGeneratorTest, emitRecordJSON) {
   "USR": "0000000000000000000000000000000000000000",
   "VirtualParents": [
     {
+      "End": true,
       "Name": "G",
       "Path": "path/to/G",
       "QualName": "path::to::G::G",
@@ -201,6 +217,8 @@ TEST(JSONGeneratorTest, emitNamespaceJSON) {
   std::string Expected = R"raw({
   "Enums": [
     {
+      "End": true,
+      "InfoType": "enum",
       "Name": "OneEnum",
       "Scoped": false,
       "USR": "0000000000000000000000000000000000000000"
@@ -208,6 +226,8 @@ TEST(JSONGeneratorTest, emitNamespaceJSON) {
   ],
   "Functions": [
     {
+      "End": true,
+      "InfoType": "function",
       "IsStatic": false,
       "Name": "OneFunction",
       "ReturnType": {
@@ -220,12 +240,16 @@ TEST(JSONGeneratorTest, emitNamespaceJSON) {
       "USR": "0000000000000000000000000000000000000000"
     }
   ],
+  "HasEnums": true,
+  "HasRecords": true,
+  "InfoType": "namespace",
   "Name": "Namespace",
   "Namespace": [
     "A"
   ],
   "Namespaces": [
     {
+      "End": true,
       "Name": "ChildNamespace",
       "Path": "path/to/A/Namespace",
       "QualName": "path::to::A::Namespace::ChildNamespace",
@@ -235,6 +259,7 @@ TEST(JSONGeneratorTest, emitNamespaceJSON) {
   "Path": "path/to/A",
   "Records": [
     {
+      "End": true,
       "Name": "ChildStruct",
       "Path": "path/to/A/Namespace",
       "QualName": "path::to::A::Namespace::ChildStruct",

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to