[clang-tools-extra] [clang-doc] add support for enums in html generation (PR #101282)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Jul 30 21:02:28 PDT 2024
https://github.com/PeterChou1 updated https://github.com/llvm/llvm-project/pull/101282
>From ac1c7b5cbf3024bf8cd4021174a47b914d7f7dea Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Tue, 30 Jul 2024 23:58:27 -0400
Subject: [PATCH 1/2] [clang-doc] add suport for clang-doc enum generation
---
clang-tools-extra/clang-doc/BitcodeReader.cpp | 4 +
clang-tools-extra/clang-doc/BitcodeWriter.cpp | 2 +
clang-tools-extra/clang-doc/HTMLGenerator.cpp | 88 ++++++++++++--
.../clang-doc/Representation.cpp | 2 +
clang-tools-extra/clang-doc/Representation.h | 4 +
clang-tools-extra/clang-doc/Serialize.cpp | 14 ++-
clang-tools-extra/test/clang-doc/enum.cpp | 113 +++++++++++++-----
7 files changed, 181 insertions(+), 46 deletions(-)
diff --git a/clang-tools-extra/clang-doc/BitcodeReader.cpp b/clang-tools-extra/clang-doc/BitcodeReader.cpp
index bfb04e7407b38..1f2fb0a8b2b85 100644
--- a/clang-tools-extra/clang-doc/BitcodeReader.cpp
+++ b/clang-tools-extra/clang-doc/BitcodeReader.cpp
@@ -415,6 +415,10 @@ template <> llvm::Expected<CommentInfo *> getCommentInfo(TypedefInfo *I) {
return &I->Description.emplace_back();
}
+template <> llvm::Expected<CommentInfo *> getCommentInfo(EnumValueInfo *I) {
+ return &I->Description.emplace_back();
+}
+
template <> llvm::Expected<CommentInfo *> getCommentInfo(CommentInfo *I) {
I->Children.emplace_back(std::make_unique<CommentInfo>());
return I->Children.back().get();
diff --git a/clang-tools-extra/clang-doc/BitcodeWriter.cpp b/clang-tools-extra/clang-doc/BitcodeWriter.cpp
index 7e5a11783d303..06f30f76e33d8 100644
--- a/clang-tools-extra/clang-doc/BitcodeWriter.cpp
+++ b/clang-tools-extra/clang-doc/BitcodeWriter.cpp
@@ -536,6 +536,8 @@ void ClangDocBitcodeWriter::emitBlock(const EnumValueInfo &I) {
emitRecord(I.Name, ENUM_VALUE_NAME);
emitRecord(I.Value, ENUM_VALUE_VALUE);
emitRecord(I.ValueExpr, ENUM_VALUE_EXPR);
+ for (const auto &CI : I.Description)
+ emitBlock(CI);
}
void ClangDocBitcodeWriter::emitBlock(const RecordInfo &I) {
diff --git a/clang-tools-extra/clang-doc/HTMLGenerator.cpp b/clang-tools-extra/clang-doc/HTMLGenerator.cpp
index aef22453035c3..a37192d6ceb9b 100644
--- a/clang-tools-extra/clang-doc/HTMLGenerator.cpp
+++ b/clang-tools-extra/clang-doc/HTMLGenerator.cpp
@@ -48,6 +48,12 @@ class HTMLTag {
TAG_SPAN,
TAG_TITLE,
TAG_UL,
+ TAG_TABLE,
+ TAG_THEAD,
+ TAG_TBODY,
+ TAG_TR,
+ TAG_TD,
+ TAG_TH
};
HTMLTag() = default;
@@ -133,6 +139,12 @@ bool HTMLTag::isSelfClosing() const {
case HTMLTag::TAG_SPAN:
case HTMLTag::TAG_TITLE:
case HTMLTag::TAG_UL:
+ case HTMLTag::TAG_TABLE:
+ case HTMLTag::TAG_THEAD:
+ case HTMLTag::TAG_TBODY:
+ case HTMLTag::TAG_TR:
+ case HTMLTag::TAG_TD:
+ case HTMLTag::TAG_TH:
return false;
}
llvm_unreachable("Unhandled HTMLTag::TagType");
@@ -174,6 +186,18 @@ StringRef HTMLTag::toString() const {
return "title";
case HTMLTag::TAG_UL:
return "ul";
+ case HTMLTag::TAG_TABLE:
+ return "table";
+ case HTMLTag::TAG_THEAD:
+ return "thead";
+ case HTMLTag::TAG_TBODY:
+ return "tbody";
+ case HTMLTag::TAG_TR:
+ return "tr";
+ case HTMLTag::TAG_TD:
+ return "td";
+ case HTMLTag::TAG_TH:
+ return "th";
}
llvm_unreachable("Unhandled HTMLTag::TagType");
}
@@ -352,6 +376,7 @@ genHTML(const EnumInfo &I, const ClangDocContext &CDCtx);
static std::vector<std::unique_ptr<TagNode>>
genHTML(const FunctionInfo &I, const ClangDocContext &CDCtx,
StringRef ParentInfoDir);
+static std::unique_ptr<TagNode> genHTML(const std::vector<CommentInfo> &C);
static std::vector<std::unique_ptr<TagNode>>
genEnumsBlock(const std::vector<EnumInfo> &Enums,
@@ -372,14 +397,33 @@ genEnumsBlock(const std::vector<EnumInfo> &Enums,
}
static std::unique_ptr<TagNode>
-genEnumMembersBlock(const llvm::SmallVector<EnumValueInfo, 4> &Members) {
+genEnumMembersBlock(const llvm::SmallVector<EnumValueInfo, 4> &Members,
+ bool HasComments) {
if (Members.empty())
return nullptr;
- auto List = std::make_unique<TagNode>(HTMLTag::TAG_UL);
- for (const auto &M : Members)
- List->Children.emplace_back(
- std::make_unique<TagNode>(HTMLTag::TAG_LI, M.Name));
+ auto List = std::make_unique<TagNode>(HTMLTag::TAG_TBODY);
+
+ for (const auto &M : Members) {
+ auto TRNode = std::make_unique<TagNode>(HTMLTag::TAG_TR);
+ TRNode->Children.emplace_back(
+ std::make_unique<TagNode>(HTMLTag::TAG_TD, M.Name));
+ // Use user supplied value if it exists, otherwise use the value
+ if (!M.ValueExpr.empty()) {
+ TRNode->Children.emplace_back(
+ std::make_unique<TagNode>(HTMLTag::TAG_TD, M.ValueExpr));
+ } else {
+ TRNode->Children.emplace_back(
+ std::make_unique<TagNode>(HTMLTag::TAG_TD, M.Value));
+ }
+
+ if (HasComments) {
+ auto TD = std::make_unique<TagNode>(HTMLTag::TAG_TD);
+ TD->Children.emplace_back(genHTML(M.Description));
+ TRNode->Children.emplace_back(std::move(TD));
+ }
+ List->Children.emplace_back(std::move(TRNode));
+ }
return List;
}
@@ -653,15 +697,35 @@ static std::vector<std::unique_ptr<TagNode>>
genHTML(const EnumInfo &I, const ClangDocContext &CDCtx) {
std::vector<std::unique_ptr<TagNode>> Out;
std::string EnumType = I.Scoped ? "enum class " : "enum ";
+ // Determine if enum members have comments attached
+ bool HasComments = false;
+ for (const auto &M : I.Members) {
+ if (!M.Description.empty()) {
+ HasComments = true;
+ break;
+ }
+ }
+ std::unique_ptr<TagNode> Table =
+ std::make_unique<TagNode>(HTMLTag::TAG_TABLE);
+ std::unique_ptr<TagNode> Thead =
+ std::make_unique<TagNode>(HTMLTag::TAG_THEAD);
+ std::unique_ptr<TagNode> TRow = std::make_unique<TagNode>(HTMLTag::TAG_TR);
+ std::unique_ptr<TagNode> TD =
+ std::make_unique<TagNode>(HTMLTag::TAG_TH, EnumType + I.Name);
+ // Span 3 columns if enum has comments
+ TD->Attributes.emplace_back("colspan", HasComments ? "3" : "2");
+
+ Table->Attributes.emplace_back("id", llvm::toHex(llvm::toStringRef(I.USR)));
+ TRow->Children.emplace_back(std::move(TD));
+ Thead->Children.emplace_back(std::move(TRow));
+ Table->Children.emplace_back(std::move(Thead));
+
+ std::unique_ptr<TagNode> Node = genEnumMembersBlock(I.Members, HasComments);
- Out.emplace_back(
- std::make_unique<TagNode>(HTMLTag::TAG_H3, EnumType + I.Name));
- Out.back()->Attributes.emplace_back("id",
- llvm::toHex(llvm::toStringRef(I.USR)));
-
- std::unique_ptr<TagNode> Node = genEnumMembersBlock(I.Members);
if (Node)
- Out.emplace_back(std::move(Node));
+ Table->Children.emplace_back(std::move(Node));
+
+ Out.emplace_back(std::move(Table));
if (I.DefLoc) {
if (!CDCtx.RepositoryUrl)
diff --git a/clang-tools-extra/clang-doc/Representation.cpp b/clang-tools-extra/clang-doc/Representation.cpp
index d08afbb962189..028dffc21793a 100644
--- a/clang-tools-extra/clang-doc/Representation.cpp
+++ b/clang-tools-extra/clang-doc/Representation.cpp
@@ -266,6 +266,8 @@ void EnumInfo::merge(EnumInfo &&Other) {
Scoped = Other.Scoped;
if (Members.empty())
Members = std::move(Other.Members);
+ if (Other.HasComments || HasComments)
+ HasComments = true;
SymbolInfo::merge(std::move(Other));
}
diff --git a/clang-tools-extra/clang-doc/Representation.h b/clang-tools-extra/clang-doc/Representation.h
index d70c279f7a2bd..db3aff2d60a1b 100644
--- a/clang-tools-extra/clang-doc/Representation.h
+++ b/clang-tools-extra/clang-doc/Representation.h
@@ -431,6 +431,8 @@ struct EnumValueInfo {
// Stores the user-supplied initialization expression for this enumeration
// constant. This will be empty for implicit enumeration values.
SmallString<16> ValueExpr;
+
+ std::vector<CommentInfo> Description; // Comment description of this field.
};
// TODO: Expand to allow for documenting templating.
@@ -443,6 +445,8 @@ struct EnumInfo : public SymbolInfo {
// Indicates whether this enum is scoped (e.g. enum class).
bool Scoped = false;
+ // Indicates whether or not enum members have comments attached
+ bool HasComments = false;
// Set to nonempty to the type when this is an explicitly typed enum. For
// enum Foo : short { ... };
diff --git a/clang-tools-extra/clang-doc/Serialize.cpp b/clang-tools-extra/clang-doc/Serialize.cpp
index 3b074d849e8a9..78b7041368d6d 100644
--- a/clang-tools-extra/clang-doc/Serialize.cpp
+++ b/clang-tools-extra/clang-doc/Serialize.cpp
@@ -394,10 +394,20 @@ static void parseEnumerators(EnumInfo &I, const EnumDecl *D) {
std::string ValueExpr;
if (const Expr *InitExpr = E->getInitExpr())
ValueExpr = getSourceCode(D, InitExpr->getSourceRange());
-
SmallString<16> ValueStr;
E->getInitVal().toString(ValueStr);
- I.Members.emplace_back(E->getNameAsString(), ValueStr, ValueExpr);
+ I.Members.emplace_back(E->getNameAsString(), ValueStr.str(), ValueExpr);
+ ASTContext &Context = E->getASTContext();
+ RawComment *Comment = E->getASTContext().getRawCommentForDeclNoCache(E);
+ if (Comment) {
+ CommentInfo CInfo;
+ Comment->setAttached();
+ if (comments::FullComment *Fc = Comment->parse(Context, nullptr, E)) {
+ EnumValueInfo &Member = I.Members.back();
+ Member.Description.emplace_back();
+ parseFullComment(Fc, Member.Description.back());
+ }
+ }
}
}
diff --git a/clang-tools-extra/test/clang-doc/enum.cpp b/clang-tools-extra/test/clang-doc/enum.cpp
index e559940a31de6..fd7bbcb53f2d2 100644
--- a/clang-tools-extra/test/clang-doc/enum.cpp
+++ b/clang-tools-extra/test/clang-doc/enum.cpp
@@ -21,9 +21,9 @@
enum Color {
// MD-INDEX-LINE: *Defined at {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp#[[@LINE-1]]*
// HTML-INDEX-LINE: <p>Defined at line [[@LINE-2]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
- Red, ///< Red
- Green, ///< Green
- Blue ///< Blue
+ Red, ///< Comment 1
+ Green, ///< Comment 2
+ Blue ///< Comment 3
};
// MD-INDEX: ## Enums
@@ -34,11 +34,16 @@ enum Color {
// MD-INDEX: | Blue |
// MD-INDEX: **brief** For specifying RGB colors
-// HTML-INDEX: <h2 id="Enums">Enums</h2>
-// HTML-INDEX: <h3 id="{{([0-9A-F]{40})}}">enum Color</h3>
-// HTML-INDEX: <li>Red</li>
-// HTML-INDEX: <li>Green</li>
-// HTML-INDEX: <li>Blue</li>
+// HTML-INDEX: <th colspan="3">enum Color</th>
+// HTML-INDEX: <td>Red</td>
+// HTML-INDEX: <td>0</td>
+// HTML-INDEX: <p> Comment 1</p>
+// HTML-INDEX: <td>Green</td>
+// HTML-INDEX: <td>1</td>
+// HTML-INDEX: <p> Comment 2</p>
+// HTML-INDEX: <td>Blue</td>
+// HTML-INDEX: <td>2</td>
+// HTML-INDEX: <p> Comment 3</p>
/**
* @brief Shape Types
@@ -46,11 +51,12 @@ enum Color {
enum class Shapes {
// MD-INDEX-LINE: *Defined at {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp#[[@LINE-1]]*
// HTML-INDEX-LINE: <p>Defined at line [[@LINE-2]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
- /// Circle
+
+ /// Comment 1
Circle,
- /// Rectangle
+ /// Comment 2
Rectangle,
- /// Triangle
+ /// Comment 3
Triangle
};
// MD-INDEX: | enum class Shapes |
@@ -60,10 +66,17 @@ enum class Shapes {
// MD-INDEX: | Triangle |
// MD-INDEX: **brief** Shape Types
-// HTML-INDEX: <h3 id="{{([0-9A-F]{40})}}">enum class Shapes</h3>
-// HTML-INDEX: <li>Circle</li>
-// HTML-INDEX: <li>Rectangle</li>
-// HTML-INDEX: <li>Triangle</li>
+// HTML-INDEX: <th colspan="3">enum class Shapes</th>
+// HTML-INDEX: <td>Circle</td>
+// HTML-INDEX: <td>0</td>
+// HTML-INDEX: <p> Comment 1</p>
+// HTML-INDEX: <td>Rectangle</td>
+// HTML-INDEX: <td>1</td>
+// HTML-INDEX: <p> Comment 2</p>
+// HTML-INDEX: <td>Triangle</td>
+// HTML-INDEX: <td>2</td>
+// HTML-INDEX: <p> Comment 3</p>
+
class Animals {
@@ -76,18 +89,25 @@ class Animals {
enum AnimalType {
// MD-ANIMAL-LINE: *Defined at {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp#[[@LINE-1]]*
// HTML-ANIMAL-LINE: <p>Defined at line [[@LINE-2]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
- Dog, /// Man's best friend
- Cat, /// Man's other best friend
- Iguana /// A lizard
+ Dog, ///< Man's best friend
+ Cat, ///< Man's other best friend
+ Iguana ///< A lizard
};
};
// HTML-ANIMAL: <h1>class Animals</h1>
// HTML-ANIMAL: <h2 id="Enums">Enums</h2>
-// HTML-ANIMAL: <h3 id="{{([0-9A-F]{40})}}">enum AnimalType</h3>
-// HTML-ANIMAL: <li>Dog</li>
-// HTML-ANIMAL: <li>Cat</li>
-// HTML-ANIMAL: <li>Iguana</li>
+// HTML-ANIMAL: <th colspan="3">enum AnimalType</th>
+// HTML-ANIMAL: <td>Dog</td>
+// HTML-ANIMAL: <td>0</td>
+// HTML-ANIMAL: <p> Man's best friend</p>
+// HTML-ANIMAL: <td>Cat</td>
+// HTML-ANIMAL: <td>1</td>
+// HTML-ANIMAL: <p> Man's other best friend</p>
+// HTML-ANIMAL: <td>Iguana</td>
+// HTML-ANIMAL: <td>2</td>
+// HTML-ANIMAL: <p> A lizard</p>
+
// MD-ANIMAL: # class Animals
// MD-ANIMAL: ## Enums
@@ -106,10 +126,11 @@ namespace Vehicles {
enum Car {
// MD-VEHICLES-LINE: *Defined at {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp#[[@LINE-1]]*
// HTML-VEHICLES-LINE: <p>Defined at line [[@LINE-2]] of file {{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
- Sedan, /// Sedan
- SUV, /// SUV
- Pickup, /// Pickup
- Hatchback /// Hatchback
+
+ Sedan, ///< Comment 1
+ SUV, ///< Comment 2
+ Pickup, ///< Comment 3
+ Hatchback ///< Comment 4
};
}
@@ -124,9 +145,37 @@ namespace Vehicles {
// MD-VEHICLES: **brief** specify type of car
// HTML-VEHICLES: <h1>namespace Vehicles</h1>
-// HTML-VEHICLES: <h2 id="Enums">Enums</h2>
-// HTML-VEHICLES: <h3 id="{{([0-9A-F]{40})}}">enum Car</h3>
-// HTML-VEHICLES: <li>Sedan</li>
-// HTML-VEHICLES: <li>SUV</li>
-// HTML-VEHICLES: <li>Pickup</li>
-// HTML-VEHICLES: <li>Hatchback</li>
\ No newline at end of file
+// HTML-VEHICLES: <th colspan="3">enum Car</th>
+// HTML-VEHICLES: <td>Sedan</td>
+// HTML-VEHICLES: <td>0</td>
+// HTML-VEHICLES: <p> Comment 1</p>
+// HTML-VEHICLES: <td>SUV</td>
+// HTML-VEHICLES: <td>1</td>
+// HTML-VEHICLES: <p> Comment 2</p>
+// HTML-VEHICLES: <td>Pickup</td>
+// HTML-VEHICLES: <td>2</td>
+// HTML-VEHICLES: <p> Comment 3</p>
+// HTML-VEHICLES: <td>Hatchback</td>
+// HTML-VEHICLES: <td>3</td>
+// HTML-VEHICLES: <p> Comment 4</p>
+
+
+enum ColorUserSpecified {
+ RedUserSpecified = 'A',
+ GreenUserSpecified = 2,
+ BlueUserSpecified = 'C'
+};
+
+// MD-INDEX: | enum ColorUserSpecified |
+// MD-INDEX: --
+// MD-INDEX: | RedUserSpecified |
+// MD-INDEX: | GreenUserSpecified |
+// MD-INDEX: | BlueUserSpecified |
+
+// HTML-INDEX: <th colspan="2">enum ColorUserSpecified</th>
+// HTML-INDEX: <td>RedUserSpecified</td>
+// HTML-INDEX: <td>'A'</td>
+// HTML-INDEX: <td>GreenUserSpecified</td>
+// HTML-INDEX: <td>2</td>
+// HTML-INDEX: <td>BlueUserSpecified</td>
+// HTML-INDEX: <td>'C'</td>
\ No newline at end of file
>From bcc4b0dc8b3b0216e6249c4de6f2cbcf14006bf6 Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Wed, 31 Jul 2024 00:02:13 -0400
Subject: [PATCH 2/2] [clang-doc] remove useless code
---
clang-tools-extra/clang-doc/Representation.cpp | 2 --
clang-tools-extra/clang-doc/Representation.h | 2 --
2 files changed, 4 deletions(-)
diff --git a/clang-tools-extra/clang-doc/Representation.cpp b/clang-tools-extra/clang-doc/Representation.cpp
index 028dffc21793a..d08afbb962189 100644
--- a/clang-tools-extra/clang-doc/Representation.cpp
+++ b/clang-tools-extra/clang-doc/Representation.cpp
@@ -266,8 +266,6 @@ void EnumInfo::merge(EnumInfo &&Other) {
Scoped = Other.Scoped;
if (Members.empty())
Members = std::move(Other.Members);
- if (Other.HasComments || HasComments)
- HasComments = true;
SymbolInfo::merge(std::move(Other));
}
diff --git a/clang-tools-extra/clang-doc/Representation.h b/clang-tools-extra/clang-doc/Representation.h
index db3aff2d60a1b..bd5254b0a8465 100644
--- a/clang-tools-extra/clang-doc/Representation.h
+++ b/clang-tools-extra/clang-doc/Representation.h
@@ -445,8 +445,6 @@ struct EnumInfo : public SymbolInfo {
// Indicates whether this enum is scoped (e.g. enum class).
bool Scoped = false;
- // Indicates whether or not enum members have comments attached
- bool HasComments = false;
// Set to nonempty to the type when this is an explicitly typed enum. For
// enum Foo : short { ... };
More information about the cfe-commits
mailing list