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 @@ -214,13 +214,6 @@ IsMainFileOnly)) return ReasonToReject::NonIndexable; - - // FIXME: Renaming virtual methods requires to rename all overridens in - // subclasses, our index doesn't have this information. - if (const auto *S = llvm::dyn_cast(&RenameDecl)) { - if (S->isVirtual()) - return ReasonToReject::UnsupportedSymbol; - } return None; } @@ -551,6 +544,20 @@ return R; } +namespace { +void recursivelyInsertOverrides(const SymbolID &Base, + llvm::DenseSet &IDs, + const SymbolIndex &Index) { + RelationsRequest Req; + Req.Predicate = RelationKind::OverriddenBy; + Req.Subjects = {Base}; + Index.relations(Req, [&](const SymbolID &, const Symbol &Override) { + IDs.insert(Override.ID); + recursivelyInsertOverrides(Override.ID, IDs, Index); + }); +} +} // namespace + // Return all rename occurrences (using the index) outside of the main file, // grouped by the absolute file path. llvm::Expected>> @@ -561,6 +568,10 @@ RefsRequest RQuest; RQuest.IDs.insert(getSymbolID(&RenameDecl)); + if (const auto *MethodDecl = llvm::dyn_cast(&RenameDecl)) + if (MethodDecl->isVirtual()) + recursivelyInsertOverrides(*RQuest.IDs.begin(), RQuest.IDs, Index); + // Absolute file path => rename occurrences in that file. llvm::StringMap> AffectedFiles; bool HasMore = Index.refs(RQuest, [&](const Ref &R) { 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 @@ -886,12 +886,6 @@ @end )cpp", "not a supported kind", HeaderFile}, - {R"cpp(// FIXME: rename virtual/override methods is not supported yet. - struct A { - virtual void f^oo() {} - }; - )cpp", - "not a supported kind", !HeaderFile}, {R"cpp( void foo(int); void foo(char); @@ -1490,6 +1484,37 @@ } )cpp", }, + { + // virtual methods. + R"cpp( + class Base { + virtual void [[foo]](); + }; + class Derived1 : public Base { + void [[f^oo]]() override; + }; + class NotDerived { + void foo() {}; + } + )cpp", + R"cpp( + #include "foo.h" + void Base::[[foo]]() {} + void Derived1::[[foo]]() {} + + class Derived2 : public Derived1 { + void [[foo]]() override {}; + }; + + void func(Base* b, Derived1* d1, + Derived2* d2, NotDerived* nd) { + b->[[foo]](); + d1->[[foo]](); + d2->[[foo]](); + nd->foo(); + } + )cpp", + }, { // rename on constructor and destructor. R"cpp(