Skip to content

Commit 6a1f9ed

Browse files
DanTupCommit Queue
authored andcommitted
[analysis_server] Insert new arguments before last child/children arguments
Usually when adding arguments, we'd always put them at the end. However there is convention (and a lint) for putting child/children last - so if the arguments in the last position are child/children, we should insert before them. Change-Id: Ia0e0cd6b10f16cef30aa0cfe4fdedecc223f08c4 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/403584 Reviewed-by: Elliott Brooks <[email protected]> Commit-Queue: Brian Wilkerson <[email protected]> Reviewed-by: Brian Wilkerson <[email protected]>
1 parent e9a6d62 commit 6a1f9ed

File tree

2 files changed

+83
-8
lines changed

2 files changed

+83
-8
lines changed

pkg/analysis_server/lib/src/lsp/handlers/custom/editable_arguments/handler_edit_argument.dart

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,22 @@ class EditArgumentHandler extends SharedMessageHandler<EditArgumentParams, Null>
267267
);
268268
}
269269

270+
/// Returns whether [argument] is a [NamedExpression] with a name of
271+
/// 'child' or 'children'.
272+
bool _isNamedChildOrChildren(Expression argument) {
273+
if (argument is! NamedExpression) {
274+
return false;
275+
}
276+
277+
return argument.name.label.name == 'child' ||
278+
argument.name.label.name == 'children';
279+
}
280+
281+
/// Returns whether [argument] is _not_ a [NamedExpression] with a name of
282+
/// 'child' or 'children'.
283+
bool _isNotNamedChildOrChildren(Expression argument) =>
284+
!_isNamedChildOrChildren(argument);
285+
270286
/// Sends [workspaceEdit] to the client and returns `null` if applied
271287
/// successfully or an error otherwise.
272288
Future<ErrorOr<Null>> _sendEditToClient(WorkspaceEdit workspaceEdit) async {
@@ -367,22 +383,27 @@ class EditArgumentHandler extends SharedMessageHandler<EditArgumentParams, Null>
367383
parameter.isNamed && parameterName != null ? '$parameterName: ' : '';
368384
var argumentCodeToInsert = '$prefix$newValueCode';
369385

386+
// Usually we insert at the end (after the last argument), but if the last
387+
// argument is child/children we should go before it.
388+
var argumentToInsertAfter = argumentList.arguments.lastWhereOrNull(
389+
_isNotNamedChildOrChildren,
390+
);
391+
370392
// Build the final code to insert.
371393
var newCode = StringBuffer();
372-
var hasTrailingComma =
373-
argumentList.arguments.lastOrNull?.endToken.next?.lexeme == ',';
374-
if (!hasTrailingComma && argumentList.arguments.isNotEmpty) {
394+
if (argumentToInsertAfter != null) {
395+
// If we're being inserted after an argument, put a new comma between us.
375396
newCode.write(', ');
376-
} else if (hasTrailingComma) {
377-
newCode.write(' ');
378397
}
379398
newCode.write(argumentCodeToInsert);
380-
if (hasTrailingComma) {
381-
newCode.write(',');
399+
if (argumentToInsertAfter == null && argumentList.arguments.isNotEmpty) {
400+
// If we're not inserted after an existing argument but there are future
401+
// arguments, add a comma in between us.
402+
newCode.write(', ');
382403
}
383404

384405
builder.addSimpleInsertion(
385-
argumentList.rightParenthesis.offset,
406+
argumentToInsertAfter?.end ?? argumentList.leftParenthesis.end,
386407
newCode.toString(),
387408
);
388409
}

pkg/analysis_server/test/lsp/edit_argument_test.dart

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,33 @@ class EditArgumentTest extends AbstractLspAnalysisServerTest {
273273
);
274274
}
275275

276+
test_named_addAfterNamed_afterChildNotAtEnd() async {
277+
await _expectSimpleArgumentEdit(
278+
params: '({ int? x, int? y, Widget? child })',
279+
originalArgs: '(child: null, x: 1)',
280+
edit: ArgumentEdit(name: 'y', newValue: 2),
281+
expectedArgs: '(child: null, x: 1, y: 2)',
282+
);
283+
}
284+
285+
test_named_addAfterNamed_beforeChildAtEnd() async {
286+
await _expectSimpleArgumentEdit(
287+
params: '({ int? x, int? y, Widget? child })',
288+
originalArgs: '(x: 1, child: null)',
289+
edit: ArgumentEdit(name: 'y', newValue: 2),
290+
expectedArgs: '(x: 1, y: 2, child: null)',
291+
);
292+
}
293+
294+
test_named_addAfterNamed_beforeChildrenAtEnd() async {
295+
await _expectSimpleArgumentEdit(
296+
params: '({ int? x, int? y, List<Widget>? children })',
297+
originalArgs: '(x: 1, children: [])',
298+
edit: ArgumentEdit(name: 'y', newValue: 2),
299+
expectedArgs: '(x: 1, y: 2, children: [])',
300+
);
301+
}
302+
276303
test_named_addAfterPositional() async {
277304
await _expectSimpleArgumentEdit(
278305
params: '(int? x, { int? y })',
@@ -282,6 +309,33 @@ class EditArgumentTest extends AbstractLspAnalysisServerTest {
282309
);
283310
}
284311

312+
test_named_addAfterPositional_afterChildNotAtEnd() async {
313+
await _expectSimpleArgumentEdit(
314+
params: '(int? x, { int? y, Widget? child })',
315+
originalArgs: '(child: null, 1)',
316+
edit: ArgumentEdit(name: 'y', newValue: 2),
317+
expectedArgs: '(child: null, 1, y: 2)',
318+
);
319+
}
320+
321+
test_named_addAfterPositional_beforeChildAtEnd() async {
322+
await _expectSimpleArgumentEdit(
323+
params: '(int? x, { int? y, Widget? child })',
324+
originalArgs: '(1, child: null)',
325+
edit: ArgumentEdit(name: 'y', newValue: 2),
326+
expectedArgs: '(1, y: 2, child: null)',
327+
);
328+
}
329+
330+
test_named_addAfterPositional_beforeChildrenAtEnd() async {
331+
await _expectSimpleArgumentEdit(
332+
params: '(int? x, { int? y, List<Widget>? children })',
333+
originalArgs: '(1, children: [])',
334+
edit: ArgumentEdit(name: 'y', newValue: 2),
335+
expectedArgs: '(1, y: 2, children: [])',
336+
);
337+
}
338+
285339
test_optionalPositional_addAfterPositional() async {
286340
await _expectSimpleArgumentEdit(
287341
params: '([int? x, int? y])',

0 commit comments

Comments
 (0)