Skip to content

Commit 42830f8

Browse files
committed
[clangd] Extend find-refs to include overrides.
find-references on `virtual void meth^od() = 0` will include override references. Differential Revision: https://reviews.llvm.org/D94390
1 parent cba1ca9 commit 42830f8

File tree

2 files changed

+71
-17
lines changed

2 files changed

+71
-17
lines changed

clang-tools-extra/clangd/XRefs.cpp

Lines changed: 46 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -879,11 +879,8 @@ class ReferenceFinder : public index::IndexDataConsumer {
879879
};
880880

881881
ReferenceFinder(const ParsedAST &AST,
882-
const std::vector<const NamedDecl *> &TargetDecls)
883-
: AST(AST) {
884-
for (const NamedDecl *D : TargetDecls)
885-
CanonicalTargets.insert(D->getCanonicalDecl());
886-
}
882+
const llvm::DenseSet<SymbolID> &TargetIDs)
883+
: AST(AST), TargetIDs(TargetIDs) {}
887884

888885
std::vector<Reference> take() && {
889886
llvm::sort(References, [](const Reference &L, const Reference &R) {
@@ -908,9 +905,9 @@ class ReferenceFinder : public index::IndexDataConsumer {
908905
llvm::ArrayRef<index::SymbolRelation> Relations,
909906
SourceLocation Loc,
910907
index::IndexDataConsumer::ASTNodeInfo ASTNode) override {
911-
assert(D->isCanonicalDecl() && "expect D to be a canonical declaration");
912908
const SourceManager &SM = AST.getSourceManager();
913-
if (!CanonicalTargets.count(D) || !isInsideMainFile(Loc, SM))
909+
if (!isInsideMainFile(Loc, SM) ||
910+
TargetIDs.find(getSymbolID(D)) == TargetIDs.end())
914911
return true;
915912
const auto &TB = AST.getTokens();
916913
Loc = SM.getFileLoc(Loc);
@@ -920,14 +917,14 @@ class ReferenceFinder : public index::IndexDataConsumer {
920917
}
921918

922919
private:
923-
llvm::SmallSet<const Decl *, 4> CanonicalTargets;
924920
std::vector<Reference> References;
925921
const ParsedAST &AST;
922+
const llvm::DenseSet<SymbolID> &TargetIDs;
926923
};
927924

928925
std::vector<ReferenceFinder::Reference>
929-
findRefs(const std::vector<const NamedDecl *> &Decls, ParsedAST &AST) {
930-
ReferenceFinder RefFinder(AST, Decls);
926+
findRefs(const llvm::DenseSet<SymbolID> &IDs, ParsedAST &AST) {
927+
ReferenceFinder RefFinder(AST, IDs);
931928
index::IndexingOptions IndexOpts;
932929
IndexOpts.SystemSymbolFilter =
933930
index::IndexingOptions::SystemSymbolFilterKind::All;
@@ -1217,7 +1214,11 @@ std::vector<DocumentHighlight> findDocumentHighlights(ParsedAST &AST,
12171214
if (!Decls.empty()) {
12181215
// FIXME: we may get multiple DocumentHighlights with the same location
12191216
// and different kinds, deduplicate them.
1220-
for (const auto &Ref : findRefs({Decls.begin(), Decls.end()}, AST))
1217+
llvm::DenseSet<SymbolID> Targets;
1218+
for (const NamedDecl *ND : Decls)
1219+
if (auto ID = getSymbolID(ND))
1220+
Targets.insert(ID);
1221+
for (const auto &Ref : findRefs(Targets, AST))
12211222
Result.push_back(toHighlight(Ref, SM));
12221223
return true;
12231224
}
@@ -1295,13 +1296,14 @@ ReferencesResult findReferences(ParsedAST &AST, Position Pos, uint32_t Limit,
12951296
llvm::consumeError(CurLoc.takeError());
12961297
return {};
12971298
}
1298-
llvm::Optional<DefinedMacro> Macro;
1299-
if (const auto *IdentifierAtCursor =
1300-
syntax::spelledIdentifierTouching(*CurLoc, AST.getTokens())) {
1301-
Macro = locateMacroAt(*IdentifierAtCursor, AST.getPreprocessor());
1302-
}
13031299

13041300
RefsRequest Req;
1301+
1302+
const auto *IdentifierAtCursor =
1303+
syntax::spelledIdentifierTouching(*CurLoc, AST.getTokens());
1304+
llvm::Optional<DefinedMacro> Macro;
1305+
if (IdentifierAtCursor)
1306+
Macro = locateMacroAt(*IdentifierAtCursor, AST.getPreprocessor());
13051307
if (Macro) {
13061308
// Handle references to macro.
13071309
if (auto MacroSID = getSymbolID(Macro->Name, Macro->Info, SM)) {
@@ -1325,9 +1327,35 @@ ReferencesResult findReferences(ParsedAST &AST, Position Pos, uint32_t Limit,
13251327
DeclRelation::TemplatePattern | DeclRelation::Alias;
13261328
std::vector<const NamedDecl *> Decls =
13271329
getDeclAtPosition(AST, *CurLoc, Relations);
1330+
llvm::DenseSet<SymbolID> Targets;
1331+
for (const NamedDecl *D : Decls)
1332+
if (auto ID = getSymbolID(D))
1333+
Targets.insert(ID);
1334+
1335+
llvm::DenseSet<SymbolID> Overrides;
1336+
if (Index) {
1337+
RelationsRequest FindOverrides;
1338+
FindOverrides.Predicate = RelationKind::OverriddenBy;
1339+
for (const NamedDecl *ND : Decls) {
1340+
// Special case: virtual void meth^od() = 0 includes refs of overrides.
1341+
if (const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(ND)) {
1342+
if (CMD->isPure())
1343+
if (IdentifierAtCursor && SM.getSpellingLoc(CMD->getLocation()) ==
1344+
IdentifierAtCursor->location())
1345+
if (auto ID = getSymbolID(CMD))
1346+
FindOverrides.Subjects.insert(ID);
1347+
}
1348+
}
1349+
if (!FindOverrides.Subjects.empty())
1350+
Index->relations(FindOverrides,
1351+
[&](const SymbolID &Subject, const Symbol &Object) {
1352+
Overrides.insert(Object.ID);
1353+
});
1354+
Targets.insert(Overrides.begin(), Overrides.end());
1355+
}
13281356

13291357
// We traverse the AST to find references in the main file.
1330-
auto MainFileRefs = findRefs(Decls, AST);
1358+
auto MainFileRefs = findRefs(Targets, AST);
13311359
// We may get multiple refs with the same location and different Roles, as
13321360
// cross-reference is only interested in locations, we deduplicate them
13331361
// by the location to avoid emitting duplicated locations.
@@ -1345,6 +1373,7 @@ ReferencesResult findReferences(ParsedAST &AST, Position Pos, uint32_t Limit,
13451373
Results.References.push_back(std::move(Result));
13461374
}
13471375
if (Index && Results.References.size() <= Limit) {
1376+
Req.IDs = std::move(Overrides);
13481377
for (const Decl *D : Decls) {
13491378
// Not all symbols can be referenced from outside (e.g.
13501379
// function-locals).

clang-tools-extra/clangd/unittests/XRefsTests.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1845,6 +1845,31 @@ TEST(FindReferences, WithinAST) {
18451845
}
18461846
}
18471847

1848+
TEST(FindReferences, IncludeOverrides) {
1849+
llvm::StringRef Test =
1850+
R"cpp(
1851+
class Base {
1852+
public:
1853+
virtual void [[f^unc]]() = 0;
1854+
};
1855+
class Derived : public Base {
1856+
public:
1857+
void [[func]]() override;
1858+
};
1859+
void test(Derived* D) {
1860+
D->[[func]]();
1861+
})cpp";
1862+
Annotations T(Test);
1863+
auto TU = TestTU::withCode(T.code());
1864+
auto AST = TU.build();
1865+
std::vector<Matcher<Location>> ExpectedLocations;
1866+
for (const auto &R : T.ranges())
1867+
ExpectedLocations.push_back(RangeIs(R));
1868+
EXPECT_THAT(findReferences(AST, T.point(), 0, TU.index().get()).References,
1869+
ElementsAreArray(ExpectedLocations))
1870+
<< Test;
1871+
}
1872+
18481873
TEST(FindReferences, MainFileReferencesOnly) {
18491874
llvm::StringRef Test =
18501875
R"cpp(

0 commit comments

Comments
 (0)