Skip to content

Commit 505a3ec

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 2c95be8 commit 505a3ec

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
@@ -152,15 +152,266 @@ Error MustacheHTMLGenerator::generateDocs(
152152
return Error::success();
153153
}
154154

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

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

0 commit comments

Comments
 (0)