[clang-tools-extra] a60fc29 - [Clang-doc] Display values and comments in MD (#183754)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Mar 11 10:50:27 PDT 2026
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*
More information about the cfe-commits
mailing list