diff options
Diffstat (limited to 'clang-tools-extra/clang-doc/JSONGenerator.cpp')
-rw-r--r-- | clang-tools-extra/clang-doc/JSONGenerator.cpp | 145 |
1 files changed, 115 insertions, 30 deletions
diff --git a/clang-tools-extra/clang-doc/JSONGenerator.cpp b/clang-tools-extra/clang-doc/JSONGenerator.cpp index cc4c683..599b381 100644 --- a/clang-tools-extra/clang-doc/JSONGenerator.cpp +++ b/clang-tools-extra/clang-doc/JSONGenerator.cpp @@ -43,6 +43,30 @@ static auto SerializeReferenceLambda = [](const auto &Ref, Object &Object) { serializeReference(Ref, Object); }; +static std::string infoTypeToString(InfoType IT) { + switch (IT) { + case InfoType::IT_default: + return "default"; + case InfoType::IT_namespace: + return "namespace"; + case InfoType::IT_record: + return "record"; + case InfoType::IT_function: + return "function"; + case InfoType::IT_enum: + return "enum"; + case InfoType::IT_typedef: + return "typedef"; + case InfoType::IT_concept: + return "concept"; + case InfoType::IT_variable: + return "variable"; + case InfoType::IT_friend: + return "friend"; + } + llvm_unreachable("Unknown InfoType encountered."); +} + static json::Object serializeLocation(const Location &Loc, const std::optional<StringRef> RepositoryUrl) { @@ -59,7 +83,39 @@ serializeLocation(const Location &Loc, return LocationObj; } -static json::Value serializeComment(const CommentInfo &I) { +static void insertComment(Object &Description, json::Value &Comment, + StringRef Key) { + auto DescriptionIt = Description.find(Key); + + if (DescriptionIt == Description.end()) { + auto CommentsArray = json::Array(); + CommentsArray.push_back(Comment); + Description[Key] = std::move(CommentsArray); + Description["Has" + Key.str()] = true; + } else { + DescriptionIt->getSecond().getAsArray()->push_back(Comment); + } +} + +static json::Value extractTextComments(Object *ParagraphComment) { + if (!ParagraphComment) + return json::Object(); + return *ParagraphComment->get("Children"); +} + +static json::Value extractVerbatimComments(json::Array VerbatimLines) { + json::Value TextArray = json::Array(); + auto &TextArrayRef = *TextArray.getAsArray(); + for (auto &Line : VerbatimLines) + TextArrayRef.push_back(*Line.getAsObject() + ->get("VerbatimBlockLineComment") + ->getAsObject() + ->get("Text")); + + return TextArray; +} + +static Object serializeComment(const CommentInfo &I, Object &Description) { // taken from PR #142273 Object Obj = Object(); @@ -70,7 +126,7 @@ static json::Value serializeComment(const CommentInfo &I) { auto &CARef = *ChildArr.getAsArray(); CARef.reserve(I.Children.size()); for (const auto &C : I.Children) - CARef.emplace_back(serializeComment(*C)); + CARef.emplace_back(serializeComment(*C, Description)); switch (I.Kind) { case CommentKind::CK_TextComment: { @@ -79,9 +135,11 @@ static json::Value serializeComment(const CommentInfo &I) { } case CommentKind::CK_BlockCommandComment: { - Child.insert({"Command", I.Name}); - Child.insert({"Children", ChildArr}); - Obj.insert({commentKindToString(I.Kind), ChildVal}); + auto TextCommentsArray = extractTextComments(CARef.front().getAsObject()); + if (I.Name == "brief") + insertComment(Description, TextCommentsArray, "BriefComments"); + else if (I.Name == "return") + insertComment(Description, TextCommentsArray, "ReturnComments"); return Obj; } @@ -103,17 +161,20 @@ static json::Value serializeComment(const CommentInfo &I) { Child.insert({"ParamName", I.ParamName}); Child.insert({"Direction", I.Direction}); Child.insert({"Explicit", I.Explicit}); - Child.insert({"Children", ChildArr}); - Obj.insert({commentKindToString(I.Kind), ChildVal}); + auto TextCommentsArray = extractTextComments(CARef.front().getAsObject()); + Child.insert({"Children", TextCommentsArray}); + if (I.Kind == CommentKind::CK_ParamCommandComment) + insertComment(Description, ChildVal, "ParamComments"); return Obj; } case CommentKind::CK_VerbatimBlockComment: { - Child.insert({"Text", I.Text}); - if (!I.CloseName.empty()) - Child.insert({"CloseName", I.CloseName}); - Child.insert({"Children", ChildArr}); - Obj.insert({commentKindToString(I.Kind), ChildVal}); + if (I.CloseName == "endcode") { + // We don't support \code language specification + auto TextCommentsArray = extractVerbatimComments(CARef); + insertComment(Description, TextCommentsArray, "CodeComments"); + } else if (I.CloseName == "endverbatim") + insertComment(Description, ChildVal, "VerbatimComments"); return Obj; } @@ -155,8 +216,8 @@ static json::Value serializeComment(const CommentInfo &I) { case CommentKind::CK_FullComment: case CommentKind::CK_ParagraphComment: { Child.insert({"Children", ChildArr}); - Obj.insert({commentKindToString(I.Kind), ChildVal}); - return Obj; + Child["ParagraphComment"] = true; + return Child; } case CommentKind::CK_Unknown: { @@ -172,6 +233,9 @@ serializeCommonAttributes(const Info &I, json::Object &Obj, const std::optional<StringRef> RepositoryUrl) { Obj["Name"] = I.Name; Obj["USR"] = toHex(toStringRef(I.USR)); + Obj["InfoType"] = infoTypeToString(I.IT); + if (!I.DocumentationFileName.empty()) + Obj["DocumentationFileName"] = I.DocumentationFileName; if (!I.Path.empty()) Obj["Path"] = I.Path; @@ -183,12 +247,20 @@ serializeCommonAttributes(const Info &I, json::Object &Obj, } if (!I.Description.empty()) { - json::Value DescArray = json::Array(); - auto &DescArrayRef = *DescArray.getAsArray(); - DescArrayRef.reserve(I.Description.size()); - for (const auto &Comment : I.Description) - DescArrayRef.push_back(serializeComment(Comment)); - Obj["Description"] = DescArray; + Object Description = Object(); + // Skip straight to the FullComment's children + auto &Comments = I.Description.at(0).Children; + for (const auto &CommentInfo : Comments) { + json::Value Comment = serializeComment(*CommentInfo, Description); + // if a ParagraphComment is returned, then it is a top-level comment that + // needs to be inserted manually. + if (auto *ParagraphComment = Comment.getAsObject(); + ParagraphComment->get("ParagraphComment")) { + auto TextCommentsArray = extractTextComments(ParagraphComment); + insertComment(Description, TextCommentsArray, "ParagraphComments"); + } + } + Obj["Description"] = std::move(Description); } // Namespaces aren't SymbolInfos, so they dont have a DefLoc @@ -205,6 +277,8 @@ static void serializeReference(const Reference &Ref, Object &ReferenceObj) { ReferenceObj["Name"] = Ref.Name; ReferenceObj["QualName"] = Ref.QualName; ReferenceObj["USR"] = toHex(toStringRef(Ref.USR)); + if (!Ref.DocumentationFileName.empty()) + ReferenceObj["DocumentationFileName"] = Ref.DocumentationFileName; } // Although namespaces and records both have ScopeChildren, they serialize them @@ -217,14 +291,18 @@ serializeCommonChildren(const ScopeChildren &Children, json::Object &Obj, serializeInfo(Info, Object, RepositoryUrl); }; - if (!Children.Enums.empty()) + if (!Children.Enums.empty()) { serializeArray(Children.Enums, Obj, "Enums", SerializeInfo); + Obj["HasEnums"] = true; + } if (!Children.Typedefs.empty()) serializeArray(Children.Typedefs, Obj, "Typedefs", SerializeInfo); - if (!Children.Records.empty()) + if (!Children.Records.empty()) { serializeArray(Children.Records, Obj, "Records", SerializeReferenceLambda); + Obj["HasRecords"] = true; + } } template <typename Container, typename SerializationFunc> @@ -234,10 +312,12 @@ static void serializeArray(const Container &Records, Object &Obj, json::Value RecordsArray = Array(); auto &RecordsArrayRef = *RecordsArray.getAsArray(); RecordsArrayRef.reserve(Records.size()); - for (const auto &Item : Records) { + for (size_t Index = 0; Index < Records.size(); ++Index) { json::Value ItemVal = Object(); auto &ItemObj = *ItemVal.getAsObject(); - SerializeInfo(Item, ItemObj); + SerializeInfo(Records[Index], ItemObj); + if (Index == Records.size() - 1) + ItemObj["End"] = true; RecordsArrayRef.push_back(ItemVal); } Obj[Key] = RecordsArray; @@ -380,6 +460,11 @@ static void serializeInfo(const FriendInfo &I, Object &Obj) { } } +static void insertArray(Object &Obj, json::Value &Array, StringRef Key) { + Obj[Key] = Array; + Obj["Has" + Key.str()] = true; +} + static void serializeInfo(const RecordInfo &I, json::Object &Obj, const std::optional<StringRef> &RepositoryUrl) { serializeCommonAttributes(I, Obj, RepositoryUrl); @@ -406,7 +491,7 @@ static void serializeInfo(const RecordInfo &I, json::Object &Obj, } if (!PubFunctionsArrayRef.empty()) - Obj["PublicFunctions"] = PubFunctionsArray; + insertArray(Obj, PubFunctionsArray, "PublicFunctions"); if (!ProtFunctionsArrayRef.empty()) Obj["ProtectedFunctions"] = ProtFunctionsArray; } @@ -430,7 +515,7 @@ static void serializeInfo(const RecordInfo &I, json::Object &Obj, } if (!PubMembersArrayRef.empty()) - Obj["PublicMembers"] = PublicMembersArray; + insertArray(Obj, PublicMembersArray, "PublicMembers"); if (!ProtMembersArrayRef.empty()) Obj["ProtectedMembers"] = ProtectedMembersArray; } @@ -496,10 +581,7 @@ static SmallString<16> determineFileName(Info *I, SmallString<128> &Path) { SmallString<16> FileName; if (I->IT == InfoType::IT_record) { auto *RecordSymbolInfo = static_cast<SymbolInfo *>(I); - if (RecordSymbolInfo->MangledName.size() < 255) - FileName = RecordSymbolInfo->MangledName; - else - FileName = toStringRef(toHex(RecordSymbolInfo->USR)); + FileName = RecordSymbolInfo->MangledName; } else if (I->IT == InfoType::IT_namespace && I->Name != "") // Serialize the global namespace as index.json FileName = I->Name; @@ -527,7 +609,10 @@ Error JSONGenerator::generateDocs( } SmallString<16> FileName = determineFileName(Info, Path); + if (FileToInfos.contains(Path)) + continue; FileToInfos[Path].push_back(Info); + Info->DocumentationFileName = FileName; } for (const auto &Group : FileToInfos) { |