1#include "Generators.h"
2#include "clang/Basic/Specifiers.h"
3#include "llvm/Support/JSON.h"
4
5using namespace llvm;
6using namespace llvm::json;
7
8namespace clang {
9namespace doc {
10
11class JSONGenerator : public Generator {
12public:
13 static const char *Format;
14
15 Error generateDocs(StringRef RootDir,
16 llvm::StringMap<std::unique_ptr<doc::Info>> Infos,
17 const ClangDocContext &CDCtx) override;
18 Error createResources(ClangDocContext &CDCtx) override;
19 Error generateDocForInfo(Info *I, llvm::raw_ostream &OS,
20 const ClangDocContext &CDCtx) override;
21};
22
23const char *JSONGenerator::Format = "json";
24
25static void serializeInfo(const ConstraintInfo &I, Object &Obj);
26static void serializeInfo(const RecordInfo &I, Object &Obj,
27 const std::optional<StringRef> &RepositoryUrl);
28
29static void serializeReference(const Reference &Ref, Object &ReferenceObj);
30
31template <typename Container, typename SerializationFunc>
32static void serializeArray(const Container &Records, Object &Obj,
33 const std::string &Key,
34 SerializationFunc SerializeInfo);
35
36// Convenience lambda to pass to serializeArray.
37// If a serializeInfo needs a RepositoryUrl, create a local lambda that captures
38// the optional.
39static auto SerializeInfoLambda = [](const auto &Info, Object &Object) {
40 serializeInfo(Info, Object);
41};
42static auto SerializeReferenceLambda = [](const auto &Ref, Object &Object) {
43 serializeReference(Ref, Object);
44};
45
46static json::Object
47serializeLocation(const Location &Loc,
48 const std::optional<StringRef> &RepositoryUrl) {
49 Object LocationObj = Object();
50 LocationObj["LineNumber"] = Loc.StartLineNumber;
51 LocationObj["Filename"] = Loc.Filename;
52
53 if (!Loc.IsFileInRootDir || !RepositoryUrl)
54 return LocationObj;
55 SmallString<128> FileURL(*RepositoryUrl);
56 sys::path::append(path&: FileURL, style: sys::path::Style::posix, a: Loc.Filename);
57 FileURL += "#" + std::to_string(val: Loc.StartLineNumber);
58 LocationObj["FileURL"] = FileURL;
59 return LocationObj;
60}
61
62static json::Value serializeComment(const CommentInfo &I) {
63 // taken from PR #142273
64 Object Obj = Object();
65
66 json::Value ChildVal = Object();
67 Object &Child = *ChildVal.getAsObject();
68
69 json::Value ChildArr = Array();
70 auto &CARef = *ChildArr.getAsArray();
71 CARef.reserve(S: I.Children.size());
72 for (const auto &C : I.Children)
73 CARef.emplace_back(A: serializeComment(I: *C));
74
75 switch (I.Kind) {
76 case CommentKind::CK_TextComment: {
77 Obj.insert(E: {.K: commentKindToString(Kind: I.Kind), .V: I.Text});
78 return Obj;
79 }
80
81 case CommentKind::CK_BlockCommandComment: {
82 Child.insert(E: {.K: "Command", .V: I.Name});
83 Child.insert(E: {.K: "Children", .V: ChildArr});
84 Obj.insert(E: {.K: commentKindToString(Kind: I.Kind), .V: ChildVal});
85 return Obj;
86 }
87
88 case CommentKind::CK_InlineCommandComment: {
89 json::Value ArgsArr = Array();
90 auto &ARef = *ArgsArr.getAsArray();
91 ARef.reserve(S: I.Args.size());
92 for (const auto &Arg : I.Args)
93 ARef.emplace_back(A: Arg);
94 Child.insert(E: {.K: "Command", .V: I.Name});
95 Child.insert(E: {.K: "Args", .V: ArgsArr});
96 Child.insert(E: {.K: "Children", .V: ChildArr});
97 Obj.insert(E: {.K: commentKindToString(Kind: I.Kind), .V: ChildVal});
98 return Obj;
99 }
100
101 case CommentKind::CK_ParamCommandComment:
102 case CommentKind::CK_TParamCommandComment: {
103 Child.insert(E: {.K: "ParamName", .V: I.ParamName});
104 Child.insert(E: {.K: "Direction", .V: I.Direction});
105 Child.insert(E: {.K: "Explicit", .V: I.Explicit});
106 Child.insert(E: {.K: "Children", .V: ChildArr});
107 Obj.insert(E: {.K: commentKindToString(Kind: I.Kind), .V: ChildVal});
108 return Obj;
109 }
110
111 case CommentKind::CK_VerbatimBlockComment: {
112 Child.insert(E: {.K: "Text", .V: I.Text});
113 if (!I.CloseName.empty())
114 Child.insert(E: {.K: "CloseName", .V: I.CloseName});
115 Child.insert(E: {.K: "Children", .V: ChildArr});
116 Obj.insert(E: {.K: commentKindToString(Kind: I.Kind), .V: ChildVal});
117 return Obj;
118 }
119
120 case CommentKind::CK_VerbatimBlockLineComment:
121 case CommentKind::CK_VerbatimLineComment: {
122 Child.insert(E: {.K: "Text", .V: I.Text});
123 Child.insert(E: {.K: "Children", .V: ChildArr});
124 Obj.insert(E: {.K: commentKindToString(Kind: I.Kind), .V: ChildVal});
125 return Obj;
126 }
127
128 case CommentKind::CK_HTMLStartTagComment: {
129 json::Value AttrKeysArray = json::Array();
130 json::Value AttrValuesArray = json::Array();
131 auto &KeyArr = *AttrKeysArray.getAsArray();
132 auto &ValArr = *AttrValuesArray.getAsArray();
133 KeyArr.reserve(S: I.AttrKeys.size());
134 ValArr.reserve(S: I.AttrValues.size());
135 for (const auto &K : I.AttrKeys)
136 KeyArr.emplace_back(A: K);
137 for (const auto &V : I.AttrValues)
138 ValArr.emplace_back(A: V);
139 Child.insert(E: {.K: "Name", .V: I.Name});
140 Child.insert(E: {.K: "SelfClosing", .V: I.SelfClosing});
141 Child.insert(E: {.K: "AttrKeys", .V: AttrKeysArray});
142 Child.insert(E: {.K: "AttrValues", .V: AttrValuesArray});
143 Child.insert(E: {.K: "Children", .V: ChildArr});
144 Obj.insert(E: {.K: commentKindToString(Kind: I.Kind), .V: ChildVal});
145 return Obj;
146 }
147
148 case CommentKind::CK_HTMLEndTagComment: {
149 Child.insert(E: {.K: "Name", .V: I.Name});
150 Child.insert(E: {.K: "Children", .V: ChildArr});
151 Obj.insert(E: {.K: commentKindToString(Kind: I.Kind), .V: ChildVal});
152 return Obj;
153 }
154
155 case CommentKind::CK_FullComment:
156 case CommentKind::CK_ParagraphComment: {
157 Child.insert(E: {.K: "Children", .V: ChildArr});
158 Obj.insert(E: {.K: commentKindToString(Kind: I.Kind), .V: ChildVal});
159 return Obj;
160 }
161
162 case CommentKind::CK_Unknown: {
163 Obj.insert(E: {.K: commentKindToString(Kind: I.Kind), .V: I.Text});
164 return Obj;
165 }
166 }
167 llvm_unreachable("Unknown comment kind encountered.");
168}
169
170static void
171serializeCommonAttributes(const Info &I, json::Object &Obj,
172 const std::optional<StringRef> &RepositoryUrl) {
173 Obj["Name"] = I.Name;
174 Obj["USR"] = toHex(Input: toStringRef(Input: I.USR));
175
176 if (!I.Path.empty())
177 Obj["Path"] = I.Path;
178
179 if (!I.Namespace.empty()) {
180 Obj["Namespace"] = json::Array();
181 for (const auto &NS : I.Namespace)
182 Obj["Namespace"].getAsArray()->push_back(E: NS.Name);
183 }
184
185 if (!I.Description.empty()) {
186 json::Value DescArray = json::Array();
187 auto &DescArrayRef = *DescArray.getAsArray();
188 DescArrayRef.reserve(S: I.Description.size());
189 for (const auto &Comment : I.Description)
190 DescArrayRef.push_back(E: serializeComment(I: Comment));
191 Obj["Description"] = DescArray;
192 }
193
194 // Namespaces aren't SymbolInfos, so they dont have a DefLoc
195 if (I.IT != InfoType::IT_namespace) {
196 const auto *Symbol = static_cast<const SymbolInfo *>(&I);
197 if (Symbol->DefLoc)
198 Obj["Location"] =
199 serializeLocation(Loc: Symbol->DefLoc.value(), RepositoryUrl);
200 }
201}
202
203static void serializeReference(const Reference &Ref, Object &ReferenceObj) {
204 ReferenceObj["Path"] = Ref.Path;
205 ReferenceObj["Name"] = Ref.Name;
206 ReferenceObj["QualName"] = Ref.QualName;
207 ReferenceObj["USR"] = toHex(Input: toStringRef(Input: Ref.USR));
208}
209
210// Although namespaces and records both have ScopeChildren, they serialize them
211// differently. Only enums, records, and typedefs are handled here.
212static void
213serializeCommonChildren(const ScopeChildren &Children, json::Object &Obj,
214 const std::optional<StringRef> &RepositoryUrl) {
215 static auto SerializeInfo = [&RepositoryUrl](const auto &Info,
216 Object &Object) {
217 serializeInfo(Info, Object, RepositoryUrl);
218 };
219
220 if (!Children.Enums.empty())
221 serializeArray(Records: Children.Enums, Obj, Key: "Enums", SerializeInfo);
222
223 if (!Children.Typedefs.empty())
224 serializeArray(Records: Children.Typedefs, Obj, Key: "Typedefs", SerializeInfo);
225
226 if (!Children.Records.empty())
227 serializeArray(Records: Children.Records, Obj, Key: "Records", SerializeInfo: SerializeReferenceLambda);
228}
229
230template <typename Container, typename SerializationFunc>
231static void serializeArray(const Container &Records, Object &Obj,
232 const std::string &Key,
233 SerializationFunc SerializeInfo) {
234 json::Value RecordsArray = Array();
235 auto &RecordsArrayRef = *RecordsArray.getAsArray();
236 RecordsArrayRef.reserve(S: Records.size());
237 for (const auto &Item : Records) {
238 json::Value ItemVal = Object();
239 auto &ItemObj = *ItemVal.getAsObject();
240 SerializeInfo(Item, ItemObj);
241 RecordsArrayRef.push_back(E: ItemVal);
242 }
243 Obj[Key] = RecordsArray;
244}
245
246static void serializeInfo(const ConstraintInfo &I, Object &Obj) {
247 serializeReference(Ref: I.ConceptRef, ReferenceObj&: Obj);
248 Obj["Expression"] = I.ConstraintExpr;
249}
250
251static void serializeInfo(const ArrayRef<TemplateParamInfo> &Params,
252 Object &Obj) {
253 json::Value ParamsArray = Array();
254 auto &ParamsArrayRef = *ParamsArray.getAsArray();
255 ParamsArrayRef.reserve(S: Params.size());
256 for (const auto &Param : Params)
257 ParamsArrayRef.push_back(E: Param.Contents);
258 Obj["Parameters"] = ParamsArray;
259}
260
261static void serializeInfo(const TemplateInfo &Template, Object &Obj) {
262 json::Value TemplateVal = Object();
263 auto &TemplateObj = *TemplateVal.getAsObject();
264
265 if (Template.Specialization) {
266 json::Value TemplateSpecializationVal = Object();
267 auto &TemplateSpecializationObj = *TemplateSpecializationVal.getAsObject();
268 TemplateSpecializationObj["SpecializationOf"] =
269 toHex(Input: toStringRef(Input: Template.Specialization->SpecializationOf));
270 if (!Template.Specialization->Params.empty())
271 serializeInfo(Params: Template.Specialization->Params, Obj&: TemplateSpecializationObj);
272 TemplateObj["Specialization"] = TemplateSpecializationVal;
273 }
274
275 if (!Template.Params.empty())
276 serializeInfo(Params: Template.Params, Obj&: TemplateObj);
277
278 if (!Template.Constraints.empty())
279 serializeArray(Records: Template.Constraints, Obj&: TemplateObj, Key: "Constraints",
280 SerializeInfo: SerializeInfoLambda);
281
282 Obj["Template"] = TemplateVal;
283}
284
285static void serializeInfo(const ConceptInfo &I, Object &Obj,
286 const std::optional<StringRef> &RepositoryUrl) {
287 serializeCommonAttributes(I, Obj, RepositoryUrl);
288 Obj["IsType"] = I.IsType;
289 Obj["ConstraintExpression"] = I.ConstraintExpression;
290 serializeInfo(Template: I.Template, Obj);
291}
292
293static void serializeInfo(const TypeInfo &I, Object &Obj) {
294 Obj["Name"] = I.Type.Name;
295 Obj["QualName"] = I.Type.QualName;
296 Obj["USR"] = toHex(Input: toStringRef(Input: I.Type.USR));
297 Obj["IsTemplate"] = I.IsTemplate;
298 Obj["IsBuiltIn"] = I.IsBuiltIn;
299}
300
301static void serializeInfo(const FieldTypeInfo &I, Object &Obj) {
302 Obj["Name"] = I.Name;
303 Obj["Type"] = I.Type.Name;
304}
305
306static void serializeInfo(const FunctionInfo &F, json::Object &Obj,
307 const std::optional<StringRef> &RepositoryURL) {
308 serializeCommonAttributes(I: F, Obj, RepositoryUrl: RepositoryURL);
309 Obj["IsStatic"] = F.IsStatic;
310
311 auto ReturnTypeObj = Object();
312 serializeInfo(I: F.ReturnType, Obj&: ReturnTypeObj);
313 Obj["ReturnType"] = std::move(ReturnTypeObj);
314
315 if (!F.Params.empty())
316 serializeArray(Records: F.Params, Obj, Key: "Params", SerializeInfo: SerializeInfoLambda);
317
318 if (F.Template)
319 serializeInfo(Template: F.Template.value(), Obj);
320}
321
322static void serializeInfo(const EnumValueInfo &I, Object &Obj) {
323 Obj["Name"] = I.Name;
324 if (!I.ValueExpr.empty())
325 Obj["ValueExpr"] = I.ValueExpr;
326 else
327 Obj["Value"] = I.Value;
328}
329
330static void serializeInfo(const EnumInfo &I, json::Object &Obj,
331 const std::optional<StringRef> &RepositoryUrl) {
332 serializeCommonAttributes(I, Obj, RepositoryUrl);
333 Obj["Scoped"] = I.Scoped;
334
335 if (I.BaseType) {
336 json::Value BaseTypeVal = Object();
337 auto &BaseTypeObj = *BaseTypeVal.getAsObject();
338 BaseTypeObj["Name"] = I.BaseType->Type.Name;
339 BaseTypeObj["QualName"] = I.BaseType->Type.QualName;
340 BaseTypeObj["USR"] = toHex(Input: toStringRef(Input: I.BaseType->Type.USR));
341 Obj["BaseType"] = BaseTypeVal;
342 }
343
344 if (!I.Members.empty())
345 serializeArray(Records: I.Members, Obj, Key: "Members", SerializeInfo: SerializeInfoLambda);
346}
347
348static void serializeInfo(const TypedefInfo &I, json::Object &Obj,
349 const std::optional<StringRef> &RepositoryUrl) {
350 serializeCommonAttributes(I, Obj, RepositoryUrl);
351 Obj["TypeDeclaration"] = I.TypeDeclaration;
352 Obj["IsUsing"] = I.IsUsing;
353 json::Value TypeVal = Object();
354 auto &TypeObj = *TypeVal.getAsObject();
355 serializeInfo(I: I.Underlying, Obj&: TypeObj);
356 Obj["Underlying"] = TypeVal;
357}
358
359static void serializeInfo(const BaseRecordInfo &I, Object &Obj,
360 const std::optional<StringRef> &RepositoryUrl) {
361 serializeInfo(I: static_cast<const RecordInfo &>(I), Obj, RepositoryUrl);
362 Obj["IsVirtual"] = I.IsVirtual;
363 Obj["Access"] = getAccessSpelling(AS: I.Access);
364 Obj["IsParent"] = I.IsParent;
365}
366
367static void serializeInfo(const FriendInfo &I, Object &Obj) {
368 auto FriendRef = Object();
369 serializeReference(Ref: I.Ref, ReferenceObj&: FriendRef);
370 Obj["Reference"] = std::move(FriendRef);
371 Obj["IsClass"] = I.IsClass;
372 if (I.Template)
373 serializeInfo(Template: I.Template.value(), Obj);
374 if (I.Params)
375 serializeArray(Records: I.Params.value(), Obj, Key: "Params", SerializeInfo: SerializeInfoLambda);
376 if (I.ReturnType) {
377 auto ReturnTypeObj = Object();
378 serializeInfo(I: I.ReturnType.value(), Obj&: ReturnTypeObj);
379 Obj["ReturnType"] = std::move(ReturnTypeObj);
380 }
381}
382
383static void serializeInfo(const RecordInfo &I, json::Object &Obj,
384 const std::optional<StringRef> &RepositoryUrl) {
385 serializeCommonAttributes(I, Obj, RepositoryUrl);
386 Obj["FullName"] = I.FullName;
387 Obj["TagType"] = getTagType(AS: I.TagType);
388 Obj["IsTypedef"] = I.IsTypeDef;
389 Obj["MangledName"] = I.MangledName;
390
391 if (!I.Children.Functions.empty()) {
392 json::Value PubFunctionsArray = Array();
393 json::Array &PubFunctionsArrayRef = *PubFunctionsArray.getAsArray();
394 json::Value ProtFunctionsArray = Array();
395 json::Array &ProtFunctionsArrayRef = *ProtFunctionsArray.getAsArray();
396
397 for (const auto &Function : I.Children.Functions) {
398 json::Value FunctionVal = Object();
399 auto &FunctionObj = *FunctionVal.getAsObject();
400 serializeInfo(F: Function, Obj&: FunctionObj, RepositoryURL: RepositoryUrl);
401 AccessSpecifier Access = Function.Access;
402 if (Access == AccessSpecifier::AS_public)
403 PubFunctionsArrayRef.push_back(E: FunctionVal);
404 else if (Access == AccessSpecifier::AS_protected)
405 ProtFunctionsArrayRef.push_back(E: FunctionVal);
406 }
407
408 if (!PubFunctionsArrayRef.empty())
409 Obj["PublicFunctions"] = PubFunctionsArray;
410 if (!ProtFunctionsArrayRef.empty())
411 Obj["ProtectedFunctions"] = ProtFunctionsArray;
412 }
413
414 if (!I.Members.empty()) {
415 json::Value PublicMembersArray = Array();
416 json::Array &PubMembersArrayRef = *PublicMembersArray.getAsArray();
417 json::Value ProtectedMembersArray = Array();
418 json::Array &ProtMembersArrayRef = *ProtectedMembersArray.getAsArray();
419
420 for (const MemberTypeInfo &Member : I.Members) {
421 json::Value MemberVal = Object();
422 auto &MemberObj = *MemberVal.getAsObject();
423 MemberObj["Name"] = Member.Name;
424 MemberObj["Type"] = Member.Type.Name;
425
426 if (Member.Access == AccessSpecifier::AS_public)
427 PubMembersArrayRef.push_back(E: MemberVal);
428 else if (Member.Access == AccessSpecifier::AS_protected)
429 ProtMembersArrayRef.push_back(E: MemberVal);
430 }
431
432 if (!PubMembersArrayRef.empty())
433 Obj["PublicMembers"] = PublicMembersArray;
434 if (!ProtMembersArrayRef.empty())
435 Obj["ProtectedMembers"] = ProtectedMembersArray;
436 }
437
438 if (!I.Bases.empty())
439 serializeArray(
440 Records: I.Bases, Obj, Key: "Bases",
441 SerializeInfo: [&RepositoryUrl](const BaseRecordInfo &Base, Object &BaseObj) {
442 serializeInfo(I: Base, Obj&: BaseObj, RepositoryUrl);
443 });
444
445 if (!I.Parents.empty())
446 serializeArray(Records: I.Parents, Obj, Key: "Parents", SerializeInfo: SerializeReferenceLambda);
447
448 if (!I.VirtualParents.empty())
449 serializeArray(Records: I.VirtualParents, Obj, Key: "VirtualParents",
450 SerializeInfo: SerializeReferenceLambda);
451
452 if (I.Template)
453 serializeInfo(Template: I.Template.value(), Obj);
454
455 if (!I.Friends.empty())
456 serializeArray(Records: I.Friends, Obj, Key: "Friends", SerializeInfo: SerializeInfoLambda);
457
458 serializeCommonChildren(Children: I.Children, Obj, RepositoryUrl);
459}
460
461static void serializeInfo(const VarInfo &I, json::Object &Obj,
462 const std::optional<StringRef> &RepositoryUrl) {
463 serializeCommonAttributes(I, Obj, RepositoryUrl);
464 Obj["IsStatic"] = I.IsStatic;
465 auto TypeObj = Object();
466 serializeInfo(I: I.Type, Obj&: TypeObj);
467 Obj["Type"] = std::move(TypeObj);
468}
469
470static void serializeInfo(const NamespaceInfo &I, json::Object &Obj,
471 const std::optional<StringRef> &RepositoryUrl) {
472 serializeCommonAttributes(I, Obj, RepositoryUrl);
473
474 if (!I.Children.Namespaces.empty())
475 serializeArray(Records: I.Children.Namespaces, Obj, Key: "Namespaces",
476 SerializeInfo: SerializeReferenceLambda);
477
478 static auto SerializeInfo = [&RepositoryUrl](const auto &Info,
479 Object &Object) {
480 serializeInfo(Info, Object, RepositoryUrl);
481 };
482
483 if (!I.Children.Functions.empty())
484 serializeArray(Records: I.Children.Functions, Obj, Key: "Functions", SerializeInfo);
485
486 if (!I.Children.Concepts.empty())
487 serializeArray(Records: I.Children.Concepts, Obj, Key: "Concepts", SerializeInfo);
488
489 if (!I.Children.Variables.empty())
490 serializeArray(Records: I.Children.Variables, Obj, Key: "Variables", SerializeInfo);
491
492 serializeCommonChildren(Children: I.Children, Obj, RepositoryUrl);
493}
494
495static SmallString<16> determineFileName(Info *I, SmallString<128> &Path) {
496 SmallString<16> FileName;
497 if (I->IT == InfoType::IT_record) {
498 auto *RecordSymbolInfo = static_cast<SymbolInfo *>(I);
499 if (RecordSymbolInfo->MangledName.size() < 255)
500 FileName = RecordSymbolInfo->MangledName;
501 else
502 FileName = toStringRef(Input: toHex(Input: RecordSymbolInfo->USR));
503 } else if (I->IT == InfoType::IT_namespace && I->Name != "")
504 // Serialize the global namespace as index.json
505 FileName = I->Name;
506 else
507 FileName = I->getFileBaseName();
508 sys::path::append(path&: Path, a: FileName + ".json");
509 return FileName;
510}
511
512Error JSONGenerator::generateDocs(
513 StringRef RootDir, llvm::StringMap<std::unique_ptr<doc::Info>> Infos,
514 const ClangDocContext &CDCtx) {
515 StringSet<> CreatedDirs;
516 StringMap<std::vector<doc::Info *>> FileToInfos;
517 for (const auto &Group : Infos) {
518 Info *Info = Group.getValue().get();
519
520 SmallString<128> Path;
521 sys::path::native(path: RootDir, result&: Path);
522 if (!CreatedDirs.contains(key: Path)) {
523 if (std::error_code Err = sys::fs::create_directories(path: Path);
524 Err != std::error_code())
525 return createFileError(F: Twine(Path), EC: Err);
526 CreatedDirs.insert(key: Path);
527 }
528
529 SmallString<16> FileName = determineFileName(I: Info, Path);
530 FileToInfos[Path].push_back(x: Info);
531 }
532
533 for (const auto &Group : FileToInfos) {
534 std::error_code FileErr;
535 raw_fd_ostream InfoOS(Group.getKey(), FileErr, sys::fs::OF_Text);
536 if (FileErr)
537 return createFileError(F: "cannot open file " + Group.getKey(), EC: FileErr);
538
539 for (const auto &Info : Group.getValue())
540 if (Error Err = generateDocForInfo(I: Info, OS&: InfoOS, CDCtx))
541 return Err;
542 }
543
544 return Error::success();
545}
546
547Error JSONGenerator::generateDocForInfo(Info *I, raw_ostream &OS,
548 const ClangDocContext &CDCtx) {
549 json::Object Obj = Object();
550
551 switch (I->IT) {
552 case InfoType::IT_namespace:
553 serializeInfo(I: *static_cast<NamespaceInfo *>(I), Obj, RepositoryUrl: CDCtx.RepositoryUrl);
554 break;
555 case InfoType::IT_record:
556 serializeInfo(I: *static_cast<RecordInfo *>(I), Obj, RepositoryUrl: CDCtx.RepositoryUrl);
557 break;
558 case InfoType::IT_concept:
559 case InfoType::IT_enum:
560 case InfoType::IT_function:
561 case InfoType::IT_typedef:
562 case InfoType::IT_variable:
563 case InfoType::IT_friend:
564 break;
565 case InfoType::IT_default:
566 return createStringError(EC: inconvertibleErrorCode(), S: "unexpected info type");
567 }
568 OS << llvm::formatv(Fmt: "{0:2}", Vals: llvm::json::Value(std::move(Obj)));
569 return Error::success();
570}
571
572Error JSONGenerator::createResources(ClangDocContext &CDCtx) {
573 return Error::success();
574}
575
576static GeneratorRegistry::Add<JSONGenerator> JSON(JSONGenerator::Format,
577 "Generator for JSON output.");
578volatile int JSONGeneratorAnchorSource = 0;
579} // namespace doc
580} // namespace clang
581

source code of clang-tools-extra/clang-doc/JSONGenerator.cpp