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 @@ -133,6 +133,10 @@ if (const VarDecl *OriginalVD = VD->getInstantiatedFromStaticDataMember()) return canonicalRenameDecl(OriginalVD); } + if (const auto *UD = dyn_cast(D)) { + if (const auto *TargetDecl = UD->getTargetDecl()) + return canonicalRenameDecl(TargetDecl); + } return dyn_cast(D->getCanonicalDecl()); } @@ -157,6 +161,22 @@ return Result; } +void filterRenameTargets(llvm::DenseSet &Decls) { + // For something like + // namespace ns { void foo(); } + // void bar() { using ns::f^oo; foo(); } + // locateDeclAt() will return a UsingDecl and foo's actual declaration. + // For renaming, we're only interested in foo's declaration, so drop the other + // one. There should never be more than one UsingDecl here, otherwise the + // rename would be ambiguos anyway. + auto UD = std::find_if(Decls.begin(), Decls.end(), [](const NamedDecl *D) { + return llvm::isa(D); + }); + if (UD != Decls.end()) { + Decls.erase(UD); + } +} + // By default, we exclude symbols from system headers and protobuf symbols as // renaming these symbols would change system/generated files which are unlikely // to be good candidates for modification. @@ -737,6 +757,7 @@ return makeError(ReasonToReject::UnsupportedSymbol); auto DeclsUnderCursor = locateDeclAt(AST, IdentifierToken->location()); + filterRenameTargets(DeclsUnderCursor); if (DeclsUnderCursor.empty()) return makeError(ReasonToReject::NoSymbolFound); if (DeclsUnderCursor.size() > 1) 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 @@ -817,6 +817,29 @@ char [[da^ta]]; } @end )cpp", + + // Issue 170: Rename symbol introduced by UsingDecl + R"cpp( + namespace ns { void [[f^oo]](); } + + using ns::[[f^oo]]; + + void f() { + [[f^oo]](); + auto p = &[[f^oo]]; + } + )cpp", + + // Issue 170: using decl that imports multiple overloads + // -> Only the overload under the cursor is renamed + R"cpp( + namespace ns { int [[^foo]](int); char foo(char); } + using ns::[[foo]]; + void f() { + [[^foo]](42); + foo('x'); + } + )cpp", }; llvm::StringRef NewName = "NewName"; for (llvm::StringRef T : Tests) { @@ -1062,6 +1085,14 @@ }; )cpp", "no symbol", false}, + + {R"cpp(// FIXME we probably want to rename both overloads here, + // but renaming currently assumes there's only a + // single canonical declaration. + namespace ns { int foo(int); char foo(char); } + using ns::^foo; + )cpp", + "there are multiple symbols at the given location", !HeaderFile}, }; for (const auto& Case : Cases) {