Author: Samrudh Nelli
Date: 2026-03-11T10:50:22-07:00
New Revision: a60fc292361a97b4957dc17173cdec79510affc2

URL: 
https://github.com/llvm/llvm-project/commit/a60fc292361a97b4957dc17173cdec79510affc2
DIFF: 
https://github.com/llvm/llvm-project/commit/a60fc292361a97b4957dc17173cdec79510affc2.diff

LOG: [Clang-doc] Display values and comments in MD (#183754)

Display enum members in a tabular format in markdown.
Support displaying enum member value and comments.
Output:
| Name | Value | Comments |
|---|---|---|
| Small | 0 | A pearl.<br>Pearls are quite small.<br><br>Pearls are used
in jewelry. |
| Medium | 1 | A tennis ball. |
| Large | 2 | A football. |

Added: 
    

Modified: 
    clang-tools-extra/clang-doc/MDGenerator.cpp
    clang-tools-extra/test/clang-doc/enum.cpp
    clang-tools-extra/unittests/clang-doc/MDGeneratorTest.cpp

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/clang-doc/MDGenerator.cpp 
b/clang-tools-extra/clang-doc/MDGenerator.cpp
index 60a880d211884..5fcd6da0492ca 100644
--- a/clang-tools-extra/clang-doc/MDGenerator.cpp
+++ b/clang-tools-extra/clang-doc/MDGenerator.cpp
@@ -8,6 +8,7 @@
 
 #include "Generators.h"
 #include "Representation.h"
+#include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/FormatVariadic.h"
@@ -67,6 +68,80 @@ static void writeSourceFileRef(const ClangDocContext &CDCtx, 
const Location &L,
   OS << "\n\n";
 }
 
+/// Writer for writing comments to a table cell in MD.
+///
+/// The writer traverses the comments recursively and outputs the
+/// comments into a stream.
+/// The formatter inserts single/double line breaks to retain the comment
+/// structure.
+///
+/// Usage :
+/// Initialize an object with a llvm::raw_ostream to output into.
+/// Call the write(C) function with an array of Comments 'C'.
+class TableCommentWriter {
+public:
+  explicit TableCommentWriter(llvm::raw_ostream &OS) : OS(OS) {}
+
+  void write(llvm::ArrayRef<CommentInfo> Comments) {
+    for (const auto &C : Comments)
+      writeTableSafeComment(C);
+
+    if (!Started)
+      OS << "--";
+  }
+
+private:
+  /// This function inserts breaks into the stream.
+  ///
+  /// We add a double break in between paragraphs.
+  /// Inside a paragraph, a single break between lines is maintained.
+  void insertSeparator() {
+    if (!Started)
+      return;
+    if (NeedsParagraphBreak) {
+      OS << "<br><br>";
+      NeedsParagraphBreak = false;
+    } else {
+      OS << "<br>";
+    }
+  }
+
+  /// This function processes every comment and its children recursively.
+  void writeTableSafeComment(const CommentInfo &I) {
+    switch (I.Kind) {
+    case CommentKind::CK_FullComment:
+      for (const auto &Child : I.Children)
+        writeTableSafeComment(*Child);
+      break;
+
+    case CommentKind::CK_ParagraphComment:
+      for (const auto &Child : I.Children)
+        writeTableSafeComment(*Child);
+      // Next content after a paragraph needs a break
+      NeedsParagraphBreak = true;
+      break;
+
+    case CommentKind::CK_TextComment:
+      if (!I.Text.empty()) {
+        insertSeparator();
+        OS << I.Text;
+        Started = true;
+      }
+      break;
+
+    // Handle other comment types (BlockCommand, InlineCommand, etc.)
+    default:
+      for (const auto &Child : I.Children)
+        writeTableSafeComment(*Child);
+      break;
+    }
+  }
+
+  llvm::raw_ostream &OS;
+  bool Started = false;
+  bool NeedsParagraphBreak = false;
+};
+
 static void maybeWriteSourceFileRef(llvm::raw_ostream &OS,
                                     const ClangDocContext &CDCtx,
                                     const std::optional<Location> &DefLoc) {
@@ -163,14 +238,36 @@ static void genMarkdown(const ClangDocContext &CDCtx, 
const EnumInfo &I,
   if (I.BaseType && !I.BaseType->Type.QualName.empty()) {
     OS << ": " << I.BaseType->Type.QualName << " ";
   }
-  OS << "|\n\n" << "--\n\n";
+  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";
-  writeLine(Members.str(), OS);
+  OS << "| Name | Value |";
+  if (!I.Members.empty()) {
+    bool HasComments = false;
+    for (const auto &Member : I.Members) {
+      if (!Member.Description.empty()) {
+        HasComments = true;
+        OS << " Comments |";
+        break;
+      }
+    }
+    OS << "\n|---|---|";
+    if (HasComments)
+      OS << "---|";
+    OS << "\n";
+    for (const auto &N : I.Members) {
+      OS << "| " << N.Name << " ";
+      if (!N.Value.empty())
+        OS << "| " << N.Value << " ";
+      if (HasComments) {
+        OS << "| ";
+        TableCommentWriter CommentWriter(OS);
+        CommentWriter.write(N.Description);
+        OS << " ";
+      }
+      OS << "|\n";
+    }
+  }
+  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 eec2bcb9f82e6..6d54dcf8bf657 100644
--- a/clang-tools-extra/test/clang-doc/enum.cpp
+++ b/clang-tools-extra/test/clang-doc/enum.cpp
@@ -41,10 +41,11 @@ enum Color {
 
 // MD-INDEX: ## Enums
 // MD-INDEX: | enum Color |
-// MD-INDEX: --
-// MD-INDEX: | Red |
-// MD-INDEX: | Green |
-// MD-INDEX: | Blue |
+// 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 |
 // MD-INDEX: **brief** For specifying RGB colors
 
 // HTML-INDEX-LABEL:  <div id="{{([0-9A-F]{40})}}" class="delimiter-container">
@@ -92,7 +93,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-62]] of file 
{{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
+// HTML-INDEX-NEXT:     <p>Defined at line [[@LINE-63]] of file 
{{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
 // HTML-INDEX-NEXT:   </div>
 
 // MD-MUSTACHE-INDEX: ## Enums
@@ -118,11 +119,13 @@ enum class Shapes {
   /// Comment 3
   Triangle
 };
+
 // MD-INDEX: | enum class Shapes |
-// MD-INDEX: --
-// MD-INDEX: | Circle |
-// MD-INDEX: | Rectangle |
-// MD-INDEX: | Triangle |
+// 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 |
 // MD-INDEX: **brief** Shape Types
 
 // HTML-INDEX-LABEL:  <div id="{{([0-9A-F]{40})}}" class="delimiter-container">
@@ -170,7 +173,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-64]] of file 
{{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
+// HTML-INDEX-NEXT:     <p>Defined at line [[@LINE-66]] of file 
{{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
 // HTML-INDEX-NEXT:   </div>
 
 typedef unsigned char uint8_t;
@@ -195,10 +198,11 @@ enum Size : uint8_t {
 };
 
 // MD-INDEX: | enum Size : uint8_t |
-// MD-INDEX: --
-// MD-INDEX: | Small |
-// MD-INDEX: | Medium |
-// MD-INDEX: | Large |
+// MD-INDEX: | Name | Value | Comments |
+// 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. |
 // MD-INDEX: **brief** Specify the size
 
 // HTML-INDEX-LABEL:   <div id="{{([0-9A-F]{40})}}" 
class="delimiter-container">
@@ -248,7 +252,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-71]] of file 
{{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
+// HTML-INDEX-NEXT:     <p>Defined at line [[@LINE-72]] of file 
{{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
 // HTML-INDEX-NEXT:   </div>
 
 /**
@@ -261,8 +265,9 @@ enum : long long {
 };
 
 // MD-INDEX: | enum (unnamed) : long long |
-// MD-INDEX: --
-// MD-INDEX: | BigVal |
+// MD-INDEX: | Name | Value | Comments |
+// 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">
@@ -292,7 +297,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-38]] of file 
{{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
+// HTML-INDEX-NEXT:     <p>Defined at line [[@LINE-39]] of file 
{{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
 // HTML-INDEX-NEXT:   </div>
 
 class FilePermissions {
@@ -312,10 +317,11 @@ class FilePermissions {
 };
 
 // MD-PERM: | enum (unnamed) |
-// MD-PERM: --
-// MD-PERM: | Read |
-// MD-PERM: | Write |
-// MD-PERM: | Execute |
+// 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 |
 // MD-PERM: **brief** File permission flags
 
 // HTML-PERM-LABEL:  <section id="Enums" class="section-container">
@@ -365,7 +371,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-63]] of file 
{{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
+// HTML-PERM-NEXT:         <p>Defined at line [[@LINE-64]] of file 
{{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
 // HTML-PERM-NEXT:     </div>
 // HTML-PERM-NEXT:   </section>
 
@@ -442,10 +448,11 @@ class Animals {
 // MD-ANIMAL: # class Animals
 // MD-ANIMAL: ## Enums
 // MD-ANIMAL: | enum AnimalType |
-// MD-ANIMAL: --
-// MD-ANIMAL: | Dog |
-// MD-ANIMAL: | Cat |
-// MD-ANIMAL: | Iguana |
+// 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 |
 // MD-ANIMAL: **brief** specify what animal the class is
 
 // MD-MUSTACHE-ANIMAL: # class Animals
@@ -476,11 +483,12 @@ enum Car {
 // MD-VEHICLES: # namespace Vehicles
 // MD-VEHICLES: ## Enums
 // MD-VEHICLES: | enum Car |
-// MD-VEHICLES: --
-// MD-VEHICLES: | Sedan |
-// MD-VEHICLES: | SUV |
-// MD-VEHICLES: | Pickup |
-// MD-VEHICLES: | Hatchback |
+// MD-VEHICLES: | Name | Value | Comments |
+// MD-VEHICLES: |---|---|---|
+// MD-VEHICLES: | Sedan | 0 | Comment 1 |
+// MD-VEHICLES: | SUV | 1 | Comment 2 |
+// MD-VEHICLES: | Pickup | 2 | -- |
+// MD-VEHICLES: | Hatchback | 3 | Comment 4 |
 // MD-VEHICLES: **brief** specify type of car
 
 // HTML-VEHICLES-LABEL:   <div id="{{([0-9A-F]{40})}}" 
class="delimiter-container">
@@ -533,7 +541,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-72]] of file 
{{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
+// HTML-VEHICLES-NEXT:      <p>Defined at line [[@LINE-73]] of file 
{{.*}}clang-tools-extra{{[\/]}}test{{[\/]}}clang-doc{{[\/]}}enum.cpp</p>
 // HTML-VEHICLES-NEXT:    </div>
 
 // MD-MUSTACHE-VEHICLES: # namespace Vehicles
@@ -553,10 +561,11 @@ enum ColorUserSpecified {
 };
 
 // MD-INDEX: | enum ColorUserSpecified |
-// MD-INDEX: --
-// MD-INDEX: | RedUserSpecified |
-// MD-INDEX: | GreenUserSpecified |
-// MD-INDEX: | BlueUserSpecified |
+// MD-INDEX: | Name | Value |
+// MD-INDEX: |---|---|
+// MD-INDEX: | RedUserSpecified | 65 |
+// MD-INDEX: | GreenUserSpecified | 2 |
+// MD-INDEX: | BlueUserSpecified | 67 |
 
 // HTML-INDEX-LABEL:  <div id="{{([0-9A-F]{40})}}" class="delimiter-container">
 // HTML-INDEX-NEXT:     <div>
@@ -582,7 +591,7 @@ 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>
 
 // MD-MUSTACHE-INDEX: | enum ColorUserSpecified |

diff  --git a/clang-tools-extra/unittests/clang-doc/MDGeneratorTest.cpp 
b/clang-tools-extra/unittests/clang-doc/MDGeneratorTest.cpp
index da22d00835126..aec8a1bc288e4 100644
--- a/clang-tools-extra/unittests/clang-doc/MDGeneratorTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/MDGeneratorTest.cpp
@@ -69,10 +69,7 @@ TEST_F(MDGeneratorTest, emitNamespaceMD) {
 
 | enum OneEnum |
 
---
-
-
-
+| Name | Value |
 
 
 )raw";
@@ -136,10 +133,7 @@ ChildStruct
 
 | enum OneEnum |
 
---
-
-
-
+| Name | Value |
 
 
 )raw";
@@ -197,10 +191,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*
 


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

Reply via email to