hokein updated this revision to Diff 121456.
hokein marked an inline comment as done.
hokein added a comment.
Document the qualified rename.
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,60 @@
*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 with no indexer support.
+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 fter 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, NewName, 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 name to change 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
@@ -47,7 +47,21 @@
bool PrintLocations;
};
-class RenameOccurrences final : public SourceChangeRefactoringRule {
+/// A refactoring action rule for USR-based rename.
+class USRRenameRule : public SourceChangeRefactoringRule {
+protected:
+ USRRenameRule(const NamedDecl *ND, std::string NewName)
+ : ND(ND), NewName(std::move(NewName)) {
+ assert(ND);
+ }
+
+ // A NamedDecl which indentifies the the symbol being renamed.
+ const NamedDecl *ND;
+ // The new name to change the symbol to.
+ std::string NewName;
+};
+
+class RenameOccurrences final : public USRRenameRule {
public:
static Expected<RenameOccurrences> initiate(RefactoringRuleContext &Context,
SourceRange SelectionRange,
@@ -57,13 +71,27 @@
private:
RenameOccurrences(const NamedDecl *ND, std::string NewName)
- : ND(ND), NewName(std::move(NewName)) {}
+ : USRRenameRule(ND, std::move(NewName)) {}
Expected<AtomicChanges>
createSourceReplacements(RefactoringRuleContext &Context) override;
+};
- const NamedDecl *ND;
- std::string NewName;
+class QualifiedRenameRule final : public USRRenameRule {
+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)
+ : USRRenameRule(ND, std::move(NewQualifiedName)) {}
+
+ Expected<AtomicChanges>
+ createSourceReplacements(RefactoringRuleContext &Context) override;
};
/// Returns source replacements that correspond to the rename of the given
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits