[clang] [clang-tools-extra] [clangd] Add missing SymbolKind cases to YAML serialization (PR #222070)

Andre Sun via cfe-commits cfe-commits at lists.llvm.org
Fri Sep 11 06:50:13 PDT 2026


https://github.com/and2049 updated https://github.com/llvm/llvm-project/pull/222070

>From 924d1761f09cf6b9c76218140111c4435b5c8847 Mon Sep 17 00:00:00 2001
From: andre sun <andsun9999 at gmail.com>
Date: Tue, 8 Sep 2026 13:06:28 -0400
Subject: [PATCH 1/3] [clangd] Add missing SymbolKind cases to YAML
 serialization

Add missing enum spellings, remove the duplicate Function entry, and
test round-tripping all symbol kinds. This fixes invalid YAML output
when indexing C++20 concepts.

Fixes #206875
---
 .../clangd/index/YAMLSerialization.cpp        |  6 +++-
 .../clangd/unittests/SerializationTests.cpp   | 28 +++++++++++++++++++
 clang-tools-extra/docs/ReleaseNotes.md        |  4 +++
 3 files changed, 37 insertions(+), 1 deletion(-)

diff --git a/clang-tools-extra/clangd/index/YAMLSerialization.cpp b/clang-tools-extra/clangd/index/YAMLSerialization.cpp
index 4d6b5822ece72..e042877a469c6 100644
--- a/clang-tools-extra/clangd/index/YAMLSerialization.cpp
+++ b/clang-tools-extra/clangd/index/YAMLSerialization.cpp
@@ -265,11 +265,11 @@ template <> struct ScalarEnumerationTraits<SymbolKind> {
 #define DEFINE_ENUM(name) IO.enumCase(Value, #name, SymbolKind::name)
 
     DEFINE_ENUM(Unknown);
-    DEFINE_ENUM(Function);
     DEFINE_ENUM(Module);
     DEFINE_ENUM(Namespace);
     DEFINE_ENUM(NamespaceAlias);
     DEFINE_ENUM(Macro);
+    DEFINE_ENUM(IncludeDirective);
     DEFINE_ENUM(Enum);
     DEFINE_ENUM(Struct);
     DEFINE_ENUM(Class);
@@ -292,6 +292,10 @@ template <> struct ScalarEnumerationTraits<SymbolKind> {
     DEFINE_ENUM(ConversionFunction);
     DEFINE_ENUM(Parameter);
     DEFINE_ENUM(Using);
+    DEFINE_ENUM(TemplateTypeParm);
+    DEFINE_ENUM(TemplateTemplateParm);
+    DEFINE_ENUM(NonTypeTemplateParm);
+    DEFINE_ENUM(Concept);
 
 #undef DEFINE_ENUM
   }
diff --git a/clang-tools-extra/clangd/unittests/SerializationTests.cpp b/clang-tools-extra/clangd/unittests/SerializationTests.cpp
index 5108e653c36a0..1215e897aab61 100644
--- a/clang-tools-extra/clangd/unittests/SerializationTests.cpp
+++ b/clang-tools-extra/clangd/unittests/SerializationTests.cpp
@@ -9,6 +9,7 @@
 #include "FindSymbols.h"
 #include "Headers.h"
 #include "RIFF.h"
+#include "TestIndex.h"
 #include "index/Serialization.h"
 #include "support/Logger.h"
 #include "clang/Tooling/CompilationDatabase.h"
@@ -260,6 +261,33 @@ TEST(SerializationTest, BinaryConversions) {
               UnorderedElementsAreArray(yamlFromRelations(*In->Relations)));
 }
 
+// Every SymbolKind must have a YAML spelling, otherwise writing the index
+// produces invalid YAML (or aborts with assertions enabled).
+TEST(SerializationTest, YAMLSymbolKindRoundTrip) {
+  SymbolSlab::Builder Builder;
+  for (unsigned K = 0; K <= static_cast<unsigned>(index::SymbolKind::Concept);
+       ++K) {
+    std::string Name = "Sym" + std::to_string(K);
+    Symbol Sym = symbol(Name);
+    Sym.SymInfo.Kind = static_cast<index::SymbolKind>(K);
+    Builder.insert(Sym);
+  }
+  SymbolSlab Symbols = std::move(Builder).build();
+
+  IndexFileOut Out;
+  Out.Symbols = &Symbols;
+  Out.Format = IndexFileFormat::YAML;
+
+  auto In = readIndexFile(llvm::to_string(Out));
+  ASSERT_TRUE(bool(In)) << In.takeError();
+  ASSERT_TRUE(In->Symbols);
+  for (const Symbol &Sym : Symbols) {
+    auto It = In->Symbols->find(Sym.ID);
+    ASSERT_NE(It, In->Symbols->end()) << Sym.Name;
+    EXPECT_EQ(It->SymInfo.Kind, Sym.SymInfo.Kind) << Sym.Name;
+  }
+}
+
 TEST(SerializationTest, SrcsTest) {
   auto In = readIndexFile(YAML);
   EXPECT_TRUE(bool(In)) << In.takeError();
diff --git a/clang-tools-extra/docs/ReleaseNotes.md b/clang-tools-extra/docs/ReleaseNotes.md
index 4523e0f78035b..b5d1e4ecd389d 100644
--- a/clang-tools-extra/docs/ReleaseNotes.md
+++ b/clang-tools-extra/docs/ReleaseNotes.md
@@ -90,6 +90,10 @@ infrastructure are described first, followed by tool-specific sections.
 
 #### Miscellaneous
 
+- Fixed `clangd-indexer --format=yaml` emitting invalid YAML when indexing
+  C++20 concepts.
+  ([#206875](https://github.com/llvm/llvm-project/issues/206875))
+
 ### Improvements to clang-doc
 
 ### Improvements to clang-query

>From 8cdb409e499db512680e51cf2cb3b1268bcb69c4 Mon Sep 17 00:00:00 2001
From: andre sun <andsun9999 at gmail.com>
Date: Wed, 9 Sep 2026 17:42:01 -0400
Subject: [PATCH 2/3] [clangd] Use a SymbolKind end marker in the YAML
 round-trip test

Add SymbolKind::Count so the test covers future kinds automatically.
---
 clang-tools-extra/clangd/CodeComplete.cpp                 | 2 ++
 clang-tools-extra/clangd/Protocol.cpp                     | 2 ++
 clang-tools-extra/clangd/Quality.cpp                      | 2 ++
 clang-tools-extra/clangd/unittests/SerializationTests.cpp | 4 ++--
 clang/include/clang/Index/IndexSymbol.h                   | 3 +++
 clang/lib/Index/IndexSymbol.cpp                           | 2 ++
 clang/tools/libclang/CXIndexDataConsumer.cpp              | 2 ++
 7 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/clang-tools-extra/clangd/CodeComplete.cpp b/clang-tools-extra/clangd/CodeComplete.cpp
index 80091d3a48b33..71a5d2beb9afa 100644
--- a/clang-tools-extra/clangd/CodeComplete.cpp
+++ b/clang-tools-extra/clangd/CodeComplete.cpp
@@ -158,6 +158,8 @@ toCompletionItemKind(index::SymbolKind Kind,
     return CompletionItemKind::TypeParameter;
   case SK::Concept:
     return CompletionItemKind::Interface;
+  case SK::Count:
+    break;
   }
   llvm_unreachable("Unhandled clang::index::SymbolKind.");
 }
diff --git a/clang-tools-extra/clangd/Protocol.cpp b/clang-tools-extra/clangd/Protocol.cpp
index c22ada45d44cf..74b5932330a55 100644
--- a/clang-tools-extra/clangd/Protocol.cpp
+++ b/clang-tools-extra/clangd/Protocol.cpp
@@ -371,6 +371,8 @@ SymbolKind indexSymbolKindToSymbolKind(const index::SymbolInfo &Info) {
     return SymbolKind::TypeParameter;
   case index::SymbolKind::Concept:
     return SymbolKind::Interface;
+  case index::SymbolKind::Count:
+    break;
   }
   llvm_unreachable("invalid symbol kind");
 }
diff --git a/clang-tools-extra/clangd/Quality.cpp b/clang-tools-extra/clangd/Quality.cpp
index dc4afe18cb354..9ff99a3269e63 100644
--- a/clang-tools-extra/clangd/Quality.cpp
+++ b/clang-tools-extra/clangd/Quality.cpp
@@ -150,6 +150,8 @@ categorize(const index::SymbolInfo &D) {
   case index::SymbolKind::Module:
   case index::SymbolKind::Unknown:
     return SymbolQualitySignals::Unknown;
+  case index::SymbolKind::Count:
+    break;
   }
   llvm_unreachable("Unknown index::SymbolKind");
 }
diff --git a/clang-tools-extra/clangd/unittests/SerializationTests.cpp b/clang-tools-extra/clangd/unittests/SerializationTests.cpp
index 1215e897aab61..be91bbdca3a53 100644
--- a/clang-tools-extra/clangd/unittests/SerializationTests.cpp
+++ b/clang-tools-extra/clangd/unittests/SerializationTests.cpp
@@ -265,8 +265,8 @@ TEST(SerializationTest, BinaryConversions) {
 // produces invalid YAML (or aborts with assertions enabled).
 TEST(SerializationTest, YAMLSymbolKindRoundTrip) {
   SymbolSlab::Builder Builder;
-  for (unsigned K = 0; K <= static_cast<unsigned>(index::SymbolKind::Concept);
-       ++K) {
+  for (auto K = static_cast<unsigned>(index::SymbolKind::Unknown);
+       K < static_cast<unsigned>(index::SymbolKind::Count); ++K) {
     std::string Name = "Sym" + std::to_string(K);
     Symbol Sym = symbol(Name);
     Sym.SymInfo.Kind = static_cast<index::SymbolKind>(K);
diff --git a/clang/include/clang/Index/IndexSymbol.h b/clang/include/clang/Index/IndexSymbol.h
index 4a7f523b885fc..011a1cbb8b954 100644
--- a/clang/include/clang/Index/IndexSymbol.h
+++ b/clang/include/clang/Index/IndexSymbol.h
@@ -60,6 +60,9 @@ enum class SymbolKind : uint8_t {
   NonTypeTemplateParm,
 
   Concept, /// C++20 concept.
+
+  /// One past the last valid kind. Must remain the last enumerator.
+  Count,
 };
 
 enum class SymbolLanguage : uint8_t {
diff --git a/clang/lib/Index/IndexSymbol.cpp b/clang/lib/Index/IndexSymbol.cpp
index 5131b321dedb2..154934ac1d412 100644
--- a/clang/lib/Index/IndexSymbol.cpp
+++ b/clang/lib/Index/IndexSymbol.cpp
@@ -570,6 +570,8 @@ StringRef index::getSymbolKindString(SymbolKind K) {
   case SymbolKind::NonTypeTemplateParm: return "non-type-template-param";
   case SymbolKind::Concept:
     return "concept";
+  case SymbolKind::Count:
+    break;
   }
   llvm_unreachable("invalid symbol kind");
 }
diff --git a/clang/tools/libclang/CXIndexDataConsumer.cpp b/clang/tools/libclang/CXIndexDataConsumer.cpp
index 8babcccf38c51..19ccec45ad2e5 100644
--- a/clang/tools/libclang/CXIndexDataConsumer.cpp
+++ b/clang/tools/libclang/CXIndexDataConsumer.cpp
@@ -1288,6 +1288,8 @@ static CXIdxEntityKind getEntityKindFromSymbolKind(SymbolKind K, SymbolLanguage
   case SymbolKind::Parameter: return CXIdxEntity_Variable;
   case SymbolKind::Concept:
     return CXIdxEntity_CXXConcept;
+  case SymbolKind::Count:
+    break;
   }
   llvm_unreachable("invalid symbol kind");
 }

>From 458a85199340b3d8f6d41a861ac4380addb54545 Mon Sep 17 00:00:00 2001
From: andre sun <andsun9999 at gmail.com>
Date: Fri, 11 Sep 2026 09:49:51 -0400
Subject: [PATCH 3/3] [clangd] Remove SymbolKind end marker and bound YAML test
 by Concept

---
 clang-tools-extra/clangd/CodeComplete.cpp                 | 2 --
 clang-tools-extra/clangd/Protocol.cpp                     | 2 --
 clang-tools-extra/clangd/Quality.cpp                      | 2 --
 clang-tools-extra/clangd/unittests/SerializationTests.cpp | 4 ++--
 clang/include/clang/Index/IndexSymbol.h                   | 3 ---
 clang/lib/Index/IndexSymbol.cpp                           | 2 --
 clang/tools/libclang/CXIndexDataConsumer.cpp              | 2 --
 7 files changed, 2 insertions(+), 15 deletions(-)

diff --git a/clang-tools-extra/clangd/CodeComplete.cpp b/clang-tools-extra/clangd/CodeComplete.cpp
index 71a5d2beb9afa..80091d3a48b33 100644
--- a/clang-tools-extra/clangd/CodeComplete.cpp
+++ b/clang-tools-extra/clangd/CodeComplete.cpp
@@ -158,8 +158,6 @@ toCompletionItemKind(index::SymbolKind Kind,
     return CompletionItemKind::TypeParameter;
   case SK::Concept:
     return CompletionItemKind::Interface;
-  case SK::Count:
-    break;
   }
   llvm_unreachable("Unhandled clang::index::SymbolKind.");
 }
diff --git a/clang-tools-extra/clangd/Protocol.cpp b/clang-tools-extra/clangd/Protocol.cpp
index 74b5932330a55..c22ada45d44cf 100644
--- a/clang-tools-extra/clangd/Protocol.cpp
+++ b/clang-tools-extra/clangd/Protocol.cpp
@@ -371,8 +371,6 @@ SymbolKind indexSymbolKindToSymbolKind(const index::SymbolInfo &Info) {
     return SymbolKind::TypeParameter;
   case index::SymbolKind::Concept:
     return SymbolKind::Interface;
-  case index::SymbolKind::Count:
-    break;
   }
   llvm_unreachable("invalid symbol kind");
 }
diff --git a/clang-tools-extra/clangd/Quality.cpp b/clang-tools-extra/clangd/Quality.cpp
index 9ff99a3269e63..dc4afe18cb354 100644
--- a/clang-tools-extra/clangd/Quality.cpp
+++ b/clang-tools-extra/clangd/Quality.cpp
@@ -150,8 +150,6 @@ categorize(const index::SymbolInfo &D) {
   case index::SymbolKind::Module:
   case index::SymbolKind::Unknown:
     return SymbolQualitySignals::Unknown;
-  case index::SymbolKind::Count:
-    break;
   }
   llvm_unreachable("Unknown index::SymbolKind");
 }
diff --git a/clang-tools-extra/clangd/unittests/SerializationTests.cpp b/clang-tools-extra/clangd/unittests/SerializationTests.cpp
index be91bbdca3a53..cbe2a9726f865 100644
--- a/clang-tools-extra/clangd/unittests/SerializationTests.cpp
+++ b/clang-tools-extra/clangd/unittests/SerializationTests.cpp
@@ -265,8 +265,8 @@ TEST(SerializationTest, BinaryConversions) {
 // produces invalid YAML (or aborts with assertions enabled).
 TEST(SerializationTest, YAMLSymbolKindRoundTrip) {
   SymbolSlab::Builder Builder;
-  for (auto K = static_cast<unsigned>(index::SymbolKind::Unknown);
-       K < static_cast<unsigned>(index::SymbolKind::Count); ++K) {
+  for (unsigned K = static_cast<unsigned>(index::SymbolKind::Unknown);
+       K <= static_cast<unsigned>(index::SymbolKind::Concept); ++K) {
     std::string Name = "Sym" + std::to_string(K);
     Symbol Sym = symbol(Name);
     Sym.SymInfo.Kind = static_cast<index::SymbolKind>(K);
diff --git a/clang/include/clang/Index/IndexSymbol.h b/clang/include/clang/Index/IndexSymbol.h
index 011a1cbb8b954..4a7f523b885fc 100644
--- a/clang/include/clang/Index/IndexSymbol.h
+++ b/clang/include/clang/Index/IndexSymbol.h
@@ -60,9 +60,6 @@ enum class SymbolKind : uint8_t {
   NonTypeTemplateParm,
 
   Concept, /// C++20 concept.
-
-  /// One past the last valid kind. Must remain the last enumerator.
-  Count,
 };
 
 enum class SymbolLanguage : uint8_t {
diff --git a/clang/lib/Index/IndexSymbol.cpp b/clang/lib/Index/IndexSymbol.cpp
index 154934ac1d412..5131b321dedb2 100644
--- a/clang/lib/Index/IndexSymbol.cpp
+++ b/clang/lib/Index/IndexSymbol.cpp
@@ -570,8 +570,6 @@ StringRef index::getSymbolKindString(SymbolKind K) {
   case SymbolKind::NonTypeTemplateParm: return "non-type-template-param";
   case SymbolKind::Concept:
     return "concept";
-  case SymbolKind::Count:
-    break;
   }
   llvm_unreachable("invalid symbol kind");
 }
diff --git a/clang/tools/libclang/CXIndexDataConsumer.cpp b/clang/tools/libclang/CXIndexDataConsumer.cpp
index 19ccec45ad2e5..8babcccf38c51 100644
--- a/clang/tools/libclang/CXIndexDataConsumer.cpp
+++ b/clang/tools/libclang/CXIndexDataConsumer.cpp
@@ -1288,8 +1288,6 @@ static CXIdxEntityKind getEntityKindFromSymbolKind(SymbolKind K, SymbolLanguage
   case SymbolKind::Parameter: return CXIdxEntity_Variable;
   case SymbolKind::Concept:
     return CXIdxEntity_CXXConcept;
-  case SymbolKind::Count:
-    break;
   }
   llvm_unreachable("invalid symbol kind");
 }



More information about the cfe-commits mailing list