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 @@ -100,7 +100,8 @@ // // Here, both partial (2) and full (3) specializations are canonicalized to (1) // which ensures all three of them are renamed. -const NamedDecl *canonicalRenameDecl(const NamedDecl *D) { +const NamedDecl *canonicalRenameDecl(const NamedDecl *D, + bool CanonicalizeCtorsToType = false) { if (const auto *VarTemplate = dyn_cast(D)) return canonicalRenameDecl( VarTemplate->getSpecializedTemplate()->getTemplatedDecl()); @@ -113,9 +114,17 @@ ClassTemplateSpecialization->getSpecializedTemplate() ->getTemplatedDecl()); if (const auto *Method = dyn_cast(D)) { - if (Method->getDeclKind() == Decl::Kind::CXXConstructor || + // By default ctors and dtors are canonicalized to the returned type but + // when CanonicalizeCtorsToType is set, we should still retrieve the + // canonical method. + if ((Method->getDeclKind() == Decl::Kind::CXXConstructor && + !CanonicalizeCtorsToType) || Method->getDeclKind() == Decl::Kind::CXXDestructor) return canonicalRenameDecl(Method->getParent()); + if (const FunctionTemplateDecl *Template = Method->getPrimaryTemplate()) + if (const auto *TemplatedDecl = + dyn_cast(Template->getTemplatedDecl())) + Method = TemplatedDecl; if (const FunctionDecl *InstantiatedMethod = Method->getInstantiatedFromMemberFunction()) Method = cast(InstantiatedMethod); @@ -151,6 +160,18 @@ if (const auto *VD = dyn_cast(D)) { if (const VarDecl *OriginalVD = VD->getInstantiatedFromStaticDataMember()) VD = OriginalVD; + // Arguments are canonicalized to their canonical function's arguments. + if (const auto *Argument = dyn_cast(VD)) { + if (const auto *Function = + dyn_cast(Argument->getDeclContext())) { + const auto *Canonical = dyn_cast( + canonicalRenameDecl(Function, /*SameType=*/true)); + assert(Canonical && "canonicalRenameDecl should return the declaration " + "of the same type with SameType=true."); + return Canonical->getParamDecl(Argument->getFunctionScopeIndex()) + ->getCanonicalDecl(); + } + } return VD->getCanonicalDecl(); } return dyn_cast(D->getCanonicalDecl()); 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 @@ -678,6 +678,61 @@ } )cpp", + // Function argument. + R"cpp( + // Main.cpp + void foo(int [[Bar^]]); + + void foo(int [[Bar^]]) {} + + // Forward declarations somewhere else. + void foo(int [[Bar^]]); + void foo(int /*Bar*/); + )cpp", + + // Template function argument. + R"cpp( + template + void foo(T [[Bar^]]); + + template + void foo(T [[Bar^]]) {} + )cpp", + R"cpp( + template + void foo(T [[Bar^]]); + + template + void foo(T [[Bar^]]) {} + + template <> + void foo(int [[Bar^]]) {} + )cpp", + + // Constructor argument. + R"cpp( + class Foo { + Foo(int [[Bar^]]); + }; + Foo::Foo(int [[Bar^]]) {} + )cpp", + R"cpp( + class Foo { + template + Foo(T Something, U [[Bar^]]); + + Foo(); + }; + + template + Foo::Foo(T Something, U [[Bar^]]) {} + + template <> + Foo::Foo(int Something, int [[Bar^]]) {} + template <> + Foo::Foo(bool Something, bool [[Bar^]]) {} + )cpp", + // Namespace alias. R"cpp( namespace a { namespace b { void foo(); } }