https://github.com/evelez7 updated https://github.com/llvm/llvm-project/pull/143209
>From 5044202d0462e22fcf5b053909bea5e432d41a67 Mon Sep 17 00:00:00 2001 From: Erick Velez <erickvel...@gmail.com> Date: Tue, 3 Jun 2025 11:39:48 -0700 Subject: [PATCH] [clang-doc] add namespaces to JSON generator --- clang-tools-extra/clang-doc/JSONGenerator.cpp | 34 ++++++ clang-tools-extra/clang-doc/Serialize.cpp | 1 + .../clang-doc/json/function-specifiers.cpp | 26 +++++ .../test/clang-doc/json/namespace.cpp | 108 ++++++++++++++++++ .../unittests/clang-doc/JSONGeneratorTest.cpp | 73 ++++++++++++ 5 files changed, 242 insertions(+) create mode 100644 clang-tools-extra/test/clang-doc/json/function-specifiers.cpp create mode 100644 clang-tools-extra/test/clang-doc/json/namespace.cpp diff --git a/clang-tools-extra/clang-doc/JSONGenerator.cpp b/clang-tools-extra/clang-doc/JSONGenerator.cpp index ef9c147f1a5e2..c8419332a437d 100644 --- a/clang-tools-extra/clang-doc/JSONGenerator.cpp +++ b/clang-tools-extra/clang-doc/JSONGenerator.cpp @@ -446,6 +446,39 @@ static void serializeInfo(const RecordInfo &I, json::Object &Obj, serializeCommonChildren(I.Children, Obj, RepositoryUrl); } +static void serializeInfo(const NamespaceInfo &I, json::Object &Obj, + std::optional<StringRef> RepositoryUrl) { + serializeCommonAttributes(I, Obj, RepositoryUrl); + SmallString<64> BasePath = I.getRelativeFilePath(""); + Obj["NamespacePath"] = BasePath; + + if (!I.Children.Namespaces.empty()) { + json::Value NamespacesArray = Array(); + auto &NamespacesArrayRef = *NamespacesArray.getAsArray(); + for (auto &Namespace : I.Children.Namespaces) { + json::Value NamespaceVal = Object(); + auto &NamespaceObj = *NamespaceVal.getAsObject(); + serializeReference(Namespace, NamespaceObj, BasePath); + NamespacesArrayRef.push_back(NamespaceVal); + } + Obj["Namespaces"] = NamespacesArray; + } + + if (!I.Children.Functions.empty()) { + json::Value FunctionsArray = Array(); + auto &FunctionsArrayRef = *FunctionsArray.getAsArray(); + for (const auto &Function : I.Children.Functions) { + json::Value FunctionVal = Object(); + auto &FunctionObj = *FunctionVal.getAsObject(); + serializeInfo(Function, FunctionObj, RepositoryUrl); + FunctionsArrayRef.push_back(FunctionVal); + } + Obj["Functions"] = FunctionsArray; + } + + serializeCommonChildren(I.Children, Obj, RepositoryUrl); +} + Error JSONGenerator::generateDocs( StringRef RootDir, llvm::StringMap<std::unique_ptr<doc::Info>> Infos, const ClangDocContext &CDCtx) { @@ -488,6 +521,7 @@ Error JSONGenerator::generateDocForInfo(Info *I, raw_ostream &OS, switch (I->IT) { case InfoType::IT_namespace: + serializeInfo(*static_cast<NamespaceInfo *>(I), Obj, CDCtx.RepositoryUrl); break; case InfoType::IT_record: serializeInfo(*static_cast<RecordInfo *>(I), Obj, CDCtx.RepositoryUrl); diff --git a/clang-tools-extra/clang-doc/Serialize.cpp b/clang-tools-extra/clang-doc/Serialize.cpp index 462001b3f3027..3cda38115ff7f 100644 --- a/clang-tools-extra/clang-doc/Serialize.cpp +++ b/clang-tools-extra/clang-doc/Serialize.cpp @@ -742,6 +742,7 @@ static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D, I.ReturnType = getTypeInfoForType(D->getReturnType(), LO); I.Prototype = getFunctionPrototype(D); parseParameters(I, D); + I.IsStatic = D->isStatic(); populateTemplateParameters(I.Template, D); diff --git a/clang-tools-extra/test/clang-doc/json/function-specifiers.cpp b/clang-tools-extra/test/clang-doc/json/function-specifiers.cpp new file mode 100644 index 0000000000000..dab4c559d0b6e --- /dev/null +++ b/clang-tools-extra/test/clang-doc/json/function-specifiers.cpp @@ -0,0 +1,26 @@ +// RUN: rm -rf %t && mkdir -p %t +// RUN: clang-doc --output=%t --format=json --executor=standalone %s +// RUN: FileCheck %s < %t/GlobalNamespace/index.json + +static void myFunction() {} + +void noExceptFunction() noexcept {} + +inline void inlineFunction() {} + +extern void externFunction() {} + +constexpr void constexprFunction() {} + +// CHECK: "Functions": [ +// CHECK-NEXT: { +// CHECK: "IsStatic": true, +// COM: FIXME: Emit ExceptionSpecificationType +// CHECK-NOT: "ExceptionSpecifcation" : "noexcept", +// COM: FIXME: Emit inline +// CHECK-NOT: "IsInline": true, +// COM: FIXME: Emit extern +// CHECK-NOT: "IsExtern": true, +// COM: FIXME: Emit constexpr +// CHECK-NOT: "IsConstexpr": true, +// CHECK-NOT: "IsConstexpr": true, diff --git a/clang-tools-extra/test/clang-doc/json/namespace.cpp b/clang-tools-extra/test/clang-doc/json/namespace.cpp new file mode 100644 index 0000000000000..885dbd841ac2e --- /dev/null +++ b/clang-tools-extra/test/clang-doc/json/namespace.cpp @@ -0,0 +1,108 @@ +// RUN: rm -rf %t && mkdir -p %t +// RUN: clang-doc --output=%t --format=json --executor=standalone %s +// RUN: FileCheck %s < %t/GlobalNamespace/index.json + +class MyClass {}; + +void myFunction(int Param); + +namespace NestedNamespace { +} // namespace NestedNamespace + +// FIXME: Global variables are not mapped or serialized. +static int Global; + +enum Color { + RED, + GREEN, + BLUE = 5 +}; + +typedef int MyTypedef; + +// CHECK: { +// CHECK-NEXT: "Enums": [ +// CHECK-NEXT: { +// CHECK-NEXT: "Location": { +// CHECK-NEXT: "Filename": "{{.*}}namespace.cpp", +// CHECK-NEXT: "LineNumber": 15 +// CHECK-NEXT: }, +// CHECK-NEXT: "Members": [ +// CHECK-NEXT: { +// CHECK-NEXT: "Name": "RED", +// CHECK-NEXT: "Value": "0" +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "Name": "GREEN", +// CHECK-NEXT: "Value": "1" +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "Name": "BLUE", +// CHECK-NEXT: "ValueExpr": "5" +// CHECK-NEXT: } +// CHECK-NEXT: ], +// CHECK-NEXT: "Name": "Color", +// CHECK-NEXT: "Scoped": false, +// CHECK-NEXT: "USR": "{{[0-9A-F]*}}" +// CHECK-NEXT: } +// CHECK-NEXT: ], +// CHECK-NEXT: "Functions": [ +// CHECK-NEXT: { +// CHECK-NEXT: "IsStatic": false, +// CHECK-NEXT: "Name": "myFunction", +// CHECK-NEXT: "Params": [ +// CHECK-NEXT: { +// CHECK-NEXT: "Name": "Param", +// CHECK-NEXT: "Type": "int" +// CHECK-NEXT: } +// CHECK-NEXT: ], +// CHECK-NEXT: "ReturnType": { +// CHECK-NEXT: "IsBuiltIn": false, +// CHECK-NEXT: "IsTemplate": false, +// CHECK-NEXT: "Name": "void", +// CHECK-NEXT: "QualName": "void", +// CHECK-NEXT: "USR": "0000000000000000000000000000000000000000" +// CHECK-NEXT: }, +// CHECK-NEXT: "USR": "{{[0-9A-F]*}}" +// CHECK-NEXT: } +// CHECK-NEXT: ], +// CHECK-NEXT: "Name": "", +// CHECK-NEXT: "NamespacePath": "GlobalNamespace", +// CHECK-NEXT: "Namespaces": [ +// CHECK-NEXT: { +// CHECK-NEXT: "Link": "../NestedNamespace/index.json", +// CHECK-NEXT: "Name": "NestedNamespace", +// CHECK-NEXT: "QualName": "NestedNamespace", +// CHECK-NEXT: "USR": "{{[0-9A-F]*}}" +// CHECK-NEXT: } +// CHECK-NEXT: ], +// CHECK-NEXT: "Records": [ +// CHECK-NEXT: { +// CHECK-NEXT: "Link": "MyClass.json", +// CHECK-NEXT: "Name": "MyClass", +// CHECK-NEXT: "QualName": "MyClass", +// CHECK-NEXT: "USR": "{{[0-9A-F]*}}" +// CHECK-NEXT: } +// CHECK-NEXT: ], +// CHECK-NEXT: "Typedefs": [ +// CHECK-NEXT: { +// CHECK-NEXT: "IsUsing": false, +// CHECK-NEXT: "Location": { +// CHECK-NEXT: "Filename": "{{.*}}namespace.cpp", +// CHECK-NEXT: "LineNumber": 21 +// CHECK-NEXT: }, +// CHECK-NEXT: "Name": "MyTypedef", +// CHECK-NEXT: "TypeDeclaration": "", +// CHECK-NEXT: "USR": "{{[0-9A-F]*}}", +// CHECK-NEXT: "Underlying": { +// CHECK-NEXT: "IsBuiltIn": false, +// CHECK-NEXT: "IsTemplate": false, +// CHECK-NEXT: "Name": "int", +// CHECK-NEXT: "QualName": "int", +// CHECK-NEXT: "USR": "0000000000000000000000000000000000000000" +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-NEXT: ], +// CHECK-NEXT: "USR": "0000000000000000000000000000000000000000" +// CHECK-NOT: "Variables": [ +// CHECK-NEXT: } diff --git a/clang-tools-extra/unittests/clang-doc/JSONGeneratorTest.cpp b/clang-tools-extra/unittests/clang-doc/JSONGeneratorTest.cpp index 8e56c6fe3bae8..b60fe30993cd1 100644 --- a/clang-tools-extra/unittests/clang-doc/JSONGeneratorTest.cpp +++ b/clang-tools-extra/unittests/clang-doc/JSONGeneratorTest.cpp @@ -171,5 +171,78 @@ TEST(JSONGeneratorTest, emitRecordJSON) { })raw"; EXPECT_EQ(Expected, Actual.str()); } + +TEST(JSONGeneratorTest, emitNamespaceJSON) { + NamespaceInfo I; + I.Name = "Namespace"; + I.Path = "path/to/A"; + I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace); + + I.Children.Namespaces.emplace_back( + EmptySID, "ChildNamespace", InfoType::IT_namespace, + "path::to::A::Namespace::ChildNamespace", "path/to/A/Namespace"); + I.Children.Records.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record, + "path::to::A::Namespace::ChildStruct", + "path/to/A/Namespace"); + I.Children.Functions.emplace_back(); + I.Children.Functions.back().Name = "OneFunction"; + I.Children.Functions.back().Access = AccessSpecifier::AS_none; + I.Children.Enums.emplace_back(); + I.Children.Enums.back().Name = "OneEnum"; + + auto G = getJSONGenerator(); + assert(G); + std::string Buffer; + llvm::raw_string_ostream Actual(Buffer); + auto Err = G->generateDocForInfo(&I, Actual, ClangDocContext()); + assert(!Err); + std::string Expected = R"raw({ + "Enums": [ + { + "Name": "OneEnum", + "Scoped": false, + "USR": "0000000000000000000000000000000000000000" + } + ], + "Functions": [ + { + "IsStatic": false, + "Name": "OneFunction", + "ReturnType": { + "IsBuiltIn": false, + "IsTemplate": false, + "Name": "", + "QualName": "", + "USR": "0000000000000000000000000000000000000000" + }, + "USR": "0000000000000000000000000000000000000000" + } + ], + "Name": "Namespace", + "Namespace": [ + "A" + ], + "NamespacePath": "path/to/A/Namespace", + "Namespaces": [ + { + "Link": "ChildNamespace/index.json", + "Name": "ChildNamespace", + "QualName": "path::to::A::Namespace::ChildNamespace", + "USR": "0000000000000000000000000000000000000000" + } + ], + "Path": "path/to/A", + "Records": [ + { + "Link": "ChildStruct.json", + "Name": "ChildStruct", + "QualName": "path::to::A::Namespace::ChildStruct", + "USR": "0000000000000000000000000000000000000000" + } + ], + "USR": "0000000000000000000000000000000000000000" +})raw"; + EXPECT_EQ(Expected, Actual.str()); +} } // namespace doc } // namespace clang _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits