Skip to content

Commit 25f5252

Browse files
committed
[clang-doc] refactor JSON for better Mustache compatibility
1 parent abdd453 commit 25f5252

17 files changed

+154
-13
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,8 @@ static llvm::Error parseRecord(const Record &R, unsigned ID,
384384
return decodeRecord(R, I->Path, Blob);
385385
case REFERENCE_FIELD:
386386
return decodeRecord(R, F, Blob);
387+
case REFERENCE_FILE:
388+
return decodeRecord(R, I->DocumentationFileName, Blob);
387389
default:
388390
return llvm::createStringError(llvm::inconvertibleErrorCode(),
389391
"invalid field for Reference");

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ static const llvm::IndexedMap<RecordIdDsc, RecordIdToIndexFunctor>
210210
{REFERENCE_TYPE, {"RefType", &genIntAbbrev}},
211211
{REFERENCE_PATH, {"Path", &genStringAbbrev}},
212212
{REFERENCE_FIELD, {"Field", &genIntAbbrev}},
213+
{REFERENCE_FILE, {"File", &genStringAbbrev}},
213214
{TEMPLATE_PARAM_CONTENTS, {"Contents", &genStringAbbrev}},
214215
{TEMPLATE_SPECIALIZATION_OF,
215216
{"SpecializationOf", &genSymbolIdAbbrev}},
@@ -286,7 +287,7 @@ static const std::vector<std::pair<BlockId, std::vector<RecordId>>>
286287
// Reference Block
287288
{BI_REFERENCE_BLOCK_ID,
288289
{REFERENCE_USR, REFERENCE_NAME, REFERENCE_QUAL_NAME, REFERENCE_TYPE,
289-
REFERENCE_PATH, REFERENCE_FIELD}},
290+
REFERENCE_PATH, REFERENCE_FIELD, REFERENCE_FILE}},
290291
// Template Blocks.
291292
{BI_TEMPLATE_BLOCK_ID, {}},
292293
{BI_TEMPLATE_PARAM_BLOCK_ID, {TEMPLATE_PARAM_CONTENTS}},
@@ -479,6 +480,7 @@ void ClangDocBitcodeWriter::emitBlock(const Reference &R, FieldId Field) {
479480
emitRecord((unsigned)R.RefType, REFERENCE_TYPE);
480481
emitRecord(R.Path, REFERENCE_PATH);
481482
emitRecord((unsigned)Field, REFERENCE_FIELD);
483+
emitRecord(R.DocumentationFileName, REFERENCE_FILE);
482484
}
483485

484486
void ClangDocBitcodeWriter::emitBlock(const FriendInfo &R) {

clang-tools-extra/clang-doc/BitcodeWriter.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ enum RecordId {
140140
REFERENCE_TYPE,
141141
REFERENCE_PATH,
142142
REFERENCE_FIELD,
143+
REFERENCE_FILE,
143144
TEMPLATE_PARAM_CONTENTS,
144145
TEMPLATE_SPECIALIZATION_OF,
145146
TYPEDEF_USR,

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

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,30 @@ static auto SerializeReferenceLambda = [](const auto &Ref, Object &Object) {
4343
serializeReference(Ref, Object);
4444
};
4545

46+
static std::string infoTypeToString(InfoType IT) {
47+
switch (IT) {
48+
case InfoType::IT_default:
49+
return "default";
50+
case InfoType::IT_namespace:
51+
return "namespace";
52+
case InfoType::IT_record:
53+
return "record";
54+
case InfoType::IT_function:
55+
return "function";
56+
case InfoType::IT_enum:
57+
return "enum";
58+
case InfoType::IT_typedef:
59+
return "typedef";
60+
case InfoType::IT_concept:
61+
return "concept";
62+
case InfoType::IT_variable:
63+
return "variable";
64+
case InfoType::IT_friend:
65+
return "friend";
66+
}
67+
llvm_unreachable("Unknown InfoType encountered.");
68+
}
69+
4670
static json::Object
4771
serializeLocation(const Location &Loc,
4872
const std::optional<StringRef> RepositoryUrl) {
@@ -172,6 +196,9 @@ serializeCommonAttributes(const Info &I, json::Object &Obj,
172196
const std::optional<StringRef> RepositoryUrl) {
173197
Obj["Name"] = I.Name;
174198
Obj["USR"] = toHex(toStringRef(I.USR));
199+
Obj["InfoType"] = infoTypeToString(I.IT);
200+
if (!I.DocumentationFileName.empty())
201+
Obj["DocumentationFileName"] = I.DocumentationFileName;
175202

176203
if (!I.Path.empty())
177204
Obj["Path"] = I.Path;
@@ -205,6 +232,8 @@ static void serializeReference(const Reference &Ref, Object &ReferenceObj) {
205232
ReferenceObj["Name"] = Ref.Name;
206233
ReferenceObj["QualName"] = Ref.QualName;
207234
ReferenceObj["USR"] = toHex(toStringRef(Ref.USR));
235+
if (!Ref.DocumentationFileName.empty())
236+
ReferenceObj["DocumentationFileName"] = Ref.DocumentationFileName;
208237
}
209238

210239
// Although namespaces and records both have ScopeChildren, they serialize them
@@ -217,14 +246,18 @@ serializeCommonChildren(const ScopeChildren &Children, json::Object &Obj,
217246
serializeInfo(Info, Object, RepositoryUrl);
218247
};
219248

220-
if (!Children.Enums.empty())
249+
if (!Children.Enums.empty()) {
221250
serializeArray(Children.Enums, Obj, "Enums", SerializeInfo);
251+
Obj["HasEnums"] = true;
252+
}
222253

223254
if (!Children.Typedefs.empty())
224255
serializeArray(Children.Typedefs, Obj, "Typedefs", SerializeInfo);
225256

226-
if (!Children.Records.empty())
257+
if (!Children.Records.empty()) {
227258
serializeArray(Children.Records, Obj, "Records", SerializeReferenceLambda);
259+
Obj["HasRecords"] = true;
260+
}
228261
}
229262

230263
template <typename Container, typename SerializationFunc>
@@ -234,10 +267,12 @@ static void serializeArray(const Container &Records, Object &Obj,
234267
json::Value RecordsArray = Array();
235268
auto &RecordsArrayRef = *RecordsArray.getAsArray();
236269
RecordsArrayRef.reserve(Records.size());
237-
for (const auto &Item : Records) {
270+
for (size_t Index = 0; Index < Records.size(); ++Index) {
238271
json::Value ItemVal = Object();
239272
auto &ItemObj = *ItemVal.getAsObject();
240-
SerializeInfo(Item, ItemObj);
273+
SerializeInfo(Records[Index], ItemObj);
274+
if (Index == Records.size() - 1)
275+
ItemObj["End"] = true;
241276
RecordsArrayRef.push_back(ItemVal);
242277
}
243278
Obj[Key] = RecordsArray;
@@ -405,8 +440,10 @@ static void serializeInfo(const RecordInfo &I, json::Object &Obj,
405440
ProtFunctionsArrayRef.push_back(FunctionVal);
406441
}
407442

408-
if (!PubFunctionsArrayRef.empty())
443+
if (!PubFunctionsArrayRef.empty()) {
409444
Obj["PublicFunctions"] = PubFunctionsArray;
445+
Obj["HasPublicFunctions"] = true;
446+
}
410447
if (!ProtFunctionsArrayRef.empty())
411448
Obj["ProtectedFunctions"] = ProtFunctionsArray;
412449
}
@@ -429,8 +466,10 @@ static void serializeInfo(const RecordInfo &I, json::Object &Obj,
429466
ProtMembersArrayRef.push_back(MemberVal);
430467
}
431468

432-
if (!PubMembersArrayRef.empty())
469+
if (!PubMembersArrayRef.empty()) {
433470
Obj["PublicMembers"] = PublicMembersArray;
471+
Obj["HasPublicMembers"] = true;
472+
}
434473
if (!ProtMembersArrayRef.empty())
435474
Obj["ProtectedMembers"] = ProtectedMembersArray;
436475
}
@@ -496,10 +535,7 @@ static SmallString<16> determineFileName(Info *I, SmallString<128> &Path) {
496535
SmallString<16> FileName;
497536
if (I->IT == InfoType::IT_record) {
498537
auto *RecordSymbolInfo = static_cast<SymbolInfo *>(I);
499-
if (RecordSymbolInfo->MangledName.size() < 255)
500-
FileName = RecordSymbolInfo->MangledName;
501-
else
502-
FileName = toStringRef(toHex(RecordSymbolInfo->USR));
538+
FileName = RecordSymbolInfo->MangledName;
503539
} else if (I->IT == InfoType::IT_namespace && I->Name != "")
504540
// Serialize the global namespace as index.json
505541
FileName = I->Name;
@@ -527,7 +563,10 @@ Error JSONGenerator::generateDocs(
527563
}
528564

529565
SmallString<16> FileName = determineFileName(Info, Path);
566+
if (FileToInfos.contains(Path))
567+
continue;
530568
FileToInfos[Path].push_back(Info);
569+
Info->DocumentationFileName = FileName;
531570
}
532571

533572
for (const auto &Group : FileToInfos) {

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,8 @@ void Reference::merge(Reference &&Other) {
247247
Name = Other.Name;
248248
if (Path.empty())
249249
Path = Other.Path;
250+
if (DocumentationFileName.empty())
251+
DocumentationFileName = Other.DocumentationFileName;
250252
}
251253

252254
bool FriendInfo::mergeable(const FriendInfo &Other) {

clang-tools-extra/clang-doc/Representation.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,10 @@ struct Reference {
121121
Reference(SymbolID USR, StringRef Name, InfoType IT, StringRef QualName,
122122
StringRef Path = StringRef())
123123
: USR(USR), Name(Name), QualName(QualName), RefType(IT), Path(Path) {}
124+
Reference(SymbolID USR, StringRef Name, InfoType IT, StringRef QualName,
125+
StringRef Path, SmallString<16> DocumentationFileName)
126+
: USR(USR), Name(Name), QualName(QualName), RefType(IT), Path(Path),
127+
DocumentationFileName(DocumentationFileName) {}
124128

125129
bool operator==(const Reference &Other) const {
126130
return std::tie(USR, Name, QualName, RefType) ==
@@ -155,6 +159,7 @@ struct Reference {
155159
// Path of directory where the clang-doc generated file will be saved
156160
// (possibly unresolved)
157161
llvm::SmallString<128> Path;
162+
SmallString<16> DocumentationFileName;
158163
};
159164

160165
// Holds the children of a record or namespace.
@@ -331,6 +336,11 @@ struct Info {
331336
llvm::SmallString<128> Path; // Path of directory where the clang-doc
332337
// generated file will be saved
333338

339+
// The name used for the file that this info is documented in.
340+
// In the JSON generator, infos are documented in files with mangled names.
341+
// Thus, we keep track of the physical filename for linking purposes.
342+
SmallString<16> DocumentationFileName;
343+
334344
void mergeBase(Info &&I);
335345
bool mergeable(const Info &Other);
336346

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -495,7 +495,8 @@ static void InsertChild(ScopeChildren &Scope, const NamespaceInfo &Info) {
495495

496496
static void InsertChild(ScopeChildren &Scope, const RecordInfo &Info) {
497497
Scope.Records.emplace_back(Info.USR, Info.Name, InfoType::IT_record,
498-
Info.Name, getInfoRelativePath(Info.Namespace));
498+
Info.Name, getInfoRelativePath(Info.Namespace),
499+
Info.MangledName);
499500
}
500501

501502
static void InsertChild(ScopeChildren &Scope, EnumInfo Info) {
@@ -777,7 +778,10 @@ static void populateSymbolInfo(SymbolInfo &I, const T *D, const FullComment *C,
777778
Mangler->mangleCXXVTable(CXXD, MangledStream);
778779
else
779780
MangledStream << D->getNameAsString();
780-
I.MangledName = MangledName;
781+
if (MangledName.size() > 255)
782+
I.MangledName = llvm::toStringRef(llvm::toHex(I.USR));
783+
else
784+
I.MangledName = MangledName;
781785
delete Mangler;
782786
}
783787

clang-tools-extra/test/clang-doc/json/class-requires.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ struct MyClass;
2020
// CHECK-NEXT: "Template": {
2121
// CHECK-NEXT: "Constraints": [
2222
// CHECK-NEXT: {
23+
// CHECK-NEXT: "End": true,
2324
// CHECK-NEXT: "Expression": "Addable<T>",
2425
// CHECK-NEXT: "Name": "Addable",
2526
// CHECK-NEXT: "Path": "",

clang-tools-extra/test/clang-doc/json/class-template.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ template<typename T> struct MyClass {
1111
// CHECK: "Name": "method",
1212
// CHECK: "Params": [
1313
// CHECK-NEXT: {
14+
// CHECK-NEXT: "End": true,
1415
// CHECK-NEXT: "Name": "Param",
1516
// CHECK-NEXT: "Type": "T"
1617
// CHECK-NEXT: }

clang-tools-extra/test/clang-doc/json/class.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,11 @@ struct MyClass {
6060
// CHECK-NEXT: "TextComment": " This is a brief description."
6161
// CHECK-NEXT: }
6262
// CHECK: "Command": "brief"
63+
// CHECK: "DocumentationFileName": "_ZTV7MyClass",
6364
// CHECK: "Enums": [
6465
// CHECK-NEXT: {
66+
// CHECK-NEXT: "End": true,
67+
// CHECK-NEXT: "InfoType": "enum",
6568
// CHECK-NEXT: "Location": {
6669
// CHECK-NEXT: "Filename": "{{.*}}class.cpp",
6770
// CHECK-NEXT: "LineNumber": 17
@@ -76,6 +79,7 @@ struct MyClass {
7679
// CHECK-NEXT: "Value": "1"
7780
// CHECK-NEXT: },
7881
// CHECK-NEXT: {
82+
// CHECK-NEXT: "End": true,
7983
// CHECK-NEXT: "Name": "BLUE",
8084
// CHECK-NEXT: "ValueExpr": "5"
8185
// CHECK-NEXT: }
@@ -94,6 +98,7 @@ struct MyClass {
9498
// CHECK-NEXT: "IsClass": false,
9599
// CHECK-NEXT: "Params": [
96100
// CHECK-NEXT: {
101+
// CHECK-NEXT: "End": true,
97102
// CHECK-NEXT: "Name": "",
98103
// CHECK-NEXT: "Type": "int"
99104
// CHECK-NEXT: }
@@ -118,6 +123,7 @@ struct MyClass {
118123
// CHECK-NEXT: }
119124
// CHECK-NEXT: },
120125
// CHECK-NEXT: {
126+
// CHECK-NEXT: "End": true,
121127
// CHECK-NEXT: "IsClass": true,
122128
// CHECK-NEXT: "Reference": {
123129
// CHECK-NEXT: "Name": "Foo",
@@ -129,6 +135,11 @@ struct MyClass {
129135
// CHECK-NEXT: ],
130136
// COM: FIXME: FullName is not emitted correctly.
131137
// CHECK-NEXT: "FullName": "",
138+
// CHECK-NEXT: "HasEnums": true,
139+
// CHECK-NEXT: "HasPublicFunctions": true,
140+
// CHECK-NEXT: "HasPublicMembers": true,
141+
// CHECK-NEXT: "HasRecords": true,
142+
// CHECK-NEXT: "InfoType": "record",
132143
// CHECK-NEXT: "IsTypedef": false,
133144
// CHECK-NEXT: "Location": {
134145
// CHECK-NEXT: "Filename": "{{.*}}class.cpp",
@@ -142,6 +153,7 @@ struct MyClass {
142153
// CHECK-NEXT: "Path": "GlobalNamespace",
143154
// CHECK-NEXT: "ProtectedFunctions": [
144155
// CHECK-NEXT: {
156+
// CHECK-NEXT: "InfoType": "function",
145157
// CHECK-NEXT: "IsStatic": false,
146158
// CHECK-NEXT: "Name": "protectedMethod",
147159
// CHECK-NEXT: "Namespace": [
@@ -166,6 +178,7 @@ struct MyClass {
166178
// CHECK-NEXT: ],
167179
// CHECK-NEXT: "PublicFunctions": [
168180
// CHECK-NEXT: {
181+
// CHECK-NEXT: "InfoType": "function",
169182
// CHECK-NEXT: "IsStatic": false,
170183
// CHECK-NEXT: "Name": "myMethod",
171184
// CHECK-NEXT: "Namespace": [
@@ -174,6 +187,7 @@ struct MyClass {
174187
// CHECK-NEXT: ],
175188
// CHECK-NEXT: "Params": [
176189
// CHECK-NEXT: {
190+
// CHECK-NEXT: "End": true,
177191
// CHECK-NEXT: "Name": "MyParam",
178192
// CHECK-NEXT: "Type": "int"
179193
// CHECK-NEXT: }
@@ -204,6 +218,8 @@ struct MyClass {
204218
// CHECK-NEXT: ],
205219
// CHECK-NEXT: "Records": [
206220
// CHECK-NEXT: {
221+
// CHECK-NEXT: "DocumentationFileName": "_ZTVN7MyClass11NestedClassE",
222+
// CHECK-NEXT: "End": true,
207223
// CHECK-NEXT: "Name": "NestedClass",
208224
// CHECK-NEXT: "Path": "GlobalNamespace{{[\/]+}}MyClass",
209225
// CHECK-NEXT: "QualName": "NestedClass",
@@ -213,6 +229,8 @@ struct MyClass {
213229
// CHECK-NEXT: "TagType": "struct",
214230
// CHECK-NEXT: "Typedefs": [
215231
// CHECK-NEXT: {
232+
// CHECK-NEXT: "End": true,
233+
// CHECK-NEXT: "InfoType": "typedef",
216234
// CHECK-NEXT: "IsUsing": false,
217235
// CHECK-NEXT: "Location": {
218236
// CHECK-NEXT: "Filename": "{{.*}}class.cpp",

0 commit comments

Comments
 (0)