diff --git a/clang-tools-extra/clangd/index/Ref.h b/clang-tools-extra/clangd/index/Ref.h --- a/clang-tools-extra/clangd/index/Ref.h +++ b/clang-tools-extra/clangd/index/Ref.h @@ -30,7 +30,12 @@ Declaration = static_cast(index::SymbolRole::Declaration), Definition = static_cast(index::SymbolRole::Definition), Reference = static_cast(index::SymbolRole::Reference), - All = Declaration | Definition | Reference, + // This corresponds to index::SymbolRole::Implicit. In order to save memory + // and keep RefKind occupying 1 byte, the original value is modified to the + // one below. + Implicit = 1 << 3, + All = Declaration | Definition | Reference | Implicit, + NotImplicit = Declaration | Definition | Reference, }; inline RefKind operator|(RefKind L, RefKind R) { diff --git a/clang-tools-extra/clangd/index/SymbolCollector.cpp b/clang-tools-extra/clangd/index/SymbolCollector.cpp --- a/clang-tools-extra/clangd/index/SymbolCollector.cpp +++ b/clang-tools-extra/clangd/index/SymbolCollector.cpp @@ -180,7 +180,14 @@ } RefKind toRefKind(index::SymbolRoleSet Roles) { - return static_cast(static_cast(RefKind::All) & Roles); + // Because RefKind::Implicit != index::SymbolRole::Implicit because due to the + // memory considerations, all flags except "Implicit" should be set + // independently. + auto Result = + static_cast(static_cast(RefKind::NotImplicit) & Roles); + if (Roles & static_cast(index::SymbolRole::Implicit)) + Result |= RefKind::Implicit; + return Result; } bool shouldIndexRelation(const index::SymbolRelation &R) { @@ -291,7 +298,17 @@ // occurrence inside the base-specifier. processRelations(*ND, *ID, Relations); - bool CollectRef = static_cast(Opts.RefFilter) & Roles; + // Check if the referenced symbol is spelled exactly the same way the + // corresponding NamedDecl is. If it isn't, mark this reference as implicit. + // An example of implicit references would be a macro expansion. + llvm::SmallString<16> Buffer; + const auto Spelling = + Lexer::getSpelling(Loc, Buffer, SM, ASTCtx->getLangOpts()); + DeclarationName Name = ND->getDeclName(); + if (Name.isIdentifier() && Name.getAsString() != Spelling) + Roles |= static_cast(index::SymbolRole::Implicit); + + bool CollectRef = static_cast(Opts.RefFilter & toRefKind(Roles)); bool IsOnlyRef = !(Roles & (static_cast(index::SymbolRole::Declaration) | static_cast(index::SymbolRole::Definition))); diff --git a/clang-tools-extra/clangd/refactor/Rename.cpp b/clang-tools-extra/clangd/refactor/Rename.cpp --- a/clang-tools-extra/clangd/refactor/Rename.cpp +++ b/clang-tools-extra/clangd/refactor/Rename.cpp @@ -296,6 +296,8 @@ bool HasMore = Index.refs(RQuest, [&](const Ref &R) { if (AffectedFiles.size() > MaxLimitFiles) return; + if (static_cast(R.Kind & RefKind::Implicit)) + return; if (auto RefFilePath = filePath(R.Location, /*HintFilePath=*/MainFile)) { if (*RefFilePath != MainFile) AffectedFiles[*RefFilePath].push_back(toRange(R.Location)); diff --git a/clang-tools-extra/clangd/unittests/RenameTests.cpp b/clang-tools-extra/clangd/unittests/RenameTests.cpp --- a/clang-tools-extra/clangd/unittests/RenameTests.cpp +++ b/clang-tools-extra/clangd/unittests/RenameTests.cpp @@ -837,7 +837,7 @@ { // variables. R"cpp( - static const int [[VA^R]] = 123; + static const int [[VA^R]] = 123; )cpp", R"cpp( #include "foo.h" @@ -868,6 +868,22 @@ } )cpp", }, + { + // Implicit references in macro expansions. + R"cpp( + class [[Fo^o]] {}; + #define FooFoo Foo + #define FOO Foo + )cpp", + R"cpp( + #include "foo.h" + void bar() { + [[Foo]] x; + FOO y; + FooFoo z; + } + )cpp", + }, }; for (const auto& T : Cases) {