| Index: pkg/analyzer_plugin/doc/tutorial/fixes.md
|
| diff --git a/pkg/analyzer_plugin/doc/tutorial/fixes.md b/pkg/analyzer_plugin/doc/tutorial/fixes.md
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..5563dc32cf6c67b6ee2c3204f3481c161a73f5f9
|
| --- /dev/null
|
| +++ b/pkg/analyzer_plugin/doc/tutorial/fixes.md
|
| @@ -0,0 +1,121 @@
|
| +# Providing Quick Fixes
|
| +
|
| +A quick fix is used by clients to provide a set of possible changes to code that
|
| +are based on diagnostics reported against the code. Quick fixes are intended to
|
| +help users resolve the issue being reported.
|
| +
|
| +If your plugin generates any diagnostics then you should consider providing
|
| +support for automatically fixing those diagnostics. There is often more than one
|
| +potential way of fixing a given problem, so it is possible for your plugin to
|
| +provide multiple fixes for a single problem.
|
| +
|
| +For example, if an undefined identifier is used in the code, you might return
|
| +a fix to create an appropriate definition for the identifier. If there is a
|
| +similar identifier that is already defined, you might also return a second fix
|
| +to replace the undefined identifier with the defined identifier.
|
| +
|
| +The latter example illustrates that fixes can be conditionally returned. You
|
| +will produce a better UX if only those fixes that actually make sense in the
|
| +given context are returned. If a lot of work is required to determine which
|
| +fixes make sense, it is possible to improve performance by generating different
|
| +diagnostics for the same issue, depending on the context in which the issue
|
| +occurs.
|
| +
|
| +In addition, fixes have a priority associated with them. The priority allows the
|
| +client to display the fixes that are most likely to be of use closer to the top
|
| +of the list when there are multiple fixes available.
|
| +
|
| +## Implementation details
|
| +
|
| +When appropriate, the analysis server will send your plugin an `edit.getFixes`
|
| +request. The request includes the `file` and `offset` associated with the
|
| +diagnostics for which fixes should be generated. Fixes are typically produced
|
| +for all of the diagnostics on a given line of code. Your plugin should only
|
| +return fixes associated with the errors that it produced earlier.
|
| +
|
| +When an `edit.getFixes` request is received, the method `handleEditGetFixes`
|
| +will be invoked. This method is responsible for returning a response that
|
| +contains the available fixes.
|
| +
|
| +The easiest way to implement this method is by adding the classes `FixesMixin`
|
| +and `DartFixesMixin` (from `package:analyzer_plugin/plugin/fix_mixin.dart`) to
|
| +the list of mixins for your subclass of `ServerPlugin`. This will leave you with
|
| +one abstract method that you need to implement: `getFixContributors`. That
|
| +method is responsible for returning a list of `FixContributor`s. It is the fix
|
| +contributors that produce the actual fixes. (Most plugins will only need a
|
| +single fix contributor.)
|
| +
|
| +To write a fix contributor, create a class that implements `FixContributor`. The
|
| +interface defines a single method named `computeFixes`. The method has two
|
| +arguments: a `FixesRequest` that describes the errors that should be fixed and a
|
| +`FixCollector` through which fixes are to be added. (If you use the mixins above
|
| +then the list of errors available through the request object will only include
|
| +the errors for which fixes should be returned.)
|
| +
|
| +The class `FixContributorMixin` defines a simple implementation of this method
|
| +that captures the two arguments in fields, iterates through the errors, and
|
| +invokes a method named `computeFixesForError` for each of the errors for which
|
| +fixes are to be computed.
|
| +
|
| +## Example
|
| +
|
| +Start by creating a class that implements `FixContributor` and that mixes in the
|
| +class `FixContributorMixin`, then implement the method `computeFixesForError`.
|
| +This method is typically implemented by a series of `if` statements that test
|
| +the error code and invoke individual methods that compute the actual fixes to be
|
| +proposed. (In addition to keeping the method `computeFixesForError` shorter,
|
| +this also allows some fixes to be used for multiple error codes.)
|
| +
|
| +To learn about the support available for creating the edits, see
|
| +[Creating Edits][creatingEdits].
|
| +
|
| +For example, your contributor might look something like the following:
|
| +
|
| +```dart
|
| +class MyFixContributor extends Object
|
| + with FixContributorMixin
|
| + implements FixContributor {
|
| + static FixKind defineComponent =
|
| + new FixKind('defineComponent', 100, "Define a component named {0}");
|
| +
|
| + AnalysisSession get session => request.result.session;
|
| +
|
| + @override
|
| + void computeFixesForError(AnalysisError error) {
|
| + ErrorCode code = error.errorCode;
|
| + if (code == MyErrorCode.undefinedComponent) {
|
| + _defineComponent(error);
|
| + _useExistingComponent(error);
|
| + }
|
| + }
|
| +
|
| + void _defineComponent(AnalysisError error) {
|
| + // TODO Get the name from the source code.
|
| + String componentName = null;
|
| + ChangeBuilder builder = new DartChangeBuilder(session);
|
| + // TODO Build the edit to insert the definition of the component.
|
| + addFix(error, defineComponent, builder, args: [componentName]);
|
| + }
|
| +
|
| + void _useExistingComponent(AnalysisError error) {
|
| + // ...
|
| + }
|
| +}
|
| +```
|
| +
|
| +Given a contributor like the one above, you can implement your plugin similar to
|
| +the following:
|
| +
|
| +```dart
|
| +class MyPlugin extends ServerPlugin with FixesMixin, DartFixesMixin {
|
| + // ...
|
| +
|
| + @override
|
| + List<FixContributor> getFixContributors(
|
| + covariant AnalysisDriverGeneric driver) {
|
| + return <FixContributor>[new MyFixContributor()];
|
| + }
|
| +}
|
| +```
|
| +
|
| +[creatingEdits]: creating_edits.md
|
|
|