From 953a97839fde72112b143b5e9a5f318a6fdc3238 Mon Sep 17 00:00:00 2001 From: Kirill Bobyrev Date: Tue, 19 Jul 2016 07:37:43 +0000 Subject: [PATCH] [clang-rename] add support for overridden functions Reviewers: klimek Differential Revision: https://reviews.llvm.org/D22408 llvm-svn: 275958 --- .../clang-rename/USRFindingAction.cpp | 144 +++++++++++++++------ 1 file changed, 102 insertions(+), 42 deletions(-) diff --git a/clang-tools-extra/clang-rename/USRFindingAction.cpp b/clang-tools-extra/clang-rename/USRFindingAction.cpp index 0ff0be6..11863b4c 100644 --- a/clang-tools-extra/clang-rename/USRFindingAction.cpp +++ b/clang-tools-extra/clang-rename/USRFindingAction.cpp @@ -8,7 +8,8 @@ //===----------------------------------------------------------------------===// /// /// \file -/// \brief Provides an action to rename every symbol at a point. +/// \brief Provides an action to find USR for the symbol at , as well as +/// all additional USRs. /// //===----------------------------------------------------------------------===// @@ -17,6 +18,9 @@ #include "clang/AST/AST.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/Basic/FileManager.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendAction.h" @@ -25,47 +29,107 @@ #include "clang/Tooling/CommonOptionsParser.h" #include "clang/Tooling/Refactoring.h" #include "clang/Tooling/Tooling.h" +#include #include +#include #include + using namespace llvm; +using namespace clang::ast_matchers; namespace clang { namespace rename { -// Get the USRs for the constructors of the class. -static std::vector getAllConstructorUSRs( - const CXXRecordDecl *Decl) { - std::vector USRs; - - // We need to get the definition of the record (as opposed to any forward - // declarations) in order to find the constructor and destructor. - const auto *RecordDecl = Decl->getDefinition(); - - // Iterate over all the constructors and add their USRs. - for (const auto *CtorDecl : RecordDecl->ctors()) - USRs.push_back(getUSRForDecl(CtorDecl)); - - // Ignore destructors. GetLocationsOfUSR will find the declaration of and - // explicit calls to a destructor through TagTypeLoc (and it is better for the - // purpose of renaming). - // - // For example, in the following code segment, - // 1 class C { - // 2 ~C(); - // 3 }; - // At line 3, there is a NamedDecl starting from '~' and a TagTypeLoc starting - // from 'C'. - - return USRs; -} +namespace { +// \brief NamedDeclFindingConsumer should delegate finding USRs of given Decl to +// AdditionalUSRFinder. AdditionalUSRFinder adds USRs of ctor and dtor if given +// Decl refers to class and adds USRs of all overridden methods if Decl refers +// to virtual method. +// +// FIXME: It's better to match ctors/dtors via typeLoc's instead of adding +// their USRs to the storage, because we can also match CXXConversionDecl's by +// typeLoc and we won't have to "manually" handle them here. +class AdditionalUSRFinder : public MatchFinder::MatchCallback { +public: + explicit AdditionalUSRFinder(const Decl *FoundDecl, ASTContext &Context, + std::vector *USRs) + : FoundDecl(FoundDecl), Context(Context), USRs(USRs), USRSet(), Finder() {} + + void Find() { + USRSet.insert(getUSRForDecl(FoundDecl)); + addUSRsFromOverrideSetsAndCtorDtors(); + addMatchers(); + Finder.matchAST(Context); + USRs->insert(USRs->end(), USRSet.begin(), USRSet.end()); + } + +private: + void addMatchers() { + const auto CXXMethodDeclMatcher = + cxxMethodDecl(isVirtual()).bind("cxxMethodDecl"); + Finder.addMatcher(CXXMethodDeclMatcher, this); + } + + // FIXME: Implement hasOverriddenMethod and matchesUSR matchers to make + // lookups more efficient. + virtual void run(const MatchFinder::MatchResult &Result) { + const auto *VirtualMethod = + Result.Nodes.getNodeAs("cxxMethodDecl"); + bool Found = false; + for (const auto &OverriddenMethod : VirtualMethod->overridden_methods()) { + if (USRSet.find(getUSRForDecl(OverriddenMethod)) != USRSet.end()) { + Found = true; + } + } + if (Found) { + USRSet.insert(getUSRForDecl(VirtualMethod)); + } + } + + void addUSRsFromOverrideSetsAndCtorDtors() { + // If D is CXXRecordDecl we should add all USRs of its constructors. + if (const auto *RecordDecl = dyn_cast(FoundDecl)) { + // Ignore destructors. Find the declaration of and explicit calls to a + // destructor through TagTypeLoc (and it is better for the purpose of + // renaming). + // + // For example, in the following code segment, + // 1 class C { + // 2 ~C(); + // 3 }; + // + // At line 3, there is a NamedDecl starting from '~' and a TagTypeLoc + // starting from 'C'. + RecordDecl = RecordDecl->getDefinition(); + + // Iterate over all the constructors and add their USRs. + for (const auto *CtorDecl : RecordDecl->ctors()) { + USRSet.insert(getUSRForDecl(CtorDecl)); + } + } + // If D is CXXMethodDecl we should add all USRs of its overriden methods. + if (const auto *MethodDecl = dyn_cast(FoundDecl)) { + for (auto &OverriddenMethod : MethodDecl->overridden_methods()) { + USRSet.insert(getUSRForDecl(OverriddenMethod)); + } + } + } + + const Decl *FoundDecl; + ASTContext &Context; + std::vector *USRs; + std::set USRSet; + MatchFinder Finder; +}; +} // namespace struct NamedDeclFindingConsumer : public ASTConsumer { void HandleTranslationUnit(ASTContext &Context) override { const auto &SourceMgr = Context.getSourceManager(); // The file we look for the USR in will always be the main source file. - const auto Point = SourceMgr.getLocForStartOfFile( - SourceMgr.getMainFileID()).getLocWithOffset(SymbolOffset); + const auto Point = SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID()) + .getLocWithOffset(SymbolOffset); if (!Point.isValid()) return; const NamedDecl *FoundDecl = nullptr; @@ -84,20 +148,17 @@ struct NamedDeclFindingConsumer : public ASTConsumer { return; } - // If the decl is a constructor or destructor, we want to instead take the - // decl of the parent record. - if (const auto *CtorDecl = dyn_cast(FoundDecl)) + // If FoundDecl is a constructor or destructor, we want to instead take the + // Decl of the corresponding class. + if (const auto *CtorDecl = dyn_cast(FoundDecl)) { FoundDecl = CtorDecl->getParent(); - else if (const auto *DtorDecl = dyn_cast(FoundDecl)) + } else if (const auto *DtorDecl = dyn_cast(FoundDecl)) { FoundDecl = DtorDecl->getParent(); - - // If the decl is in any way relatedpp to a class, we want to make sure we - // search for the constructor and destructor as well as everything else. - if (const auto *Record = dyn_cast(FoundDecl)) - *USRs = getAllConstructorUSRs(Record); - - USRs->push_back(getUSRForDecl(FoundDecl)); + } *SpellingName = FoundDecl->getNameAsString(); + + AdditionalUSRFinder Finder(FoundDecl, Context, USRs); + Finder.Find(); } unsigned SymbolOffset; @@ -106,8 +167,7 @@ struct NamedDeclFindingConsumer : public ASTConsumer { std::vector *USRs; }; -std::unique_ptr -USRFindingAction::newASTConsumer() { +std::unique_ptr USRFindingAction::newASTConsumer() { std::unique_ptr Consumer( new NamedDeclFindingConsumer); SpellingName = ""; -- 2.7.4