https://github.com/HighCommander4 updated 
https://github.com/llvm/llvm-project/pull/181967

>From 49f4c893c165572a3d5f486fc50dae9c95c51f97 Mon Sep 17 00:00:00 2001
From: Nathan Ridge <[email protected]>
Date: Wed, 18 Feb 2026 01:38:36 -0500
Subject: [PATCH] [Index] Reflect in SymbolSubKind whether a typedef points to
 a struct or a class

Typedefs don't have their own symbol kind in the Language Server
Protocol, the choices are Struct or Class. For clangd to be able
to represent typedefs accurately in response to requests such as
workspace/symbol, it needs this information surfaced in
index::SymbolInfo.

Fixes https://github.com/clangd/clangd/issues/2253
---
 clang-tools-extra/clangd/FindSymbols.cpp      |  4 +--
 clang-tools-extra/clangd/Protocol.cpp         | 16 ++++++---
 clang-tools-extra/clangd/Protocol.h           |  2 +-
 clang-tools-extra/clangd/XRefs.cpp            |  4 +--
 .../clangd/unittests/FindSymbolsTests.cpp     | 22 ++++++++++++
 clang/include/clang/Index/IndexSymbol.h       |  3 +-
 clang/lib/Index/IndexSymbol.cpp               | 36 ++++++++++++++++---
 .../Index/Core/index-dependent-source.cpp     |  4 +--
 clang/test/Index/Core/index-source.cpp        |  4 +--
 9 files changed, 76 insertions(+), 19 deletions(-)

diff --git a/clang-tools-extra/clangd/FindSymbols.cpp 
b/clang-tools-extra/clangd/FindSymbols.cpp
index 7655a39d5ba1f..4afc7536df034 100644
--- a/clang-tools-extra/clangd/FindSymbols.cpp
+++ b/clang-tools-extra/clangd/FindSymbols.cpp
@@ -152,7 +152,7 @@ getWorkspaceSymbols(llvm::StringRef Query, int Limit,
 
     SymbolInformation Info;
     Info.name = (Sym.Name + Sym.TemplateSpecializationArgs).str();
-    Info.kind = indexSymbolKindToSymbolKind(Sym.SymInfo.Kind);
+    Info.kind = indexSymbolKindToSymbolKind(Sym.SymInfo);
     Info.location = *Loc;
     Scope.consume_back("::");
     Info.containerName = Scope.str();
@@ -233,7 +233,7 @@ std::optional<DocumentSymbol> declToSym(ASTContext &Ctx, 
const NamedDecl &ND) {
   index::SymbolInfo SymInfo = index::getSymbolInfo(&ND);
   // FIXME: This is not classifying constructors, destructors and operators
   // correctly.
-  SymbolKind SK = indexSymbolKindToSymbolKind(SymInfo.Kind);
+  SymbolKind SK = indexSymbolKindToSymbolKind(SymInfo);
 
   DocumentSymbol SI;
   SI.name = getSymbolName(Ctx, ND);
diff --git a/clang-tools-extra/clangd/Protocol.cpp 
b/clang-tools-extra/clangd/Protocol.cpp
index 560b8e00ed377..6860a7e40ad57 100644
--- a/clang-tools-extra/clangd/Protocol.cpp
+++ b/clang-tools-extra/clangd/Protocol.cpp
@@ -295,8 +295,8 @@ SymbolKind adjustKindToCapability(SymbolKind Kind,
   }
 }
 
-SymbolKind indexSymbolKindToSymbolKind(index::SymbolKind Kind) {
-  switch (Kind) {
+SymbolKind indexSymbolKindToSymbolKind(const index::SymbolInfo &Info) {
+  switch (Info.Kind) {
   // FIXME: for backwards compatibility, the include directive kind is treated
   // the same as Unknown
   case index::SymbolKind::IncludeDirective:
@@ -322,8 +322,16 @@ SymbolKind indexSymbolKindToSymbolKind(index::SymbolKind 
Kind) {
     return SymbolKind::Interface;
   case index::SymbolKind::Union:
     return SymbolKind::Class;
-  case index::SymbolKind::TypeAlias:
-    return SymbolKind::Class;
+  case index::SymbolKind::TypeAlias: {
+    switch (Info.SubKind) {
+    case index::SymbolSubKind::UsingStruct:
+      return SymbolKind::Struct;
+    case index::SymbolSubKind::UsingClass:
+      return SymbolKind::Class;
+    default:
+      return SymbolKind::Class;
+    }
+  }
   case index::SymbolKind::Function:
     return SymbolKind::Function;
   case index::SymbolKind::Variable:
diff --git a/clang-tools-extra/clangd/Protocol.h 
b/clang-tools-extra/clangd/Protocol.h
index 2248572060431..128850491ef0c 100644
--- a/clang-tools-extra/clangd/Protocol.h
+++ b/clang-tools-extra/clangd/Protocol.h
@@ -417,7 +417,7 @@ SymbolKind adjustKindToCapability(SymbolKind Kind,
 // Note, some are not perfect matches and should be improved when this LSP
 // issue is addressed:
 // https://github.com/Microsoft/language-server-protocol/issues/344
-SymbolKind indexSymbolKindToSymbolKind(index::SymbolKind Kind);
+SymbolKind indexSymbolKindToSymbolKind(const index::SymbolInfo &Info);
 
 // Determines the encoding used to measure offsets and lengths of source in 
LSP.
 enum class OffsetEncoding {
diff --git a/clang-tools-extra/clangd/XRefs.cpp 
b/clang-tools-extra/clangd/XRefs.cpp
index 8a24d19a7d129..efd76fe1d76ae 100644
--- a/clang-tools-extra/clangd/XRefs.cpp
+++ b/clang-tools-extra/clangd/XRefs.cpp
@@ -1806,7 +1806,7 @@ declToHierarchyItem(const NamedDecl &ND, llvm::StringRef 
TUPath) {
   index::SymbolInfo SymInfo = index::getSymbolInfo(&ND);
   // FIXME: This is not classifying constructors, destructors and operators
   // correctly.
-  SymbolKind SK = indexSymbolKindToSymbolKind(SymInfo.Kind);
+  SymbolKind SK = indexSymbolKindToSymbolKind(SymInfo);
 
   HierarchyItem HI;
   HI.name = printName(Ctx, ND);
@@ -1863,7 +1863,7 @@ static std::optional<HierarchyItem> 
symbolToHierarchyItem(const Symbol &S,
   HierarchyItem HI;
   HI.name = std::string(S.Name);
   HI.detail = (S.Scope + S.Name).str();
-  HI.kind = indexSymbolKindToSymbolKind(S.SymInfo.Kind);
+  HI.kind = indexSymbolKindToSymbolKind(S.SymInfo);
   HI.selectionRange = Loc->range;
   // FIXME: Populate 'range' correctly
   // (https://github.com/clangd/clangd/issues/59).
diff --git a/clang-tools-extra/clangd/unittests/FindSymbolsTests.cpp 
b/clang-tools-extra/clangd/unittests/FindSymbolsTests.cpp
index d6e94bf752452..6a6c87c70317a 100644
--- a/clang-tools-extra/clangd/unittests/FindSymbolsTests.cpp
+++ b/clang-tools-extra/clangd/unittests/FindSymbolsTests.cpp
@@ -110,6 +110,28 @@ TEST(WorkspaceSymbols, Unnamed) {
                                 withKind(SymbolKind::Field))));
 }
 
+TEST(WorkspaceSymbols, TypeAlias) {
+  TestTU TU;
+  TU.Code = R"cpp(
+    struct Struct {};
+    class Class {};
+    class Container {
+      using StructAlias = Struct;
+      using ClassAlias = Class;
+    };
+  )cpp";
+  EXPECT_THAT(
+      getSymbols(TU, "Struct"),
+      UnorderedElementsAre(AllOf(qName("Struct"), 
withKind(SymbolKind::Struct)),
+                           AllOf(qName("Container::StructAlias"),
+                                 withKind(SymbolKind::Struct))));
+  EXPECT_THAT(
+      getSymbols(TU, "Class"),
+      UnorderedElementsAre(
+          AllOf(qName("Class"), withKind(SymbolKind::Class)),
+          AllOf(qName("Container::ClassAlias"), withKind(SymbolKind::Class))));
+}
+
 TEST(WorkspaceSymbols, InMainFile) {
   TestTU TU;
   TU.Code = R"cpp(
diff --git a/clang/include/clang/Index/IndexSymbol.h 
b/clang/include/clang/Index/IndexSymbol.h
index deb9337d9d1a1..1b1291b3349c6 100644
--- a/clang/include/clang/Index/IndexSymbol.h
+++ b/clang/include/clang/Index/IndexSymbol.h
@@ -76,7 +76,8 @@ enum class SymbolSubKind : uint8_t {
   CXXMoveConstructor,
   AccessorGetter,
   AccessorSetter,
-  UsingTypename,
+  UsingClass,
+  UsingStruct,
   UsingValue,
   UsingEnum,
 };
diff --git a/clang/lib/Index/IndexSymbol.cpp b/clang/lib/Index/IndexSymbol.cpp
index c3cbc03cf9b41..a167bc9faa076 100644
--- a/clang/lib/Index/IndexSymbol.cpp
+++ b/clang/lib/Index/IndexSymbol.cpp
@@ -8,10 +8,12 @@
 
 #include "clang/Index/IndexSymbol.h"
 #include "clang/AST/Attr.h"
+#include "clang/AST/Decl.h"
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/PrettyPrinter.h"
+#include "clang/AST/TypeBase.h"
 #include "clang/Lex/MacroInfo.h"
 
 using namespace clang;
@@ -83,6 +85,22 @@ bool index::isFunctionLocalSymbol(const Decl *D) {
   return true;
 }
 
+static SymbolSubKind getSubKindForTypedef(const TypedefNameDecl *TND) {
+  if (const TagDecl *TD = TND->getUnderlyingType()->getAsTagDecl()) {
+    switch (TD->getTagKind()) {
+    case TagTypeKind::Class:
+      return SymbolSubKind::UsingClass;
+    case TagTypeKind::Struct:
+      return SymbolSubKind::UsingStruct;
+    default:
+      // Leave SymbolSubKind blank.
+      // New subkinds like UsingUnion can be added if/when needed.
+      return SymbolSubKind::None;
+    }
+  }
+  return SymbolSubKind::None;
+}
+
 SymbolInfo index::getSymbolInfo(const Decl *D) {
   assert(D);
   SymbolInfo Info;
@@ -171,8 +189,11 @@ SymbolInfo index::getSymbolInfo(const Decl *D) {
     case Decl::Import:
       Info.Kind = SymbolKind::Module;
       break;
-    case Decl::Typedef:
-      Info.Kind = SymbolKind::TypeAlias; break; // Lang = C
+    case Decl::Typedef: {
+      Info.Kind = SymbolKind::TypeAlias; // Lang = C
+      Info.SubKind = getSubKindForTypedef(cast<TypedefDecl>(D));
+      break;
+    }
     case Decl::Function:
       Info.Kind = SymbolKind::Function;
       break;
@@ -310,13 +331,15 @@ SymbolInfo index::getSymbolInfo(const Decl *D) {
       Info.Lang = SymbolLanguage::CXX;
       Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic;
       break;
-    case Decl::TypeAlias:
+    case Decl::TypeAlias: {
       Info.Kind = SymbolKind::TypeAlias;
+      Info.SubKind = getSubKindForTypedef(cast<TypeAliasDecl>(D));
       Info.Lang = SymbolLanguage::CXX;
       break;
+    }
     case Decl::UnresolvedUsingTypename:
       Info.Kind = SymbolKind::Using;
-      Info.SubKind = SymbolSubKind::UsingTypename;
+      Info.SubKind = SymbolSubKind::UsingClass;
       Info.Lang = SymbolLanguage::CXX;
       Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic;
       break;
@@ -553,7 +576,10 @@ StringRef index::getSymbolSubKindString(SymbolSubKind K) {
   case SymbolSubKind::CXXMoveConstructor: return "cxx-move-ctor";
   case SymbolSubKind::AccessorGetter: return "acc-get";
   case SymbolSubKind::AccessorSetter: return "acc-set";
-  case SymbolSubKind::UsingTypename: return "using-typename";
+  case SymbolSubKind::UsingClass:
+    return "using-class";
+  case SymbolSubKind::UsingStruct:
+    return "using-struct";
   case SymbolSubKind::UsingValue: return "using-value";
   case SymbolSubKind::UsingEnum: return "using-enum";
   }
diff --git a/clang/test/Index/Core/index-dependent-source.cpp 
b/clang/test/Index/Core/index-dependent-source.cpp
index ef414c8fdf7a0..b718ae4a831df 100644
--- a/clang/test/Index/Core/index-dependent-source.cpp
+++ b/clang/test/Index/Core/index-dependent-source.cpp
@@ -179,7 +179,7 @@ struct UsingB : public UsingA<T> {
 // CHECK: [[@LINE+2]]:40 | type-alias/C | TypeB | 
c:index-dependent-source.cpp@ST>1#T@UsingB@T@TypeB | <no-cgname> | Def,RelChild 
| rel: 1
 // CHECK: [[@LINE+1]]:20 | struct(Gen)/C++ | OtherUsing | c:@ST>1#T@OtherUsing 
| <no-cgname> | Ref,RelCont | rel: 1
   typedef typename OtherUsing<T>::Type TypeB;
-// CHECK: [[@LINE+2]]:29 | using/using-typename(Gen)/C++ | Type | 
c:index-dependent-source.cpp@ST>1#T@UsingB@UUT@UsingA<T>::Type | <no-cgname> | 
Decl,RelChild | rel: 1
+// CHECK: [[@LINE+2]]:29 | using/using-class(Gen)/C++ | Type | 
c:index-dependent-source.cpp@ST>1#T@UsingB@UUT@UsingA<T>::Type | <no-cgname> | 
Decl,RelChild | rel: 1
 // CHECK: [[@LINE+1]]:18 | struct(Gen)/C++ | UsingA | c:@ST>1#T@UsingA | 
<no-cgname> | Ref,RelCont | rel: 1
   using typename UsingA<T>::Type;
 // CHECK: [[@LINE+2]]:20 | using/using-value(Gen)/C++ | func | 
c:index-dependent-source.cpp@ST>1#T@UsingB@UUV@UsingA<T>::func | <no-cgname> | 
Decl,RelChild | rel: 1
@@ -200,7 +200,7 @@ struct UsingC : public UsingB<T> {
 // CHECK: [[@LINE+2]]:25 | type-alias/C | TypeB | 
c:index-dependent-source.cpp@ST>1#T@UsingB@T@TypeB | <no-cgname> | Ref,RelCont 
| rel: 1
 // CHECK: [[@LINE+1]]:14 | struct(Gen)/C++ | UsingB | c:@ST>1#T@UsingB | 
<no-cgname> | Ref,RelCont | rel: 1
     typename UsingB<T>::TypeB value1;
-// CHECK: [[@LINE+2]]:25 | using/using-typename(Gen)/C++ | Type | 
c:index-dependent-source.cpp@ST>1#T@UsingB@UUT@UsingA<T>::Type | <no-cgname> | 
Ref,RelCont | rel: 1
+// CHECK: [[@LINE+2]]:25 | using/using-class(Gen)/C++ | Type | 
c:index-dependent-source.cpp@ST>1#T@UsingB@UUT@UsingA<T>::Type | <no-cgname> | 
Ref,RelCont | rel: 1
 // CHECK: [[@LINE+1]]:14 | struct(Gen)/C++ | UsingB | c:@ST>1#T@UsingB | 
<no-cgname> | Ref,RelCont | rel: 1
     typename UsingB<T>::Type value2;
 // CHECK: [[@LINE+2]]:16 | using/using-value(Gen)/C++ | func | 
c:index-dependent-source.cpp@ST>1#T@UsingB@UUV@UsingA<T>::func | <no-cgname> | 
Ref,Call,RelCall,RelCont | rel: 1
diff --git a/clang/test/Index/Core/index-source.cpp 
b/clang/test/Index/Core/index-source.cpp
index 36bc663b89684..e376523a58f7c 100644
--- a/clang/test/Index/Core/index-source.cpp
+++ b/clang/test/Index/Core/index-source.cpp
@@ -23,10 +23,10 @@ class Cls { public:
 // CHECK: [[@LINE+2]]:24 | class/C++ | Cls | [[Cls_USR]] | <no-cgname> | 
Ref,RelBase,RelCont | rel: 1
 // CHECK-NEXT: RelBase,RelCont | SubCls1 | [[SubCls1_USR]]
 class SubCls1 : public Cls {};
-// CHECK: [[@LINE+1]]:13 | type-alias/C | ClsAlias | [[ClsAlias_USR:.*]] | 
<no-cgname> | Def | rel: 0
+// CHECK: [[@LINE+1]]:13 | type-alias/using-class/C | ClsAlias | 
[[ClsAlias_USR:.*]] | <no-cgname> | Def | rel: 0
 typedef Cls ClsAlias;
 // CHECK: [[@LINE+5]]:7 | class/C++ | SubCls2 | [[SubCls2_USR:.*]] | 
<no-cgname> | Def | rel: 0
-// CHECK: [[@LINE+4]]:24 | type-alias/C | ClsAlias | [[ClsAlias_USR]] | 
<no-cgname> | Ref,RelCont | rel: 1
+// CHECK: [[@LINE+4]]:24 | type-alias/using-class/C | ClsAlias | 
[[ClsAlias_USR]] | <no-cgname> | Ref,RelCont | rel: 1
 // CHECK-NEXT: RelCont | SubCls2 | [[SubCls2_USR]]
 // CHECK: [[@LINE+2]]:24 | class/C++ | Cls | [[Cls_USR]] | <no-cgname> | 
Ref,Impl,RelBase,RelCont | rel: 1
 // CHECK-NEXT: RelBase,RelCont | SubCls2 | [[SubCls2_USR]]

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

Reply via email to