Version 2.16.0-97.0.dev
Merge commit 'b0977940fa38a25443d3ccebb7c53bd327246a83' into 'dev'
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart
index 21f5f37..8cdcb87 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart
@@ -9,9 +9,7 @@
import 'package:analysis_server/src/utilities/flutter.dart';
import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/dart/element/type.dart';
/// A contributor that produces suggestions for named expression labels that
/// correspond to named parameters when completing in argument lists.
@@ -113,7 +111,8 @@
? 0
: null;
- var addTrailingComma = !_isFollowedByAComma() && _isInFlutterCreation();
+ var addTrailingComma =
+ !request.target.isFollowedByComma && _isInFlutterCreation();
_addDefaultParamSuggestions(parameters,
appendComma: addTrailingComma,
replacementLength: replacementLength);
@@ -122,12 +121,7 @@
_addDefaultParamSuggestions(parameters, appendComma: true);
} else if (_isInsertingToArgListWithSynthetic()) {
_addDefaultParamSuggestions(parameters,
- appendComma: !_isFollowedByAComma());
- } else {
- var argument = request.target.containingNode;
- if (argument is NamedExpression) {
- _buildClosureSuggestions(argument);
- }
+ appendComma: !request.target.isFollowedByComma);
}
}
@@ -147,15 +141,6 @@
return 0;
}
- void _buildClosureSuggestions(NamedExpression argument) {
- var type = argument.staticParameterElement?.type;
- if (type is FunctionType) {
- builder.suggestClosure(type,
- includeTrailingComma:
- argument.endToken.next?.type != TokenType.COMMA);
- }
- }
-
/// Return `true` if the caret is preceding an arg where a name could be added
/// (turning a positional arg into a named arg).
bool _isAddingLabelToPositional() {
@@ -222,24 +207,6 @@
return false;
}
- bool _isFollowedByAComma() {
- // new A(^); NO
- // new A(one: 1, ^); NO
- // new A(^ , one: 1); YES
- // new A(^), ... NO
-
- var containingNode = request.target.containingNode;
- var entity = request.target.entity;
- var token = entity is AstNode
- ? entity.endToken
- : entity is Token
- ? entity
- : null;
- return (token != containingNode.endToken) &&
- token?.next?.type == TokenType.COMMA &&
- !(token?.next?.isSynthetic ?? false);
- }
-
bool _isInFlutterCreation() {
var flutter = Flutter.instance;
var containingNode = request.target.containingNode;
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/closure_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/closure_contributor.dart
new file mode 100644
index 0000000..5700872
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/completion/dart/closure_contributor.dart
@@ -0,0 +1,33 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
+import 'package:analysis_server/src/services/completion/dart/completion_manager.dart';
+import 'package:analysis_server/src/services/completion/dart/suggestion_builder.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/type.dart';
+
+/// A contributor that produces a closure matching the context type.
+class ClosureContributor extends DartCompletionContributor {
+ ClosureContributor(
+ DartCompletionRequest request,
+ SuggestionBuilder builder,
+ ) : super(request, builder);
+
+ bool get _isArgument {
+ var node = request.target.containingNode;
+ return node is ArgumentList || node is NamedExpression;
+ }
+
+ @override
+ Future<void> computeSuggestions() async {
+ var contextType = request.contextType;
+ if (contextType is FunctionType) {
+ builder.suggestClosure(
+ contextType,
+ includeTrailingComma: _isArgument && !request.target.isFollowedByComma,
+ );
+ }
+ }
+}
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart b/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart
index 90da0ef..4193128 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart
@@ -6,6 +6,7 @@
import 'package:analysis_server/src/provisional/completion/completion_core.dart';
import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
import 'package:analysis_server/src/services/completion/dart/arglist_contributor.dart';
+import 'package:analysis_server/src/services/completion/dart/closure_contributor.dart';
import 'package:analysis_server/src/services/completion/dart/combinator_contributor.dart';
import 'package:analysis_server/src/services/completion/dart/documentation_cache.dart';
import 'package:analysis_server/src/services/completion/dart/extension_member_contributor.dart';
@@ -138,6 +139,7 @@
var builder = SuggestionBuilder(request, listener: listener);
var contributors = <DartCompletionContributor>[
ArgListContributor(request, builder),
+ ClosureContributor(request, builder),
CombinatorContributor(request, builder),
ExtensionMemberContributor(request, builder),
FieldFormalContributor(request, builder),
diff --git a/pkg/analysis_server/test/services/completion/dart/arglist_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/arglist_contributor_test.dart
index fc2016f..f320c5f 100644
--- a/pkg/analysis_server/test/services/completion/dart/arglist_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/arglist_contributor_test.dart
@@ -120,107 +120,6 @@
@reflectiveTest
class ArgListContributorTest extends DartCompletionContributorTest
with ArgListContributorMixin {
- Future<void> test_closure_namedArgument() async {
- addTestSource(r'''
-void f({void Function(int a, String b) closure}) {}
-
-void main() {
- f(closure: ^);
-}
-''');
- await computeSuggestions();
-
- assertSuggest(
- '(a, b) => ,',
- selectionOffset: 10,
- );
-
- assertSuggest(
- '''
-(a, b) {
-${' ' * 4}
-${' ' * 2}},''',
- selectionOffset: 13,
- );
- }
-
- Future<void> test_closure_namedArgument_hasComma() async {
- addTestSource(r'''
-void f({void Function(int a, String b) closure}) {}
-
-void main() {
- f(
- closure: ^,
- );
-}
-''');
- await computeSuggestions();
-
- assertSuggest(
- '(a, b) => ',
- selectionOffset: 10,
- );
-
- assertSuggest(
- '''
-(a, b) {
-${' ' * 6}
-${' ' * 4}}''',
- selectionOffset: 15,
- );
- }
-
- Future<void> test_closure_namedArgument_parameters_optionalNamed() async {
- addTestSource(r'''
-void f({void Function(int a, {int b, int c}) closure}) {}
-
-void main() {
- f(closure: ^);
-}
-''');
- await computeSuggestions();
-
- assertSuggest(
- '(a, {b, c}) => ,',
- selectionOffset: 15,
- );
- }
-
- Future<void>
- test_closure_namedArgument_parameters_optionalPositional() async {
- addTestSource(r'''
-void f({void Function(int a, [int b, int c]) closure]) {}
-
-void main() {
- f(closure: ^);
-}
-''');
- await computeSuggestions();
-
- assertSuggest(
- '(a, [b, c]) => ,',
- selectionOffset: 15,
- );
- }
-
- /// todo (pq): implement positional functional parameters
- @failingTest
- Future<void> test_closure_positionalArgument() async {
- addTestSource(r'''
-void f(void Function(int a, int b) closure) {}
-
-void main() {
- f(^);
-}
-''');
- await computeSuggestions();
-
- assertSuggest(
- '(a, b, c) => ,',
- selectionOffset: 13,
- );
- }
-
Future<void> test_fieldFormal_documentation() async {
var content = '''
class A {
@@ -486,6 +385,45 @@
Future<void> test_named_03() async {
await _tryParametersArguments(
parameters: '({bool one, int two})',
+ arguments: '(o^ two: 2)',
+ check: () {
+ assertSuggestArgumentsAndTypes(
+ namedArgumentsWithTypes: {'one': 'bool'}, includeComma: true);
+ assertSuggestArgumentAndCompletion('one',
+ completion: 'one: ,', selectionOffset: 5);
+ },
+ );
+ }
+
+ Future<void> test_named_04() async {
+ await _tryParametersArguments(
+ parameters: '({bool one, int two})',
+ arguments: '(o^, two: 2)',
+ check: () {
+ assertSuggestArgumentsAndTypes(
+ namedArgumentsWithTypes: {'one': 'bool'}, includeComma: false);
+ assertSuggestArgumentAndCompletion('one',
+ completion: 'one: ', selectionOffset: 5);
+ },
+ );
+ }
+
+ Future<void> test_named_05() async {
+ await _tryParametersArguments(
+ parameters: '({bool one, int two})',
+ arguments: '(o^ , two: 2)',
+ check: () {
+ assertSuggestArgumentsAndTypes(
+ namedArgumentsWithTypes: {'one': 'bool'}, includeComma: false);
+ assertSuggestArgumentAndCompletion('one',
+ completion: 'one: ', selectionOffset: 5);
+ },
+ );
+ }
+
+ Future<void> test_named_06() async {
+ await _tryParametersArguments(
+ parameters: '({bool one, int two})',
arguments: '(^o,)',
check: () {
assertSuggestArgumentsAndTypes(
@@ -497,7 +435,7 @@
);
}
- Future<void> test_named_04() async {
+ Future<void> test_named_07() async {
await _tryParametersArguments(
parameters: '({bool one, int two})',
arguments: '(^ two: 2)',
@@ -510,20 +448,7 @@
);
}
- Future<void> test_named_05() async {
- await _tryParametersArguments(
- parameters: '({bool one, int two})',
- arguments: '(o^ two: 2)',
- check: () {
- assertSuggestArgumentsAndTypes(
- namedArgumentsWithTypes: {'one': 'bool'}, includeComma: true);
- assertSuggestArgumentAndCompletion('one',
- completion: 'one: ,', selectionOffset: 5);
- },
- );
- }
-
- Future<void> test_named_06() async {
+ Future<void> test_named_08() async {
await _tryParametersArguments(
parameters: '({bool one, int two})',
arguments: '(^two: 2)',
@@ -533,7 +458,7 @@
);
}
- Future<void> test_named_07() async {
+ Future<void> test_named_09() async {
await _tryParametersArguments(
parameters: '({bool one, int two})',
arguments: '(^, two: 2)',
@@ -548,20 +473,7 @@
);
}
- Future<void> test_named_08() async {
- await _tryParametersArguments(
- parameters: '({bool one, int two})',
- arguments: '(o^, two: 2)',
- check: () {
- assertSuggestArgumentsAndTypes(
- namedArgumentsWithTypes: {'one': 'bool'}, includeComma: false);
- assertSuggestArgumentAndCompletion('one',
- completion: 'one: ', selectionOffset: 5);
- },
- );
- }
-
- Future<void> test_named_09() async {
+ Future<void> test_named_10() async {
await _tryParametersArguments(
parameters: '({bool one, int two})',
arguments: '(^ , two: 2)',
@@ -573,7 +485,7 @@
);
}
- Future<void> test_named_10() async {
+ Future<void> test_named_11() async {
await _tryParametersArguments(
parameters: '(int one, {bool two, int three})',
arguments: '(1, ^, three: 3)',
@@ -585,7 +497,7 @@
);
}
- Future<void> test_named_11() async {
+ Future<void> test_named_12() async {
await _tryParametersArguments(
parameters: '(int one, {bool two, int three})',
arguments: '(1, ^ three: 3)',
@@ -595,7 +507,7 @@
);
}
- Future<void> test_named_12() async {
+ Future<void> test_named_13() async {
await _tryParametersArguments(
parameters: '(int one, {bool two, int three})',
arguments: '(1, ^three: 3)',
@@ -606,7 +518,7 @@
}
@failingTest
- Future<void> test_named_13() async {
+ Future<void> test_named_14() async {
await _tryParametersArguments(
parameters: '({bool one, int two})',
arguments: '(two: 2^)',
@@ -617,7 +529,7 @@
}
@failingTest
- Future<void> test_named_14() async {
+ Future<void> test_named_15() async {
await _tryParametersArguments(
parameters: '({bool one, int two})',
arguments: '(two: 2 ^)',
@@ -627,7 +539,7 @@
);
}
- Future<void> test_named_15() async {
+ Future<void> test_named_16() async {
await _tryParametersArguments(
parameters: '({bool one, int two})',
arguments: '(two: 2, ^)',
@@ -641,7 +553,7 @@
);
}
- Future<void> test_named_16() async {
+ Future<void> test_named_17() async {
await _tryParametersArguments(
parameters: '({bool one, int two})',
arguments: '(two: 2, o^)',
@@ -655,7 +567,7 @@
);
}
- Future<void> test_named_17() async {
+ Future<void> test_named_18() async {
await _tryParametersArguments(
parameters: '({bool one, int two})',
arguments: '(two: 2, o^,)',
@@ -669,7 +581,7 @@
);
}
- Future<void> test_named_18() async {
+ Future<void> test_named_19() async {
await _tryParametersArguments(
parameters: '(int one, int two, int three, {int four, int five})',
arguments: '(1, ^, 3)',
@@ -679,7 +591,7 @@
);
}
- Future<void> test_named_19() async {
+ Future<void> test_named_20() async {
await _tryParametersArguments(
languageVersion: '2.15',
parameters: '(int one, int two, int three, {int four, int five})',
@@ -690,7 +602,7 @@
);
}
- Future<void> test_named_20() async {
+ Future<void> test_named_21() async {
await _tryParametersArguments(
parameters: '({bool one, int two})',
arguments: '(o^: false)',
@@ -703,7 +615,7 @@
);
}
- Future<void> test_named_21() async {
+ Future<void> test_named_22() async {
await _tryParametersArguments(
parameters: '(bool one, {int two, double three})',
arguments: '(false, ^t: 2)',
@@ -713,7 +625,7 @@
);
}
- Future<void> test_named_22() async {
+ Future<void> test_named_23() async {
await _tryParametersArguments(
parameters: '(bool one, {int two, double three})',
arguments: '(false, ^: 2)',
@@ -725,7 +637,7 @@
);
}
- Future<void> test_named_23() async {
+ Future<void> test_named_24() async {
await _tryParametersArguments(
parameters: '({bool one, int two})',
arguments: '(one: ^)',
diff --git a/pkg/analysis_server/test/services/completion/dart/closure_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/closure_contributor_test.dart
new file mode 100644
index 0000000..21a2ef7
--- /dev/null
+++ b/pkg/analysis_server/test/services/completion/dart/closure_contributor_test.dart
@@ -0,0 +1,154 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
+import 'package:analysis_server/src/services/completion/dart/closure_contributor.dart';
+import 'package:analysis_server/src/services/completion/dart/completion_manager.dart';
+import 'package:analysis_server/src/services/completion/dart/suggestion_builder.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'completion_contributor_util.dart';
+
+void main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(ClosureContributorTest);
+ });
+}
+
+@reflectiveTest
+class ClosureContributorTest extends DartCompletionContributorTest {
+ @override
+ DartCompletionContributor createContributor(
+ DartCompletionRequest request,
+ SuggestionBuilder builder,
+ ) {
+ return ClosureContributor(request, builder);
+ }
+
+ Future<void> test_argumentList_named() async {
+ addTestSource(r'''
+void f({void Function(int a, String b) closure}) {}
+
+void main() {
+ f(closure: ^);
+}
+''');
+ await computeSuggestions();
+
+ assertSuggest(
+ '(a, b) => ,',
+ selectionOffset: 10,
+ );
+
+ assertSuggest(
+ '''
+(a, b) {
+${' ' * 4}
+${' ' * 2}},''',
+ selectionOffset: 13,
+ );
+ }
+
+ Future<void> test_argumentList_named_hasComma() async {
+ addTestSource(r'''
+void f({void Function(int a, String b) closure}) {}
+
+void main() {
+ f(
+ closure: ^,
+ );
+}
+''');
+ await computeSuggestions();
+
+ assertSuggest(
+ '(a, b) => ',
+ selectionOffset: 10,
+ );
+
+ assertSuggest(
+ '''
+(a, b) {
+${' ' * 6}
+${' ' * 4}}''',
+ selectionOffset: 15,
+ );
+ }
+
+ Future<void> test_argumentList_positional() async {
+ addTestSource(r'''
+void f(void Function(int a, int b) closure) {}
+
+void main() {
+ f(^);
+}
+''');
+ await computeSuggestions();
+
+ assertSuggest(
+ '(a, b) => ,',
+ selectionOffset: 10,
+ );
+ }
+
+ Future<void> test_argumentList_positional_hasComma() async {
+ addTestSource(r'''
+void f(void Function(int a, int b) closure) {}
+
+void main() {
+ f(^,);
+}
+''');
+ await computeSuggestions();
+
+ assertSuggest(
+ '(a, b) => ',
+ selectionOffset: 10,
+ );
+ }
+
+ Future<void> test_parameters_optionalNamed() async {
+ addTestSource(r'''
+void f({void Function(int a, {int b, int c}) closure}) {}
+
+void main() {
+ f(closure: ^);
+}
+''');
+ await computeSuggestions();
+
+ assertSuggest(
+ '(a, {b, c}) => ,',
+ selectionOffset: 15,
+ );
+ }
+
+ Future<void> test_parameters_optionalPositional() async {
+ addTestSource(r'''
+void f({void Function(int a, [int b, int c]) closure]) {}
+
+void main() {
+ f(closure: ^);
+}
+''');
+ await computeSuggestions();
+
+ assertSuggest(
+ '(a, [b, c]) => ,',
+ selectionOffset: 15,
+ );
+ }
+
+ Future<void> test_variableInitializer() async {
+ addTestSource(r'''
+void Function(int a, int b) v = ^;
+''');
+ await computeSuggestions();
+
+ assertSuggest(
+ '(a, b) => ',
+ selectionOffset: 10,
+ );
+ }
+}
diff --git a/pkg/analysis_server/test/services/completion/dart/test_all.dart b/pkg/analysis_server/test/services/completion/dart/test_all.dart
index c8ccce6..4ed7cd0 100644
--- a/pkg/analysis_server/test/services/completion/dart/test_all.dart
+++ b/pkg/analysis_server/test/services/completion/dart/test_all.dart
@@ -5,6 +5,7 @@
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'arglist_contributor_test.dart' as arglist_test;
+import 'closure_contributor_test.dart' as closure_contributor;
import 'combinator_contributor_test.dart' as combinator_test;
import 'completion_manager_test.dart' as completion_manager;
import 'extension_member_contributor_test.dart' as extension_member_contributor;
@@ -27,6 +28,7 @@
void main() {
defineReflectiveSuite(() {
arglist_test.main();
+ closure_contributor.main();
combinator_test.main();
completion_manager.main();
extension_member_contributor.main();
diff --git a/pkg/analyzer_plugin/lib/src/utilities/completion/completion_target.dart b/pkg/analyzer_plugin/lib/src/utilities/completion/completion_target.dart
index 24e9359..31590d0 100644
--- a/pkg/analyzer_plugin/lib/src/utilities/completion/completion_target.dart
+++ b/pkg/analyzer_plugin/lib/src/utilities/completion/completion_target.dart
@@ -343,6 +343,37 @@
return false;
}
+ /// Return `true` if the [offset] is followed by a comma.
+ bool get isFollowedByComma {
+ // f(^); NO
+ // f(one: 1, ^); NO
+ // f(^ , one: 1); YES
+ // f(^, one: 1); YES
+ // f(^ one: 1); NO
+
+ bool isExistingComma(Token? token) {
+ return token != null &&
+ !token.isSynthetic &&
+ token.type == TokenType.COMMA;
+ }
+
+ var entity = this.entity;
+
+ Token token;
+ if (entity is AstNode) {
+ token = entity.endToken;
+ } else if (entity is Token) {
+ token = entity;
+ } else {
+ return false;
+ }
+
+ if (token.offset <= offset && offset <= token.end) {
+ return isExistingComma(token.next);
+ }
+ return isExistingComma(token);
+ }
+
/// If the target is an argument in an argument list, and the invocation is
/// resolved, return the corresponding [ParameterElement].
ParameterElement? get parameterElement {
diff --git a/pkg/test_runner/lib/src/testing_servers.dart b/pkg/test_runner/lib/src/testing_servers.dart
index 984f83c..ca69031 100644
--- a/pkg/test_runner/lib/src/testing_servers.dart
+++ b/pkg/test_runner/lib/src/testing_servers.dart
@@ -166,6 +166,7 @@
server.addHandler('/$prefixBuildDir', fileHandler);
server.addHandler('/$prefixDartDir', fileHandler);
server.addHandler('/packages', fileHandler);
+ server.addHandler('/upload', _handleUploadRequest);
_serverList.add(httpServer);
return server;
});
@@ -237,6 +238,23 @@
});
}
+ void _handleUploadRequest(HttpRequest request) async {
+ try {
+ var builder = await request.fold(BytesBuilder(), (var b, var d) {
+ b.add(d);
+ return b;
+ });
+ var data = builder.takeBytes();
+ DebugLogger.info(
+ 'Uploaded data: ${String.fromCharCodes(data as Iterable<int>)}');
+ request.response.headers.set("Access-Control-Allow-Origin", "*");
+ request.response.close();
+ } catch (e) {
+ DebugLogger.warning(
+ 'HttpServer: error while processing upload request', e);
+ }
+ }
+
Uri _getFileUriFromRequestUri(Uri request) {
// Go to the top of the file to see an explanation of the URL path scheme.
var pathSegments = request.normalizePath().pathSegments;
diff --git a/tools/VERSION b/tools/VERSION
index 2ce508d..63f943c 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 16
PATCH 0
-PRERELEASE 96
+PRERELEASE 97
PRERELEASE_PATCH 0
\ No newline at end of file