@@ -25,6 +25,7 @@ import 'package:analyzer/dart/analysis/results.dart';
2525import 'package:analyzer/dart/analysis/session.dart'
2626 show InconsistentAnalysisException;
2727import 'package:analyzer/src/generated/engine.dart' show AnalysisEngine;
28+ import 'package:collection/collection.dart' show groupBy;
2829
2930class CodeActionHandler extends MessageHandler <CodeActionParams ,
3031 List <Either2 <Command , CodeAction >>> {
@@ -96,29 +97,52 @@ class CodeActionHandler extends MessageHandler<CodeActionParams,
9697 /// version of each document being modified so it's important to call this
9798 /// immediately after computing edits to ensure the document is not modified
9899 /// before the version number is read.
99- Either2 < Command , CodeAction > _createAssistAction (Assist assist) {
100- return Either2 < Command , CodeAction >. t2 ( CodeAction (
100+ CodeAction _createAssistAction (Assist assist) {
101+ return CodeAction (
101102 assist.change.message,
102103 toCodeActionKind (assist.change.id, CodeActionKind .Refactor ),
103104 const [],
104105 createWorkspaceEdit (server, assist.change.edits),
105106 null ,
106- )) ;
107+ );
107108 }
108109
109110 /// Creates a CodeAction to apply this fix. Note: This code will fetch the
110111 /// version of each document being modified so it's important to call this
111112 /// immediately after computing edits to ensure the document is not modified
112113 /// before the version number is read.
113- Either2 <Command , CodeAction > _createFixAction (
114- Fix fix, Diagnostic diagnostic) {
115- return Either2 <Command , CodeAction >.t2 (CodeAction (
114+ CodeAction _createFixAction (Fix fix, Diagnostic diagnostic) {
115+ return CodeAction (
116116 fix.change.message,
117117 toCodeActionKind (fix.change.id, CodeActionKind .QuickFix ),
118118 [diagnostic],
119119 createWorkspaceEdit (server, fix.change.edits),
120120 null ,
121- ));
121+ );
122+ }
123+
124+ /// Dedupes actions that perform the same edit and merge their diagnostics
125+ /// together. This avoids duplicates where there are multiple errors on
126+ /// the same line that have the same fix (for example importing a
127+ /// library that fixes multiple unresolved types).
128+ List <CodeAction > _dedupeActions (Iterable <CodeAction > actions) {
129+ final groups = groupBy (actions, (CodeAction action) => action.edit);
130+ return groups.keys.map ((edit) {
131+ final first = groups[edit].first;
132+ // Avoid constructing new CodeActions if there was only one in this group.
133+ if (groups[edit].length == 1 ) {
134+ return first;
135+ }
136+ // Build a new CodeAction that merges the diagnostics from each same
137+ // code action onto a single one.
138+ return CodeAction (
139+ first.title,
140+ first.kind,
141+ // Merge diagnostics from all of the CodeActions.
142+ groups[edit].expand ((r) => r.diagnostics).toList (),
143+ first.edit,
144+ first.command);
145+ }).toList ();
122146 }
123147
124148 Future <List <Either2 <Command , CodeAction >>> _getAssistActions (
@@ -145,7 +169,11 @@ class CodeActionHandler extends MessageHandler<CodeActionParams,
145169 final assists = await processor.compute ();
146170 assists.sort (Assist .SORT_BY_RELEVANCE );
147171
148- return assists.map (_createAssistAction).toList ();
172+ final assistActions = _dedupeActions (assists.map (_createAssistAction));
173+
174+ return assistActions
175+ .map ((action) => Either2 <Command , CodeAction >.t2 (action))
176+ .toList ();
149177 } on InconsistentAnalysisException {
150178 // If an InconsistentAnalysisException occurs, it's likely the user modified
151179 // the source and therefore is no longer interested in the results, so
@@ -172,6 +200,7 @@ class CodeActionHandler extends MessageHandler<CodeActionParams,
172200 _getFixActions (kinds, supportsLiterals, range, unit),
173201 ]);
174202 final flatResults = results.expand ((x) => x).toList ();
203+
175204 return success (flatResults);
176205 }
177206
@@ -188,7 +217,7 @@ class CodeActionHandler extends MessageHandler<CodeActionParams,
188217 }
189218
190219 final lineInfo = unit.lineInfo;
191- final codeActions = < Either2 < Command , CodeAction > > [];
220+ final codeActions = < CodeAction > [];
192221 final fixContributor = DartFixContributor ();
193222
194223 try {
@@ -216,7 +245,12 @@ class CodeActionHandler extends MessageHandler<CodeActionParams,
216245 }
217246 }
218247 }
219- return codeActions;
248+
249+ final dedupedActions = _dedupeActions (codeActions);
250+
251+ return dedupedActions
252+ .map ((action) => Either2 <Command , CodeAction >.t2 (action))
253+ .toList ();
220254 } on InconsistentAnalysisException {
221255 // If an InconsistentAnalysisException occurs, it's likely the user modified
222256 // the source and therefore is no longer interested in the results, so
0 commit comments