Skip to content

Commit 2d4c5cc

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 6230781 commit 2d4c5cc

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
@@ -156,15 +156,266 @@ Error MustacheHTMLGenerator::generateDocs(
156156
return Error::success();
157157
}
158158

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

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

0 commit comments

Comments
 (0)