RefactoringEngine.rst 11 KB

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