aboutsummaryrefslogtreecommitdiff
path: root/clang-tools-extra/clang-doc/JSONGenerator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang-tools-extra/clang-doc/JSONGenerator.cpp')
-rw-r--r--clang-tools-extra/clang-doc/JSONGenerator.cpp145
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) {