r317672 - [clang-refactor] Introduce a new rename rule for qualified symbols

Haojian Wu via cfe-commits cfe-commits at lists.llvm.org
Wed Nov 8 00:56:56 PST 2017


Author: hokein
Date: Wed Nov  8 00:56:56 2017
New Revision: 317672

URL: http://llvm.org/viewvc/llvm-project?rev=317672&view=rev
Log:
[clang-refactor] Introduce a new rename rule for qualified symbols

Summary: Prototype of a new rename rule for renaming qualified symbol.

Reviewers: arphaman, ioeric, sammccall

Reviewed By: arphaman, sammccall

Subscribers: jklaehn, cfe-commits, klimek

Differential Revision: https://reviews.llvm.org/D39332

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

Modified: cfe/trunk/include/clang/Tooling/Refactoring/Rename/RenamingAction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Tooling/Refactoring/Rename/RenamingAction.h?rev=317672&r1=317671&r2=317672&view=diff
==============================================================================
--- cfe/trunk/include/clang/Tooling/Refactoring/Rename/RenamingAction.h (original)
+++ cfe/trunk/include/clang/Tooling/Refactoring/Rename/RenamingAction.h Wed Nov  8 00:56:56 2017
@@ -66,6 +66,28 @@ private:
   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(const NamedDecl *ND,
+                      std::string NewQualifiedName)
+      : ND(ND), NewQualifiedName(std::move(NewQualifiedName)) {}
+
+  Expected<AtomicChanges>
+  createSourceReplacements(RefactoringRuleContext &Context) override;
+
+  // A NamedDecl which indentifies the the symbol being renamed.
+  const NamedDecl *ND;
+  // The new qualified name to change the symbol to.
+  std::string NewQualifiedName;
+};
+
 /// Returns source replacements that correspond to the rename of the given
 /// symbol occurrences.
 llvm::Expected<std::vector<AtomicChange>>

Modified: cfe/trunk/lib/Tooling/Refactoring/RefactoringActions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Tooling/Refactoring/RefactoringActions.cpp?rev=317672&r1=317671&r2=317672&view=diff
==============================================================================
--- cfe/trunk/lib/Tooling/Refactoring/RefactoringActions.cpp (original)
+++ cfe/trunk/lib/Tooling/Refactoring/RefactoringActions.cpp Wed Nov  8 00:56:56 2017
@@ -46,6 +46,22 @@ public:
   }
 };
 
+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 name to change the symbol to";
+  }
+};
+
 class NewNameOption : public RequiredRefactoringOption<std::string> {
 public:
   StringRef getName() const override { return "new-name"; }
@@ -70,6 +86,10 @@ public:
     RefactoringActionRules Rules;
     Rules.push_back(createRefactoringActionRule<RenameOccurrences>(
         SourceRangeSelectionRequirement(), OptionRequirement<NewNameOption>()));
+    // FIXME: Use NewNameOption.
+    Rules.push_back(createRefactoringActionRule<QualifiedRenameRule>(
+        OptionRequirement<OldQualifiedNameOption>(),
+        OptionRequirement<NewQualifiedNameOption>()));
     return Rules;
   }
 };

Modified: cfe/trunk/lib/Tooling/Refactoring/Rename/RenamingAction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Tooling/Refactoring/Rename/RenamingAction.cpp?rev=317672&r1=317671&r2=317672&view=diff
==============================================================================
--- cfe/trunk/lib/Tooling/Refactoring/Rename/RenamingAction.cpp (original)
+++ cfe/trunk/lib/Tooling/Refactoring/Rename/RenamingAction.cpp Wed Nov  8 00:56:56 2017
@@ -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>
 
@@ -93,6 +95,60 @@ RenameOccurrences::createSourceReplaceme
       *Occurrences, Context.getASTContext().getSourceManager(), Name);
 }
 
+Expected<QualifiedRenameRule>
+QualifiedRenameRule::initiate(RefactoringRuleContext &Context,
+                              std::string OldQualifiedName,
+                              std::string NewQualifiedName) {
+  const NamedDecl *ND =
+      getNamedDeclFor(Context.getASTContext(), OldQualifiedName);
+  if (!ND)
+    return llvm::make_error<llvm::StringError>("Could not find symbol " +
+                                                   OldQualifiedName,
+                                               llvm::errc::invalid_argument);
+  return QualifiedRenameRule(ND, std::move(NewQualifiedName));
+}
+
+const RefactoringDescriptor &QualifiedRenameRule::describe() {
+  static const RefactoringDescriptor Descriptor = {
+      /*Name=*/"local-qualified-rename",
+      /*Title=*/"Qualified Rename",
+      /*Description=*/
+      R"(Finds and renames qualified symbols in code within a translation unit.
+It is used to move/rename a symbol to a new namespace/name:
+  * Supported symbols: classes, class members, functions, enums, and type alias.
+  * Renames all symbol occurrences from the old qualified name to the new
+    qualified name. All symbol references will be correctly qualified; For
+    symbol definitions, only name will be changed.
+For example, rename "A::Foo" to "B::Bar":
+  Old code:
+    namespace foo {
+    class A {};
+    }
+
+    namespace bar {
+    void f(foo::A a) {}
+    }
+
+  New code after rename:
+    namespace foo {
+    class B {};
+    }
+
+    namespace bar {
+    void f(B b) {}
+    })"
+  };
+  return Descriptor;
+}
+
+Expected<AtomicChanges>
+QualifiedRenameRule::createSourceReplacements(RefactoringRuleContext &Context) {
+  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) {

Added: cfe/trunk/test/Refactor/LocalRename/QualifiedRename.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Refactor/LocalRename/QualifiedRename.cpp?rev=317672&view=auto
==============================================================================
--- cfe/trunk/test/Refactor/LocalRename/QualifiedRename.cpp (added)
+++ cfe/trunk/test/Refactor/LocalRename/QualifiedRename.cpp Wed Nov  8 00:56:56 2017
@@ -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: }

Modified: cfe/trunk/tools/clang-refactor/ClangRefactor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/clang-refactor/ClangRefactor.cpp?rev=317672&r1=317671&r2=317672&view=diff
==============================================================================
--- cfe/trunk/tools/clang-refactor/ClangRefactor.cpp (original)
+++ cfe/trunk/tools/clang-refactor/ClangRefactor.cpp Wed Nov  8 00:56:56 2017
@@ -257,20 +257,19 @@ public:
                               RefactoringActionRules ActionRules,
                               cl::OptionCategory &Category)
       : SubCommand(Action->getCommand(), Action->getDescription()),
-        Action(std::move(Action)), ActionRules(std::move(ActionRules)),
-        HasSelection(false) {
+        Action(std::move(Action)), ActionRules(std::move(ActionRules)) {
     // Check if the selection option is supported.
     for (const auto &Rule : this->ActionRules) {
-      if ((HasSelection = Rule->hasSelectionRequirement()))
+      if (Rule->hasSelectionRequirement()) {
+        Selection = llvm::make_unique<cl::opt<std::string>>(
+            "selection",
+            cl::desc(
+                "The selected source range in which the refactoring should "
+                "be initiated (<file>:<line>:<column>-<line>:<column> or "
+                "<file>:<line>:<column>)"),
+            cl::cat(Category), cl::sub(*this));
         break;
-    }
-    if (HasSelection) {
-      Selection = llvm::make_unique<cl::opt<std::string>>(
-          "selection",
-          cl::desc("The selected source range in which the refactoring should "
-                   "be initiated (<file>:<line>:<column>-<line>:<column> or "
-                   "<file>:<line>:<column>)"),
-          cl::cat(Category), cl::sub(*this));
+      }
     }
     // Create the refactoring options.
     for (const auto &Rule : this->ActionRules) {
@@ -284,10 +283,10 @@ public:
 
   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)
@@ -296,9 +295,6 @@ public:
     return false;
   }
 
-  // Whether the selection is supported by any rule in the subcommand.
-  bool hasSelection() const { return HasSelection; }
-
   SourceSelectionArgument *getSelection() const {
     assert(Selection && "selection not supported!");
     return ParsedSelection.get();
@@ -314,8 +310,6 @@ private:
   std::unique_ptr<cl::opt<std::string>> Selection;
   std::unique_ptr<SourceSelectionArgument> ParsedSelection;
   RefactoringActionCommandLineOptions Options;
-  // Whether the selection is supported by any rule in the subcommand.
-  bool HasSelection;
 };
 
 class ClangRefactorConsumer final : public ClangRefactorToolConsumerInterface {
@@ -403,13 +397,19 @@ public:
     // If the selection option is test specific, we use a test-specific
     // consumer.
     std::unique_ptr<ClangRefactorToolConsumerInterface> TestConsumer;
-    if (SelectedSubcommand->hasSelection())
+    bool HasSelection = MatchingRule->hasSelectionRequirement();
+    if (HasSelection)
       TestConsumer = SelectedSubcommand->getSelection()->createCustomConsumer();
     ClangRefactorToolConsumerInterface *ActiveConsumer =
         TestConsumer ? TestConsumer.get() : Consumer.get();
     ActiveConsumer->beginTU(AST);
-    // FIXME (Alex L): Implement non-selection based invocation path.
-    if (SelectedSubcommand->hasSelection()) {
+
+    auto InvokeRule = [&](RefactoringResultConsumer &Consumer) {
+      if (opts::Verbose)
+        logInvocation(*SelectedSubcommand, Context);
+      MatchingRule->invoke(*ActiveConsumer, Context);
+    };
+    if (HasSelection) {
       assert(SelectedSubcommand->getSelection() &&
              "Missing selection argument?");
       if (opts::Verbose)
@@ -417,14 +417,13 @@ public:
       if (SelectedSubcommand->getSelection()->forAllRanges(
               Context.getSources(), [&](SourceRange R) {
                 Context.setSelectionRange(R);
-                if (opts::Verbose)
-                  logInvocation(*SelectedSubcommand, Context);
-                MatchingRule->invoke(*ActiveConsumer, Context);
+                InvokeRule(*ActiveConsumer);
               }))
         HasFailed = true;
       ActiveConsumer->endTU();
       return;
     }
+    InvokeRule(*ActiveConsumer);
     ActiveConsumer->endTU();
   }
 
@@ -529,23 +528,24 @@ private:
   }
 
   llvm::Expected<RefactoringActionRule *>
-  getMatchingRule(const RefactoringActionSubcommand &Subcommand) {
+  getMatchingRule(RefactoringActionSubcommand &Subcommand) {
     SmallVector<RefactoringActionRule *, 4> MatchingRules;
     llvm::StringSet<> MissingOptions;
 
     for (const auto &Rule : Subcommand.getActionRules()) {
-      bool SelectionMatches = true;
-      if (Rule->hasSelectionRequirement()) {
-        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());
-        continue;
+      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");
+          }
+        }
       }
       for (const RefactoringOption *Opt : Visitor.getMissingRequiredOptions())
         MissingOptions.insert(Opt->getName());
@@ -593,11 +593,6 @@ private:
           Error, llvm::inconvertibleErrorCode());
     }
     RefactoringActionSubcommand *Subcommand = &(**It);
-    if (Subcommand->parseArguments())
-      return llvm::make_error<llvm::StringError>(
-          llvm::Twine("Failed to parse arguments for subcommand ") +
-              Subcommand->getName(),
-          llvm::inconvertibleErrorCode());
     return Subcommand;
   }
 




More information about the cfe-commits mailing list