Skip to content

Commit ff75aeb

Browse files
srawlinsCommit Queue
authored andcommitted
DAS plugins: Support assists in plugins
To support this feature: * Remove `DartAssistContextImpl` as it has no differences from `DartAssistContext`. Thus the getters `DartAssistContext` are made into fields, and all callers now call `DartAssistContext()`. * Add a top level `computeAssists` function, similar to the top-level `computeFixes` function. Change-Id: I3ef5fd9ee9430150004b29c11ab972939b85b214 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/417360 Reviewed-by: Brian Wilkerson <[email protected]> Reviewed-by: Phil Quitslund <[email protected]> Commit-Queue: Samuel Rawlins <[email protected]>
1 parent 1d99b13 commit ff75aeb

File tree

11 files changed

+157
-76
lines changed

11 files changed

+157
-76
lines changed

pkg/analysis_server/lib/src/cider/assists.dart

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5-
import 'package:analysis_server/src/services/correction/assist.dart';
65
import 'package:analysis_server_plugin/src/correction/assist_core.dart';
6+
import 'package:analysis_server_plugin/src/correction/assist_dart.dart';
77
import 'package:analysis_server_plugin/src/correction/assist_processor.dart';
88
import 'package:analysis_server_plugin/src/correction/dart_change_workspace.dart';
99
import 'package:analyzer/dart/analysis/session.dart';
@@ -33,19 +33,16 @@ class CiderAssistsComputer {
3333

3434
await _logger.runAsync('Compute assists', () async {
3535
try {
36-
var workspace = DartChangeWorkspace([resolvedUnit.session]);
37-
var context = DartAssistContextImpl(
36+
var context = DartAssistContext(
3837
InstrumentationService.NULL_SERVICE,
39-
workspace,
38+
DartChangeWorkspace([resolvedUnit.session]),
4039
resolvedLibrary,
4140
resolvedUnit,
4241
offset,
4342
length,
4443
);
45-
var processor = AssistProcessor(context);
46-
var assists = await processor.compute();
47-
assists.sort(Assist.compareAssists);
48-
result.addAll(assists);
44+
var assists = await computeAssists(context);
45+
result.addAll(assists..sort(Assist.compareAssists));
4946
} on InconsistentAnalysisException {
5047
// If an InconsistentAnalysisException occurs, it's likely the user modified
5148
// the source and therefore is no longer interested in the results.

pkg/analysis_server/lib/src/handler/legacy/edit_get_assists.dart

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ import 'package:analysis_server/src/handler/legacy/legacy_handler.dart';
1010
import 'package:analysis_server/src/legacy_analysis_server.dart';
1111
import 'package:analysis_server/src/plugin/result_converter.dart';
1212
import 'package:analysis_server/src/request_handler_mixin.dart';
13-
import 'package:analysis_server/src/services/correction/assist.dart';
1413
import 'package:analysis_server_plugin/src/correction/assist_core.dart';
14+
import 'package:analysis_server_plugin/src/correction/assist_dart.dart';
1515
import 'package:analysis_server_plugin/src/correction/assist_performance.dart';
1616
import 'package:analysis_server_plugin/src/correction/assist_processor.dart';
1717
import 'package:analysis_server_plugin/src/correction/dart_change_workspace.dart';
@@ -101,7 +101,7 @@ class EditGetAssistsHandler extends LegacyHandler
101101

102102
if (libraryResult != null) {
103103
var unitResult = libraryResult.unitWithPath(file)!;
104-
var context = DartAssistContextImpl(
104+
var context = DartAssistContext(
105105
server.instrumentationService,
106106
DartChangeWorkspace(await server.currentSessions),
107107
libraryResult,
@@ -112,12 +112,10 @@ class EditGetAssistsHandler extends LegacyHandler
112112

113113
try {
114114
var performanceTracker = AssistPerformance();
115-
var processor = AssistProcessor(
115+
var assists = await computeAssists(
116116
context,
117117
performance: performanceTracker,
118118
);
119-
120-
var assists = await processor.compute();
121119
assists.sort(Assist.compareAssists);
122120
for (var assist in assists) {
123121
changes.add(assist.change);

pkg/analysis_server/lib/src/lsp/handlers/code_actions/dart.dart

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@ import 'package:analysis_server/src/lsp/handlers/code_actions/abstract_code_acti
1010
import 'package:analysis_server/src/lsp/mapping.dart';
1111
import 'package:analysis_server/src/protocol_server.dart'
1212
hide AnalysisOptions, Position;
13-
import 'package:analysis_server/src/services/correction/assist.dart';
1413
import 'package:analysis_server/src/services/correction/fix_performance.dart';
1514
import 'package:analysis_server/src/services/correction/refactoring_performance.dart';
1615
import 'package:analysis_server/src/services/refactoring/framework/refactoring_context.dart';
1716
import 'package:analysis_server/src/services/refactoring/framework/refactoring_processor.dart';
1817
import 'package:analysis_server/src/services/refactoring/legacy/refactoring.dart';
1918
import 'package:analysis_server_plugin/edit/fix/dart_fix_context.dart';
2019
import 'package:analysis_server_plugin/src/correction/assist_core.dart';
20+
import 'package:analysis_server_plugin/src/correction/assist_dart.dart';
2121
import 'package:analysis_server_plugin/src/correction/assist_performance.dart';
2222
import 'package:analysis_server_plugin/src/correction/assist_processor.dart';
2323
import 'package:analysis_server_plugin/src/correction/dart_change_workspace.dart';
@@ -124,14 +124,13 @@ class DartCodeActionsProducer extends AbstractCodeActionsProducer {
124124
}) async {
125125
// These assists are only provided as literal CodeActions.
126126
if (!supportsLiterals) {
127-
return [];
127+
return const [];
128128
}
129129

130130
try {
131-
var workspace = DartChangeWorkspace(await server.currentSessions);
132-
var context = DartAssistContextImpl(
131+
var context = DartAssistContext(
133132
server.instrumentationService,
134-
workspace,
133+
DartChangeWorkspace(await server.currentSessions),
135134
libraryResult,
136135
unitResult,
137136
offset,
@@ -141,12 +140,11 @@ class DartCodeActionsProducer extends AbstractCodeActionsProducer {
141140
late List<Assist> assists;
142141
if (performance != null) {
143142
var performanceTracker = AssistPerformance();
144-
var processor = AssistProcessor(
143+
assists = await computeAssists(
145144
context,
146145
performance: performanceTracker,
147146
);
148147

149-
assists = await processor.compute();
150148
server.recentPerformance.getAssists.add(
151149
GetAssistsPerformance(
152150
performance: performance,
@@ -158,8 +156,7 @@ class DartCodeActionsProducer extends AbstractCodeActionsProducer {
158156
),
159157
);
160158
} else {
161-
var processor = AssistProcessor(context);
162-
assists = await processor.compute();
159+
assists = await computeAssists(context);
163160
}
164161

165162
return assists.map((assist) {
@@ -175,7 +172,7 @@ class DartCodeActionsProducer extends AbstractCodeActionsProducer {
175172
// If an InconsistentAnalysisException occurs, it's likely the user modified
176173
// the source and therefore is no longer interested in the results, so
177174
// just return an empty set.
178-
return [];
175+
return const [];
179176
}
180177
}
181178

pkg/analysis_server/lib/src/services/correction/assist.dart

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,42 +2,8 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5-
import 'package:analysis_server_plugin/src/correction/assist_dart.dart';
6-
import 'package:analysis_server_plugin/src/correction/change_workspace.dart';
7-
import 'package:analyzer/dart/analysis/results.dart';
8-
import 'package:analyzer/instrumentation/service.dart';
95
import 'package:analyzer_plugin/utilities/assist/assist.dart';
106

11-
/// The implementation of [DartAssistContext].
12-
class DartAssistContextImpl implements DartAssistContext {
13-
@override
14-
final InstrumentationService instrumentationService;
15-
16-
@override
17-
final ChangeWorkspace workspace;
18-
19-
@override
20-
final ResolvedLibraryResult libraryResult;
21-
22-
@override
23-
final ResolvedUnitResult unitResult;
24-
25-
@override
26-
final int selectionOffset;
27-
28-
@override
29-
final int selectionLength;
30-
31-
DartAssistContextImpl(
32-
this.instrumentationService,
33-
this.workspace,
34-
this.libraryResult,
35-
this.unitResult,
36-
this.selectionOffset,
37-
this.selectionLength,
38-
);
39-
}
40-
417
/// An enumeration of possible assist kinds.
428
abstract final class DartAssistKind {
439
static const ADD_DIAGNOSTIC_PROPERTY_REFERENCE = AssistKind(

pkg/analysis_server/test/src/services/correction/assist/assist_processor.dart

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5-
import 'package:analysis_server/src/services/correction/assist.dart';
65
import 'package:analysis_server_plugin/src/correction/assist_core.dart';
6+
import 'package:analysis_server_plugin/src/correction/assist_dart.dart';
77
import 'package:analysis_server_plugin/src/correction/assist_processor.dart';
88
import 'package:analysis_server_plugin/src/correction/change_workspace.dart';
99
import 'package:analysis_server_plugin/src/correction/dart_change_workspace.dart';
@@ -202,16 +202,15 @@ abstract class AssistProcessorTest extends AbstractSingleUnitTest {
202202
if (libraryResult == null) {
203203
return const [];
204204
}
205-
var context = DartAssistContextImpl(
205+
var context = DartAssistContext(
206206
TestInstrumentationService(),
207207
await workspace,
208208
libraryResult,
209209
testAnalysisResult,
210210
_offset,
211211
_length,
212212
);
213-
var processor = AssistProcessor(context);
214-
return await processor.compute();
213+
return await computeAssists(context);
215214
}
216215

217216
List<Position> _findResultPositions(List<String> searchStrings) {

pkg/analysis_server_plugin/lib/registry.dart

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,16 @@ import 'package:analyzer/error/error.dart';
77
import 'package:analyzer/src/lint/linter.dart';
88

99
abstract class PluginRegistry {
10-
/// Register this fix [generator] for the given lint [code] with the
10+
/// Registers this assist [generator] with the analyzer's rule registry.
11+
void registerAssist(ProducerGenerator generator);
12+
13+
/// Registers this fix [generator] for the given lint [code] with the
1114
/// analyzer's rule registry.
1215
void registerFixForRule(LintCode code, ProducerGenerator generator);
1316

14-
/// Register this [rule] with the analyzer's rule registry.
17+
/// Registers this [rule] with the analyzer's rule registry.
1518
void registerLintRule(AnalysisRule rule);
1619

17-
/// Register this [rule] with the analyzer's rule registry.
20+
/// Registers this [rule] with the analyzer's rule registry.
1821
void registerWarningRule(AnalysisRule rule);
1922
}

pkg/analysis_server_plugin/lib/src/correction/assist_dart.dart

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,32 @@ import 'package:analyzer/dart/analysis/results.dart';
77
import 'package:analyzer/instrumentation/service.dart';
88

99
/// An object used to provide context information for Dart assist contributors.
10-
///
11-
/// Clients may not extend, implement or mix-in this class.
12-
abstract class DartAssistContext {
10+
final class DartAssistContext {
1311
/// The instrumentation service used to report errors that prevent a fix from
1412
/// being composed.
15-
InstrumentationService get instrumentationService;
13+
final InstrumentationService instrumentationService;
14+
15+
/// The workspace in which an assist operates.
16+
final ChangeWorkspace workspace;
1617

1718
/// The resolved library result in which an assist operates.
18-
ResolvedLibraryResult get libraryResult;
19+
final ResolvedLibraryResult libraryResult;
1920

20-
/// The length of the selection.
21-
int get selectionLength;
21+
/// The unit result in which an assist operates.
22+
final ResolvedUnitResult unitResult;
2223

2324
/// The starting offset of the selection.
24-
int get selectionOffset;
25+
final int selectionOffset;
2526

26-
/// The unit result in which an assist operates.
27-
ResolvedUnitResult get unitResult;
27+
/// The length of the selection.
28+
final int selectionLength;
2829

29-
/// The workspace in which an assist operates.
30-
ChangeWorkspace get workspace;
30+
DartAssistContext(
31+
this.instrumentationService,
32+
this.workspace,
33+
this.libraryResult,
34+
this.unitResult,
35+
this.selectionOffset,
36+
this.selectionLength,
37+
);
3138
}

pkg/analysis_server_plugin/lib/src/correction/assist_processor.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@ import 'package:analyzer/src/generated/java_core.dart';
1414
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
1515
import 'package:analyzer_plugin/utilities/change_builder/conflicting_edit_exception.dart';
1616

17+
Future<List<Assist>> computeAssists(DartAssistContext context,
18+
{AssistPerformance? performance}) =>
19+
AssistProcessor(
20+
context,
21+
performance: performance,
22+
).compute();
23+
1724
/// The computer for Dart assists.
1825
class AssistProcessor {
1926
final AssistPerformance? _performance;

pkg/analysis_server_plugin/lib/src/plugin_server.dart

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ import 'dart:async';
77
import 'package:analysis_server_plugin/edit/fix/dart_fix_context.dart';
88
import 'package:analysis_server_plugin/edit/fix/fix.dart';
99
import 'package:analysis_server_plugin/plugin.dart';
10+
import 'package:analysis_server_plugin/src/correction/assist_core.dart';
11+
import 'package:analysis_server_plugin/src/correction/assist_dart.dart';
12+
import 'package:analysis_server_plugin/src/correction/assist_processor.dart';
1013
import 'package:analysis_server_plugin/src/correction/dart_change_workspace.dart';
1114
import 'package:analysis_server_plugin/src/correction/fix_processor.dart';
1215
import 'package:analysis_server_plugin/src/registry.dart';
@@ -98,6 +101,60 @@ class PluginServer {
98101
return protocol.AnalysisSetPriorityFilesResult();
99102
}
100103

104+
/// Handles an 'edit.getAssists' request.
105+
///
106+
/// Throws a [RequestFailure] if the request could not be handled.
107+
Future<protocol.EditGetAssistsResult> handleEditGetAssists(
108+
protocol.EditGetAssistsParams parameters) async {
109+
var path = parameters.file;
110+
111+
var recentState = _recentState[path];
112+
if (recentState == null) {
113+
return protocol.EditGetAssistsResult(const []);
114+
}
115+
116+
var (:analysisContext, :errors) = recentState;
117+
var libraryResult =
118+
await analysisContext.currentSession.getResolvedLibrary(path);
119+
if (libraryResult is! ResolvedLibraryResult) {
120+
return protocol.EditGetAssistsResult(const []);
121+
}
122+
var unitResult = libraryResult.unitWithPath(path);
123+
if (unitResult is! ResolvedUnitResult) {
124+
return protocol.EditGetAssistsResult(const []);
125+
}
126+
127+
var context = DartAssistContext(
128+
// TODO(srawlins): Use a real instrumentation service. Other
129+
// implementations get InstrumentationService from AnalysisServer.
130+
InstrumentationService.NULL_SERVICE,
131+
DartChangeWorkspace([analysisContext.currentSession]),
132+
libraryResult,
133+
unitResult,
134+
parameters.offset,
135+
parameters.length,
136+
);
137+
138+
List<Assist> assists;
139+
try {
140+
assists = await computeAssists(context);
141+
} on InconsistentAnalysisException {
142+
// TODO(srawlins): Is it important to at least log this? Or does it
143+
// happen on the regular?
144+
assists = [];
145+
}
146+
147+
if (assists.isEmpty) {
148+
return protocol.EditGetAssistsResult(const []);
149+
}
150+
151+
var corrections = [
152+
for (var assist in assists..sort(Assist.compareAssists))
153+
protocol.PrioritizedSourceChange(assist.kind.priority, assist.change)
154+
];
155+
return protocol.EditGetAssistsResult(corrections);
156+
}
157+
101158
/// Handles an 'edit.getFixes' request.
102159
///
103160
/// Throws a [RequestFailure] if the request could not be handled.

pkg/analysis_server_plugin/lib/src/registry.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// BSD-style license that can be found in the LICENSE file.
44

55
import 'package:analysis_server_plugin/registry.dart';
6+
import 'package:analysis_server_plugin/src/correction/assist_generators.dart';
67
import 'package:analysis_server_plugin/src/correction/fix_generators.dart';
78
import 'package:analysis_server_plugin/src/correction/ignore_diagnostic.dart';
89
import 'package:analyzer/error/error.dart';
@@ -13,6 +14,11 @@ final class PluginRegistryImpl implements PluginRegistry {
1314
/// Returns currently registered lint rules.
1415
Iterable<AnalysisRule> get registeredRules => Registry.ruleRegistry;
1516

17+
@override
18+
void registerAssist(ProducerGenerator generator) {
19+
registeredAssistGenerators.registerGenerator(generator);
20+
}
21+
1622
@override
1723
void registerFixForRule(LintCode code, ProducerGenerator generator) {
1824
registeredFixGenerators.registerFixForLint(code, generator);

0 commit comments

Comments
 (0)