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 @@ -119,11 +119,35 @@ // declaration. while (Method->isVirtual() && Method->size_overridden_methods()) Method = *Method->overridden_methods().begin(); - return dyn_cast(Method->getCanonicalDecl()); + return Method->getCanonicalDecl(); } if (const auto *Function = dyn_cast(D)) if (const FunctionTemplateDecl *Template = Function->getPrimaryTemplate()) return canonicalRenameDecl(Template); + if (const auto *Field = dyn_cast(D)) { + // This is a hacky way to do something like + // CXXMethodDecl::getInstantiatedFromMemberFunction for the field because + // Clang AST does not store relevant information about the field that is + // instantiated. + const auto *TemplateSpec = + dyn_cast(Field->getParent()); + if (!TemplateSpec) + return Field->getCanonicalDecl(); + const CXXRecordDecl *FieldParent = + TemplateSpec->getTemplateInstantiationPattern(); + // Field is not instantiation. + if (!FieldParent || Field->getParent() == FieldParent) + return Field->getCanonicalDecl(); + for (const FieldDecl *Candidate : FieldParent->fields()) { + if (Field->getFieldIndex() == Candidate->getFieldIndex()) { + assert(Field->getLocation() == Candidate->getLocation() && + "Field should be generated from Candidate so it has the same " + "location."); + return Candidate->getCanonicalDecl(); + } + } + llvm_unreachable("FieldParent should have field with same index as Field."); + } 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 @@ -540,6 +540,81 @@ } )cpp", + // Fields in classes & partial and full specialiations. + R"cpp( + class Foo { + public: + Foo(int Variable) : [[Variabl^e]](Variable) {} + + int [[Va^riable]] = 42; + + private: + void foo() { ++[[Vari^able]]; } + }; + + void bar() { + Foo f(9000); + f.[[Variable^]] = -1; + } + )cpp", + R"cpp( + template + struct Foo { + T [[Vari^able]] = 42; + }; + + void foo() { + Foo f; + f.[[Varia^ble]] = 9000; + } + )cpp", + R"cpp( + template + struct Foo { + T Variable[42]; + U Another; + + void bar() {} + }; + + template + struct Foo { + T [[Var^iable]]; + void bar() { ++[[Var^iable]]; } + }; + + void foo() { + Foo f; + f.[[Var^iable]] = 9000; + } + )cpp", + R"cpp( + template + struct Foo { + T Variable[42]; + U Another; + + void bar() {} + }; + + template + struct Foo { + T Variable; + void bar() { ++Variable; } + }; + + template<> + struct Foo { + unsigned [[Var^iable]]; + void bar() { ++[[Var^iable]]; } + }; + + void foo() { + Foo f; + f.[[Var^iable]] = 9000; + } + )cpp", + // Template parameters. R"cpp( template