[clang-tools-extra] [clang-doc] integrate JSON generator with Mustache templates (PR #149006)

via cfe-commits cfe-commits at lists.llvm.org
Wed Jul 16 09:06:10 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-tools-extra

Author: Erick Velez (evelez7)

<details>
<summary>Changes</summary>

This patch changes the HTML Mustache generator to use the JSON generator
and consume its output to generate its templates.

---

Patch is 85.75 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/149006.diff


26 Files Affected:

- (modified) clang-tools-extra/clang-doc/BitcodeReader.cpp (+2) 
- (modified) clang-tools-extra/clang-doc/BitcodeWriter.cpp (+3-1) 
- (modified) clang-tools-extra/clang-doc/BitcodeWriter.h (+1) 
- (modified) clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp (+84-405) 
- (modified) clang-tools-extra/clang-doc/JSONGenerator.cpp (+56-13) 
- (modified) clang-tools-extra/clang-doc/Representation.cpp (+6-3) 
- (modified) clang-tools-extra/clang-doc/Representation.h (+15) 
- (modified) clang-tools-extra/clang-doc/Serialize.cpp (+6-2) 
- (modified) clang-tools-extra/clang-doc/assets/class-template.mustache (+68-60) 
- (modified) clang-tools-extra/clang-doc/assets/enum-template.mustache (+18-12) 
- (modified) clang-tools-extra/clang-doc/assets/function-template.mustache (+1-1) 
- (modified) clang-tools-extra/clang-doc/assets/namespace-template.mustache (+25-20) 
- (modified) clang-tools-extra/test/clang-doc/basic-project.mustache.test (+35-61) 
- (modified) clang-tools-extra/test/clang-doc/json/class-requires.cpp (+1) 
- (modified) clang-tools-extra/test/clang-doc/json/class-template.cpp (+1) 
- (modified) clang-tools-extra/test/clang-doc/json/class.cpp (+21) 
- (modified) clang-tools-extra/test/clang-doc/json/compound-constraints.cpp (+4) 
- (modified) clang-tools-extra/test/clang-doc/json/concept.cpp (+2) 
- (modified) clang-tools-extra/test/clang-doc/json/function-requires.cpp (+7) 
- (modified) clang-tools-extra/test/clang-doc/json/method-template.cpp (+2) 
- (modified) clang-tools-extra/test/clang-doc/json/namespace.cpp (+18) 
- (modified) clang-tools-extra/test/clang-doc/json/nested-namespace.cpp (+4) 
- (modified) clang-tools-extra/test/clang-doc/mustache-index.cpp (+9-5) 
- (modified) clang-tools-extra/test/clang-doc/mustache-separate-namespace.cpp (+6-2) 
- (modified) clang-tools-extra/unittests/clang-doc/HTMLMustacheGeneratorTest.cpp (-129) 
- (modified) clang-tools-extra/unittests/clang-doc/JSONGeneratorTest.cpp (+26) 


``````````diff
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/HTMLMustacheGenerator.cpp b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
index 7aeaa1b7cf67d..c640fb4fb613f 100644
--- a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
+++ b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
@@ -27,6 +27,9 @@ using namespace llvm::mustache;
 
 namespace clang {
 namespace doc {
+static Error generateDocForJSON(json::Value &JSON, StringRef Filename,
+                                StringRef Path, raw_fd_ostream &OS,
+                                const ClangDocContext &CDCtx);
 
 static Error createFileOpenError(StringRef FileName, std::error_code EC) {
   return createFileError("cannot open file " + FileName, EC);
@@ -132,404 +135,75 @@ Error MustacheHTMLGenerator::generateDocs(
       return Err;
   }
 
-  // Track which directories we already tried to create.
-  StringSet<> CreatedDirs;
-  // Collect all output by file name and create the necessary directories.
-  StringMap<std::vector<doc::Info *>> FileToInfos;
-  for (const auto &Group : Infos) {
-    llvm::TimeTraceScope TS("setup directories");
-    doc::Info *Info = Group.getValue().get();
-
-    SmallString<128> Path;
-    sys::path::native(RootDir, Path);
-    sys::path::append(Path, Info->getRelativeFilePath(""));
-    if (!CreatedDirs.contains(Path)) {
-      if (std::error_code EC = sys::fs::create_directories(Path))
-        return createStringError(EC, "failed to create directory '%s'.",
-                                 Path.c_str());
-      CreatedDirs.insert(Path);
-    }
+  {
+    llvm::TimeTraceScope TS("Generate JSON for Mustache");
+    if (auto JSONGenerator = findGeneratorByName("json")) {
+      if (Error Err = JSONGenerator.get()->generateDocs(
+              RootDir, std::move(Infos), CDCtx))
+        return Err;
+    } else
+      return JSONGenerator.takeError();
+  }
 
-    sys::path::append(Path, Info->getFileBaseName() + ".html");
-    FileToInfos[Path].push_back(Info);
+  StringMap<json::Value> JSONFileMap;
+  {
+    llvm::TimeTraceScope TS("Iterate JSON files");
+    std::error_code EC;
+    sys::fs::directory_iterator JSONIter(RootDir, EC);
+    std::vector<json::Value> JSONFiles;
+    JSONFiles.reserve(Infos.size());
+    if (EC)
+      return createStringError("Failed to create directory iterator.");
+
+    while (JSONIter != sys::fs::directory_iterator()) {
+      if (EC)
+        return createStringError(EC, "Failed to iterate directory");
+
+      auto Path = StringRef(JSONIter->path());
+      if (!Path.ends_with(".json")) {
+        JSONIter.increment(EC);
+        continue;
+      }
+
+      auto File = MemoryBuffer::getFile(Path);
+      if ((EC = File.getError()))
+        continue;
+
+      auto Parsed = json::parse((*File)->getBuffer());
+      if (!Parsed)
+        return Parsed.takeError();
+      ;
+      JSONFileMap.try_emplace(Path, *Parsed);
+      JSONIter.increment(EC);
+    }
   }
 
   {
     llvm::TimeTraceScope TS("Generate Docs");
-    for (const auto &Group : FileToInfos) {
+    for (const auto &File : JSONFileMap) {
       llvm::TimeTraceScope TS("Info to Doc");
       std::error_code FileErr;
-      raw_fd_ostream InfoOS(Group.getKey(), FileErr, sys::fs::OF_None);
+      auto JSON = File.getValue();
+      auto Path = File.getKey().str();
+      SmallString<16> HTMLPath(Path.begin(), Path.end());
+      sys::path::replace_extension(HTMLPath, "html");
+      raw_fd_ostream InfoOS(HTMLPath, FileErr, sys::fs::OF_None);
       if (FileErr)
-        return createFileOpenError(Group.getKey(), FileErr);
+        return createFileOpenError(File.getKey(), FileErr);
 
-      for (const auto &Info : Group.getValue())
-        if (Error Err = generateDocForInfo(Info, InfoOS, CDCtx))
-          return Err;
+      if (Error Err = generateDocForJSON(JSON, sys::path::stem(HTMLPath),
+                                         HTMLPath, InfoOS, CDCtx))
+        return Err;
     }
   }
   return Error::success();
 }
 
-static json::Value
-extractValue(const Location &L,
-             std::optional<StringRef> RepositoryUrl = std::nullopt) {
-  Object Obj = Object();
-  // TODO: Consider using both Start/End line numbers to improve location report
-  Obj.insert({"LineNumber", L.StartLineNumber});
-  Obj.insert({"Filename", L.Filename});
-
-  if (!L.IsFileInRootDir || !RepositoryUrl)
-    return Obj;
-  SmallString<128> FileURL(*RepositoryUrl);
-  sys::path::append(FileURL, sys::path::Style::posix, L.Filename);
-  FileURL += "#" + std::to_string(L.StartLineNumber);
-  Obj.insert({"FileURL", FileURL});
-
-  return Obj;
-}
-
-static json::Value extractValue(const Reference &I,
-                                StringRef CurrentDirectory) {
-  SmallString<64> Path = I.getRelativeFilePath(CurrentDirectory);
-  sys::path::append(Path, I.getFileBaseName() + ".html");
-  sys::path::native(Path, sys::path::Style::posix);
-  Object Obj = Object();
-  Obj.insert({"Link", Path});
-  Obj.insert({"Name", I.Name});
-  Obj.insert({"QualName", I.QualName});
-  Obj.insert({"ID", toHex(toStringRef(I.USR))});
-  return Obj;
-}
-
-static json::Value extractValue(const TypedefInfo &I) {
-  // Not Supported
-  return nullptr;
-}
-
-static json::Value extractValue(const CommentInfo &I) {
-  Object Obj = Object();
-
-  json::Value ChildVal = Object();
-  Object &Child = *ChildVal.getAsObject();
-
-  json::Value ChildArr = Array();
-  auto &CARef = *ChildArr.getAsArray();
-  CARef.reserve(I.Children.size());
-  for (const auto &C : I.Children)
-    CARef.emplace_back(extractValue(*C));
-
-  switch (I.Kind) {
-  case CommentKind::CK_TextComment: {
-    Obj.insert({commentKindToString(I.Kind), I.Text});
-    return Obj;
-  }
-
-  case CommentKind::CK_BlockCommandComment: {
-    Child.insert({"Command", I.Name});
-    Child.insert({"Children", ChildArr});
-    Obj.insert({commentKindToString(I.Kind), ChildVal});
-    return Obj;
-  }
-
-  case CommentKind::CK_InlineCommandComment: {
-    json::Value ArgsArr = Array();
-    auto &ARef = *ArgsArr.getAsArray();
-    ARef.reserve(I.Args.size());
-    for (const auto &Arg : I.Args)
-      ARef.emplace_back(Arg);
-    Child.insert({"Command", I.Name});
-    Child.insert({"Args", ArgsArr});
-    Child.insert({"Children", ChildArr});
-    Obj.insert({commentKindToString(I.Kind), ChildVal});
-    return Obj;
-  }
-
-  case CommentKind::CK_ParamCommandComment:
-  case CommentKind::CK_TParamCommandComment: {
-    Child.insert({"ParamName", I.ParamName});
-    Child.insert({"Direction", I.Direction});
-    Child.insert({"Explicit", I.Explicit});
-    Child.insert({"Children", ChildArr});
-    Obj.insert({commentKindToString(I.Kind), ChildVal});
-    return Obj;
-  }
-
-  case CommentKind::CK_VerbatimBlockComment: {
-    Child.insert({"Text", I.Text});
-    if (!I.CloseName.empty())
-      Child.insert({"CloseName", I.CloseName});
-    Child.insert({"Children", ChildArr});
-    Obj.insert({commentKindToString(I.Kind), ChildVal});
-    return Obj;
-  }
-
-  case CommentKind::CK_VerbatimBlockLineComment:
-  case CommentKind::CK_VerbatimLineComment: {
-    Child.insert({"Text", I.Text});
-    Child.insert({"Children", ChildArr});
-    Obj.insert({commentKindToString(I.Kind), ChildVal});
-    return Obj;
-  }
-
-  case CommentKind::CK_HTMLStartTagComment: {
-    json::Value AttrKeysArray = json::Array();
-    json::Value AttrValuesArray = json::Array();
-    auto &KeyArr = *AttrKeysArray.getAsArray();
-    auto &ValArr = *AttrValuesArray.getAsArray();
-    KeyArr.reserve(I.AttrKeys.size());
-    ValArr.reserve(I.AttrValues.size());
-    for (const auto &K : I.AttrKeys)
-      KeyArr.emplace_back(K);
-    for (const auto &V : I.AttrValues)
-      ValArr.emplace_back(V);
-    Child.insert({"Name", I.Name});
-    Child.insert({"SelfClosing", I.SelfClosing});
-    Child.insert({"AttrKeys", AttrKeysArray});
-    Child.insert({"AttrValues", AttrValuesArray});
-    Child.insert({"Children", ChildArr});
-    Obj.insert({commentKindToString(I.Kind), ChildVal});
-    return Obj;
-  }
-
-  case CommentKind::CK_HTMLEndTagComment: {
-    Child.insert({"Name", I.Name});
-    Child.insert({"Children", ChildArr});
-    Obj.insert({commentKindToString(I.Kind), ChildVal});
-    return Obj;
-  }
-
-  case CommentKind::CK_FullComment:
-  case CommentKind::CK_ParagraphComment: {
-    Child.insert({"Children", ChildArr});
-    Obj.insert({commentKindToString(I.Kind), ChildVal});
-    return Obj;
-  }
-
-  case CommentKind::CK_Unknown: {
-    Obj.insert({commentKindToString(I.Kind), I.Text});
-    return Obj;
-  }
-  }
-  llvm_unreachable("Unknown comment kind encountered.");
-}
-
-static void maybeInsertLocation(std::optional<Location> Loc,
-                                const ClangDocContext &CDCtx, Object &Obj) {
-  if (!Loc)
-    return;
-  Location L = *Loc;
-  Obj.insert({"Location", extractValue(L, CDCtx.RepositoryUrl)});
-}
-
-static void extractDescriptionFromInfo(ArrayRef<CommentInfo> Descriptions,
-                                       json::Object &EnumValObj) {
-  if (Descriptions.empty())
-    return;
-  json::Value DescArr = Array();
-  json::Array &DescARef = *DescArr.getAsArray();
-  DescARef.reserve(Descriptions.size());
-  for (const CommentInfo &Child : Descriptions)
-    DescARef.emplace_back(extractValue(Child));
-  EnumValObj.insert({"EnumValueComments", DescArr});
-}
-
-static json::Value extractValue(const FunctionInfo &I, StringRef ParentInfoDir,
-                                const ClangDocContext &CDCtx) {
-  Object Obj = Object();
-  Obj.insert({"Name", I.Name});
-  Obj.insert({"ID", toHex(toStringRef(I.USR))});
-  Obj.insert({"Access", getAccessSpelling(I.Access).str()});
-  Obj.insert({"ReturnType", extractValue(I.ReturnType.Type, ParentInfoDir)});
-
-  json::Value ParamArr = Array();
-  json::Array &ParamARef = *ParamArr.getAsArray();
-  ParamARef.reserve(I.Params.size());
-  for (const auto Val : enumerate(I.Params)) {
-    json::Value V = Object();
-    auto &VRef = *V.getAsObject();
-    VRef.insert({"Name", Val.value().Name});
-    VRef.insert({"Type", Val.value().Type.Name});
-    VRef.insert({"End", Val.index() + 1 == I.Params.size()});
-    ParamARef.emplace_back(V);
-  }
-  Obj.insert({"Params", ParamArr});
-
-  maybeInsertLocation(I.DefLoc, CDCtx, Obj);
-  return Obj;
-}
-
-static json::Value extractValue(const EnumInfo &I,
-                                const ClangDocContext &CDCtx) {
-  Object Obj = Object();
-  std::string EnumType = I.Scoped ? "enum class " : "enum ";
-  EnumType += I.Name;
-  bool HasComment = llvm::any_of(
-      I.Members, [](const EnumValueInfo &M) { return !M.Description.empty(); });
-  Obj.insert({"EnumName", EnumType});
-  Obj.insert({"HasComment", HasComment});
-  Obj.insert({"ID", toHex(toStringRef(I.USR))});
-  json::Value EnumArr = Array();
-  json::Array &EnumARef = *EnumArr.getAsArray();
-  EnumARef.reserve(I.Members.size());
-  for (const EnumValueInfo &M : I.Members) {
-    json::Value EnumValue = Object();
-    auto &EnumValObj = *EnumValue.getAsObject();
-    EnumValObj.insert({"Name", M.Name});
-    if (!M.ValueExpr.empty())
-      EnumValObj.insert({"ValueExpr", M.ValueExpr});
-    else
-      EnumValObj.insert({"Value", M.Value});
-
-    extractDescriptionFromInfo(M.Description, EnumValObj);
-    EnumARef.emplace_back(EnumValue);
-  }
-  Obj.insert({"EnumValues", EnumArr});
-
-  extractDescriptionFromInfo(I.Description, Obj);
-  maybeInsertLocation(I.DefLoc, CDCtx, Obj);
-
-  return Obj;
-}
-
-static void extractScopeChildren(const ScopeChildren &S, Object &Obj,
-                                 StringRef ParentInfoDir,
-                                 const ClangDocContext &CDCtx) {
-  json::Value NamespaceArr = Array();
-  json::Array &NamespaceARef = *NamespaceArr.getAsArray();
-  NamespaceARef.reserve(S.Namespaces.size());
-  for (const Reference &Child : S.Namespaces)
-    NamespaceARef.emplace_back(extractValue(Child, ParentInfoDir));
-
-  if (!NamespaceARef.empty())
-    Obj.insert({"Namespace", Object{{"Links", NamespaceArr}}});
-
-  json::Value RecordArr = Array();
-  json::Array &RecordARef = *RecordArr.getAsArray();
-  RecordARef.reserve(S.Records.size());
-  for (const Reference &Child : S.Records)
-    RecordARef.emplace_back(extractValue(Child, ParentInfoDir));
-
-  if (!RecordARef.empty())
-    Obj.insert({"Record", Object{{"Links", RecordArr}}});
-
-  json::Value FunctionArr = Array();
-  json::Array &FunctionARef = *FunctionArr.getAsArray();
-  FunctionARef.reserve(S.Functions.size());
-
-  json::Value PublicFunctionArr = Array();
-  json::Array &PublicFunctionARef = *PublicFunctionArr.getAsArray();
-  PublicFunctionARef.reserve(S.Functions.size());
-
-  json::Value ProtectedFunctionArr = Array();
-  json::Array &ProtectedFunctionARef = *ProtectedFunctionArr.getAsArray();
-  ProtectedFunctionARef.reserve(S.Functions.size());
-
-  for (const FunctionInfo &Child : S.Functions) {
-    json::Value F = extractValue(Child, ParentInfoDir, CDCtx);
-    AccessSpecifier Access = Child.Access;
-    if (Access == AccessSpecifier::AS_public)
-      PublicFunctionARef.emplace_back(F);
-    else if (Access == AccessSpecifier::AS_protected)
-      ProtectedFunctionARef.emplace_back(F);
-    else
-      FunctionARef.emplace_back(F);
-  }
-
-  if (!FunctionARef.empty())
-    Obj.insert({"Function", Object{{"Obj", FunctionArr}}});
-
-  if (!PublicFunctionARef.empty())
-    Obj.insert({"PublicFunction", Object{{"Obj", PublicFunctionArr}}});
-
-  if (!ProtectedFunctionARef.empty())
-    Obj.insert({"ProtectedFunction", Object{{"Obj", ProtectedFunctionArr}}});
-
-  json::Value EnumArr = Array();
-  auto &EnumARef = *EnumArr.getAsArray();
-  EnumARef.reserve(S.Enums.size());
-  for (const EnumInfo &Child : S.Enums)
-    EnumARef.emplace_back(extractValue(Child, CDCtx));
-
-  if (!EnumARef.empty())
-    Obj.insert({"Enums", Object{{"Obj", EnumArr}}});
-
-  json::Value TypedefArr = Array();
-  auto &TypedefARef = *TypedefArr.getAsArray();
-  TypedefARef.reserve(S.Typedefs.size());
-  for (const TypedefInfo &Child : S.Typedefs)
-    TypedefARef.emplace_back(extractValue(Child));
-
-  if (!TypedefARef.empty())
-    Obj.insert({"Typedefs", Object{{"Obj", TypedefArr}}});
-}
-
-static json::Value extractValue(const NamespaceInfo &I,
-                                const ClangDocContext &CDCtx) {
-  Object NamespaceValue = Object();
-  std::string InfoTitle = I.Name.empty() ? "Global Namespace"
-                                         : (Twine("namespace ") + I.Name).str();
-
-  SmallString<64> BasePath = I.getRelativeFilePath("");
-  NamespaceValue.insert({"NamespaceTitle", InfoTitle});
-  NamespaceValue.insert({"NamespacePath", BasePath});
-
-  extractDescriptionFromInfo(I.Description, NamespaceValue);
-  extractScopeChildren(I.Children, NamespaceValue, BasePath, CDCtx);
-  return NamespaceValue;
-}
-
-static json::Value extractValue(const RecordInfo &I,
-                                const ClangDocContext &CDCtx) {
-  Object RecordValue = Object();
-  extractDescriptionFromInfo(I.Description, RecordValue);
-  RecordValue.insert({"Name", I.Name});
-  RecordValue.insert({"FullName", I.FullName});
-  RecordValue.insert({"RecordType", getTagType(I.TagType)});
-
-  maybeInsertLocation(I.DefLoc, CDCtx, RecordValue);
-
-  SmallString<64> BasePath = I.getRelativeFilePath("");
-  extractScopeChildren(I.Children, RecordValue, BasePath, CDCtx);
-  json::Value PublicMembers = Array();
-  json::Array &PubMemberRef = *PublicMembers.getAsArray();
-  PubMemberRef.reserve(I.Members.size());
-  json::Value ProtectedMembers = Array();
-  json::Array &ProtMemberRef = *ProtectedMembers.getAsArray();
-  ProtMemberRef.reserve(I.Members.size());
-  json::Value PrivateMembers = Array();
-  json::Array &PrivMemberRef = *PrivateMembers.getAsArray();
-  PrivMemberRef.reserve(I.Members.size());
-  for (const MemberTypeInfo &Member : I.Members) {
-    json::Value MemberValue = Object();
-    auto &MVRef = *MemberValue.getAsObject();
-    MVRef.insert({"Name", Member.Name});
-    MVRef.insert({"Type", Member.Type.Name});
-    extractDescriptionFromInfo(Member.Description, MVRef);
-
-    if (Member.Access == AccessSpecifier::AS_public)
-      PubMemberRef.emplace_back(MemberValue);
-    else if (Member.Access == AccessSpecifier::AS_protected)
-      ProtMemberRef.emplace_back(MemberValue);
-    else if (Member.Access == AccessSpecifier::AS_private)
-      ProtMemberRef.emplace_back(MemberValue);
-  }
-  if (!PubMemberRef.empty())
-    RecordValue.insert({"PublicMembers", Object{{"Obj", PublicMembers}}});
-  if (!ProtMemberRef.empty())
-    RecordValue.insert({"ProtectedMembers", Object{{"Obj", ProtectedMembers}}});
-  if (!PrivMemberRef.empty())
-    RecordValue.insert({"PrivateMembers", Object{{"Obj", PrivateMembers}}});
-
-  return RecordValue;
-}
-
 static Error setupTemplateValue(const ClangDocContext &CDCtx, json::Value &V,
-                                Info *I) {
+                                StringRef JSONPath) {
   V.getAsObject()->insert({"ProjectName", CDCtx.ProjectName});
   json::Value StylesheetArr = Array();
-  auto InfoPath = I->getRelativeFilePath("");
-  SmallString<128> RelativePath = computeRelativePath("", InfoPath);
+  SmallString<128> RelativePath("./");
   sys::path::native(RelativePath, sys::path::Style::posix);
 
   auto *SSA = StylesheetArr.getAsArray();
@@ -555,38 +229,43 @@ static Error setupTemplateValue(const ClangDocContext &CDCtx, json::Value &V,
   return Error::success();
 }
 
-Error MustacheHTMLGenerator::generateDocForInfo(Info *I, raw_ostream &OS,
-                                                const ClangDocContext &CDCtx) {
-  switch (I->IT) {
-  case InfoType::IT_namespace: {
-    json::Value V =
-        extractValue(*static_cast<clang::doc::NamespaceInfo *>(I), CDCtx);
-    if (auto Err = setupTemplateValue(...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/149006


More information about the cfe-commits mailing list