-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[clang-doc] Extract Info into JSON values #138063
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: users/ilovepi/clang-doc-mustache-templete-helper
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -162,15 +162,271 @@ Error MustacheHTMLGenerator::generateDocs( | |||||
return Error::success(); | ||||||
} | ||||||
|
||||||
static json::Value | ||||||
extractValue(const Location &L, | ||||||
std::optional<StringRef> RepositoryUrl = std::nullopt) { | ||||||
Object Obj = Object(); | ||||||
// TODO: Consider using both Start/End line numbers to improve location report | ||||||
Obj.insert({"LineNumber", L.StartLineNumber}); | ||||||
Obj.insert({"Filename", L.Filename}); | ||||||
|
||||||
if (!L.IsFileInRootDir || !RepositoryUrl) | ||||||
return Obj; | ||||||
SmallString<128> FileURL(*RepositoryUrl); | ||||||
sys::path::append(FileURL, sys::path::Style::posix, L.Filename); | ||||||
FileURL += "#" + std::to_string(L.StartLineNumber); | ||||||
Obj.insert({"FileURL", FileURL}); | ||||||
|
||||||
return Obj; | ||||||
} | ||||||
|
||||||
static json::Value extractValue(const Reference &I, | ||||||
StringRef CurrentDirectory) { | ||||||
SmallString<64> Path = I.getRelativeFilePath(CurrentDirectory); | ||||||
sys::path::append(Path, I.getFileBaseName() + ".html"); | ||||||
sys::path::native(Path, sys::path::Style::posix); | ||||||
Object Obj = Object(); | ||||||
Obj.insert({"Link", Path}); | ||||||
Obj.insert({"Name", I.Name}); | ||||||
Obj.insert({"QualName", I.QualName}); | ||||||
Obj.insert({"ID", toHex(toStringRef(I.USR))}); | ||||||
return Obj; | ||||||
} | ||||||
|
||||||
static json::Value extractValue(const TypedefInfo &I) { | ||||||
// Not Supported | ||||||
return nullptr; | ||||||
} | ||||||
|
||||||
static json::Value extractValue(const CommentInfo &I) { | ||||||
assert((I.Kind == "BlockCommandComment" || I.Kind == "FullComment" || | ||||||
I.Kind == "ParagraphComment" || I.Kind == "TextComment") && | ||||||
"Unknown Comment type in CommentInfo."); | ||||||
|
||||||
Object Obj = Object(); | ||||||
json::Value Child = Object(); | ||||||
|
||||||
// TextComment has no children, so return it. | ||||||
if (I.Kind == "TextComment") { | ||||||
Obj.insert({"TextComment", I.Text}); | ||||||
return Obj; | ||||||
} | ||||||
|
||||||
// BlockCommandComment needs to generate a Command key. | ||||||
if (I.Kind == "BlockCommandComment") | ||||||
Child.getAsObject()->insert({"Command", I.Name}); | ||||||
|
||||||
// Use the same handling for everything else. | ||||||
// Only valid for: | ||||||
// - BlockCommandComment | ||||||
// - FullComment | ||||||
// - ParagraphComment | ||||||
json::Value ChildArr = Array(); | ||||||
auto &CARef = *ChildArr.getAsArray(); | ||||||
CARef.reserve(I.Children.size()); | ||||||
for (const auto &C : I.Children) | ||||||
CARef.emplace_back(extractValue(*C)); | ||||||
Child.getAsObject()->insert({"Children", ChildArr}); | ||||||
Obj.insert({I.Kind, Child}); | ||||||
|
||||||
return Obj; | ||||||
} | ||||||
|
||||||
static void maybeInsertLocation(std::optional<Location> Loc, | ||||||
const ClangDocContext &CDCtx, Object &Obj) { | ||||||
if (!Loc) | ||||||
return; | ||||||
Location L = *Loc; | ||||||
Obj.insert({"Location", extractValue(L, CDCtx.RepositoryUrl)}); | ||||||
} | ||||||
|
||||||
static void extractDescriptionFromInfo(ArrayRef<CommentInfo> Descriptions, | ||||||
json::Object &EnumValObj) { | ||||||
if (Descriptions.empty()) | ||||||
return; | ||||||
json::Value DescArr = Array(); | ||||||
json::Array &DescARef = *DescArr.getAsArray(); | ||||||
for (const CommentInfo &Child : Descriptions) | ||||||
DescARef.emplace_back(extractValue(Child)); | ||||||
EnumValObj.insert({"EnumValueComments", DescArr}); | ||||||
} | ||||||
|
||||||
static json::Value extractValue(const FunctionInfo &I, StringRef ParentInfoDir, | ||||||
const ClangDocContext &CDCtx) { | ||||||
Object Obj = Object(); | ||||||
Obj.insert({"Name", I.Name}); | ||||||
Obj.insert({"ID", toHex(toStringRef(I.USR))}); | ||||||
Obj.insert({"Access", getAccessSpelling(I.Access).str()}); | ||||||
Obj.insert({"ReturnType", extractValue(I.ReturnType.Type, ParentInfoDir)}); | ||||||
|
||||||
json::Value ParamArr = Array(); | ||||||
json::Array &ParamARef = *ParamArr.getAsArray(); | ||||||
for (const auto Val : enumerate(I.Params)) { | ||||||
json::Value V = Object(); | ||||||
auto &VRef = *V.getAsObject(); | ||||||
VRef.insert({"Name", Val.value().Name}); | ||||||
VRef.insert({"Type", Val.value().Type.Name}); | ||||||
VRef.insert({"End", Val.index() + 1 == I.Params.size()}); | ||||||
ParamARef.emplace_back(V); | ||||||
} | ||||||
Obj.insert({"Params", ParamArr}); | ||||||
|
||||||
maybeInsertLocation(I.DefLoc, CDCtx, Obj); | ||||||
return Obj; | ||||||
} | ||||||
|
||||||
static json::Value extractValue(const EnumInfo &I, | ||||||
const ClangDocContext &CDCtx) { | ||||||
Object Obj = Object(); | ||||||
std::string EnumType = I.Scoped ? "enum class " : "enum "; | ||||||
EnumType += I.Name; | ||||||
bool HasComment = std::any_of( | ||||||
I.Members.begin(), I.Members.end(), | ||||||
[](const EnumValueInfo &M) { return !M.Description.empty(); }); | ||||||
Obj.insert({"EnumName", EnumType}); | ||||||
Obj.insert({"HasComment", HasComment}); | ||||||
Obj.insert({"ID", toHex(toStringRef(I.USR))}); | ||||||
json::Value EnumArr = Array(); | ||||||
json::Array &EnumARef = *EnumArr.getAsArray(); | ||||||
for (const EnumValueInfo &M : I.Members) { | ||||||
json::Value EnumValue = Object(); | ||||||
auto &EnumValObj = *EnumValue.getAsObject(); | ||||||
EnumValObj.insert({"Name", M.Name}); | ||||||
if (!M.ValueExpr.empty()) | ||||||
EnumValObj.insert({"ValueExpr", M.ValueExpr}); | ||||||
else | ||||||
EnumValObj.insert({"Value", M.Value}); | ||||||
|
||||||
extractDescriptionFromInfo(M.Description, EnumValObj); | ||||||
EnumARef.emplace_back(EnumValue); | ||||||
} | ||||||
Obj.insert({"EnumValues", EnumArr}); | ||||||
|
||||||
extractDescriptionFromInfo(I.Description, Obj); | ||||||
maybeInsertLocation(I.DefLoc, CDCtx, Obj); | ||||||
|
||||||
return Obj; | ||||||
} | ||||||
|
||||||
static void extractScopeChildren(const ScopeChildren &S, Object &Obj, | ||||||
StringRef ParentInfoDir, | ||||||
const ClangDocContext &CDCtx) { | ||||||
json::Value NamespaceArr = Array(); | ||||||
json::Array &NamespaceARef = *NamespaceArr.getAsArray(); | ||||||
for (const Reference &Child : S.Namespaces) | ||||||
NamespaceARef.emplace_back(extractValue(Child, ParentInfoDir)); | ||||||
|
||||||
if (!NamespaceARef.empty()) | ||||||
Obj.insert({"Namespace", Object{{"Links", NamespaceArr}}}); | ||||||
|
||||||
json::Value RecordArr = Array(); | ||||||
json::Array &RecordARef = *RecordArr.getAsArray(); | ||||||
for (const Reference &Child : S.Records) | ||||||
RecordARef.emplace_back(extractValue(Child, ParentInfoDir)); | ||||||
|
||||||
if (!RecordARef.empty()) | ||||||
Obj.insert({"Record", Object{{"Links", RecordArr}}}); | ||||||
|
||||||
json::Value FunctionArr = Array(); | ||||||
json::Array &FunctionARef = *FunctionArr.getAsArray(); | ||||||
|
||||||
json::Value PublicFunction = Array(); | ||||||
json::Array &PublicFunctionARef = *PublicFunction.getAsArray(); | ||||||
|
||||||
json::Value ProtectedFunction = Array(); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
nit |
||||||
json::Array &ProtectedFunctionARef = *ProtectedFunction.getAsArray(); | ||||||
|
||||||
for (const FunctionInfo &Child : S.Functions) { | ||||||
json::Value F = extractValue(Child, ParentInfoDir, CDCtx); | ||||||
AccessSpecifier Access = Child.Access; | ||||||
if (Access == AccessSpecifier::AS_public) | ||||||
PublicFunctionARef.emplace_back(F); | ||||||
else if (Access == AccessSpecifier::AS_protected) | ||||||
ProtectedFunctionARef.emplace_back(F); | ||||||
else | ||||||
FunctionARef.emplace_back(F); | ||||||
} | ||||||
|
||||||
if (!FunctionARef.empty()) | ||||||
Obj.insert({"Function", Object{{"Obj", FunctionArr}}}); | ||||||
|
||||||
if (!PublicFunctionARef.empty()) | ||||||
Obj.insert({"PublicFunction", Object{{"Obj", PublicFunction}}}); | ||||||
|
||||||
if (!ProtectedFunctionARef.empty()) | ||||||
Obj.insert({"ProtectedFunction", Object{{"Obj", ProtectedFunction}}}); | ||||||
|
||||||
json::Value ArrEnum = Array(); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
auto &ArrEnumRef = *ArrEnum.getAsArray(); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
for (const EnumInfo &Child : S.Enums) | ||||||
ArrEnumRef.emplace_back(extractValue(Child, CDCtx)); | ||||||
|
||||||
if (!ArrEnumRef.empty()) | ||||||
Obj.insert({"Enums", Object{{"Obj", ArrEnum}}}); | ||||||
|
||||||
json::Value ArrTypedefs = Array(); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
auto &ArrTypedefsRef = *ArrTypedefs.getAsArray(); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
for (const TypedefInfo &Child : S.Typedefs) | ||||||
ArrTypedefsRef.emplace_back(extractValue(Child)); | ||||||
|
||||||
if (!ArrTypedefsRef.empty()) | ||||||
Obj.insert({"Typedefs", Object{{"Obj", ArrTypedefs}}}); | ||||||
} | ||||||
|
||||||
static json::Value extractValue(const NamespaceInfo &I, | ||||||
const ClangDocContext &CDCtx) { | ||||||
Object NamespaceValue = Object(); | ||||||
std::string InfoTitle = I.Name.empty() ? "Global Namespace" | ||||||
: (Twine("namespace ") + I.Name).str(); | ||||||
|
||||||
SmallString<64> BasePath = I.getRelativeFilePath(""); | ||||||
NamespaceValue.insert({"NamespaceTitle", InfoTitle}); | ||||||
NamespaceValue.insert({"NamespacePath", BasePath}); | ||||||
|
||||||
extractDescriptionFromInfo(I.Description, NamespaceValue); | ||||||
extractScopeChildren(I.Children, NamespaceValue, BasePath, CDCtx); | ||||||
return NamespaceValue; | ||||||
} | ||||||
|
||||||
static json::Value extractValue(const RecordInfo &I, | ||||||
const ClangDocContext &CDCtx) { | ||||||
Object RecordValue = Object(); | ||||||
extractDescriptionFromInfo(I.Description, RecordValue); | ||||||
RecordValue.insert({"Name", I.Name}); | ||||||
RecordValue.insert({"FullName", I.FullName}); | ||||||
RecordValue.insert({"RecordType", getTagType(I.TagType)}); | ||||||
|
||||||
maybeInsertLocation(I.DefLoc, CDCtx, RecordValue); | ||||||
|
||||||
StringRef BasePath = I.getRelativeFilePath(""); | ||||||
extractScopeChildren(I.Children, RecordValue, BasePath, CDCtx); | ||||||
json::Value PublicMembers = Array(); | ||||||
json::Array &PubMemberRef = *PublicMembers.getAsArray(); | ||||||
json::Value ProtectedMembers = Array(); | ||||||
json::Array &ProtMemberRef = *ProtectedMembers.getAsArray(); | ||||||
json::Value PrivateMembers = Array(); | ||||||
json::Array &PrivMemberRef = *PrivateMembers.getAsArray(); | ||||||
for (const MemberTypeInfo &Member : I.Members) { | ||||||
json::Value MemberValue = Object(); | ||||||
auto &MVRef = *MemberValue.getAsObject(); | ||||||
MVRef.insert({"Name", Member.Name}); | ||||||
MVRef.insert({"Type", Member.Type.Name}); | ||||||
extractDescriptionFromInfo(Member.Description, MVRef); | ||||||
|
||||||
if (Member.Access == AccessSpecifier::AS_public) | ||||||
PubMemberRef.emplace_back(MemberValue); | ||||||
else if (Member.Access == AccessSpecifier::AS_protected) | ||||||
ProtMemberRef.emplace_back(MemberValue); | ||||||
else if (Member.Access == AccessSpecifier::AS_private) | ||||||
ProtMemberRef.emplace_back(MemberValue); | ||||||
} | ||||||
if (!PubMemberRef.empty()) | ||||||
RecordValue.insert({"PublicMembers", Object{{"Obj", PublicMembers}}}); | ||||||
if (!ProtMemberRef.empty()) | ||||||
RecordValue.insert({"ProtectedMembers", Object{{"Obj", ProtectedMembers}}}); | ||||||
if (!PrivMemberRef.empty()) | ||||||
RecordValue.insert({"PrivateMembers", Object{{"Obj", PrivateMembers}}}); | ||||||
|
||||||
return RecordValue; | ||||||
} | ||||||
|
||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit