Skip to content

Commit d570409

Browse files
authored
Refactor clang doc comment structure (#142273)
This patch refactors CommentKind handling in clang-doc by introducing a strongly typed enum class for better type safety and clarity. It updates all relevant places, including YAML traits and serialization, to work with the new enum. Additionally, it enhances the Mustache-based HTML generation by fully supporting all comment kinds, ensuring accurate structured rendering of comment blocks. The changes simplify future maintenance, improve robustness by eliminating unchecked defaults, and ensure consistency between generators. Fixes #142083
1 parent 0e2103a commit d570409

15 files changed

+446
-208
lines changed

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -315,9 +315,13 @@ static llvm::Error parseRecord(const Record &R, unsigned ID,
315315

316316
static llvm::Error parseRecord(const Record &R, unsigned ID,
317317
llvm::StringRef Blob, CommentInfo *I) {
318+
llvm::SmallString<16> KindStr;
318319
switch (ID) {
319320
case COMMENT_KIND:
320-
return decodeRecord(R, I->Kind, Blob);
321+
if (llvm::Error Err = decodeRecord(R, KindStr, Blob))
322+
return Err;
323+
I->Kind = stringToCommentKind(KindStr);
324+
return llvm::Error::success();
321325
case COMMENT_TEXT:
322326
return decodeRecord(R, I->Text, Blob);
323327
case COMMENT_NAME:

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -484,8 +484,9 @@ void ClangDocBitcodeWriter::emitBlock(const MemberTypeInfo &T) {
484484

485485
void ClangDocBitcodeWriter::emitBlock(const CommentInfo &I) {
486486
StreamSubBlockGuard Block(Stream, BI_COMMENT_BLOCK_ID);
487+
// Handle Kind (enum) separately, since it is not a string.
488+
emitRecord(commentKindToString(I.Kind), COMMENT_KIND);
487489
for (const auto &L : std::vector<std::pair<llvm::StringRef, RecordId>>{
488-
{I.Kind, COMMENT_KIND},
489490
{I.Text, COMMENT_TEXT},
490491
{I.Name, COMMENT_NAME},
491492
{I.Direction, COMMENT_DIRECTION},

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

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -635,7 +635,8 @@ genHTML(const Index &Index, StringRef InfoPath, bool IsOutermostList) {
635635
}
636636

637637
static std::unique_ptr<HTMLNode> genHTML(const CommentInfo &I) {
638-
if (I.Kind == "FullComment") {
638+
switch (I.Kind) {
639+
case CommentKind::CK_FullComment: {
639640
auto FullComment = std::make_unique<TagNode>(HTMLTag::TAG_DIV);
640641
for (const auto &Child : I.Children) {
641642
std::unique_ptr<HTMLNode> Node = genHTML(*Child);
@@ -645,7 +646,7 @@ static std::unique_ptr<HTMLNode> genHTML(const CommentInfo &I) {
645646
return std::move(FullComment);
646647
}
647648

648-
if (I.Kind == "ParagraphComment") {
649+
case CommentKind::CK_ParagraphComment: {
649650
auto ParagraphComment = std::make_unique<TagNode>(HTMLTag::TAG_P);
650651
for (const auto &Child : I.Children) {
651652
std::unique_ptr<HTMLNode> Node = genHTML(*Child);
@@ -657,7 +658,7 @@ static std::unique_ptr<HTMLNode> genHTML(const CommentInfo &I) {
657658
return std::move(ParagraphComment);
658659
}
659660

660-
if (I.Kind == "BlockCommandComment") {
661+
case CommentKind::CK_BlockCommandComment: {
661662
auto BlockComment = std::make_unique<TagNode>(HTMLTag::TAG_DIV);
662663
BlockComment->Children.emplace_back(
663664
std::make_unique<TagNode>(HTMLTag::TAG_DIV, I.Name));
@@ -670,12 +671,26 @@ static std::unique_ptr<HTMLNode> genHTML(const CommentInfo &I) {
670671
return nullptr;
671672
return std::move(BlockComment);
672673
}
673-
if (I.Kind == "TextComment") {
674-
if (I.Text == "")
674+
675+
case CommentKind::CK_TextComment: {
676+
if (I.Text.empty())
675677
return nullptr;
676678
return std::make_unique<TextNode>(I.Text);
677679
}
678-
return nullptr;
680+
681+
// For now, return nullptr for unsupported comment kinds
682+
case CommentKind::CK_InlineCommandComment:
683+
case CommentKind::CK_HTMLStartTagComment:
684+
case CommentKind::CK_HTMLEndTagComment:
685+
case CommentKind::CK_ParamCommandComment:
686+
case CommentKind::CK_TParamCommandComment:
687+
case CommentKind::CK_VerbatimBlockComment:
688+
case CommentKind::CK_VerbatimBlockLineComment:
689+
case CommentKind::CK_VerbatimLineComment:
690+
case CommentKind::CK_Unknown:
691+
return nullptr;
692+
}
693+
llvm_unreachable("Unhandled CommentKind");
679694
}
680695

681696
static std::unique_ptr<TagNode> genHTML(const std::vector<CommentInfo> &C) {

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

Lines changed: 115 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -208,37 +208,110 @@ static json::Value extractValue(const TypedefInfo &I) {
208208
}
209209

210210
static json::Value extractValue(const CommentInfo &I) {
211-
assert((I.Kind == "BlockCommandComment" || I.Kind == "FullComment" ||
212-
I.Kind == "ParagraphComment" || I.Kind == "TextComment") &&
213-
"Unknown Comment type in CommentInfo.");
214-
215211
Object Obj = Object();
216-
json::Value Child = Object();
217212

218-
// TextComment has no children, so return it.
219-
if (I.Kind == "TextComment") {
220-
Obj.insert({"TextComment", I.Text});
221-
return Obj;
222-
}
213+
json::Value ChildVal = Object();
214+
Object &Child = *ChildVal.getAsObject();
223215

224-
// BlockCommandComment needs to generate a Command key.
225-
if (I.Kind == "BlockCommandComment")
226-
Child.getAsObject()->insert({"Command", I.Name});
227-
228-
// Use the same handling for everything else.
229-
// Only valid for:
230-
// - BlockCommandComment
231-
// - FullComment
232-
// - ParagraphComment
233216
json::Value ChildArr = Array();
234217
auto &CARef = *ChildArr.getAsArray();
235218
CARef.reserve(I.Children.size());
236219
for (const auto &C : I.Children)
237220
CARef.emplace_back(extractValue(*C));
238-
Child.getAsObject()->insert({"Children", ChildArr});
239-
Obj.insert({I.Kind, Child});
240221

241-
return Obj;
222+
switch (I.Kind) {
223+
case CommentKind::CK_TextComment: {
224+
Obj.insert({commentKindToString(I.Kind), I.Text});
225+
return Obj;
226+
}
227+
228+
case CommentKind::CK_BlockCommandComment: {
229+
Child.insert({"Command", I.Name});
230+
Child.insert({"Children", ChildArr});
231+
Obj.insert({commentKindToString(I.Kind), ChildVal});
232+
return Obj;
233+
}
234+
235+
case CommentKind::CK_InlineCommandComment: {
236+
json::Value ArgsArr = Array();
237+
auto &ARef = *ArgsArr.getAsArray();
238+
ARef.reserve(I.Args.size());
239+
for (const auto &Arg : I.Args)
240+
ARef.emplace_back(Arg);
241+
Child.insert({"Command", I.Name});
242+
Child.insert({"Args", ArgsArr});
243+
Child.insert({"Children", ChildArr});
244+
Obj.insert({commentKindToString(I.Kind), ChildVal});
245+
return Obj;
246+
}
247+
248+
case CommentKind::CK_ParamCommandComment:
249+
case CommentKind::CK_TParamCommandComment: {
250+
Child.insert({"ParamName", I.ParamName});
251+
Child.insert({"Direction", I.Direction});
252+
Child.insert({"Explicit", I.Explicit});
253+
Child.insert({"Children", ChildArr});
254+
Obj.insert({commentKindToString(I.Kind), ChildVal});
255+
return Obj;
256+
}
257+
258+
case CommentKind::CK_VerbatimBlockComment: {
259+
Child.insert({"Text", I.Text});
260+
if (!I.CloseName.empty())
261+
Child.insert({"CloseName", I.CloseName});
262+
Child.insert({"Children", ChildArr});
263+
Obj.insert({commentKindToString(I.Kind), ChildVal});
264+
return Obj;
265+
}
266+
267+
case CommentKind::CK_VerbatimBlockLineComment:
268+
case CommentKind::CK_VerbatimLineComment: {
269+
Child.insert({"Text", I.Text});
270+
Child.insert({"Children", ChildArr});
271+
Obj.insert({commentKindToString(I.Kind), ChildVal});
272+
return Obj;
273+
}
274+
275+
case CommentKind::CK_HTMLStartTagComment: {
276+
json::Value AttrKeysArray = json::Array();
277+
json::Value AttrValuesArray = json::Array();
278+
auto &KeyArr = *AttrKeysArray.getAsArray();
279+
auto &ValArr = *AttrValuesArray.getAsArray();
280+
KeyArr.reserve(I.AttrKeys.size());
281+
ValArr.reserve(I.AttrValues.size());
282+
for (const auto &K : I.AttrKeys)
283+
KeyArr.emplace_back(K);
284+
for (const auto &V : I.AttrValues)
285+
ValArr.emplace_back(V);
286+
Child.insert({"Name", I.Name});
287+
Child.insert({"SelfClosing", I.SelfClosing});
288+
Child.insert({"AttrKeys", AttrKeysArray});
289+
Child.insert({"AttrValues", AttrValuesArray});
290+
Child.insert({"Children", ChildArr});
291+
Obj.insert({commentKindToString(I.Kind), ChildVal});
292+
return Obj;
293+
}
294+
295+
case CommentKind::CK_HTMLEndTagComment: {
296+
Child.insert({"Name", I.Name});
297+
Child.insert({"Children", ChildArr});
298+
Obj.insert({commentKindToString(I.Kind), ChildVal});
299+
return Obj;
300+
}
301+
302+
case CommentKind::CK_FullComment:
303+
case CommentKind::CK_ParagraphComment: {
304+
Child.insert({"Children", ChildArr});
305+
Obj.insert({commentKindToString(I.Kind), ChildVal});
306+
return Obj;
307+
}
308+
309+
case CommentKind::CK_Unknown: {
310+
Obj.insert({commentKindToString(I.Kind), I.Text});
311+
return Obj;
312+
}
313+
}
314+
llvm_unreachable("Unknown comment kind encountered.");
242315
}
243316

244317
static void maybeInsertLocation(std::optional<Location> Loc,
@@ -255,6 +328,7 @@ static void extractDescriptionFromInfo(ArrayRef<CommentInfo> Descriptions,
255328
return;
256329
json::Value DescArr = Array();
257330
json::Array &DescARef = *DescArr.getAsArray();
331+
DescARef.reserve(Descriptions.size());
258332
for (const CommentInfo &Child : Descriptions)
259333
DescARef.emplace_back(extractValue(Child));
260334
EnumValObj.insert({"EnumValueComments", DescArr});
@@ -270,6 +344,7 @@ static json::Value extractValue(const FunctionInfo &I, StringRef ParentInfoDir,
270344

271345
json::Value ParamArr = Array();
272346
json::Array &ParamARef = *ParamArr.getAsArray();
347+
ParamARef.reserve(I.Params.size());
273348
for (const auto Val : enumerate(I.Params)) {
274349
json::Value V = Object();
275350
auto &VRef = *V.getAsObject();
@@ -297,6 +372,7 @@ static json::Value extractValue(const EnumInfo &I,
297372
Obj.insert({"ID", toHex(toStringRef(I.USR))});
298373
json::Value EnumArr = Array();
299374
json::Array &EnumARef = *EnumArr.getAsArray();
375+
EnumARef.reserve(I.Members.size());
300376
for (const EnumValueInfo &M : I.Members) {
301377
json::Value EnumValue = Object();
302378
auto &EnumValObj = *EnumValue.getAsObject();
@@ -322,6 +398,7 @@ static void extractScopeChildren(const ScopeChildren &S, Object &Obj,
322398
const ClangDocContext &CDCtx) {
323399
json::Value NamespaceArr = Array();
324400
json::Array &NamespaceARef = *NamespaceArr.getAsArray();
401+
NamespaceARef.reserve(S.Namespaces.size());
325402
for (const Reference &Child : S.Namespaces)
326403
NamespaceARef.emplace_back(extractValue(Child, ParentInfoDir));
327404

@@ -330,6 +407,7 @@ static void extractScopeChildren(const ScopeChildren &S, Object &Obj,
330407

331408
json::Value RecordArr = Array();
332409
json::Array &RecordARef = *RecordArr.getAsArray();
410+
RecordARef.reserve(S.Records.size());
333411
for (const Reference &Child : S.Records)
334412
RecordARef.emplace_back(extractValue(Child, ParentInfoDir));
335413

@@ -338,12 +416,15 @@ static void extractScopeChildren(const ScopeChildren &S, Object &Obj,
338416

339417
json::Value FunctionArr = Array();
340418
json::Array &FunctionARef = *FunctionArr.getAsArray();
419+
FunctionARef.reserve(S.Functions.size());
341420

342421
json::Value PublicFunctionArr = Array();
343422
json::Array &PublicFunctionARef = *PublicFunctionArr.getAsArray();
423+
PublicFunctionARef.reserve(S.Functions.size());
344424

345425
json::Value ProtectedFunctionArr = Array();
346426
json::Array &ProtectedFunctionARef = *ProtectedFunctionArr.getAsArray();
427+
ProtectedFunctionARef.reserve(S.Functions.size());
347428

348429
for (const FunctionInfo &Child : S.Functions) {
349430
json::Value F = extractValue(Child, ParentInfoDir, CDCtx);
@@ -367,6 +448,7 @@ static void extractScopeChildren(const ScopeChildren &S, Object &Obj,
367448

368449
json::Value EnumArr = Array();
369450
auto &EnumARef = *EnumArr.getAsArray();
451+
EnumARef.reserve(S.Enums.size());
370452
for (const EnumInfo &Child : S.Enums)
371453
EnumARef.emplace_back(extractValue(Child, CDCtx));
372454

@@ -375,6 +457,7 @@ static void extractScopeChildren(const ScopeChildren &S, Object &Obj,
375457

376458
json::Value TypedefArr = Array();
377459
auto &TypedefARef = *TypedefArr.getAsArray();
460+
TypedefARef.reserve(S.Typedefs.size());
378461
for (const TypedefInfo &Child : S.Typedefs)
379462
TypedefARef.emplace_back(extractValue(Child));
380463

@@ -411,10 +494,13 @@ static json::Value extractValue(const RecordInfo &I,
411494
extractScopeChildren(I.Children, RecordValue, BasePath, CDCtx);
412495
json::Value PublicMembers = Array();
413496
json::Array &PubMemberRef = *PublicMembers.getAsArray();
497+
PubMemberRef.reserve(I.Members.size());
414498
json::Value ProtectedMembers = Array();
415499
json::Array &ProtMemberRef = *ProtectedMembers.getAsArray();
500+
ProtMemberRef.reserve(I.Members.size());
416501
json::Value PrivateMembers = Array();
417502
json::Array &PrivMemberRef = *PrivateMembers.getAsArray();
503+
PrivMemberRef.reserve(I.Members.size());
418504
for (const MemberTypeInfo &Member : I.Members) {
419505
json::Value MemberValue = Object();
420506
auto &MVRef = *MemberValue.getAsObject();
@@ -446,20 +532,25 @@ static Error setupTemplateValue(const ClangDocContext &CDCtx, json::Value &V,
446532
auto InfoPath = I->getRelativeFilePath("");
447533
SmallString<128> RelativePath = computeRelativePath("", InfoPath);
448534
sys::path::native(RelativePath, sys::path::Style::posix);
535+
536+
auto *SSA = StylesheetArr.getAsArray();
537+
SSA->reserve(CDCtx.UserStylesheets.size());
449538
for (const auto &FilePath : CDCtx.UserStylesheets) {
450539
SmallString<128> StylesheetPath = RelativePath;
451540
sys::path::append(StylesheetPath, sys::path::Style::posix,
452541
sys::path::filename(FilePath));
453-
StylesheetArr.getAsArray()->emplace_back(StylesheetPath);
542+
SSA->emplace_back(StylesheetPath);
454543
}
455544
V.getAsObject()->insert({"Stylesheets", StylesheetArr});
456545

457546
json::Value ScriptArr = Array();
547+
auto *SCA = ScriptArr.getAsArray();
548+
SCA->reserve(CDCtx.JsScripts.size());
458549
for (auto Script : CDCtx.JsScripts) {
459550
SmallString<128> JsPath = RelativePath;
460551
sys::path::append(JsPath, sys::path::Style::posix,
461552
sys::path::filename(Script));
462-
ScriptArr.getAsArray()->emplace_back(JsPath);
553+
SCA->emplace_back(JsPath);
463554
}
464555
V.getAsObject()->insert({"Scripts", ScriptArr});
465556
return Error::success();

0 commit comments

Comments
 (0)