Skip to content

Commit 979bfbf

Browse files
committed
[clang-doc] add namespaces to JSON generator
1 parent 54287df commit 979bfbf

File tree

5 files changed

+243
-0
lines changed

5 files changed

+243
-0
lines changed

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

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,41 @@ static void serializeInfo(const RecordInfo &I, json::Object &Obj,
446446
serializeCommonChildren(I.Children, Obj, RepositoryUrl);
447447
}
448448

449+
static void serializeInfo(const NamespaceInfo &I, json::Object &Obj,
450+
std::optional<StringRef> RepositoryUrl) {
451+
serializeCommonAttributes(I, Obj, RepositoryUrl);
452+
SmallString<64> BasePath = I.getRelativeFilePath("");
453+
Obj["NamespacePath"] = BasePath;
454+
455+
if (!I.Children.Namespaces.empty()) {
456+
json::Value NamespacesArray = Array();
457+
auto &NamespacesArrayRef = *NamespacesArray.getAsArray();
458+
NamespacesArrayRef.reserve(I.Children.Namespaces.size());
459+
for (auto &Namespace : I.Children.Namespaces) {
460+
json::Value NamespaceVal = Object();
461+
auto &NamespaceObj = *NamespaceVal.getAsObject();
462+
serializeReference(Namespace, NamespaceObj, BasePath);
463+
NamespacesArrayRef.push_back(NamespaceVal);
464+
}
465+
Obj["Namespaces"] = NamespacesArray;
466+
}
467+
468+
if (!I.Children.Functions.empty()) {
469+
json::Value FunctionsArray = Array();
470+
auto &FunctionsArrayRef = *FunctionsArray.getAsArray();
471+
FunctionsArrayRef.reserve(I.Children.Functions.size());
472+
for (const auto &Function : I.Children.Functions) {
473+
json::Value FunctionVal = Object();
474+
auto &FunctionObj = *FunctionVal.getAsObject();
475+
serializeInfo(Function, FunctionObj, RepositoryUrl);
476+
FunctionsArrayRef.push_back(FunctionVal);
477+
}
478+
Obj["Functions"] = FunctionsArray;
479+
}
480+
481+
serializeCommonChildren(I.Children, Obj, RepositoryUrl);
482+
}
483+
449484
Error JSONGenerator::generateDocs(
450485
StringRef RootDir, llvm::StringMap<std::unique_ptr<doc::Info>> Infos,
451486
const ClangDocContext &CDCtx) {
@@ -488,6 +523,7 @@ Error JSONGenerator::generateDocForInfo(Info *I, raw_ostream &OS,
488523

489524
switch (I->IT) {
490525
case InfoType::IT_namespace:
526+
serializeInfo(*static_cast<NamespaceInfo *>(I), Obj, CDCtx.RepositoryUrl);
491527
break;
492528
case InfoType::IT_record:
493529
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: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
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: "NamespacePath": "GlobalNamespace",
71+
// CHECK-NEXT: "Namespaces": [
72+
// CHECK-NEXT: {
73+
// CHECK-NEXT: "Link": "../NestedNamespace/index.json",
74+
// CHECK-NEXT: "Name": "NestedNamespace",
75+
// CHECK-NEXT: "QualName": "NestedNamespace",
76+
// CHECK-NEXT: "USR": "{{[0-9A-F]*}}"
77+
// CHECK-NEXT: }
78+
// CHECK-NEXT: ],
79+
// CHECK-NEXT: "Records": [
80+
// CHECK-NEXT: {
81+
// CHECK-NEXT: "Link": "MyClass.json",
82+
// CHECK-NEXT: "Name": "MyClass",
83+
// CHECK-NEXT: "QualName": "MyClass",
84+
// CHECK-NEXT: "USR": "{{[0-9A-F]*}}"
85+
// CHECK-NEXT: }
86+
// CHECK-NEXT: ],
87+
// CHECK-NEXT: "Typedefs": [
88+
// CHECK-NEXT: {
89+
// CHECK-NEXT: "IsUsing": false,
90+
// CHECK-NEXT: "Location": {
91+
// CHECK-NEXT: "Filename": "{{.*}}namespace.cpp",
92+
// CHECK-NEXT: "LineNumber": 21
93+
// CHECK-NEXT: },
94+
// CHECK-NEXT: "Name": "MyTypedef",
95+
// CHECK-NEXT: "TypeDeclaration": "",
96+
// CHECK-NEXT: "USR": "{{[0-9A-F]*}}",
97+
// CHECK-NEXT: "Underlying": {
98+
// CHECK-NEXT: "IsBuiltIn": false,
99+
// CHECK-NEXT: "IsTemplate": false,
100+
// CHECK-NEXT: "Name": "int",
101+
// CHECK-NEXT: "QualName": "int",
102+
// CHECK-NEXT: "USR": "0000000000000000000000000000000000000000"
103+
// CHECK-NEXT: }
104+
// CHECK-NEXT: }
105+
// CHECK-NEXT: ],
106+
// CHECK-NEXT: "USR": "0000000000000000000000000000000000000000"
107+
// CHECK-NOT: "Variables": [
108+
// CHECK-NEXT: }

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

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,5 +171,78 @@ 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+
"NamespacePath": "path/to/A/Namespace",
226+
"Namespaces": [
227+
{
228+
"Link": "ChildNamespace/index.json",
229+
"Name": "ChildNamespace",
230+
"QualName": "path::to::A::Namespace::ChildNamespace",
231+
"USR": "0000000000000000000000000000000000000000"
232+
}
233+
],
234+
"Path": "path/to/A",
235+
"Records": [
236+
{
237+
"Link": "ChildStruct.json",
238+
"Name": "ChildStruct",
239+
"QualName": "path::to::A::Namespace::ChildStruct",
240+
"USR": "0000000000000000000000000000000000000000"
241+
}
242+
],
243+
"USR": "0000000000000000000000000000000000000000"
244+
})raw";
245+
EXPECT_EQ(Expected, Actual.str());
246+
}
174247
} // namespace doc
175248
} // namespace clang

0 commit comments

Comments
 (0)