Index: include/clang/Tooling/Refactoring/RefactoringActionRegistry.def =================================================================== --- include/clang/Tooling/Refactoring/RefactoringActionRegistry.def +++ include/clang/Tooling/Refactoring/RefactoringActionRegistry.def @@ -3,6 +3,7 @@ #endif REFACTORING_ACTION(LocalRename) +REFACTORING_ACTION(LocalQualifiedRename) REFACTORING_ACTION(Extract) #undef REFACTORING_ACTION 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 #include @@ -114,12 +116,72 @@ } }; +class OldQualifiedNameOption : public RequiredRefactoringOption { + public: + StringRef getName() const override { return "old-qualified-name"; } + StringRef getDescription() const override { + return "The old qualified name to be renamed"; + } +}; + +class QualifiedRenameOccurrences : public SourceChangeRefactoringRule { +public: + QualifiedRenameOccurrences(std::string OldQualifiedName, + std::string NewQualifiedName) + : OldQualifiedName(std::move(OldQualifiedName)), + NewQualifiedName(std::move(NewQualifiedName)) {} + + Expected + createSourceReplacements(RefactoringRuleContext &Context) override { + const NamedDecl *ND = + getNamedDeclFor(Context.getASTContext(), OldQualifiedName); + if (!ND) { + return llvm::make_error("Could not find symbol " + + OldQualifiedName, + llvm::errc::invalid_argument); + } + auto USRs = getUSRsForDeclaration(ND, Context.getASTContext()); + return tooling::createRenameAtomicChanges( + USRs, NewQualifiedName, + Context.getASTContext().getTranslationUnitDecl()); + } + +private: + std::string OldQualifiedName; + std::string NewQualifiedName; +}; + +class LocalQualifiedRename final : public RefactoringAction { +public: + StringRef getCommand() const override { + return "local-qualified-rename"; + } + + StringRef getDescription() const override { + return "Finds and rename qualified symbol in code with no indexer support"; + } + + /// Returns a set of refactoring actions rules that are defined by this + /// action. + RefactoringActionRules createActionRules() const override { + RefactoringActionRules Rules; + Rules.push_back(createRefactoringActionRule( + OptionRequirement(), + OptionRequirement())); + return Rules; + } +}; + } // end anonymous namespace std::unique_ptr createLocalRenameAction() { return llvm::make_unique(); } +std::unique_ptr createLocalQualifiedRenameAction() { + return llvm::make_unique(); +} + Expected> createRenameReplacements(const SymbolOccurrences &Occurrences, const SourceManager &SM, const SymbolName &NewName) { Index: test/Refactor/LocalQualifiedRename/QualifiedRename.cpp =================================================================== --- /dev/null +++ test/Refactor/LocalQualifiedRename/QualifiedRename.cpp @@ -0,0 +1,24 @@ +// RUN: clang-refactor local-qualified-rename -old-qualified-name="foo::A" -new-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: tools/clang-refactor/ClangRefactor.cpp =================================================================== --- tools/clang-refactor/ClangRefactor.cpp +++ tools/clang-refactor/ClangRefactor.cpp @@ -500,8 +500,6 @@ auto InvokeRule = [&](RefactoringResultConsumer &Consumer) { logInvocation(Subcommand, Context); for (RefactoringActionRule *Rule : MatchingRules) { - if (!Rule->hasSelectionRequirement()) - continue; Rule->invoke(Consumer, Context); return; } @@ -529,6 +527,8 @@ HasFailed = true; ActiveConsumer.endTU(); return; + } else { + InvokeRule(ActiveConsumer); } // FIXME (Alex L): Implement non-selection based invocation path. ActiveConsumer.endTU();