omtcyfz updated this revision to Diff 64228.
omtcyfz marked an inline comment as done.

https://reviews.llvm.org/D22408

Files:
  clang-rename/USRFindingAction.cpp
  test/clang-rename/VirtualFunctionFindInBaseClass.cpp
  test/clang-rename/VirtualFunctionFindInDerivedClass.cpp

Index: test/clang-rename/VirtualFunctionFindInDerivedClass.cpp
===================================================================
--- /dev/null
+++ test/clang-rename/VirtualFunctionFindInDerivedClass.cpp
@@ -0,0 +1,33 @@
+// RUN: cat %s > %t.cpp
+// RUN: clang-rename -offset=165 -new-name=bar %t.cpp -i --
+// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s
+
+class Foo {
+public:
+  virtual void foo() {}   // CHECK: virtual void bar() {}
+};
+
+class Bar : public Foo {
+public:
+  void foo() override {}  // CHECK: void bar() override {}
+};
+
+class Baz : public Bar {
+ public:
+  void foo() override {}  // CHECK: void bar() override {}
+};
+
+int main() {
+  Foo f;
+  f.foo();                // CHECK: f.bar();
+
+  Bar b;
+  b.foo();                // CHECK: b.bar();
+
+  Baz obj;
+  obj.foo();              // CHECK: obj.bar();
+
+  return 0;
+}
+
+// Use grep -FUbo 'foo' <file> to get the correct offset of foo when changing
Index: test/clang-rename/VirtualFunctionFindInBaseClass.cpp
===================================================================
--- /dev/null
+++ test/clang-rename/VirtualFunctionFindInBaseClass.cpp
@@ -0,0 +1,33 @@
+// RUN: cat %s > %t.cpp
+// RUN: clang-rename -offset=165 -new-name=bar %t.cpp -i --
+// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s
+
+class Foo {
+public:
+  virtual void foo() {}   // CHECK: virtual void bar() {}
+};
+
+class Bar : public Foo {
+public:
+  void foo() override {}  // CHECK: void bar() override {}
+};
+
+class Baz : public Bar {
+ public:
+  void foo() override {}  // CHECK: void bar() override {}
+};
+
+int main() {
+  Foo f;
+  f.foo();                // CHECK: f.bar();
+
+  Bar b;
+  b.foo();                // CHECK: b.bar();
+
+  Baz obj;
+  obj.foo();              // CHECK: obj.bar();
+
+  return 0;
+}
+
+// Use grep -FUbo 'foo' <file> to get the correct offset of foo when changing
Index: clang-rename/USRFindingAction.cpp
===================================================================
--- clang-rename/USRFindingAction.cpp
+++ clang-rename/USRFindingAction.cpp
@@ -8,64 +8,111 @@
 //===----------------------------------------------------------------------===//
 ///
 /// \file
-/// \brief Provides an action to rename every symbol at a point.
+/// \brief Provides an action to find USR for the symbol at <offset> and all
+/// relevant USRs aswell.
 ///
 //===----------------------------------------------------------------------===//
 
 #include "USRFindingAction.h"
 #include "USRFinder.h"
 #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/Basic/FileManager.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/FrontendAction.h"
 #include "clang/Lex/Lexer.h"
 #include "clang/Lex/Preprocessor.h"
 #include "clang/Tooling/CommonOptionsParser.h"
 #include "clang/Tooling/Refactoring.h"
 #include "clang/Tooling/Tooling.h"
+#include <algorithm>
 #include <string>
 #include <vector>
 
 using namespace llvm;
 
 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;
+namespace {
+// \brief NamedDeclFindingConsumer should delegate finding USRs relevant to
+// given Decl to RelevantUSRFinder.
+//
+// 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 RelevantUSRFinder : public clang::RecursiveASTVisitor<RelevantUSRFinder> {
+public:
+  explicit RelevantUSRFinder(const Decl *FoundDecl, TranslationUnitDecl *TUDecl,
+                             std::vector<std::string> *USRs)
+      : FoundDecl(FoundDecl), USRs(USRs) {
+    USRs->push_back(getUSRForDecl(FoundDecl));
+    addRelevantUSRs();
+    TraverseDecl(TUDecl);
+  }
 
-  // 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();
+  // CXXMethodDecl which overrides one of the methods stored for renaming
+  // should be added to the storage, too.
+  bool VisitCXXMethodDecl(CXXMethodDecl *D) {
+    if (D->isVirtual()) {
+      bool Found = false;
+      for (const auto &OverriddenMethod : D->overridden_methods()) {
+        if (std::find(USRs->begin(), USRs->end(),
+                      getUSRForDecl(OverriddenMethod)) != USRs->end()) {
+          Found = true;
+        }
+      }
+      if (Found) {
+        USRs->push_back(getUSRForDecl(D));
+      }
+    }
+    return true;
+  }
 
-  // Iterate over all the constructors and add their USRs.
-  for (const auto *CtorDecl : RecordDecl->ctors())
-    USRs.push_back(getUSRForDecl(CtorDecl));
+private:
+  void addRelevantUSRs() {
+    // 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();
 
-  // 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'.
+      // Iterate over all the constructors and add their USRs.
+      for (const auto *CtorDecl : RecordDecl->ctors()) {
+        USRs->push_back(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()) {
+        USRs->push_back(getUSRForDecl(OverriddenMethod));
+      }
+    }
+  }
 
-  return USRs;
-}
+  const Decl *FoundDecl;
+  std::vector<std::string> *USRs;
+};
+} // 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,30 +131,26 @@
       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();
+
+    auto *TUDecl = Context.getTranslationUnitDecl();
+    RelevantUSRFinder Finder(FoundDecl, TUDecl, USRs);
   }
 
   unsigned SymbolOffset;
   std::string OldName;
   std::string *SpellingName;
   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 = "";
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to