Skip to content

Commit 8fda644

Browse files
pqcommit-bot@chromium.org
authored andcommitted
lambda generation for positional args
Fixes: #40202 (See issue for animation of UX.) Change-Id: I029a7768b887fedef4873f3fa23171d21df8808f Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/132380 Commit-Queue: Phil Quitslund <[email protected]> Reviewed-by: Brian Wilkerson <[email protected]>
1 parent 53134fc commit 8fda644

File tree

3 files changed

+152
-37
lines changed

3 files changed

+152
-37
lines changed

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

Lines changed: 1 addition & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ class ArgListContributor extends DartCompletionContributor {
148148
) {
149149
if (type is FunctionType) {
150150
var indent = getRequestLineIndent(request);
151-
var parametersString = _buildClosureParameters(type);
151+
var parametersString = buildClosureParameters(type);
152152

153153
var blockBuffer = StringBuffer(parametersString);
154154
blockBuffer.writeln(' {');
@@ -340,38 +340,6 @@ class ArgListContributor extends DartCompletionContributor {
340340
return newExpr != null && flutter.isWidgetCreation(newExpr);
341341
}
342342

343-
static String _buildClosureParameters(FunctionType type) {
344-
var buffer = StringBuffer();
345-
buffer.write('(');
346-
347-
var hasNamed = false;
348-
var hasOptionalPositional = false;
349-
var parameters = type.parameters;
350-
for (var i = 0; i < parameters.length; ++i) {
351-
var parameter = parameters[i];
352-
if (i != 0) {
353-
buffer.write(', ');
354-
}
355-
if (parameter.isNamed && !hasNamed) {
356-
hasNamed = true;
357-
buffer.write('{');
358-
} else if (parameter.isOptionalPositional && !hasOptionalPositional) {
359-
hasOptionalPositional = true;
360-
buffer.write('[');
361-
}
362-
buffer.write(parameter.name);
363-
}
364-
365-
if (hasNamed) {
366-
buffer.write('}');
367-
} else if (hasOptionalPositional) {
368-
buffer.write(']');
369-
}
370-
371-
buffer.write(')');
372-
return buffer.toString();
373-
}
374-
375343
/**
376344
* If the given [comment] is not `null`, fill the [suggestion] documentation
377345
* fields.

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

Lines changed: 71 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,43 @@ void addDefaultArgDetails(
6060
sb.write(', ');
6161
}
6262
offset = sb.length;
63-
String name = param.name;
64-
sb.write(name);
65-
ranges.addAll([offset, name.length]);
63+
64+
if (param.type is FunctionType) {
65+
FunctionType type = param.type;
66+
67+
var rangeStart = offset;
68+
var rangeLength;
69+
70+
// todo (pq): consider adding ranges for params
71+
// pending: https://github.com/dart-lang/sdk/issues/40207
72+
// (types in closure param completions make this UX awkward)
73+
final parametersString = buildClosureParameters(type);
74+
final blockBuffer = StringBuffer(parametersString);
75+
76+
blockBuffer.write(' ');
77+
78+
// todo (pq): consider refactoring to share common logic w/ ArgListContributor.buildClosureSuggestions
79+
final returnType = type.returnType;
80+
if (returnType.isVoid) {
81+
blockBuffer.write('{');
82+
rangeStart = sb.length + blockBuffer.length;
83+
blockBuffer.write(' }');
84+
rangeLength = 1;
85+
} else {
86+
final returnValue = returnType.isDartCoreBool ? 'false' : 'null';
87+
blockBuffer.write('=> ');
88+
rangeStart = sb.length + blockBuffer.length;
89+
blockBuffer.write(returnValue);
90+
rangeLength = returnValue.length;
91+
}
92+
93+
sb.write(blockBuffer);
94+
ranges.addAll([rangeStart, rangeLength]);
95+
} else {
96+
String name = param.name;
97+
sb.write(name);
98+
ranges.addAll([offset, name.length]);
99+
}
66100
}
67101

68102
for (ParameterElement param in namedParams) {
@@ -83,6 +117,39 @@ void addDefaultArgDetails(
83117
suggestion.defaultArgumentListTextRanges = ranges.isNotEmpty ? ranges : null;
84118
}
85119

120+
String buildClosureParameters(FunctionType type) {
121+
var buffer = StringBuffer();
122+
buffer.write('(');
123+
124+
var hasNamed = false;
125+
var hasOptionalPositional = false;
126+
var parameters = type.parameters;
127+
for (var i = 0; i < parameters.length; ++i) {
128+
var parameter = parameters[i];
129+
if (i != 0) {
130+
buffer.write(', ');
131+
}
132+
if (parameter.isNamed && !hasNamed) {
133+
hasNamed = true;
134+
buffer.write('{');
135+
} else if (parameter.isOptionalPositional && !hasOptionalPositional) {
136+
hasOptionalPositional = true;
137+
buffer.write('[');
138+
}
139+
// todo (pq): consider abbreviating names
140+
buffer.write(parameter.name);
141+
}
142+
143+
if (hasNamed) {
144+
buffer.write('}');
145+
} else if (hasOptionalPositional) {
146+
buffer.write(']');
147+
}
148+
149+
buffer.write(')');
150+
return buffer.toString();
151+
}
152+
86153
/**
87154
* Create a new protocol Element for inclusion in a completion suggestion.
88155
*/
@@ -268,7 +335,7 @@ String nameForType(SimpleIdentifier identifier, TypeAnnotation declaredType) {
268335
return type.toString();
269336
}
270337

271-
// TODO(pq): fix to use getDefaultStringParameterValue()
338+
/// TODO(pq): fix to use getDefaultStringParameterValue()
272339
String _getDefaultValue(ParameterElement param) => 'null';
273340

274341
/**

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

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2578,6 +2578,86 @@ g(F.^
25782578
assertNotSuggested('T2');
25792579
}
25802580

2581+
test_method_parameter_function_in_param_list() async {
2582+
addTestSource('''
2583+
class C {
2584+
void f(int x, void Function(int a, int b) closure, int y) {}
2585+
}
2586+
2587+
void main() {
2588+
new C().^
2589+
}
2590+
''');
2591+
await computeSuggestions();
2592+
2593+
final suggestion = assertSuggestMethod('f', 'C', 'void');
2594+
expect(suggestion.defaultArgumentListString, 'x, (a, b) { }, y');
2595+
2596+
// Select 'x', ' ', 'y'
2597+
expect(suggestion.defaultArgumentListTextRanges,
2598+
containsAllInOrder([0, 1, 11, 1, 15, 1]));
2599+
}
2600+
2601+
test_method_parameter_function_return_bool() async {
2602+
addTestSource('''
2603+
class C {
2604+
void f(bool Function(int a, int b) closure) {}
2605+
}
2606+
2607+
void main() {
2608+
new C().^
2609+
}
2610+
''');
2611+
await computeSuggestions();
2612+
2613+
final suggestion = assertSuggestMethod('f', 'C', 'void');
2614+
expect(suggestion.defaultArgumentListString, '(a, b) => false');
2615+
2616+
// Select 'false'
2617+
expect(
2618+
suggestion.defaultArgumentListTextRanges, containsAllInOrder([10, 5]));
2619+
}
2620+
2621+
test_method_parameter_function_return_object() async {
2622+
addTestSource('''
2623+
class C {
2624+
void f(Object Function(int a, int b) closure) {}
2625+
}
2626+
2627+
void main() {
2628+
new C().^
2629+
}
2630+
''');
2631+
await computeSuggestions();
2632+
2633+
final suggestion = assertSuggestMethod('f', 'C', 'void');
2634+
expect(suggestion.defaultArgumentListString, '(a, b) => null');
2635+
2636+
// Select 'null'
2637+
expect(
2638+
suggestion.defaultArgumentListTextRanges, containsAllInOrder([10, 4]));
2639+
}
2640+
2641+
test_method_parameter_function_return_void() async {
2642+
addTestSource('''
2643+
class C {
2644+
void f(void Function(int a, int b) closure) {}
2645+
}
2646+
2647+
void main() {
2648+
new C().^
2649+
}
2650+
''');
2651+
await computeSuggestions();
2652+
2653+
final suggestion = assertSuggestMethod('f', 'C', 'void');
2654+
expect(suggestion.defaultArgumentListString, '(a, b) { }');
2655+
2656+
// Select ' '
2657+
expect(
2658+
suggestion.defaultArgumentListTextRanges, containsAllInOrder([8, 1]));
2659+
}
2660+
25812661
test_method_parameters_mixed_required_and_named() async {
25822662
addTestSource('''
25832663
class C {

0 commit comments

Comments
 (0)