From 85b0b75fca624aaf4a059fa1f1beefa790c5ed64 Mon Sep 17 00:00:00 2001 From: Erick Velez Date: Thu, 13 Nov 2025 20:23:17 -0800 Subject: [PATCH 1/3] fix unittest --- clang-tools-extra/clang-doc/JSONGenerator.cpp | 1 + clang-tools-extra/clang-doc/assets/class-template.mustache | 4 ++-- clang-tools-extra/test/clang-doc/basic-project.mustache.test | 2 +- clang-tools-extra/test/clang-doc/json/class.cpp | 2 ++ clang-tools-extra/unittests/clang-doc/JSONGeneratorTest.cpp | 2 ++ 5 files changed, 8 insertions(+), 3 deletions(-) diff --git a/clang-tools-extra/clang-doc/JSONGenerator.cpp b/clang-tools-extra/clang-doc/JSONGenerator.cpp index 77aa8794561e4..0253ebf5335da 100644 --- a/clang-tools-extra/clang-doc/JSONGenerator.cpp +++ b/clang-tools-extra/clang-doc/JSONGenerator.cpp @@ -551,6 +551,7 @@ static void serializeInfo(const RecordInfo &I, json::Object &Obj, auto &MemberObj = *MemberVal.getAsObject(); MemberObj["Name"] = Member.Name; MemberObj["Type"] = Member.Type.Name; + MemberObj["IsStatic"] = Member.IsStatic; if (Member.Access == AccessSpecifier::AS_public) PubMembersArrayRef.push_back(MemberVal); diff --git a/clang-tools-extra/clang-doc/assets/class-template.mustache b/clang-tools-extra/clang-doc/assets/class-template.mustache index 1197e76ab553c..22cd5f06894a4 100644 --- a/clang-tools-extra/clang-doc/assets/class-template.mustache +++ b/clang-tools-extra/clang-doc/assets/class-template.mustache @@ -154,7 +154,7 @@
{{#PublicMembers}}
-
{{Type}} {{Name}}
+
{{#IsStatic}}static {{/IsStatic}}{{Type}} {{Name}}
{{#MemberComments}}
{{>Comments}} @@ -171,7 +171,7 @@
{{#Obj}}
-
{{Type}} {{Name}}
+
{{#IsStatic}}static {{/IsStatic}}{{Type}} {{Name}}
{{#MemberComments}}
{{>Comments}} diff --git a/clang-tools-extra/test/clang-doc/basic-project.mustache.test b/clang-tools-extra/test/clang-doc/basic-project.mustache.test index b985a39265de7..d406c9f297960 100644 --- a/clang-tools-extra/test/clang-doc/basic-project.mustache.test +++ b/clang-tools-extra/test/clang-doc/basic-project.mustache.test @@ -204,7 +204,7 @@ HTML-CALC:
HTML-CALC:
int public_val
HTML-CALC:
HTML-CALC:
-HTML-CALC:
const int static_val
+HTML-CALC:
static const int static_val
HTML-CALC:
HTML-CALC:
HTML-CALC: diff --git a/clang-tools-extra/test/clang-doc/json/class.cpp b/clang-tools-extra/test/clang-doc/json/class.cpp index 8bf9402adf054..9d3102a11db9d 100644 --- a/clang-tools-extra/test/clang-doc/json/class.cpp +++ b/clang-tools-extra/test/clang-doc/json/class.cpp @@ -158,6 +158,7 @@ struct MyClass { // CHECK-NEXT: ], // CHECK-NEXT: "ProtectedMembers": [ // CHECK-NEXT: { +// CHECK-NEXT: "IsStatic": false, // CHECK-NEXT: "Name": "ProtectedField", // CHECK-NEXT: "Type": "int" // CHECK-NEXT: } @@ -198,6 +199,7 @@ struct MyClass { // CHECK-NEXT: }, // CHECK: "PublicMembers": [ // CHECK-NEXT: { +// CHECK-NEXT: "IsStatic": false, // CHECK-NEXT: "Name": "PublicField", // CHECK-NEXT: "Type": "int" // CHECK-NEXT: } diff --git a/clang-tools-extra/unittests/clang-doc/JSONGeneratorTest.cpp b/clang-tools-extra/unittests/clang-doc/JSONGeneratorTest.cpp index bd437553961f6..d5ce34d2b984c 100644 --- a/clang-tools-extra/unittests/clang-doc/JSONGeneratorTest.cpp +++ b/clang-tools-extra/unittests/clang-doc/JSONGeneratorTest.cpp @@ -90,6 +90,7 @@ TEST_F(JSONGeneratorTest, emitRecordJSON) { ], "PublicMembers": [ { + "IsStatic": false, "Name": "N", "Type": "int" } @@ -140,6 +141,7 @@ TEST_F(JSONGeneratorTest, emitRecordJSON) { "Path": "GlobalNamespace", "ProtectedMembers": [ { + "IsStatic": false, "Name": "X", "Type": "int" } From 45d8e8a1662089056d2293c631b617ab22986f60 Mon Sep 17 00:00:00 2001 From: Erick Velez Date: Sun, 16 Nov 2025 12:43:44 -0800 Subject: [PATCH 2/3] fix unittest --- clang-tools-extra/clang-doc/JSONGenerator.cpp | 8 +- .../test/clang-doc/json/inheritance.cpp | 111 ++++++++++++++++++ .../unittests/clang-doc/JSONGeneratorTest.cpp | 2 + 3 files changed, 119 insertions(+), 2 deletions(-) create mode 100644 clang-tools-extra/test/clang-doc/json/inheritance.cpp diff --git a/clang-tools-extra/clang-doc/JSONGenerator.cpp b/clang-tools-extra/clang-doc/JSONGenerator.cpp index 0253ebf5335da..c65c3dc759c3e 100644 --- a/clang-tools-extra/clang-doc/JSONGenerator.cpp +++ b/clang-tools-extra/clang-doc/JSONGenerator.cpp @@ -572,12 +572,16 @@ static void serializeInfo(const RecordInfo &I, json::Object &Obj, serializeInfo(Base, BaseObj, RepositoryUrl); }); - if (!I.Parents.empty()) + if (!I.Parents.empty()) { serializeArray(I.Parents, Obj, "Parents", SerializeReferenceLambda); + Obj["HasParents"] = true; + } - if (!I.VirtualParents.empty()) + if (!I.VirtualParents.empty()) { serializeArray(I.VirtualParents, Obj, "VirtualParents", SerializeReferenceLambda); + Obj["HasVirtualParents"] = true; + } if (I.Template) serializeInfo(I.Template.value(), Obj); diff --git a/clang-tools-extra/test/clang-doc/json/inheritance.cpp b/clang-tools-extra/test/clang-doc/json/inheritance.cpp new file mode 100644 index 0000000000000..53476da870c61 --- /dev/null +++ b/clang-tools-extra/test/clang-doc/json/inheritance.cpp @@ -0,0 +1,111 @@ +// RUN: rm -rf %t && mkdir -p %t +// RUN: clang-doc --output=%t --format=json --executor=standalone %s +// RUN: FileCheck %s < %t/json/GlobalNamespace/_ZTV7MyClass.json + +class Virtual {}; +class Foo : virtual Virtual {}; +class Bar : Foo {}; +class Fizz : virtual Virtual {}; +class Buzz : Fizz {}; + +class MyClass : Bar, Buzz {}; + +// CHECK: "Bases": [ +// CHECK-NEXT: { +// CHECK-NEXT: "Access": "private", +// CHECK-NEXT: "InfoType": "record", +// CHECK-NEXT: "IsParent": true, +// CHECK-NEXT: "IsTypedef": false, +// CHECK-NEXT: "IsVirtual": false, +// CHECK-NEXT: "MangledName": "", +// CHECK-NEXT: "Name": "Bar", +// CHECK-NEXT: "Path": "GlobalNamespace", +// CHECK-NEXT: "TagType": "struct", +// CHECK-NEXT: "USR": "{{[0-9A-F]*}}" +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "Access": "private", +// CHECK-NEXT: "InfoType": "record", +// CHECK-NEXT: "IsParent": false, +// CHECK-NEXT: "IsTypedef": false, +// CHECK-NEXT: "IsVirtual": false, +// CHECK-NEXT: "MangledName": "", +// CHECK-NEXT: "Name": "Foo", +// CHECK-NEXT: "Path": "GlobalNamespace", +// CHECK-NEXT: "TagType": "struct", +// CHECK-NEXT: "USR": "{{[0-9A-F]*}}" +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "Access": "private", +// CHECK-NEXT: "InfoType": "record", +// CHECK-NEXT: "IsParent": false, +// CHECK-NEXT: "IsTypedef": false, +// CHECK-NEXT: "IsVirtual": true, +// CHECK-NEXT: "MangledName": "", +// CHECK-NEXT: "Name": "Virtual", +// CHECK-NEXT: "Path": "GlobalNamespace", +// CHECK-NEXT: "TagType": "struct", +// CHECK-NEXT: "USR": "{{[0-9A-F]*}}" +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "Access": "private", +// CHECK-NEXT: "InfoType": "record", +// CHECK-NEXT: "IsParent": true, +// CHECK-NEXT: "IsTypedef": false, +// CHECK-NEXT: "IsVirtual": false, +// CHECK-NEXT: "MangledName": "", +// CHECK-NEXT: "Name": "Buzz", +// CHECK-NEXT: "Path": "GlobalNamespace", +// CHECK-NEXT: "TagType": "struct", +// CHECK-NEXT: "USR": "{{[0-9A-F]*}}" +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "Access": "private", +// CHECK-NEXT: "InfoType": "record", +// CHECK-NEXT: "IsParent": false, +// CHECK-NEXT: "IsTypedef": false, +// CHECK-NEXT: "IsVirtual": false, +// CHECK-NEXT: "MangledName": "", +// CHECK-NEXT: "Name": "Fizz", +// CHECK-NEXT: "Path": "GlobalNamespace", +// CHECK-NEXT: "TagType": "struct", +// CHECK-NEXT: "USR": "{{[0-9A-F]*}}" +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "Access": "private", +// CHECK-NEXT: "End": true, +// CHECK-NEXT: "InfoType": "record", +// CHECK-NEXT: "IsParent": false, +// CHECK-NEXT: "IsTypedef": false, +// CHECK-NEXT: "IsVirtual": true, +// CHECK-NEXT: "MangledName": "", +// CHECK-NEXT: "Name": "Virtual", +// CHECK-NEXT: "Path": "GlobalNamespace", +// CHECK-NEXT: "TagType": "struct", +// CHECK-NEXT: "USR": "{{[0-9A-F]*}}" +// CHECK-NEXT: } +// CHECK-NEXT: ], +// CHECK: "Parents": [ +// CHECK-NEXT: { +// CHECK-NEXT: "Name": "Bar", +// CHECK-NEXT: "Path": "GlobalNamespace", +// CHECK-NEXT: "QualName": "Bar", +// CHECK-NEXT: "USR": "{{[0-9A-F]*}}" +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "End": true, +// CHECK-NEXT: "Name": "Buzz", +// CHECK-NEXT: "Path": "GlobalNamespace", +// CHECK-NEXT: "QualName": "Buzz", +// CHECK-NEXT: "USR": "{{[0-9A-F]*}}" +// CHECK-NEXT: } +// CHECK-NEXT: ], +// CHECK: "VirtualParents": [ +// CHECK-NEXT: { +// CHECK-NEXT: "End": true, +// CHECK-NEXT: "Name": "Virtual", +// CHECK-NEXT: "Path": "GlobalNamespace", +// CHECK-NEXT: "QualName": "Virtual", +// CHECK-NEXT: "USR": "{{[0-9A-F]*}}" +// CHECK-NEXT: } +// CHECK-NEXT: ] \ No newline at end of file diff --git a/clang-tools-extra/unittests/clang-doc/JSONGeneratorTest.cpp b/clang-tools-extra/unittests/clang-doc/JSONGeneratorTest.cpp index d5ce34d2b984c..bcb9fd8e47bc6 100644 --- a/clang-tools-extra/unittests/clang-doc/JSONGeneratorTest.cpp +++ b/clang-tools-extra/unittests/clang-doc/JSONGeneratorTest.cpp @@ -116,8 +116,10 @@ TEST_F(JSONGeneratorTest, emitRecordJSON) { } ], "HasEnums": true, + "HasParents": true, "HasPublicFunctions": true, "HasRecords": true, + "HasVirtualParents": true, "InfoType": "record", "IsTypedef": false, "Location": { From 0be4b3662d1b660562cc37d0d155bbc04036576f Mon Sep 17 00:00:00 2001 From: Erick Velez Date: Sun, 16 Nov 2025 13:38:47 -0800 Subject: [PATCH 3/3] [clang-doc] Serialize private members in JSON --- clang-tools-extra/clang-doc/JSONGenerator.cpp | 6 ++++++ clang-tools-extra/test/clang-doc/json/class.cpp | 10 ++++++++++ 2 files changed, 16 insertions(+) diff --git a/clang-tools-extra/clang-doc/JSONGenerator.cpp b/clang-tools-extra/clang-doc/JSONGenerator.cpp index c65c3dc759c3e..c47c65ddc2d73 100644 --- a/clang-tools-extra/clang-doc/JSONGenerator.cpp +++ b/clang-tools-extra/clang-doc/JSONGenerator.cpp @@ -545,6 +545,8 @@ static void serializeInfo(const RecordInfo &I, json::Object &Obj, json::Array &PubMembersArrayRef = *PublicMembersArray.getAsArray(); json::Value ProtectedMembersArray = Array(); json::Array &ProtMembersArrayRef = *ProtectedMembersArray.getAsArray(); + json::Value PrivateMembersArray = Array(); + json::Array &PrivateMembersArrayRef = *PrivateMembersArray.getAsArray(); for (const MemberTypeInfo &Member : I.Members) { json::Value MemberVal = Object(); @@ -557,12 +559,16 @@ static void serializeInfo(const RecordInfo &I, json::Object &Obj, PubMembersArrayRef.push_back(MemberVal); else if (Member.Access == AccessSpecifier::AS_protected) ProtMembersArrayRef.push_back(MemberVal); + else if (Member.Access == AccessSpecifier::AS_private) + PrivateMembersArrayRef.push_back(MemberVal); } if (!PubMembersArrayRef.empty()) insertArray(Obj, PublicMembersArray, "PublicMembers"); if (!ProtMembersArrayRef.empty()) Obj["ProtectedMembers"] = ProtectedMembersArray; + if (!PrivateMembersArrayRef.empty()) + insertArray(Obj, PrivateMembersArray, "PrivateMembers"); } if (!I.Bases.empty()) diff --git a/clang-tools-extra/test/clang-doc/json/class.cpp b/clang-tools-extra/test/clang-doc/json/class.cpp index 9d3102a11db9d..d57e8a990c3fe 100644 --- a/clang-tools-extra/test/clang-doc/json/class.cpp +++ b/clang-tools-extra/test/clang-doc/json/class.cpp @@ -30,6 +30,8 @@ struct MyClass { int protectedMethod(); int ProtectedField; +private: + int PrivateField; }; // CHECK: { @@ -122,6 +124,7 @@ struct MyClass { // CHECK-NEXT: } // CHECK-NEXT: ], // CHECK-NEXT: "HasEnums": true, +// CHECK-NEXT: "HasPrivateMembers": true, // CHECK-NEXT: "HasPublicFunctions": true, // CHECK-NEXT: "HasPublicMembers": true, // CHECK-NEXT: "HasRecords": true, @@ -137,6 +140,13 @@ struct MyClass { // CHECK-NEXT: "GlobalNamespace" // CHECK-NEXT: ], // CHECK-NEXT: "Path": "GlobalNamespace", +// CHECK-NEXT: "PrivateMembers": [ +// CHECK-NEXT: { +// CHECK-NEXT: "IsStatic": false, +// CHECK-NEXT: "Name": "PrivateField", +// CHECK-NEXT: "Type": "int" +// CHECK-NEXT: } +// CHECK-NEXT: ], // CHECK-NEXT: "ProtectedFunctions": [ // CHECK-NEXT: { // CHECK-NEXT: "InfoType": "function",