diff --git a/clang-tools-extra/clangd/XRefs.h b/clang-tools-extra/clangd/XRefs.h --- a/clang-tools-extra/clangd/XRefs.h +++ b/clang-tools-extra/clangd/XRefs.h @@ -83,7 +83,9 @@ bool HasMore = false; }; -/// Returns implementations of the virtual function at a specified \p Pos. +/// Returns implementations at a specified \p Pos: +/// - overrides for a virtual method; +/// - subclasses for a base class; std::vector findImplementations(ParsedAST &AST, Position Pos, const SymbolIndex *Index); diff --git a/clang-tools-extra/clangd/XRefs.cpp b/clang-tools-extra/clangd/XRefs.cpp --- a/clang-tools-extra/clangd/XRefs.cpp +++ b/clang-tools-extra/clangd/XRefs.cpp @@ -292,13 +292,14 @@ return D; } -std::vector findOverrides(llvm::DenseSet IDs, - const SymbolIndex *Index, - llvm::StringRef MainFilePath) { +std::vector findImplementors(llvm::DenseSet IDs, + RelationKind Predicate, + const SymbolIndex *Index, + llvm::StringRef MainFilePath) { if (IDs.empty()) return {}; RelationsRequest Req; - Req.Predicate = RelationKind::OverriddenBy; + Req.Predicate = Predicate; Req.Subjects = std::move(IDs); std::vector Results; Index->relations(Req, [&](const SymbolID &Subject, const Symbol &Object) { @@ -458,7 +459,8 @@ }); } - auto Overrides = findOverrides(VirtualMethods, Index, MainFilePath); + auto Overrides = findImplementors(VirtualMethods, RelationKind::OverriddenBy, + Index, MainFilePath); Result.insert(Result.end(), Overrides.begin(), Overrides.end()); return Result; } @@ -1239,12 +1241,20 @@ } DeclRelationSet Relations = DeclRelation::TemplatePattern | DeclRelation::Alias; - llvm::DenseSet VirtualMethods; - for (const NamedDecl *ND : getDeclAtPosition(AST, *CurLoc, Relations)) - if (const CXXMethodDecl *CXXMD = llvm::dyn_cast(ND)) - if (CXXMD->isVirtual()) - VirtualMethods.insert(getSymbolID(ND)); - return findOverrides(std::move(VirtualMethods), Index, *MainFilePath); + llvm::DenseSet IDs; + RelationKind QueryKind; + for (const NamedDecl *ND : getDeclAtPosition(AST, *CurLoc, Relations)) { + if (const auto *CXXMD = llvm::dyn_cast(ND)) { + if (CXXMD->isVirtual()) { + IDs.insert(getSymbolID(ND)); + QueryKind = RelationKind::OverriddenBy; + } + } else if (const auto *RD = dyn_cast(ND)) { + IDs.insert(getSymbolID(RD)); + QueryKind = RelationKind::BaseOf; + } + } + return findImplementors(std::move(IDs), QueryKind, Index, *MainFilePath); } ReferencesResult findReferences(ParsedAST &AST, Position Pos, uint32_t Limit, diff --git a/clang-tools-extra/clangd/unittests/XRefsTests.cpp b/clang-tools-extra/clangd/unittests/XRefsTests.cpp --- a/clang-tools-extra/clangd/unittests/XRefsTests.cpp +++ b/clang-tools-extra/clangd/unittests/XRefsTests.cpp @@ -1611,11 +1611,11 @@ TEST(FindImplementations, Inheritance) { llvm::StringRef Test = R"cpp( - struct Base { + struct $0^Base { virtual void F$1^oo(); void C$4^oncrete(); }; - struct Child1 : Base { + struct $0[[Child1]] : Base { void $1[[Fo$3^o]]() override; virtual void B$2^ar(); void Concrete(); // No implementations for concrete methods. @@ -1625,7 +1625,7 @@ void $2[[Bar]]() override; }; void FromReference() { - Base* B; + $0^Base* B; B->Fo$1^o(); B->C$4^oncrete(); &Base::Fo$1^o; @@ -1633,12 +1633,16 @@ C1->B$2^ar(); C1->Fo$3^o(); } + // CRTP should work. + template + struct $5^TemplateBase {}; + struct $5[[Child3]] : public TemplateBase {}; )cpp"; Annotations Code(Test); auto TU = TestTU::withCode(Code.code()); auto AST = TU.build(); - for (const std::string &Label : {"1", "2", "3", "4"}) { + for (StringRef Label : {"0", "1", "2", "3", "4", "5"}) { for (const auto &Point : Code.points(Label)) { EXPECT_THAT(findImplementations(AST, Point, TU.index().get()), UnorderedPointwise(DeclRange(), Code.ranges(Label)))