Skip to content

Commit 5825a34

Browse files
FMorschelCommit Queue
authored andcommitted
[DAS] Fixes regression in completion for unnamed parameters in closures
Fixes: #61518 Change-Id: Ia190a35188d2e9cf67fd7a6e75580cbcf2f9c6a2 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/450180 Commit-Queue: Brian Wilkerson <[email protected]> Reviewed-by: Brian Wilkerson <[email protected]> Auto-Submit: Felipe Morschel <[email protected]> Reviewed-by: Samuel Rawlins <[email protected]>
1 parent b021d84 commit 5825a34

File tree

11 files changed

+190
-29
lines changed

11 files changed

+190
-29
lines changed

pkg/analysis_server/lib/src/services/completion/dart/in_scope_completion_pass.dart

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import 'package:analyzer/dart/ast/syntactic_entity.dart';
2222
import 'package:analyzer/dart/ast/token.dart';
2323
import 'package:analyzer/dart/ast/visitor.dart';
2424
import 'package:analyzer/dart/element/element.dart';
25+
import 'package:analyzer/dart/element/nullability_suffix.dart';
2526
import 'package:analyzer/dart/element/type.dart';
2627
import 'package:analyzer/source/source_range.dart';
2728
import 'package:analyzer/src/dart/ast/ast.dart';
@@ -320,12 +321,26 @@ class InScopeCompletionPass extends SimpleAstVisitor<void> {
320321
// Only suggest expression keywords if it's possible that the user is
321322
// completing a positional argument.
322323
if (positionalArgumentCount < positionalParameterCount) {
323-
_forExpression(parent, mustBeNonVoid: true);
324324
// This assumes that the positional parameters will always be first in
325325
// the list of parameters.
326326
var parameter = parameters[positionalArgumentCount];
327327
var parameterType = parameter.type;
328-
if (parameterType is FunctionType) {
328+
var isFunctionType = parameterType is FunctionType;
329+
_forExpression(
330+
parent,
331+
mustBeNonVoid: true,
332+
canBeNull:
333+
parameterType.nullabilitySuffix != NullabilitySuffix.none ||
334+
parameterType is DynamicType,
335+
// TODO(FMorschel): Determine if the expected type is bool and only
336+
// suggest `true` and `false` in that case.
337+
canBeBool: !isFunctionType,
338+
// TODO(FMorschel): Determine if the parameter type has a constant
339+
// constructor.
340+
// Function tear-offs and closures cannot be constant.
341+
canSuggestConst: !isFunctionType,
342+
);
343+
if (isFunctionType) {
329344
Expression? argument;
330345
if (argumentIndex < arguments.length) {
331346
argument = arguments[argumentIndex];
@@ -3552,6 +3567,9 @@ class InScopeCompletionPass extends SimpleAstVisitor<void> {
35523567
AstNode node, {
35533568
bool mustBeAssignable = false,
35543569
bool mustBeNonVoid = false,
3570+
bool canBeBool = true,
3571+
bool canBeNull = true,
3572+
bool canSuggestConst = true,
35553573
}) {
35563574
var mustBeConstant =
35573575
node is Expression &&
@@ -3561,6 +3579,9 @@ class InScopeCompletionPass extends SimpleAstVisitor<void> {
35613579
node,
35623580
mustBeConstant: mustBeConstant,
35633581
mustBeStatic: mustBeStatic,
3582+
canBeBool: canBeBool,
3583+
canBeNull: canBeNull,
3584+
canSuggestConst: canSuggestConst,
35643585
);
35653586
declarationHelper(
35663587
mustBeAssignable: mustBeAssignable,

pkg/analysis_server/lib/src/services/completion/dart/keyword_helper.dart

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,9 @@ class KeywordHelper {
263263
/// keywords to include.
264264
void addExpressionKeywords(
265265
AstNode? node, {
266+
bool canBeBool = true,
267+
bool canBeNull = true,
268+
bool canSuggestConst = true,
266269
bool mustBeConstant = false,
267270
bool mustBeStatic = false,
268271
}) {
@@ -311,11 +314,17 @@ class KeywordHelper {
311314
return true;
312315
}
313316

314-
addKeyword(Keyword.FALSE);
315-
addKeyword(Keyword.NULL);
316-
addKeyword(Keyword.TRUE);
317+
if (canBeBool) {
318+
addKeyword(Keyword.FALSE);
319+
}
320+
if (canBeNull) {
321+
addKeyword(Keyword.NULL);
322+
}
323+
if (canBeBool) {
324+
addKeyword(Keyword.TRUE);
325+
}
317326
if (node != null) {
318-
if (constIsValid(node)) {
327+
if (canSuggestConst && constIsValid(node)) {
319328
addKeyword(Keyword.CONST);
320329
}
321330
if (!mustBeConstant && !mustBeStatic) {

pkg/analysis_server/lib/src/services/completion/dart/utilities.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ String buildClosureParameters(
4242
var hasNamed = false;
4343
var hasOptionalPositional = false;
4444
var parameters = type.formalParameters;
45-
var existingNames = parameters.map((p) => p.displayName).toSet();
45+
var existingNames = parameters.map((p) => p.name).nonNulls.toSet();
4646
for (var i = 0; i < parameters.length; ++i) {
4747
var parameter = parameters[i];
4848
if (i != 0) {
@@ -59,7 +59,7 @@ String buildClosureParameters(
5959
buffer.write(parameter.type);
6060
buffer.write(' ');
6161
}
62-
var name = parameter.displayName;
62+
var name = parameter.name ?? '';
6363
if (name.isEmpty) {
6464
name = 'p$i';
6565
var index = 1;

pkg/analysis_server/test/client/completion_driver_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ abstract class AbstractCompletionDriverTest
6868

6969
/// Return `true` if closures (suggestions starting with a left paren) should
7070
/// be included in the text to be compared.
71-
bool get includeClosures => false;
71+
bool includeClosures = false;
7272

7373
/// Return `true` if overrides should be included in the text to be compared.
7474
bool get includeOverrides => true;

pkg/analysis_server/test/lsp/completion.dart

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@ mixin CompletionTestMixin on AbstractLspAnalysisServerTest {
1515
List<CompletionItem> completionResults = [];
1616

1717
int sortTextSorter(CompletionItem item1, CompletionItem item2) =>
18-
(item1.sortText ?? item1.label).compareTo(item2.sortText ?? item2.label);
18+
(item1.sortText == item2.sortText)
19+
? item1.label.compareTo(item2.label)
20+
: (item1.sortText ?? item1.label).compareTo(
21+
item2.sortText ?? item2.label,
22+
);
1923

2024
Future<String?> verifyCompletions(
2125
Uri fileUri,

pkg/analysis_server/test/lsp/completion_dart_test.dart

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1545,6 +1545,28 @@ void g() {
15451545
);
15461546
}
15471547

1548+
Future<void> test_closure_unnamedParameters() async {
1549+
var content = '''
1550+
void f(void Function(int) x) {
1551+
f(^);
1552+
}
1553+
''';
1554+
1555+
var expectedContent = '''
1556+
void f(void Function(int) x) {
1557+
f((p0) => ^,);
1558+
}
1559+
''';
1560+
1561+
await verifyCompletions(
1562+
mainFileUri,
1563+
content,
1564+
expectCompletions: ['(p0) =>', '(p0) {}'],
1565+
applyEditsFor: '(p0) =>',
1566+
expectedContent: expectedContent,
1567+
);
1568+
}
1569+
15481570
Future<void> test_color_material() async {
15491571
content = '''
15501572
import 'package:flutter/material.dart';

pkg/analysis_server/test/lsp/completion_yaml_test.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -530,7 +530,7 @@ dependencies:
530530
await verifyCompletions(
531531
pubspecFileUri,
532532
content,
533-
expectCompletions: ['^2.3.4', '^2.1.0'],
533+
expectCompletions: ['^2.1.0', '^2.3.4'],
534534
applyEditsFor: '^2.3.4',
535535
expectedContent: expected,
536536
openCloseFile: false,
@@ -630,7 +630,7 @@ name: ''';
630630
await verifyCompletions(
631631
pubspecFileUri,
632632
content,
633-
expectCompletions: ['name: ', 'description: '],
633+
expectCompletions: ['description: ', 'name: '],
634634
applyEditsFor: 'name: ',
635635
expectedContent: expected,
636636
);

pkg/analysis_server/test/services/completion/dart/completion_test.dart

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4089,8 +4089,6 @@ replacement
40894089
suggestions
40904090
n
40914091
kind: localVariable
4092-
null
4093-
kind: keyword
40944092
const
40954093
kind: keyword
40964094
''');
@@ -4985,8 +4983,6 @@ suggestions
49854983
kind: keyword
49864984
false
49874985
kind: keyword
4988-
null
4989-
kind: keyword
49904986
this
49914987
kind: keyword
49924988
const
@@ -5890,18 +5886,39 @@ void r() {
58905886
x(^);
58915887
}
58925888
''');
5889+
// Could be:
5890+
//
5891+
// ```dart
5892+
// switch (i) {
5893+
// < 0 => (k) {},
5894+
// _ => v,
5895+
// }
5896+
// ```
58935897
assertResponse(r'''
58945898
suggestions
58955899
v
58965900
kind: localVariable
5897-
true
5898-
kind: keyword
5899-
false
5901+
switch
59005902
kind: keyword
5903+
''');
5904+
}
5905+
5906+
Future<void> test_commentSnippets058_1_nullable() async {
5907+
allowedIdentifiers = {'v'};
5908+
await computeSuggestions('''
5909+
typedef void callback(int k);
5910+
void x(callback? q){}
5911+
void r() {
5912+
callback v;
5913+
x(^);
5914+
}
5915+
''');
5916+
assertResponse(r'''
5917+
suggestions
5918+
v
5919+
kind: localVariable
59015920
null
59025921
kind: keyword
5903-
const
5904-
kind: keyword
59055922
switch
59065923
kind: keyword
59075924
''');
@@ -7946,8 +7963,6 @@ suggestions
79467963
kind: constructorInvocation
79477964
A.second
79487965
kind: constructorInvocation
7949-
null
7950-
kind: keyword
79517966
false
79527967
kind: keyword
79537968
true

pkg/analysis_server/test/services/completion/dart/declaration/closure_test.dart

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,25 @@ suggestions
139139
''');
140140
}
141141

142+
Future<void> test_parameter_unnamed() async {
143+
await computeSuggestions('''
144+
void f(void Function(int) x) {
145+
f(^);
146+
}
147+
''');
148+
assertResponse('''
149+
suggestions
150+
(p0) => ^,
151+
kind: invocation
152+
displayText: (p0) =>
153+
(p0) {
154+
^
155+
},
156+
kind: invocation
157+
displayText: (p0) {}
158+
''');
159+
}
160+
142161
Future<void> test_parameters_optionalNamed() async {
143162
await computeSuggestions('''
144163
void f({void Function(int a, {int b, int c}) closure}) {}

pkg/analysis_server/test/services/completion/dart/location/argument_list_test.dart

Lines changed: 77 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,6 @@ suggestions
7171
kind: keyword
7272
false
7373
kind: keyword
74-
null
75-
kind: keyword
7674
const
7775
kind: keyword
7876
switch
@@ -98,8 +96,6 @@ replacement
9896
suggestions
9997
random
10098
kind: localVariable
101-
null
102-
kind: keyword
10399
false
104100
kind: keyword
105101
true
@@ -235,6 +231,83 @@ suggestions
235231
kind: keyword
236232
null
237233
kind: keyword
234+
''');
235+
}
236+
237+
Future<void> test_closure_namedParameters() async {
238+
includeClosures = true;
239+
await computeSuggestions('''
240+
void f(void Function(int i) x) {
241+
f(^);
242+
}
243+
''');
244+
assertResponse('''
245+
suggestions
246+
(i) => ^,
247+
kind: invocation
248+
(i) {
249+
^
250+
},
251+
kind: invocation
252+
switch
253+
kind: keyword
254+
''');
255+
}
256+
257+
Future<void> test_closure_unnamedParameters() async {
258+
includeClosures = true;
259+
await computeSuggestions('''
260+
void f(void Function(int) x) {
261+
f(^);
262+
}
263+
''');
264+
assertResponse('''
265+
suggestions
266+
(p0) => ^,
267+
kind: invocation
268+
(p0) {
269+
^
270+
},
271+
kind: invocation
272+
switch
273+
kind: keyword
274+
''');
275+
}
276+
277+
Future<void> test_closure_unnamedParameters_equal() async {
278+
includeClosures = true;
279+
await computeSuggestions('''
280+
void f(void Function(int p2, int p2_1, int) x) {
281+
f(^);
282+
}
283+
''');
284+
// We expect it to try and use `p2` but since it is already in use, it
285+
// should try `p2_1`, and then `p2_2`.
286+
assertResponse('''
287+
suggestions
288+
(p2, p2_1, p2_2) => ^,
289+
kind: invocation
290+
(p2, p2_1, p2_2) {
291+
^
292+
},
293+
kind: invocation
294+
switch
295+
kind: keyword
296+
''');
297+
}
298+
299+
Future<void> test_nullableClosure() async {
300+
await computeSuggestions('''
301+
void f(void Function(int i)? x) {
302+
f(^);
303+
}
304+
''');
305+
assertResponse('''
306+
suggestions
307+
null
308+
kind: keyword
309+
switch
310+
kind: keyword
238311
''');
239312
}
240313
}

0 commit comments

Comments
 (0)