@@ -8,6 +8,7 @@ import 'package:analysis_server/src/services/correction/fix.dart';
8
8
import 'package:analysis_server/src/utilities/extensions/range_factory.dart' ;
9
9
import 'package:analyzer/dart/analysis/features.dart' ;
10
10
import 'package:analyzer/dart/ast/ast.dart' ;
11
+ import 'package:analyzer/dart/ast/token.dart' ;
11
12
import 'package:analyzer/dart/ast/visitor.dart' ;
12
13
import 'package:analyzer/dart/element/element.dart' ;
13
14
import 'package:analyzer/source/source_range.dart' ;
@@ -136,15 +137,49 @@ class ConvertToSuperParameters extends CorrectionProducer {
136
137
await builder.addDartFileEdit (file, (builder) {
137
138
// Convert the parameters.
138
139
for (var parameterData in allParameters) {
140
+ var keyword = parameterData.finalKeyword;
141
+
142
+ void insertSuper () {
143
+ if (keyword == null ) {
144
+ builder.addSimpleInsertion (parameterData.nameOffset, 'super.' );
145
+ } else {
146
+ var tokenAfterKeyword = keyword.next! ;
147
+ if (tokenAfterKeyword.offset == parameterData.nameOffset) {
148
+ builder.addSimpleReplacement (
149
+ range.startStart (keyword, tokenAfterKeyword), 'super.' );
150
+ } else {
151
+ builder.addDeletion (range.startStart (keyword, tokenAfterKeyword));
152
+ builder.addSimpleInsertion (parameterData.nameOffset, 'super.' );
153
+ }
154
+ }
155
+ }
156
+
139
157
var typeToDelete = parameterData.typeToDelete;
140
158
if (typeToDelete == null ) {
141
- builder. addSimpleInsertion (parameterData.nameOffset, 'super.' );
159
+ insertSuper ( );
142
160
} else {
143
161
var primaryRange = typeToDelete.primaryRange;
144
162
if (primaryRange == null ) {
163
+ // This only happens when the type is an inline function type with
164
+ // no return type, such as `f(int i)`. Inline function types can't
165
+ // have a `final` keyword unless there's an error in the code.
145
166
builder.addSimpleInsertion (parameterData.nameOffset, 'super.' );
146
167
} else {
147
- builder.addSimpleReplacement (primaryRange, 'super.' );
168
+ if (keyword == null ) {
169
+ builder.addSimpleReplacement (primaryRange, 'super.' );
170
+ } else {
171
+ var tokenAfterKeyword = keyword.next! ;
172
+ if (tokenAfterKeyword.offset == primaryRange.offset) {
173
+ builder.addSimpleReplacement (
174
+ range.startOffsetEndOffset (
175
+ keyword.offset, primaryRange.end),
176
+ 'super.' );
177
+ } else {
178
+ builder
179
+ .addDeletion (range.startStart (keyword, tokenAfterKeyword));
180
+ builder.addSimpleReplacement (primaryRange, 'super.' );
181
+ }
182
+ }
148
183
}
149
184
var parameterRange = typeToDelete.parameterRange;
150
185
if (parameterRange != null ) {
@@ -200,20 +235,24 @@ class ConvertToSuperParameters extends CorrectionProducer {
200
235
if (! typeSystem.isSubtypeOf (thisType, superType)) {
201
236
return null ;
202
237
}
203
- var identifier = parameter.parameter.identifier;
238
+
239
+ var parameterNode = parameter.parameter;
240
+ var identifier = parameterNode.identifier;
204
241
if (identifier == null ) {
205
242
// This condition should never occur, but the test is here to promote the
206
243
// type.
207
244
return null ;
208
245
}
246
+
209
247
// Return the data.
210
248
return _ParameterData (
211
249
argumentIndex: argumentIndex,
212
- defaultValueRange: _defaultValueRange (
213
- parameter.parameter, superParameter, parameter.element),
250
+ defaultValueRange:
251
+ _defaultValueRange (parameterNode, superParameter, parameter.element),
252
+ finalKeyword: _finalKeyword (parameterNode),
214
253
nameOffset: identifier.offset,
215
254
parameterIndex: parameter.index,
216
- typeToDelete: superType == thisType ? _type (parameter.parameter ) : null ,
255
+ typeToDelete: superType == thisType ? _type (parameterNode ) : null ,
217
256
);
218
257
}
219
258
@@ -235,6 +274,21 @@ class ConvertToSuperParameters extends CorrectionProducer {
235
274
return null ;
236
275
}
237
276
277
+ /// Return data about the type annotation on the [parameter] . This is the
278
+ /// information about the ranges of text that need to be removed in order to
279
+ /// remove the type annotation.
280
+ Token ? _finalKeyword (FormalParameter parameter) {
281
+ if (parameter is DefaultFormalParameter ) {
282
+ return _finalKeyword (parameter.parameter);
283
+ } else if (parameter is SimpleFormalParameter ) {
284
+ var keyword = parameter.keyword;
285
+ if (keyword? .type == Keyword .FINAL ) {
286
+ return keyword;
287
+ }
288
+ }
289
+ return null ;
290
+ }
291
+
238
292
/// Return the constructor to be converted, or `null` if the cursor is not on
239
293
/// the name of a constructor.
240
294
ConstructorDeclaration ? _findConstructor () {
@@ -376,6 +430,10 @@ class _Parameter {
376
430
377
431
/// Information used to convert a single parameter.
378
432
class _ParameterData {
433
+ /// The `final` keyword on the parameter, or `null` if there is no `final`
434
+ /// keyword.
435
+ final Token ? finalKeyword;
436
+
379
437
/// The type annotation that should be deleted from the parameter list, or
380
438
/// `null` if there is no type annotation to delete or if the type should not
381
439
/// be deleted.
@@ -397,7 +455,8 @@ class _ParameterData {
397
455
398
456
/// Initialize a newly create data object.
399
457
_ParameterData (
400
- {required this .typeToDelete,
458
+ {required this .finalKeyword,
459
+ required this .typeToDelete,
401
460
required this .nameOffset,
402
461
required this .defaultValueRange,
403
462
required this .parameterIndex,
0 commit comments