From 655f299c6acaec5258587ec9866c9e3f2e9fcc04 Mon Sep 17 00:00:00 2001 From: Erick Velez Date: Fri, 14 Nov 2025 21:43:34 -0800 Subject: [PATCH] fix unittest --- clang-tools-extra/clang-doc/Generators.cpp | 4 ++ clang-tools-extra/clang-doc/HTMLGenerator.cpp | 12 ++++ clang-tools-extra/clang-doc/JSONGenerator.cpp | 54 +++++++++++++++- .../clang-doc/assets/index-template.mustache | 41 ++++++++++++ clang-tools-extra/clang-doc/support/Utils.cpp | 3 + .../clang-doc/tool/CMakeLists.txt | 1 + clang-tools-extra/test/clang-doc/index.cpp | 63 +++++++++++++++++++ .../test/clang-doc/json/class-requires.cpp | 1 - .../test/clang-doc/json/class.cpp | 1 - .../clang-doc/json/compound-constraints.cpp | 11 ---- .../test/clang-doc/json/function-requires.cpp | 2 - .../test/clang-doc/json/namespace.cpp | 1 - .../test/clang-doc/namespace.cpp | 2 +- .../unittests/clang-doc/JSONGeneratorTest.cpp | 1 - 14 files changed, 178 insertions(+), 19 deletions(-) create mode 100644 clang-tools-extra/clang-doc/assets/index-template.mustache create mode 100644 clang-tools-extra/test/clang-doc/index.cpp diff --git a/clang-tools-extra/clang-doc/Generators.cpp b/clang-tools-extra/clang-doc/Generators.cpp index d6c1cc948ce30..fafe41eebb779 100644 --- a/clang-tools-extra/clang-doc/Generators.cpp +++ b/clang-tools-extra/clang-doc/Generators.cpp @@ -164,6 +164,10 @@ Error MustacheGenerator::generateDocumentation( Expected MustacheGenerator::getInfoTypeStr(Object *Info, StringRef Filename) { + // Checking for a USR ensures that only the special top-level index file is + // caught here, since it is not an Info. + if (Filename == "index" && !Info->get("USR")) + return "index"; auto StrValue = (*Info)["InfoType"]; if (StrValue.kind() != json::Value::Kind::String) return createStringError("JSON file '%s' does not contain key: 'InfoType'.", diff --git a/clang-tools-extra/clang-doc/HTMLGenerator.cpp b/clang-tools-extra/clang-doc/HTMLGenerator.cpp index 77b287476423e..3fc89311749ad 100644 --- a/clang-tools-extra/clang-doc/HTMLGenerator.cpp +++ b/clang-tools-extra/clang-doc/HTMLGenerator.cpp @@ -29,6 +29,8 @@ static std::unique_ptr NamespaceTemplate = nullptr; static std::unique_ptr RecordTemplate = nullptr; +static std::unique_ptr IndexTemplate = nullptr; + class HTMLGenerator : public MustacheGenerator { public: static const char *Format; @@ -60,6 +62,8 @@ Error HTMLGenerator::setupTemplateFiles(const ClangDocContext &CDCtx) { ConvertToNative(CDCtx.MustacheTemplates.lookup("namespace-template")); std::string ClassFilePath = ConvertToNative(CDCtx.MustacheTemplates.lookup("class-template")); + std::string IndexFilePath = + ConvertToNative(CDCtx.MustacheTemplates.lookup("index-template")); std::string CommentFilePath = ConvertToNative(CDCtx.MustacheTemplates.lookup("comment-template")); std::string FunctionFilePath = @@ -83,6 +87,9 @@ Error HTMLGenerator::setupTemplateFiles(const ClangDocContext &CDCtx) { if (Error Err = setupTemplate(RecordTemplate, ClassFilePath, Partials)) return Err; + if (Error Err = setupTemplate(IndexTemplate, IndexFilePath, Partials)) + return Err; + return Error::success(); } @@ -130,6 +137,11 @@ Error HTMLGenerator::generateDocForJSON(json::Value &JSON, raw_fd_ostream &OS, return Err; assert(RecordTemplate && "RecordTemplate is nullptr."); RecordTemplate->render(JSON, OS); + } else if (ObjTypeStr == "index") { + if (auto Err = setupTemplateResources(CDCtx, JSON, RelativeRootPath)) + return Err; + assert(IndexTemplate && "IndexTemplate is nullptr."); + IndexTemplate->render(JSON, OS); } return Error::success(); } diff --git a/clang-tools-extra/clang-doc/JSONGenerator.cpp b/clang-tools-extra/clang-doc/JSONGenerator.cpp index 83fa556782793..52b3c4d0fc0c7 100644 --- a/clang-tools-extra/clang-doc/JSONGenerator.cpp +++ b/clang-tools-extra/clang-doc/JSONGenerator.cpp @@ -318,7 +318,8 @@ serializeCommonAttributes(const Info &I, json::Object &Obj, } static void serializeReference(const Reference &Ref, Object &ReferenceObj) { - ReferenceObj["Path"] = Ref.Path; + if (!Ref.Path.empty()) + ReferenceObj["Path"] = Ref.Path; ReferenceObj["Name"] = Ref.Name; ReferenceObj["QualName"] = Ref.QualName; ReferenceObj["USR"] = toHex(toStringRef(Ref.USR)); @@ -647,6 +648,54 @@ static SmallString<16> determineFileName(Info *I, SmallString<128> &Path) { return FileName; } +// Creates a JSON file above the global namespace directory. +// An index can be used to create the top-level HTML index page or the Markdown +// index file. +static Error serializeIndex(const ClangDocContext &CDCtx, StringRef RootDir) { + if (CDCtx.Idx.Children.empty()) + return Error::success(); + + json::Value ObjVal = Object(); + Object &Obj = *ObjVal.getAsObject(); + if (!CDCtx.ProjectName.empty()) + Obj["ProjectName"] = CDCtx.ProjectName; + + auto IndexCopy = CDCtx.Idx; + IndexCopy.sort(); + json::Value IndexArray = json::Array(); + auto &IndexArrayRef = *IndexArray.getAsArray(); + + if (IndexCopy.Children.empty()) { + // If the index is empty, default to displaying the global namespace. + IndexCopy.Children.emplace_back(GlobalNamespaceID, "", + InfoType::IT_namespace, "GlobalNamespace"); + } else { + IndexArrayRef.reserve(CDCtx.Idx.Children.size()); + } + + for (auto &Idx : IndexCopy.Children) { + if (!Idx.Children.empty()) { + std::string TypeStr = infoTypeToString(Idx.RefType); + // MD output expects a capitalized type string + TypeStr[0] = toUppercase(TypeStr[0]); + json::Value IdxVal = Object(); + auto &IdxObj = *IdxVal.getAsObject(); + serializeReference(Idx, IdxObj); + IndexArrayRef.push_back(IdxVal); + } + } + Obj["Index"] = IndexArray; + + SmallString<128> IndexFilePath(RootDir); + sys::path::append(IndexFilePath, "/json/index.json"); + std::error_code FileErr; + raw_fd_ostream RootOS(IndexFilePath, FileErr, sys::fs::OF_Text); + if (FileErr) + return createFileError("cannot open file " + IndexFilePath, FileErr); + RootOS << llvm::formatv("{0:2}", ObjVal); + return Error::success(); +} + Error JSONGenerator::generateDocumentation( StringRef RootDir, llvm::StringMap> Infos, const ClangDocContext &CDCtx, std::string DirName) { @@ -685,6 +734,9 @@ Error JSONGenerator::generateDocumentation( return Err; } + if (auto Err = serializeIndex(CDCtx, RootDir)) + return Err; + return Error::success(); } diff --git a/clang-tools-extra/clang-doc/assets/index-template.mustache b/clang-tools-extra/clang-doc/assets/index-template.mustache new file mode 100644 index 0000000000000..de64da4d709ee --- /dev/null +++ b/clang-tools-extra/clang-doc/assets/index-template.mustache @@ -0,0 +1,41 @@ + + +{{>HeadPartial}} + + {{>NavbarPartial}} +
+
+ +
+
+
+

Index

+ {{#Index}} + + {{/Index}} +
+
+
+
+ + diff --git a/clang-tools-extra/clang-doc/support/Utils.cpp b/clang-tools-extra/clang-doc/support/Utils.cpp index d0fd6f45b8a02..e0d92d23b045e 100644 --- a/clang-tools-extra/clang-doc/support/Utils.cpp +++ b/clang-tools-extra/clang-doc/support/Utils.cpp @@ -60,6 +60,8 @@ void getHtmlFiles(StringRef AssetsPath, clang::doc::ClangDocContext &CDCtx) { appendPathPosix(AssetsPath, "head-template.mustache"); SmallString<128> NavbarTemplate = appendPathPosix(AssetsPath, "navbar-template.mustache"); + SmallString<128> IndexTemplate = + appendPathPosix(AssetsPath, "index-template.mustache"); CDCtx.MustacheTemplates.insert( {"namespace-template", NamespaceTemplate.c_str()}); @@ -70,4 +72,5 @@ void getHtmlFiles(StringRef AssetsPath, clang::doc::ClangDocContext &CDCtx) { CDCtx.MustacheTemplates.insert({"comment-template", CommentTemplate.c_str()}); CDCtx.MustacheTemplates.insert({"head-template", HeadTemplate.c_str()}); CDCtx.MustacheTemplates.insert({"navbar-template", NavbarTemplate.c_str()}); + CDCtx.MustacheTemplates.insert({"index-template", IndexTemplate.c_str()}); } diff --git a/clang-tools-extra/clang-doc/tool/CMakeLists.txt b/clang-tools-extra/clang-doc/tool/CMakeLists.txt index c8b4162a0e716..6d8665379e750 100644 --- a/clang-tools-extra/clang-doc/tool/CMakeLists.txt +++ b/clang-tools-extra/clang-doc/tool/CMakeLists.txt @@ -33,6 +33,7 @@ set(assets template.mustache head-template.mustache navbar-template.mustache + index-template.mustache ) set(asset_dir "${CMAKE_CURRENT_SOURCE_DIR}/../assets") diff --git a/clang-tools-extra/test/clang-doc/index.cpp b/clang-tools-extra/test/clang-doc/index.cpp new file mode 100644 index 0000000000000..e6662455c6657 --- /dev/null +++ b/clang-tools-extra/test/clang-doc/index.cpp @@ -0,0 +1,63 @@ +// RUN: rm -rf %t && mkdir -p %t +// RUN: clang-doc --format=html --output=%t --executor=standalone %s +// RUN: FileCheck %s < %t/json/index.json -check-prefix=CHECK-JSON +// RUN: FileCheck %s < %t/html/index.html -check-prefix=CHECK-HTML + +class Foo {}; + +namespace inner { + class Bar {}; +} + +{ +// CHECK-JSON: "Index": [ +// CHECK-JSON-NEXT: { +// CHECK-JSON-NEXT: "Name": "GlobalNamespace", +// CHECK-JSON-NEXT: "QualName": "GlobalNamespace", +// CHECK-JSON-NEXT: "USR": "0000000000000000000000000000000000000000" +// CHECK-JSON-NEXT: }, +// CHECK-JSON-NEXT: { +// CHECK-JSON-NEXT: "Name": "inner", +// CHECK-JSON-NEXT: "QualName": "inner", +// CHECK-JSON-NEXT: "USR": "96AD5C6626E13385428E4BF18C3523B9AF6508B8" +// CHECK-JSON-NEXT: } +// CHECK-JSON-NEXT: ] + +// CHECK-HTML:
+// CHECK-HTML-NEXT:
+// CHECK-HTML-NEXT: +// CHECK-HTML-NEXT:
+// CHECK-HTML-NEXT:
+// CHECK-HTML-NEXT:
+// CHECK-HTML-NEXT:

Index

+// CHECK-HTML-NEXT: +// CHECK-HTML-NEXT:
+// CHECK-HTML-NEXT: +// CHECK-HTML-NEXT:
namespace inner
+// CHECK-HTML-NEXT:
+// CHECK-HTML-NEXT:
+// CHECK-HTML-NEXT:
+// CHECK-HTML-NEXT:
+// CHECK-HTML-NEXT:
+// CHECK-HTML-NEXT:
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 4e5ec3a5729cd..de9aff285dcb9 100644 --- a/clang-tools-extra/test/clang-doc/json/class-requires.cpp +++ b/clang-tools-extra/test/clang-doc/json/class-requires.cpp @@ -23,7 +23,6 @@ struct MyClass; // CHECK-NEXT: "End": true, // CHECK-NEXT: "Expression": "Addable", // CHECK-NEXT: "Name": "Addable", -// CHECK-NEXT: "Path": "", // CHECK-NEXT: "QualName": "Addable", // CHECK-NEXT: "USR": "{{[0-9A-F]*}}" // 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 d57e8a990c3fe..e62489d4e67ca 100644 --- a/clang-tools-extra/test/clang-doc/json/class.cpp +++ b/clang-tools-extra/test/clang-doc/json/class.cpp @@ -95,7 +95,6 @@ struct MyClass { // CHECK-NEXT: ], // CHECK-NEXT: "Reference": { // CHECK-NEXT: "Name": "friendFunction", -// CHECK-NEXT: "Path": "", // CHECK-NEXT: "QualName": "friendFunction", // CHECK-NEXT: "USR": "{{[0-9A-F]*}}" // CHECK-NEXT: }, 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 5b15a88d562de..afaad8f5d6775 100644 --- a/clang-tools-extra/test/clang-doc/json/compound-constraints.cpp +++ b/clang-tools-extra/test/clang-doc/json/compound-constraints.cpp @@ -32,7 +32,6 @@ template requires (Incrementable && Decrementable) || PreIncre // CHECK-NEXT: { // CHECK-NEXT: "Expression": "Incrementable", // CHECK-NEXT: "Name": "Incrementable", -// CHECK-NEXT: "Path": "", // CHECK-NEXT: "QualName": "Incrementable", // CHECK-NEXT: "USR": "{{[0-9A-F]*}}" // CHECK-NEXT: }, @@ -40,7 +39,6 @@ template requires (Incrementable && Decrementable) || PreIncre // CHECK-NEXT: "End": true, // CHECK-NEXT: "Expression": "Decrementable", // CHECK-NEXT: "Name": "Decrementable", -// CHECK-NEXT: "Path": "", // CHECK-NEXT: "QualName": "Decrementable", // CHECK-NEXT: "USR": "{{[0-9A-F]*}}" // CHECK-NEXT: } @@ -51,7 +49,6 @@ template requires (Incrementable && Decrementable) || PreIncre // CHECK-NEXT: { // CHECK-NEXT: "Expression": "Incrementable", // CHECK-NEXT: "Name": "Incrementable", -// CHECK-NEXT: "Path": "", // CHECK-NEXT: "QualName": "Incrementable", // CHECK-NEXT: "USR": "{{[0-9A-F]*}}" // CHECK-NEXT: }, @@ -59,7 +56,6 @@ template requires (Incrementable && Decrementable) || PreIncre // CHECK-NEXT: "End": true, // CHECK-NEXT: "Expression": "Decrementable", // CHECK-NEXT: "Name": "Decrementable", -// CHECK-NEXT: "Path": "", // CHECK-NEXT: "QualName": "Decrementable", // CHECK-NEXT: "USR": "{{[0-9A-F]*}}" // CHECK-NEXT: } @@ -70,21 +66,18 @@ template requires (Incrementable && Decrementable) || PreIncre // CHECK-NEXT: { // CHECK-NEXT: "Expression": "Incrementable", // CHECK-NEXT: "Name": "Incrementable", -// CHECK-NEXT: "Path": "", // CHECK-NEXT: "QualName": "Incrementable", // CHECK-NEXT: "USR": "{{[0-9A-F]*}}" // CHECK-NEXT: }, // CHECK-NEXT: { // CHECK-NEXT: "Expression": "Decrementable", // CHECK-NEXT: "Name": "Decrementable", -// CHECK-NEXT: "Path": "", // CHECK-NEXT: "QualName": "Decrementable", // CHECK-NEXT: "USR": "{{[0-9A-F]*}}" // CHECK-NEXT: }, // CHECK-NEXT: { // CHECK-NEXT: "Expression": "PreIncrementable", // CHECK-NEXT: "Name": "PreIncrementable", -// CHECK-NEXT: "Path": "", // CHECK-NEXT: "QualName": "PreIncrementable", // CHECK-NEXT: "USR": "{{[0-9A-F]*}}" // CHECK-NEXT: }, @@ -92,7 +85,6 @@ template requires (Incrementable && Decrementable) || PreIncre // CHECK-NEXT: "End": true, // CHECK-NEXT: "Expression": "PreDecrementable", // CHECK-NEXT: "Name": "PreDecrementable", -// CHECK-NEXT: "Path": "", // CHECK-NEXT: "QualName": "PreDecrementable", // CHECK-NEXT: "USR": "{{[0-9A-F]*}}" // CHECK-NEXT: } @@ -103,14 +95,12 @@ template requires (Incrementable && Decrementable) || PreIncre // CHECK-NEXT: { // CHECK-NEXT: "Expression": "Incrementable", // CHECK-NEXT: "Name": "Incrementable", -// CHECK-NEXT: "Path": "", // CHECK-NEXT: "QualName": "Incrementable", // CHECK-NEXT: "USR": "{{[0-9A-F]*}}" // CHECK-NEXT: }, // CHECK-NEXT: { // CHECK-NEXT: "Expression": "Decrementable", // CHECK-NEXT: "Name": "Decrementable", -// CHECK-NEXT: "Path": "", // CHECK-NEXT: "QualName": "Decrementable", // CHECK-NEXT: "USR": "{{[0-9A-F]*}}" // CHECK-NEXT: }, @@ -118,7 +108,6 @@ template requires (Incrementable && Decrementable) || PreIncre // CHECK-NEXT: "End": true, // CHECK-NEXT: "Expression": "PreIncrementable", // CHECK-NEXT: "Name": "PreIncrementable", -// CHECK-NEXT: "Path": "", // CHECK-NEXT: "QualName": "PreIncrementable", // CHECK-NEXT: "USR": "{{[0-9A-F]*}}" // CHECK-NEXT: } 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 8ba6adc66a54b..0c2459df45f91 100644 --- a/clang-tools-extra/test/clang-doc/json/function-requires.cpp +++ b/clang-tools-extra/test/clang-doc/json/function-requires.cpp @@ -37,7 +37,6 @@ template Incrementable auto incrementTwo(T t); // CHECK-NEXT: "End": true, // CHECK-NEXT: "Expression": "Incrementable", // CHECK-NEXT: "Name": "Incrementable", -// CHECK-NEXT: "Path": "", // CHECK-NEXT: "QualName": "Incrementable", // CHECK-NEXT: "USR": "{{[0-9A-F]*}}" // CHECK-NEXT: } @@ -73,7 +72,6 @@ template Incrementable auto incrementTwo(T t); // CHECK-NEXT: "End": true, // CHECK-NEXT: "Expression": "Incrementable", // CHECK-NEXT: "Name": "Incrementable", -// CHECK-NEXT: "Path": "", // CHECK-NEXT: "QualName": "Incrementable", // CHECK-NEXT: "USR": "{{[0-9A-F]*}}" // 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 c1370d9fe379f..200246e87b516 100644 --- a/clang-tools-extra/test/clang-doc/json/namespace.cpp +++ b/clang-tools-extra/test/clang-doc/json/namespace.cpp @@ -80,7 +80,6 @@ typedef int MyTypedef; // CHECK-NEXT: { // CHECK-NEXT: "End": true, // CHECK-NEXT: "Name": "NestedNamespace", -// CHECK-NEXT: "Path": "", // CHECK-NEXT: "QualName": "NestedNamespace", // CHECK-NEXT: "USR": "{{[0-9A-F]*}}" // CHECK-NEXT: } diff --git a/clang-tools-extra/test/clang-doc/namespace.cpp b/clang-tools-extra/test/clang-doc/namespace.cpp index 8580ea6739a21..79b1ab8833261 100644 --- a/clang-tools-extra/test/clang-doc/namespace.cpp +++ b/clang-tools-extra/test/clang-doc/namespace.cpp @@ -1,7 +1,7 @@ // RUN: rm -rf %t && mkdir -p %t // RUN: clang-doc --format=html --output=%t --executor=standalone %s // RUN: clang-doc --format=md --output=%t --executor=standalone %s -// RUN: FileCheck %s < %t/@nonymous_namespace/AnonClass.md -check-prefix=MD-ANON-CLASS-LINE +// run: filecheck %s < %t/@nonymous_namespace/anonclass.md -check-prefix=md-anon-class-line // RUN: FileCheck %s < %t/@nonymous_namespace/AnonClass.md -check-prefix=MD-ANON-CLASS // RUN: FileCheck %s < %t/@nonymous_namespace/index.md -check-prefix=MD-ANON-INDEX-LINE // RUN: FileCheck %s < %t/@nonymous_namespace/index.md -check-prefix=MD-ANON-INDEX diff --git a/clang-tools-extra/unittests/clang-doc/JSONGeneratorTest.cpp b/clang-tools-extra/unittests/clang-doc/JSONGeneratorTest.cpp index b468964630d45..0bbb14506bcbf 100644 --- a/clang-tools-extra/unittests/clang-doc/JSONGeneratorTest.cpp +++ b/clang-tools-extra/unittests/clang-doc/JSONGeneratorTest.cpp @@ -135,7 +135,6 @@ TEST_F(JSONGeneratorTest, emitRecordJSON) { { "End": true, "Name": "F", - "Path": "", "QualName": "", "USR": "0000000000000000000000000000000000000000" }