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 @@ -370,7 +370,6 @@ class ReferenceFinder : public index::IndexDataConsumer { public: struct Reference { - const Decl *CanonicalTarget; SourceLocation Loc; index::SymbolRoleSet Role; }; @@ -384,17 +383,15 @@ std::vector take() && { llvm::sort(References, [](const Reference &L, const Reference &R) { - return std::tie(L.Loc, L.CanonicalTarget, L.Role) < - std::tie(R.Loc, R.CanonicalTarget, R.Role); + return std::tie(L.Loc, L.Role) < std::tie(R.Loc, R.Role); }); // We sometimes see duplicates when parts of the AST get traversed twice. - References.erase( - std::unique(References.begin(), References.end(), - [](const Reference &L, const Reference &R) { - return std::tie(L.CanonicalTarget, L.Loc, L.Role) == - std::tie(R.CanonicalTarget, R.Loc, R.Role); - }), - References.end()); + References.erase(std::unique(References.begin(), References.end(), + [](const Reference &L, const Reference &R) { + return std::tie(L.Loc, L.Role) == + std::tie(R.Loc, R.Role); + }), + References.end()); return std::move(References); } @@ -407,7 +404,7 @@ const SourceManager &SM = AST.getSourceManager(); Loc = SM.getFileLoc(Loc); if (isInsideMainFile(Loc, SM) && CanonicalTargets.count(D)) - References.push_back({D, Loc, Roles}); + References.push_back({Loc, Roles}); return true; } @@ -441,6 +438,8 @@ // FIXME: show references to macro within file? auto References = findRefs(Symbols.Decls, AST); + // FIXME: we may get multiple DocumentHighlights with the same location and + // different kinds, deduplicate them. std::vector Result; for (const auto &Ref : References) { if (auto Range = @@ -951,6 +950,15 @@ // We traverse the AST to find references in the main file. // TODO: should we handle macros, too? auto MainFileRefs = findRefs(Symbols.Decls, AST); + // We may get multiple refs with the same location and different Roles, as + // cross-reference is only interested in locations, we deduplicate them + // by the location to avoid emitting duplicated locations. + MainFileRefs.erase(std::unique(MainFileRefs.begin(), MainFileRefs.end(), + [](const ReferenceFinder::Reference &L, + const ReferenceFinder::Reference &R) { + return L.Loc == R.Loc; + }), + MainFileRefs.end()); for (const auto &Ref : MainFileRefs) { if (auto Range = getTokenRange(AST.getASTContext().getSourceManager(), 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 @@ -2037,35 +2037,36 @@ TEST(FindReferences, ExplicitSymbols) { const char *Tests[] = { R"cpp( - struct Foo { Foo* [self]() const; }; + struct Foo { Foo* [[self]]() const; }; void f() { - if (Foo* T = foo.[^self]()) {} // Foo member call expr. + Foo foo; + if (Foo* T = foo.[[^self]]()) {} // Foo member call expr. } )cpp", R"cpp( struct Foo { Foo(int); }; Foo f() { - int [b]; - return [^b]; // Foo constructor expr. + int [[b]]; + return [[^b]]; // Foo constructor expr. } )cpp", R"cpp( struct Foo {}; void g(Foo); - Foo [f](); + Foo [[f]](); void call() { - g([^f]()); // Foo constructor expr. + g([[^f]]()); // Foo constructor expr. } )cpp", R"cpp( - void [foo](int); - void [foo](double); + void [[foo]](int); + void [[foo]](double); namespace ns { - using ::[fo^o]; + using ::[[fo^o]]; } )cpp", }; @@ -2075,6 +2076,7 @@ std::vector> ExpectedLocations; for (const auto &R : T.ranges()) ExpectedLocations.push_back(RangeIs(R)); + ASSERT_THAT(ExpectedLocations, Not(IsEmpty())); EXPECT_THAT(findReferences(AST, T.point(), 0), ElementsAreArray(ExpectedLocations)) << Test;