Skip to content

Commit 0325597

Browse files
evelez7tomtor
authored andcommitted
[clang-doc] add namespaces to JSON generator (llvm#143209)
Emit namespaces to JSON. Also adds tests for namespaces and non-member constructs.
1 parent 2f03a9d commit 0325597

File tree

5 files changed

+239
-0
lines changed

5 files changed

+239
-0
lines changed

clang-tools-extra/clang-doc/JSONGenerator.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,39 @@ static void serializeInfo(const RecordInfo &I, json::Object &Obj,
440440
serializeCommonChildren(I.Children, Obj, RepositoryUrl);
441441
}
442442

443+
static void serializeInfo(const NamespaceInfo &I, json::Object &Obj,
444+
std::optional<StringRef> RepositoryUrl) {
445+
serializeCommonAttributes(I, Obj, RepositoryUrl);
446+
447+
if (!I.Children.Namespaces.empty()) {
448+
json::Value NamespacesArray = Array();
449+
auto &NamespacesArrayRef = *NamespacesArray.getAsArray();
450+
NamespacesArrayRef.reserve(I.Children.Namespaces.size());
451+
for (auto &Namespace : I.Children.Namespaces) {
452+
json::Value NamespaceVal = Object();
453+
auto &NamespaceObj = *NamespaceVal.getAsObject();
454+
serializeReference(Namespace, NamespaceObj);
455+
NamespacesArrayRef.push_back(NamespaceVal);
456+
}
457+
Obj["Namespaces"] = NamespacesArray;
458+
}
459+
460+
if (!I.Children.Functions.empty()) {
461+
json::Value FunctionsArray = Array();
462+
auto &FunctionsArrayRef = *FunctionsArray.getAsArray();
463+
FunctionsArrayRef.reserve(I.Children.Functions.size());
464+
for (const auto &Function : I.Children.Functions) {
465+
json::Value FunctionVal = Object();
466+
auto &FunctionObj = *FunctionVal.getAsObject();
467+
serializeInfo(Function, FunctionObj, RepositoryUrl);
468+
FunctionsArrayRef.push_back(FunctionVal);
469+
}
470+
Obj["Functions"] = FunctionsArray;
471+
}
472+
473+
serializeCommonChildren(I.Children, Obj, RepositoryUrl);
474+
}
475+
443476
Error JSONGenerator::generateDocs(
444477
StringRef RootDir, llvm::StringMap<std::unique_ptr<doc::Info>> Infos,
445478
const ClangDocContext &CDCtx) {
@@ -482,6 +515,7 @@ Error JSONGenerator::generateDocForInfo(Info *I, raw_ostream &OS,
482515

483516
switch (I->IT) {
484517
case InfoType::IT_namespace:
518+
serializeInfo(*static_cast<NamespaceInfo *>(I), Obj, CDCtx.RepositoryUrl);
485519
break;
486520
case InfoType::IT_record:
487521
serializeInfo(*static_cast<RecordInfo *>(I), Obj, CDCtx.RepositoryUrl);

clang-tools-extra/clang-doc/Serialize.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -742,6 +742,7 @@ static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D,
742742
I.ReturnType = getTypeInfoForType(D->getReturnType(), LO);
743743
I.Prototype = getFunctionPrototype(D);
744744
parseParameters(I, D);
745+
I.IsStatic = D->isStatic();
745746

746747
populateTemplateParameters(I.Template, D);
747748

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// RUN: rm -rf %t && mkdir -p %t
2+
// RUN: clang-doc --output=%t --format=json --executor=standalone %s
3+
// RUN: FileCheck %s < %t/GlobalNamespace/index.json
4+
5+
static void myFunction() {}
6+
7+
void noExceptFunction() noexcept {}
8+
9+
inline void inlineFunction() {}
10+
11+
extern void externFunction() {}
12+
13+
constexpr void constexprFunction() {}
14+
15+
// CHECK: "Functions": [
16+
// CHECK-NEXT: {
17+
// CHECK: "IsStatic": true,
18+
// COM: FIXME: Emit ExceptionSpecificationType
19+
// CHECK-NOT: "ExceptionSpecifcation" : "noexcept",
20+
// COM: FIXME: Emit inline
21+
// CHECK-NOT: "IsInline": true,
22+
// COM: FIXME: Emit extern
23+
// CHECK-NOT: "IsExtern": true,
24+
// COM: FIXME: Emit constexpr
25+
// CHECK-NOT: "IsConstexpr": true,
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
// RUN: rm -rf %t && mkdir -p %t
2+
// RUN: clang-doc --output=%t --format=json --executor=standalone %s
3+
// RUN: FileCheck %s < %t/GlobalNamespace/index.json
4+
5+
class MyClass {};
6+
7+
void myFunction(int Param);
8+
9+
namespace NestedNamespace {
10+
} // namespace NestedNamespace
11+
12+
// FIXME: Global variables are not mapped or serialized.
13+
static int Global;
14+
15+
enum Color {
16+
RED,
17+
GREEN,
18+
BLUE = 5
19+
};
20+
21+
typedef int MyTypedef;
22+
23+
// CHECK: {
24+
// CHECK-NEXT: "Enums": [
25+
// CHECK-NEXT: {
26+
// CHECK-NEXT: "Location": {
27+
// CHECK-NEXT: "Filename": "{{.*}}namespace.cpp",
28+
// CHECK-NEXT: "LineNumber": 15
29+
// CHECK-NEXT: },
30+
// CHECK-NEXT: "Members": [
31+
// CHECK-NEXT: {
32+
// CHECK-NEXT: "Name": "RED",
33+
// CHECK-NEXT: "Value": "0"
34+
// CHECK-NEXT: },
35+
// CHECK-NEXT: {
36+
// CHECK-NEXT: "Name": "GREEN",
37+
// CHECK-NEXT: "Value": "1"
38+
// CHECK-NEXT: },
39+
// CHECK-NEXT: {
40+
// CHECK-NEXT: "Name": "BLUE",
41+
// CHECK-NEXT: "ValueExpr": "5"
42+
// CHECK-NEXT: }
43+
// CHECK-NEXT: ],
44+
// CHECK-NEXT: "Name": "Color",
45+
// CHECK-NEXT: "Scoped": false,
46+
// CHECK-NEXT: "USR": "{{[0-9A-F]*}}"
47+
// CHECK-NEXT: }
48+
// CHECK-NEXT: ],
49+
// CHECK-NEXT: "Functions": [
50+
// CHECK-NEXT: {
51+
// CHECK-NEXT: "IsStatic": false,
52+
// CHECK-NEXT: "Name": "myFunction",
53+
// CHECK-NEXT: "Params": [
54+
// CHECK-NEXT: {
55+
// CHECK-NEXT: "Name": "Param",
56+
// CHECK-NEXT: "Type": "int"
57+
// CHECK-NEXT: }
58+
// CHECK-NEXT: ],
59+
// CHECK-NEXT: "ReturnType": {
60+
// CHECK-NEXT: "IsBuiltIn": false,
61+
// CHECK-NEXT: "IsTemplate": false,
62+
// CHECK-NEXT: "Name": "void",
63+
// CHECK-NEXT: "QualName": "void",
64+
// CHECK-NEXT: "USR": "0000000000000000000000000000000000000000"
65+
// CHECK-NEXT: },
66+
// CHECK-NEXT: "USR": "{{[0-9A-F]*}}"
67+
// CHECK-NEXT: }
68+
// CHECK-NEXT: ],
69+
// CHECK-NEXT: "Name": "",
70+
// CHECK-NEXT: "Namespaces": [
71+
// CHECK-NEXT: {
72+
// CHECK-NEXT: "Name": "NestedNamespace",
73+
// CHECK-NEXT: "Path": "",
74+
// CHECK-NEXT: "QualName": "NestedNamespace",
75+
// CHECK-NEXT: "USR": "{{[0-9A-F]*}}"
76+
// CHECK-NEXT: }
77+
// CHECK-NEXT: ],
78+
// CHECK-NEXT: "Records": [
79+
// CHECK-NEXT: {
80+
// CHECK-NEXT: "Name": "MyClass",
81+
// CHECK-NEXT: "Path": "GlobalNamespace",
82+
// CHECK-NEXT: "QualName": "MyClass",
83+
// CHECK-NEXT: "USR": "{{[0-9A-F]*}}"
84+
// CHECK-NEXT: }
85+
// CHECK-NEXT: ],
86+
// CHECK-NEXT: "Typedefs": [
87+
// CHECK-NEXT: {
88+
// CHECK-NEXT: "IsUsing": false,
89+
// CHECK-NEXT: "Location": {
90+
// CHECK-NEXT: "Filename": "{{.*}}namespace.cpp",
91+
// CHECK-NEXT: "LineNumber": 21
92+
// CHECK-NEXT: },
93+
// CHECK-NEXT: "Name": "MyTypedef",
94+
// CHECK-NEXT: "TypeDeclaration": "",
95+
// CHECK-NEXT: "USR": "{{[0-9A-F]*}}",
96+
// CHECK-NEXT: "Underlying": {
97+
// CHECK-NEXT: "IsBuiltIn": false,
98+
// CHECK-NEXT: "IsTemplate": false,
99+
// CHECK-NEXT: "Name": "int",
100+
// CHECK-NEXT: "QualName": "int",
101+
// CHECK-NEXT: "USR": "0000000000000000000000000000000000000000"
102+
// CHECK-NEXT: }
103+
// CHECK-NEXT: }
104+
// CHECK-NEXT: ],
105+
// CHECK-NEXT: "USR": "0000000000000000000000000000000000000000"
106+
// CHECK-NOT: "Variables": [
107+
// CHECK-NEXT: }

clang-tools-extra/unittests/clang-doc/JSONGeneratorTest.cpp

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,5 +171,77 @@ TEST(JSONGeneratorTest, emitRecordJSON) {
171171
})raw";
172172
EXPECT_EQ(Expected, Actual.str());
173173
}
174+
175+
TEST(JSONGeneratorTest, emitNamespaceJSON) {
176+
NamespaceInfo I;
177+
I.Name = "Namespace";
178+
I.Path = "path/to/A";
179+
I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
180+
181+
I.Children.Namespaces.emplace_back(
182+
EmptySID, "ChildNamespace", InfoType::IT_namespace,
183+
"path::to::A::Namespace::ChildNamespace", "path/to/A/Namespace");
184+
I.Children.Records.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record,
185+
"path::to::A::Namespace::ChildStruct",
186+
"path/to/A/Namespace");
187+
I.Children.Functions.emplace_back();
188+
I.Children.Functions.back().Name = "OneFunction";
189+
I.Children.Functions.back().Access = AccessSpecifier::AS_none;
190+
I.Children.Enums.emplace_back();
191+
I.Children.Enums.back().Name = "OneEnum";
192+
193+
auto G = getJSONGenerator();
194+
assert(G);
195+
std::string Buffer;
196+
llvm::raw_string_ostream Actual(Buffer);
197+
auto Err = G->generateDocForInfo(&I, Actual, ClangDocContext());
198+
assert(!Err);
199+
std::string Expected = R"raw({
200+
"Enums": [
201+
{
202+
"Name": "OneEnum",
203+
"Scoped": false,
204+
"USR": "0000000000000000000000000000000000000000"
205+
}
206+
],
207+
"Functions": [
208+
{
209+
"IsStatic": false,
210+
"Name": "OneFunction",
211+
"ReturnType": {
212+
"IsBuiltIn": false,
213+
"IsTemplate": false,
214+
"Name": "",
215+
"QualName": "",
216+
"USR": "0000000000000000000000000000000000000000"
217+
},
218+
"USR": "0000000000000000000000000000000000000000"
219+
}
220+
],
221+
"Name": "Namespace",
222+
"Namespace": [
223+
"A"
224+
],
225+
"Namespaces": [
226+
{
227+
"Name": "ChildNamespace",
228+
"Path": "path/to/A/Namespace",
229+
"QualName": "path::to::A::Namespace::ChildNamespace",
230+
"USR": "0000000000000000000000000000000000000000"
231+
}
232+
],
233+
"Path": "path/to/A",
234+
"Records": [
235+
{
236+
"Name": "ChildStruct",
237+
"Path": "path/to/A/Namespace",
238+
"QualName": "path::to::A::Namespace::ChildStruct",
239+
"USR": "0000000000000000000000000000000000000000"
240+
}
241+
],
242+
"USR": "0000000000000000000000000000000000000000"
243+
})raw";
244+
EXPECT_EQ(Expected, Actual.str());
245+
}
174246
} // namespace doc
175247
} // namespace clang

0 commit comments

Comments
 (0)