Skip to content

Commit cfd35ee

Browse files
ilovepiPeterChou1
andcommitted
[clang-doc] Extract Info into JSON values
Split from #133161. This patch provides the implementation of a number of extractValue overloads used with the different types of Info. The new helper functions extract the relevant information from the different *Infos and inserts them into the correct fields of the JSON values that will be used with the specific Mustache templates, which will land separately. Co-authored-by: Peter Chou <[email protected]>
1 parent 290ea15 commit cfd35ee

File tree

1 file changed

+251
-0
lines changed

1 file changed

+251
-0
lines changed

clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp

Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,15 +141,266 @@ Error MustacheHTMLGenerator::generateDocs(
141141
return Error::success();
142142
}
143143

144+
static json::Value
145+
extractValue(const Location &L,
146+
std::optional<StringRef> RepositoryUrl = std::nullopt) {
147+
Object Obj = Object();
148+
// Should there be Start/End line numbers?
149+
Obj.insert({"LineNumber", L.StartLineNumber});
150+
Obj.insert({"Filename", L.Filename});
151+
152+
if (!L.IsFileInRootDir || !RepositoryUrl) {
153+
return Obj;
154+
}
155+
SmallString<128> FileURL(*RepositoryUrl);
156+
sys::path::append(FileURL, sys::path::Style::posix, L.Filename);
157+
FileURL += "#" + std::to_string(L.StartLineNumber);
158+
Obj.insert({"FileURL", FileURL});
159+
160+
return Obj;
161+
}
162+
163+
static json::Value extractValue(const Reference &I,
164+
StringRef CurrentDirectory) {
165+
SmallString<64> Path = I.getRelativeFilePath(CurrentDirectory);
166+
sys::path::append(Path, I.getFileBaseName() + ".html");
167+
sys::path::native(Path, sys::path::Style::posix);
168+
Object Obj = Object();
169+
Obj.insert({"Link", Path});
170+
Obj.insert({"Name", I.Name});
171+
Obj.insert({"QualName", I.QualName});
172+
Obj.insert({"ID", toHex(toStringRef(I.USR))});
173+
return Obj;
174+
}
175+
176+
static json::Value extractValue(const TypedefInfo &I) {
177+
// Not Supported
178+
return nullptr;
179+
}
180+
181+
static json::Value extractValue(const CommentInfo &I) {
182+
assert((I.Kind == "BlockCommandComment" || I.Kind == "FullComment" ||
183+
I.Kind == "ParagraphComment" || I.Kind == "TextComment") &&
184+
"Unknown Comment type in CommentInfo.");
185+
186+
Object Obj = Object();
187+
json::Value Child = Object();
188+
189+
// TextComment has no children, so return it.
190+
if (I.Kind == "TextComment") {
191+
Obj.insert({"TextComment", I.Text});
192+
return Obj;
193+
}
194+
195+
// BlockCommandComment needs to generate a Command key.
196+
if (I.Kind == "BlockCommandComment") {
197+
Child.getAsObject()->insert({"Command", I.Name});
198+
}
199+
200+
// Use the same handling for everything else.
201+
// Only valid for:
202+
// - BlockCommandComment
203+
// - FullComment
204+
// - ParagraphComment
205+
json::Value ChildArr = Array();
206+
auto &CARef = *ChildArr.getAsArray();
207+
CARef.reserve(I.Children.size());
208+
for (const auto &C : I.Children)
209+
CARef.emplace_back(extractValue(*C));
210+
Child.getAsObject()->insert({"Children", ChildArr});
211+
Obj.insert({I.Kind, Child});
212+
213+
return Obj;
214+
}
215+
216+
static void maybeInsertLocation(std::optional<Location> Loc,
217+
const ClangDocContext &CDCtx, Object &Obj) {
218+
if (!Loc)
219+
return;
220+
Location L = *Loc;
221+
Obj.insert({"Location", extractValue(L, CDCtx.RepositoryUrl)});
222+
}
223+
224+
static void extractDescriptionFromInfo(ArrayRef<CommentInfo> Descriptions,
225+
json::Object &EnumValObj) {
226+
if (Descriptions.empty())
227+
return;
228+
json::Value ArrDesc = Array();
229+
json::Array &ADescRef = *ArrDesc.getAsArray();
230+
for (const CommentInfo &Child : Descriptions)
231+
ADescRef.emplace_back(extractValue(Child));
232+
EnumValObj.insert({"EnumValueComments", ArrDesc});
233+
}
234+
235+
static json::Value extractValue(const FunctionInfo &I, StringRef ParentInfoDir,
236+
const ClangDocContext &CDCtx) {
237+
Object Obj = Object();
238+
Obj.insert({"Name", I.Name});
239+
Obj.insert({"ID", toHex(toStringRef(I.USR))});
240+
Obj.insert({"Access", getAccessSpelling(I.Access).str()});
241+
Obj.insert({"ReturnType", extractValue(I.ReturnType.Type, ParentInfoDir)});
242+
243+
json::Value ParamArr = Array();
244+
for (const auto Val : enumerate(I.Params)) {
245+
json::Value V = Object();
246+
auto &VRef = *V.getAsObject();
247+
VRef.insert({"Name", Val.value().Name});
248+
VRef.insert({"Type", Val.value().Type.Name});
249+
VRef.insert({"End", Val.index() + 1 == I.Params.size()});
250+
ParamArr.getAsArray()->emplace_back(V);
251+
}
252+
Obj.insert({"Params", ParamArr});
253+
254+
maybeInsertLocation(I.DefLoc, CDCtx, Obj);
255+
return Obj;
256+
}
257+
258+
static json::Value extractValue(const EnumInfo &I,
259+
const ClangDocContext &CDCtx) {
260+
Object Obj = Object();
261+
std::string EnumType = I.Scoped ? "enum class " : "enum ";
262+
EnumType += I.Name;
263+
bool HasComment = std::any_of(
264+
I.Members.begin(), I.Members.end(),
265+
[](const EnumValueInfo &M) { return !M.Description.empty(); });
266+
Obj.insert({"EnumName", EnumType});
267+
Obj.insert({"HasComment", HasComment});
268+
Obj.insert({"ID", toHex(toStringRef(I.USR))});
269+
json::Value Arr = Array();
270+
json::Array &ARef = *Arr.getAsArray();
271+
for (const EnumValueInfo &M : I.Members) {
272+
json::Value EnumValue = Object();
273+
auto &EnumValObj = *EnumValue.getAsObject();
274+
EnumValObj.insert({"Name", M.Name});
275+
if (!M.ValueExpr.empty())
276+
EnumValObj.insert({"ValueExpr", M.ValueExpr});
277+
else
278+
EnumValObj.insert({"Value", M.Value});
279+
280+
extractDescriptionFromInfo(M.Description, EnumValObj);
281+
ARef.emplace_back(EnumValue);
282+
}
283+
Obj.insert({"EnumValues", Arr});
284+
285+
extractDescriptionFromInfo(I.Description, Obj);
286+
maybeInsertLocation(I.DefLoc, CDCtx, Obj);
287+
288+
return Obj;
289+
}
290+
291+
static void extractScopeChildren(const ScopeChildren &S, Object &Obj,
292+
StringRef ParentInfoDir,
293+
const ClangDocContext &CDCtx) {
294+
json::Value ArrNamespace = Array();
295+
for (const Reference &Child : S.Namespaces)
296+
ArrNamespace.getAsArray()->emplace_back(extractValue(Child, ParentInfoDir));
297+
298+
if (!ArrNamespace.getAsArray()->empty())
299+
Obj.insert({"Namespace", Object{{"Links", ArrNamespace}}});
300+
301+
json::Value ArrRecord = Array();
302+
for (const Reference &Child : S.Records)
303+
ArrRecord.getAsArray()->emplace_back(extractValue(Child, ParentInfoDir));
304+
305+
if (!ArrRecord.getAsArray()->empty())
306+
Obj.insert({"Record", Object{{"Links", ArrRecord}}});
307+
308+
json::Value ArrFunction = Array();
309+
json::Value PublicFunction = Array();
310+
json::Value ProtectedFunction = Array();
311+
json::Value PrivateFunction = Array();
312+
313+
for (const FunctionInfo &Child : S.Functions) {
314+
json::Value F = extractValue(Child, ParentInfoDir, CDCtx);
315+
AccessSpecifier Access = Child.Access;
316+
if (Access == AccessSpecifier::AS_public)
317+
PublicFunction.getAsArray()->emplace_back(F);
318+
else if (Access == AccessSpecifier::AS_protected)
319+
ProtectedFunction.getAsArray()->emplace_back(F);
320+
else
321+
ArrFunction.getAsArray()->emplace_back(F);
322+
}
323+
324+
if (!ArrFunction.getAsArray()->empty())
325+
Obj.insert({"Function", Object{{"Obj", ArrFunction}}});
326+
327+
if (!PublicFunction.getAsArray()->empty())
328+
Obj.insert({"PublicFunction", Object{{"Obj", PublicFunction}}});
329+
330+
if (!ProtectedFunction.getAsArray()->empty())
331+
Obj.insert({"ProtectedFunction", Object{{"Obj", ProtectedFunction}}});
332+
333+
json::Value ArrEnum = Array();
334+
auto &ArrEnumRef = *ArrEnum.getAsArray();
335+
for (const EnumInfo &Child : S.Enums)
336+
ArrEnumRef.emplace_back(extractValue(Child, CDCtx));
337+
338+
if (!ArrEnumRef.empty())
339+
Obj.insert({"Enums", Object{{"Obj", ArrEnum}}});
340+
341+
json::Value ArrTypedefs = Array();
342+
auto &ArrTypedefsRef = *ArrTypedefs.getAsArray();
343+
for (const TypedefInfo &Child : S.Typedefs)
344+
ArrTypedefsRef.emplace_back(extractValue(Child));
345+
346+
if (!ArrTypedefsRef.empty())
347+
Obj.insert({"Typedefs", Object{{"Obj", ArrTypedefs}}});
348+
}
349+
144350
static json::Value extractValue(const NamespaceInfo &I,
145351
const ClangDocContext &CDCtx) {
146352
Object NamespaceValue = Object();
353+
std::string InfoTitle = I.Name.empty() ? "Global Namespace"
354+
: (Twine("namespace ") + I.Name).str();
355+
356+
SmallString<64> BasePath = I.getRelativeFilePath("");
357+
NamespaceValue.insert({"NamespaceTitle", InfoTitle});
358+
NamespaceValue.insert({"NamespacePath", BasePath});
359+
360+
extractDescriptionFromInfo(I.Description, NamespaceValue);
361+
extractScopeChildren(I.Children, NamespaceValue, BasePath, CDCtx);
147362
return NamespaceValue;
148363
}
149364

150365
static json::Value extractValue(const RecordInfo &I,
151366
const ClangDocContext &CDCtx) {
152367
Object RecordValue = Object();
368+
extractDescriptionFromInfo(I.Description, RecordValue);
369+
RecordValue.insert({"Name", I.Name});
370+
RecordValue.insert({"FullName", I.FullName});
371+
RecordValue.insert({"RecordType", getTagType(I.TagType)});
372+
373+
maybeInsertLocation(I.DefLoc, CDCtx, RecordValue);
374+
375+
StringRef BasePath = I.getRelativeFilePath("");
376+
extractScopeChildren(I.Children, RecordValue, BasePath, CDCtx);
377+
json::Value PublicMembers = Array();
378+
json::Array &PubMemberRef = *PublicMembers.getAsArray();
379+
json::Value ProtectedMembers = Array();
380+
json::Array &ProtMemberRef = *ProtectedMembers.getAsArray();
381+
json::Value PrivateMembers = Array();
382+
json::Array &PrivMemberRef = *PrivateMembers.getAsArray();
383+
for (const MemberTypeInfo &Member : I.Members) {
384+
json::Value MemberValue = Object();
385+
auto &MVRef = *MemberValue.getAsObject();
386+
MVRef.insert({"Name", Member.Name});
387+
MVRef.insert({"Type", Member.Type.Name});
388+
extractDescriptionFromInfo(Member.Description, MVRef);
389+
390+
if (Member.Access == AccessSpecifier::AS_public)
391+
PubMemberRef.emplace_back(MemberValue);
392+
else if (Member.Access == AccessSpecifier::AS_protected)
393+
ProtMemberRef.emplace_back(MemberValue);
394+
else if (Member.Access == AccessSpecifier::AS_private)
395+
ProtMemberRef.emplace_back(MemberValue);
396+
}
397+
if (!PubMemberRef.empty())
398+
RecordValue.insert({"PublicMembers", Object{{"Obj", PublicMembers}}});
399+
if (!ProtMemberRef.empty())
400+
RecordValue.insert({"ProtectedMembers", Object{{"Obj", ProtectedMembers}}});
401+
if (!PrivMemberRef.empty())
402+
RecordValue.insert({"PrivateMembers", Object{{"Obj", PrivateMembers}}});
403+
153404
return RecordValue;
154405
}
155406

0 commit comments

Comments
 (0)