[clang-tools-extra] [clang-doc] add support for enums comments in html generation (PR #101282)

via cfe-commits cfe-commits at lists.llvm.org
Mon Aug 12 15:29:58 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/6] [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 bfb04e7407b380..1f2fb0a8b2b855 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 7e5a11783d303a..06f30f76e33d8c 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 aef22453035c30..a37192d6ceb9b0 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 d08afbb9621890..028dffc21793ae 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 d70c279f7a2bdc..db3aff2d60a1b5 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 3b074d849e8a9c..78b7041368d6df 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 e559940a31de69..fd7bbcb53f2d2b 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/6] [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 028dffc21793ae..d08afbb9621890 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 db3aff2d60a1b5..bd5254b0a84657 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 { ... };

>From 5fe47ca87f8dd592fee7a45401eed2620152e5c1 Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Wed, 31 Jul 2024 00:33:48 -0400
Subject: [PATCH 3/6] [clang-doc] modify unittest

---
 .../unittests/clang-doc/HTMLGeneratorTest.cpp | 33 +++++++++++++++----
 1 file changed, 27 insertions(+), 6 deletions(-)

diff --git a/clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp b/clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp
index e4a7340318b934..7ee482e275149d 100644
--- a/clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp
@@ -92,7 +92,13 @@ TEST(HTMLGeneratorTest, emitNamespaceHTML) {
     </div>
     <h2 id="Enums">Enums</h2>
     <div>
-      <h3 id="0000000000000000000000000000000000000000">enum OneEnum</h3>
+      <table id="0000000000000000000000000000000000000000">
+        <thead>
+          <tr>
+            <th colspan="2">enum OneEnum</th>
+          </tr>
+        </thead>
+      </table>
     </div>
   </div>
   <div id="sidebar-right" class="col-xs-6 col-sm-6 col-md-2 sidebar sidebar-offcanvas-right">
@@ -212,7 +218,13 @@ TEST(HTMLGeneratorTest, emitRecordHTML) {
     </div>
     <h2 id="Enums">Enums</h2>
     <div>
-      <h3 id="0000000000000000000000000000000000000000">enum OneEnum</h3>
+      <table id="0000000000000000000000000000000000000000">
+        <thead>
+          <tr>
+            <th colspan="2">enum OneEnum</th>
+          </tr>
+        </thead>
+      </table>
     </div>
   </div>
   <div id="sidebar-right" class="col-xs-6 col-sm-6 col-md-2 sidebar sidebar-offcanvas-right">
@@ -346,10 +358,19 @@ TEST(HTMLGeneratorTest, emitEnumHTML) {
 <main>
   <div id="sidebar-left" path="" class="col-xs-6 col-sm-3 col-md-2 sidebar sidebar-offcanvas-left"></div>
   <div id="main-content" class="col-xs-12 col-sm-9 col-md-8 main-content">
-    <h3 id="0000000000000000000000000000000000000000">enum class e</h3>
-    <ul>
-      <li>X</li>
-    </ul>
+    <table id="0000000000000000000000000000000000000000">
+      <thead>
+        <tr>
+          <th colspan="2">enum class e</th>
+        </tr>
+      </thead>
+      <tbody>
+        <tr>
+          <td>X</td>
+          <td>0</td>
+        </tr>
+      </tbody>
+    </table>
     <p>
       Defined at line 
       <a href="https://www.repository.com/test.cpp#10">10</a>

>From 28fb40f0cdbe37257d8aea9f05519519d9f2c470 Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Mon, 12 Aug 2024 17:12:48 -0400
Subject: [PATCH 4/6] [clang-doc] address pr comments

---
 clang-tools-extra/clang-doc/HTMLGenerator.cpp | 38 ++++++++-----------
 .../clang-doc/Representation.cpp              |  2 +-
 clang-tools-extra/clang-doc/Representation.h  |  4 +-
 clang-tools-extra/clang-doc/Serialize.cpp     |  8 ++--
 4 files changed, 23 insertions(+), 29 deletions(-)

diff --git a/clang-tools-extra/clang-doc/HTMLGenerator.cpp b/clang-tools-extra/clang-doc/HTMLGenerator.cpp
index a37192d6ceb9b0..ad7e08667e5cbc 100644
--- a/clang-tools-extra/clang-doc/HTMLGenerator.cpp
+++ b/clang-tools-extra/clang-doc/HTMLGenerator.cpp
@@ -397,8 +397,7 @@ genEnumsBlock(const std::vector<EnumInfo> &Enums,
 }
 
 static std::unique_ptr<TagNode>
-genEnumMembersBlock(const llvm::SmallVector<EnumValueInfo, 4> &Members,
-                    bool HasComments) {
+genEnumMembersBlock(const llvm::SmallVector<EnumValueInfo, 4> &Members) {
   if (Members.empty())
     return nullptr;
 
@@ -416,8 +415,7 @@ genEnumMembersBlock(const llvm::SmallVector<EnumValueInfo, 4> &Members,
       TRNode->Children.emplace_back(
           std::make_unique<TagNode>(HTMLTag::TAG_TD, M.Value));
     }
-
-    if (HasComments) {
+    if (M.Description.empty()) {
       auto TD = std::make_unique<TagNode>(HTMLTag::TAG_TD);
       TD->Children.emplace_back(genHTML(M.Description));
       TRNode->Children.emplace_back(std::move(TD));
@@ -663,7 +661,7 @@ static std::unique_ptr<HTMLNode> genHTML(const CommentInfo &I) {
     }
     return std::move(FullComment);
   }
- 
+
   if (I.Kind == "ParagraphComment") {
     auto ParagraphComment = std::make_unique<TagNode>(HTMLTag::TAG_P);
     for (const auto &Child : I.Children) {
@@ -698,16 +696,12 @@ 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;
-    }
-  }
+  bool HasComments =
+      std::any_of(I.Members.begin(), I.Members.end(),
+                  [](const EnumValueInfo &M) { return M.Description.empty(); });
   std::unique_ptr<TagNode> Table =
       std::make_unique<TagNode>(HTMLTag::TAG_TABLE);
-  std::unique_ptr<TagNode> Thead =
+  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 =
@@ -717,10 +711,10 @@ genHTML(const EnumInfo &I, const ClangDocContext &CDCtx) {
 
   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));
+  THead->Children.emplace_back(std::move(TRow));
+  Table->Children.emplace_back(std::move(THead));
 
-  std::unique_ptr<TagNode> Node = genEnumMembersBlock(I.Members, HasComments);
+  std::unique_ptr<TagNode> Node = genEnumMembersBlock(I.Members);
 
   if (Node)
     Table->Children.emplace_back(std::move(Node));
@@ -731,8 +725,8 @@ genHTML(const EnumInfo &I, const ClangDocContext &CDCtx) {
     if (!CDCtx.RepositoryUrl)
       Out.emplace_back(writeFileDefinition(*I.DefLoc));
     else
-      Out.emplace_back(writeFileDefinition(
-          *I.DefLoc, StringRef{*CDCtx.RepositoryUrl}));
+      Out.emplace_back(
+          writeFileDefinition(*I.DefLoc, StringRef{*CDCtx.RepositoryUrl}));
   }
 
   std::string Description;
@@ -780,8 +774,8 @@ genHTML(const FunctionInfo &I, const ClangDocContext &CDCtx,
     if (!CDCtx.RepositoryUrl)
       Out.emplace_back(writeFileDefinition(*I.DefLoc));
     else
-      Out.emplace_back(writeFileDefinition(
-          *I.DefLoc, StringRef{*CDCtx.RepositoryUrl}));
+      Out.emplace_back(
+          writeFileDefinition(*I.DefLoc, StringRef{*CDCtx.RepositoryUrl}));
   }
 
   std::string Description;
@@ -847,8 +841,8 @@ genHTML(const RecordInfo &I, Index &InfoIndex, const ClangDocContext &CDCtx,
     if (!CDCtx.RepositoryUrl)
       Out.emplace_back(writeFileDefinition(*I.DefLoc));
     else
-      Out.emplace_back(writeFileDefinition(
-          *I.DefLoc, StringRef{*CDCtx.RepositoryUrl}));
+      Out.emplace_back(
+          writeFileDefinition(*I.DefLoc, StringRef{*CDCtx.RepositoryUrl}));
   }
 
   std::string Description;
diff --git a/clang-tools-extra/clang-doc/Representation.cpp b/clang-tools-extra/clang-doc/Representation.cpp
index d08afbb9621890..da948ee74c9d63 100644
--- a/clang-tools-extra/clang-doc/Representation.cpp
+++ b/clang-tools-extra/clang-doc/Representation.cpp
@@ -221,7 +221,7 @@ void SymbolInfo::merge(SymbolInfo &&Other) {
 }
 
 NamespaceInfo::NamespaceInfo(SymbolID USR, StringRef Name, StringRef Path)
-      : Info(InfoType::IT_namespace, USR, Name, Path) {}
+    : Info(InfoType::IT_namespace, USR, Name, Path) {}
 
 void NamespaceInfo::merge(NamespaceInfo &&Other) {
   assert(mergeable(Other));
diff --git a/clang-tools-extra/clang-doc/Representation.h b/clang-tools-extra/clang-doc/Representation.h
index bd5254b0a84657..873ac728066261 100644
--- a/clang-tools-extra/clang-doc/Representation.h
+++ b/clang-tools-extra/clang-doc/Representation.h
@@ -48,7 +48,7 @@ enum class InfoType {
 // A representation of a parsed comment.
 struct CommentInfo {
   CommentInfo() = default;
-  CommentInfo(CommentInfo &Other) = delete;
+  CommentInfo(CommentInfo &Other) = default;
   CommentInfo(CommentInfo &&Other) = default;
   CommentInfo &operator=(CommentInfo &&Other) = default;
 
@@ -432,7 +432,7 @@ struct EnumValueInfo {
   // constant. This will be empty for implicit enumeration values.
   SmallString<16> ValueExpr;
 
-  std::vector<CommentInfo> Description; // Comment description of this field.
+  std::vector<CommentInfo> Description; /// Comment description of this field.
 };
 
 // TODO: Expand to allow for documenting templating.
diff --git a/clang-tools-extra/clang-doc/Serialize.cpp b/clang-tools-extra/clang-doc/Serialize.cpp
index 78b7041368d6df..273bc10d3b55d8 100644
--- a/clang-tools-extra/clang-doc/Serialize.cpp
+++ b/clang-tools-extra/clang-doc/Serialize.cpp
@@ -398,8 +398,8 @@ static void parseEnumerators(EnumInfo &I, const EnumDecl *D) {
     E->getInitVal().toString(ValueStr);
     I.Members.emplace_back(E->getNameAsString(), ValueStr.str(), ValueExpr);
     ASTContext &Context = E->getASTContext();
-    RawComment *Comment = E->getASTContext().getRawCommentForDeclNoCache(E);
-    if (Comment) {
+    if (RawComment *Comment =
+            E->getASTContext().getRawCommentForDeclNoCache(E)) {
       CommentInfo CInfo;
       Comment->setAttached();
       if (comments::FullComment *Fc = Comment->parse(Context, nullptr, E)) {
@@ -568,7 +568,7 @@ static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D,
 static void populateMemberTypeInfo(MemberTypeInfo &I, const FieldDecl *D) {
   assert(D && "Expect non-null FieldDecl in populateMemberTypeInfo");
 
-  ASTContext& Context = D->getASTContext();
+  ASTContext &Context = D->getASTContext();
   // TODO investigate whether we can use ASTContext::getCommentForDecl instead
   // of this logic. See also similar code in Mapper.cpp.
   RawComment *Comment = Context.getRawCommentForDeclNoCache(D);
@@ -576,7 +576,7 @@ static void populateMemberTypeInfo(MemberTypeInfo &I, const FieldDecl *D) {
     return;
 
   Comment->setAttached();
-  if (comments::FullComment* fc = Comment->parse(Context, nullptr, D)) {
+  if (comments::FullComment *fc = Comment->parse(Context, nullptr, D)) {
     I.Description.emplace_back();
     parseFullComment(fc, I.Description.back());
   }

>From 0d150ea08af767017e108096533f0c0d8b31668a Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Mon, 12 Aug 2024 17:24:55 -0400
Subject: [PATCH 5/6] [clang-doc] revert CommentInfo change

---
 clang-tools-extra/clang-doc/Representation.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang-tools-extra/clang-doc/Representation.h b/clang-tools-extra/clang-doc/Representation.h
index 873ac728066261..8f2bba786316fe 100644
--- a/clang-tools-extra/clang-doc/Representation.h
+++ b/clang-tools-extra/clang-doc/Representation.h
@@ -48,7 +48,7 @@ enum class InfoType {
 // A representation of a parsed comment.
 struct CommentInfo {
   CommentInfo() = default;
-  CommentInfo(CommentInfo &Other) = default;
+  CommentInfo(CommentInfo &Other) = delete;
   CommentInfo(CommentInfo &&Other) = default;
   CommentInfo &operator=(CommentInfo &&Other) = default;
 

>From e5e70b87003e4e7b8e68d23fc89f7edd6961764f Mon Sep 17 00:00:00 2001
From: PeterChou1 <peter.chou at mail.utoronto.ca>
Date: Mon, 12 Aug 2024 18:29:39 -0400
Subject: [PATCH 6/6] [clang-doc] fix test

---
 clang-tools-extra/clang-doc/HTMLGenerator.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang-tools-extra/clang-doc/HTMLGenerator.cpp b/clang-tools-extra/clang-doc/HTMLGenerator.cpp
index ad7e08667e5cbc..00f94788ced44c 100644
--- a/clang-tools-extra/clang-doc/HTMLGenerator.cpp
+++ b/clang-tools-extra/clang-doc/HTMLGenerator.cpp
@@ -415,7 +415,7 @@ genEnumMembersBlock(const llvm::SmallVector<EnumValueInfo, 4> &Members) {
       TRNode->Children.emplace_back(
           std::make_unique<TagNode>(HTMLTag::TAG_TD, M.Value));
     }
-    if (M.Description.empty()) {
+    if (!M.Description.empty()) {
       auto TD = std::make_unique<TagNode>(HTMLTag::TAG_TD);
       TD->Children.emplace_back(genHTML(M.Description));
       TRNode->Children.emplace_back(std::move(TD));



More information about the cfe-commits mailing list