arphaman updated this revision to Diff 120335.
arphaman added a comment.
- Refactoring operations like ExtractFunction should be declared in headers and
should contain the initiation checks.
- Refactoring actions can now be all created in one "engine" file.
- A new descriptor interface describes a rule (name, description + optional
editor title).
Repository:
rL LLVM
https://reviews.llvm.org/D38985
Files:
include/clang/Tooling/Refactoring/Extract/ExtractFunction.h
include/clang/Tooling/Refactoring/RefactoringActionRegistry.def
include/clang/Tooling/Refactoring/RefactoringActionRule.h
include/clang/Tooling/Refactoring/RefactoringActionRules.h
include/clang/Tooling/Refactoring/RefactoringActionRulesInternal.h
include/clang/Tooling/Refactoring/Rename/RenamingAction.h
include/clang/module.modulemap
lib/Tooling/Refactoring/Extract.cpp
lib/Tooling/Refactoring/RefactoringActions.cpp
lib/Tooling/Refactoring/Rename/RenamingAction.cpp
unittests/Tooling/RefactoringActionRulesTest.cpp
Index: unittests/Tooling/RefactoringActionRulesTest.cpp
===================================================================
--- unittests/Tooling/RefactoringActionRulesTest.cpp
+++ unittests/Tooling/RefactoringActionRulesTest.cpp
@@ -7,10 +7,11 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Tooling/Refactoring/RefactoringActionRules.h"
#include "ReplacementTest.h"
#include "RewriterTestContext.h"
#include "clang/Tooling/Refactoring.h"
-#include "clang/Tooling/Refactoring/RefactoringActionRules.h"
+#include "clang/Tooling/Refactoring/RefactoringAction.h"
#include "clang/Tooling/Refactoring/RefactoringDiagnostic.h"
#include "clang/Tooling/Refactoring/Rename/SymbolName.h"
#include "clang/Tooling/Tooling.h"
@@ -22,6 +23,12 @@
namespace {
+class TestDescriptor : public RefactoringDescriptorInterface {
+public:
+ virtual StringRef getName() const { return "test"; }
+ virtual StringRef getDescription() const { return ""; }
+};
+
class RefactoringActionRulesTest : public ::testing::Test {
protected:
void SetUp() override {
@@ -63,6 +70,12 @@
ReplaceAWithB(std::pair<SourceRange, int> Selection)
: Selection(Selection) {}
+ static Expected<ReplaceAWithB>
+ initiate(RefactoringRuleContext &Cotnext,
+ std::pair<SourceRange, int> Selection) {
+ return ReplaceAWithB(Selection);
+ }
+
Expected<AtomicChanges>
createSourceReplacements(RefactoringRuleContext &Context) {
const SourceManager &SM = Context.getSources();
@@ -87,8 +100,8 @@
return std::make_pair(*R, 20);
}
};
- auto Rule =
- createRefactoringActionRule<ReplaceAWithB>(SelectionRequirement());
+ auto Rule = createRefactoringActionRule<ReplaceAWithB, TestDescriptor>(
+ SelectionRequirement());
// When the requirements are satisifed, the rule's function must be invoked.
{
@@ -141,15 +154,20 @@
TEST_F(RefactoringActionRulesTest, ReturnError) {
class ErrorRule : public SourceChangeRefactoringRule {
public:
+ static Expected<ErrorRule> initiate(RefactoringRuleContext &,
+ SourceRange R) {
+ return ErrorRule(R);
+ }
+
ErrorRule(SourceRange R) {}
Expected<AtomicChanges> createSourceReplacements(RefactoringRuleContext &) {
return llvm::make_error<llvm::StringError>(
"Error", llvm::make_error_code(llvm::errc::invalid_argument));
}
};
- auto Rule =
- createRefactoringActionRule<ErrorRule>(SourceRangeSelectionRequirement());
+ auto Rule = createRefactoringActionRule<ErrorRule, TestDescriptor>(
+ SourceRangeSelectionRequirement());
RefactoringRuleContext RefContext(Context.Sources);
SourceLocation Cursor =
Context.Sources.getLocForStartOfFile(Context.Sources.getMainFileID());
@@ -191,6 +209,11 @@
public:
FindOccurrences(SourceRange Selection) : Selection(Selection) {}
+ static Expected<FindOccurrences> initiate(RefactoringRuleContext &,
+ SourceRange Selection) {
+ return FindOccurrences(Selection);
+ }
+
Expected<SymbolOccurrences>
findSymbolOccurrences(RefactoringRuleContext &) override {
SymbolOccurrences Occurrences;
@@ -201,7 +224,7 @@
}
};
- auto Rule = createRefactoringActionRule<FindOccurrences>(
+ auto Rule = createRefactoringActionRule<FindOccurrences, TestDescriptor>(
SourceRangeSelectionRequirement());
RefactoringRuleContext RefContext(Context.Sources);
@@ -219,4 +242,27 @@
SourceRange(Cursor, Cursor.getLocWithOffset(strlen("test"))));
}
+TEST_F(RefactoringActionRulesTest, EditorCommandBinding) {
+ std::vector<std::unique_ptr<RefactoringAction>> Actions =
+ createRefactoringActions();
+ for (auto &Action : Actions) {
+ if (Action->getCommand() == "extract") {
+ std::vector<std::unique_ptr<RefactoringActionRule>> Rules =
+ Action->createActiveActionRules();
+ ASSERT_FALSE(Rules.empty());
+ const RefactoringDescriptorInterface &Descriptor =
+ Rules[0]->getDescriptor();
+ EXPECT_EQ(Descriptor.getName(), "extract-function");
+ EXPECT_EQ(
+ Descriptor.getDescription(),
+ "(WIP action; use with caution!) Extracts code into a new function");
+ EXPECT_EQ(Descriptor.getEditorTitle(),
+ Optional<StringRef>("Extract Function"));
+ return;
+ }
+ }
+ // Never found 'extract'?
+ ASSERT_TRUE(false);
+}
+
} // end anonymous namespace
Index: lib/Tooling/Refactoring/Rename/RenamingAction.cpp
===================================================================
--- lib/Tooling/Refactoring/Rename/RenamingAction.cpp
+++ lib/Tooling/Refactoring/Rename/RenamingAction.cpp
@@ -41,22 +41,6 @@
namespace {
-class SymbolSelectionRequirement : public SourceRangeSelectionRequirement {
-public:
- Expected<const NamedDecl *> evaluate(RefactoringRuleContext &Context) const {
- Expected<SourceRange> Selection =
- SourceRangeSelectionRequirement::evaluate(Context);
- if (!Selection)
- return Selection.takeError();
- const NamedDecl *ND =
- getNamedDeclAt(Context.getASTContext(), Selection->getBegin());
- if (!ND)
- return Context.createDiagnosticError(
- Selection->getBegin(), diag::err_refactor_selection_no_symbol);
- return getCanonicalSymbolDeclaration(ND);
- }
-};
-
class OccurrenceFinder final : public FindSymbolOccurrencesRefactoringRule {
public:
OccurrenceFinder(const NamedDecl *ND) : ND(ND) {}
@@ -74,50 +58,29 @@
const NamedDecl *ND;
};
-class RenameOccurrences final : public SourceChangeRefactoringRule {
-public:
- RenameOccurrences(const NamedDecl *ND, std::string NewName)
- : Finder(ND), NewName(std::move(NewName)) {}
-
- Expected<AtomicChanges>
- createSourceReplacements(RefactoringRuleContext &Context) override {
- Expected<SymbolOccurrences> Occurrences =
- Finder.findSymbolOccurrences(Context);
- if (!Occurrences)
- return Occurrences.takeError();
- // FIXME: Verify that the new name is valid.
- SymbolName Name(NewName);
- return createRenameReplacements(
- *Occurrences, Context.getASTContext().getSourceManager(), Name);
- }
-
-private:
- OccurrenceFinder Finder;
- std::string NewName;
-};
-
-class LocalRename final : public RefactoringAction {
-public:
- StringRef getCommand() const override { return "local-rename"; }
-
- StringRef getDescription() const override {
- return "Finds and renames symbols 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<RenameOccurrences>(
- SymbolSelectionRequirement(), OptionRequirement<NewNameOption>()));
- return Rules;
- }
-};
-
} // end anonymous namespace
-std::unique_ptr<RefactoringAction> createLocalRenameAction() {
- return llvm::make_unique<LocalRename>();
+Expected<RenameOccurrences>
+RenameOccurrences::initiate(RefactoringRuleContext &Context,
+ SourceRange SelectionRange, std::string NewName) {
+ const NamedDecl *ND =
+ getNamedDeclAt(Context.getASTContext(), SelectionRange.getBegin());
+ if (!ND)
+ return Context.createDiagnosticError(
+ SelectionRange.getBegin(), diag::err_refactor_selection_no_symbol);
+ return RenameOccurrences(getCanonicalSymbolDeclaration(ND), NewName);
+}
+
+Expected<AtomicChanges>
+RenameOccurrences::createSourceReplacements(RefactoringRuleContext &Context) {
+ Expected<SymbolOccurrences> Occurrences =
+ OccurrenceFinder(ND).findSymbolOccurrences(Context);
+ if (!Occurrences)
+ return Occurrences.takeError();
+ // FIXME: Verify that the new name is valid.
+ SymbolName Name(NewName);
+ return createRenameReplacements(
+ *Occurrences, Context.getASTContext().getSourceManager(), Name);
}
Expected<std::vector<AtomicChange>>
Index: lib/Tooling/Refactoring/RefactoringActions.cpp
===================================================================
--- lib/Tooling/Refactoring/RefactoringActions.cpp
+++ lib/Tooling/Refactoring/RefactoringActions.cpp
@@ -7,21 +7,113 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Tooling/Refactoring/Extract/ExtractFunction.h"
#include "clang/Tooling/Refactoring/RefactoringAction.h"
+#include "clang/Tooling/Refactoring/RefactoringOptions.h"
+#include "clang/Tooling/Refactoring/Rename/RenamingAction.h"
namespace clang {
namespace tooling {
-// Forward declare the individual create*Action functions.
-#define REFACTORING_ACTION(Name) \
- std::unique_ptr<RefactoringAction> create##Name##Action();
-#include "clang/Tooling/Refactoring/RefactoringActionRegistry.def"
+namespace {
+
+template <typename T> class RefactoringDescriptor;
+
+// The generic descriptors for all of the refactorings.
+
+template <>
+class RefactoringDescriptor<ExtractFunction>
+ : public RefactoringDescriptorInterface {
+public:
+ StringRef getName() const override { return "extract-function"; }
+
+ StringRef getDescription() const override {
+ return "(WIP action; use with caution!) Extracts code into a new function";
+ }
+
+ Optional<StringRef> getEditorTitle() const override {
+ return StringRef("Extract Function");
+ }
+};
+
+template <>
+class RefactoringDescriptor<RenameOccurrences>
+ : public RefactoringDescriptorInterface {
+public:
+ StringRef getName() const override { return "local-rename"; }
+
+ StringRef getDescription() const override {
+ return "Finds and renames symbols in code with no indexer support";
+ }
+};
+
+class DeclNameOption final : public OptionalRefactoringOption<std::string> {
+public:
+ StringRef getName() const { return "name"; }
+ StringRef getDescription() const {
+ return "Name of the extracted declaration";
+ }
+};
+
+// FIXME: Remove the Actions alltogether.
+class ExtractRefactoring final : public RefactoringAction {
+public:
+ StringRef getCommand() const override { return "extract"; }
+
+ StringRef getDescription() const override {
+ return "(WIP action; use with caution!) Extracts code into a new function";
+ }
+
+ /// Returns a set of refactoring actions rules that are defined by this
+ /// action.
+ RefactoringActionRules createActionRules() const override {
+ RefactoringActionRules Rules;
+ Rules.push_back(
+ createRefactoringActionRule<ExtractFunction,
+ RefactoringDescriptor<ExtractFunction>>(
+ CodeRangeASTSelectionRequirement(),
+ OptionRequirement<DeclNameOption>()));
+ return Rules;
+ }
+};
+
+class NewNameOption : public RequiredRefactoringOption<std::string> {
+public:
+ StringRef getName() const override { return "new-name"; }
+ StringRef getDescription() const override {
+ return "The new name to change the symbol to";
+ }
+};
+
+// FIXME: Remove the Actions alltogether.
+class LocalRename final : public RefactoringAction {
+public:
+ StringRef getCommand() const override { return "local-rename"; }
+
+ StringRef getDescription() const override {
+ return "Finds and renames symbols 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<RenameOccurrences,
+ RefactoringDescriptor<RenameOccurrences>>(
+ SourceRangeSelectionRequirement(),
+ OptionRequirement<NewNameOption>()));
+ return Rules;
+ }
+};
+
+} // end anonymous namespace
std::vector<std::unique_ptr<RefactoringAction>> createRefactoringActions() {
std::vector<std::unique_ptr<RefactoringAction>> Actions;
-#define REFACTORING_ACTION(Name) Actions.push_back(create##Name##Action());
-#include "clang/Tooling/Refactoring/RefactoringActionRegistry.def"
+ Actions.push_back(llvm::make_unique<LocalRename>());
+ Actions.push_back(llvm::make_unique<ExtractRefactoring>());
return Actions;
}
Index: lib/Tooling/Refactoring/Extract.cpp
===================================================================
--- lib/Tooling/Refactoring/Extract.cpp
+++ lib/Tooling/Refactoring/Extract.cpp
@@ -16,9 +16,7 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
#include "clang/Rewrite/Core/Rewriter.h"
-#include "clang/Tooling/Refactoring/RefactoringAction.h"
-#include "clang/Tooling/Refactoring/RefactoringActionRules.h"
-#include "clang/Tooling/Refactoring/RefactoringOptions.h"
+#include "clang/Tooling/Refactoring/Extract/ExtractFunction.h"
namespace clang {
namespace tooling {
@@ -44,58 +42,34 @@
}
}
-class ExtractableCodeSelectionRequirement final
- : public CodeRangeASTSelectionRequirement {
-public:
- Expected<CodeRangeASTSelection>
- evaluate(RefactoringRuleContext &Context) const {
- Expected<CodeRangeASTSelection> Selection =
- CodeRangeASTSelectionRequirement::evaluate(Context);
- if (!Selection)
- return Selection.takeError();
- CodeRangeASTSelection &Code = *Selection;
-
- // We would like to extract code out of functions/methods/blocks.
- // Prohibit extraction from things like global variable / field
- // initializers and other top-level expressions.
- if (!Code.isInFunctionLikeBodyOfCode())
- return Context.createDiagnosticError(
- diag::err_refactor_code_outside_of_function);
-
- // Avoid extraction of simple literals and references.
- if (Code.size() == 1 && isSimpleExpression(dyn_cast<Expr>(Code[0])))
- return Context.createDiagnosticError(
- diag::err_refactor_extract_simple_expression);
-
- // FIXME (Alex L): Prohibit extraction of Objective-C property setters.
- return Selection;
- }
-};
-
-class ExtractFunction final : public SourceChangeRefactoringRule {
-public:
- ExtractFunction(CodeRangeASTSelection Code, Optional<std::string> DeclName)
- : Code(std::move(Code)),
- DeclName(DeclName ? std::move(*DeclName) : "extracted") {}
-
- Expected<AtomicChanges>
- createSourceReplacements(RefactoringRuleContext &Context) override;
-
-private:
- CodeRangeASTSelection Code;
-
- // FIXME: Account for naming collisions:
- // - error when name is specified by user.
- // - rename to "extractedN" when name is implicit.
- std::string DeclName;
-};
-
SourceLocation computeFunctionExtractionLocation(const Decl *D) {
// FIXME (Alex L): Method -> function extraction should place function before
// C++ record if the method is defined inside the record.
return D->getLocStart();
}
+} // end anonymous namespace
+
+Expected<ExtractFunction>
+ExtractFunction::initiate(RefactoringRuleContext &Context,
+ CodeRangeASTSelection Code,
+ Optional<std::string> DeclName) {
+ // We would like to extract code out of functions/methods/blocks.
+ // Prohibit extraction from things like global variable / field
+ // initializers and other top-level expressions.
+ if (!Code.isInFunctionLikeBodyOfCode())
+ return Context.createDiagnosticError(
+ diag::err_refactor_code_outside_of_function);
+
+ // Avoid extraction of simple literals and references.
+ if (Code.size() == 1 && isSimpleExpression(dyn_cast<Expr>(Code[0])))
+ return Context.createDiagnosticError(
+ diag::err_refactor_extract_simple_expression);
+
+ // FIXME (Alex L): Prohibit extraction of Objective-C property setters.
+ return ExtractFunction(std::move(Code), DeclName);
+}
+
// FIXME: Support C++ method extraction.
// FIXME: Support Objective-C method extraction.
Expected<AtomicChanges>
@@ -194,39 +168,5 @@
return AtomicChanges{std::move(Change)};
}
-class DeclNameOption final : public OptionalRefactoringOption<std::string> {
-public:
- StringRef getName() const { return "name"; }
- StringRef getDescription() const {
- return "Name of the extracted declaration";
- }
-};
-
-class ExtractRefactoring final : public RefactoringAction {
-public:
- StringRef getCommand() const override { return "extract"; }
-
- StringRef getDescription() const override {
- return "(WIP action; use with caution!) Extracts code into a new function "
- "/ method / variable";
- }
-
- /// Returns a set of refactoring actions rules that are defined by this
- /// action.
- RefactoringActionRules createActionRules() const override {
- RefactoringActionRules Rules;
- Rules.push_back(createRefactoringActionRule<ExtractFunction>(
- ExtractableCodeSelectionRequirement(),
- OptionRequirement<DeclNameOption>()));
- return Rules;
- }
-};
-
-} // end anonymous namespace
-
-std::unique_ptr<RefactoringAction> createExtractAction() {
- return llvm::make_unique<ExtractRefactoring>();
-}
-
} // end namespace tooling
} // end namespace clang
Index: include/clang/module.modulemap
===================================================================
--- include/clang/module.modulemap
+++ include/clang/module.modulemap
@@ -146,8 +146,6 @@
// importing the AST matchers library gives a link dependency on the AST
// matchers (and thus the AST), which clang-format should not have.
exclude header "Tooling/RefactoringCallbacks.h"
-
- textual header "Tooling/Refactoring/RefactoringActionRegistry.def"
}
module Clang_ToolingCore {
Index: include/clang/Tooling/Refactoring/Rename/RenamingAction.h
===================================================================
--- include/clang/Tooling/Refactoring/Rename/RenamingAction.h
+++ include/clang/Tooling/Refactoring/Rename/RenamingAction.h
@@ -17,6 +17,7 @@
#include "clang/Tooling/Refactoring.h"
#include "clang/Tooling/Refactoring/AtomicChange.h"
+#include "clang/Tooling/Refactoring/RefactoringActionRules.h"
#include "clang/Tooling/Refactoring/RefactoringOptions.h"
#include "clang/Tooling/Refactoring/Rename/SymbolOccurrences.h"
#include "llvm/Support/Error.h"
@@ -46,12 +47,21 @@
bool PrintLocations;
};
-class NewNameOption : public RequiredRefactoringOption<std::string> {
+class RenameOccurrences final : public SourceChangeRefactoringRule {
public:
- StringRef getName() const override { return "new-name"; }
- StringRef getDescription() const override {
- return "The new name to change the symbol to";
- }
+ static Expected<RenameOccurrences> initiate(RefactoringRuleContext &Context,
+ SourceRange SelectionRange,
+ std::string NewName);
+
+ Expected<AtomicChanges>
+ createSourceReplacements(RefactoringRuleContext &Context) override;
+
+private:
+ RenameOccurrences(const NamedDecl *ND, std::string NewName)
+ : ND(ND), NewName(std::move(NewName)) {}
+
+ const NamedDecl *ND;
+ std::string NewName;
};
/// Returns source replacements that correspond to the rename of the given
Index: include/clang/Tooling/Refactoring/RefactoringActionRulesInternal.h
===================================================================
--- include/clang/Tooling/Refactoring/RefactoringActionRulesInternal.h
+++ include/clang/Tooling/Refactoring/RefactoringActionRulesInternal.h
@@ -57,7 +57,11 @@
return Consumer.handleError(std::move(Err));
// Construct the target action rule by extracting the evaluated
// requirements from Expected<> wrappers and then run it.
- RuleType(std::move((*std::get<Is>(Values)))...).invoke(Consumer, Context);
+ auto Rule =
+ RuleType::initiate(Context, std::move((*std::get<Is>(Values)))...);
+ if (!Rule)
+ return Consumer.handleError(Rule.takeError());
+ Rule->invoke(Consumer, Context);
}
inline void visitRefactoringOptionsImpl(RefactoringOptionVisitor &) {}
@@ -110,7 +114,8 @@
} // end namespace internal
-template <typename RuleType, typename... RequirementTypes>
+template <typename RuleType, typename DescriptorType,
+ typename... RequirementTypes>
std::unique_ptr<RefactoringActionRule>
createRefactoringActionRule(const RequirementTypes &... Requirements) {
static_assert(std::is_base_of<RefactoringActionRuleBase, RuleType>::value,
@@ -142,8 +147,15 @@
llvm::index_sequence_for<RequirementTypes...>());
}
+ const RefactoringDescriptorInterface &getDescriptor() override {
+ if (!Descriptor)
+ Descriptor = llvm::make_unique<DescriptorType>();
+ return *Descriptor;
+ }
+
private:
std::tuple<RequirementTypes...> Requirements;
+ std::unique_ptr<DescriptorType> Descriptor;
};
return llvm::make_unique<Rule>(std::make_tuple(Requirements...));
Index: include/clang/Tooling/Refactoring/RefactoringActionRules.h
===================================================================
--- include/clang/Tooling/Refactoring/RefactoringActionRules.h
+++ include/clang/Tooling/Refactoring/RefactoringActionRules.h
@@ -36,10 +36,20 @@
/// - Gather the set of options and define a command-line / visual interface
/// that allows users to input these options without ever invoking the
/// action.
-template <typename RuleType, typename... RequirementTypes>
+template <typename RuleType, typename DescriptorType,
+ typename... RequirementTypes>
std::unique_ptr<RefactoringActionRule>
createRefactoringActionRule(const RequirementTypes &... Requirements);
+/// Creates a refactoring action rule that's accessible in an editor by
+/// wrapping around the given rule.
+///
+/// \param Name the name of the editor command.
+/// \param Title the title (display string) of the editor command.
+std::unique_ptr<RefactoringActionRule>
+createEditorBinding(std::unique_ptr<RefactoringActionRule> Rule, StringRef Name,
+ StringRef Title);
+
/// A set of refactoring action rules that should have unique initiation
/// requirements.
using RefactoringActionRules =
Index: include/clang/Tooling/Refactoring/RefactoringActionRule.h
===================================================================
--- include/clang/Tooling/Refactoring/RefactoringActionRule.h
+++ include/clang/Tooling/Refactoring/RefactoringActionRule.h
@@ -11,6 +11,8 @@
#define LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULE_H
#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
#include <vector>
namespace clang {
@@ -20,6 +22,26 @@
class RefactoringResultConsumer;
class RefactoringRuleContext;
+/// Describes a refactoring rule.
+class RefactoringDescriptorInterface {
+public:
+ virtual ~RefactoringDescriptorInterface() {}
+
+ /// Returns the name of the refactoring.
+ virtual StringRef getName() const = 0;
+
+ /// Returns the human readable description of what the refactoring does.
+ virtual StringRef getDescription() const = 0;
+
+ /// Returns the title that should be used in an editor for this refactoring.
+ ///
+ /// When the refactoring has no title, it won't be available in an editor
+ /// unless the editor client explicitly supports the refactoring through
+ /// a specialized interface (like a specialized protocol entry in LSP in
+ /// clangd).
+ virtual Optional<StringRef> getEditorTitle() const { return None; }
+};
+
/// A common refactoring action rule interface that defines the 'invoke'
/// function that performs the refactoring operation (either fully or
/// partially).
@@ -52,6 +74,9 @@
/// requirements that use options, the options from the first requirement
/// are visited before the options in the second requirement.
virtual void visitRefactoringOptions(RefactoringOptionVisitor &Visitor) = 0;
+
+ /// Returns the descriptor for this refactoring rule.
+ virtual const RefactoringDescriptorInterface &getDescriptor() = 0;
};
} // end namespace tooling
Index: include/clang/Tooling/Refactoring/RefactoringActionRegistry.def
===================================================================
--- include/clang/Tooling/Refactoring/RefactoringActionRegistry.def
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef REFACTORING_ACTION
-#define REFACTORING_ACTION(Name)
-#endif
-
-REFACTORING_ACTION(LocalRename)
-REFACTORING_ACTION(Extract)
-
-#undef REFACTORING_ACTION
Index: include/clang/Tooling/Refactoring/Extract/ExtractFunction.h
===================================================================
--- /dev/null
+++ include/clang/Tooling/Refactoring/Extract/ExtractFunction.h
@@ -0,0 +1,51 @@
+//===--- ExtractFunction.h - Clang refactoring library --------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_REFACTOR_EXTRACT_EXTRACT_FUNCTION_H
+#define LLVM_CLANG_TOOLING_REFACTOR_EXTRACT_EXTRACT_FUNCTION_H
+
+#include "clang/Tooling/Refactoring/ASTSelection.h"
+#include "clang/Tooling/Refactoring/RefactoringActionRules.h"
+
+namespace clang {
+namespace tooling {
+
+/// An "Extract Function" refactoring moves code into a new function that's
+/// then called from the place where the original code was.
+class ExtractFunction final : public SourceChangeRefactoringRule {
+public:
+ /// Initiates the extract function refactoring operation.
+ ///
+ /// \param Code The selected set of statements.
+ /// \param DeclName The name name of the extract function. If None,
+ /// "extracted" is used.
+ static Expected<ExtractFunction> initiate(RefactoringRuleContext &Context,
+ CodeRangeASTSelection Code,
+ Optional<std::string> DeclName);
+
+ Expected<AtomicChanges>
+ createSourceReplacements(RefactoringRuleContext &Context) override;
+
+private:
+ ExtractFunction(CodeRangeASTSelection Code, Optional<std::string> DeclName)
+ : Code(std::move(Code)),
+ DeclName(DeclName ? std::move(*DeclName) : "extracted") {}
+
+ CodeRangeASTSelection Code;
+
+ // FIXME: Account for naming collisions:
+ // - error when name is specified by user.
+ // - rename to "extractedN" when name is implicit.
+ std::string DeclName;
+};
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_REFACTOR_EXTRACT_EXTRACT_FUNCTION_H
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits