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 @@ -1300,7 +1300,7 @@ return {}; } - llvm::DenseSet IDs; + llvm::DenseSet IDs, BaseMethod; const auto *IdentifierAtCursor = syntax::spelledIdentifierTouching(*CurLoc, AST.getTokens()); @@ -1347,9 +1347,13 @@ if (const auto *CMD = llvm::dyn_cast(ND)) { if (CMD->isVirtual()) if (IdentifierAtCursor && SM.getSpellingLoc(CMD->getLocation()) == - IdentifierAtCursor->location()) + IdentifierAtCursor->location()) { if (auto ID = getSymbolID(CMD)) OverriddenBy.Subjects.insert(ID); + for (const NamedDecl *Base : CMD->overridden_methods()) + if (auto ID = getSymbolID(Base)) + BaseMethod.insert(ID); + } } } } @@ -1407,7 +1411,8 @@ } } // Now query the index for references from other files. - auto QueryIndex = [&](llvm::DenseSet IDs, bool AllowAttributes) { + auto QueryIndex = [&](llvm::DenseSet IDs, bool AllowAttributes, + bool AllowMainFileSymbols) { RefsRequest Req; Req.IDs = std::move(IDs); Req.Limit = Limit; @@ -1419,7 +1424,8 @@ return; auto LSPLoc = toLSPLocation(R.Location, *MainFilePath); // Avoid indexed results for the main file - the AST is authoritative. - if (!LSPLoc || LSPLoc->uri.file() == *MainFilePath) + if (!LSPLoc || + (!AllowMainFileSymbols && LSPLoc->uri.file() == *MainFilePath)) return; ReferencesResult::Reference Result; Result.Loc = std::move(*LSPLoc); @@ -1434,12 +1440,17 @@ Results.References.push_back(std::move(Result)); }); }; - QueryIndex(std::move(IDs), /*AllowAttributes=*/true); + QueryIndex(std::move(IDs), /*AllowAttributes=*/true, + /*AllowMainFileSymbols=*/false); + // For a virtual method: Occurrences of BaseMethod should be treated as refs + // and not as decl/def. Allow symbols from main file since AST does not report + // these. + QueryIndex(std::move(BaseMethod), /*AllowAttributes=*/false, + /*AllowMainFileSymbols=*/true); if (Results.References.size() > Limit) { Results.HasMore = true; Results.References.resize(Limit); } - // FIXME: Report refs of base methods. return Results; } 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 @@ -1883,6 +1883,29 @@ checkFindRefs(Test, /*UseIndex=*/true); } +TEST(FindReferences, RefsToBaseMethod) { + llvm::StringRef Test = + R"cpp( + class BaseBase { + public: + virtual void func(); + }; + class Base : public BaseBase { + public: + void [[func]]() override; + }; + class Derived : public Base { + public: + void $decl[[fu^nc]]() override; + }; + void test(BaseBase* BB, Base* B, Derived* D) { + BB->func(); // refs to base's base method are not reported. + B->[[func]](); // References to the base method. + D->[[func]](); + })cpp"; + checkFindRefs(Test, /*UseIndex=*/true); +} + TEST(FindReferences, MainFileReferencesOnly) { llvm::StringRef Test = R"cpp(