Home | History | Annotate | Line # | Download | only in docs
      1 ==========================
      2 Clang's refactoring engine
      3 ==========================
      4 
      5 This document describes the design of Clang's refactoring engine and provides
      6 a couple of examples that show how various primitives in the refactoring API
      7 can be used to implement different refactoring actions. The :doc:`LibTooling`
      8 library provides several other APIs that are used when developing a
      9 refactoring action.
     10 
     11 Refactoring engine can be used to implement local refactorings that are
     12 initiated using a selection in an editor or an IDE. You can combine
     13 :doc:`AST matchers<LibASTMatchers>` and the refactoring engine to implement
     14 refactorings that don't lend themselves well to source selection and/or have to
     15 query ASTs for some particular nodes.
     16 
     17 We assume basic knowledge about the Clang AST. See the :doc:`Introduction
     18 to the Clang AST <IntroductionToTheClangAST>` if you want to learn more
     19 about how the AST is structured.
     20 
     21 ..  FIXME: create new refactoring action tutorial and link to the tutorial
     22 
     23 Introduction
     24 ------------
     25 
     26 Clang's refactoring engine defines a set refactoring actions that implement
     27 a number of different source transformations. The ``clang-refactor``
     28 command-line tool can be used to perform these refactorings. Certain
     29 refactorings are also available in other clients like text editors and IDEs.
     30 
     31 A refactoring action is a class that defines a list of related refactoring
     32 operations (rules). These rules are grouped under a common umbrella - a single
     33 ``clang-refactor`` command. In addition to rules, the refactoring action
     34 provides the action's command name and description to ``clang-refactor``.
     35 Each action must implement the ``RefactoringAction`` interface. Here's an
     36 outline of a ``local-rename`` action:
     37 
     38 .. code-block:: c++
     39 
     40   class LocalRename final : public RefactoringAction {
     41   public:
     42     StringRef getCommand() const override { return "local-rename"; }
     43 
     44     StringRef getDescription() const override {
     45       return "Finds and renames symbols in code with no indexer support";
     46     }
     47 
     48     RefactoringActionRules createActionRules() const override {
     49       ...
     50     }
     51   };
     52 
     53 Refactoring Action Rules
     54 ------------------------
     55 
     56 An individual refactoring action is responsible for creating the set of
     57 grouped refactoring action rules that represent one refactoring operation.
     58 Although the rules in one action may have a number of different implementations,
     59 they should strive to produce a similar result. It should be easy for users to
     60 identify which refactoring action produced the result regardless of which
     61 refactoring action rule was used.
     62 
     63 The distinction between actions and rules enables the creation of actions
     64 that define a set of different rules that produce similar results. For example,
     65 the "add missing switch cases" refactoring operation typically adds missing
     66 cases to one switch at a time. However, it could be useful to have a
     67 refactoring that works on all switches that operate on a particular enum, as
     68 one could then automatically update all of them after adding a new enum
     69 constant. To achieve that, we can create two different rules that will use one
     70 ``clang-refactor`` subcommand. The first rule will describe a local operation
     71 that's initiated when the user selects a single switch. The second rule will
     72 describe a global operation that works across translation units and is initiated
     73 when the user provides the name of the enum to clang-refactor (or the user could
     74 select the enum declaration instead). The clang-refactor tool will then analyze
     75 the selection and other options passed to the refactoring action, and will pick
     76 the most appropriate rule for the given selection and other options.
     77 
     78 Rule Types
     79 ^^^^^^^^^^
     80 
     81 Clang's refactoring engine supports several different refactoring rules:
     82 
     83 - ``SourceChangeRefactoringRule`` produces source replacements that are applied
     84   to the source files. Subclasses that choose to implement this rule have to
     85   implement the ``createSourceReplacements`` member function. This type of
     86   rule is typically used to implement local refactorings that transform the
     87   source in one translation unit only.
     88 
     89 - ``FindSymbolOccurrencesRefactoringRule`` produces a "partial" refactoring
     90   result: a set of occurrences that refer to a particular symbol. This type
     91   of rule is typically used to implement an interactive renaming action that
     92   allows users to specify which occurrences should be renamed during the
     93   refactoring. Subclasses that choose to implement this rule have to implement
     94   the ``findSymbolOccurrences`` member function.
     95 
     96 The following set of quick checks might help if you are unsure about the type
     97 of rule you should use:
     98 
     99 #. If you would like to transform the source in one translation unit and if
    100    you don't need any cross-TU information, then the
    101    ``SourceChangeRefactoringRule`` should work for you.
    102 
    103 #. If you would like to implement a rename-like operation with potential
    104    interactive components, then ``FindSymbolOccurrencesRefactoringRule`` might
    105    work for you.
    106 
    107 How to Create a Rule
    108 ^^^^^^^^^^^^^^^^^^^^
    109 
    110 Once you determine which type of rule is suitable for your needs you can
    111 implement the refactoring by subclassing the rule and implementing its
    112 interface. The subclass should have a constructor that takes the inputs that
    113 are needed to perform the refactoring. For example, if you want to implement a
    114 rule that simply deletes a selection, you should create a subclass of
    115 ``SourceChangeRefactoringRule`` with a constructor that accepts the selection
    116 range:
    117 
    118 .. code-block:: c++
    119 
    120   class DeleteSelectedRange final : public SourceChangeRefactoringRule {
    121   public:
    122     DeleteSelection(SourceRange Selection) : Selection(Selection) {}
    123 
    124     Expected<AtomicChanges>
    125     createSourceReplacements(RefactoringRuleContext &Context) override {
    126       AtomicChange Replacement(Context.getSources(), Selection.getBegin());
    127       Replacement.replace(Context.getSource,
    128                           CharSourceRange::getCharRange(Selection), "");
    129       return { Replacement };
    130     }
    131   private:
    132     SourceRange Selection;
    133   };
    134 
    135 The rule's subclass can then be added to the list of refactoring action's
    136 rules for a particular action using the ``createRefactoringActionRule``
    137 function. For example, the class that's shown above can be added to the
    138 list of action rules using the following code:
    139 
    140 .. code-block:: c++
    141 
    142   RefactoringActionRules Rules;
    143   Rules.push_back(
    144     createRefactoringActionRule<DeleteSelectedRange>(
    145           SourceRangeSelectionRequirement())
    146   );
    147 
    148 The ``createRefactoringActionRule`` function takes in a list of refactoring
    149 action rule requirement values. These values describe the initiation
    150 requirements that have to be satisfied by the refactoring engine before the
    151 provided action rule can be constructed and invoked. The next section
    152 describes how these requirements are evaluated and lists all the possible
    153 requirements that can be used to construct a refactoring action rule.
    154 
    155 Refactoring Action Rule Requirements
    156 ------------------------------------
    157 
    158 A refactoring action rule requirement is a value whose type derives from the
    159 ``RefactoringActionRuleRequirement`` class. The type must define an
    160 ``evaluate`` member function that returns a value of type ``Expected<...>``.
    161 When a requirement value is used as an argument to
    162 ``createRefactoringActionRule``, that value is evaluated during the initiation
    163 of the action rule. The evaluated result is then passed to the rule's
    164 constructor unless the evaluation produced an error. For example, the
    165 ``DeleteSelectedRange`` sample rule that's defined in the previous section
    166 will be evaluated using the following steps:
    167 
    168 #. ``SourceRangeSelectionRequirement``'s ``evaluate`` member function will be
    169    called first. It will return an ``Expected<SourceRange>``.
    170 
    171 #. If the return value is an error the initiation will fail and the error
    172    will be reported to the client. Note that the client may not report the
    173    error to the user.
    174 
    175 #. Otherwise the source range return value will be used to construct the
    176    ``DeleteSelectedRange`` rule. The rule will then be invoked as the initiation
    177    succeeded (all requirements were evaluated successfully).
    178 
    179 The same series of steps applies to any refactoring rule. Firstly, the engine
    180 will evaluate all of the requirements. Then it will check if these requirements
    181 are satisfied (they should not produce an error). Then it will construct the
    182 rule and invoke it.
    183 
    184 The separation of requirements, their evaluation and the invocation of the
    185 refactoring action rule allows the refactoring clients to:
    186 
    187 - Disable refactoring action rules whose requirements are not supported.
    188 
    189 - Gather the set of options and define a command-line / visual interface
    190   that allows users to input these options without ever invoking the
    191   action.
    192 
    193 Selection Requirements
    194 ^^^^^^^^^^^^^^^^^^^^^^
    195 
    196 The refactoring rule requirements that require some form of source selection
    197 are listed below:
    198 
    199 - ``SourceRangeSelectionRequirement`` evaluates to a source range when the
    200   action is invoked with some sort of selection. This requirement should be
    201   satisfied when a refactoring is initiated in an editor, even when the user
    202   has not selected anything (the range will contain the cursor's location in
    203   that case).
    204 
    205 ..  FIXME: Future selection requirements
    206 
    207 ..  FIXME: Maybe mention custom selection requirements?
    208 
    209 Other Requirements
    210 ^^^^^^^^^^^^^^^^^^
    211 
    212 There are several other requirements types that can be used when creating
    213 a refactoring rule:
    214 
    215 - The ``RefactoringOptionsRequirement`` requirement is an abstract class that
    216   should be subclassed by requirements working with options. The more
    217   concrete ``OptionRequirement`` requirement is a simple implementation of the
    218   aforementioned class that returns the value of the specified option when
    219   it's evaluated. The next section talks more about refactoring options and
    220   how they can be used when creating a rule.
    221 
    222 Refactoring Options
    223 -------------------
    224 
    225 Refactoring options are values that affect a refactoring operation and are
    226 specified either using command-line options or another client-specific
    227 mechanism. Options should be created using a class that derives either from
    228 the ``OptionalRequiredOption`` or ``RequiredRefactoringOption``. The following
    229 example shows how one can created a required string option that corresponds to
    230 the ``-new-name`` command-line option in clang-refactor:
    231 
    232 .. code-block:: c++
    233 
    234   class NewNameOption : public RequiredRefactoringOption<std::string> {
    235   public:
    236     StringRef getName() const override { return "new-name"; }
    237     StringRef getDescription() const override {
    238       return "The new name to change the symbol to";
    239     }
    240   };
    241 
    242 The option that's shown in the example above can then be used to create
    243 a requirement for a refactoring rule using a requirement like
    244 ``OptionRequirement``:
    245 
    246 .. code-block:: c++
    247 
    248   createRefactoringActionRule<RenameOccurrences>(
    249     ...,
    250     OptionRequirement<NewNameOption>())
    251   );
    252 
    253 ..  FIXME: Editor Bindings section
    254