Skip to content

Commit 30a9f13

Browse files
srawlinsCommit Queue
authored andcommitted
DAS plugins: document assists
Change-Id: I2c50f36111cc319a85ad1a09369bcbdda14416d8 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/419762 Reviewed-by: Brian Wilkerson <[email protected]> Commit-Queue: Samuel Rawlins <[email protected]>
1 parent 9c88769 commit 30a9f13

File tree

3 files changed

+140
-20
lines changed

3 files changed

+140
-20
lines changed

pkg/analysis_server_plugin/doc/writing_a_plugin.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,16 +37,16 @@ final plugin = SimplePlugin();
3737
class SimplePlugin extends Plugin {
3838
@override
3939
void register(PluginRegistry registry) {
40-
// Here we register analysis rules, and quick fixes.
40+
// Here we register analysis rules, quick fixes, and quick assists.
4141
}
4242
}
4343
```
4444

4545
Here we have a class, `SimplePlugin`, which extends the `Plugin` class from the
4646
`analysis_server_plugin` package. This class has one method that we override:
47-
`register`. In the `register` method, we can register analysis rules and quick
48-
fixes (CorrectionProducers). See details in the [writing rules][] doc, and the
49-
[writing fixes][] doc.
47+
`register`. In the `register` method, we can register analysis rules, quick
48+
fixes, and quick assists (CorrectionProducers). See details in the
49+
[writing rules][] doc, and the [writing fixes][] and [writing assists][] docs.
5050

5151
Additionally, we provide a top-level variable in this file called `plugin`,
5252
which is an instance of our `SimplePlugin` class. When a running instance of
@@ -65,4 +65,5 @@ can help in debugging plugin code.
6565

6666
[writing rules]: https://github.com/dart-lang/sdk/blob/main/pkg/analysis_server_plugin/doc/writing_rules.md
6767
[writing fixes]: https://github.com/dart-lang/sdk/blob/main/pkg/analysis_server_plugin/doc/writing_fixes.md
68+
[writing assists]: https://github.com/dart-lang/sdk/blob/main/pkg/analysis_server_plugin/doc/writing_assists.md
6869
[analyzer diagnostics pages]: https://github.com/dart-lang/sdk/blob/main/pkg/analysis_server/doc/tutorial/instrumentation.md#open-the-analyzer-diagnostics-pages
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
# Writing assists
2+
3+
This package gives analyzer plugin authors the ability to write "quick assists,"
4+
which can make local changes to source code, like small refactorings, from a
5+
developer's IDE. This document describes briefly how to write such an assist,
6+
and how to register it in an analyzer plugin.
7+
8+
## The ResolvedCorrectionProducer class
9+
10+
A quick assist is specified by subclassing the ResolvedCorrectionProducer class.
11+
Here is our example:
12+
13+
```dart
14+
import 'package:analysis_server_plugin/edit/dart/correction_producer.dart';
15+
import 'package:analyzer/dart/ast/ast.dart';
16+
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
17+
import 'package:analyzer_plugin/utilities/assist/assist.dart';
18+
import 'package:analyzer_plugin/utilities/range_factory.dart';
19+
20+
class RemoveAwait extends ResolvedCorrectionProducer {
21+
static const _removeAwaitKind = AssistKind(
22+
'dart.assist.removeAwait', 30 /* default */, "Remove the 'await' keyword");
23+
24+
RemoveAwait({required super.context});
25+
26+
@override
27+
CorrectionApplicability get applicability =>
28+
CorrectionApplicability.singleLocation;
29+
30+
@override
31+
AssistKind get assistKind => _removeAwaitKind;
32+
33+
@override
34+
Future<void> compute(ChangeBuilder builder) async {
35+
var awaitExpression = node;
36+
if (awaitExpression is AwaitExpression) {
37+
var awaitToken = awaitExpression.awaitKeyword;
38+
await builder.addDartFileEdit(file, (builder) {
39+
builder.addDeletion(range.startStart(awaitToken, awaitToken.next!));
40+
});
41+
}
42+
}
43+
}
44+
```
45+
46+
Let's look at each declaration individually:
47+
48+
* `class RemoveAwait` - A quick assist is a class that extends
49+
`ResolvedCorrectionProducer`. The name of the base class indicates that an
50+
instance of this class can produce "corrections" (a set of edits) for a
51+
resolved library.
52+
* `static const _removeAwaitKind = AssistKind(...)` - Each quick assist must
53+
have an associated `AssistKind` which has a unique `id`
54+
(`'dart.assist.removeAwait'`), a priority (`DartFixKindPriority.standard` is a
55+
fine default), and a message which is displayed in the IDE
56+
(`"Remove the 'await' keyword"`).
57+
* `RemoveAwait({required super.context});` - A standard constructor that accepts
58+
a `CorrectionProducerContext` and passes it up to the super-constructor.
59+
* `CorrectionApplicability get applicability =>` - the applicability field
60+
describes how widely an assist can be applied safely and sensibly. Currently,
61+
only `CorrectionApplicability.singleLocation` should be used.
62+
* `AssistKind get assistKind => _removeAwaitKind;` - each instance of this class
63+
can refer to the static field for it's `assistKind`.
64+
* `Future<void> compute(ChangeBuilder builder)` - This method is called when the
65+
client has requested quick assists at a specific location, and we want a
66+
possible correction from this correction producer. This is the code that
67+
looks at the `node` field and surrounding code and determines what correction
68+
to offer, if any.
69+
70+
* `await builder.addDartFileEdit(...)` - Once we have determined that we want
71+
to offer an assist, we call this method, and specify code deletions,
72+
insertions, and/or replacements inside the callback function. If there are
73+
cases where this correction producer will not offer any quick assists (such
74+
as the source code having certain properties), then those cases should be
75+
checked so that we don't call this method in such cases.
76+
* `builder.addDeletion(...)` - For this assist (removing an `await` keyword),
77+
we can use `addDeletion` to specify a range of source code text to delete.
78+
The `DartFileEditBuilder` class has many utilities for adding various edits.
79+
80+
Writing a quick assist can be non-trivial, even for changes which are
81+
conceptually simple. It may be helpful to see examples that are similar to a
82+
desired assist. See the [assists that are offered by Dart Analysis
83+
Server][existing-assists] for hundreds of examples.
84+
85+
Instances of the correction producer class are short-lived, and they can contain
86+
state related to the source-code-under-analysis. Indeed, the
87+
`CorrectionProducerContext`, which is passed into the constructor, and available
88+
as a field in the super-class, contains information specific to the
89+
code-under-analysis.
90+
91+
## Registering a quick assist
92+
93+
In order for a quick assist to be used in an analyzer plugin, it must be
94+
registered. Register the quick assist's constructor inside a plugin's
95+
`register` method:
96+
97+
```dart
98+
import 'package:analysis_server_plugin/plugin.dart';
99+
import 'package:analysis_server_plugin/registry.dart';
100+
101+
final plugin = SimplePlugin();
102+
103+
class SimplePlugin extends Plugin {
104+
@override
105+
void register(PluginRegistry registry) {
106+
registry.registerAssist(RemoveAwait.new);
107+
}
108+
}
109+
```
110+
111+
Instances of correction producers contain state related to the specific
112+
source-code-under-analysis, which is why the constructor is given here,
113+
instead of a long-lived instance.
114+
115+
See [writing a plugin][] for information about the `Plugin` class.
116+
117+
[writing rules]: https://github.com/dart-lang/sdk/blob/main/pkg/analysis_server_plugin/doc/writing_rules.md
118+
[existing-assists]: https://github.com/dart-lang/sdk/tree/main/pkg/analysis_server/lib/src/services/correction/dart
119+
[writing a plugin]: https://github.com/dart-lang/sdk/blob/main/pkg/analysis_server_plugin/doc/writing_rules.md

pkg/analysis_server_plugin/doc/writing_fixes.md

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ register it in an analyzer plugin.
88
## The analysis rule
99

1010
A quick fix must be associated with a diagnostic in order to be presented to a
11-
devloper in their IDE. (There is a separate feature calls "assists" which do
12-
not need to be associated with diagnostics; analyzer plugins can't currently
13-
offer assists.)
11+
developer in their IDE. (There is a separate feature calls "assists" which do
12+
not need to be associated with diagnostics; see the
13+
[writing assists][] doc.)
1414

1515
For this guide, we will be using the "MyRule" rule from the [writing rules][]
1616
guide.
@@ -31,9 +31,9 @@ import 'package:analyzer_plugin/utilities/range_factory.dart';
3131
3232
class RemoveAwait extends ResolvedCorrectionProducer {
3333
static const _removeAwaitKind = FixKind(
34-
'dart.fix.moveBelowEnclosingTestCall',
34+
'dart.fix.removeAwait',
3535
DartFixKindPriority.standard,
36-
"Move below the enclosing 'test' call");
36+
"Remove the 'await' keyword");
3737
3838
RemoveAwait({required super.context});
3939
@@ -65,12 +65,11 @@ Let's look at each declaration individually:
6565
resolved library.
6666
* `static const _removeAwaitKind = FixKind(...)` - Each quick fix must have an
6767
associated `FixKind` which has a unique `id`
68-
(`'dart.fix.moveBelowEnclosingTestCall'`), a priority
69-
(`DartFixKindPriority.standard` is a fine default), and a message which is
70-
displayed in the IDE (`"Move below the enclosing 'test' call"`).
71-
* `RemoveAwait({required super.context});` - A standard constructor that
72-
accepts a `CorrectionProducerContext` and passes it up to the
73-
super-constructor.
68+
(`'dart.fix.removeAwait'`), a priority (`DartFixKindPriority.standard` is a
69+
fine default), and a message which is displayed in the IDE
70+
(`"Remove the 'await' keyword"`).
71+
* `RemoveAwait({required super.context});` - A standard constructor that accepts
72+
a `CorrectionProducerContext` and passes it up to the super-constructor.
7473
* `CorrectionApplicability get applicability =>` - the applicability field
7574
describes how widely a fix can be applied safely and sensibly. Currently,
7675
fixes registered in plugins cannot be applied in bulk, so only
@@ -99,11 +98,11 @@ Let's look at each declaration individually:
9998
desired fix. See the [fixes that are offered by Dart Analysis
10099
Server][existing-fixes] for hundreds of examples.
101100

102-
Instances of the correction producer class are short-lived, and they can
103-
contain state related to the specific reported diagnostic and
104-
code-under-analysis. Indeed, the `CorrectionProducerContext`, which is passed
105-
into the constructor, and available as a field in the super-class, contains
106-
information specific to the code-under-analysis and the diagnostic.
101+
Instances of the correction producer class are short-lived, and they can contain
102+
state related to the specific reported diagnostic and code-under-analysis.
103+
Indeed, the `CorrectionProducerContext`, which is passed into the constructor,
104+
and available as a field in the super-class, contains information specific to
105+
the code-under-analysis and the diagnostic.
107106

108107
## Registering a quick fix
109108

@@ -135,5 +134,6 @@ instead of a long-lived instance.
135134
See [writing a plugin][] for information about the `Plugin` class.
136135

137136
[writing rules]: https://github.com/dart-lang/sdk/blob/main/pkg/analysis_server_plugin/doc/writing_rules.md
137+
[writing assists]: https://github.com/dart-lang/sdk/blob/main/pkg/analysis_server_plugin/doc/writing_assists.md
138138
[existing-fixes]: https://github.com/dart-lang/sdk/tree/main/pkg/analysis_server/lib/src/services/correction/dart
139139
[writing a plugin]: https://github.com/dart-lang/sdk/blob/main/pkg/analysis_server_plugin/doc/writing_rules.md

0 commit comments

Comments
 (0)