Skip to content

Commit 8e0b4fc

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 3d87071 commit 8e0b4fc

File tree

1 file changed

+249
-0
lines changed

1 file changed

+249
-0
lines changed

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

Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,15 +162,264 @@ Error MustacheHTMLGenerator::generateDocs(
162162
return Error::success();
163163
}
164164

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

171384
static json::Value extractValue(const RecordInfo &I,
172385
const ClangDocContext &CDCtx) {
173386
Object RecordValue = Object();
387+
extractDescriptionFromInfo(I.Description, RecordValue);
388+
RecordValue.insert({"Name", I.Name});
389+
RecordValue.insert({"FullName", I.FullName});
390+
RecordValue.insert({"RecordType", getTagType(I.TagType)});
391+
392+
maybeInsertLocation(I.DefLoc, CDCtx, RecordValue);
393+
394+
StringRef BasePath = I.getRelativeFilePath("");
395+
extractScopeChildren(I.Children, RecordValue, BasePath, CDCtx);
396+
json::Value PublicMembers = Array();
397+
json::Array &PubMemberRef = *PublicMembers.getAsArray();
398+
json::Value ProtectedMembers = Array();
399+
json::Array &ProtMemberRef = *ProtectedMembers.getAsArray();
400+
json::Value PrivateMembers = Array();
401+
json::Array &PrivMemberRef = *PrivateMembers.getAsArray();
402+
for (const MemberTypeInfo &Member : I.Members) {
403+
json::Value MemberValue = Object();
404+
auto &MVRef = *MemberValue.getAsObject();
405+
MVRef.insert({"Name", Member.Name});
406+
MVRef.insert({"Type", Member.Type.Name});
407+
extractDescriptionFromInfo(Member.Description, MVRef);
408+
409+
if (Member.Access == AccessSpecifier::AS_public)
410+
PubMemberRef.emplace_back(MemberValue);
411+
else if (Member.Access == AccessSpecifier::AS_protected)
412+
ProtMemberRef.emplace_back(MemberValue);
413+
else if (Member.Access == AccessSpecifier::AS_private)
414+
ProtMemberRef.emplace_back(MemberValue);
415+
}
416+
if (!PubMemberRef.empty())
417+
RecordValue.insert({"PublicMembers", Object{{"Obj", PublicMembers}}});
418+
if (!ProtMemberRef.empty())
419+
RecordValue.insert({"ProtectedMembers", Object{{"Obj", ProtectedMembers}}});
420+
if (!PrivMemberRef.empty())
421+
RecordValue.insert({"PrivateMembers", Object{{"Obj", PrivateMembers}}});
422+
174423
return RecordValue;
175424
}
176425

0 commit comments

Comments
 (0)