diff --git a/clang-tools-extra/clangd/FindSymbols.cpp b/clang-tools-extra/clangd/FindSymbols.cpp index 243746056aed..e3d4b7febaf1 100644 --- a/clang-tools-extra/clangd/FindSymbols.cpp +++ b/clang-tools-extra/clangd/FindSymbols.cpp @@ -350,7 +350,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(); @@ -431,7 +431,7 @@ std::optional 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 a697486d48f9..793db7b05299 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 a88c9a391f97..7a99721a1e85 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 d4398a593d48..5b9ba1baa070 100644 --- a/clang-tools-extra/clangd/XRefs.cpp +++ b/clang-tools-extra/clangd/XRefs.cpp @@ -1814,7 +1814,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); @@ -1871,7 +1871,7 @@ static std::optional 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 d0dd5d0f8f43..2d237429ebfb 100644 --- a/clang-tools-extra/clangd/unittests/FindSymbolsTests.cpp +++ b/clang-tools-extra/clangd/unittests/FindSymbolsTests.cpp @@ -116,6 +116,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 deb9337d9d1a..4a7f523b885f 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 c3cbc03cf9b4..9b7fee421bdf 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(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(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 36bc663b8968..e376523a58f7 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]] | | 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:.*]] | | Def | rel: 0 +// CHECK: [[@LINE+1]]:13 | type-alias/using-class/C | ClsAlias | [[ClsAlias_USR:.*]] | | Def | rel: 0 typedef Cls ClsAlias; // CHECK: [[@LINE+5]]:7 | class/C++ | SubCls2 | [[SubCls2_USR:.*]] | | Def | rel: 0 -// CHECK: [[@LINE+4]]:24 | type-alias/C | ClsAlias | [[ClsAlias_USR]] | | Ref,RelCont | rel: 1 +// CHECK: [[@LINE+4]]:24 | type-alias/using-class/C | ClsAlias | [[ClsAlias_USR]] | | Ref,RelCont | rel: 1 // CHECK-NEXT: RelCont | SubCls2 | [[SubCls2_USR]] // CHECK: [[@LINE+2]]:24 | class/C++ | Cls | [[Cls_USR]] | | Ref,Impl,RelBase,RelCont | rel: 1 // CHECK-NEXT: RelBase,RelCont | SubCls2 | [[SubCls2_USR]]