@@ -7,11 +7,18 @@ import 'dart:collection';
7
7
8
8
import 'package:analysis_server/lsp_protocol/protocol_generated.dart' ;
9
9
import 'package:analysis_server/lsp_protocol/protocol_special.dart' ;
10
+ import 'package:analysis_server/plugin/edit/fix/fix_core.dart' ;
10
11
import 'package:analysis_server/src/lsp/constants.dart' ;
11
12
import 'package:analysis_server/src/lsp/handlers/handlers.dart' ;
12
13
import 'package:analysis_server/src/lsp/lsp_analysis_server.dart' ;
13
14
import 'package:analysis_server/src/lsp/mapping.dart' ;
15
+ import 'package:analysis_server/src/lsp/source_edits.dart' ;
16
+ import 'package:analysis_server/src/protocol_server.dart' show SourceChange;
17
+ import 'package:analysis_server/src/services/correction/fix.dart' ;
18
+ import 'package:analysis_server/src/services/correction/fix_internal.dart' ;
14
19
import 'package:analyzer/dart/analysis/results.dart' ;
20
+ import 'package:analyzer/dart/analysis/session.dart'
21
+ show InconsistentAnalysisException;
15
22
import 'package:analyzer/src/generated/engine.dart' show AnalysisEngine;
16
23
17
24
typedef ActionHandler = Future <List <Either2 <Command , CodeAction >>> Function (
@@ -22,20 +29,6 @@ class CodeActionHandler extends MessageHandler<CodeActionParams,
22
29
CodeActionHandler (LspAnalysisServer server) : super (server);
23
30
Method get handlesMessage => Method .textDocument_codeAction;
24
31
25
- /// Wraps a command in a CodeAction if the client supports it so that a
26
- /// CodeActionKind can be supplied.
27
- Either2 <Command , CodeAction > commandOrCodeAction (
28
- bool clientSupportsLiteralCodeActions,
29
- CodeActionKind kind,
30
- Command command,
31
- ) {
32
- return clientSupportsLiteralCodeActions
33
- ? Either2 <Command , CodeAction >.t2 (
34
- new CodeAction (command.title, kind, null , null , command),
35
- )
36
- : Either2 <Command , CodeAction >.t1 (command);
37
- }
38
-
39
32
@override
40
33
CodeActionParams convertParams (Map <String , dynamic > json) =>
41
34
CodeActionParams .fromJson (json);
@@ -60,6 +53,42 @@ class CodeActionHandler extends MessageHandler<CodeActionParams,
60
53
unit));
61
54
}
62
55
56
+ /// Wraps a command in a CodeAction if the client supports it so that a
57
+ /// CodeActionKind can be supplied.
58
+ Either2 <Command , CodeAction > _commandOrCodeAction (
59
+ bool clientSupportsLiteralCodeActions,
60
+ CodeActionKind kind,
61
+ Command command,
62
+ ) {
63
+ return clientSupportsLiteralCodeActions
64
+ ? Either2 <Command , CodeAction >.t2 (
65
+ new CodeAction (command.title, kind, null , null , command),
66
+ )
67
+ : Either2 <Command , CodeAction >.t1 (command);
68
+ }
69
+
70
+ Either2 <Command , CodeAction > _createFixAction (
71
+ Fix fix, Diagnostic diagnostic) {
72
+ return new Either2 <Command , CodeAction >.t2 (new CodeAction (
73
+ fix.change.message,
74
+ CodeActionKind .QuickFix ,
75
+ [diagnostic],
76
+ _createWorkspaceEdit (fix.change),
77
+ null ,
78
+ ));
79
+ }
80
+
81
+ WorkspaceEdit _createWorkspaceEdit (SourceChange change) {
82
+ return toWorkspaceEdit (
83
+ server.clientCapabilities? .workspace,
84
+ change.edits
85
+ .map ((e) => new FileEditInformation (
86
+ server.getVersionedDocumentIdentifier (e.file),
87
+ server.getLineInfo (e.file),
88
+ e.edits))
89
+ .toList ());
90
+ }
91
+
63
92
Future <List <Either2 <Command , CodeAction >>> _getAssistActions (
64
93
HashSet <CodeActionKind > clientSupportedCodeActionKinds,
65
94
bool clientSupportsLiteralCodeActions,
@@ -104,8 +133,40 @@ class CodeActionHandler extends MessageHandler<CodeActionParams,
104
133
Range range,
105
134
ResolvedUnitResult unit,
106
135
) async {
107
- // TODO(dantup): Implement fixes.
108
- return [];
136
+ // TODO(dantup): Is it acceptable not to support these for clients that can't
137
+ // handle Code Action literals? (Doing so requires we encode this into a
138
+ // command/arguments set and allow the client to call us back later).
139
+ if (! clientSupportsLiteralCodeActions) {
140
+ return const [];
141
+ }
142
+ // Keep trying until we run without getting an `InconsistentAnalysisException`.
143
+ while (true ) {
144
+ final lineInfo = unit.lineInfo;
145
+ final codeActions = < Either2 <Command , CodeAction >> [];
146
+ final fixContributor = new DartFixContributor ();
147
+ try {
148
+ for (final error in unit.errors) {
149
+ // Server lineNumber is one-based so subtract one.
150
+ int errorLine = lineInfo.getLocation (error.offset).lineNumber - 1 ;
151
+ if (errorLine >= range.start.line && errorLine <= range.end.line) {
152
+ var context = new DartFixContextImpl (unit, error);
153
+ final fixes = await fixContributor.computeFixes (context);
154
+ if (fixes.isNotEmpty) {
155
+ fixes.sort (Fix .SORT_BY_RELEVANCE );
156
+
157
+ final diagnostic = toDiagnostic (lineInfo, error);
158
+ codeActions.addAll (
159
+ fixes.map ((fix) => _createFixAction (fix, diagnostic)),
160
+ );
161
+ }
162
+ }
163
+ }
164
+
165
+ return codeActions;
166
+ } on InconsistentAnalysisException {
167
+ // Loop around to try again to compute the fixes.
168
+ }
169
+ }
109
170
}
110
171
111
172
Future <List <Either2 <Command , CodeAction >>> _getRefactorActions (
@@ -141,12 +202,12 @@ class CodeActionHandler extends MessageHandler<CodeActionParams,
141
202
}
142
203
143
204
return [
144
- commandOrCodeAction (
205
+ _commandOrCodeAction (
145
206
clientSupportsLiteralCodeActions,
146
207
DartCodeActionKind .SortMembers ,
147
208
new Command ('Sort Members' , Commands .sortMembers, [path]),
148
209
),
149
- commandOrCodeAction (
210
+ _commandOrCodeAction (
150
211
clientSupportsLiteralCodeActions,
151
212
CodeActionKind .SourceOrganizeImports ,
152
213
new Command ('Organize Imports' , Commands .organizeImports, [path]),
0 commit comments