Skip to content

Commit 5ef2456

Browse files
authored
[clang-doc] add support for enums comments in html generation (#101282)
Part of #101129 This patch adds support for attaching comments to enums for HTML in clang-doc. It changes the enum generation to table tags where as perviously we're using lists which is more in line with what other doc generators are doing. It also gives clang-doc the ability to show user specified enum values
1 parent 324b676 commit 5ef2456

File tree

8 files changed

+201
-58
lines changed

8 files changed

+201
-58
lines changed

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,10 @@ template <> llvm::Expected<CommentInfo *> getCommentInfo(TypedefInfo *I) {
415415
return &I->Description.emplace_back();
416416
}
417417

418+
template <> llvm::Expected<CommentInfo *> getCommentInfo(EnumValueInfo *I) {
419+
return &I->Description.emplace_back();
420+
}
421+
418422
template <> llvm::Expected<CommentInfo *> getCommentInfo(CommentInfo *I) {
419423
I->Children.emplace_back(std::make_unique<CommentInfo>());
420424
return I->Children.back().get();

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,8 @@ void ClangDocBitcodeWriter::emitBlock(const EnumValueInfo &I) {
536536
emitRecord(I.Name, ENUM_VALUE_NAME);
537537
emitRecord(I.Value, ENUM_VALUE_VALUE);
538538
emitRecord(I.ValueExpr, ENUM_VALUE_EXPR);
539+
for (const auto &CI : I.Description)
540+
emitBlock(CI);
539541
}
540542

541543
void ClangDocBitcodeWriter::emitBlock(const RecordInfo &I) {

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

Lines changed: 71 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,12 @@ class HTMLTag {
4848
TAG_SPAN,
4949
TAG_TITLE,
5050
TAG_UL,
51+
TAG_TABLE,
52+
TAG_THEAD,
53+
TAG_TBODY,
54+
TAG_TR,
55+
TAG_TD,
56+
TAG_TH
5157
};
5258

5359
HTMLTag() = default;
@@ -133,6 +139,12 @@ bool HTMLTag::isSelfClosing() const {
133139
case HTMLTag::TAG_SPAN:
134140
case HTMLTag::TAG_TITLE:
135141
case HTMLTag::TAG_UL:
142+
case HTMLTag::TAG_TABLE:
143+
case HTMLTag::TAG_THEAD:
144+
case HTMLTag::TAG_TBODY:
145+
case HTMLTag::TAG_TR:
146+
case HTMLTag::TAG_TD:
147+
case HTMLTag::TAG_TH:
136148
return false;
137149
}
138150
llvm_unreachable("Unhandled HTMLTag::TagType");
@@ -174,6 +186,18 @@ StringRef HTMLTag::toString() const {
174186
return "title";
175187
case HTMLTag::TAG_UL:
176188
return "ul";
189+
case HTMLTag::TAG_TABLE:
190+
return "table";
191+
case HTMLTag::TAG_THEAD:
192+
return "thead";
193+
case HTMLTag::TAG_TBODY:
194+
return "tbody";
195+
case HTMLTag::TAG_TR:
196+
return "tr";
197+
case HTMLTag::TAG_TD:
198+
return "td";
199+
case HTMLTag::TAG_TH:
200+
return "th";
177201
}
178202
llvm_unreachable("Unhandled HTMLTag::TagType");
179203
}
@@ -377,10 +401,27 @@ genEnumMembersBlock(const llvm::SmallVector<EnumValueInfo, 4> &Members) {
377401
if (Members.empty())
378402
return nullptr;
379403

380-
auto List = std::make_unique<TagNode>(HTMLTag::TAG_UL);
381-
for (const auto &M : Members)
382-
List->Children.emplace_back(
383-
std::make_unique<TagNode>(HTMLTag::TAG_LI, M.Name));
404+
auto List = std::make_unique<TagNode>(HTMLTag::TAG_TBODY);
405+
406+
for (const auto &M : Members) {
407+
auto TRNode = std::make_unique<TagNode>(HTMLTag::TAG_TR);
408+
TRNode->Children.emplace_back(
409+
std::make_unique<TagNode>(HTMLTag::TAG_TD, M.Name));
410+
// Use user supplied value if it exists, otherwise use the value
411+
if (!M.ValueExpr.empty()) {
412+
TRNode->Children.emplace_back(
413+
std::make_unique<TagNode>(HTMLTag::TAG_TD, M.ValueExpr));
414+
} else {
415+
TRNode->Children.emplace_back(
416+
std::make_unique<TagNode>(HTMLTag::TAG_TD, M.Value));
417+
}
418+
if (!M.Description.empty()) {
419+
auto TD = std::make_unique<TagNode>(HTMLTag::TAG_TD);
420+
TD->Children.emplace_back(genHTML(M.Description));
421+
TRNode->Children.emplace_back(std::move(TD));
422+
}
423+
List->Children.emplace_back(std::move(TRNode));
424+
}
384425
return List;
385426
}
386427

@@ -624,7 +665,7 @@ static std::unique_ptr<HTMLNode> genHTML(const CommentInfo &I) {
624665
}
625666
return std::move(FullComment);
626667
}
627-
668+
628669
if (I.Kind == "ParagraphComment") {
629670
auto ParagraphComment = std::make_unique<TagNode>(HTMLTag::TAG_P);
630671
for (const auto &Child : I.Children) {
@@ -658,22 +699,36 @@ static std::vector<std::unique_ptr<TagNode>>
658699
genHTML(const EnumInfo &I, const ClangDocContext &CDCtx) {
659700
std::vector<std::unique_ptr<TagNode>> Out;
660701
std::string EnumType = I.Scoped ? "enum class " : "enum ";
661-
662-
Out.emplace_back(
663-
std::make_unique<TagNode>(HTMLTag::TAG_H3, EnumType + I.Name));
664-
Out.back()->Attributes.emplace_back("id",
665-
llvm::toHex(llvm::toStringRef(I.USR)));
666-
667-
std::unique_ptr<TagNode> Node = genEnumMembersBlock(I.Members);
668-
if (Node)
669-
Out.emplace_back(std::move(Node));
702+
// Determine if enum members have comments attached
703+
bool HasComments = std::any_of(
704+
I.Members.begin(), I.Members.end(),
705+
[](const EnumValueInfo &M) { return !M.Description.empty(); });
706+
std::unique_ptr<TagNode> Table =
707+
std::make_unique<TagNode>(HTMLTag::TAG_TABLE);
708+
std::unique_ptr<TagNode> THead =
709+
std::make_unique<TagNode>(HTMLTag::TAG_THEAD);
710+
std::unique_ptr<TagNode> TRow = std::make_unique<TagNode>(HTMLTag::TAG_TR);
711+
std::unique_ptr<TagNode> TD =
712+
std::make_unique<TagNode>(HTMLTag::TAG_TH, EnumType + I.Name);
713+
// Span 3 columns if enum has comments
714+
TD->Attributes.emplace_back("colspan", HasComments ? "3" : "2");
715+
716+
Table->Attributes.emplace_back("id", llvm::toHex(llvm::toStringRef(I.USR)));
717+
TRow->Children.emplace_back(std::move(TD));
718+
THead->Children.emplace_back(std::move(TRow));
719+
Table->Children.emplace_back(std::move(THead));
720+
721+
if (std::unique_ptr<TagNode> Node = genEnumMembersBlock(I.Members))
722+
Table->Children.emplace_back(std::move(Node));
723+
724+
Out.emplace_back(std::move(Table));
670725

671726
if (I.DefLoc) {
672727
if (!CDCtx.RepositoryUrl)
673728
Out.emplace_back(writeFileDefinition(*I.DefLoc));
674729
else
675-
Out.emplace_back(writeFileDefinition(
676-
*I.DefLoc, StringRef{*CDCtx.RepositoryUrl}));
730+
Out.emplace_back(
731+
writeFileDefinition(*I.DefLoc, StringRef{*CDCtx.RepositoryUrl}));
677732
}
678733

679734
std::string Description;

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ void SymbolInfo::merge(SymbolInfo &&Other) {
221221
}
222222

223223
NamespaceInfo::NamespaceInfo(SymbolID USR, StringRef Name, StringRef Path)
224-
: Info(InfoType::IT_namespace, USR, Name, Path) {}
224+
: Info(InfoType::IT_namespace, USR, Name, Path) {}
225225

226226
void NamespaceInfo::merge(NamespaceInfo &&Other) {
227227
assert(mergeable(Other));

clang-tools-extra/clang-doc/Representation.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,8 @@ struct EnumValueInfo {
455455
// Stores the user-supplied initialization expression for this enumeration
456456
// constant. This will be empty for implicit enumeration values.
457457
SmallString<16> ValueExpr;
458+
459+
std::vector<CommentInfo> Description; /// Comment description of this field.
458460
};
459461

460462
// TODO: Expand to allow for documenting templating.

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

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -394,10 +394,20 @@ static void parseEnumerators(EnumInfo &I, const EnumDecl *D) {
394394
std::string ValueExpr;
395395
if (const Expr *InitExpr = E->getInitExpr())
396396
ValueExpr = getSourceCode(D, InitExpr->getSourceRange());
397-
398397
SmallString<16> ValueStr;
399398
E->getInitVal().toString(ValueStr);
400-
I.Members.emplace_back(E->getNameAsString(), ValueStr, ValueExpr);
399+
I.Members.emplace_back(E->getNameAsString(), ValueStr.str(), ValueExpr);
400+
ASTContext &Context = E->getASTContext();
401+
if (RawComment *Comment =
402+
E->getASTContext().getRawCommentForDeclNoCache(E)) {
403+
CommentInfo CInfo;
404+
Comment->setAttached();
405+
if (comments::FullComment *Fc = Comment->parse(Context, nullptr, E)) {
406+
EnumValueInfo &Member = I.Members.back();
407+
Member.Description.emplace_back();
408+
parseFullComment(Fc, Member.Description.back());
409+
}
410+
}
401411
}
402412
}
403413

@@ -566,7 +576,7 @@ static void populateMemberTypeInfo(MemberTypeInfo &I, const FieldDecl *D) {
566576
return;
567577

568578
Comment->setAttached();
569-
if (comments::FullComment* fc = Comment->parse(Context, nullptr, D)) {
579+
if (comments::FullComment *fc = Comment->parse(Context, nullptr, D)) {
570580
I.Description.emplace_back();
571581
parseFullComment(fc, I.Description.back());
572582
}

clang-tools-extra/test/clang-doc/enum.cpp

Lines changed: 81 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@
2121
enum Color {
2222
// MD-INDEX-LINE: *Defined at {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp#[[@LINE-1]]*
2323
// HTML-INDEX-LINE: <p>Defined at line [[@LINE-2]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
24-
Red, ///< Red
25-
Green, ///< Green
26-
Blue ///< Blue
24+
Red, ///< Comment 1
25+
Green, ///< Comment 2
26+
Blue ///< Comment 3
2727
};
2828

2929
// MD-INDEX: ## Enums
@@ -34,23 +34,29 @@ enum Color {
3434
// MD-INDEX: | Blue |
3535
// MD-INDEX: **brief** For specifying RGB colors
3636

37-
// HTML-INDEX: <h2 id="Enums">Enums</h2>
38-
// HTML-INDEX: <h3 id="{{([0-9A-F]{40})}}">enum Color</h3>
39-
// HTML-INDEX: <li>Red</li>
40-
// HTML-INDEX: <li>Green</li>
41-
// HTML-INDEX: <li>Blue</li>
37+
// HTML-INDEX: <th colspan="3">enum Color</th>
38+
// HTML-INDEX: <td>Red</td>
39+
// HTML-INDEX: <td>0</td>
40+
// HTML-INDEX: <p> Comment 1</p>
41+
// HTML-INDEX: <td>Green</td>
42+
// HTML-INDEX: <td>1</td>
43+
// HTML-INDEX: <p> Comment 2</p>
44+
// HTML-INDEX: <td>Blue</td>
45+
// HTML-INDEX: <td>2</td>
46+
// HTML-INDEX: <p> Comment 3</p>
4247

4348
/**
4449
* @brief Shape Types
4550
*/
4651
enum class Shapes {
4752
// MD-INDEX-LINE: *Defined at {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp#[[@LINE-1]]*
4853
// HTML-INDEX-LINE: <p>Defined at line [[@LINE-2]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
49-
/// Circle
54+
55+
/// Comment 1
5056
Circle,
51-
/// Rectangle
57+
/// Comment 2
5258
Rectangle,
53-
/// Triangle
59+
/// Comment 3
5460
Triangle
5561
};
5662
// MD-INDEX: | enum class Shapes |
@@ -60,10 +66,17 @@ enum class Shapes {
6066
// MD-INDEX: | Triangle |
6167
// MD-INDEX: **brief** Shape Types
6268

63-
// HTML-INDEX: <h3 id="{{([0-9A-F]{40})}}">enum class Shapes</h3>
64-
// HTML-INDEX: <li>Circle</li>
65-
// HTML-INDEX: <li>Rectangle</li>
66-
// HTML-INDEX: <li>Triangle</li>
69+
// HTML-INDEX: <th colspan="3">enum class Shapes</th>
70+
// HTML-INDEX: <td>Circle</td>
71+
// HTML-INDEX: <td>0</td>
72+
// HTML-INDEX: <p> Comment 1</p>
73+
// HTML-INDEX: <td>Rectangle</td>
74+
// HTML-INDEX: <td>1</td>
75+
// HTML-INDEX: <p> Comment 2</p>
76+
// HTML-INDEX: <td>Triangle</td>
77+
// HTML-INDEX: <td>2</td>
78+
// HTML-INDEX: <p> Comment 3</p>
79+
6780

6881

6982
class Animals {
@@ -76,18 +89,25 @@ class Animals {
7689
enum AnimalType {
7790
// MD-ANIMAL-LINE: *Defined at {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp#[[@LINE-1]]*
7891
// HTML-ANIMAL-LINE: <p>Defined at line [[@LINE-2]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
79-
Dog, /// Man's best friend
80-
Cat, /// Man's other best friend
81-
Iguana /// A lizard
92+
Dog, ///< Man's best friend
93+
Cat, ///< Man's other best friend
94+
Iguana ///< A lizard
8295
};
8396
};
8497

8598
// HTML-ANIMAL: <h1>class Animals</h1>
8699
// HTML-ANIMAL: <h2 id="Enums">Enums</h2>
87-
// HTML-ANIMAL: <h3 id="{{([0-9A-F]{40})}}">enum AnimalType</h3>
88-
// HTML-ANIMAL: <li>Dog</li>
89-
// HTML-ANIMAL: <li>Cat</li>
90-
// HTML-ANIMAL: <li>Iguana</li>
100+
// HTML-ANIMAL: <th colspan="3">enum AnimalType</th>
101+
// HTML-ANIMAL: <td>Dog</td>
102+
// HTML-ANIMAL: <td>0</td>
103+
// HTML-ANIMAL: <p> Man&apos;s best friend</p>
104+
// HTML-ANIMAL: <td>Cat</td>
105+
// HTML-ANIMAL: <td>1</td>
106+
// HTML-ANIMAL: <p> Man&apos;s other best friend</p>
107+
// HTML-ANIMAL: <td>Iguana</td>
108+
// HTML-ANIMAL: <td>2</td>
109+
// HTML-ANIMAL: <p> A lizard</p>
110+
91111

92112
// MD-ANIMAL: # class Animals
93113
// MD-ANIMAL: ## Enums
@@ -106,10 +126,11 @@ namespace Vehicles {
106126
enum Car {
107127
// MD-VEHICLES-LINE: *Defined at {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp#[[@LINE-1]]*
108128
// HTML-VEHICLES-LINE: <p>Defined at line [[@LINE-2]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
109-
Sedan, /// Sedan
110-
SUV, /// SUV
111-
Pickup, /// Pickup
112-
Hatchback /// Hatchback
129+
130+
Sedan, ///< Comment 1
131+
SUV, ///< Comment 2
132+
Pickup, ///< Comment 3
133+
Hatchback ///< Comment 4
113134
};
114135
}
115136

@@ -124,9 +145,37 @@ namespace Vehicles {
124145
// MD-VEHICLES: **brief** specify type of car
125146

126147
// HTML-VEHICLES: <h1>namespace Vehicles</h1>
127-
// HTML-VEHICLES: <h2 id="Enums">Enums</h2>
128-
// HTML-VEHICLES: <h3 id="{{([0-9A-F]{40})}}">enum Car</h3>
129-
// HTML-VEHICLES: <li>Sedan</li>
130-
// HTML-VEHICLES: <li>SUV</li>
131-
// HTML-VEHICLES: <li>Pickup</li>
132-
// HTML-VEHICLES: <li>Hatchback</li>
148+
// HTML-VEHICLES: <th colspan="3">enum Car</th>
149+
// HTML-VEHICLES: <td>Sedan</td>
150+
// HTML-VEHICLES: <td>0</td>
151+
// HTML-VEHICLES: <p> Comment 1</p>
152+
// HTML-VEHICLES: <td>SUV</td>
153+
// HTML-VEHICLES: <td>1</td>
154+
// HTML-VEHICLES: <p> Comment 2</p>
155+
// HTML-VEHICLES: <td>Pickup</td>
156+
// HTML-VEHICLES: <td>2</td>
157+
// HTML-VEHICLES: <p> Comment 3</p>
158+
// HTML-VEHICLES: <td>Hatchback</td>
159+
// HTML-VEHICLES: <td>3</td>
160+
// HTML-VEHICLES: <p> Comment 4</p>
161+
162+
163+
enum ColorUserSpecified {
164+
RedUserSpecified = 'A',
165+
GreenUserSpecified = 2,
166+
BlueUserSpecified = 'C'
167+
};
168+
169+
// MD-INDEX: | enum ColorUserSpecified |
170+
// MD-INDEX: --
171+
// MD-INDEX: | RedUserSpecified |
172+
// MD-INDEX: | GreenUserSpecified |
173+
// MD-INDEX: | BlueUserSpecified |
174+
175+
// HTML-INDEX: <th colspan="2">enum ColorUserSpecified</th>
176+
// HTML-INDEX: <td>RedUserSpecified</td>
177+
// HTML-INDEX: <td>&apos;A&apos;</td>
178+
// HTML-INDEX: <td>GreenUserSpecified</td>
179+
// HTML-INDEX: <td>2</td>
180+
// HTML-INDEX: <td>BlueUserSpecified</td>
181+
// HTML-INDEX: <td>&apos;C&apos;</td>

0 commit comments

Comments
 (0)