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
