Skip to content

Commit b82cfaa

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 80bfa46 commit b82cfaa

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
@@ -163,15 +163,266 @@ Error MustacheHTMLGenerator::generateDocs(
163163
return Error::success();
164164
}
165165

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

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

0 commit comments

Comments
 (0)