diff --git a/clang-tools-extra/clang-doc/JSONGenerator.cpp b/clang-tools-extra/clang-doc/JSONGenerator.cpp index 30243c9f3df5c..75302b0dc3264 100644 --- a/clang-tools-extra/clang-doc/JSONGenerator.cpp +++ b/clang-tools-extra/clang-doc/JSONGenerator.cpp @@ -83,7 +83,21 @@ 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 Object serializeComment(const CommentInfo &I, Object &Description) { // taken from PR #142273 Object Obj = Object(); @@ -94,7 +108,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: { @@ -104,8 +118,13 @@ static json::Value serializeComment(const CommentInfo &I) { case CommentKind::CK_BlockCommandComment: { Child.insert({"Command", I.Name}); + // TODO: The "Children" level of nesting isn't needed for comments that + // don't hold additional information at the top level. BriefComments can + // just be an array of ParagraphComments. Child.insert({"Children", ChildArr}); Obj.insert({commentKindToString(I.Kind), ChildVal}); + if (I.Name == "brief") + insertComment(Description, ChildVal, "BriefComments"); return Obj; } @@ -137,7 +156,10 @@ static json::Value serializeComment(const CommentInfo &I) { if (!I.CloseName.empty()) Child.insert({"CloseName", I.CloseName}); Child.insert({"Children", ChildArr}); - Obj.insert({commentKindToString(I.Kind), ChildVal}); + if (I.CloseName == "endcode") + insertComment(Description, ChildVal, "CodeComments"); + else if (I.CloseName == "endverbatim") + insertComment(Description, ChildVal, "VerbatimComments"); return Obj; } @@ -210,12 +232,18 @@ 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()->get("ParagraphComment")) + insertComment(Description, *ParagraphComment, "ParagraphComments"); + } + Obj["Description"] = std::move(Description); } // Namespaces aren't SymbolInfos, so they dont have a DefLoc diff --git a/clang-tools-extra/test/clang-doc/json/class.cpp b/clang-tools-extra/test/clang-doc/json/class.cpp index a36358982b019..e8fafca28a956 100644 --- a/clang-tools-extra/test/clang-doc/json/class.cpp +++ b/clang-tools-extra/test/clang-doc/json/class.cpp @@ -33,33 +33,30 @@ struct MyClass { }; // CHECK: { -// CHECK-NEXT: "Description": [ -// CHECK-NEXT: { -// CHECK-NEXT: "FullComment": { -// CHECK-NEXT: "Children": [ -// CHECK-NEXT: { -// CHECK-NEXT: "ParagraphComment": { -// CHECK-NEXT: "Children": [ -// CHECK-NEXT: { -// CHECK-NEXT: "TextComment": " This is a nice class." -// CHECK-NEXT: }, -// CHECK-NEXT: { -// CHECK-NEXT: "TextComment": " It has some nice methods and fields." -// CHECK-NEXT: }, -// CHECK-NEXT: { -// CHECK-NEXT: "TextComment": "" -// CHECK-NEXT: } -// CHECK-NEXT: ] -// CHECK: { -// CHECK-NEXT: "BlockCommandComment": { -// CHECK-NEXT: "Children": [ -// CHECK-NEXT: { -// CHECK-NEXT: "ParagraphComment": { -// CHECK-NEXT: "Children": [ -// CHECK-NEXT: { -// CHECK-NEXT: "TextComment": " This is a brief description." -// CHECK-NEXT: } -// CHECK: "Command": "brief" +// CHECK-NEXT: "Description": { +// CHECK-NEXT: "BriefComments": [ +// CHECK-NEXT: { +// CHECK-NEXT: "Children": [ +// CHECK-NEXT: { +// CHECK-NEXT: "ParagraphComment": { +// CHECK-NEXT: "Children": [ +// CHECK-NEXT: { +// CHECK-NEXT: "TextComment": " This is a brief description." +// CHECK: "Command": "brief" +// CHECK: "HasBriefComments": true, +// CHECK-NEXT: "HasParagraphComments": true, +// CHECK-NEXT: "ParagraphComments": [ +// CHECK-NEXT: { +// CHECK-NEXT: "Children": [ +// CHECK-NEXT: { +// CHECK-NEXT: "TextComment": " This is a nice class." +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "TextComment": " It has some nice methods and fields." +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "TextComment": "" +// CHECK-NEXT: } // CHECK: "DocumentationFileName": "_ZTV7MyClass", // CHECK: "Enums": [ // CHECK-NEXT: { diff --git a/clang-tools-extra/test/clang-doc/json/concept.cpp b/clang-tools-extra/test/clang-doc/json/concept.cpp index 766415bbbeecd..2874caf28f8f5 100644 --- a/clang-tools-extra/test/clang-doc/json/concept.cpp +++ b/clang-tools-extra/test/clang-doc/json/concept.cpp @@ -13,16 +13,13 @@ concept Incrementable = requires(T x) { // CHECK-NEXT: "Concepts": [ // CHECK-NEXT: { // CHECK-NEXT: "ConstraintExpression": "requires (T x) { ++x; x++; }", -// CHECK-NEXT: "Description": [ +// CHECK-NEXT: "Description": { +// CHECK-NEXT: "HasParagraphComments": true, +// CHECK-NEXT: "ParagraphComments": [ // CHECK-NEXT: { -// CHECK-NEXT: "FullComment": { -// CHECK-NEXT: "Children": [ -// CHECK-NEXT: { -// CHECK-NEXT: "ParagraphComment": { -// CHECK-NEXT: "Children": [ -// CHECK-NEXT: { -// CHECK-NEXT: "TextComment": " Requires that T suports post and pre-incrementing." -// CHECK: ], +// CHECK-NEXT: "Children": [ +// CHECK-NEXT: { +// CHECK-NEXT: "TextComment": " Requires that T suports post and pre-incrementing." // CHECK: "End": true, // CHECK-NEXT: "InfoType": "concept", // CHECK-NEXT: "IsType": true,