675 lines · cpp
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 generateDocumentation(StringRef RootDir,16 llvm::StringMap<std::unique_ptr<doc::Info>> Infos,17 const ClangDocContext &CDCtx,18 std::string DirName) override;19 Error createResources(ClangDocContext &CDCtx) override;20 Error generateDocForInfo(Info *I, llvm::raw_ostream &OS,21 const ClangDocContext &CDCtx) override;22};23 24const char *JSONGenerator::Format = "json";25 26static void serializeInfo(const ConstraintInfo &I, Object &Obj);27static void serializeInfo(const RecordInfo &I, Object &Obj,28 const std::optional<StringRef> &RepositoryUrl);29 30static void serializeReference(const Reference &Ref, Object &ReferenceObj);31 32template <typename Container, typename SerializationFunc>33static void serializeArray(const Container &Records, Object &Obj,34 const std::string &Key,35 SerializationFunc SerializeInfo);36 37// Convenience lambda to pass to serializeArray.38// If a serializeInfo needs a RepositoryUrl, create a local lambda that captures39// the optional.40static auto SerializeInfoLambda = [](const auto &Info, Object &Object) {41 serializeInfo(Info, Object);42};43static auto SerializeReferenceLambda = [](const auto &Ref, Object &Object) {44 serializeReference(Ref, Object);45};46 47static std::string infoTypeToString(InfoType IT) {48 switch (IT) {49 case InfoType::IT_default:50 return "default";51 case InfoType::IT_namespace:52 return "namespace";53 case InfoType::IT_record:54 return "record";55 case InfoType::IT_function:56 return "function";57 case InfoType::IT_enum:58 return "enum";59 case InfoType::IT_typedef:60 return "typedef";61 case InfoType::IT_concept:62 return "concept";63 case InfoType::IT_variable:64 return "variable";65 case InfoType::IT_friend:66 return "friend";67 }68 llvm_unreachable("Unknown InfoType encountered.");69}70 71static json::Object72serializeLocation(const Location &Loc,73 const std::optional<StringRef> RepositoryUrl) {74 Object LocationObj = Object();75 LocationObj["LineNumber"] = Loc.StartLineNumber;76 LocationObj["Filename"] = Loc.Filename;77 78 if (!Loc.IsFileInRootDir || !RepositoryUrl)79 return LocationObj;80 SmallString<128> FileURL(*RepositoryUrl);81 sys::path::append(FileURL, sys::path::Style::posix, Loc.Filename);82 FileURL += "#" + std::to_string(Loc.StartLineNumber);83 LocationObj["FileURL"] = FileURL;84 return LocationObj;85}86 87static void insertComment(Object &Description, json::Value &Comment,88 StringRef Key) {89 auto DescriptionIt = Description.find(Key);90 91 if (DescriptionIt == Description.end()) {92 auto CommentsArray = json::Array();93 CommentsArray.push_back(Comment);94 Description[Key] = std::move(CommentsArray);95 Description["Has" + Key.str()] = true;96 } else {97 DescriptionIt->getSecond().getAsArray()->push_back(Comment);98 }99}100 101static json::Value extractTextComments(Object *ParagraphComment) {102 if (!ParagraphComment)103 return json::Object();104 return *ParagraphComment->get("Children");105}106 107static json::Value extractVerbatimComments(json::Array VerbatimLines) {108 json::Value TextArray = json::Array();109 auto &TextArrayRef = *TextArray.getAsArray();110 for (auto &Line : VerbatimLines)111 TextArrayRef.push_back(*Line.getAsObject()112 ->get("VerbatimBlockLineComment")113 ->getAsObject()114 ->get("Text"));115 116 return TextArray;117}118 119static Object serializeComment(const CommentInfo &I, Object &Description) {120 // taken from PR #142273121 Object Obj = Object();122 123 json::Value ChildVal = Object();124 Object &Child = *ChildVal.getAsObject();125 126 json::Value ChildArr = Array();127 auto &CARef = *ChildArr.getAsArray();128 CARef.reserve(I.Children.size());129 for (const auto &C : I.Children)130 CARef.emplace_back(serializeComment(*C, Description));131 132 switch (I.Kind) {133 case CommentKind::CK_TextComment: {134 Obj.insert({commentKindToString(I.Kind), I.Text});135 return Obj;136 }137 138 case CommentKind::CK_BlockCommandComment: {139 auto TextCommentsArray = extractTextComments(CARef.front().getAsObject());140 if (I.Name == "brief")141 insertComment(Description, TextCommentsArray, "BriefComments");142 else if (I.Name == "return")143 insertComment(Description, TextCommentsArray, "ReturnComments");144 else if (I.Name == "throws" || I.Name == "throw") {145 json::Value ThrowsVal = Object();146 auto &ThrowsObj = *ThrowsVal.getAsObject();147 ThrowsObj["Exception"] = I.Args.front();148 ThrowsObj["Children"] = TextCommentsArray;149 insertComment(Description, ThrowsVal, "ThrowsComments");150 }151 return Obj;152 }153 154 case CommentKind::CK_InlineCommandComment: {155 json::Value ArgsArr = Array();156 auto &ARef = *ArgsArr.getAsArray();157 ARef.reserve(I.Args.size());158 for (const auto &Arg : I.Args)159 ARef.emplace_back(Arg);160 Child.insert({"Command", I.Name});161 Child.insert({"Args", ArgsArr});162 Child.insert({"Children", ChildArr});163 Obj.insert({commentKindToString(I.Kind), ChildVal});164 return Obj;165 }166 167 case CommentKind::CK_ParamCommandComment:168 case CommentKind::CK_TParamCommandComment: {169 Child.insert({"ParamName", I.ParamName});170 Child.insert({"Direction", I.Direction});171 Child.insert({"Explicit", I.Explicit});172 auto TextCommentsArray = extractTextComments(CARef.front().getAsObject());173 Child.insert({"Children", TextCommentsArray});174 if (I.Kind == CommentKind::CK_ParamCommandComment)175 insertComment(Description, ChildVal, "ParamComments");176 return Obj;177 }178 179 case CommentKind::CK_VerbatimBlockComment: {180 if (I.CloseName == "endcode") {181 // We don't support \code language specification182 auto TextCommentsArray = extractVerbatimComments(CARef);183 insertComment(Description, TextCommentsArray, "CodeComments");184 } else if (I.CloseName == "endverbatim")185 insertComment(Description, ChildVal, "VerbatimComments");186 return Obj;187 }188 189 case CommentKind::CK_VerbatimBlockLineComment:190 case CommentKind::CK_VerbatimLineComment: {191 Child.insert({"Text", I.Text});192 Child.insert({"Children", ChildArr});193 Obj.insert({commentKindToString(I.Kind), ChildVal});194 return Obj;195 }196 197 case CommentKind::CK_HTMLStartTagComment: {198 json::Value AttrKeysArray = json::Array();199 json::Value AttrValuesArray = json::Array();200 auto &KeyArr = *AttrKeysArray.getAsArray();201 auto &ValArr = *AttrValuesArray.getAsArray();202 KeyArr.reserve(I.AttrKeys.size());203 ValArr.reserve(I.AttrValues.size());204 for (const auto &K : I.AttrKeys)205 KeyArr.emplace_back(K);206 for (const auto &V : I.AttrValues)207 ValArr.emplace_back(V);208 Child.insert({"Name", I.Name});209 Child.insert({"SelfClosing", I.SelfClosing});210 Child.insert({"AttrKeys", AttrKeysArray});211 Child.insert({"AttrValues", AttrValuesArray});212 Child.insert({"Children", ChildArr});213 Obj.insert({commentKindToString(I.Kind), ChildVal});214 return Obj;215 }216 217 case CommentKind::CK_HTMLEndTagComment: {218 Child.insert({"Name", I.Name});219 Child.insert({"Children", ChildArr});220 Obj.insert({commentKindToString(I.Kind), ChildVal});221 return Obj;222 }223 224 case CommentKind::CK_FullComment:225 case CommentKind::CK_ParagraphComment: {226 Child.insert({"Children", ChildArr});227 Child["ParagraphComment"] = true;228 return Child;229 }230 231 case CommentKind::CK_Unknown: {232 Obj.insert({commentKindToString(I.Kind), I.Text});233 return Obj;234 }235 }236 llvm_unreachable("Unknown comment kind encountered.");237}238 239static void240serializeCommonAttributes(const Info &I, json::Object &Obj,241 const std::optional<StringRef> RepositoryUrl) {242 Obj["Name"] = I.Name;243 Obj["USR"] = toHex(toStringRef(I.USR));244 Obj["InfoType"] = infoTypeToString(I.IT);245 if (!I.DocumentationFileName.empty())246 Obj["DocumentationFileName"] = I.DocumentationFileName;247 248 if (!I.Path.empty())249 Obj["Path"] = I.Path;250 251 if (!I.Namespace.empty()) {252 Obj["Namespace"] = json::Array();253 for (const auto &NS : I.Namespace)254 Obj["Namespace"].getAsArray()->push_back(NS.Name);255 }256 257 if (!I.Description.empty()) {258 Object Description = Object();259 // Skip straight to the FullComment's children260 auto &Comments = I.Description.at(0).Children;261 for (const auto &CommentInfo : Comments) {262 json::Value Comment = serializeComment(*CommentInfo, Description);263 // if a ParagraphComment is returned, then it is a top-level comment that264 // needs to be inserted manually.265 if (auto *ParagraphComment = Comment.getAsObject();266 ParagraphComment->get("ParagraphComment")) {267 auto TextCommentsArray = extractTextComments(ParagraphComment);268 insertComment(Description, TextCommentsArray, "ParagraphComments");269 }270 }271 Obj["Description"] = std::move(Description);272 }273 274 // Namespaces aren't SymbolInfos, so they dont have a DefLoc275 if (I.IT != InfoType::IT_namespace) {276 const auto *Symbol = static_cast<const SymbolInfo *>(&I);277 if (Symbol->DefLoc)278 Obj["Location"] =279 serializeLocation(Symbol->DefLoc.value(), RepositoryUrl);280 }281}282 283static void serializeReference(const Reference &Ref, Object &ReferenceObj) {284 ReferenceObj["Path"] = Ref.Path;285 ReferenceObj["Name"] = Ref.Name;286 ReferenceObj["QualName"] = Ref.QualName;287 ReferenceObj["USR"] = toHex(toStringRef(Ref.USR));288 if (!Ref.DocumentationFileName.empty())289 ReferenceObj["DocumentationFileName"] = Ref.DocumentationFileName;290}291 292// Although namespaces and records both have ScopeChildren, they serialize them293// differently. Only enums, records, and typedefs are handled here.294static void295serializeCommonChildren(const ScopeChildren &Children, json::Object &Obj,296 const std::optional<StringRef> RepositoryUrl) {297 static auto SerializeInfo = [RepositoryUrl](const auto &Info,298 Object &Object) {299 serializeInfo(Info, Object, RepositoryUrl);300 };301 302 if (!Children.Enums.empty()) {303 serializeArray(Children.Enums, Obj, "Enums", SerializeInfo);304 Obj["HasEnums"] = true;305 }306 307 if (!Children.Typedefs.empty())308 serializeArray(Children.Typedefs, Obj, "Typedefs", SerializeInfo);309 310 if (!Children.Records.empty()) {311 serializeArray(Children.Records, Obj, "Records", SerializeReferenceLambda);312 Obj["HasRecords"] = true;313 }314}315 316template <typename Container, typename SerializationFunc>317static void serializeArray(const Container &Records, Object &Obj,318 const std::string &Key,319 SerializationFunc SerializeInfo) {320 json::Value RecordsArray = Array();321 auto &RecordsArrayRef = *RecordsArray.getAsArray();322 RecordsArrayRef.reserve(Records.size());323 for (size_t Index = 0; Index < Records.size(); ++Index) {324 json::Value ItemVal = Object();325 auto &ItemObj = *ItemVal.getAsObject();326 SerializeInfo(Records[Index], ItemObj);327 if (Index == Records.size() - 1)328 ItemObj["End"] = true;329 RecordsArrayRef.push_back(ItemVal);330 }331 Obj[Key] = RecordsArray;332}333 334static void serializeInfo(const ConstraintInfo &I, Object &Obj) {335 serializeReference(I.ConceptRef, Obj);336 Obj["Expression"] = I.ConstraintExpr;337}338 339static void serializeInfo(const ArrayRef<TemplateParamInfo> &Params,340 Object &Obj) {341 json::Value ParamsArray = Array();342 auto &ParamsArrayRef = *ParamsArray.getAsArray();343 ParamsArrayRef.reserve(Params.size());344 for (const auto &Param : Params)345 ParamsArrayRef.push_back(Param.Contents);346 Obj["Parameters"] = ParamsArray;347}348 349static void serializeInfo(const TemplateInfo &Template, Object &Obj) {350 json::Value TemplateVal = Object();351 auto &TemplateObj = *TemplateVal.getAsObject();352 353 if (Template.Specialization) {354 json::Value TemplateSpecializationVal = Object();355 auto &TemplateSpecializationObj = *TemplateSpecializationVal.getAsObject();356 TemplateSpecializationObj["SpecializationOf"] =357 toHex(toStringRef(Template.Specialization->SpecializationOf));358 if (!Template.Specialization->Params.empty())359 serializeInfo(Template.Specialization->Params, TemplateSpecializationObj);360 TemplateObj["Specialization"] = TemplateSpecializationVal;361 }362 363 if (!Template.Params.empty())364 serializeInfo(Template.Params, TemplateObj);365 366 if (!Template.Constraints.empty())367 serializeArray(Template.Constraints, TemplateObj, "Constraints",368 SerializeInfoLambda);369 370 Obj["Template"] = TemplateVal;371}372 373static void serializeInfo(const ConceptInfo &I, Object &Obj,374 const std::optional<StringRef> &RepositoryUrl) {375 serializeCommonAttributes(I, Obj, RepositoryUrl);376 Obj["IsType"] = I.IsType;377 Obj["ConstraintExpression"] = I.ConstraintExpression;378 serializeInfo(I.Template, Obj);379}380 381static void serializeInfo(const TypeInfo &I, Object &Obj) {382 Obj["Name"] = I.Type.Name;383 Obj["QualName"] = I.Type.QualName;384 Obj["USR"] = toHex(toStringRef(I.Type.USR));385 Obj["IsTemplate"] = I.IsTemplate;386 Obj["IsBuiltIn"] = I.IsBuiltIn;387}388 389static void serializeInfo(const FieldTypeInfo &I, Object &Obj) {390 Obj["Name"] = I.Name;391 Obj["Type"] = I.Type.Name;392}393 394static void serializeInfo(const FunctionInfo &F, json::Object &Obj,395 const std::optional<StringRef> RepositoryURL) {396 serializeCommonAttributes(F, Obj, RepositoryURL);397 Obj["IsStatic"] = F.IsStatic;398 399 auto ReturnTypeObj = Object();400 serializeInfo(F.ReturnType, ReturnTypeObj);401 Obj["ReturnType"] = std::move(ReturnTypeObj);402 403 if (!F.Params.empty())404 serializeArray(F.Params, Obj, "Params", SerializeInfoLambda);405 406 if (F.Template)407 serializeInfo(F.Template.value(), Obj);408}409 410static void serializeInfo(const EnumValueInfo &I, Object &Obj) {411 Obj["Name"] = I.Name;412 if (!I.ValueExpr.empty())413 Obj["ValueExpr"] = I.ValueExpr;414 else415 Obj["Value"] = I.Value;416}417 418static void serializeInfo(const EnumInfo &I, json::Object &Obj,419 const std::optional<StringRef> &RepositoryUrl) {420 serializeCommonAttributes(I, Obj, RepositoryUrl);421 Obj["Scoped"] = I.Scoped;422 423 if (I.BaseType) {424 json::Value BaseTypeVal = Object();425 auto &BaseTypeObj = *BaseTypeVal.getAsObject();426 BaseTypeObj["Name"] = I.BaseType->Type.Name;427 BaseTypeObj["QualName"] = I.BaseType->Type.QualName;428 BaseTypeObj["USR"] = toHex(toStringRef(I.BaseType->Type.USR));429 Obj["BaseType"] = BaseTypeVal;430 }431 432 if (!I.Members.empty())433 serializeArray(I.Members, Obj, "Members", SerializeInfoLambda);434}435 436static void serializeInfo(const TypedefInfo &I, json::Object &Obj,437 const std::optional<StringRef> &RepositoryUrl) {438 serializeCommonAttributes(I, Obj, RepositoryUrl);439 Obj["TypeDeclaration"] = I.TypeDeclaration;440 Obj["IsUsing"] = I.IsUsing;441 json::Value TypeVal = Object();442 auto &TypeObj = *TypeVal.getAsObject();443 serializeInfo(I.Underlying, TypeObj);444 Obj["Underlying"] = TypeVal;445}446 447static void serializeInfo(const BaseRecordInfo &I, Object &Obj,448 const std::optional<StringRef> &RepositoryUrl) {449 serializeInfo(static_cast<const RecordInfo &>(I), Obj, RepositoryUrl);450 Obj["IsVirtual"] = I.IsVirtual;451 Obj["Access"] = getAccessSpelling(I.Access);452 Obj["IsParent"] = I.IsParent;453}454 455static void serializeInfo(const FriendInfo &I, Object &Obj) {456 auto FriendRef = Object();457 serializeReference(I.Ref, FriendRef);458 Obj["Reference"] = std::move(FriendRef);459 Obj["IsClass"] = I.IsClass;460 if (I.Template)461 serializeInfo(I.Template.value(), Obj);462 if (I.Params)463 serializeArray(I.Params.value(), Obj, "Params", SerializeInfoLambda);464 if (I.ReturnType) {465 auto ReturnTypeObj = Object();466 serializeInfo(I.ReturnType.value(), ReturnTypeObj);467 Obj["ReturnType"] = std::move(ReturnTypeObj);468 }469}470 471static void insertArray(Object &Obj, json::Value &Array, StringRef Key) {472 Obj[Key] = Array;473 Obj["Has" + Key.str()] = true;474}475 476static void serializeInfo(const RecordInfo &I, json::Object &Obj,477 const std::optional<StringRef> &RepositoryUrl) {478 serializeCommonAttributes(I, Obj, RepositoryUrl);479 Obj["TagType"] = getTagType(I.TagType);480 Obj["IsTypedef"] = I.IsTypeDef;481 Obj["MangledName"] = I.MangledName;482 483 if (!I.Children.Functions.empty()) {484 json::Value PubFunctionsArray = Array();485 json::Array &PubFunctionsArrayRef = *PubFunctionsArray.getAsArray();486 json::Value ProtFunctionsArray = Array();487 json::Array &ProtFunctionsArrayRef = *ProtFunctionsArray.getAsArray();488 489 for (const auto &Function : I.Children.Functions) {490 json::Value FunctionVal = Object();491 auto &FunctionObj = *FunctionVal.getAsObject();492 serializeInfo(Function, FunctionObj, RepositoryUrl);493 AccessSpecifier Access = Function.Access;494 if (Access == AccessSpecifier::AS_public)495 PubFunctionsArrayRef.push_back(FunctionVal);496 else if (Access == AccessSpecifier::AS_protected)497 ProtFunctionsArrayRef.push_back(FunctionVal);498 }499 500 if (!PubFunctionsArrayRef.empty())501 insertArray(Obj, PubFunctionsArray, "PublicFunctions");502 if (!ProtFunctionsArrayRef.empty())503 Obj["ProtectedFunctions"] = ProtFunctionsArray;504 }505 506 if (!I.Members.empty()) {507 json::Value PublicMembersArray = Array();508 json::Array &PubMembersArrayRef = *PublicMembersArray.getAsArray();509 json::Value ProtectedMembersArray = Array();510 json::Array &ProtMembersArrayRef = *ProtectedMembersArray.getAsArray();511 512 for (const MemberTypeInfo &Member : I.Members) {513 json::Value MemberVal = Object();514 auto &MemberObj = *MemberVal.getAsObject();515 MemberObj["Name"] = Member.Name;516 MemberObj["Type"] = Member.Type.Name;517 518 if (Member.Access == AccessSpecifier::AS_public)519 PubMembersArrayRef.push_back(MemberVal);520 else if (Member.Access == AccessSpecifier::AS_protected)521 ProtMembersArrayRef.push_back(MemberVal);522 }523 524 if (!PubMembersArrayRef.empty())525 insertArray(Obj, PublicMembersArray, "PublicMembers");526 if (!ProtMembersArrayRef.empty())527 Obj["ProtectedMembers"] = ProtectedMembersArray;528 }529 530 if (!I.Bases.empty())531 serializeArray(532 I.Bases, Obj, "Bases",533 [&RepositoryUrl](const BaseRecordInfo &Base, Object &BaseObj) {534 serializeInfo(Base, BaseObj, RepositoryUrl);535 });536 537 if (!I.Parents.empty())538 serializeArray(I.Parents, Obj, "Parents", SerializeReferenceLambda);539 540 if (!I.VirtualParents.empty())541 serializeArray(I.VirtualParents, Obj, "VirtualParents",542 SerializeReferenceLambda);543 544 if (I.Template)545 serializeInfo(I.Template.value(), Obj);546 547 if (!I.Friends.empty())548 serializeArray(I.Friends, Obj, "Friends", SerializeInfoLambda);549 550 serializeCommonChildren(I.Children, Obj, RepositoryUrl);551}552 553static void serializeInfo(const VarInfo &I, json::Object &Obj,554 const std::optional<StringRef> RepositoryUrl) {555 serializeCommonAttributes(I, Obj, RepositoryUrl);556 Obj["IsStatic"] = I.IsStatic;557 auto TypeObj = Object();558 serializeInfo(I.Type, TypeObj);559 Obj["Type"] = std::move(TypeObj);560}561 562static void serializeInfo(const NamespaceInfo &I, json::Object &Obj,563 const std::optional<StringRef> RepositoryUrl) {564 serializeCommonAttributes(I, Obj, RepositoryUrl);565 566 if (!I.Children.Namespaces.empty())567 serializeArray(I.Children.Namespaces, Obj, "Namespaces",568 SerializeReferenceLambda);569 570 static auto SerializeInfo = [RepositoryUrl](const auto &Info,571 Object &Object) {572 serializeInfo(Info, Object, RepositoryUrl);573 };574 575 if (!I.Children.Functions.empty())576 serializeArray(I.Children.Functions, Obj, "Functions", SerializeInfo);577 578 if (!I.Children.Concepts.empty())579 serializeArray(I.Children.Concepts, Obj, "Concepts", SerializeInfo);580 581 if (!I.Children.Variables.empty())582 serializeArray(I.Children.Variables, Obj, "Variables", SerializeInfo);583 584 serializeCommonChildren(I.Children, Obj, RepositoryUrl);585}586 587static SmallString<16> determineFileName(Info *I, SmallString<128> &Path) {588 SmallString<16> FileName;589 if (I->IT == InfoType::IT_record) {590 auto *RecordSymbolInfo = static_cast<SymbolInfo *>(I);591 FileName = RecordSymbolInfo->MangledName;592 } else if (I->IT == InfoType::IT_namespace) {593 FileName = "index";594 } else595 FileName = I->Name;596 sys::path::append(Path, FileName + ".json");597 return FileName;598}599 600Error JSONGenerator::generateDocumentation(601 StringRef RootDir, llvm::StringMap<std::unique_ptr<doc::Info>> Infos,602 const ClangDocContext &CDCtx, std::string DirName) {603 StringSet<> CreatedDirs;604 StringMap<std::vector<doc::Info *>> FileToInfos;605 for (const auto &Group : Infos) {606 Info *Info = Group.getValue().get();607 608 SmallString<128> Path;609 auto RootDirStr = RootDir.str() + "/json";610 StringRef JSONDir = StringRef(RootDirStr);611 sys::path::native(JSONDir, Path);612 sys::path::append(Path, Info->getRelativeFilePath(""));613 if (!CreatedDirs.contains(Path)) {614 if (std::error_code Err = sys::fs::create_directories(Path);615 Err != std::error_code())616 return createFileError(Twine(Path), Err);617 CreatedDirs.insert(Path);618 }619 620 SmallString<16> FileName = determineFileName(Info, Path);621 if (FileToInfos.contains(Path))622 continue;623 FileToInfos[Path].push_back(Info);624 Info->DocumentationFileName = FileName;625 }626 627 for (const auto &Group : FileToInfos) {628 std::error_code FileErr;629 raw_fd_ostream InfoOS(Group.getKey(), FileErr, sys::fs::OF_Text);630 if (FileErr)631 return createFileError("cannot open file " + Group.getKey(), FileErr);632 633 for (const auto &Info : Group.getValue())634 if (Error Err = generateDocForInfo(Info, InfoOS, CDCtx))635 return Err;636 }637 638 return Error::success();639}640 641Error JSONGenerator::generateDocForInfo(Info *I, raw_ostream &OS,642 const ClangDocContext &CDCtx) {643 json::Object Obj = Object();644 645 switch (I->IT) {646 case InfoType::IT_namespace:647 serializeInfo(*static_cast<NamespaceInfo *>(I), Obj, CDCtx.RepositoryUrl);648 break;649 case InfoType::IT_record:650 serializeInfo(*static_cast<RecordInfo *>(I), Obj, CDCtx.RepositoryUrl);651 break;652 case InfoType::IT_concept:653 case InfoType::IT_enum:654 case InfoType::IT_function:655 case InfoType::IT_typedef:656 case InfoType::IT_variable:657 case InfoType::IT_friend:658 break;659 case InfoType::IT_default:660 return createStringError(inconvertibleErrorCode(), "unexpected info type");661 }662 OS << llvm::formatv("{0:2}", llvm::json::Value(std::move(Obj)));663 return Error::success();664}665 666Error JSONGenerator::createResources(ClangDocContext &CDCtx) {667 return Error::success();668}669 670static GeneratorRegistry::Add<JSONGenerator> JSON(JSONGenerator::Format,671 "Generator for JSON output.");672volatile int JSONGeneratorAnchorSource = 0;673} // namespace doc674} // namespace clang675