summaryrefslogtreecommitdiffstats
path: root/docs
diff options
context:
space:
mode:
authorAlex Lorenz <arphaman@gmail.com>2017-09-29 12:21:38 +0000
committerAlex Lorenz <arphaman@gmail.com>2017-09-29 12:21:38 +0000
commitcb0496ffd71adcb5f792c06087490e4567b72324 (patch)
treecce2d5b0b1b95778b75bb9259b72f4897f4c4e75 /docs
parent94efed908a60ba04964f220f0822e3463d0dcc38 (diff)
[docs][refactor] Add refactoring engine design documentation
This commit adds a refactoring engine design document that talks about the design and provides several example of how the engine can be used. Differential Revision: https://reviews.llvm.org/D37976 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@314509 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'docs')
-rw-r--r--docs/RefactoringEngine.rst253
-rw-r--r--docs/index.rst1
2 files changed, 254 insertions, 0 deletions
diff --git a/docs/RefactoringEngine.rst b/docs/RefactoringEngine.rst
new file mode 100644
index 0000000000..581493fe40
--- /dev/null
+++ b/docs/RefactoringEngine.rst
@@ -0,0 +1,253 @@
+==========================
+Clang's refactoring engine
+==========================
+
+This document describes the design of Clang's refactoring engine and provides
+a couple of examples that show how various primitives in the refactoring API
+can be used to implement different refactoring actions. The :doc:`LibTooling`
+library provides several other APIs that are used when developing a
+refactoring action.
+
+Refactoring engine can be used to implement local refactorings that are
+initiated using a selection in an editor or an IDE. You can combine
+:doc:`AST matchers<LibASTMatchers>` and the refactoring engine to implement
+refactorings that don't lend themselves well to source selection and/or have to
+query ASTs for some particular nodes.
+
+We assume basic knowledge about the Clang AST. See the :doc:`Introduction
+to the Clang AST <IntroductionToTheClangAST>` if you want to learn more
+about how the AST is structured.
+
+.. FIXME: create new refactoring action tutorial and link to the tutorial
+
+Introduction
+------------
+
+Clang's refactoring engine defines a set refactoring actions that implement
+a number of different source transformations. The ``clang-refactor``
+command-line tool can be used to perform these refactorings. Certain
+refactorings are also available in other clients like text editors and IDEs.
+
+A refactoring action is a class that defines a list of related refactoring
+operations (rules). These rules are grouped under a common umbrella - a single
+``clang-refactor`` command. In addition to rules, the refactoring action
+provides the action's command name and description to ``clang-refactor``.
+Each action must implement the ``RefactoringAction`` interface. Here's an
+outline of a ``local-rename`` action:
+
+.. code-block:: c++
+
+ 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";
+ }
+
+ RefactoringActionRules createActionRules() const override {
+ ...
+ }
+ };
+
+Refactoring Action Rules
+------------------------
+
+An individual refactoring action is responsible for creating the set of
+grouped refactoring action rules that represent one refactoring operation.
+Although the rules in one action may have a number of different implementations,
+they should strive to produce a similar result. It should be easy for users to
+identify which refactoring action produced the result regardless of which
+refactoring action rule was used.
+
+The distinction between actions and rules enables the creation of actions
+that define a set of different rules that produce similar results. For example,
+the "add missing switch cases" refactoring operation typically adds missing
+cases to one switch at a time. However, it could be useful to have a
+refactoring that works on all switches that operate on a particular enum, as
+one could then automatically update all of them after adding a new enum
+constant. To achieve that, we can create two different rules that will use one
+``clang-refactor`` subcommand. The first rule will describe a local operation
+that's initiated when the user selects a single switch. The second rule will
+describe a global operation that works across translation units and is initiated
+when the user provides the name of the enum to clang-refactor (or the user could
+select the enum declaration instead). The clang-refactor tool will then analyze
+the selection and other options passed to the refactoring action, and will pick
+the most appropriate rule for the given selection and other options.
+
+Rule Types
+^^^^^^^^^^
+
+Clang's refactoring engine supports several different refactoring rules:
+
+- ``SourceChangeRefactoringRule`` produces source replacements that are applied
+ to the source files. Subclasses that choose to implement this rule have to
+ implement the ``createSourceReplacements`` member function. This type of
+ rule is typically used to implement local refactorings that transform the
+ source in one translation unit only.
+
+- ``FindSymbolOccurrencesRefactoringRule`` produces a "partial" refactoring
+ result: a set of occurrences that refer to a particular symbol. This type
+ of rule is typically used to implement an interactive renaming action that
+ allows users to specify which occurrences should be renamed during the
+ refactoring. Subclasses that choose to implement this rule have to implement
+ the ``findSymbolOccurrences`` member function.
+
+The following set of quick checks might help if you are unsure about the type
+of rule you should use:
+
+#. If you would like to transform the source in one translation unit and if
+ you don't need any cross-TU information, then the
+ ``SourceChangeRefactoringRule`` should work for you.
+
+#. If you would like to implement a rename-like operation with potential
+ interactive components, then ``FindSymbolOccurrencesRefactoringRule`` might
+ work for you.
+
+How to Create a Rule
+^^^^^^^^^^^^^^^^^^^^
+
+Once you determine which type of rule is suitable for your needs you can
+implement the refactoring by subclassing the rule and implementing its
+interface. The subclass should have a constructor that takes the inputs that
+are needed to perform the refactoring. For example, if you want to implement a
+rule that simply deletes a selection, you should create a subclass of
+``SourceChangeRefactoringRule`` with a constructor that accepts the selection
+range:
+
+.. code-block:: c++
+
+ class DeleteSelectedRange final : public SourceChangeRefactoringRule {
+ public:
+ DeleteSelection(SourceRange Selection) : Selection(Selection) {}
+
+ Expected<AtomicChanges>
+ createSourceReplacements(RefactoringRuleContext &Context) override {
+ AtomicChange Replacement(Context.getSources(), Selection.getBegin());
+ Replacement.replace(Context.getSource,
+ CharSourceRange::getCharRange(Selection), "");
+ return { Replacement };
+ }
+ private:
+ SourceRange Selection;
+ };
+
+The rule's subclass can then be added to the list of refactoring action's
+rules for a particular action using the ``createRefactoringActionRule``
+function. For example, the class that's shown above can be added to the
+list of action rules using the following code:
+
+.. code-block:: c++
+
+ RefactoringActionRules Rules;
+ Rules.push_back(
+ createRefactoringActionRule<DeleteSelectedRange>(
+ SourceRangeSelectionRequirement())
+ )
+
+The ``createRefactoringActionRule`` function takes in a list of refactoring
+action rule requirement values. These values describe the initiation
+requirements that have to be satisfied by the refactoring engine before the
+provided action rule can be constructed and invoked. The next section
+describes how these requirements are evaluated and lists all the possible
+requirements that can be used to construct a refactoring action rule.
+
+Refactoring Action Rule Requirements
+------------------------------------
+
+A refactoring action rule requirement is a value whose type derives from the
+``RefactoringActionRuleRequirement`` class. The type must define an
+``evaluate`` member function that returns a value of type ``Expected<...>``.
+When a requirement value is used as an argument to
+``createRefactoringActionRule``, that value is evaluated during the initiation
+of the action rule. The evaluated result is then passed to the rule's
+constructor unless the evaluation produced an error. For example, the
+``DeleteSelectedRange`` sample rule that's defined in the previous section
+will be evaluated using the following steps:
+
+#. ``SourceRangeSelectionRequirement``'s ``evaluate`` member function will be
+ called first. It will return an ``Expected<SourceRange>``.
+
+#. If the return value is an error the initiation will fail and the error
+ will be reported to the client. Note that the client may not report the
+ error to the user.
+
+#. Otherwise the source range return value will be used to construct the
+ ``DeleteSelectedRange`` rule. The rule will then be invoked as the initiation
+ succeeded (all requirements were evaluated successfully).
+
+The same series of steps applies to any refactoring rule. Firstly, the engine
+will evaluate all of the requirements. Then it will check if these requirements
+are satisfied (they should not produce an error). Then it will construct the
+rule and invoke it.
+
+The separation of requirements, their evaluation and the invocation of the
+refactoring action rule allows the refactoring clients to:
+
+- Disable refactoring action rules whose requirements are not supported.
+
+- Gather the set of options and define a command-line / visual interface
+ that allows users to input these options without ever invoking the
+ action.
+
+Selection Requirements
+^^^^^^^^^^^^^^^^^^^^^^
+
+The refactoring rule requirements that require some form of source selection
+are listed below:
+
+- ``SourceRangeSelectionRequirement`` evaluates to a source range when the
+ action is invoked with some sort of selection. This requirement should be
+ satisfied when a refactoring is initiated in an editor, even when the user
+ has not selected anything (the range will contain the cursor's location in
+ that case).
+
+.. FIXME: Future selection requirements
+
+.. FIXME: Maybe mention custom selection requirements?
+
+Other Requirements
+^^^^^^^^^^^^^^^^^^
+
+There are several other requirements types that can be used when creating
+a refactoring rule:
+
+- The ``RefactoringOptionsRequirement`` requirement is an abstract class that
+ should be subclassed by requirements working with options. The more
+ concrete ``OptionRequirement`` requirement is a simple implementation of the
+ aforementioned class that returns the value of the specified option when
+ it's evaluated. The next section talks more about refactoring options and
+ how they can be used when creating a rule.
+
+Refactoring Options
+-------------------
+
+Refactoring options are values that affect a refactoring operation and are
+specified either using command-line options or another client-specific
+mechanism. Options should be created using a class that derives either from
+the ``OptionalRequiredOption`` or ``RequiredRefactoringOption``. The following
+example shows how one can created a required string option that corresponds to
+the ``-new-name`` command-line option in clang-refactor:
+
+.. code-block:: c++
+
+ 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";
+ }
+ };
+
+The option that's shown in the example above can then be used to create
+a requirement for a refactoring rule using a requirement like
+``OptionRequirement``:
+
+.. code-block:: c++
+
+ createRefactoringActionRule<RenameOccurrences>(
+ ...,
+ OptionRequirement<NewNameOption>())
+ );
+
+.. FIXME: Editor Bindings section
diff --git a/docs/index.rst b/docs/index.rst
index 0097ebbf65..daf943a60b 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -60,6 +60,7 @@ Using Clang as a Library
LibASTMatchers
HowToSetupToolingForLLVM
JSONCompilationDatabase
+ RefactoringEngine
Using Clang Tools
=================