hokein updated this revision to Diff 120792.
hokein added a comment.

- rebase to master
- move the implementation to a refactoring rule in `local-rename`
- support non-selection based refactoring action invocation call path


https://reviews.llvm.org/D39332

Files:
  include/clang/Tooling/Refactoring/Rename/RenamingAction.h
  lib/Tooling/Refactoring/RefactoringActions.cpp
  lib/Tooling/Refactoring/Rename/RenamingAction.cpp
  test/Refactor/LocalRename/QualifiedRename.cpp
  tools/clang-refactor/ClangRefactor.cpp

Index: tools/clang-refactor/ClangRefactor.cpp
===================================================================
--- tools/clang-refactor/ClangRefactor.cpp
+++ tools/clang-refactor/ClangRefactor.cpp
@@ -283,10 +283,10 @@
 
   const RefactoringActionRules &getActionRules() const { return ActionRules; }
 
-  /// Parses the command-line arguments that are specific to this rule.
+  /// Parses the "-selection" command-line argument.
   ///
   /// \returns true on error, false otherwise.
-  bool parseArguments() {
+  bool parseSelectionArgument() {
     if (Selection) {
       ParsedSelection = SourceSelectionArgument::fromString(*Selection);
       if (!ParsedSelection)
@@ -464,20 +464,20 @@
     SmallVector<RefactoringActionRule *, 4> MatchingRules;
     llvm::StringSet<> MissingOptions;
 
-    bool HasSelection = false;
     for (const auto &Rule : Subcommand.getActionRules()) {
-      bool SelectionMatches = true;
-      if (Rule->hasSelectionRequirement()) {
-        HasSelection = true;
-        if (!Subcommand.getSelection()) {
-          MissingOptions.insert("selection");
-          SelectionMatches = false;
-        }
-      }
       CommandLineRefactoringOptionVisitor Visitor(Subcommand.getOptions());
       Rule->visitRefactoringOptions(Visitor);
-      if (SelectionMatches && Visitor.getMissingRequiredOptions().empty()) {
-        MatchingRules.push_back(Rule.get());
+      if (Visitor.getMissingRequiredOptions().empty()) {
+        if (!Rule->hasSelectionRequirement()) {
+          MatchingRules.push_back(Rule.get());
+        } else {
+          Subcommand.parseSelectionArgument();
+          if (Subcommand.getSelection()) {
+            MatchingRules.push_back(Rule.get());
+          } else {
+            MissingOptions.insert("selection");
+          }
+        }
         continue;
       }
       for (const RefactoringOption *Opt : Visitor.getMissingRequiredOptions())
@@ -490,6 +490,14 @@
         llvm::errs() << "  missing '-" << Opt.getKey() << "' option\n";
       return true;
     }
+    if (MatchingRules.size() > 1) {
+      llvm::errs() << "error: find multiple matched action rules for the given "
+                      "arguments\n";
+      return true;
+    }
+
+    RefactoringActionRule* MatchingRule = MatchingRules[0];
+    bool HasSelection = MatchingRule->hasSelectionRequirement();
 
     ClangRefactorConsumer Consumer;
     bool HasFailed = false;
@@ -499,16 +507,7 @@
 
           auto InvokeRule = [&](RefactoringResultConsumer &Consumer) {
             logInvocation(Subcommand, Context);
-            for (RefactoringActionRule *Rule : MatchingRules) {
-              if (!Rule->hasSelectionRequirement())
-                continue;
-              Rule->invoke(Consumer, Context);
-              return;
-            }
-            // FIXME (Alex L): If more than one initiation succeeded, then the
-            // rules are ambiguous.
-            llvm_unreachable(
-                "The action must have at least one selection rule");
+            MatchingRule->invoke(Consumer, Context);
           };
 
           std::unique_ptr<ClangRefactorToolConsumerInterface> CustomConsumer;
@@ -530,7 +529,8 @@
             ActiveConsumer.endTU();
             return;
           }
-          // FIXME (Alex L): Implement non-selection based invocation path.
+
+          InvokeRule(ActiveConsumer);
           ActiveConsumer.endTU();
         }))
       return true;
@@ -567,8 +567,6 @@
   }
   RefactoringActionSubcommand &ActionCommand = **It;
 
-  if (ActionCommand.parseArguments())
-    return 1;
   if (Tool.invokeAction(ActionCommand, Options.getCompilations(),
                         Options.getSourcePathList()))
     return 1;
Index: test/Refactor/LocalRename/QualifiedRename.cpp
===================================================================
--- /dev/null
+++ test/Refactor/LocalRename/QualifiedRename.cpp
@@ -0,0 +1,24 @@
+// RUN: clang-refactor local-rename -old-qualified-name="foo::A" -new-qualified-name="bar::B" %s -- -std=c++11 2>&1 | grep -v CHECK | FileCheck %s
+
+namespace foo {
+class A {};
+}
+// CHECK: namespace foo {
+// CHECK-NEXT: class B {};
+// CHECK-NEXT: }
+
+namespace bar {
+void f(foo::A* a) {
+  foo::A b;
+}
+// CHECK: void f(B* a) {
+// CHECK-NEXT:   B b;
+// CHECK-NEXT: }
+}
+
+void f(foo::A* a) {
+  foo::A b;
+}
+// CHECK: void f(bar::B* a) {
+// CHECK-NEXT:   bar::B b;
+// CHECK-NEXT: }
Index: lib/Tooling/Refactoring/Rename/RenamingAction.cpp
===================================================================
--- lib/Tooling/Refactoring/Rename/RenamingAction.cpp
+++ lib/Tooling/Refactoring/Rename/RenamingAction.cpp
@@ -31,6 +31,8 @@
 #include "clang/Tooling/Refactoring/Rename/USRLocFinder.h"
 #include "clang/Tooling/Tooling.h"
 #include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Error.h"
 #include <string>
 #include <vector>
 
@@ -92,6 +94,39 @@
       *Occurrences, Context.getASTContext().getSourceManager(), Name);
 }
 
+Expected<QualifiedRenameRule>
+QualifiedRenameRule::initiate(RefactoringRuleContext &Context,
+                              std::string OldQualifiedName,
+                              std::string NewQualifiedName) {
+  return QualifiedRenameRule(std::move(OldQualifiedName),
+                             std::move(NewQualifiedName));
+}
+
+const RefactoringDescriptor &QualifiedRenameRuledescribe() {
+  static const RefactoringDescriptor Descriptor = {
+      /*Name=*/"local-qualified-rename",
+      /*Title=*/"Qualified Rename",
+      /*Description=*/
+      "Finds and renames qualified symbols in code with no indexer support",
+  };
+  return Descriptor;
+}
+
+Expected<AtomicChanges>
+QualifiedRenameRule::createSourceReplacements(RefactoringRuleContext &Context) {
+  const NamedDecl *ND =
+      getNamedDeclFor(Context.getASTContext(), OldQualifiedName);
+  if (!ND) {
+    return llvm::make_error<llvm::StringError>("Could not find symbol " +
+                                                   OldQualifiedName,
+                                               llvm::errc::invalid_argument);
+  }
+  auto USRs = getUSRsForDeclaration(ND, Context.getASTContext());
+  assert(!USRs.empty());
+  return tooling::createRenameAtomicChanges(
+      USRs, NewQualifiedName, Context.getASTContext().getTranslationUnitDecl());
+}
+
 Expected<std::vector<AtomicChange>>
 createRenameReplacements(const SymbolOccurrences &Occurrences,
                          const SourceManager &SM, const SymbolName &NewName) {
Index: lib/Tooling/Refactoring/RefactoringActions.cpp
===================================================================
--- lib/Tooling/Refactoring/RefactoringActions.cpp
+++ lib/Tooling/Refactoring/RefactoringActions.cpp
@@ -46,6 +46,22 @@
   }
 };
 
+class OldQualifiedNameOption : public RequiredRefactoringOption<std::string> {
+public:
+  StringRef getName() const override { return "old-qualified-name"; }
+  StringRef getDescription() const override {
+    return "The old qualified name to be renamed";
+  }
+};
+
+class NewQualifiedNameOption : public RequiredRefactoringOption<std::string> {
+public:
+  StringRef getName() const override { return "new-qualified-name"; }
+  StringRef getDescription() const override {
+    return "The new qualified to chagne the symbol to";
+  }
+};
+
 class NewNameOption : public RequiredRefactoringOption<std::string> {
 public:
   StringRef getName() const override { return "new-name"; }
@@ -70,6 +86,10 @@
     RefactoringActionRules Rules;
     Rules.push_back(createRefactoringActionRule<RenameOccurrences>(
         SourceRangeSelectionRequirement(), OptionRequirement<NewNameOption>()));
+    // FIXME: Use NewNameOption.
+    Rules.push_back(createRefactoringActionRule<QualifiedRenameRule>(
+        OptionRequirement<OldQualifiedNameOption>(),
+        OptionRequirement<NewQualifiedNameOption>()));
     return Rules;
   }
 };
Index: include/clang/Tooling/Refactoring/Rename/RenamingAction.h
===================================================================
--- include/clang/Tooling/Refactoring/Rename/RenamingAction.h
+++ include/clang/Tooling/Refactoring/Rename/RenamingAction.h
@@ -66,6 +66,27 @@
   std::string NewName;
 };
 
+class QualifiedRenameRule final : public SourceChangeRefactoringRule {
+public:
+  static Expected<QualifiedRenameRule> initiate(RefactoringRuleContext &Context,
+                                                std::string OldQualifiedName,
+                                                std::string NewQualifiedName);
+
+  static const RefactoringDescriptor &describe();
+
+private:
+  QualifiedRenameRule(std::string OldQualifiedName,
+                      std::string NewQualifiedName)
+      : OldQualifiedName(std::move(OldQualifiedName)),
+        NewQualifiedName(std::move(NewQualifiedName)) {}
+
+  Expected<AtomicChanges>
+  createSourceReplacements(RefactoringRuleContext &Context) override;
+
+  std::string OldQualifiedName;
+  std::string NewQualifiedName;
+};
+
 /// Returns source replacements that correspond to the rename of the given
 /// symbol occurrences.
 llvm::Expected<std::vector<AtomicChange>>
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to