[clang-tools-extra] r275958 - [clang-rename] add support for overridden functions
Kirill Bobyrev via cfe-commits
cfe-commits at lists.llvm.org
Tue Jul 19 00:37:43 PDT 2016
Author: omtcyfz
Date: Tue Jul 19 02:37:43 2016
New Revision: 275958
URL: http://llvm.org/viewvc/llvm-project?rev=275958&view=rev
Log:
[clang-rename] add support for overridden functions
Reviewers: klimek
Differential Revision: https://reviews.llvm.org/D22408
Modified:
clang-tools-extra/trunk/clang-rename/USRFindingAction.cpp
Modified: clang-tools-extra/trunk/clang-rename/USRFindingAction.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-rename/USRFindingAction.cpp?rev=275958&r1=275957&r2=275958&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-rename/USRFindingAction.cpp (original)
+++ clang-tools-extra/trunk/clang-rename/USRFindingAction.cpp Tue Jul 19 02:37:43 2016
@@ -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 <offset>, 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 <algorithm>
#include <string>
+#include <set>
#include <vector>
+
using namespace llvm;
+using namespace clang::ast_matchers;
namespace clang {
namespace rename {
-// Get the USRs for the constructors of the class.
-static std::vector<std::string> getAllConstructorUSRs(
- const CXXRecordDecl *Decl) {
- std::vector<std::string> 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'.
+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<std::string> *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>("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<CXXRecordDecl>(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<CXXMethodDecl>(FoundDecl)) {
+ for (auto &OverriddenMethod : MethodDecl->overridden_methods()) {
+ USRSet.insert(getUSRForDecl(OverriddenMethod));
+ }
+ }
+ }
- return USRs;
-}
+ const Decl *FoundDecl;
+ ASTContext &Context;
+ std::vector<std::string> *USRs;
+ std::set<std::string> 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
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<CXXConstructorDecl>(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<CXXConstructorDecl>(FoundDecl)) {
FoundDecl = CtorDecl->getParent();
- else if (const auto *DtorDecl = dyn_cast<CXXDestructorDecl>(FoundDecl))
+ } else if (const auto *DtorDecl = dyn_cast<CXXDestructorDecl>(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<CXXRecordDecl>(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
std::vector<std::string> *USRs;
};
-std::unique_ptr<ASTConsumer>
-USRFindingAction::newASTConsumer() {
+std::unique_ptr<ASTConsumer> USRFindingAction::newASTConsumer() {
std::unique_ptr<NamedDeclFindingConsumer> Consumer(
new NamedDeclFindingConsumer);
SpellingName = "";
More information about the cfe-commits
mailing list