OLD | NEW |
(Empty) | |
| 1 # Providing Quick Fixes |
| 2 |
| 3 A quick fix is used by clients to provide a set of possible changes to code that |
| 4 are based on diagnostics reported against the code. Quick fixes are intended to |
| 5 help users resolve the issue being reported. |
| 6 |
| 7 If your plugin generates any diagnostics then you should consider providing |
| 8 support for automatically fixing those diagnostics. There is often more than one |
| 9 potential way of fixing a given problem, so it is possible for your plugin to |
| 10 provide multiple fixes for a single problem. |
| 11 |
| 12 For example, if an undefined identifier is used in the code, you might return |
| 13 a fix to create an appropriate definition for the identifier. If there is a |
| 14 similar identifier that is already defined, you might also return a second fix |
| 15 to replace the undefined identifier with the defined identifier. |
| 16 |
| 17 The latter example illustrates that fixes can be conditionally returned. You |
| 18 will produce a better UX if only those fixes that actually make sense in the |
| 19 given context are returned. If a lot of work is required to determine which |
| 20 fixes make sense, it is possible to improve performance by generating different |
| 21 diagnostics for the same issue, depending on the context in which the issue |
| 22 occurs. |
| 23 |
| 24 In addition, fixes have a priority associated with them. The priority allows the |
| 25 client to display the fixes that are most likely to be of use closer to the top |
| 26 of the list when there are multiple fixes available. |
| 27 |
| 28 ## Implementation details |
| 29 |
| 30 When appropriate, the analysis server will send your plugin an `edit.getFixes` |
| 31 request. The request includes the `file` and `offset` associated with the |
| 32 diagnostics for which fixes should be generated. Fixes are typically produced |
| 33 for all of the diagnostics on a given line of code. Your plugin should only |
| 34 return fixes associated with the errors that it produced earlier. |
| 35 |
| 36 When an `edit.getFixes` request is received, the method `handleEditGetFixes` |
| 37 will be invoked. This method is responsible for returning a response that |
| 38 contains the available fixes. |
| 39 |
| 40 The easiest way to implement this method is by adding the classes `FixesMixin` |
| 41 and `DartFixesMixin` (from `package:analyzer_plugin/plugin/fix_mixin.dart`) to |
| 42 the list of mixins for your subclass of `ServerPlugin`. This will leave you with |
| 43 one abstract method that you need to implement: `getFixContributors`. That |
| 44 method is responsible for returning a list of `FixContributor`s. It is the fix |
| 45 contributors that produce the actual fixes. (Most plugins will only need a |
| 46 single fix contributor.) |
| 47 |
| 48 To write a fix contributor, create a class that implements `FixContributor`. The |
| 49 interface defines a single method named `computeFixes`. The method has two |
| 50 arguments: a `FixesRequest` that describes the errors that should be fixed and a |
| 51 `FixCollector` through which fixes are to be added. (If you use the mixins above |
| 52 then the list of errors available through the request object will only include |
| 53 the errors for which fixes should be returned.) |
| 54 |
| 55 The class `FixContributorMixin` defines a simple implementation of this method |
| 56 that captures the two arguments in fields, iterates through the errors, and |
| 57 invokes a method named `computeFixesForError` for each of the errors for which |
| 58 fixes are to be computed. |
| 59 |
| 60 ## Example |
| 61 |
| 62 Start by creating a class that implements `FixContributor` and that mixes in the |
| 63 class `FixContributorMixin`, then implement the method `computeFixesForError`. |
| 64 This method is typically implemented by a series of `if` statements that test |
| 65 the error code and invoke individual methods that compute the actual fixes to be |
| 66 proposed. (In addition to keeping the method `computeFixesForError` shorter, |
| 67 this also allows some fixes to be used for multiple error codes.) |
| 68 |
| 69 To learn about the support available for creating the edits, see |
| 70 [Creating Edits][creatingEdits]. |
| 71 |
| 72 For example, your contributor might look something like the following: |
| 73 |
| 74 ```dart |
| 75 class MyFixContributor extends Object |
| 76 with FixContributorMixin |
| 77 implements FixContributor { |
| 78 static FixKind defineComponent = |
| 79 new FixKind('defineComponent', 100, "Define a component named {0}"); |
| 80 |
| 81 AnalysisSession get session => request.result.session; |
| 82 |
| 83 @override |
| 84 void computeFixesForError(AnalysisError error) { |
| 85 ErrorCode code = error.errorCode; |
| 86 if (code == MyErrorCode.undefinedComponent) { |
| 87 _defineComponent(error); |
| 88 _useExistingComponent(error); |
| 89 } |
| 90 } |
| 91 |
| 92 void _defineComponent(AnalysisError error) { |
| 93 // TODO Get the name from the source code. |
| 94 String componentName = null; |
| 95 ChangeBuilder builder = new DartChangeBuilder(session); |
| 96 // TODO Build the edit to insert the definition of the component. |
| 97 addFix(error, defineComponent, builder, args: [componentName]); |
| 98 } |
| 99 |
| 100 void _useExistingComponent(AnalysisError error) { |
| 101 // ... |
| 102 } |
| 103 } |
| 104 ``` |
| 105 |
| 106 Given a contributor like the one above, you can implement your plugin similar to |
| 107 the following: |
| 108 |
| 109 ```dart |
| 110 class MyPlugin extends ServerPlugin with FixesMixin, DartFixesMixin { |
| 111 // ... |
| 112 |
| 113 @override |
| 114 List<FixContributor> getFixContributors( |
| 115 covariant AnalysisDriverGeneric driver) { |
| 116 return <FixContributor>[new MyFixContributor()]; |
| 117 } |
| 118 } |
| 119 ``` |
| 120 |
| 121 [creatingEdits]: creating_edits.md |
OLD | NEW |