[analysis_server] Include 'required' keyword in closure completion text
This adds missing 'required' keywords when completing closures. The keyword is only added to the completion text and not the displayed label because there's limited space for completions and seeing the end of the completion (for example `=>` vs `{}` is more useful.
Fixes https://github.com/Dart-Code/Dart-Code/issues/4834
Change-Id: I3cb791bcd84533e9bc3819d8a527233f026849bd
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/336021
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Samuel Rawlins <srawlins@google.com>
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart b/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
index 6045348..7bbc2bb 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
@@ -351,6 +351,11 @@
void suggestClosure(FunctionType type, {bool includeTrailingComma = false}) {
var indent = getRequestLineIndent(request);
var parametersString = buildClosureParameters(type);
+ // Build a version of the parameter string without keywords for the
+ // completion label because `required` is less useful and may push the
+ // end of the completion (`=>` vs `() {}`) off the end.
+ var parametersDisplayString =
+ buildClosureParameters(type, includeKeywords: false);
var blockBuffer = StringBuffer(parametersString);
blockBuffer.writeln(' {');
@@ -389,14 +394,14 @@
_addSuggestion(
createSuggestion(
completion: blockBuffer.toString(),
- displayText: '$parametersString {}',
+ displayText: '$parametersDisplayString {}',
selectionOffset: blockSelectionOffset,
),
);
_addSuggestion(
createSuggestion(
completion: expressionBuffer.toString(),
- displayText: '$parametersString =>',
+ displayText: '$parametersDisplayString =>',
selectionOffset: expressionSelectionOffset,
),
);
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/utilities.dart b/pkg/analysis_server/lib/src/services/completion/dart/utilities.dart
index a113e2b..5b09594 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/utilities.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/utilities.dart
@@ -30,7 +30,8 @@
return b.relevance.compareTo(a.relevance);
};
-String buildClosureParameters(FunctionType type) {
+String buildClosureParameters(FunctionType type,
+ {bool includeKeywords = true}) {
var buffer = StringBuffer();
buffer.write('(');
@@ -59,6 +60,10 @@
index++;
}
}
+
+ if (includeKeywords && parameter.isRequiredNamed) {
+ buffer.write('required ');
+ }
buffer.write(name);
}
diff --git a/pkg/analysis_server/test/lsp/completion_dart_test.dart b/pkg/analysis_server/test/lsp/completion_dart_test.dart
index c2532ef..09f386b 100644
--- a/pkg/analysis_server/test/lsp/completion_dart_test.dart
+++ b/pkg/analysis_server/test/lsp/completion_dart_test.dart
@@ -843,6 +843,34 @@
);
}
+ Future<void> test_closure_requiredNamed() async {
+ final content = '''
+void f({void Function({int a, required String b}) closure}) {}
+
+void g() {
+ f(closure: ^);
+}
+''';
+
+ final expectedContent = '''
+void f({void Function({int a, required String b}) closure}) {}
+
+void g() {
+ f(closure: ({a, required b}) => ^,);
+}
+''';
+
+ await verifyCompletions(
+ mainFileUri,
+ content,
+ // Display text does not contain 'required' because it makes the
+ // completion much longer, we just include it in the completion text.
+ expectCompletions: ['({a, b}) {}', '({a, b}) =>'],
+ applyEditsFor: '({a, b}) =>',
+ expectedContent: expectedContent,
+ );
+ }
+
Future<void> test_comment() async {
final content = '''
// foo ^
diff --git a/pkg/analysis_server/test/services/completion/dart/declaration/closure_test.dart b/pkg/analysis_server/test/services/completion/dart/declaration/closure_test.dart
index 6e98d53..9aa9fb0 100644
--- a/pkg/analysis_server/test/services/completion/dart/declaration/closure_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/declaration/closure_test.dart
@@ -28,6 +28,12 @@
@override
bool get includeKeywords => false;
+ @override
+ Future<void> setUp() async {
+ await super.setUp();
+ printerConfiguration.withDisplayText = true;
+ }
+
Future<void> test_argumentList_named() async {
await computeSuggestions('''
void f({void Function(int a, String b) closure}) {}
@@ -40,11 +46,13 @@
suggestions
(a, b) => ,
kind: invocation
+ displayText: (a, b) =>
selection: 10
(a, b) {
${' ' * 4}
},
kind: invocation
+ displayText: (a, b) {}
selection: 13
''');
}
@@ -63,10 +71,12 @@
suggestions
|(a, b) => |
kind: invocation
+ displayText: (a, b) =>
(a, b) {
${' ' * 6}
}
kind: invocation
+ displayText: (a, b) {}
selection: 15
''');
}
@@ -83,11 +93,13 @@
suggestions
(a, b) => ,
kind: invocation
+ displayText: (a, b) =>
selection: 10
(a, b) {
${' ' * 4}
},
kind: invocation
+ displayText: (a, b) {}
selection: 13
''');
}
@@ -104,10 +116,12 @@
suggestions
|(a, b) => |
kind: invocation
+ displayText: (a, b) =>
(a, b) {
${' ' * 4}
}
kind: invocation
+ displayText: (a, b) {}
selection: 13
''');
}
@@ -124,11 +138,13 @@
suggestions
(a, {b, c}) => ,
kind: invocation
+ displayText: (a, {b, c}) =>
selection: 15
(a, {b, c}) {
${' ' * 4}
},
kind: invocation
+ displayText: (a, {b, c}) {}
selection: 18
''');
}
@@ -145,15 +161,40 @@
suggestions
(a, [b, c]) => ,
kind: invocation
+ displayText: (a, [b, c]) =>
selection: 15
(a, [b, c]) {
${' ' * 4}
},
kind: invocation
+ displayText: (a, [b, c]) {}
selection: 18
''');
}
+ Future<void> test_parameters_requiredNamed() async {
+ await computeSuggestions('''
+void f({void Function(int a, {int b, required int c}) closure}) {}
+
+void g() {
+ f(closure: ^);
+}
+''');
+ assertResponse('''
+suggestions
+ (a, {b, required c}) => ,
+ kind: invocation
+ displayText: (a, {b, c}) =>
+ selection: 24
+ (a, {b, required c}) {
+${' ' * 4}
+ },
+ kind: invocation
+ displayText: (a, {b, c}) {}
+ selection: 27
+''');
+ }
+
Future<void> test_variableInitializer() async {
await computeSuggestions('''
void Function(int a, int b) v = ^;
@@ -162,10 +203,12 @@
suggestions
|(a, b) => |
kind: invocation
+ displayText: (a, b) =>
(a, b) {
${' ' * 2}
}
kind: invocation
+ displayText: (a, b) {}
selection: 11
''');
}