kbobyrev updated this revision to Diff 304776. kbobyrev marked 5 inline comments as done. kbobyrev added a comment.
- Handle VarDecl - Handle FunctionTemplateDecl - Remove FieldDecl handling (leave for the future patches) - Simplify code - Prevent regressions by adding more tests Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D71880/new/ https://reviews.llvm.org/D71880 Files: clang-tools-extra/clangd/refactor/Rename.cpp clang-tools-extra/clangd/unittests/RenameTests.cpp
Index: clang-tools-extra/clangd/unittests/RenameTests.cpp =================================================================== --- clang-tools-extra/clangd/unittests/RenameTests.cpp +++ clang-tools-extra/clangd/unittests/RenameTests.cpp @@ -588,6 +588,103 @@ ns::[[Old^Alias]] Bar; } )cpp", + + // Templated method instantiation. + R"cpp( + template<typename T> + class Foo { + public: + static T [[f^oo]]() {} + }; + + void bar() { + Foo<int>::[[f^oo]](); + } + )cpp", + R"cpp( + template<typename T> + class Foo { + public: + T [[f^oo]]() {} + }; + + void bar() { + Foo<int>().[[f^oo]](); + } + )cpp", + + // Templated class specialization. + R"cpp( + template<typename T, typename U=bool> + class [[Foo^]]; + + template<typename T, typename U> + class [[Foo^]] {}; + + template<typename T=int, typename U> + class [[Foo^]]; + )cpp", + R"cpp( + template<typename T=float, typename U=int> + class [[Foo^]]; + + template<typename T, typename U> + class [[Foo^]] {}; + )cpp", + + // Function template specialization. + R"cpp( + template<typename T=int, typename U=bool> + U [[foo^]](); + + template<typename T, typename U> + U [[foo^]]() {}; + )cpp", + R"cpp( + template<typename T, typename U> + U [[foo^]]() {}; + + template<typename T=int, typename U=bool> + U [[foo^]](); + )cpp", + R"cpp( + template<typename T=int, typename U=bool> + U [[foo^]](); + + template<typename T, typename U> + U [[foo^]](); + )cpp", + + R"cpp( + template <typename T, int U> + bool [[F^oo]] = true; + + // Explicit template specialization + template <> + bool [[F^oo]]<int, 0> = false; + + // Partial template specialization + template <typename T> + bool [[F^oo]]<T, 1> = false; + + void foo() { + // Ref to the explicit template specialization + [[F^oo]]<int, 0>; + // Ref to the primary template. + [[F^oo]]<double, 2>; + } + )cpp", + R"cpp( + template <typename T> + void [[f^oo]](T t); + + template <> + void [[f^oo]](int a); + + void test() { + [[f^oo]]<double>(1); + } + )cpp", }; llvm::StringRef NewName = "NewName"; for (llvm::StringRef T : Tests) { Index: clang-tools-extra/clangd/refactor/Rename.cpp =================================================================== --- clang-tools-extra/clangd/refactor/Rename.cpp +++ clang-tools-extra/clangd/refactor/Rename.cpp @@ -18,12 +18,12 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclTemplate.h" #include "clang/Basic/SourceLocation.h" -#include "clang/Tooling/Refactoring/Rename/USRFindingAction.h" #include "clang/Tooling/Syntax/Tokens.h" #include "llvm/ADT/None.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Error.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FormatVariadic.h" #include <algorithm> @@ -76,6 +76,8 @@ return OtherFile; } +const NamedDecl *canonicalRenameDecl(const NamedDecl *D); + llvm::DenseSet<const NamedDecl *> locateDeclAt(ParsedAST &AST, SourceLocation TokenStartLoc) { unsigned Offset = @@ -92,8 +94,7 @@ targetDecl(SelectedNode->ASTNode, DeclRelation::Alias | DeclRelation::TemplatePattern)) { // Get to CXXRecordDecl from constructor or destructor. - D = tooling::getCanonicalSymbolDeclaration(D); - Result.insert(D); + Result.insert(canonicalRenameDecl(D)); } return Result; } @@ -222,23 +223,73 @@ return error("Cannot rename symbol: {0}", Message(Reason)); } +const NamedDecl *canonicalRenameDecl(const TemplateDecl *D) { + return D->getTemplatedDecl(); +} + +const NamedDecl *canonicalRenameDecl(const CXXMethodDecl *D) { + const auto *Result = D; + if (const auto *InstantiatedMethod = D->getInstantiatedFromMemberFunction()) + Result = cast<CXXMethodDecl>(InstantiatedMethod); + while (Result->isVirtual() && Result->size_overridden_methods()) + Result = *Result->overridden_methods().begin(); + return Result; +} + +const NamedDecl *canonicalRenameDecl(const FunctionDecl *D) { + if (const auto *Template = D->getPrimaryTemplate()) + return canonicalRenameDecl(Template); + return D; +} + +const NamedDecl *canonicalRenameDecl(const FunctionTemplateDecl *D) { + const auto *TemplatedDecl = D->getTemplatedDecl(); + if (const auto *Primary = TemplatedDecl->getPrimaryTemplate()) + return Primary; + return TemplatedDecl; +} + +const NamedDecl *canonicalRenameDecl(const VarTemplateSpecializationDecl *D) { + return D->getSpecializedTemplate()->getTemplatedDecl(); +} + +const NamedDecl *canonicalRenameDecl(const ClassTemplateSpecializationDecl *D) { + return D->getSpecializedTemplate()->getTemplatedDecl(); +} + +// Canonical declarations help simplify the process of renaming. Examples: +// - Given a constructor/destructor, canonical declaration is the parent +// CXXRecordDecl +// - Specializations should point to the specialized declaration. +// - Instantiations should point to instantiated declaration. +const NamedDecl *canonicalRenameDecl(const NamedDecl *D) { + D = dyn_cast<NamedDecl>(D->getCanonicalDecl()); + if (const auto *Constructor = dyn_cast<CXXConstructorDecl>(D)) + return canonicalRenameDecl(Constructor->getParent()); + if (const auto *Destructor = dyn_cast<CXXDestructorDecl>(D)) + return canonicalRenameDecl(Destructor->getParent()); + if (const auto *FuctionTemplate = dyn_cast<FunctionTemplateDecl>(D)) + return canonicalRenameDecl(FuctionTemplate); + if (const auto *VarTemplate = dyn_cast<VarTemplateSpecializationDecl>(D)) + return canonicalRenameDecl(VarTemplate); + if (const auto *Template = dyn_cast<TemplateDecl>(D)) + return canonicalRenameDecl(Template); + if (const auto *ClassTemplateSpecialization = + dyn_cast<ClassTemplateSpecializationDecl>(D)) + return canonicalRenameDecl(ClassTemplateSpecialization); + if (const auto *Method = dyn_cast<CXXMethodDecl>(D)) + return canonicalRenameDecl(Method); + if (const auto *Function = dyn_cast<FunctionDecl>(D)) + return canonicalRenameDecl(Function); + return D; +} + // Return all rename occurrences in the main file. std::vector<SourceLocation> findOccurrencesWithinFile(ParsedAST &AST, const NamedDecl &ND) { trace::Span Tracer("FindOccurrencesWithinFile"); - // If the cursor is at the underlying CXXRecordDecl of the - // ClassTemplateDecl, ND will be the CXXRecordDecl. In this case, we need to - // get the primary template manually. - // getUSRsForDeclaration will find other related symbols, e.g. virtual and its - // overriddens, primary template and all explicit specializations. - // FIXME: Get rid of the remaining tooling APIs. - const auto *RenameDecl = - ND.getDescribedTemplate() ? ND.getDescribedTemplate() : &ND; - std::vector<std::string> RenameUSRs = - tooling::getUSRsForDeclaration(RenameDecl, AST.getASTContext()); - llvm::DenseSet<SymbolID> TargetIDs; - for (auto &USR : RenameUSRs) - TargetIDs.insert(SymbolID(USR)); + assert(canonicalRenameDecl(&ND) == &ND && + "ND should be already canonicalized."); std::vector<SourceLocation> Results; for (Decl *TopLevelDecl : AST.getLocalTopLevelDecls()) { @@ -246,11 +297,11 @@ if (Ref.Targets.empty()) return; for (const auto *Target : Ref.Targets) { - auto ID = getSymbolID(Target); - if (!ID || TargetIDs.find(ID) == TargetIDs.end()) + if (canonicalRenameDecl(Target) == &ND) { + Results.push_back(Ref.NameLoc); return; + } } - Results.push_back(Ref.NameLoc); }); }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits