[clang-tools-extra] Refactor clang doc comment structure (PR #142273)

Samarth Narang via cfe-commits cfe-commits at lists.llvm.org
Sun Jun 1 16:04:10 PDT 2025


https://github.com/snarang181 updated https://github.com/llvm/llvm-project/pull/142273

>From cd99fbe06a384db3775d1fc8c923275df07d4db3 Mon Sep 17 00:00:00 2001
From: Samarth Narang <snarang at umass.edu>
Date: Sat, 31 May 2025 10:05:52 -0400
Subject: [PATCH 1/8] [clang-doc] Refactor CommentInfo.Kind to use CommentKind
 enum

This patch replaces the raw SmallString<16> `Kind` field in `CommentInfo`
with a strongly typed enum `CommentKind`. This improves type safety,
allows compiler-checked switch handling, and removes the reliance on
string comparisons across the clang-doc codebase.
---
 clang-tools-extra/clang-doc/BitcodeReader.cpp |  9 ++-
 clang-tools-extra/clang-doc/BitcodeWriter.cpp |  3 +-
 clang-tools-extra/clang-doc/HTMLGenerator.cpp | 74 ++++++++++---------
 .../clang-doc/HTMLMustacheGenerator.cpp       | 12 +--
 clang-tools-extra/clang-doc/MDGenerator.cpp   | 59 ++++++++++-----
 .../clang-doc/Representation.cpp              | 60 +++++++++++++++
 clang-tools-extra/clang-doc/Representation.h  | 33 +++++++--
 clang-tools-extra/clang-doc/Serialize.cpp     |  2 +-
 clang-tools-extra/clang-doc/YAMLGenerator.cpp | 20 ++++-
 9 files changed, 201 insertions(+), 71 deletions(-)

diff --git a/clang-tools-extra/clang-doc/BitcodeReader.cpp b/clang-tools-extra/clang-doc/BitcodeReader.cpp
index f8e338eb7c6ed..2e5d402106547 100644
--- a/clang-tools-extra/clang-doc/BitcodeReader.cpp
+++ b/clang-tools-extra/clang-doc/BitcodeReader.cpp
@@ -315,8 +315,13 @@ static llvm::Error parseRecord(const Record &R, unsigned ID,
 static llvm::Error parseRecord(const Record &R, unsigned ID,
                                llvm::StringRef Blob, CommentInfo *I) {
   switch (ID) {
-  case COMMENT_KIND:
-    return decodeRecord(R, I->Kind, Blob);
+  case COMMENT_KIND: {
+    llvm::SmallString<16> KindStr;
+    if (llvm::Error Err = decodeRecord(R, KindStr, Blob))
+      return Err;
+    I->Kind = stringToCommentKind(KindStr);
+    return llvm::Error::success();
+  }
   case COMMENT_TEXT:
     return decodeRecord(R, I->Text, Blob);
   case COMMENT_NAME:
diff --git a/clang-tools-extra/clang-doc/BitcodeWriter.cpp b/clang-tools-extra/clang-doc/BitcodeWriter.cpp
index f0a445e606bff..efd60fdc2ec76 100644
--- a/clang-tools-extra/clang-doc/BitcodeWriter.cpp
+++ b/clang-tools-extra/clang-doc/BitcodeWriter.cpp
@@ -484,8 +484,9 @@ void ClangDocBitcodeWriter::emitBlock(const MemberTypeInfo &T) {
 
 void ClangDocBitcodeWriter::emitBlock(const CommentInfo &I) {
   StreamSubBlockGuard Block(Stream, BI_COMMENT_BLOCK_ID);
+  // Handle Kind (enum) separately, since it is not a string. 
+  emitRecord(commentKindToString(I.Kind), COMMENT_KIND);
   for (const auto &L : std::vector<std::pair<llvm::StringRef, RecordId>>{
-           {I.Kind, COMMENT_KIND},
            {I.Text, COMMENT_TEXT},
            {I.Name, COMMENT_NAME},
            {I.Direction, COMMENT_DIRECTION},
diff --git a/clang-tools-extra/clang-doc/HTMLGenerator.cpp b/clang-tools-extra/clang-doc/HTMLGenerator.cpp
index 93b9279462a89..eb7bfb842589b 100644
--- a/clang-tools-extra/clang-doc/HTMLGenerator.cpp
+++ b/clang-tools-extra/clang-doc/HTMLGenerator.cpp
@@ -635,47 +635,53 @@ genHTML(const Index &Index, StringRef InfoPath, bool IsOutermostList) {
 }
 
 static std::unique_ptr<HTMLNode> genHTML(const CommentInfo &I) {
-  if (I.Kind == "FullComment") {
-    auto FullComment = std::make_unique<TagNode>(HTMLTag::TAG_DIV);
-    for (const auto &Child : I.Children) {
-      std::unique_ptr<HTMLNode> Node = genHTML(*Child);
-      if (Node)
-        FullComment->Children.emplace_back(std::move(Node));
+  switch (I.Kind) {
+    case CommentKind::CK_FullComment: {
+      auto FullComment = std::make_unique<TagNode>(HTMLTag::TAG_DIV);
+      for (const auto &Child : I.Children) {
+        std::unique_ptr<HTMLNode> Node = genHTML(*Child);
+        if (Node)
+          FullComment->Children.emplace_back(std::move(Node));
+      }
+      return std::move(FullComment);
     }
-    return std::move(FullComment);
-  }
 
-  if (I.Kind == "ParagraphComment") {
-    auto ParagraphComment = std::make_unique<TagNode>(HTMLTag::TAG_P);
-    for (const auto &Child : I.Children) {
-      std::unique_ptr<HTMLNode> Node = genHTML(*Child);
-      if (Node)
-        ParagraphComment->Children.emplace_back(std::move(Node));
+    case CommentKind::CK_ParagraphComment: {
+      auto ParagraphComment = std::make_unique<TagNode>(HTMLTag::TAG_P);
+      for (const auto &Child : I.Children) {
+        std::unique_ptr<HTMLNode> Node = genHTML(*Child);
+        if (Node)
+          ParagraphComment->Children.emplace_back(std::move(Node));
+      }
+      if (ParagraphComment->Children.empty())
+        return nullptr;
+      return std::move(ParagraphComment);
     }
-    if (ParagraphComment->Children.empty())
-      return nullptr;
-    return std::move(ParagraphComment);
-  }
 
-  if (I.Kind == "BlockCommandComment") {
-    auto BlockComment = std::make_unique<TagNode>(HTMLTag::TAG_DIV);
-    BlockComment->Children.emplace_back(
-        std::make_unique<TagNode>(HTMLTag::TAG_DIV, I.Name));
-    for (const auto &Child : I.Children) {
-      std::unique_ptr<HTMLNode> Node = genHTML(*Child);
-      if (Node)
-        BlockComment->Children.emplace_back(std::move(Node));
+    case CommentKind::CK_BlockCommandComment: {
+      auto BlockComment = std::make_unique<TagNode>(HTMLTag::TAG_DIV);
+      BlockComment->Children.emplace_back(
+          std::make_unique<TagNode>(HTMLTag::TAG_DIV, I.Name));
+      for (const auto &Child : I.Children) {
+        std::unique_ptr<HTMLNode> Node = genHTML(*Child);
+        if (Node)
+          BlockComment->Children.emplace_back(std::move(Node));
+      }
+      if (BlockComment->Children.empty())
+        return nullptr;
+      return std::move(BlockComment);
     }
-    if (BlockComment->Children.empty())
-      return nullptr;
-    return std::move(BlockComment);
-  }
-  if (I.Kind == "TextComment") {
-    if (I.Text == "")
+
+    case CommentKind::CK_TextComment: {
+      if (I.Text.empty())
+        return nullptr;
+      return std::make_unique<TextNode>(I.Text);
+    }
+
+    // For now, no handling — fallthrough.
+    default:
       return nullptr;
-    return std::make_unique<TextNode>(I.Text);
   }
-  return nullptr;
 }
 
 static std::unique_ptr<TagNode> genHTML(const std::vector<CommentInfo> &C) {
diff --git a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
index 65dc2e93582e8..95306eee12f31 100644
--- a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
+++ b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
@@ -198,21 +198,23 @@ static json::Value extractValue(const TypedefInfo &I) {
 }
 
 static json::Value extractValue(const CommentInfo &I) {
-  assert((I.Kind == "BlockCommandComment" || I.Kind == "FullComment" ||
-          I.Kind == "ParagraphComment" || I.Kind == "TextComment") &&
+  assert((I.Kind == CommentKind::CK_BlockCommandComment ||
+          I.Kind == CommentKind::CK_FullComment ||
+          I.Kind == CommentKind::CK_ParagraphComment ||
+          I.Kind == CommentKind::CK_TextComment) &&
          "Unknown Comment type in CommentInfo.");
 
   Object Obj = Object();
   json::Value Child = Object();
 
   // TextComment has no children, so return it.
-  if (I.Kind == "TextComment") {
+  if (I.Kind == CommentKind::CK_TextComment) {
     Obj.insert({"TextComment", I.Text});
     return Obj;
   }
 
   // BlockCommandComment needs to generate a Command key.
-  if (I.Kind == "BlockCommandComment")
+  if (I.Kind == CommentKind::CK_BlockCommandComment)
     Child.getAsObject()->insert({"Command", I.Name});
 
   // Use the same handling for everything else.
@@ -226,7 +228,7 @@ static json::Value extractValue(const CommentInfo &I) {
   for (const auto &C : I.Children)
     CARef.emplace_back(extractValue(*C));
   Child.getAsObject()->insert({"Children", ChildArr});
-  Obj.insert({I.Kind, Child});
+  Obj.insert({commentKindToString(I.Kind), Child});
 
   return Obj;
 }
diff --git a/clang-tools-extra/clang-doc/MDGenerator.cpp b/clang-tools-extra/clang-doc/MDGenerator.cpp
index ccd6175c96cb8..87bbfbddb22e2 100644
--- a/clang-tools-extra/clang-doc/MDGenerator.cpp
+++ b/clang-tools-extra/clang-doc/MDGenerator.cpp
@@ -75,39 +75,49 @@ static void maybeWriteSourceFileRef(llvm::raw_ostream &OS,
 }
 
 static void writeDescription(const CommentInfo &I, raw_ostream &OS) {
-  if (I.Kind == "FullComment") {
+  switch (I.Kind) {
+  case CommentKind::CK_FullComment:
     for (const auto &Child : I.Children)
       writeDescription(*Child, OS);
-  } else if (I.Kind == "ParagraphComment") {
+    break;
+
+  case CommentKind::CK_ParagraphComment:
     for (const auto &Child : I.Children)
       writeDescription(*Child, OS);
     writeNewLine(OS);
-  } else if (I.Kind == "BlockCommandComment") {
+    break;
+
+  case CommentKind::CK_BlockCommandComment:
     OS << genEmphasis(I.Name);
     for (const auto &Child : I.Children)
       writeDescription(*Child, OS);
-  } else if (I.Kind == "InlineCommandComment") {
+    break;
+
+  case CommentKind::CK_InlineCommandComment:
     OS << genEmphasis(I.Name) << " " << I.Text;
-  } else if (I.Kind == "ParamCommandComment") {
-    std::string Direction = I.Explicit ? (" " + I.Direction).str() : "";
-    OS << genEmphasis(I.ParamName) << I.Text << Direction;
-    for (const auto &Child : I.Children)
-      writeDescription(*Child, OS);
-  } else if (I.Kind == "TParamCommandComment") {
+    break;
+
+  case CommentKind::CK_ParamCommandComment:
+  case CommentKind::CK_TParamCommandComment: {
     std::string Direction = I.Explicit ? (" " + I.Direction).str() : "";
     OS << genEmphasis(I.ParamName) << I.Text << Direction;
     for (const auto &Child : I.Children)
       writeDescription(*Child, OS);
-  } else if (I.Kind == "VerbatimBlockComment") {
+    break;
+  }
+
+  case CommentKind::CK_VerbatimBlockComment:
     for (const auto &Child : I.Children)
       writeDescription(*Child, OS);
-  } else if (I.Kind == "VerbatimBlockLineComment") {
-    OS << I.Text;
-    writeNewLine(OS);
-  } else if (I.Kind == "VerbatimLineComment") {
+    break;
+
+  case CommentKind::CK_VerbatimBlockLineComment:
+  case CommentKind::CK_VerbatimLineComment:
     OS << I.Text;
     writeNewLine(OS);
-  } else if (I.Kind == "HTMLStartTagComment") {
+    break;
+
+  case CommentKind::CK_HTMLStartTagComment: {
     if (I.AttrKeys.size() != I.AttrValues.size())
       return;
     std::string Buffer;
@@ -117,12 +127,21 @@ static void writeDescription(const CommentInfo &I, raw_ostream &OS) {
 
     std::string CloseTag = I.SelfClosing ? "/>" : ">";
     writeLine("<" + I.Name + Attrs.str() + CloseTag, OS);
-  } else if (I.Kind == "HTMLEndTagComment") {
+    break;
+  }
+
+  case CommentKind::CK_HTMLEndTagComment:
     writeLine("</" + I.Name + ">", OS);
-  } else if (I.Kind == "TextComment") {
+    break;
+
+  case CommentKind::CK_TextComment:
     OS << I.Text;
-  } else {
-    OS << "Unknown comment kind: " << I.Kind << ".\n\n";
+    break;
+
+  case CommentKind::CK_Unknown:
+  default:
+    OS << "Unknown comment kind: " << static_cast<int>(I.Kind) << ".\n\n";
+    break;
   }
 }
 
diff --git a/clang-tools-extra/clang-doc/Representation.cpp b/clang-tools-extra/clang-doc/Representation.cpp
index 9ab2f342d969a..9fb3839419731 100644
--- a/clang-tools-extra/clang-doc/Representation.cpp
+++ b/clang-tools-extra/clang-doc/Representation.cpp
@@ -26,6 +26,66 @@
 namespace clang {
 namespace doc {
 
+CommentKind stringToCommentKind(llvm::StringRef KindStr) {
+  if (KindStr == "FullComment")
+    return CommentKind::CK_FullComment;
+  if (KindStr == "ParagraphComment")
+    return CommentKind::CK_ParagraphComment;
+  if (KindStr == "TextComment")
+    return CommentKind::CK_TextComment;
+  if (KindStr == "InlineCommandComment")
+    return CommentKind::CK_InlineCommandComment;
+  if (KindStr == "HTMLStartTagComment")
+    return CommentKind::CK_HTMLStartTagComment;
+  if (KindStr == "HTMLEndTagComment")
+    return CommentKind::CK_HTMLEndTagComment;
+  if (KindStr == "BlockCommandComment")
+    return CommentKind::CK_BlockCommandComment;
+  if (KindStr == "ParamCommandComment")
+    return CommentKind::CK_ParamCommandComment;
+  if (KindStr == "TParamCommandComment")
+    return CommentKind::CK_TParamCommandComment;
+  if (KindStr == "VerbatimBlockComment")
+    return CommentKind::CK_VerbatimBlockComment;
+  if (KindStr == "VerbatimBlockLineComment")
+    return CommentKind::CK_VerbatimBlockLineComment;
+  if (KindStr == "VerbatimLineComment")
+    return CommentKind::CK_VerbatimLineComment;
+  return CommentKind::CK_Unknown;
+}
+
+llvm::StringRef commentKindToString(CommentKind Kind) {
+  switch (Kind) {
+  case CommentKind::CK_FullComment:
+    return "FullComment";
+  case CommentKind::CK_ParagraphComment:
+    return "ParagraphComment";
+  case CommentKind::CK_TextComment:
+    return "TextComment";
+  case CommentKind::CK_InlineCommandComment:
+    return "InlineCommandComment";
+  case CommentKind::CK_HTMLStartTagComment:
+    return "HTMLStartTagComment";
+  case CommentKind::CK_HTMLEndTagComment:
+    return "HTMLEndTagComment";
+  case CommentKind::CK_BlockCommandComment:
+    return "BlockCommandComment";
+  case CommentKind::CK_ParamCommandComment:
+    return "ParamCommandComment";
+  case CommentKind::CK_TParamCommandComment:
+    return "TParamCommandComment";
+  case CommentKind::CK_VerbatimBlockComment:
+    return "VerbatimBlockComment";
+  case CommentKind::CK_VerbatimBlockLineComment:
+    return "VerbatimBlockLineComment";
+  case CommentKind::CK_VerbatimLineComment:
+    return "VerbatimLineComment";
+  case CommentKind::CK_Unknown:
+    return "Unknown";
+  }
+  llvm_unreachable("Unhandled CommentKind");
+}
+
 namespace {
 
 const SymbolID EmptySID = SymbolID();
diff --git a/clang-tools-extra/clang-doc/Representation.h b/clang-tools-extra/clang-doc/Representation.h
index a3a6217f76bbd..15f5638a80803 100644
--- a/clang-tools-extra/clang-doc/Representation.h
+++ b/clang-tools-extra/clang-doc/Representation.h
@@ -45,6 +45,25 @@ enum class InfoType {
   IT_typedef
 };
 
+enum class CommentKind {
+  CK_FullComment,
+  CK_ParagraphComment,
+  CK_TextComment,
+  CK_InlineCommandComment,
+  CK_HTMLStartTagComment,
+  CK_HTMLEndTagComment,
+  CK_BlockCommandComment,
+  CK_ParamCommandComment,
+  CK_TParamCommandComment,
+  CK_VerbatimBlockComment,
+  CK_VerbatimBlockLineComment,
+  CK_VerbatimLineComment,
+  CK_Unknown
+};
+
+CommentKind stringToCommentKind(llvm::StringRef KindStr);
+llvm::StringRef commentKindToString(CommentKind Kind);
+
 // A representation of a parsed comment.
 struct CommentInfo {
   CommentInfo() = default;
@@ -60,13 +79,13 @@ struct CommentInfo {
   // the vector.
   bool operator<(const CommentInfo &Other) const;
 
-  // TODO: The Kind field should be an enum, so we can switch on it easily.
-  SmallString<16>
-      Kind; // Kind of comment (FullComment, ParagraphComment, TextComment,
-            // InlineCommandComment, HTMLStartTagComment, HTMLEndTagComment,
-            // BlockCommandComment, ParamCommandComment,
-            // TParamCommandComment, VerbatimBlockComment,
-            // VerbatimBlockLineComment, VerbatimLineComment).
+  CommentKind Kind = CommentKind::
+      CK_Unknown; // Kind of comment (FullComment, ParagraphComment,
+                  // TextComment, InlineCommandComment, HTMLStartTagComment,
+                  // HTMLEndTagComment, BlockCommandComment,
+                  // ParamCommandComment, TParamCommandComment,
+                  // VerbatimBlockComment, VerbatimBlockLineComment,
+                  // VerbatimLineComment).
   SmallString<64> Text;      // Text of the comment.
   SmallString<16> Name;      // Name of the comment (for Verbatim and HTML).
   SmallString<8> Direction;  // Parameter direction (for (T)ParamCommand).
diff --git a/clang-tools-extra/clang-doc/Serialize.cpp b/clang-tools-extra/clang-doc/Serialize.cpp
index 3932a939de973..462001b3f3027 100644
--- a/clang-tools-extra/clang-doc/Serialize.cpp
+++ b/clang-tools-extra/clang-doc/Serialize.cpp
@@ -270,7 +270,7 @@ class ClangDocCommentVisitor
 };
 
 void ClangDocCommentVisitor::parseComment(const comments::Comment *C) {
-  CurrentCI.Kind = C->getCommentKindName();
+  CurrentCI.Kind = stringToCommentKind(C->getCommentKindName());
   ConstCommentVisitor<ClangDocCommentVisitor>::visit(C);
   for (comments::Comment *Child :
        llvm::make_range(C->child_begin(), C->child_end())) {
diff --git a/clang-tools-extra/clang-doc/YAMLGenerator.cpp b/clang-tools-extra/clang-doc/YAMLGenerator.cpp
index 8c110b34e8e20..38bebbde6675f 100644
--- a/clang-tools-extra/clang-doc/YAMLGenerator.cpp
+++ b/clang-tools-extra/clang-doc/YAMLGenerator.cpp
@@ -65,6 +65,24 @@ template <> struct ScalarEnumerationTraits<InfoType> {
   }
 };
 
+template <> struct llvm::yaml::ScalarEnumerationTraits<clang::doc::CommentKind> {
+  static void enumeration(IO &IO, clang::doc::CommentKind &Value) {
+    IO.enumCase(Value, "FullComment", clang::doc::CommentKind::CK_FullComment);
+    IO.enumCase(Value, "ParagraphComment", clang::doc::CommentKind::CK_ParagraphComment);
+    IO.enumCase(Value, "TextComment", clang::doc::CommentKind::CK_TextComment);
+    IO.enumCase(Value, "InlineCommandComment", clang::doc::CommentKind::CK_InlineCommandComment);
+    IO.enumCase(Value, "HTMLStartTagComment", clang::doc::CommentKind::CK_HTMLStartTagComment);
+    IO.enumCase(Value, "HTMLEndTagComment", clang::doc::CommentKind::CK_HTMLEndTagComment);
+    IO.enumCase(Value, "BlockCommandComment", clang::doc::CommentKind::CK_BlockCommandComment);
+    IO.enumCase(Value, "ParamCommandComment", clang::doc::CommentKind::CK_ParamCommandComment);
+    IO.enumCase(Value, "TParamCommandComment", clang::doc::CommentKind::CK_TParamCommandComment);
+    IO.enumCase(Value, "VerbatimBlockComment", clang::doc::CommentKind::CK_VerbatimBlockComment);
+    IO.enumCase(Value, "VerbatimBlockLineComment", clang::doc::CommentKind::CK_VerbatimBlockLineComment);
+    IO.enumCase(Value, "VerbatimLineComment", clang::doc::CommentKind::CK_VerbatimLineComment);
+    IO.enumCase(Value, "Unknown", clang::doc::CommentKind::CK_Unknown);
+  }
+};
+
 // Scalars to YAML output.
 template <unsigned U> struct ScalarTraits<SmallString<U>> {
 
@@ -149,7 +167,7 @@ static void recordInfoMapping(IO &IO, RecordInfo &I) {
 }
 
 static void commentInfoMapping(IO &IO, CommentInfo &I) {
-  IO.mapOptional("Kind", I.Kind, SmallString<16>());
+  IO.mapOptional("Kind", I.Kind, CommentKind::CK_Unknown);
   IO.mapOptional("Text", I.Text, SmallString<64>());
   IO.mapOptional("Name", I.Name, SmallString<16>());
   IO.mapOptional("Direction", I.Direction, SmallString<8>());

>From a6438fb3db00419188a2051dfc261bcf633dc100 Mon Sep 17 00:00:00 2001
From: Samarth Narang <snarang at umass.edu>
Date: Sat, 31 May 2025 10:06:51 -0400
Subject: [PATCH 2/8] Clang Formatter run

---
 clang-tools-extra/clang-doc/BitcodeWriter.cpp |  2 +-
 clang-tools-extra/clang-doc/HTMLGenerator.cpp | 76 +++++++++----------
 clang-tools-extra/clang-doc/YAMLGenerator.cpp | 33 +++++---
 3 files changed, 61 insertions(+), 50 deletions(-)

diff --git a/clang-tools-extra/clang-doc/BitcodeWriter.cpp b/clang-tools-extra/clang-doc/BitcodeWriter.cpp
index efd60fdc2ec76..708ce09d9e5b2 100644
--- a/clang-tools-extra/clang-doc/BitcodeWriter.cpp
+++ b/clang-tools-extra/clang-doc/BitcodeWriter.cpp
@@ -484,7 +484,7 @@ void ClangDocBitcodeWriter::emitBlock(const MemberTypeInfo &T) {
 
 void ClangDocBitcodeWriter::emitBlock(const CommentInfo &I) {
   StreamSubBlockGuard Block(Stream, BI_COMMENT_BLOCK_ID);
-  // Handle Kind (enum) separately, since it is not a string. 
+  // Handle Kind (enum) separately, since it is not a string.
   emitRecord(commentKindToString(I.Kind), COMMENT_KIND);
   for (const auto &L : std::vector<std::pair<llvm::StringRef, RecordId>>{
            {I.Text, COMMENT_TEXT},
diff --git a/clang-tools-extra/clang-doc/HTMLGenerator.cpp b/clang-tools-extra/clang-doc/HTMLGenerator.cpp
index eb7bfb842589b..8a36fbf99c857 100644
--- a/clang-tools-extra/clang-doc/HTMLGenerator.cpp
+++ b/clang-tools-extra/clang-doc/HTMLGenerator.cpp
@@ -636,51 +636,51 @@ genHTML(const Index &Index, StringRef InfoPath, bool IsOutermostList) {
 
 static std::unique_ptr<HTMLNode> genHTML(const CommentInfo &I) {
   switch (I.Kind) {
-    case CommentKind::CK_FullComment: {
-      auto FullComment = std::make_unique<TagNode>(HTMLTag::TAG_DIV);
-      for (const auto &Child : I.Children) {
-        std::unique_ptr<HTMLNode> Node = genHTML(*Child);
-        if (Node)
-          FullComment->Children.emplace_back(std::move(Node));
-      }
-      return std::move(FullComment);
-    }
-
-    case CommentKind::CK_ParagraphComment: {
-      auto ParagraphComment = std::make_unique<TagNode>(HTMLTag::TAG_P);
-      for (const auto &Child : I.Children) {
-        std::unique_ptr<HTMLNode> Node = genHTML(*Child);
-        if (Node)
-          ParagraphComment->Children.emplace_back(std::move(Node));
-      }
-      if (ParagraphComment->Children.empty())
-        return nullptr;
-      return std::move(ParagraphComment);
+  case CommentKind::CK_FullComment: {
+    auto FullComment = std::make_unique<TagNode>(HTMLTag::TAG_DIV);
+    for (const auto &Child : I.Children) {
+      std::unique_ptr<HTMLNode> Node = genHTML(*Child);
+      if (Node)
+        FullComment->Children.emplace_back(std::move(Node));
     }
+    return std::move(FullComment);
+  }
 
-    case CommentKind::CK_BlockCommandComment: {
-      auto BlockComment = std::make_unique<TagNode>(HTMLTag::TAG_DIV);
-      BlockComment->Children.emplace_back(
-          std::make_unique<TagNode>(HTMLTag::TAG_DIV, I.Name));
-      for (const auto &Child : I.Children) {
-        std::unique_ptr<HTMLNode> Node = genHTML(*Child);
-        if (Node)
-          BlockComment->Children.emplace_back(std::move(Node));
-      }
-      if (BlockComment->Children.empty())
-        return nullptr;
-      return std::move(BlockComment);
+  case CommentKind::CK_ParagraphComment: {
+    auto ParagraphComment = std::make_unique<TagNode>(HTMLTag::TAG_P);
+    for (const auto &Child : I.Children) {
+      std::unique_ptr<HTMLNode> Node = genHTML(*Child);
+      if (Node)
+        ParagraphComment->Children.emplace_back(std::move(Node));
     }
+    if (ParagraphComment->Children.empty())
+      return nullptr;
+    return std::move(ParagraphComment);
+  }
 
-    case CommentKind::CK_TextComment: {
-      if (I.Text.empty())
-        return nullptr;
-      return std::make_unique<TextNode>(I.Text);
+  case CommentKind::CK_BlockCommandComment: {
+    auto BlockComment = std::make_unique<TagNode>(HTMLTag::TAG_DIV);
+    BlockComment->Children.emplace_back(
+        std::make_unique<TagNode>(HTMLTag::TAG_DIV, I.Name));
+    for (const auto &Child : I.Children) {
+      std::unique_ptr<HTMLNode> Node = genHTML(*Child);
+      if (Node)
+        BlockComment->Children.emplace_back(std::move(Node));
     }
+    if (BlockComment->Children.empty())
+      return nullptr;
+    return std::move(BlockComment);
+  }
 
-    // For now, no handling — fallthrough.
-    default:
+  case CommentKind::CK_TextComment: {
+    if (I.Text.empty())
       return nullptr;
+    return std::make_unique<TextNode>(I.Text);
+  }
+
+  // For now, no handling — fallthrough.
+  default:
+    return nullptr;
   }
 }
 
diff --git a/clang-tools-extra/clang-doc/YAMLGenerator.cpp b/clang-tools-extra/clang-doc/YAMLGenerator.cpp
index 38bebbde6675f..09fadcbc1e742 100644
--- a/clang-tools-extra/clang-doc/YAMLGenerator.cpp
+++ b/clang-tools-extra/clang-doc/YAMLGenerator.cpp
@@ -65,20 +65,31 @@ template <> struct ScalarEnumerationTraits<InfoType> {
   }
 };
 
-template <> struct llvm::yaml::ScalarEnumerationTraits<clang::doc::CommentKind> {
+template <>
+struct llvm::yaml::ScalarEnumerationTraits<clang::doc::CommentKind> {
   static void enumeration(IO &IO, clang::doc::CommentKind &Value) {
     IO.enumCase(Value, "FullComment", clang::doc::CommentKind::CK_FullComment);
-    IO.enumCase(Value, "ParagraphComment", clang::doc::CommentKind::CK_ParagraphComment);
+    IO.enumCase(Value, "ParagraphComment",
+                clang::doc::CommentKind::CK_ParagraphComment);
     IO.enumCase(Value, "TextComment", clang::doc::CommentKind::CK_TextComment);
-    IO.enumCase(Value, "InlineCommandComment", clang::doc::CommentKind::CK_InlineCommandComment);
-    IO.enumCase(Value, "HTMLStartTagComment", clang::doc::CommentKind::CK_HTMLStartTagComment);
-    IO.enumCase(Value, "HTMLEndTagComment", clang::doc::CommentKind::CK_HTMLEndTagComment);
-    IO.enumCase(Value, "BlockCommandComment", clang::doc::CommentKind::CK_BlockCommandComment);
-    IO.enumCase(Value, "ParamCommandComment", clang::doc::CommentKind::CK_ParamCommandComment);
-    IO.enumCase(Value, "TParamCommandComment", clang::doc::CommentKind::CK_TParamCommandComment);
-    IO.enumCase(Value, "VerbatimBlockComment", clang::doc::CommentKind::CK_VerbatimBlockComment);
-    IO.enumCase(Value, "VerbatimBlockLineComment", clang::doc::CommentKind::CK_VerbatimBlockLineComment);
-    IO.enumCase(Value, "VerbatimLineComment", clang::doc::CommentKind::CK_VerbatimLineComment);
+    IO.enumCase(Value, "InlineCommandComment",
+                clang::doc::CommentKind::CK_InlineCommandComment);
+    IO.enumCase(Value, "HTMLStartTagComment",
+                clang::doc::CommentKind::CK_HTMLStartTagComment);
+    IO.enumCase(Value, "HTMLEndTagComment",
+                clang::doc::CommentKind::CK_HTMLEndTagComment);
+    IO.enumCase(Value, "BlockCommandComment",
+                clang::doc::CommentKind::CK_BlockCommandComment);
+    IO.enumCase(Value, "ParamCommandComment",
+                clang::doc::CommentKind::CK_ParamCommandComment);
+    IO.enumCase(Value, "TParamCommandComment",
+                clang::doc::CommentKind::CK_TParamCommandComment);
+    IO.enumCase(Value, "VerbatimBlockComment",
+                clang::doc::CommentKind::CK_VerbatimBlockComment);
+    IO.enumCase(Value, "VerbatimBlockLineComment",
+                clang::doc::CommentKind::CK_VerbatimBlockLineComment);
+    IO.enumCase(Value, "VerbatimLineComment",
+                clang::doc::CommentKind::CK_VerbatimLineComment);
     IO.enumCase(Value, "Unknown", clang::doc::CommentKind::CK_Unknown);
   }
 };

>From fe7faa57dc0b03bde34e578bc8f5f3e700614346 Mon Sep 17 00:00:00 2001
From: Samarth Narang <snarang at umass.edu>
Date: Sat, 31 May 2025 10:58:37 -0400
Subject: [PATCH 3/8] Remove default switch case

---
 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 87bbfbddb22e2..2becccf8b07da 100644
--- a/clang-tools-extra/clang-doc/MDGenerator.cpp
+++ b/clang-tools-extra/clang-doc/MDGenerator.cpp
@@ -139,7 +139,6 @@ static void writeDescription(const CommentInfo &I, raw_ostream &OS) {
     break;
 
   case CommentKind::CK_Unknown:
-  default:
     OS << "Unknown comment kind: " << static_cast<int>(I.Kind) << ".\n\n";
     break;
   }

>From 8af49f9cebbab05f61faecec81f7a43d3132716d Mon Sep 17 00:00:00 2001
From: Samarth Narang <snarang at umass.edu>
Date: Sat, 31 May 2025 11:00:58 -0400
Subject: [PATCH 4/8] Fix test cases for clang-doc comment structure refactor

---
 .../test/clang-doc/templates.cpp              |  16 +--
 .../unittests/clang-doc/BitcodeTest.cpp       |  68 +++++-----
 .../unittests/clang-doc/HTMLGeneratorTest.cpp |  20 +--
 .../unittests/clang-doc/MDGeneratorTest.cpp   |  56 ++++----
 .../unittests/clang-doc/MergeTest.cpp         |  18 +--
 .../unittests/clang-doc/YAMLGeneratorTest.cpp | 122 +++++++++---------
 6 files changed, 153 insertions(+), 147 deletions(-)

diff --git a/clang-tools-extra/test/clang-doc/templates.cpp b/clang-tools-extra/test/clang-doc/templates.cpp
index 426a0b16befd4..abe03a7d2d0ea 100644
--- a/clang-tools-extra/test/clang-doc/templates.cpp
+++ b/clang-tools-extra/test/clang-doc/templates.cpp
@@ -112,22 +112,22 @@ tuple<int, int, bool> func_with_tuple_param(tuple<int, int, bool> t) { return t;
 // YAML-NEXT:   - USR:             '{{([0-9A-F]{40})}}'
 // YAML-NEXT:    Name:            'func_with_tuple_param'
 // YAML-NEXT:    Description:
-// YAML-NEXT:      - Kind:            'FullComment'
+// YAML-NEXT:      - Kind:            FullComment
 // YAML-NEXT:        Children:
-// YAML-NEXT:          - Kind:            'ParagraphComment'
+// YAML-NEXT:          - Kind:            ParagraphComment
 // YAML-NEXT:            Children:
-// YAML-NEXT:              - Kind:            'TextComment'
+// YAML-NEXT:              - Kind:            TextComment
 // YAML-NEXT:                Text:            ' A function with a tuple parameter'
-// YAML-NEXT:          - Kind:            'ParagraphComment'
+// YAML-NEXT:          - Kind:            ParagraphComment
 // YAML-NEXT:            Children:
-// YAML-NEXT:              - Kind:            'TextComment'
-// YAML-NEXT:          - Kind:            'ParamCommandComment'
+// YAML-NEXT:              - Kind:            TextComment
+// YAML-NEXT:          - Kind:            ParamCommandComment
 // YAML-NEXT:            Direction:       '[in]'
 // YAML-NEXT:            ParamName:       't'
 // YAML-NEXT:            Children:
-// YAML-NEXT:              - Kind:            'ParagraphComment'
+// YAML-NEXT:              - Kind:            ParagraphComment
 // YAML-NEXT:                Children:
-// YAML-NEXT:                  - Kind:            'TextComment'
+// YAML-NEXT:                  - Kind:            TextComment
 // YAML-NEXT:                    Text:            ' The input to func_with_tuple_param'
 // YAML-NEXT:    DefLocation:
 // YAML-NEXT:      LineNumber:      [[# @LINE - 23]]
diff --git a/clang-tools-extra/unittests/clang-doc/BitcodeTest.cpp b/clang-tools-extra/unittests/clang-doc/BitcodeTest.cpp
index 4f2466af9a6bd..bbe158ed50e28 100644
--- a/clang-tools-extra/unittests/clang-doc/BitcodeTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/BitcodeTest.cpp
@@ -93,12 +93,12 @@ TEST(BitcodeTest, emitRecordInfoBitcode) {
 
   // Documentation for the data member.
   CommentInfo TopComment;
-  TopComment.Kind = "FullComment";
+  TopComment.Kind = CommentKind::CK_FullComment;
   TopComment.Children.emplace_back(std::make_unique<CommentInfo>());
   CommentInfo *Brief = TopComment.Children.back().get();
-  Brief->Kind = "ParagraphComment";
+  Brief->Kind = CommentKind::CK_ParagraphComment;
   Brief->Children.emplace_back(std::make_unique<CommentInfo>());
-  Brief->Children.back()->Kind = "TextComment";
+  Brief->Children.back()->Kind = CommentKind::CK_TextComment;
   Brief->Children.back()->Name = "ParagraphComment";
   Brief->Children.back()->Text = "Value of the thing.";
   I.Bases.back().Members.back().Description.emplace_back(std::move(TopComment));
@@ -184,13 +184,13 @@ TEST(BitcodeTest, emitTypedefInfoBitcode) {
   I.IsUsing = true;
 
   CommentInfo Top;
-  Top.Kind = "FullComment";
+  Top.Kind = CommentKind::CK_FullComment;
 
   Top.Children.emplace_back(std::make_unique<CommentInfo>());
   CommentInfo *BlankLine = Top.Children.back().get();
-  BlankLine->Kind = "ParagraphComment";
+  BlankLine->Kind = CommentKind::CK_ParagraphComment;
   BlankLine->Children.emplace_back(std::make_unique<CommentInfo>());
-  BlankLine->Children.back()->Kind = "TextComment";
+  BlankLine->Children.back()->Kind = CommentKind::CK_TextComment;
 
   I.Description.emplace_back(std::move(Top));
 
@@ -220,103 +220,105 @@ TEST(SerializeTest, emitInfoWithCommentBitcode) {
   F.Params.emplace_back(TypeInfo("int"), "I");
 
   CommentInfo Top;
-  Top.Kind = "FullComment";
+  Top.Kind = CommentKind::CK_FullComment;
 
   Top.Children.emplace_back(std::make_unique<CommentInfo>());
   CommentInfo *BlankLine = Top.Children.back().get();
-  BlankLine->Kind = "ParagraphComment";
+  BlankLine->Kind = CommentKind::CK_ParagraphComment;
   BlankLine->Children.emplace_back(std::make_unique<CommentInfo>());
-  BlankLine->Children.back()->Kind = "TextComment";
+  BlankLine->Children.back()->Kind = CommentKind::CK_TextComment;
 
   Top.Children.emplace_back(std::make_unique<CommentInfo>());
   CommentInfo *Brief = Top.Children.back().get();
-  Brief->Kind = "ParagraphComment";
+  Brief->Kind = CommentKind::CK_ParagraphComment;
   Brief->Children.emplace_back(std::make_unique<CommentInfo>());
-  Brief->Children.back()->Kind = "TextComment";
+  Brief->Children.back()->Kind = CommentKind::CK_TextComment;
   Brief->Children.back()->Name = "ParagraphComment";
   Brief->Children.back()->Text = " Brief description.";
 
   Top.Children.emplace_back(std::make_unique<CommentInfo>());
   CommentInfo *Extended = Top.Children.back().get();
-  Extended->Kind = "ParagraphComment";
+  Extended->Kind = CommentKind::CK_ParagraphComment;
   Extended->Children.emplace_back(std::make_unique<CommentInfo>());
-  Extended->Children.back()->Kind = "TextComment";
+  Extended->Children.back()->Kind = CommentKind::CK_TextComment;
   Extended->Children.back()->Text = " Extended description that";
   Extended->Children.emplace_back(std::make_unique<CommentInfo>());
-  Extended->Children.back()->Kind = "TextComment";
+  Extended->Children.back()->Kind = CommentKind::CK_TextComment;
   Extended->Children.back()->Text = " continues onto the next line.";
 
   Top.Children.emplace_back(std::make_unique<CommentInfo>());
   CommentInfo *HTML = Top.Children.back().get();
-  HTML->Kind = "ParagraphComment";
+  HTML->Kind = CommentKind::CK_ParagraphComment;
   HTML->Children.emplace_back(std::make_unique<CommentInfo>());
-  HTML->Children.back()->Kind = "TextComment";
+  HTML->Children.back()->Kind = CommentKind::CK_TextComment;
   HTML->Children.emplace_back(std::make_unique<CommentInfo>());
-  HTML->Children.back()->Kind = "HTMLStartTagComment";
+  HTML->Children.back()->Kind = CommentKind::CK_HTMLStartTagComment;
   HTML->Children.back()->Name = "ul";
   HTML->Children.back()->AttrKeys.emplace_back("class");
   HTML->Children.back()->AttrValues.emplace_back("test");
   HTML->Children.emplace_back(std::make_unique<CommentInfo>());
-  HTML->Children.back()->Kind = "HTMLStartTagComment";
+  HTML->Children.back()->Kind = CommentKind::CK_HTMLStartTagComment;
   HTML->Children.back()->Name = "li";
   HTML->Children.emplace_back(std::make_unique<CommentInfo>());
-  HTML->Children.back()->Kind = "TextComment";
+  HTML->Children.back()->Kind = CommentKind::CK_TextComment;
   HTML->Children.back()->Text = " Testing.";
   HTML->Children.emplace_back(std::make_unique<CommentInfo>());
-  HTML->Children.back()->Kind = "HTMLEndTagComment";
+  HTML->Children.back()->Kind = CommentKind::CK_HTMLEndTagComment;
   HTML->Children.back()->Name = "ul";
   HTML->Children.back()->SelfClosing = true;
 
   Top.Children.emplace_back(std::make_unique<CommentInfo>());
   CommentInfo *Verbatim = Top.Children.back().get();
-  Verbatim->Kind = "VerbatimBlockComment";
+  Verbatim->Kind = CommentKind::CK_VerbatimBlockComment;
   Verbatim->Name = "verbatim";
   Verbatim->CloseName = "endverbatim";
   Verbatim->Children.emplace_back(std::make_unique<CommentInfo>());
-  Verbatim->Children.back()->Kind = "VerbatimBlockLineComment";
+  Verbatim->Children.back()->Kind = CommentKind::CK_VerbatimBlockLineComment;
   Verbatim->Children.back()->Text = " The description continues.";
 
   Top.Children.emplace_back(std::make_unique<CommentInfo>());
   CommentInfo *ParamOut = Top.Children.back().get();
-  ParamOut->Kind = "ParamCommandComment";
+  ParamOut->Kind = CommentKind::CK_ParamCommandComment;
   ParamOut->Direction = "[out]";
   ParamOut->ParamName = "I";
   ParamOut->Explicit = true;
   ParamOut->Children.emplace_back(std::make_unique<CommentInfo>());
-  ParamOut->Children.back()->Kind = "ParagraphComment";
+  ParamOut->Children.back()->Kind = CommentKind::CK_ParagraphComment;
   ParamOut->Children.back()->Children.emplace_back(
       std::make_unique<CommentInfo>());
-  ParamOut->Children.back()->Children.back()->Kind = "TextComment";
+  ParamOut->Children.back()->Children.back()->Kind =
+      CommentKind::CK_TextComment;
   ParamOut->Children.back()->Children.emplace_back(
       std::make_unique<CommentInfo>());
-  ParamOut->Children.back()->Children.back()->Kind = "TextComment";
+  ParamOut->Children.back()->Children.back()->Kind =
+      CommentKind::CK_TextComment;
   ParamOut->Children.back()->Children.back()->Text = " is a parameter.";
 
   Top.Children.emplace_back(std::make_unique<CommentInfo>());
   CommentInfo *ParamIn = Top.Children.back().get();
-  ParamIn->Kind = "ParamCommandComment";
+  ParamIn->Kind = CommentKind::CK_ParamCommandComment;
   ParamIn->Direction = "[in]";
   ParamIn->ParamName = "J";
   ParamIn->Children.emplace_back(std::make_unique<CommentInfo>());
-  ParamIn->Children.back()->Kind = "ParagraphComment";
+  ParamIn->Children.back()->Kind = CommentKind::CK_ParagraphComment;
   ParamIn->Children.back()->Children.emplace_back(
       std::make_unique<CommentInfo>());
-  ParamIn->Children.back()->Children.back()->Kind = "TextComment";
+  ParamIn->Children.back()->Children.back()->Kind = CommentKind::CK_TextComment;
   ParamIn->Children.back()->Children.back()->Text = " is a parameter.";
   ParamIn->Children.back()->Children.emplace_back(
       std::make_unique<CommentInfo>());
-  ParamIn->Children.back()->Children.back()->Kind = "TextComment";
+  ParamIn->Children.back()->Children.back()->Kind = CommentKind::CK_TextComment;
 
   Top.Children.emplace_back(std::make_unique<CommentInfo>());
   CommentInfo *Return = Top.Children.back().get();
-  Return->Kind = "BlockCommandComment";
+  Return->Kind = CommentKind::CK_BlockCommandComment;
   Return->Name = "return";
   Return->Explicit = true;
   Return->Children.emplace_back(std::make_unique<CommentInfo>());
-  Return->Children.back()->Kind = "ParagraphComment";
+  Return->Children.back()->Kind = CommentKind::CK_ParagraphComment;
   Return->Children.back()->Children.emplace_back(
       std::make_unique<CommentInfo>());
-  Return->Children.back()->Children.back()->Kind = "TextComment";
+  Return->Children.back()->Children.back()->Kind = CommentKind::CK_TextComment;
   Return->Children.back()->Children.back()->Text = "void";
 
   F.Description.emplace_back(std::move(Top));
diff --git a/clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp b/clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp
index edf502475b511..143414354d36c 100644
--- a/clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp
@@ -407,37 +407,37 @@ TEST(HTMLGeneratorTest, emitCommentHTML) {
   I.Access = AccessSpecifier::AS_none;
 
   CommentInfo Top;
-  Top.Kind = "FullComment";
+  Top.Kind = CommentKind::CK_FullComment;
 
   Top.Children.emplace_back(std::make_unique<CommentInfo>());
   CommentInfo *BlankLine = Top.Children.back().get();
-  BlankLine->Kind = "ParagraphComment";
+  BlankLine->Kind = CommentKind::CK_ParagraphComment;
   BlankLine->Children.emplace_back(std::make_unique<CommentInfo>());
-  BlankLine->Children.back()->Kind = "TextComment";
+  BlankLine->Children.back()->Kind = CommentKind::CK_TextComment;
 
   Top.Children.emplace_back(std::make_unique<CommentInfo>());
   CommentInfo *Brief = Top.Children.back().get();
-  Brief->Kind = "ParagraphComment";
+  Brief->Kind = CommentKind::CK_ParagraphComment;
   Brief->Children.emplace_back(std::make_unique<CommentInfo>());
-  Brief->Children.back()->Kind = "TextComment";
+  Brief->Children.back()->Kind = CommentKind::CK_TextComment;
   Brief->Children.back()->Name = "ParagraphComment";
   Brief->Children.back()->Text = " Brief description.";
 
   Top.Children.emplace_back(std::make_unique<CommentInfo>());
   CommentInfo *Extended = Top.Children.back().get();
-  Extended->Kind = "ParagraphComment";
+  Extended->Kind = CommentKind::CK_ParagraphComment;
   Extended->Children.emplace_back(std::make_unique<CommentInfo>());
-  Extended->Children.back()->Kind = "TextComment";
+  Extended->Children.back()->Kind = CommentKind::CK_TextComment;
   Extended->Children.back()->Text = " Extended description that";
   Extended->Children.emplace_back(std::make_unique<CommentInfo>());
-  Extended->Children.back()->Kind = "TextComment";
+  Extended->Children.back()->Kind = CommentKind::CK_TextComment;
   Extended->Children.back()->Text = " continues onto the next line.";
 
   Top.Children.emplace_back(std::make_unique<CommentInfo>());
   CommentInfo *Entities = Top.Children.back().get();
-  Entities->Kind = "ParagraphComment";
+  Entities->Kind = CommentKind::CK_ParagraphComment;
   Entities->Children.emplace_back(std::make_unique<CommentInfo>());
-  Entities->Children.back()->Kind = "TextComment";
+  Entities->Children.back()->Kind = CommentKind::CK_TextComment;
   Entities->Children.back()->Name = "ParagraphComment";
   Entities->Children.back()->Text =
       " Comment with html entities: &, <, >, \", \'.";
diff --git a/clang-tools-extra/unittests/clang-doc/MDGeneratorTest.cpp b/clang-tools-extra/unittests/clang-doc/MDGeneratorTest.cpp
index 1795ef5a46c3a..f4c69cf868a1f 100644
--- a/clang-tools-extra/unittests/clang-doc/MDGeneratorTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/MDGeneratorTest.cpp
@@ -218,103 +218,105 @@ TEST(MDGeneratorTest, emitCommentMD) {
   I.Access = AccessSpecifier::AS_none;
 
   CommentInfo Top;
-  Top.Kind = "FullComment";
+  Top.Kind = CommentKind::CK_FullComment;
 
   Top.Children.emplace_back(std::make_unique<CommentInfo>());
   CommentInfo *BlankLine = Top.Children.back().get();
-  BlankLine->Kind = "ParagraphComment";
+  BlankLine->Kind = CommentKind::CK_ParagraphComment;
   BlankLine->Children.emplace_back(std::make_unique<CommentInfo>());
-  BlankLine->Children.back()->Kind = "TextComment";
+  BlankLine->Children.back()->Kind = CommentKind::CK_TextComment;
 
   Top.Children.emplace_back(std::make_unique<CommentInfo>());
   CommentInfo *Brief = Top.Children.back().get();
-  Brief->Kind = "ParagraphComment";
+  Brief->Kind = CommentKind::CK_ParagraphComment;
   Brief->Children.emplace_back(std::make_unique<CommentInfo>());
-  Brief->Children.back()->Kind = "TextComment";
+  Brief->Children.back()->Kind = CommentKind::CK_TextComment;
   Brief->Children.back()->Name = "ParagraphComment";
   Brief->Children.back()->Text = " Brief description.";
 
   Top.Children.emplace_back(std::make_unique<CommentInfo>());
   CommentInfo *Extended = Top.Children.back().get();
-  Extended->Kind = "ParagraphComment";
+  Extended->Kind = CommentKind::CK_ParagraphComment;
   Extended->Children.emplace_back(std::make_unique<CommentInfo>());
-  Extended->Children.back()->Kind = "TextComment";
+  Extended->Children.back()->Kind = CommentKind::CK_TextComment;
   Extended->Children.back()->Text = " Extended description that";
   Extended->Children.emplace_back(std::make_unique<CommentInfo>());
-  Extended->Children.back()->Kind = "TextComment";
+  Extended->Children.back()->Kind = CommentKind::CK_TextComment;
   Extended->Children.back()->Text = " continues onto the next line.";
 
   Top.Children.emplace_back(std::make_unique<CommentInfo>());
   CommentInfo *HTML = Top.Children.back().get();
-  HTML->Kind = "ParagraphComment";
+  HTML->Kind = CommentKind::CK_ParagraphComment;
   HTML->Children.emplace_back(std::make_unique<CommentInfo>());
-  HTML->Children.back()->Kind = "TextComment";
+  HTML->Children.back()->Kind = CommentKind::CK_TextComment;
   HTML->Children.emplace_back(std::make_unique<CommentInfo>());
-  HTML->Children.back()->Kind = "HTMLStartTagComment";
+  HTML->Children.back()->Kind = CommentKind::CK_HTMLStartTagComment;
   HTML->Children.back()->Name = "ul";
   HTML->Children.back()->AttrKeys.emplace_back("class");
   HTML->Children.back()->AttrValues.emplace_back("test");
   HTML->Children.emplace_back(std::make_unique<CommentInfo>());
-  HTML->Children.back()->Kind = "HTMLStartTagComment";
+  HTML->Children.back()->Kind = CommentKind::CK_HTMLStartTagComment;
   HTML->Children.back()->Name = "li";
   HTML->Children.emplace_back(std::make_unique<CommentInfo>());
-  HTML->Children.back()->Kind = "TextComment";
+  HTML->Children.back()->Kind = CommentKind::CK_TextComment;
   HTML->Children.back()->Text = " Testing.";
   HTML->Children.emplace_back(std::make_unique<CommentInfo>());
-  HTML->Children.back()->Kind = "HTMLEndTagComment";
+  HTML->Children.back()->Kind = CommentKind::CK_HTMLEndTagComment;
   HTML->Children.back()->Name = "ul";
   HTML->Children.back()->SelfClosing = true;
 
   Top.Children.emplace_back(std::make_unique<CommentInfo>());
   CommentInfo *Verbatim = Top.Children.back().get();
-  Verbatim->Kind = "VerbatimBlockComment";
+  Verbatim->Kind = CommentKind::CK_VerbatimBlockComment;
   Verbatim->Name = "verbatim";
   Verbatim->CloseName = "endverbatim";
   Verbatim->Children.emplace_back(std::make_unique<CommentInfo>());
-  Verbatim->Children.back()->Kind = "VerbatimBlockLineComment";
+  Verbatim->Children.back()->Kind = CommentKind::CK_VerbatimBlockLineComment;
   Verbatim->Children.back()->Text = " The description continues.";
 
   Top.Children.emplace_back(std::make_unique<CommentInfo>());
   CommentInfo *ParamOut = Top.Children.back().get();
-  ParamOut->Kind = "ParamCommandComment";
+  ParamOut->Kind = CommentKind::CK_ParamCommandComment;
   ParamOut->Direction = "[out]";
   ParamOut->ParamName = "I";
   ParamOut->Explicit = true;
   ParamOut->Children.emplace_back(std::make_unique<CommentInfo>());
-  ParamOut->Children.back()->Kind = "ParagraphComment";
+  ParamOut->Children.back()->Kind = CommentKind::CK_ParagraphComment;
   ParamOut->Children.back()->Children.emplace_back(
       std::make_unique<CommentInfo>());
-  ParamOut->Children.back()->Children.back()->Kind = "TextComment";
+  ParamOut->Children.back()->Children.back()->Kind =
+      CommentKind::CK_TextComment;
   ParamOut->Children.back()->Children.emplace_back(
       std::make_unique<CommentInfo>());
-  ParamOut->Children.back()->Children.back()->Kind = "TextComment";
+  ParamOut->Children.back()->Children.back()->Kind =
+      CommentKind::CK_TextComment;
   ParamOut->Children.back()->Children.back()->Text = " is a parameter.";
 
   Top.Children.emplace_back(std::make_unique<CommentInfo>());
   CommentInfo *ParamIn = Top.Children.back().get();
-  ParamIn->Kind = "ParamCommandComment";
+  ParamIn->Kind = CommentKind::CK_ParamCommandComment;
   ParamIn->Direction = "[in]";
   ParamIn->ParamName = "J";
   ParamIn->Children.emplace_back(std::make_unique<CommentInfo>());
-  ParamIn->Children.back()->Kind = "ParagraphComment";
+  ParamIn->Children.back()->Kind = CommentKind::CK_ParagraphComment;
   ParamIn->Children.back()->Children.emplace_back(
       std::make_unique<CommentInfo>());
-  ParamIn->Children.back()->Children.back()->Kind = "TextComment";
+  ParamIn->Children.back()->Children.back()->Kind = CommentKind::CK_TextComment;
   ParamIn->Children.back()->Children.back()->Text = " is a parameter.";
   ParamIn->Children.back()->Children.emplace_back(
       std::make_unique<CommentInfo>());
-  ParamIn->Children.back()->Children.back()->Kind = "TextComment";
+  ParamIn->Children.back()->Children.back()->Kind = CommentKind::CK_TextComment;
 
   Top.Children.emplace_back(std::make_unique<CommentInfo>());
   CommentInfo *Return = Top.Children.back().get();
-  Return->Kind = "BlockCommandComment";
+  Return->Kind = CommentKind::CK_BlockCommandComment;
   Return->Name = "return";
   Return->Explicit = true;
   Return->Children.emplace_back(std::make_unique<CommentInfo>());
-  Return->Children.back()->Kind = "ParagraphComment";
+  Return->Children.back()->Kind = CommentKind::CK_ParagraphComment;
   Return->Children.back()->Children.emplace_back(
       std::make_unique<CommentInfo>());
-  Return->Children.back()->Children.back()->Kind = "TextComment";
+  Return->Children.back()->Children.back()->Kind = CommentKind::CK_TextComment;
   Return->Children.back()->Children.back()->Text = "void";
 
   I.Description.emplace_back(std::move(Top));
diff --git a/clang-tools-extra/unittests/clang-doc/MergeTest.cpp b/clang-tools-extra/unittests/clang-doc/MergeTest.cpp
index f99748fdf347a..ade744e58ab0d 100644
--- a/clang-tools-extra/unittests/clang-doc/MergeTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/MergeTest.cpp
@@ -166,11 +166,11 @@ TEST(MergeTest, mergeFunctionInfos) {
 
   One.Description.emplace_back();
   auto *OneFullComment = &One.Description.back();
-  OneFullComment->Kind = "FullComment";
+  OneFullComment->Kind = CommentKind::CK_FullComment;
   auto OneParagraphComment = std::make_unique<CommentInfo>();
-  OneParagraphComment->Kind = "ParagraphComment";
+  OneParagraphComment->Kind = CommentKind::CK_ParagraphComment;
   auto OneTextComment = std::make_unique<CommentInfo>();
-  OneTextComment->Kind = "TextComment";
+  OneTextComment->Kind = CommentKind::CK_TextComment;
   OneTextComment->Text = "This is a text comment.";
   OneParagraphComment->Children.push_back(std::move(OneTextComment));
   OneFullComment->Children.push_back(std::move(OneParagraphComment));
@@ -186,11 +186,11 @@ TEST(MergeTest, mergeFunctionInfos) {
 
   Two.Description.emplace_back();
   auto *TwoFullComment = &Two.Description.back();
-  TwoFullComment->Kind = "FullComment";
+  TwoFullComment->Kind = CommentKind::CK_FullComment;
   auto TwoParagraphComment = std::make_unique<CommentInfo>();
-  TwoParagraphComment->Kind = "ParagraphComment";
+  TwoParagraphComment->Kind = CommentKind::CK_ParagraphComment;
   auto TwoTextComment = std::make_unique<CommentInfo>();
-  TwoTextComment->Kind = "TextComment";
+  TwoTextComment->Kind = CommentKind::CK_TextComment;
   TwoTextComment->Text = "This is a text comment.";
   TwoParagraphComment->Children.push_back(std::move(TwoTextComment));
   TwoFullComment->Children.push_back(std::move(TwoParagraphComment));
@@ -213,11 +213,11 @@ TEST(MergeTest, mergeFunctionInfos) {
 
   Expected->Description.emplace_back();
   auto *ExpectedFullComment = &Expected->Description.back();
-  ExpectedFullComment->Kind = "FullComment";
+  ExpectedFullComment->Kind = CommentKind::CK_FullComment;
   auto ExpectedParagraphComment = std::make_unique<CommentInfo>();
-  ExpectedParagraphComment->Kind = "ParagraphComment";
+  ExpectedParagraphComment->Kind = CommentKind::CK_ParagraphComment;
   auto ExpectedTextComment = std::make_unique<CommentInfo>();
-  ExpectedTextComment->Kind = "TextComment";
+  ExpectedTextComment->Kind = CommentKind::CK_TextComment;
   ExpectedTextComment->Text = "This is a text comment.";
   ExpectedParagraphComment->Children.push_back(std::move(ExpectedTextComment));
   ExpectedFullComment->Children.push_back(std::move(ExpectedParagraphComment));
diff --git a/clang-tools-extra/unittests/clang-doc/YAMLGeneratorTest.cpp b/clang-tools-extra/unittests/clang-doc/YAMLGeneratorTest.cpp
index 407a503e2d43a..a9e7c6413cf13 100644
--- a/clang-tools-extra/unittests/clang-doc/YAMLGeneratorTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/YAMLGeneratorTest.cpp
@@ -91,12 +91,12 @@ TEST(YAMLGeneratorTest, emitRecordYAML) {
 
   // Member documentation.
   CommentInfo TopComment;
-  TopComment.Kind = "FullComment";
+  TopComment.Kind = CommentKind::CK_FullComment;
   TopComment.Children.emplace_back(std::make_unique<CommentInfo>());
   CommentInfo *Brief = TopComment.Children.back().get();
-  Brief->Kind = "ParagraphComment";
+  Brief->Kind = CommentKind::CK_ParagraphComment;
   Brief->Children.emplace_back(std::make_unique<CommentInfo>());
-  Brief->Children.back()->Kind = "TextComment";
+  Brief->Children.back()->Kind = CommentKind::CK_TextComment;
   Brief->Children.back()->Name = "ParagraphComment";
   Brief->Children.back()->Text = "Value of the thing.";
   I.Members.back().Description.push_back(std::move(TopComment));
@@ -150,11 +150,11 @@ IsTypeDef:       true
     Name:            'X'
     Access:          Private
     Description:
-      - Kind:            'FullComment'
+      - Kind:            FullComment
         Children:
-          - Kind:            'ParagraphComment'
+          - Kind:            ParagraphComment
             Children:
-              - Kind:            'TextComment'
+              - Kind:            TextComment
                 Text:            'Value of the thing.'
                 Name:            'ParagraphComment'
 Bases:
@@ -375,103 +375,105 @@ TEST(YAMLGeneratorTest, emitCommentYAML) {
   I.Access = AccessSpecifier::AS_none;
 
   CommentInfo Top;
-  Top.Kind = "FullComment";
+  Top.Kind = CommentKind::CK_FullComment;
 
   Top.Children.emplace_back(std::make_unique<CommentInfo>());
   CommentInfo *BlankLine = Top.Children.back().get();
-  BlankLine->Kind = "ParagraphComment";
+  BlankLine->Kind = CommentKind::CK_ParagraphComment;
   BlankLine->Children.emplace_back(std::make_unique<CommentInfo>());
-  BlankLine->Children.back()->Kind = "TextComment";
+  BlankLine->Children.back()->Kind = CommentKind::CK_TextComment;
 
   Top.Children.emplace_back(std::make_unique<CommentInfo>());
   CommentInfo *Brief = Top.Children.back().get();
-  Brief->Kind = "ParagraphComment";
+  Brief->Kind = CommentKind::CK_ParagraphComment;
   Brief->Children.emplace_back(std::make_unique<CommentInfo>());
-  Brief->Children.back()->Kind = "TextComment";
+  Brief->Children.back()->Kind = CommentKind::CK_TextComment;
   Brief->Children.back()->Name = "ParagraphComment";
   Brief->Children.back()->Text = " Brief description.";
 
   Top.Children.emplace_back(std::make_unique<CommentInfo>());
   CommentInfo *Extended = Top.Children.back().get();
-  Extended->Kind = "ParagraphComment";
+  Extended->Kind = CommentKind::CK_ParagraphComment;
   Extended->Children.emplace_back(std::make_unique<CommentInfo>());
-  Extended->Children.back()->Kind = "TextComment";
+  Extended->Children.back()->Kind = CommentKind::CK_TextComment;
   Extended->Children.back()->Text = " Extended description that";
   Extended->Children.emplace_back(std::make_unique<CommentInfo>());
-  Extended->Children.back()->Kind = "TextComment";
+  Extended->Children.back()->Kind = CommentKind::CK_TextComment;
   Extended->Children.back()->Text = " continues onto the next line.";
 
   Top.Children.emplace_back(std::make_unique<CommentInfo>());
   CommentInfo *HTML = Top.Children.back().get();
-  HTML->Kind = "ParagraphComment";
+  HTML->Kind = CommentKind::CK_ParagraphComment;
   HTML->Children.emplace_back(std::make_unique<CommentInfo>());
-  HTML->Children.back()->Kind = "TextComment";
+  HTML->Children.back()->Kind = CommentKind::CK_TextComment;
   HTML->Children.emplace_back(std::make_unique<CommentInfo>());
-  HTML->Children.back()->Kind = "HTMLStartTagComment";
+  HTML->Children.back()->Kind = CommentKind::CK_HTMLStartTagComment;
   HTML->Children.back()->Name = "ul";
   HTML->Children.back()->AttrKeys.emplace_back("class");
   HTML->Children.back()->AttrValues.emplace_back("test");
   HTML->Children.emplace_back(std::make_unique<CommentInfo>());
-  HTML->Children.back()->Kind = "HTMLStartTagComment";
+  HTML->Children.back()->Kind = CommentKind::CK_HTMLStartTagComment;
   HTML->Children.back()->Name = "li";
   HTML->Children.emplace_back(std::make_unique<CommentInfo>());
-  HTML->Children.back()->Kind = "TextComment";
+  HTML->Children.back()->Kind = CommentKind::CK_TextComment;
   HTML->Children.back()->Text = " Testing.";
   HTML->Children.emplace_back(std::make_unique<CommentInfo>());
-  HTML->Children.back()->Kind = "HTMLEndTagComment";
+  HTML->Children.back()->Kind = CommentKind::CK_HTMLEndTagComment;
   HTML->Children.back()->Name = "ul";
   HTML->Children.back()->SelfClosing = true;
 
   Top.Children.emplace_back(std::make_unique<CommentInfo>());
   CommentInfo *Verbatim = Top.Children.back().get();
-  Verbatim->Kind = "VerbatimBlockComment";
+  Verbatim->Kind = CommentKind::CK_VerbatimBlockComment;
   Verbatim->Name = "verbatim";
   Verbatim->CloseName = "endverbatim";
   Verbatim->Children.emplace_back(std::make_unique<CommentInfo>());
-  Verbatim->Children.back()->Kind = "VerbatimBlockLineComment";
+  Verbatim->Children.back()->Kind = CommentKind::CK_VerbatimBlockLineComment;
   Verbatim->Children.back()->Text = " The description continues.";
 
   Top.Children.emplace_back(std::make_unique<CommentInfo>());
   CommentInfo *ParamOut = Top.Children.back().get();
-  ParamOut->Kind = "ParamCommandComment";
+  ParamOut->Kind = CommentKind::CK_ParamCommandComment;
   ParamOut->Direction = "[out]";
   ParamOut->ParamName = "I";
   ParamOut->Explicit = true;
   ParamOut->Children.emplace_back(std::make_unique<CommentInfo>());
-  ParamOut->Children.back()->Kind = "ParagraphComment";
+  ParamOut->Children.back()->Kind = CommentKind::CK_ParagraphComment;
   ParamOut->Children.back()->Children.emplace_back(
       std::make_unique<CommentInfo>());
-  ParamOut->Children.back()->Children.back()->Kind = "TextComment";
+  ParamOut->Children.back()->Children.back()->Kind =
+      CommentKind::CK_TextComment;
   ParamOut->Children.back()->Children.emplace_back(
       std::make_unique<CommentInfo>());
-  ParamOut->Children.back()->Children.back()->Kind = "TextComment";
+  ParamOut->Children.back()->Children.back()->Kind =
+      CommentKind::CK_TextComment;
   ParamOut->Children.back()->Children.back()->Text = " is a parameter.";
 
   Top.Children.emplace_back(std::make_unique<CommentInfo>());
   CommentInfo *ParamIn = Top.Children.back().get();
-  ParamIn->Kind = "ParamCommandComment";
+  ParamIn->Kind = CommentKind::CK_ParamCommandComment;
   ParamIn->Direction = "[in]";
   ParamIn->ParamName = "J";
   ParamIn->Children.emplace_back(std::make_unique<CommentInfo>());
-  ParamIn->Children.back()->Kind = "ParagraphComment";
+  ParamIn->Children.back()->Kind = CommentKind::CK_ParagraphComment;
   ParamIn->Children.back()->Children.emplace_back(
       std::make_unique<CommentInfo>());
-  ParamIn->Children.back()->Children.back()->Kind = "TextComment";
+  ParamIn->Children.back()->Children.back()->Kind = CommentKind::CK_TextComment;
   ParamIn->Children.back()->Children.back()->Text = " is a parameter.";
   ParamIn->Children.back()->Children.emplace_back(
       std::make_unique<CommentInfo>());
-  ParamIn->Children.back()->Children.back()->Kind = "TextComment";
+  ParamIn->Children.back()->Children.back()->Kind = CommentKind::CK_TextComment;
 
   Top.Children.emplace_back(std::make_unique<CommentInfo>());
   CommentInfo *Return = Top.Children.back().get();
-  Return->Kind = "BlockCommandComment";
+  Return->Kind = CommentKind::CK_BlockCommandComment;
   Return->Name = "return";
   Return->Explicit = true;
   Return->Children.emplace_back(std::make_unique<CommentInfo>());
-  Return->Children.back()->Kind = "ParagraphComment";
+  Return->Children.back()->Kind = CommentKind::CK_ParagraphComment;
   Return->Children.back()->Children.emplace_back(
       std::make_unique<CommentInfo>());
-  Return->Children.back()->Children.back()->Kind = "TextComment";
+  Return->Children.back()->Children.back()->Kind = CommentKind::CK_TextComment;
   Return->Children.back()->Children.back()->Text = "void";
 
   I.Description.emplace_back(std::move(Top));
@@ -487,70 +489,70 @@ TEST(YAMLGeneratorTest, emitCommentYAML) {
 USR:             '0000000000000000000000000000000000000000'
 Name:            'f'
 Description:
-  - Kind:            'FullComment'
+  - Kind:            FullComment
     Children:
-      - Kind:            'ParagraphComment'
+      - Kind:            ParagraphComment
         Children:
-          - Kind:            'TextComment'
-      - Kind:            'ParagraphComment'
+          - Kind:            TextComment
+      - Kind:            ParagraphComment
         Children:
-          - Kind:            'TextComment'
+          - Kind:            TextComment
             Text:            ' Brief description.'
             Name:            'ParagraphComment'
-      - Kind:            'ParagraphComment'
+      - Kind:            ParagraphComment
         Children:
-          - Kind:            'TextComment'
+          - Kind:            TextComment
             Text:            ' Extended description that'
-          - Kind:            'TextComment'
+          - Kind:            TextComment
             Text:            ' continues onto the next line.'
-      - Kind:            'ParagraphComment'
+      - Kind:            ParagraphComment
         Children:
-          - Kind:            'TextComment'
-          - Kind:            'HTMLStartTagComment'
+          - Kind:            TextComment
+          - Kind:            HTMLStartTagComment
             Name:            'ul'
             AttrKeys:
               - 'class'
             AttrValues:
               - 'test'
-          - Kind:            'HTMLStartTagComment'
+          - Kind:            HTMLStartTagComment
             Name:            'li'
-          - Kind:            'TextComment'
+          - Kind:            TextComment
             Text:            ' Testing.'
-          - Kind:            'HTMLEndTagComment'
+          - Kind:            HTMLEndTagComment
             Name:            'ul'
             SelfClosing:     true
-      - Kind:            'VerbatimBlockComment'
+      - Kind:            VerbatimBlockComment
         Name:            'verbatim'
         CloseName:       'endverbatim'
         Children:
-          - Kind:            'VerbatimBlockLineComment'
+          - Kind:            VerbatimBlockLineComment
             Text:            ' The description continues.'
-      - Kind:            'ParamCommandComment'
+      - Kind:            ParamCommandComment
         Direction:       '[out]'
         ParamName:       'I'
         Explicit:        true
         Children:
-          - Kind:            'ParagraphComment'
+          - Kind:            ParagraphComment
             Children:
-              - Kind:            'TextComment'
-              - Kind:            'TextComment'
+              - Kind:            TextComment
+              - Kind:            TextComment
                 Text:            ' is a parameter.'
-      - Kind:            'ParamCommandComment'
+      - Kind:            ParamCommandComment
         Direction:       '[in]'
         ParamName:       'J'
         Children:
-          - Kind:            'ParagraphComment'
+          - Kind:            ParagraphComment
             Children:
-              - Kind:            'TextComment'
+              - Kind:            TextComment
                 Text:            ' is a parameter.'
-              - Kind:            'TextComment'
-      - Kind:            'BlockCommandComment'
+              - Kind:            TextComment
+      - Kind:            BlockCommandComment
         Name:            'return'
         Explicit:        true
         Children:
-          - Kind:            'ParagraphComment'
+          - Kind:            ParagraphComment
             Children:
-              - Kind:            'TextComment'
+              - Kind:            TextComment
                 Text:            'void'
 DefLocation:
   LineNumber:      10

>From db2573da15298451718b537c6c6ed731eff8403e Mon Sep 17 00:00:00 2001
From: Samarth Narang <snarang at umass.edu>
Date: Sat, 31 May 2025 11:19:56 -0400
Subject: [PATCH 5/8] Add lit test

---
 .../test/clang-doc/Inputs/html-tag-comment.yaml | 12 ++++++++++++
 .../test/clang-doc/html-tag-comment.cpp         | 17 +++++++++++++++++
 2 files changed, 29 insertions(+)
 create mode 100644 clang-tools-extra/test/clang-doc/Inputs/html-tag-comment.yaml
 create mode 100644 clang-tools-extra/test/clang-doc/html-tag-comment.cpp

diff --git a/clang-tools-extra/test/clang-doc/Inputs/html-tag-comment.yaml b/clang-tools-extra/test/clang-doc/Inputs/html-tag-comment.yaml
new file mode 100644
index 0000000000000..875e9b5947f47
--- /dev/null
+++ b/clang-tools-extra/test/clang-doc/Inputs/html-tag-comment.yaml
@@ -0,0 +1,12 @@
+---
+Name:            'withHtmlTag'
+Description:
+  - Kind:          FullComment
+    Children:
+      - Kind:        VerbatimBlockComment
+        Name:        'verbatim'
+        CloseName:   'endverbatim'
+        Children:
+          - Kind:      VerbatimBlockLineComment
+            Text:      '<ul class="test"><li> Testing. </li></ul>'
+...
diff --git a/clang-tools-extra/test/clang-doc/html-tag-comment.cpp b/clang-tools-extra/test/clang-doc/html-tag-comment.cpp
new file mode 100644
index 0000000000000..97e2e3b22e368
--- /dev/null
+++ b/clang-tools-extra/test/clang-doc/html-tag-comment.cpp
@@ -0,0 +1,17 @@
+// RUN: clang-doc --public --format=yaml -p %T %s -output=%t
+// RUN: FileCheck --input-file=%S/Inputs/html-tag-comment.yaml %s
+
+/// \verbatim <ul class="test"><li> Testing. </li></ul> \endverbatim
+void withHtmlTag() {}
+// CHECK: ---
+// CHECK: Name:            'withHtmlTag'
+// CHECK: Description:
+// CHECK:   - Kind:          FullComment
+// CHECK:     Children:
+// CHECK:       - Kind:        VerbatimBlockComment
+// CHECK:         Name:        'verbatim'
+// CHECK:         CloseName:   'endverbatim'
+// CHECK:         Children:
+// CHECK:           - Kind:      VerbatimBlockLineComment
+// CHECK:             Text:      '<ul class="test"><li> Testing. </li></ul>'
+// CHECK: ...

>From 231e42240a0401ae8e8f9a5ec679352f68b70fe3 Mon Sep 17 00:00:00 2001
From: Samarth Narang <snarang at umass.edu>
Date: Sun, 1 Jun 2025 08:47:48 -0400
Subject: [PATCH 6/8] Add support for different CommentKind types in
 HTMLMustacheGenerator Change existing handling from if/else to switch-case
 for better clarity and extensibility.

---
 .../clang-doc/HTMLMustacheGenerator.cpp       | 116 ++++++++++++++----
 1 file changed, 92 insertions(+), 24 deletions(-)

diff --git a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
index 95306eee12f31..0b39c4271db22 100644
--- a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
+++ b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
@@ -198,39 +198,107 @@ static json::Value extractValue(const TypedefInfo &I) {
 }
 
 static json::Value extractValue(const CommentInfo &I) {
-  assert((I.Kind == CommentKind::CK_BlockCommandComment ||
-          I.Kind == CommentKind::CK_FullComment ||
-          I.Kind == CommentKind::CK_ParagraphComment ||
-          I.Kind == CommentKind::CK_TextComment) &&
-         "Unknown Comment type in CommentInfo.");
-
   Object Obj = Object();
   json::Value Child = Object();
 
-  // TextComment has no children, so return it.
-  if (I.Kind == CommentKind::CK_TextComment) {
-    Obj.insert({"TextComment", I.Text});
+  json::Value ChildArr = Array();
+  auto &CARef = *ChildArr.getAsArray();
+  CARef.reserve(I.Children.size());
+  for (const auto &C : I.Children) {
+    CARef.emplace_back(extractValue(*C));
+  }
+
+  switch (I.Kind) {
+  case CommentKind::CK_TextComment: {
+    Obj.insert({commentKindToString(I.Kind), I.Text});
     return Obj;
   }
 
-  // BlockCommandComment needs to generate a Command key.
-  if (I.Kind == CommentKind::CK_BlockCommandComment)
+  case CommentKind::CK_BlockCommandComment: {
     Child.getAsObject()->insert({"Command", I.Name});
+    Child.getAsObject()->insert({"Children", ChildArr});
+    Obj.insert({commentKindToString(I.Kind), Child});
+    return Obj;
+  }
 
-  // Use the same handling for everything else.
-  // Only valid for:
-  //  - BlockCommandComment
-  //  - FullComment
-  //  - ParagraphComment
-  json::Value ChildArr = Array();
-  auto &CARef = *ChildArr.getAsArray();
-  CARef.reserve(I.Children.size());
-  for (const auto &C : I.Children)
-    CARef.emplace_back(extractValue(*C));
-  Child.getAsObject()->insert({"Children", ChildArr});
-  Obj.insert({commentKindToString(I.Kind), Child});
+  case CommentKind::CK_InlineCommandComment: {
+    json::Value ArgsArr = Array();
+    for (const auto &Arg : I.Args) {
+      ArgsArr.getAsArray()->emplace_back(Arg);
+    }
+    Child.getAsObject()->insert({"Command", I.Name});
+    Child.getAsObject()->insert({"Args", ArgsArr});
+    Child.getAsObject()->insert({"Children", ChildArr});
+    Obj.insert({commentKindToString(I.Kind), Child});
+    return Obj;
+  }
 
-  return Obj;
+  case CommentKind::CK_ParamCommandComment:
+  case CommentKind::CK_TParamCommandComment: {
+    Child.getAsObject()->insert({"ParamName", I.ParamName});
+    Child.getAsObject()->insert({"Direction", I.Direction});
+    Child.getAsObject()->insert({"Explicit", I.Explicit});
+    Child.getAsObject()->insert({"Children", ChildArr});
+    Obj.insert({commentKindToString(I.Kind), Child});
+    return Obj;
+  }
+
+  case CommentKind::CK_VerbatimBlockComment: {
+    Child.getAsObject()->insert({"Text", I.Text});
+    Child.getAsObject()->insert({"Children", ChildArr});
+    if (!I.CloseName.empty())
+      Child.getAsObject()->insert({"CloseName", I.CloseName});
+    Obj.insert({commentKindToString(I.Kind), Child});
+    return Obj;
+  }
+
+  case CommentKind::CK_VerbatimBlockLineComment:
+  case CommentKind::CK_VerbatimLineComment: {
+    Child.getAsObject()->insert({"Text", I.Text});
+    Child.getAsObject()->insert({"Children", ChildArr});
+    Obj.insert({commentKindToString(I.Kind), Child});
+    return Obj;
+  }
+
+  case CommentKind::CK_HTMLStartTagComment: {
+    json::Value AttrKeysArray = json::Array();
+    for (const auto &Key : I.AttrKeys)
+      AttrKeysArray.getAsArray()->emplace_back(Key);
+
+    json::Value AttrValuesArray = json::Array();
+    for (const auto &Val : I.AttrValues)
+      AttrValuesArray.getAsArray()->emplace_back(Val);
+
+    Child.getAsObject()->insert({"Name", I.Name});
+    Child.getAsObject()->insert({"SelfClosing", I.SelfClosing});
+    Child.getAsObject()->insert({"AttrKeys", AttrKeysArray});
+    Child.getAsObject()->insert({"AttrValues", AttrValuesArray});
+    Child.getAsObject()->insert({"Children", ChildArr});
+    Obj.insert({commentKindToString(I.Kind), Child});
+    return Obj;
+  }
+
+  case CommentKind::CK_HTMLEndTagComment: {
+    Child.getAsObject()->insert({"Name", I.Name});
+    Child.getAsObject()->insert({"Children", ChildArr});
+    Obj.insert({commentKindToString(I.Kind), Child});
+    return Obj;
+  }
+
+  case CommentKind::CK_FullComment:
+  case CommentKind::CK_ParagraphComment: {
+    Child.getAsObject()->insert({"Children", ChildArr});
+    Obj.insert({commentKindToString(I.Kind), Child});
+    return Obj;
+  }
+
+  case CommentKind::CK_Unknown: {
+    Obj.insert({commentKindToString(I.Kind), I.Text});
+    return Obj;
+  }
+
+    llvm_unreachable("Unknown comment kind encountered.");
+  }
 }
 
 static void maybeInsertLocation(std::optional<Location> Loc,

>From e7d33b22670f02f8cad42b65f983a1dbdf352411 Mon Sep 17 00:00:00 2001
From: Samarth Narang <snarang at umass.edu>
Date: Sun, 1 Jun 2025 09:13:09 -0400
Subject: [PATCH 7/8] Remove tests

---
 .../test/clang-doc/Inputs/html-tag-comment.yaml | 12 ------------
 .../test/clang-doc/html-tag-comment.cpp         | 17 -----------------
 2 files changed, 29 deletions(-)
 delete mode 100644 clang-tools-extra/test/clang-doc/Inputs/html-tag-comment.yaml
 delete mode 100644 clang-tools-extra/test/clang-doc/html-tag-comment.cpp

diff --git a/clang-tools-extra/test/clang-doc/Inputs/html-tag-comment.yaml b/clang-tools-extra/test/clang-doc/Inputs/html-tag-comment.yaml
deleted file mode 100644
index 875e9b5947f47..0000000000000
--- a/clang-tools-extra/test/clang-doc/Inputs/html-tag-comment.yaml
+++ /dev/null
@@ -1,12 +0,0 @@
----
-Name:            'withHtmlTag'
-Description:
-  - Kind:          FullComment
-    Children:
-      - Kind:        VerbatimBlockComment
-        Name:        'verbatim'
-        CloseName:   'endverbatim'
-        Children:
-          - Kind:      VerbatimBlockLineComment
-            Text:      '<ul class="test"><li> Testing. </li></ul>'
-...
diff --git a/clang-tools-extra/test/clang-doc/html-tag-comment.cpp b/clang-tools-extra/test/clang-doc/html-tag-comment.cpp
deleted file mode 100644
index 97e2e3b22e368..0000000000000
--- a/clang-tools-extra/test/clang-doc/html-tag-comment.cpp
+++ /dev/null
@@ -1,17 +0,0 @@
-// RUN: clang-doc --public --format=yaml -p %T %s -output=%t
-// RUN: FileCheck --input-file=%S/Inputs/html-tag-comment.yaml %s
-
-/// \verbatim <ul class="test"><li> Testing. </li></ul> \endverbatim
-void withHtmlTag() {}
-// CHECK: ---
-// CHECK: Name:            'withHtmlTag'
-// CHECK: Description:
-// CHECK:   - Kind:          FullComment
-// CHECK:     Children:
-// CHECK:       - Kind:        VerbatimBlockComment
-// CHECK:         Name:        'verbatim'
-// CHECK:         CloseName:   'endverbatim'
-// CHECK:         Children:
-// CHECK:           - Kind:      VerbatimBlockLineComment
-// CHECK:             Text:      '<ul class="test"><li> Testing. </li></ul>'
-// CHECK: ...

>From 8760ea823b072e73b48c1acbbb744dcfb4ed3e57 Mon Sep 17 00:00:00 2001
From: Samarth Narang <snarang at umass.edu>
Date: Sun, 1 Jun 2025 19:02:42 -0400
Subject: [PATCH 8/8] Switch stringToCommentKind() to use StringMap lookup

---
 .../clang-doc/Representation.cpp              | 44 +++++++++----------
 1 file changed, 20 insertions(+), 24 deletions(-)

diff --git a/clang-tools-extra/clang-doc/Representation.cpp b/clang-tools-extra/clang-doc/Representation.cpp
index 9fb3839419731..b10e018311b9b 100644
--- a/clang-tools-extra/clang-doc/Representation.cpp
+++ b/clang-tools-extra/clang-doc/Representation.cpp
@@ -20,6 +20,7 @@
 //
 //===----------------------------------------------------------------------===//
 #include "Representation.h"
+#include "llvm/ADT/StringMap.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/Path.h"
 
@@ -27,30 +28,25 @@ namespace clang {
 namespace doc {
 
 CommentKind stringToCommentKind(llvm::StringRef KindStr) {
-  if (KindStr == "FullComment")
-    return CommentKind::CK_FullComment;
-  if (KindStr == "ParagraphComment")
-    return CommentKind::CK_ParagraphComment;
-  if (KindStr == "TextComment")
-    return CommentKind::CK_TextComment;
-  if (KindStr == "InlineCommandComment")
-    return CommentKind::CK_InlineCommandComment;
-  if (KindStr == "HTMLStartTagComment")
-    return CommentKind::CK_HTMLStartTagComment;
-  if (KindStr == "HTMLEndTagComment")
-    return CommentKind::CK_HTMLEndTagComment;
-  if (KindStr == "BlockCommandComment")
-    return CommentKind::CK_BlockCommandComment;
-  if (KindStr == "ParamCommandComment")
-    return CommentKind::CK_ParamCommandComment;
-  if (KindStr == "TParamCommandComment")
-    return CommentKind::CK_TParamCommandComment;
-  if (KindStr == "VerbatimBlockComment")
-    return CommentKind::CK_VerbatimBlockComment;
-  if (KindStr == "VerbatimBlockLineComment")
-    return CommentKind::CK_VerbatimBlockLineComment;
-  if (KindStr == "VerbatimLineComment")
-    return CommentKind::CK_VerbatimLineComment;
+  static const llvm::StringMap<CommentKind> KindMap = {
+      {"FullComment", CommentKind::CK_FullComment},
+      {"ParagraphComment", CommentKind::CK_ParagraphComment},
+      {"TextComment", CommentKind::CK_TextComment},
+      {"InlineCommandComment", CommentKind::CK_InlineCommandComment},
+      {"HTMLStartTagComment", CommentKind::CK_HTMLStartTagComment},
+      {"HTMLEndTagComment", CommentKind::CK_HTMLEndTagComment},
+      {"BlockCommandComment", CommentKind::CK_BlockCommandComment},
+      {"ParamCommandComment", CommentKind::CK_ParamCommandComment},
+      {"TParamCommandComment", CommentKind::CK_TParamCommandComment},
+      {"VerbatimBlockComment", CommentKind::CK_VerbatimBlockComment},
+      {"VerbatimBlockLineComment", CommentKind::CK_VerbatimBlockLineComment},
+      {"VerbatimLineComment", CommentKind::CK_VerbatimLineComment},
+  };
+
+  auto It = KindMap.find(KindStr);
+  if (It != KindMap.end()) {
+    return It->second;
+  }
   return CommentKind::CK_Unknown;
 }
 



More information about the cfe-commits mailing list