https://github.com/SamrudhNelli updated 
https://github.com/llvm/llvm-project/pull/183754

>From d9e58f68ad9fa377e91d1778d2393c3bc8451c55 Mon Sep 17 00:00:00 2001
From: Samrudh Nelli <[email protected]>
Date: Fri, 27 Feb 2026 21:07:37 +0530
Subject: [PATCH 01/10] display in a table format

---
 clang-tools-extra/clang-doc/MDGenerator.cpp |  63 ++++-
 clang-tools-extra/test/clang-doc/enum.cpp   | 284 +++++++++++++++-----
 2 files changed, 277 insertions(+), 70 deletions(-)

diff --git a/clang-tools-extra/clang-doc/MDGenerator.cpp 
b/clang-tools-extra/clang-doc/MDGenerator.cpp
index fcb75af80f9e9..6fd0bf2df038a 100644
--- a/clang-tools-extra/clang-doc/MDGenerator.cpp
+++ b/clang-tools-extra/clang-doc/MDGenerator.cpp
@@ -67,6 +67,30 @@ static void writeSourceFileRef(const ClangDocContext &CDCtx, 
const Location &L,
   OS << "\n\n";
 }
 
+static std::string genRawText(const std::vector<CommentInfo> &Comments) {
+  std::string Result;
+  llvm::raw_string_ostream OS(Result);
+  std::queue<const CommentInfo *> Q;
+  for (const auto &CI : Comments)
+    Q.push(&CI);
+  const CommentInfo *Comment;
+  bool First = true;
+  while (Q.size()) {
+    Comment = Q.front();
+    Q.pop();
+    if (!Comment->Text.empty())
+    {
+      if (!First)
+        OS << "<br>";
+      OS << Comment->Text;
+      First = false;
+    }
+    for (const auto &CI : Comment->Children)
+      Q.push(CI.get());
+  }
+  return Result;
+}
+
 static void maybeWriteSourceFileRef(llvm::raw_ostream &OS,
                                     const ClangDocContext &CDCtx,
                                     const std::optional<Location> &DefLoc) {
@@ -157,16 +181,41 @@ static void writeNameLink(const StringRef &CurrentPath, 
const Reference &R,
 static void genMarkdown(const ClangDocContext &CDCtx, const EnumInfo &I,
                         llvm::raw_ostream &OS) {
   if (I.Scoped)
-    writeLine("| enum class " + I.Name + " |", OS);
-  else
-    writeLine("| enum " + I.Name + " |", OS);
-  writeLine("--", OS);
+    OS << "class ";
+  OS << (I.Name.empty() ? "(unnamed)" : StringRef(I.Name)) << " ";
+  if (I.BaseType && !I.BaseType->Type.QualName.empty()) {
+    OS << ": " << I.BaseType->Type.QualName << " ";
+  }
+  OS << "|\n\n";
 
   std::string Buffer;
   llvm::raw_string_ostream Members(Buffer);
-  if (!I.Members.empty())
-    for (const auto &N : I.Members)
-      Members << "| " << N.Name << " |\n";
+  Members << "| Name | Value |";
+  if (!I.Members.empty()) {
+    bool HasComments = false;
+    for (const auto &Member : I.Members) {
+      if (!Member.Description.empty()) {
+        HasComments = true;
+        Members << " Comments |";
+        break;
+      }
+    }
+    Members << "\n";
+    Members << "|:-:|:-:|";
+    if (HasComments)
+      Members << ":-:|";
+    Members << "\n";
+    for (const auto &N : I.Members) {
+      Members << "| " << N.Name << " ";
+      if (!N.Value.empty())
+        Members << "| " << N.Value << " ";
+      if (HasComments) {
+        std::string RawComment = 
StringRef(genRawText(N.Description)).trim().str();
+        Members << "| " << (RawComment.empty() ? "--" : RawComment) << " ";
+      }
+      Members << "|\n";
+    }
+  }
   writeLine(Members.str(), OS);
 
   maybeWriteSourceFileRef(OS, CDCtx, I.DefLoc);
diff --git a/clang-tools-extra/test/clang-doc/enum.cpp 
b/clang-tools-extra/test/clang-doc/enum.cpp
index 6e11bbf065f25..c58d94404fcdc 100644
--- a/clang-tools-extra/test/clang-doc/enum.cpp
+++ b/clang-tools-extra/test/clang-doc/enum.cpp
@@ -30,9 +30,9 @@ enum Color {
 // MD-INDEX: ## Enums
 // MD-INDEX: | enum Color |
 // MD-INDEX: --
-// MD-INDEX: | Red |
-// MD-INDEX: | Green |
-// MD-INDEX: | Blue |
+// MD-INDEX: | Red | 0 | Comment 1 |
+// MD-INDEX: | Green | Comment 2 |
+// MD-INDEX: | Blue | Comment 3 |
 // MD-INDEX: **brief** For specifying RGB colors
 
 // HTML-INDEX:     <div>
@@ -73,37 +73,192 @@ enum class Shapes {
   /// Comment 3
   Triangle
 };
+
 // MD-INDEX: | enum class Shapes |
 // MD-INDEX: --
-// MD-INDEX: | Circle |
-// MD-INDEX: | Rectangle |
-// MD-INDEX: | Triangle |
+// MD-INDEX: | Circle | 0 | Comment 1 |
+// MD-INDEX: | Rectangle | 1 | Comment 2 |
+// MD-INDEX: | Triangle | 2 | Comment 3 |
 // MD-INDEX: **brief** Shape Types
 
-// COM: FIXME: Serialize "enum class" in template
-// HTML-INDEX:     <div>
-// HTML-INDEX:         <pre><code class="language-cpp code-clang-doc">enum 
Shapes</code></pre>
-// HTML-INDEX:     </div>
-// HTML-INDEX:     <table class="table-wrapper">
-// HTML-INDEX:         <tbody>
-// HTML-INDEX:             <tr>
-// HTML-INDEX:                 <th>Name</th>
-// HTML-INDEX:                 <th>Value</th>
-// HTML-INDEX:             </tr>
-// HTML-INDEX:             <tr>
-// HTML-INDEX:                 <td>Circle</td>
-// HTML-INDEX:                 <td>0</td>
-// HTML-INDEX:             </tr>
-// HTML-INDEX:             <tr>
-// HTML-INDEX:                 <td>Rectangle</td>
-// HTML-INDEX:                 <td>1</td>
-// HTML-INDEX:             </tr>
-// HTML-INDEX:             <tr>
-// HTML-INDEX:                 <td>Triangle</td>
-// HTML-INDEX:                 <td>2</td>
-// HTML-INDEX:             </tr>
-// HTML-INDEX:         </tbody>
-// HTML-INDEX:     </table>
+// HTML-INDEX-LABEL:  <div id="{{([0-9A-F]{40})}}" class="delimiter-container">
+// HTML-INDEX-NEXT:     <div>
+// HTML-INDEX-NEXT:       <pre><code class="language-cpp code-clang-doc">enum 
class Shapes</code></pre>
+// HTML-INDEX-NEXT:     </div>
+// HTML-INDEX-NEXT:     <table class="table-wrapper">
+// HTML-INDEX-NEXT:         <tbody>
+// HTML-INDEX-NEXT:             <tr>
+// HTML-INDEX-NEXT:                 <th>Name</th>
+// HTML-INDEX-NEXT:                 <th>Value</th>
+// HTML-INDEX-NEXT:             </tr>
+// HTML-INDEX-NEXT:             <tr>
+// HTML-INDEX-NEXT:                 <td>Circle</td>
+// HTML-INDEX-NEXT:                 <td>0</td>
+// HTML-INDEX-NEXT:             </tr>
+// HTML-INDEX-NEXT:             <tr>
+// HTML-INDEX-NEXT:                 <td>Rectangle</td>
+// HTML-INDEX-NEXT:                 <td>1</td>
+// HTML-INDEX-NEXT:             </tr>
+// HTML-INDEX-NEXT:             <tr>
+// HTML-INDEX-NEXT:                 <td>Triangle</td>
+// HTML-INDEX-NEXT:                 <td>2</td>
+// HTML-INDEX-NEXT:             </tr>
+// HTML-INDEX-NEXT:         </tbody>
+// HTML-INDEX-NEXT:     </table>
+// HTML-INDEX-NEXT:     <div class="doc-card">
+// HTML-INDEX-NEXT:       <div class="nested-delimiter-container">
+// HTML-INDEX-NEXT:           <p> Shape Types</p>
+// HTML-INDEX-NEXT:       </div>
+// HTML-INDEX-NEXT:     </div>
+// HTML-INDEX-NEXT:     <p>Defined at line [[@LINE-48]] of file 
{{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
+// HTML-INDEX-NEXT:   </div>
+
+typedef unsigned char uint8_t;
+/**
+ * @brief Specify the size
+ */
+enum Size : uint8_t {
+  // 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>
+  Small,   ///< A pearl
+  Medium,  ///< A tennis ball
+  Large    ///< A football
+};
+
+// MD-INDEX: | enum Size : uint8_t |
+// MD-INDEX: --
+// MD-INDEX: | Small | 0 | A pearl |
+// MD-INDEX: | Medium | 1 | A tennis ball |
+// MD-INDEX: | Large | 2 | A football |
+// MD-INDEX: **brief** Specify the size
+
+// HTML-INDEX-LABEL:   <div id="{{([0-9A-F]{40})}}" 
class="delimiter-container">
+// HTML-INDEX-NEXT:     <div>
+// HTML-INDEX-NEXT:       <pre><code class="language-cpp code-clang-doc">enum 
Size : uint8_t</code></pre>
+// HTML-INDEX-NEXT:     </div>
+// HTML-INDEX-NEXT:     <table class="table-wrapper">
+// HTML-INDEX-NEXT:         <tbody>
+// HTML-INDEX-NEXT:             <tr>
+// HTML-INDEX-NEXT:                 <th>Name</th>
+// HTML-INDEX-NEXT:                 <th>Value</th>
+// HTML-INDEX-NEXT:             </tr>
+// HTML-INDEX-NEXT:             <tr>
+// HTML-INDEX-NEXT:                 <td>Small</td>
+// HTML-INDEX-NEXT:                 <td>0</td>
+// HTML-INDEX-NEXT:             </tr>
+// HTML-INDEX-NEXT:             <tr>
+// HTML-INDEX-NEXT:                 <td>Medium</td>
+// HTML-INDEX-NEXT:                 <td>1</td>
+// HTML-INDEX-NEXT:             </tr>
+// HTML-INDEX-NEXT:             <tr>
+// HTML-INDEX-NEXT:                 <td>Large</td>
+// HTML-INDEX-NEXT:                 <td>2</td>
+// HTML-INDEX-NEXT:             </tr>
+// HTML-INDEX-NEXT:         </tbody>
+// HTML-INDEX-NEXT:     </table>
+// HTML-INDEX-NEXT:     <div class="doc-card">
+// HTML-INDEX-NEXT:       <div class="nested-delimiter-container">
+// HTML-INDEX-NEXT:           <p> Specify the size</p>
+// HTML-INDEX-NEXT:       </div>
+// HTML-INDEX-NEXT:     </div>
+// HTML-INDEX-NEXT:     <p>Defined at line [[@LINE-44]] of file 
{{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
+// HTML-INDEX-NEXT:   </div>
+
+/**
+ * @brief Very long number
+ */
+enum : long long {
+  // 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>
+  BigVal = 999999999999   ///< A very large value
+};
+
+// MD-INDEX: | enum (unnamed) : long long |
+// MD-INDEX: --
+// MD-INDEX: | BigVal | 999999999999 | A very large value |
+// MD-INDEX: **brief** Very long number
+
+// HTML-INDEX-LABEL:  <div id="{{([0-9A-F]{40})}}" class="delimiter-container">
+// HTML-INDEX-NEXT:     <div>
+// HTML-INDEX-NEXT:       <pre><code class="language-cpp code-clang-doc">enum 
(unnamed) : long long</code></pre>
+// HTML-INDEX-NEXT:     </div>
+// HTML-INDEX-NEXT:     <table class="table-wrapper">
+// HTML-INDEX-NEXT:         <tbody>
+// HTML-INDEX-NEXT:             <tr>
+// HTML-INDEX-NEXT:                 <th>Name</th>
+// HTML-INDEX-NEXT:                 <th>Value</th>
+// HTML-INDEX-NEXT:             </tr>
+// HTML-INDEX-NEXT:             <tr>
+// HTML-INDEX-NEXT:                 <td>BigVal</td>
+// HTML-INDEX-NEXT:                 <td>999999999999</td>
+// HTML-INDEX-NEXT:             </tr>
+// HTML-INDEX-NEXT:         </tbody>
+// HTML-INDEX-NEXT:     </table>
+// HTML-INDEX-NEXT:     <div class="doc-card">
+// HTML-INDEX-NEXT:       <div class="nested-delimiter-container">
+// HTML-INDEX-NEXT:           <p> Very long number</p>
+// HTML-INDEX-NEXT:       </div>
+// HTML-INDEX-NEXT:     </div>
+// HTML-INDEX-NEXT:     <p>Defined at line [[@LINE-32]] of file 
{{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
+// HTML-INDEX-NEXT:   </div>
+
+class FilePermissions {
+// MD-PERM-LINE: *Defined at 
{{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp#[[@LINE-1]]*
+// HTML-PERM-LINE: <p>Defined at line [[@LINE-2]] of file 
{{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
+public:
+  /**
+   * @brief File permission flags
+   */
+  enum {
+  // MD-PERM-LINE: *Defined at 
{{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp#[[@LINE-1]]*
+  // HTML-PERM-LINE: <p>Defined at line [[@LINE-2]] of file 
{{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
+    Read    = 1,     ///> Permission to READ r
+    Write   = 2,     ///> Permission to WRITE w
+    Execute = 4      ///> Permission to EXECUTE x
+  };
+};
+
+// MD-PERM: | enum (unnamed) |
+// MD-PERM: --
+// MD-PERM: | Read | 1 | Permission to READ r |
+// MD-PERM: | Write | 2 | Permission to WRITE w |
+// MD-PERM: | Execute | 4 | Permission to EXECUTE x |
+// MD-PERM: **brief** File permission flags
+
+// HTML-PERM-LABEL:  <section id="Enums" class="section-container">
+// HTML-PERM-NEXT:     <h2>Enumerations</h2>
+// HTML-PERM-NEXT:     <div id="{{([0-9A-F]{40})}}" 
class="delimiter-container">
+// HTML-PERM-NEXT:       <div>
+// HTML-PERM-NEXT:         <pre><code class="language-cpp code-clang-doc">enum 
(unnamed)</code></pre>
+// HTML-PERM-NEXT:       </div>
+// HTML-PERM-NEXT:       <table class="table-wrapper">
+// HTML-PERM-NEXT:           <tbody>
+// HTML-PERM-NEXT:               <tr>
+// HTML-PERM-NEXT:                   <th>Name</th>
+// HTML-PERM-NEXT:                   <th>Value</th>
+// HTML-PERM-NEXT:               </tr>
+// HTML-PERM-NEXT:               <tr>
+// HTML-PERM-NEXT:                   <td>Read</td>
+// HTML-PERM-NEXT:                   <td>1</td>
+// HTML-PERM-NEXT:               </tr>
+// HTML-PERM-NEXT:               <tr>
+// HTML-PERM-NEXT:                   <td>Write</td>
+// HTML-PERM-NEXT:                   <td>2</td>
+// HTML-PERM-NEXT:               </tr>
+// HTML-PERM-NEXT:               <tr>
+// HTML-PERM-NEXT:                   <td>Execute</td>
+// HTML-PERM-NEXT:                   <td>4</td>
+// HTML-PERM-NEXT:               </tr>
+// HTML-PERM-NEXT:           </tbody>
+// HTML-PERM-NEXT:       </table>
+// HTML-PERM-NEXT:       <div class="doc-card">
+// HTML-PERM-NEXT:         <div class="nested-delimiter-container">
+// HTML-PERM-NEXT:             <p> File permission flags</p>
+// HTML-PERM-NEXT:         </div>
+// HTML-PERM-NEXT:       </div>
+// HTML-PERM-NEXT:         <p>Defined at line [[@LINE-47]] of file 
{{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
+// HTML-PERM-NEXT:     </div>
+// HTML-PERM-NEXT:   </section>
 
 // COM: FIXME: Add enums declared inside of classes to class template
 class Animals {
@@ -161,9 +316,9 @@ class Animals {
 // MD-ANIMAL: ## Enums
 // MD-ANIMAL: | enum AnimalType |
 // MD-ANIMAL: --
-// MD-ANIMAL: | Dog |
-// MD-ANIMAL: | Cat |
-// MD-ANIMAL: | Iguana |
+// MD-ANIMAL: | Dog | 0 | Man's best friend |
+// MD-ANIMAL: | Cat | 1 | Man's other best friend |
+// MD-ANIMAL: | Iguana | 2 | A lizard |
 // MD-ANIMAL: **brief** specify what animal the class is
 
 namespace Vehicles {
@@ -185,10 +340,10 @@ enum Car {
 // MD-VEHICLES: ## Enums
 // MD-VEHICLES: | enum Car |
 // MD-VEHICLES: --
-// MD-VEHICLES: | Sedan |
-// MD-VEHICLES: | SUV |
-// MD-VEHICLES: | Pickup |
-// MD-VEHICLES: | Hatchback |
+// MD-VEHICLES: | Sedan | 0 | Comment 1 |
+// MD-VEHICLES: | SUV | 1 | Comment 2 |
+// MD-VEHICLES: | Pickup | 2 | Comment 3 |
+// MD-VEHICLES: | Hatchback | 3 | Comment 4 |
 // MD-VEHICLES: **brief** specify type of car
 
 // HTML-VEHICLES:     <div>
@@ -227,30 +382,33 @@ enum ColorUserSpecified {
 
 // MD-INDEX: | enum ColorUserSpecified |
 // MD-INDEX: --
-// MD-INDEX: | RedUserSpecified |
-// MD-INDEX: | GreenUserSpecified |
-// MD-INDEX: | BlueUserSpecified |
+// MD-INDEX: | RedUserSpecified | 65 |
+// MD-INDEX: | GreenUserSpecified | 2 |
+// MD-INDEX: | BlueUserSpecified | 67 |
 
-// HTML-INDEX:     <div>
-// HTML-INDEX:         <pre><code class="language-cpp code-clang-doc">enum 
ColorUserSpecified</code></pre>
-// HTML-INDEX:     </div>
-// HTML-INDEX:     <table class="table-wrapper">
-// HTML-INDEX:         <tbody>
-// HTML-INDEX:             <tr>
-// HTML-INDEX:                 <th>Name</th>
-// HTML-INDEX:                 <th>Value</th>
-// HTML-INDEX:             </tr>
-// HTML-INDEX:             <tr>
-// HTML-INDEX:                 <td>RedUserSpecified</td>
-// HTML-INDEX:                 <td>&#39;A&#39;</td>
-// HTML-INDEX:             </tr>
-// HTML-INDEX:             <tr>
-// HTML-INDEX:                 <td>GreenUserSpecified</td>
-// HTML-INDEX:                 <td>2</td>
-// HTML-INDEX:             </tr>
-// HTML-INDEX:             <tr>
-// HTML-INDEX:                 <td>BlueUserSpecified</td>
-// HTML-INDEX:                 <td>&#39;C&#39;</td>
-// HTML-INDEX:             </tr>
-// HTML-INDEX:         </tbody>
-// HTML-INDEX:     </table>
+// HTML-INDEX-LABEL:  <div id="{{([0-9A-F]{40})}}" class="delimiter-container">
+// HTML-INDEX-NEXT:     <div>
+// HTML-INDEX-NEXT:       <pre><code class="language-cpp code-clang-doc">enum 
ColorUserSpecified</code></pre>
+// HTML-INDEX-NEXT:     </div>
+// HTML-INDEX-NEXT:     <table class="table-wrapper">
+// HTML-INDEX-NEXT:         <tbody>
+// HTML-INDEX-NEXT:             <tr>
+// HTML-INDEX-NEXT:                 <th>Name</th>
+// HTML-INDEX-NEXT:                 <th>Value</th>
+// HTML-INDEX-NEXT:             </tr>
+// HTML-INDEX-NEXT:             <tr>
+// HTML-INDEX-NEXT:                 <td>RedUserSpecified</td>
+// HTML-INDEX-NEXT:                 <td>&#39;A&#39;</td>
+// HTML-INDEX-NEXT:             </tr>
+// HTML-INDEX-NEXT:             <tr>
+// HTML-INDEX-NEXT:                 <td>GreenUserSpecified</td>
+// HTML-INDEX-NEXT:                 <td>2</td>
+// HTML-INDEX-NEXT:             </tr>
+// HTML-INDEX-NEXT:             <tr>
+// HTML-INDEX-NEXT:                 <td>BlueUserSpecified</td>
+// HTML-INDEX-NEXT:                 <td>&#39;C&#39;</td>
+// HTML-INDEX-NEXT:             </tr>
+// HTML-INDEX-NEXT:         </tbody>
+// HTML-INDEX-NEXT:     </table>
+// HTML-INDEX-NEXT:     <p>Defined at line [[@LINE-36]] of file 
{{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
+// HTML-INDEX-NEXT:   </div>

>From 7ee114499bf2dd88895ed16a0b463fd9c9ad3ced Mon Sep 17 00:00:00 2001
From: Samrudh Nelli <[email protected]>
Date: Mon, 2 Mar 2026 14:46:12 +0530
Subject: [PATCH 02/10] fix tests

---
 clang-tools-extra/test/clang-doc/enum.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang-tools-extra/test/clang-doc/enum.cpp 
b/clang-tools-extra/test/clang-doc/enum.cpp
index c58d94404fcdc..280c8892e4d43 100644
--- a/clang-tools-extra/test/clang-doc/enum.cpp
+++ b/clang-tools-extra/test/clang-doc/enum.cpp
@@ -31,8 +31,8 @@ enum Color {
 // MD-INDEX: | enum Color |
 // MD-INDEX: --
 // MD-INDEX: | Red | 0 | Comment 1 |
-// MD-INDEX: | Green | Comment 2 |
-// MD-INDEX: | Blue | Comment 3 |
+// MD-INDEX: | Green | 1 | Comment 2 |
+// MD-INDEX: | Blue | 2 | Comment 3 |
 // MD-INDEX: **brief** For specifying RGB colors
 
 // HTML-INDEX:     <div>

>From 9b75c69c8aad9f5ecffe2d096a398d7358b40558 Mon Sep 17 00:00:00 2001
From: Samrudh Nelli <[email protected]>
Date: Mon, 2 Mar 2026 17:16:34 +0530
Subject: [PATCH 03/10] fix tests

---
 clang-tools-extra/clang-doc/MDGenerator.cpp   |  3 +-
 clang-tools-extra/test/clang-doc/enum.cpp     | 65 ++++++++++++-------
 .../unittests/clang-doc/MDGeneratorTest.cpp   | 14 ++--
 3 files changed, 48 insertions(+), 34 deletions(-)

diff --git a/clang-tools-extra/clang-doc/MDGenerator.cpp 
b/clang-tools-extra/clang-doc/MDGenerator.cpp
index 665c86bfa2016..53605850b7a47 100644
--- a/clang-tools-extra/clang-doc/MDGenerator.cpp
+++ b/clang-tools-extra/clang-doc/MDGenerator.cpp
@@ -82,8 +82,9 @@ static std::string genRawText(const std::vector<CommentInfo> 
&Comments) {
     {
       if (!First)
         OS << "<br>";
+      else 
+        First = false;
       OS << Comment->Text;
-      First = false;
     }
     for (const auto &CI : Comment->Children)
       Q.push(CI.get());
diff --git a/clang-tools-extra/test/clang-doc/enum.cpp 
b/clang-tools-extra/test/clang-doc/enum.cpp
index 6730ad96934f1..d0a308c2d055f 100644
--- a/clang-tools-extra/test/clang-doc/enum.cpp
+++ b/clang-tools-extra/test/clang-doc/enum.cpp
@@ -33,7 +33,8 @@ enum Color {
 
 // MD-INDEX: ## Enums
 // MD-INDEX: | enum Color |
-// MD-INDEX: --
+// MD-INDEX: | Name | Value | Comments |
+// MD-INDEX: |:-:|:-:|:-:|
 // MD-INDEX: | Red | 0 | Comment 1 |
 // MD-INDEX: | Green | 1 | Comment 2 |
 // MD-INDEX: | Blue | 2 | Comment 3 |
@@ -68,7 +69,7 @@ enum Color {
 // HTML-INDEX-NEXT:           <p> For specifying RGB colors</p>
 // HTML-INDEX-NEXT:       </div>
 // HTML-INDEX-NEXT:     </div>
-// HTML-INDEX-NEXT:     <p>Defined at line [[@LINE-45]] of file 
{{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
+// HTML-INDEX-NEXT:     <p>Defined at line [[@LINE-46]] of file 
{{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
 // HTML-INDEX-NEXT:   </div>
 
 /**
@@ -87,7 +88,8 @@ enum class Shapes {
 };
 
 // MD-INDEX: | enum class Shapes |
-// MD-INDEX: --
+// MD-INDEX: | Name | Value | Comments |
+// MD-INDEX: |:-:|:-:|:-:|
 // MD-INDEX: | Circle | 0 | Comment 1 |
 // MD-INDEX: | Rectangle | 1 | Comment 2 |
 // MD-INDEX: | Triangle | 2 | Comment 3 |
@@ -122,7 +124,7 @@ enum class Shapes {
 // HTML-INDEX-NEXT:           <p> Shape Types</p>
 // HTML-INDEX-NEXT:       </div>
 // HTML-INDEX-NEXT:     </div>
-// HTML-INDEX-NEXT:     <p>Defined at line [[@LINE-48]] of file 
{{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
+// HTML-INDEX-NEXT:     <p>Defined at line [[@LINE-49]] of file 
{{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
 // HTML-INDEX-NEXT:   </div>
 
 typedef unsigned char uint8_t;
@@ -132,16 +134,26 @@ typedef unsigned char uint8_t;
 enum Size : uint8_t {
   // 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>
-  Small,   ///< A pearl
-  Medium,  ///< A tennis ball
-  Large    ///< A football
+
+  /// A pearl.
+  /// Pearls are quite small.
+  ///
+  /// Pearls are used in jewelry.
+  Small,
+
+  /// @brief A tennis ball.
+  Medium,
+
+  /// A football.
+  Large
 };
 
 // MD-INDEX: | enum Size : uint8_t |
-// MD-INDEX: --
-// MD-INDEX: | Small | 0 | A pearl |
-// MD-INDEX: | Medium | 1 | A tennis ball |
-// MD-INDEX: | Large | 2 | A football |
+// MD-INDEX: | Name | Value | Comments |
+// MD-INDEX: |:-:|:-:|:-:|
+// MD-INDEX: | Small | 0 | A pearl.<br> Pearls are quite small.<br> Pearls are 
used in jewelry. |
+// MD-INDEX: | Medium | 1 | A tennis ball. |
+// MD-INDEX: | Large | 2 | A football. |
 // MD-INDEX: **brief** Specify the size
 
 // HTML-INDEX-LABEL:   <div id="{{([0-9A-F]{40})}}" 
class="delimiter-container">
@@ -173,7 +185,7 @@ enum Size : uint8_t {
 // HTML-INDEX-NEXT:           <p> Specify the size</p>
 // HTML-INDEX-NEXT:       </div>
 // HTML-INDEX-NEXT:     </div>
-// HTML-INDEX-NEXT:     <p>Defined at line [[@LINE-44]] of file 
{{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
+// HTML-INDEX-NEXT:     <p>Defined at line [[@LINE-54]] of file 
{{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
 // HTML-INDEX-NEXT:   </div>
 
 /**
@@ -186,7 +198,8 @@ enum : long long {
 };
 
 // MD-INDEX: | enum (unnamed) : long long |
-// MD-INDEX: --
+// MD-INDEX: | Name | Value | Comments |
+// MD-INDEX: |:-:|:-:|:-:|
 // MD-INDEX: | BigVal | 999999999999 | A very large value |
 // MD-INDEX: **brief** Very long number
 
@@ -211,7 +224,7 @@ enum : long long {
 // HTML-INDEX-NEXT:           <p> Very long number</p>
 // HTML-INDEX-NEXT:       </div>
 // HTML-INDEX-NEXT:     </div>
-// HTML-INDEX-NEXT:     <p>Defined at line [[@LINE-32]] of file 
{{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
+// HTML-INDEX-NEXT:     <p>Defined at line [[@LINE-33]] of file 
{{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
 // HTML-INDEX-NEXT:   </div>
 
 class FilePermissions {
@@ -224,14 +237,15 @@ class FilePermissions {
   enum {
   // MD-PERM-LINE: *Defined at 
{{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp#[[@LINE-1]]*
   // HTML-PERM-LINE: <p>Defined at line [[@LINE-2]] of file 
{{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
-    Read    = 1,     ///> Permission to READ r
-    Write   = 2,     ///> Permission to WRITE w
-    Execute = 4      ///> Permission to EXECUTE x
+    Read    = 1,     ///< Permission to READ r
+    Write   = 2,     ///< Permission to WRITE w
+    Execute = 4      ///< Permission to EXECUTE x
   };
 };
 
 // MD-PERM: | enum (unnamed) |
-// MD-PERM: --
+// MD-PERM: | Name | Value | Comments |
+// MD-PERM: |:-:|:-:|:-:|
 // MD-PERM: | Read | 1 | Permission to READ r |
 // MD-PERM: | Write | 2 | Permission to WRITE w |
 // MD-PERM: | Execute | 4 | Permission to EXECUTE x |
@@ -268,7 +282,7 @@ class FilePermissions {
 // HTML-PERM-NEXT:             <p> File permission flags</p>
 // HTML-PERM-NEXT:         </div>
 // HTML-PERM-NEXT:       </div>
-// HTML-PERM-NEXT:         <p>Defined at line [[@LINE-47]] of file 
{{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
+// HTML-PERM-NEXT:         <p>Defined at line [[@LINE-48]] of file 
{{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
 // HTML-PERM-NEXT:     </div>
 // HTML-PERM-NEXT:   </section>
 
@@ -327,7 +341,8 @@ class Animals {
 // MD-ANIMAL: # class Animals
 // MD-ANIMAL: ## Enums
 // MD-ANIMAL: | enum AnimalType |
-// MD-ANIMAL: --
+// MD-ANIMAL: | Name | Value | Comments |
+// MD-ANIMAL: |:-:|:-:|:-:|
 // MD-ANIMAL: | Dog | 0 | Man's best friend |
 // MD-ANIMAL: | Cat | 1 | Man's other best friend |
 // MD-ANIMAL: | Iguana | 2 | A lizard |
@@ -351,7 +366,8 @@ enum Car {
 // MD-VEHICLES: # namespace Vehicles
 // MD-VEHICLES: ## Enums
 // MD-VEHICLES: | enum Car |
-// MD-VEHICLES: --
+// MD-VEHICLES: | Name | Value | Comments |
+// MD-VEHICLES: |:-:|:-:|:-:|
 // MD-VEHICLES: | Sedan | 0 | Comment 1 |
 // MD-VEHICLES: | SUV | 1 | Comment 2 |
 // MD-VEHICLES: | Pickup | 2 | Comment 3 |
@@ -391,7 +407,7 @@ enum Car {
 // HTML-VEHICLES-NEXT:           <p> specify type of car</p>
 // HTML-VEHICLES-NEXT:        </div>
 // HTML-VEHICLES-NEXT:      </div>
-// HTML-VEHICLES-NEXT:      <p>Defined at line [[@LINE-54]] of file 
{{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
+// HTML-VEHICLES-NEXT:      <p>Defined at line [[@LINE-55]] of file 
{{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
 // HTML-VEHICLES-NEXT:    </div>
 
 enum ColorUserSpecified {
@@ -401,7 +417,8 @@ enum ColorUserSpecified {
 };
 
 // MD-INDEX: | enum ColorUserSpecified |
-// MD-INDEX: --
+// MD-INDEX: | Name | Value |
+// MD-INDEX: |:-:|:-:|
 // MD-INDEX: | RedUserSpecified | 65 |
 // MD-INDEX: | GreenUserSpecified | 2 |
 // MD-INDEX: | BlueUserSpecified | 67 |
@@ -430,5 +447,5 @@ enum ColorUserSpecified {
 // HTML-INDEX-NEXT:             </tr>
 // HTML-INDEX-NEXT:         </tbody>
 // HTML-INDEX-NEXT:     </table>
-// HTML-INDEX-NEXT:     <p>Defined at line [[@LINE-36]] of file 
{{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
+// HTML-INDEX-NEXT:     <p>Defined at line [[@LINE-37]] of file 
{{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
 // HTML-INDEX-NEXT:   </div>
diff --git a/clang-tools-extra/unittests/clang-doc/MDGeneratorTest.cpp 
b/clang-tools-extra/unittests/clang-doc/MDGeneratorTest.cpp
index b44b09b28e90f..d9f32f8eabc41 100644
--- a/clang-tools-extra/unittests/clang-doc/MDGeneratorTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/MDGeneratorTest.cpp
@@ -69,9 +69,7 @@ TEST_F(MDGeneratorTest, emitNamespaceMD) {
 
 | enum OneEnum |
 
---
-
-
+| Name | Value |
 
 
 
@@ -136,9 +134,7 @@ ChildStruct
 
 | enum OneEnum |
 
---
-
-
+| Name | Value |
 
 
 
@@ -197,9 +193,9 @@ TEST_F(MDGeneratorTest, emitEnumMD) {
   assert(!Err);
   std::string Expected = R"raw(| enum class e |
 
---
-
-| X |
+| Name | Value |
+|:-:|:-:|
+| X | 0 |
 
 
 *Defined at test.cpp#10*

>From 9980251ef58bc63792bcb23b59e4a3fc0403b071 Mon Sep 17 00:00:00 2001
From: Samrudh Nelli <[email protected]>
Date: Mon, 2 Mar 2026 17:19:15 +0530
Subject: [PATCH 04/10] format the code

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

diff --git a/clang-tools-extra/clang-doc/MDGenerator.cpp 
b/clang-tools-extra/clang-doc/MDGenerator.cpp
index 53605850b7a47..c410be0b1769b 100644
--- a/clang-tools-extra/clang-doc/MDGenerator.cpp
+++ b/clang-tools-extra/clang-doc/MDGenerator.cpp
@@ -82,7 +82,7 @@ static std::string genRawText(const std::vector<CommentInfo> 
&Comments) {
     {
       if (!First)
         OS << "<br>";
-      else 
+      else
         First = false;
       OS << Comment->Text;
     }

>From 87cb5c17c728906b67d86bc0557a7f974daf9960 Mon Sep 17 00:00:00 2001
From: Samrudh Nelli <[email protected]>
Date: Mon, 2 Mar 2026 17:28:00 +0530
Subject: [PATCH 05/10] clang-format the code

---
 clang-tools-extra/clang-doc/MDGenerator.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/clang-tools-extra/clang-doc/MDGenerator.cpp 
b/clang-tools-extra/clang-doc/MDGenerator.cpp
index c410be0b1769b..e6b67fdec81e3 100644
--- a/clang-tools-extra/clang-doc/MDGenerator.cpp
+++ b/clang-tools-extra/clang-doc/MDGenerator.cpp
@@ -78,8 +78,7 @@ static std::string genRawText(const std::vector<CommentInfo> 
&Comments) {
   while (Q.size()) {
     Comment = Q.front();
     Q.pop();
-    if (!Comment->Text.empty())
-    {
+    if (!Comment->Text.empty()) {
       if (!First)
         OS << "<br>";
       else
@@ -212,7 +211,8 @@ static void genMarkdown(const ClangDocContext &CDCtx, const 
EnumInfo &I,
       if (!N.Value.empty())
         Members << "| " << N.Value << " ";
       if (HasComments) {
-        std::string RawComment = 
StringRef(genRawText(N.Description)).trim().str();
+        std::string RawComment =
+            StringRef(genRawText(N.Description)).trim().str();
         Members << "| " << (RawComment.empty() ? "--" : RawComment) << " ";
       }
       Members << "|\n";

>From 96a9e19a3593acd7c385332a1677807dde0cc1da Mon Sep 17 00:00:00 2001
From: Samrudh Nelli <[email protected]>
Date: Wed, 4 Mar 2026 19:37:22 +0530
Subject: [PATCH 06/10] Switch to a recursive solution to handle paragraphs

---
 clang-tools-extra/clang-doc/MDGenerator.cpp | 63 +++++++++++++--------
 clang-tools-extra/test/clang-doc/enum.cpp   |  2 +-
 2 files changed, 41 insertions(+), 24 deletions(-)

diff --git a/clang-tools-extra/clang-doc/MDGenerator.cpp 
b/clang-tools-extra/clang-doc/MDGenerator.cpp
index e6b67fdec81e3..bec44a88944bb 100644
--- a/clang-tools-extra/clang-doc/MDGenerator.cpp
+++ b/clang-tools-extra/clang-doc/MDGenerator.cpp
@@ -8,7 +8,9 @@
 
 #include "Generators.h"
 #include "Representation.h"
+#include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/FormatVariadic.h"
 #include "llvm/Support/Path.h"
@@ -67,28 +69,42 @@ static void writeSourceFileRef(const ClangDocContext 
&CDCtx, const Location &L,
   OS << "\n\n";
 }
 
-static std::string genRawText(const std::vector<CommentInfo> &Comments) {
-  std::string Result;
-  llvm::raw_string_ostream OS(Result);
-  std::queue<const CommentInfo *> Q;
-  for (const auto &CI : Comments)
-    Q.push(&CI);
-  const CommentInfo *Comment;
-  bool First = true;
-  while (Q.size()) {
-    Comment = Q.front();
-    Q.pop();
-    if (!Comment->Text.empty()) {
-      if (!First)
-        OS << "<br>";
-      else
-        First = false;
-      OS << Comment->Text;
+static void extractChildComment(const CommentInfo &Comment,
+                                llvm::raw_ostream &OS, bool &FirstLine,
+                                bool &FirstParagraph, bool &ParagraphBreak) {
+  if (Comment.Kind == CommentKind::CK_ParagraphComment) {
+    if (!FirstParagraph)
+      ParagraphBreak = true;
+  }
+
+  if (!Comment.Text.empty()) {
+    if (FirstParagraph)
+      FirstParagraph = false;
+    if (ParagraphBreak) {
+      OS << "<br><br>";
+      ParagraphBreak = false;
+      FirstLine = true;
     }
-    for (const auto &CI : Comment->Children)
-      Q.push(CI.get());
+
+    if (!FirstLine)
+      OS << "<br>";
+    else
+      FirstLine = false;
+
+    OS << Comment.Text;
   }
-  return Result;
+
+  for (const auto &Child : Comment.Children)
+    extractChildComment(*Child, OS, FirstLine, FirstParagraph, ParagraphBreak);
+}
+
+static void genCommentString(ArrayRef<CommentInfo> Comments,
+                             std::string &Buffer) {
+  llvm::raw_string_ostream OS(Buffer);
+  bool FirstLine = true, FirstParagraph = true, ParagraphBreak = false;
+
+  for (const auto &Child : Comments)
+    extractChildComment(Child, OS, FirstLine, FirstParagraph, ParagraphBreak);
 }
 
 static void maybeWriteSourceFileRef(llvm::raw_ostream &OS,
@@ -211,9 +227,10 @@ static void genMarkdown(const ClangDocContext &CDCtx, 
const EnumInfo &I,
       if (!N.Value.empty())
         Members << "| " << N.Value << " ";
       if (HasComments) {
-        std::string RawComment =
-            StringRef(genRawText(N.Description)).trim().str();
-        Members << "| " << (RawComment.empty() ? "--" : RawComment) << " ";
+        std::string CommentString;
+        genCommentString(ArrayRef(N.Description), CommentString);
+        Members << "| " << (CommentString.empty() ? "--" : CommentString)
+                << " ";
       }
       Members << "|\n";
     }
diff --git a/clang-tools-extra/test/clang-doc/enum.cpp 
b/clang-tools-extra/test/clang-doc/enum.cpp
index d0a308c2d055f..6cb7c3fcdbdc5 100644
--- a/clang-tools-extra/test/clang-doc/enum.cpp
+++ b/clang-tools-extra/test/clang-doc/enum.cpp
@@ -151,7 +151,7 @@ enum Size : uint8_t {
 // MD-INDEX: | enum Size : uint8_t |
 // MD-INDEX: | Name | Value | Comments |
 // MD-INDEX: |:-:|:-:|:-:|
-// MD-INDEX: | Small | 0 | A pearl.<br> Pearls are quite small.<br> Pearls are 
used in jewelry. |
+// MD-INDEX: | Small | 0 | A pearl.<br> Pearls are quite small.<br><br> Pearls 
are used in jewelry. |
 // MD-INDEX: | Medium | 1 | A tennis ball. |
 // MD-INDEX: | Large | 2 | A football. |
 // MD-INDEX: **brief** Specify the size

>From fdae5455175fd2952b68afa22283234fe42259b2 Mon Sep 17 00:00:00 2001
From: Samrudh Nelli <[email protected]>
Date: Wed, 4 Mar 2026 19:47:30 +0530
Subject: [PATCH 07/10] remove unused header file

---
 clang-tools-extra/clang-doc/MDGenerator.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/clang-tools-extra/clang-doc/MDGenerator.cpp 
b/clang-tools-extra/clang-doc/MDGenerator.cpp
index bec44a88944bb..ebbeda08dad28 100644
--- a/clang-tools-extra/clang-doc/MDGenerator.cpp
+++ b/clang-tools-extra/clang-doc/MDGenerator.cpp
@@ -10,7 +10,6 @@
 #include "Representation.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/StringRef.h"
-#include "llvm/Support/Error.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/FormatVariadic.h"
 #include "llvm/Support/Path.h"

>From ed2830985d476d38dcfdf1c7f9d499a12aead6fd Mon Sep 17 00:00:00 2001
From: Samrudh Nelli <[email protected]>
Date: Fri, 6 Mar 2026 03:47:14 +0530
Subject: [PATCH 08/10] implement paragraph breaks without using boolean flags

---
 clang-tools-extra/clang-doc/MDGenerator.cpp | 68 +++++++++++----------
 1 file changed, 36 insertions(+), 32 deletions(-)

diff --git a/clang-tools-extra/clang-doc/MDGenerator.cpp 
b/clang-tools-extra/clang-doc/MDGenerator.cpp
index ebbeda08dad28..3629307350a41 100644
--- a/clang-tools-extra/clang-doc/MDGenerator.cpp
+++ b/clang-tools-extra/clang-doc/MDGenerator.cpp
@@ -68,42 +68,47 @@ static void writeSourceFileRef(const ClangDocContext 
&CDCtx, const Location &L,
   OS << "\n\n";
 }
 
-static void extractChildComment(const CommentInfo &Comment,
-                                llvm::raw_ostream &OS, bool &FirstLine,
-                                bool &FirstParagraph, bool &ParagraphBreak) {
-  if (Comment.Kind == CommentKind::CK_ParagraphComment) {
-    if (!FirstParagraph)
-      ParagraphBreak = true;
-  }
+static std::string extractCommentText(const CommentInfo &Comment) {
+  std::vector<std::string> Parts;
+
+  if (!Comment.Text.empty())
+    Parts.push_back(StringRef(Comment.Text).str());
+
+  for (size_t Idx = 0; Idx < Comment.Children.size(); ++Idx) {
+    const auto &Child = Comment.Children[Idx];
+    std::string ChildText = extractCommentText(*Child);
 
-  if (!Comment.Text.empty()) {
-    if (FirstParagraph)
-      FirstParagraph = false;
-    if (ParagraphBreak) {
-      OS << "<br><br>";
-      ParagraphBreak = false;
-      FirstLine = true;
+    if (ChildText.empty())
+      continue;
+
+    if (Idx > 0 && Comment.Kind == CommentKind::CK_ParagraphComment) {
+      if (Comment.Children[Idx - 1]->Kind == CommentKind::CK_TextComment &&
+          Child->Kind == CommentKind::CK_TextComment) {
+        Parts.push_back("<br>");
+      }
     }
 
-    if (!FirstLine)
-      OS << "<br>";
-    else
-      FirstLine = false;
+    Parts.push_back(ChildText);
+  }
 
-    OS << Comment.Text;
+  if (Comment.Kind == CommentKind::CK_BlockCommandComment ||
+      Comment.Kind == CommentKind::CK_FullComment) {
+    return llvm::join(Parts, "<br><br>");
   }
 
-  for (const auto &Child : Comment.Children)
-    extractChildComment(*Child, OS, FirstLine, FirstParagraph, ParagraphBreak);
+  return llvm::join(Parts, "");
 }
 
-static void genCommentString(ArrayRef<CommentInfo> Comments,
-                             std::string &Buffer) {
-  llvm::raw_string_ostream OS(Buffer);
-  bool FirstLine = true, FirstParagraph = true, ParagraphBreak = false;
-
-  for (const auto &Child : Comments)
-    extractChildComment(Child, OS, FirstLine, FirstParagraph, ParagraphBreak);
+static void genCommentString(llvm::ArrayRef<CommentInfo> Comments,
+                             llvm::raw_ostream &OS) {
+  std::string CommentText = "";
+  for (const auto &Child : Comments) {
+    CommentText += extractCommentText(Child);
+  }
+  if (!CommentText.empty())
+    OS << CommentText;
+  else
+    OS << "--";
 }
 
 static void maybeWriteSourceFileRef(llvm::raw_ostream &OS,
@@ -226,10 +231,9 @@ static void genMarkdown(const ClangDocContext &CDCtx, 
const EnumInfo &I,
       if (!N.Value.empty())
         Members << "| " << N.Value << " ";
       if (HasComments) {
-        std::string CommentString;
-        genCommentString(ArrayRef(N.Description), CommentString);
-        Members << "| " << (CommentString.empty() ? "--" : CommentString)
-                << " ";
+        Members << "| ";
+        genCommentString(ArrayRef(N.Description), Members);
+        Members << " ";
       }
       Members << "|\n";
     }

>From 4468b4bcb897e79ce8ad83461676b41ddecf0d0d Mon Sep 17 00:00:00 2001
From: Samrudh Nelli <[email protected]>
Date: Fri, 6 Mar 2026 22:11:41 +0530
Subject: [PATCH 09/10] use streams rather than vector of strings

---
 clang-tools-extra/clang-doc/MDGenerator.cpp | 49 ++++++++++-----------
 1 file changed, 24 insertions(+), 25 deletions(-)

diff --git a/clang-tools-extra/clang-doc/MDGenerator.cpp 
b/clang-tools-extra/clang-doc/MDGenerator.cpp
index 3629307350a41..e0b05cd5f5d5b 100644
--- a/clang-tools-extra/clang-doc/MDGenerator.cpp
+++ b/clang-tools-extra/clang-doc/MDGenerator.cpp
@@ -9,11 +9,13 @@
 #include "Generators.h"
 #include "Representation.h"
 #include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/FormatVariadic.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Support/raw_ostream.h"
+#include <cstdint>
 #include <string>
 
 using namespace llvm;
@@ -68,46 +70,43 @@ static void writeSourceFileRef(const ClangDocContext 
&CDCtx, const Location &L,
   OS << "\n\n";
 }
 
-static std::string extractCommentText(const CommentInfo &Comment) {
-  std::vector<std::string> Parts;
+static void extractCommentText(const CommentInfo &Comment,
+                               llvm::raw_ostream &OS) {
 
-  if (!Comment.Text.empty())
-    Parts.push_back(StringRef(Comment.Text).str());
+  OS << Comment.Text;
+  bool FirstChild = true;
 
-  for (size_t Idx = 0; Idx < Comment.Children.size(); ++Idx) {
+  for (size_t Idx = 0, End = Comment.Children.size(); Idx < End; ++Idx) {
     const auto &Child = Comment.Children[Idx];
-    std::string ChildText = extractCommentText(*Child);
+    llvm::SmallString<128> ChildBuffer;
+    llvm::raw_svector_ostream ChildOS(ChildBuffer);
+    extractCommentText(*Child, ChildOS);
 
-    if (ChildText.empty())
+    if (ChildBuffer.empty())
       continue;
 
-    if (Idx > 0 && Comment.Kind == CommentKind::CK_ParagraphComment) {
-      if (Comment.Children[Idx - 1]->Kind == CommentKind::CK_TextComment &&
-          Child->Kind == CommentKind::CK_TextComment) {
-        Parts.push_back("<br>");
-      }
-    }
+    if (Idx > 0 && Comment.Kind == CommentKind::CK_ParagraphComment &&
+        Comment.Children[Idx - 1]->Kind == CommentKind::CK_TextComment &&
+        Child->Kind == CommentKind::CK_TextComment)
+      OS << "<br>";
 
-    Parts.push_back(ChildText);
-  }
+    if (FirstChild)
+      FirstChild = false;
+    else if (Comment.Kind == CommentKind::CK_BlockCommandComment ||
+             Comment.Kind == CommentKind::CK_FullComment)
+      OS << "<br><br>";
 
-  if (Comment.Kind == CommentKind::CK_BlockCommandComment ||
-      Comment.Kind == CommentKind::CK_FullComment) {
-    return llvm::join(Parts, "<br><br>");
+    OS << ChildBuffer;
   }
-
-  return llvm::join(Parts, "");
 }
 
 static void genCommentString(llvm::ArrayRef<CommentInfo> Comments,
                              llvm::raw_ostream &OS) {
-  std::string CommentText = "";
+  uint64_t InitPos = OS.tell();
   for (const auto &Child : Comments) {
-    CommentText += extractCommentText(Child);
+    extractCommentText(Child, OS);
   }
-  if (!CommentText.empty())
-    OS << CommentText;
-  else
+  if (InitPos == OS.tell())
     OS << "--";
 }
 

>From 7de7e01db6377b616370a65234f4347f14091f90 Mon Sep 17 00:00:00 2001
From: Samrudh Nelli <[email protected]>
Date: Sat, 7 Mar 2026 18:28:02 +0530
Subject: [PATCH 10/10] use an efficient logic for formatting comments

A big thanks to @ilovepi for the code and approach.
Also revert to left-padding the table content.
---
 clang-tools-extra/clang-doc/MDGenerator.cpp   | 104 ++++++++++--------
 clang-tools-extra/test/clang-doc/enum.cpp     |  16 +--
 .../unittests/clang-doc/MDGeneratorTest.cpp   |   5 +-
 3 files changed, 68 insertions(+), 57 deletions(-)

diff --git a/clang-tools-extra/clang-doc/MDGenerator.cpp 
b/clang-tools-extra/clang-doc/MDGenerator.cpp
index e0b05cd5f5d5b..4a9f159659b25 100644
--- a/clang-tools-extra/clang-doc/MDGenerator.cpp
+++ b/clang-tools-extra/clang-doc/MDGenerator.cpp
@@ -15,7 +15,6 @@
 #include "llvm/Support/FormatVariadic.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Support/raw_ostream.h"
-#include <cstdint>
 #include <string>
 
 using namespace llvm;
@@ -70,43 +69,60 @@ static void writeSourceFileRef(const ClangDocContext 
&CDCtx, const Location &L,
   OS << "\n\n";
 }
 
-static void extractCommentText(const CommentInfo &Comment,
-                               llvm::raw_ostream &OS) {
+struct CommentState {
+  bool Started = false;
+  bool NeedsParagraphBreak = false;
 
-  OS << Comment.Text;
-  bool FirstChild = true;
-
-  for (size_t Idx = 0, End = Comment.Children.size(); Idx < End; ++Idx) {
-    const auto &Child = Comment.Children[Idx];
-    llvm::SmallString<128> ChildBuffer;
-    llvm::raw_svector_ostream ChildOS(ChildBuffer);
-    extractCommentText(*Child, ChildOS);
+  void insertSeparator(llvm::raw_ostream &OS) {
+    if (!Started)
+      return;
+    if (NeedsParagraphBreak) {
+      OS << "<br><br>";
+      NeedsParagraphBreak = false;
+    } else {
+      OS << "<br>";
+    }
+  }
+};
 
-    if (ChildBuffer.empty())
-      continue;
+static void writeTableSafeComment(const CommentInfo &I, llvm::raw_ostream &OS,
+                                  CommentState &State) {
+  switch (I.Kind) {
+  case CommentKind::CK_FullComment:
+    for (const auto &Child : I.Children)
+      writeTableSafeComment(*Child, OS, State);
+    break;
 
-    if (Idx > 0 && Comment.Kind == CommentKind::CK_ParagraphComment &&
-        Comment.Children[Idx - 1]->Kind == CommentKind::CK_TextComment &&
-        Child->Kind == CommentKind::CK_TextComment)
-      OS << "<br>";
+  case CommentKind::CK_ParagraphComment:
+    for (const auto &Child : I.Children)
+      writeTableSafeComment(*Child, OS, State);
+    State.NeedsParagraphBreak =
+        true; // Next content after a paragraph needs a break
+    break;
 
-    if (FirstChild)
-      FirstChild = false;
-    else if (Comment.Kind == CommentKind::CK_BlockCommandComment ||
-             Comment.Kind == CommentKind::CK_FullComment)
-      OS << "<br><br>";
+  case CommentKind::CK_TextComment:
+    if (!I.Text.empty()) {
+      State.insertSeparator(OS);
+      OS << I.Text;
+      State.Started = true;
+    }
+    break;
 
-    OS << ChildBuffer;
+  // Handle other comment types (BlockCommand, InlineCommand, etc.)
+  default:
+    for (const auto &Child : I.Children)
+      writeTableSafeComment(*Child, OS, State);
+    break;
   }
 }
 
-static void genCommentString(llvm::ArrayRef<CommentInfo> Comments,
-                             llvm::raw_ostream &OS) {
-  uint64_t InitPos = OS.tell();
-  for (const auto &Child : Comments) {
-    extractCommentText(Child, OS);
-  }
-  if (InitPos == OS.tell())
+static void genMDComment(llvm::ArrayRef<CommentInfo> Comments,
+                         llvm::raw_ostream &OS) {
+  CommentState State;
+  for (const auto &C : Comments)
+    writeTableSafeComment(C, OS, State);
+
+  if (!State.Started)
     OS << "--";
 }
 
@@ -208,36 +224,34 @@ static void genMarkdown(const ClangDocContext &CDCtx, 
const EnumInfo &I,
   }
   OS << "|\n\n";
 
-  std::string Buffer;
-  llvm::raw_string_ostream Members(Buffer);
-  Members << "| Name | Value |";
+  OS << "| Name | Value |";
   if (!I.Members.empty()) {
     bool HasComments = false;
     for (const auto &Member : I.Members) {
       if (!Member.Description.empty()) {
         HasComments = true;
-        Members << " Comments |";
+        OS << " Comments |";
         break;
       }
     }
-    Members << "\n";
-    Members << "|:-:|:-:|";
+    OS << "\n";
+    OS << "|---|---|";
     if (HasComments)
-      Members << ":-:|";
-    Members << "\n";
+      OS << "---|";
+    OS << "\n";
     for (const auto &N : I.Members) {
-      Members << "| " << N.Name << " ";
+      OS << "| " << N.Name << " ";
       if (!N.Value.empty())
-        Members << "| " << N.Value << " ";
+        OS << "| " << N.Value << " ";
       if (HasComments) {
-        Members << "| ";
-        genCommentString(ArrayRef(N.Description), Members);
-        Members << " ";
+        OS << "| ";
+        genMDComment(ArrayRef(N.Description), OS);
+        OS << " ";
       }
-      Members << "|\n";
+      OS << "|\n";
     }
   }
-  writeLine(Members.str(), OS);
+  OS << "\n";
 
   maybeWriteSourceFileRef(OS, CDCtx, I.DefLoc);
 
diff --git a/clang-tools-extra/test/clang-doc/enum.cpp 
b/clang-tools-extra/test/clang-doc/enum.cpp
index 6cb7c3fcdbdc5..5168afc7c74b0 100644
--- a/clang-tools-extra/test/clang-doc/enum.cpp
+++ b/clang-tools-extra/test/clang-doc/enum.cpp
@@ -34,7 +34,7 @@ enum Color {
 // MD-INDEX: ## Enums
 // MD-INDEX: | enum Color |
 // MD-INDEX: | Name | Value | Comments |
-// MD-INDEX: |:-:|:-:|:-:|
+// MD-INDEX: |---|---|---|
 // MD-INDEX: | Red | 0 | Comment 1 |
 // MD-INDEX: | Green | 1 | Comment 2 |
 // MD-INDEX: | Blue | 2 | Comment 3 |
@@ -89,7 +89,7 @@ enum class Shapes {
 
 // MD-INDEX: | enum class Shapes |
 // MD-INDEX: | Name | Value | Comments |
-// MD-INDEX: |:-:|:-:|:-:|
+// MD-INDEX: |---|---|---|
 // MD-INDEX: | Circle | 0 | Comment 1 |
 // MD-INDEX: | Rectangle | 1 | Comment 2 |
 // MD-INDEX: | Triangle | 2 | Comment 3 |
@@ -150,7 +150,7 @@ enum Size : uint8_t {
 
 // MD-INDEX: | enum Size : uint8_t |
 // MD-INDEX: | Name | Value | Comments |
-// MD-INDEX: |:-:|:-:|:-:|
+// MD-INDEX: |---|---|---|
 // MD-INDEX: | Small | 0 | A pearl.<br> Pearls are quite small.<br><br> Pearls 
are used in jewelry. |
 // MD-INDEX: | Medium | 1 | A tennis ball. |
 // MD-INDEX: | Large | 2 | A football. |
@@ -199,7 +199,7 @@ enum : long long {
 
 // MD-INDEX: | enum (unnamed) : long long |
 // MD-INDEX: | Name | Value | Comments |
-// MD-INDEX: |:-:|:-:|:-:|
+// MD-INDEX: |---|---|---|
 // MD-INDEX: | BigVal | 999999999999 | A very large value |
 // MD-INDEX: **brief** Very long number
 
@@ -245,7 +245,7 @@ class FilePermissions {
 
 // MD-PERM: | enum (unnamed) |
 // MD-PERM: | Name | Value | Comments |
-// MD-PERM: |:-:|:-:|:-:|
+// MD-PERM: |---|---|---|
 // MD-PERM: | Read | 1 | Permission to READ r |
 // MD-PERM: | Write | 2 | Permission to WRITE w |
 // MD-PERM: | Execute | 4 | Permission to EXECUTE x |
@@ -342,7 +342,7 @@ class Animals {
 // MD-ANIMAL: ## Enums
 // MD-ANIMAL: | enum AnimalType |
 // MD-ANIMAL: | Name | Value | Comments |
-// MD-ANIMAL: |:-:|:-:|:-:|
+// MD-ANIMAL: |---|---|---|
 // MD-ANIMAL: | Dog | 0 | Man's best friend |
 // MD-ANIMAL: | Cat | 1 | Man's other best friend |
 // MD-ANIMAL: | Iguana | 2 | A lizard |
@@ -367,7 +367,7 @@ enum Car {
 // MD-VEHICLES: ## Enums
 // MD-VEHICLES: | enum Car |
 // MD-VEHICLES: | Name | Value | Comments |
-// MD-VEHICLES: |:-:|:-:|:-:|
+// MD-VEHICLES: |---|---|---|
 // MD-VEHICLES: | Sedan | 0 | Comment 1 |
 // MD-VEHICLES: | SUV | 1 | Comment 2 |
 // MD-VEHICLES: | Pickup | 2 | Comment 3 |
@@ -418,7 +418,7 @@ enum ColorUserSpecified {
 
 // MD-INDEX: | enum ColorUserSpecified |
 // MD-INDEX: | Name | Value |
-// MD-INDEX: |:-:|:-:|
+// MD-INDEX: |---|---|
 // MD-INDEX: | RedUserSpecified | 65 |
 // MD-INDEX: | GreenUserSpecified | 2 |
 // MD-INDEX: | BlueUserSpecified | 67 |
diff --git a/clang-tools-extra/unittests/clang-doc/MDGeneratorTest.cpp 
b/clang-tools-extra/unittests/clang-doc/MDGeneratorTest.cpp
index d9f32f8eabc41..53d8b8444b3ad 100644
--- a/clang-tools-extra/unittests/clang-doc/MDGeneratorTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/MDGeneratorTest.cpp
@@ -72,7 +72,6 @@ TEST_F(MDGeneratorTest, emitNamespaceMD) {
 | Name | Value |
 
 
-
 )raw";
   EXPECT_EQ(Expected, Actual.str());
 }
@@ -137,7 +136,6 @@ ChildStruct
 | Name | Value |
 
 
-
 )raw";
   EXPECT_EQ(Expected, Actual.str());
 }
@@ -194,10 +192,9 @@ TEST_F(MDGeneratorTest, emitEnumMD) {
   std::string Expected = R"raw(| enum class e |
 
 | Name | Value |
-|:-:|:-:|
+|---|---|
 | X | 0 |
 
-
 *Defined at test.cpp#10*
 
 )raw";

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to