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