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 @@ -737,6 +737,21 @@ LexedIndex + 1, Fuel, MatchedCB); } +/// In general, if we have multiple targets under the cursor we consider them +/// ambiguous and return an error. However, there are some exceptions. +bool areRenameTargetsAmbiguous( + const llvm::DenseSet &Targets) { + // If the cursor is on a using declaration, we may get multiple targets, e.g. + // namespace ns { void foo(int); void foo(char); } + // using ns::f^oo + // We want to rename both declarations here, so allow this. + if (llvm::any_of(Targets, + [](const NamedDecl *D) { return llvm::isa(D); })) + return false; + + return Targets.size() > 1; +} + } // namespace llvm::Expected rename(const RenameInputs &RInputs) { @@ -766,12 +781,13 @@ return makeError(ReasonToReject::UnsupportedSymbol); auto DeclsUnderCursor = locateDeclAt(AST, IdentifierToken->location()); - filterRenameTargets(DeclsUnderCursor); if (DeclsUnderCursor.empty()) return makeError(ReasonToReject::NoSymbolFound); - if (DeclsUnderCursor.size() > 1) + if (areRenameTargetsAmbiguous(DeclsUnderCursor)) return makeError(ReasonToReject::AmbiguousSymbol); + filterRenameTargets(DeclsUnderCursor); + llvm::DenseSet RenameDecls; for (const auto *D : DeclsUnderCursor) { auto CD = canonicalRenameDecls(D); 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 @@ -840,6 +840,17 @@ foo('x'); } )cpp", + + // Renaming a using-declaration that introduces multiple symbols + R"cpp( + namespace ns { struct [[foo]] {}; int [[foo]](int); char [[foo]](char); } + using ns::[[f^oo]]; + void bar() { + [[foo]](1); + [[foo]]('x'); + struct [[foo]] f; + } + )cpp", }; llvm::StringRef NewName = "NewName"; for (llvm::StringRef T : Tests) { @@ -1085,14 +1096,6 @@ }; )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) {