https://github.com/HighCommander4 updated https://github.com/llvm/llvm-project/pull/181967
>From b5691322d6ec66cd6868805b0038865b4a0516c4 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 | 2 + clang/lib/Index/IndexSymbol.cpp | 43 ++++++++++++++++--- clang/test/Index/Core/index-source.cpp | 4 +- 8 files changed, 80 insertions(+), 17 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..4a7f523b885fc 100644 --- a/clang/include/clang/Index/IndexSymbol.h +++ b/clang/include/clang/Index/IndexSymbol.h @@ -79,6 +79,8 @@ enum class SymbolSubKind : uint8_t { UsingTypename, UsingValue, UsingEnum, + UsingClass, + UsingStruct, }; typedef uint16_t SymbolPropertySet; diff --git a/clang/lib/Index/IndexSymbol.cpp b/clang/lib/Index/IndexSymbol.cpp index c3cbc03cf9b41..9b7fee421bdfe 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,23 @@ 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; + } + } + // Not a tag type, e.g. typedef for a builtin type. + return SymbolSubKind::None; +} + SymbolInfo index::getSymbolInfo(const Decl *D) { assert(D); SymbolInfo Info; @@ -171,8 +190,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,10 +332,12 @@ 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; @@ -553,9 +577,16 @@ 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::UsingValue: return "using-value"; - case SymbolSubKind::UsingEnum: return "using-enum"; + case SymbolSubKind::UsingTypename: + return "using-typename"; + case SymbolSubKind::UsingValue: + return "using-value"; + case SymbolSubKind::UsingEnum: + return "using-enum"; + case SymbolSubKind::UsingClass: + return "using-class"; + case SymbolSubKind::UsingStruct: + return "using-struct"; } llvm_unreachable("invalid symbol subkind"); } 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
