Version 2.10.0-95.0.dev
Merge commit '910d1d7e0541c41f14c65cc8a37c79c9013e7c7d' into 'dev'
diff --git a/pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart b/pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart
index 8ca0596..27e4114 100644
--- a/pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart
+++ b/pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart
@@ -44,6 +44,7 @@
import 'package:analysis_server/src/services/correction/dart/replace_with_is_empty.dart';
import 'package:analysis_server/src/services/correction/dart/replace_with_tear_off.dart';
import 'package:analysis_server/src/services/correction/dart/replace_with_var.dart';
+import 'package:analysis_server/src/services/correction/dart/sort_child_property_last.dart';
import 'package:analysis_server/src/services/correction/dart/use_curly_braces.dart';
import 'package:analysis_server/src/services/correction/dart/use_is_not_empty.dart';
import 'package:analysis_server/src/services/correction/dart/use_rethrow.dart';
@@ -103,6 +104,7 @@
LintNames.prefer_single_quotes: ConvertToSingleQuotes.newInstance,
LintNames.prefer_spread_collections: ConvertAddAllToSpread.newInstance,
LintNames.slash_for_doc_comments: ConvertDocumentationIntoLine.newInstance,
+ LintNames.sort_child_properties_last: SortChildPropertyLast.newInstance,
LintNames.type_init_formals: RemoveTypeAnnotation.newInstance,
LintNames.unawaited_futures: AddAwait.newInstance,
LintNames.unnecessary_brace_in_string_interps:
diff --git a/pkg/analysis_server/test/src/services/correction/fix/bulk/sort_child_properties_last.dart b/pkg/analysis_server/test/src/services/correction/fix/bulk/sort_child_properties_last.dart
new file mode 100644
index 0000000..80c02dd
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/bulk/sort_child_properties_last.dart
@@ -0,0 +1,64 @@
+// Copyright (c) 2020, 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/services/linter/lint_names.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'bulk_fix_processor.dart';
+
+void main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(SortChildPropertyLastTest);
+ });
+}
+
+@reflectiveTest
+class SortChildPropertyLastTest extends BulkFixProcessorTest {
+ @override
+ String get lintCode => LintNames.sort_child_properties_last;
+
+ Future<void> test_singleFile() async {
+ addFlutterPackage();
+ await resolveTestUnit('''
+import 'package:flutter/material.dart';
+main() {
+ Column(
+ children: [
+ Column(
+ children: [
+ Text('a'),
+ ],
+ crossAxisAlignment: CrossAxisAlignment.center,
+ ),
+ Text('b'),
+ Text('c'),
+ Text('d'),
+ ],
+ crossAxisAlignment: CrossAxisAlignment.center,
+ );
+}
+''');
+ // todo (pq): two diagnostics are produced but only the first is fixed.
+ // see: linter/test/rules/sort_child_properties_last.dart:nestedChildren()
+ await assertHasFix('''
+import 'package:flutter/material.dart';
+main() {
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ Column(
+ children: [
+ Text('a'),
+ ],
+ crossAxisAlignment: CrossAxisAlignment.center,
+ ),
+ Text('b'),
+ Text('c'),
+ Text('d'),
+ ],
+ );
+}
+''');
+ }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/bulk/test_all.dart b/pkg/analysis_server/test/src/services/correction/fix/bulk/test_all.dart
index 009ee47..36033cf 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/bulk/test_all.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/bulk/test_all.dart
@@ -46,6 +46,7 @@
import 'replace_with_is_empty_test.dart' as replace_with_is_empty;
import 'replace_with_tear_off_test.dart' as replace_with_tear_off;
import 'replace_with_var_test.dart' as replace_with_var;
+import 'sort_child_properties_last.dart' as sort_child_properties_last;
import 'use_curly_braces_test.dart' as use_curly_braces;
import 'use_is_not_empty_test.dart' as use_is_not_empty;
import 'use_rethrow_test.dart' as use_rethrow;
@@ -88,6 +89,7 @@
replace_with_is_empty.main();
replace_with_tear_off.main();
replace_with_var.main();
+ sort_child_properties_last.main();
use_curly_braces.main();
use_is_not_empty.main();
use_rethrow.main();
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/add_type_parameter_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/add_type_parameter_test.dart
index 1744e2f..a296cb0 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/add_type_parameter_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/add_type_parameter_test.dart
@@ -13,35 +13,17 @@
void main() {
defineReflectiveSuite(() {
defineReflectiveTests(AddTypeParameterToClassTest);
- defineReflectiveTests(AddTypeParameterToConstructorTest);
defineReflectiveTests(AddTypeParameterToExtensionTest);
defineReflectiveTests(AddTypeParameterToMethodTest);
+ defineReflectiveTests(AddTypeParameterToMixinTest);
+ defineReflectiveTests(AddTypeParameterToTopLevelFunctionTest);
+ defineReflectiveTests(AddTypeParameterToTypedefTest);
});
}
@reflectiveTest
class AddTypeParameterToClassTest extends _AddTypeParameterChange {
- Future<void> test_class_removed() async {
- setPackageContent('''
-class C<S, T> {}
-''');
- setPackageData(_add(0, components: ['C']));
- await resolveTestUnit('''
-import '$importUri';
-
-void f(C<int> c) {}
-''');
- await assertHasFix('''
-import '$importUri';
-
-void f(C<String, int> c) {}
-''');
- }
-}
-
-@reflectiveTest
-class AddTypeParameterToConstructorTest extends _AddTypeParameterChange {
- Future<void> test_constructor_removed() async {
+ Future<void> test_constructorInvocation_removed() async {
setPackageContent('''
class C<S, T> {
void C() {}
@@ -63,11 +45,96 @@
}
''');
}
+
+ Future<void> test_inExtends_removed() async {
+ setPackageContent('''
+class A<S, T> {}
+''');
+ setPackageData(_add(0, components: ['A']));
+ await resolveTestUnit('''
+import '$importUri';
+
+class B extends A<int> {}
+''');
+ await assertHasFix('''
+import '$importUri';
+
+class B extends A<String, int> {}
+''');
+ }
+
+ Future<void> test_inImplements_removed() async {
+ setPackageContent('''
+class A<S, T> {}
+''');
+ setPackageData(_add(0, components: ['A']));
+ await resolveTestUnit('''
+import '$importUri';
+
+class B implements A<int> {}
+''');
+ await assertHasFix('''
+import '$importUri';
+
+class B implements A<String, int> {}
+''');
+ }
+
+ Future<void> test_inOn_removed() async {
+ setPackageContent('''
+class A<S, T> {}
+''');
+ setPackageData(_add(0, components: ['A']));
+ await resolveTestUnit('''
+import '$importUri';
+
+extension E on A<int> {}
+''');
+ await assertHasFix('''
+import '$importUri';
+
+extension E on A<String, int> {}
+''');
+ }
+
+ Future<void> test_inTypeAnnotation_removed() async {
+ setPackageContent('''
+class C<S, T> {}
+''');
+ setPackageData(_add(0, components: ['C']));
+ await resolveTestUnit('''
+import '$importUri';
+
+void f(C<int> c) {}
+''');
+ await assertHasFix('''
+import '$importUri';
+
+void f(C<String, int> c) {}
+''');
+ }
+
+ Future<void> test_inWith_removed() async {
+ setPackageContent('''
+class A<S, T> {}
+''');
+ setPackageData(_add(0, components: ['A']));
+ await resolveTestUnit('''
+import '$importUri';
+
+class B with A<int> {}
+''');
+ await assertHasFix('''
+import '$importUri';
+
+class B with A<String, int> {}
+''');
+ }
}
@reflectiveTest
class AddTypeParameterToExtensionTest extends _AddTypeParameterChange {
- Future<void> test_extension_removed() async {
+ Future<void> test_override_removed() async {
setPackageContent('''
class C {}
extension E<S, T> on C {
@@ -94,7 +161,126 @@
@reflectiveTest
class AddTypeParameterToMethodTest extends _AddTypeParameterChange {
- Future<void> test_method_bound_removed() async {
+ Future<void> test_first_deprecated() async {
+ setPackageContent('''
+class C {
+ @deprecated
+ void m<T>() {}
+}
+''');
+ setPackageData(_add(0));
+ await resolveTestUnit('''
+import '$importUri';
+
+void f(C c) {
+ c.m<int>();
+}
+''');
+ await assertHasFix('''
+import '$importUri';
+
+void f(C c) {
+ c.m<String, int>();
+}
+''');
+ }
+
+ Future<void> test_first_removed() async {
+ setPackageContent('''
+class C {
+ void m<S, T>() {}
+}
+''');
+ setPackageData(_add(0));
+ await resolveTestUnit('''
+import '$importUri';
+
+void f(C c) {
+ c.m<int>();
+}
+''');
+ await assertHasFix('''
+import '$importUri';
+
+void f(C c) {
+ c.m<String, int>();
+}
+''');
+ }
+
+ Future<void> test_last_deprecated() async {
+ setPackageContent('''
+class C {
+ @deprecated
+ void m<S, T>() {}
+}
+''');
+ setPackageData(_add(2));
+ await resolveTestUnit('''
+import '$importUri';
+
+void f(C c) {
+ c.m<int, double>();
+}
+''');
+ await assertHasFix('''
+import '$importUri';
+
+void f(C c) {
+ c.m<int, double, String>();
+}
+''');
+ }
+
+ Future<void> test_middle_deprecated() async {
+ setPackageContent('''
+class C {
+ @deprecated
+ void m<S, U>() {}
+}
+''');
+ setPackageData(_add(1));
+ await resolveTestUnit('''
+import '$importUri';
+
+void f(C c) {
+ c.m<int, double>();
+}
+''');
+ await assertHasFix('''
+import '$importUri';
+
+void f(C c) {
+ c.m<int, String, double>();
+}
+''');
+ }
+
+ Future<void> test_only_deprecated() async {
+ setPackageContent('''
+class C {
+ @deprecated
+ void m() {}
+}
+''');
+ setPackageData(_add(0));
+ await resolveTestUnit('''
+import '$importUri';
+
+void f(C c) {
+ c.m();
+}
+''');
+ await assertHasFix('''
+import '$importUri';
+
+void f(C c) {
+ c.m<String>();
+}
+''');
+ }
+
+ Future<void> test_override_withBound_removed() async {
setPackageContent('''
class C {
void m<T extends num>() {}
@@ -119,79 +305,7 @@
''');
}
- Future<void> test_method_first_deprecated() async {
- setPackageContent('''
-class C {
- @deprecated
- void m<T>() {}
-}
-''');
- setPackageData(_add(0));
- await resolveTestUnit('''
-import '$importUri';
-
-void f(C c) {
- c.m<int>();
-}
-''');
- await assertHasFix('''
-import '$importUri';
-
-void f(C c) {
- c.m<String, int>();
-}
-''');
- }
-
- Future<void> test_method_last_deprecated() async {
- setPackageContent('''
-class C {
- @deprecated
- void m<S, T>() {}
-}
-''');
- setPackageData(_add(2));
- await resolveTestUnit('''
-import '$importUri';
-
-void f(C c) {
- c.m<int, double>();
-}
-''');
- await assertHasFix('''
-import '$importUri';
-
-void f(C c) {
- c.m<int, double, String>();
-}
-''');
- }
-
- Future<void> test_method_middle_deprecated() async {
- setPackageContent('''
-class C {
- @deprecated
- void m<S, U>() {}
-}
-''');
- setPackageData(_add(1));
- await resolveTestUnit('''
-import '$importUri';
-
-void f(C c) {
- c.m<int, double>();
-}
-''');
- await assertHasFix('''
-import '$importUri';
-
-void f(C c) {
- c.m<int, String, double>();
-}
-''');
- }
-
- Future<void> test_method_noBound_removed() async {
+ Future<void> test_override_withoutBound_removed() async {
setPackageContent('''
class C {
void m<T>() {}
@@ -215,50 +329,126 @@
}
''');
}
-
- Future<void> test_method_only_deprecated() async {
- setPackageContent('''
-class C {
- @deprecated
- void m() {}
}
+
+@reflectiveTest
+class AddTypeParameterToMixinTest extends _AddTypeParameterChange {
+ Future<void> test_inWith_removed() async {
+ setPackageContent('''
+mixin M<S, T> {}
''');
- setPackageData(_add(0));
+ setPackageData(_add(0, components: ['M']));
await resolveTestUnit('''
import '$importUri';
-void f(C c) {
- c.m();
+class B with M<int> {}
+''');
+ await assertHasFix('''
+import '$importUri';
+
+class B with M<String, int> {}
+''');
+ }
+}
+
+@reflectiveTest
+class AddTypeParameterToTopLevelFunctionTest extends _AddTypeParameterChange {
+ Future<void> test_only_deprecated() async {
+ setPackageContent('''
+@deprecated
+void f() {}
+''');
+ setPackageData(_add(0, components: ['f']));
+ await resolveTestUnit('''
+import '$importUri';
+
+void g() {
+ f();
}
''');
await assertHasFix('''
import '$importUri';
-void f(C c) {
- c.m<String>();
+void g() {
+ f<String>();
+}
+''');
+ }
+}
+
+@reflectiveTest
+class AddTypeParameterToTypedefTest extends _AddTypeParameterChange {
+ @failingTest
+ Future<void> test_functionType_removed() async {
+ // The test fails because the change is to the typedef `F`, not to the
+ // parameter `f`, so we don't see that the change might apply.
+ //
+ // Note, however, that there isn't currently any way to specify that the
+ // type parameter belongs to the function type being declared rather than to
+ // the typedef, so even if we fixed the problem above we would apply the
+ // change in the wrong places.
+ setPackageContent('''
+typedef F = T Function<S, T>();
+''');
+ setPackageData(_add(0, components: ['F']));
+ await resolveTestUnit('''
+import '$importUri';
+
+void g(F f) {
+ f<int>();
+}
+''');
+ await assertHasFix('''
+import '$importUri';
+
+void g(F f) {
+ f<String, int>();
}
''');
}
- Future<void> test_method_removed() async {
+ Future<void> test_typedef_first_removed() async {
setPackageContent('''
-class C {
- void m<S, T>() {}
-}
+typedef F<S, T> = T Function();
''');
- setPackageData(_add(0));
+ setPackageData(_add(0, components: ['F']));
await resolveTestUnit('''
import '$importUri';
-void f(C c) {
- c.m<int>();
+void g(F<int> f) {
+ f();
}
''');
await assertHasFix('''
import '$importUri';
-void f(C c) {
- c.m<String, int>();
+void g(F<String, int> f) {
+ f();
+}
+''');
+ }
+
+ @failingTest
+ Future<void> test_typedef_only_removed() async {
+ // The test fails because there is no diagnostic generated when there were
+ // no type arguments before the change; the type arguments are silently
+ // inferred to be `dynamic`.
+ setPackageContent('''
+typedef F<T> = T Function();
+''');
+ setPackageData(_add(0, components: ['F']));
+ await resolveTestUnit('''
+import '$importUri';
+
+void g(F f) {
+ f();
+}
+''');
+ await assertHasFix('''
+import '$importUri';
+
+void g(F<String> f) {
+ f();
}
''');
}
diff --git a/pkg/analyzer/lib/src/dart/analysis/feature_set_provider.dart b/pkg/analyzer/lib/src/dart/analysis/feature_set_provider.dart
index d8c7d05..45de3c8 100644
--- a/pkg/analyzer/lib/src/dart/analysis/feature_set_provider.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/feature_set_provider.dart
@@ -96,8 +96,16 @@
}
/// Return the package corresponding to the [uri] or [path], `null` if none.
+ ///
+ /// For `package` and `asset` schemes the package name is retrieved from the
+ /// first path segment of [uri].
+ ///
+ /// For `file` schemes this tries to look up by the normalized [uri] path.
+ ///
+ /// If unable to find a package through other mechanisms mechanisms, or it is
+ /// an unrecognized uri scheme, then the package is looked up by [path].
Package _findPackage(Uri uri, String path) {
- if (uri.isScheme('package')) {
+ if (uri.isScheme('package') || uri.isScheme('asset')) {
var pathSegments = uri.pathSegments;
if (pathSegments.isNotEmpty) {
var packageName = pathSegments.first;
diff --git a/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
index 0cacd29..a0b22fb 100644
--- a/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
@@ -265,25 +265,15 @@
CompileTimeErrorCode.ASSIGNMENT_TO_CONST,
left,
);
- } else if (variable.setter == null) {
- if (variable is FieldElement) {
- if (variable.isSynthetic) {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_NO_SETTER,
- left,
- [variable.name, variable.enclosingElement.displayName],
- );
- } else {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.ASSIGNMENT_TO_FINAL,
- left,
- [variable.name],
- );
- }
- return;
- }
+ } else if (variable is FieldElement && variable.isSynthetic) {
_errorReporter.reportErrorForNode(
- CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_LOCAL,
+ CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_NO_SETTER,
+ left,
+ [variable.name, variable.enclosingElement.displayName],
+ );
+ } else {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.ASSIGNMENT_TO_FINAL,
left,
[variable.name],
);
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index 81b0968..8abc401 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -1671,25 +1671,15 @@
CompileTimeErrorCode.ASSIGNMENT_TO_CONST,
expression,
);
- } else if (variable.setter == null) {
- if (variable is FieldElement) {
- if (variable.isSynthetic) {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_NO_SETTER,
- highlightedNode,
- [variable.name, variable.enclosingElement.displayName],
- );
- } else {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.ASSIGNMENT_TO_FINAL,
- highlightedNode,
- [variable.name],
- );
- }
- return;
- }
+ } else if (variable is FieldElement && variable.isSynthetic) {
_errorReporter.reportErrorForNode(
- CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_LOCAL,
+ CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_NO_SETTER,
+ highlightedNode,
+ [variable.name, variable.enclosingElement.displayName],
+ );
+ } else {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.ASSIGNMENT_TO_FINAL,
highlightedNode,
[variable.name],
);
diff --git a/pkg/analyzer/test/src/dart/resolution/assignment_test.dart b/pkg/analyzer/test/src/dart/resolution/assignment_test.dart
index c499ea1..d8b9392 100644
--- a/pkg/analyzer/test/src/dart/resolution/assignment_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/assignment_test.dart
@@ -1459,7 +1459,7 @@
x = 2;
}
''', [
- error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_LOCAL, 30, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 30, 1),
]);
var assignment = findNode.assignment('x = 2');
@@ -2214,7 +2214,7 @@
}
}
''', [
- error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_LOCAL, 86, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 86, 1),
]);
var assignment = findNode.assignment('x = 2');
@@ -2416,7 +2416,7 @@
x = 2;
}
''', [
- error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_LOCAL, 31, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 31, 1),
]);
var assignment = findNode.assignment('x = 2');
diff --git a/pkg/analyzer/test/src/diagnostics/assignment_to_final_local_test.dart b/pkg/analyzer/test/src/diagnostics/assignment_to_final_local_test.dart
index bd8e7d6..7c95b50 100644
--- a/pkg/analyzer/test/src/diagnostics/assignment_to_final_local_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/assignment_to_final_local_test.dart
@@ -125,14 +125,6 @@
error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_LOCAL, 23, 1),
]);
}
-
- test_topLevelVariable() async {
- await assertErrorsInCode('''
-final x = 0;
-f() { x = 1; }''', [
- error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_LOCAL, 19, 1),
- ]);
- }
}
@reflectiveTest
@@ -147,28 +139,4 @@
}
''');
}
-
- test_set_external_variable_final_invalid() async {
- await assertErrorsInCode('''
-external final int x;
-void f(int value) {
- x = value;
-}
-''', [
- error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_LOCAL, 44, 1),
- ]);
- }
-
- test_topLevelVariable_late() async {
- await assertErrorsInCode('''
-late final int a;
-late final int b = 0;
-void f() {
- a = 1;
- b = 1;
-}
-''', [
- error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_LOCAL, 62, 1),
- ]);
- }
}
diff --git a/pkg/analyzer/test/src/diagnostics/assignment_to_final_no_setter_test.dart b/pkg/analyzer/test/src/diagnostics/assignment_to_final_no_setter_test.dart
index fe06f6f..0fb1b14 100644
--- a/pkg/analyzer/test/src/diagnostics/assignment_to_final_no_setter_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/assignment_to_final_no_setter_test.dart
@@ -15,44 +15,103 @@
@reflectiveTest
class AssignmentToFinalNoSetterTest extends PubPackageResolutionTest {
- test_instance_undefined_hasGetter() async {
+ test_prefixedIdentifier_class_instanceGetter() async {
await assertErrorsInCode('''
-extension E on int {
- int get foo => 0;
+class A {
+ int get x => 0;
}
-f() {
- 0.foo = 1;
+
+void f(A a) {
+ a.x = 0;
+ a.x += 0;
+ ++a.x;
+ a.x++;
}
''', [
- error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_NO_SETTER, 53, 3),
- ]);
- }
-
- test_prefixedIdentifier() async {
- await assertErrorsInCode('''
-class A {
- int get x => 0;
-}
-main() {
- A a = new A();
- a.x = 0;
-}''', [
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_NO_SETTER, 49, 1),
error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_NO_SETTER, 60, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_NO_SETTER, 74, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_NO_SETTER, 81, 1),
]);
}
- test_propertyAccess() async {
+ test_propertyAccess_class_instanceGetter() async {
await assertErrorsInCode('''
class A {
int get x => 0;
}
-class B {
- static A a;
+
+void f(A a) {
+ (a).x = 0;
+ (a).x += 0;
+ ++(a).x;
+ (a).x++;
}
-main() {
- B.a.x = 0;
-}''', [
+''', [
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_NO_SETTER, 51, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_NO_SETTER, 64, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_NO_SETTER, 80, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_NO_SETTER, 89, 1),
+ ]);
+ }
+
+ test_propertyAccess_extension_instanceGetter() async {
+ await assertErrorsInCode('''
+extension E on int {
+ int get x => 0;
+}
+
+void f() {
+ 0.x = 0;
+ 0.x += 0;
+ ++0.x;
+ 0.x++;
+}
+''', [
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_NO_SETTER, 57, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_NO_SETTER, 68, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_NO_SETTER, 82, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_NO_SETTER, 89, 1),
+ ]);
+ }
+
+ test_simpleIdentifier_class_instanceGetter() async {
+ await assertErrorsInCode('''
+class A {
+ int get x => 0;
+
+ void f() {
+ x = 0;
+ x += 0;
+ ++x;
+ x++;
+ }
+}
+''', [
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_NO_SETTER, 46, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_NO_SETTER, 57, 1),
error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_NO_SETTER, 71, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_NO_SETTER, 78, 1),
+ ]);
+ }
+
+ test_simpleIdentifier_class_staticGetter() async {
+ await assertErrorsInCode('''
+class A {
+ static int get x => 0;
+
+ void f() {
+ x = 0;
+ x += 0;
+ ++x;
+ x++;
+ }
+}
+''', [
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_NO_SETTER, 53, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_NO_SETTER, 64, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_NO_SETTER, 78, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_NO_SETTER, 85, 1),
]);
}
}
diff --git a/pkg/analyzer/test/src/diagnostics/assignment_to_final_test.dart b/pkg/analyzer/test/src/diagnostics/assignment_to_final_test.dart
index bc8888d..6b1537c 100644
--- a/pkg/analyzer/test/src/diagnostics/assignment_to_final_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/assignment_to_final_test.dart
@@ -16,29 +16,87 @@
@reflectiveTest
class AssignmentToFinalTest extends PubPackageResolutionTest {
- test_instanceVariable() async {
+ test_prefixedIdentifier_instanceField() async {
+ await assertNoErrorsInCode('''
+class A {
+ var x = 0;
+}
+
+void f(A a) {
+ a.x = 0;
+ a.x += 0;
+ ++a.x;
+ a.x++;
+}
+''');
+ }
+
+ test_prefixedIdentifier_instanceField_final() async {
await assertErrorsInCode('''
class A {
- final v = 0;
+ final x = 0;
}
-f() {
- A a = new A();
- a.v = 1;
-}''', [
- error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 54, 1),
+
+void f(A a) {
+ a.x = 0;
+ a.x += 0;
+ ++a.x;
+ a.x++;
+}
+''', [
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 46, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 57, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 71, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 78, 1),
]);
}
- test_instanceVariable_plusEq() async {
+ test_simpleIdentifier_topLevelGetter() async {
await assertErrorsInCode('''
-class A {
- final v = 0;
+int get x => 0;
+
+void f() {
+ x = 0;
+ x += 0;
+ ++x;
+ x++;
}
-f() {
- A a = new A();
- a.v += 1;
-}''', [
- error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 54, 1),
+''', [
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 30, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 39, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 51, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 56, 1),
+ ]);
+ }
+
+ test_simpleIdentifier_topLevelVariable() async {
+ await assertNoErrorsInCode('''
+var x = 0;
+
+void f() {
+ x = 0;
+ x += 0;
+ ++x;
+ x++;
+}
+''');
+ }
+
+ test_simpleIdentifier_topLevelVariable_final() async {
+ await assertErrorsInCode('''
+final x = 0;
+
+void f() {
+ x = 0;
+ x += 0;
+ ++x;
+ x++;
+}
+''', [
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 27, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 36, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 48, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 53, 1),
]);
}
}
@@ -46,131 +104,330 @@
@reflectiveTest
class AssignmentToFinalWithNullSafetyTest extends AssignmentToFinalTest
with WithNullSafetyMixin {
- test_field_late_propertyAccess() async {
- await assertErrorsInCode('''
-class A {
- late final int a;
- late final int b = 0;
- void m() {
- this.a = 1;
- this.b = 1;
- }
-}
-''', [
- error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 92, 1),
- ]);
- }
-
- test_field_late_simpleIdentifier() async {
- await assertErrorsInCode('''
-class A {
- late final int a;
- late final int b = 0;
- void m() {
- a = 1;
- b = 1;
- }
-}
-''', [
- error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 82, 1),
- ]);
- }
-
- test_field_static_final_late_prefixedIdentifier() async {
- await assertErrorsInCode('''
-class A {
- static late final int a;
- static late final int b = 0;
+ test_prefixedIdentifier_instanceField_abstract() async {
+ await assertNoErrorsInCode('''
+abstract class A {
+ abstract int x;
}
-void f() {
- A.a = 1;
- A.b = 1;
+void f(A a) {
+ a.x = 0;
+ a.x += 0;
+ ++a.x;
+ a.x++;
}
-''', [
- error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 97, 1),
- ]);
+''');
}
- test_field_static_final_late_simpleIdentifier() async {
+ test_prefixedIdentifier_instanceField_abstractFinal() async {
await assertErrorsInCode('''
-class A {
- static late final int a;
- static late final int b = 0;
- void m() {
- a = 1;
- b = 1;
- }
+abstract class A {
+ abstract final int x;
+}
+
+void f(A a) {
+ a.x = 0;
+ a.x += 0;
+ ++a.x;
+ a.x++;
}
''', [
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 64, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 75, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 89, 1),
error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 96, 1),
]);
}
- test_set_abstract_field_final_invalid() async {
- await assertErrorsInCode('''
-abstract class A {
- abstract final int x;
-}
-void f(A a, int x) {
- a.x = x;
-}
-''', [
- error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 70, 1),
- ]);
- }
-
- test_set_abstract_field_final_overridden_valid() async {
+ test_prefixedIdentifier_instanceField_external() async {
await assertNoErrorsInCode('''
abstract class A {
- abstract final int x;
+ external int x;
}
-abstract class B extends A {
- void set x(int value);
-}
-void f(B b, int x) {
- b.x = x; // ok because setter provided in derived class
+
+void f(A a) {
+ a.x = 0;
+ a.x += 0;
+ ++a.x;
+ a.x++;
}
''');
}
- test_set_external_field_final_invalid() async {
+ test_prefixedIdentifier_instanceField_externalFinal() async {
await assertErrorsInCode('''
-class A {
+abstract class A {
external final int x;
}
-void f(A a, int x) {
- a.x = x;
+
+void f(A a) {
+ a.x = 0;
+ a.x += 0;
+ ++a.x;
+ a.x++;
+}
+''', [
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 64, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 75, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 89, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 96, 1),
+ ]);
+ }
+
+ test_prefixedIdentifier_instanceField_lateFinal() async {
+ await assertNoErrorsInCode('''
+abstract class A {
+ late final int x;
+}
+
+void f(A a) {
+ a.x = 0;
+ a.x += 0;
+ ++a.x;
+ a.x++;
+}
+''');
+ }
+
+ test_prefixedIdentifier_instanceField_lateFinal_hasInitializer() async {
+ await assertErrorsInCode('''
+abstract class A {
+ late final int x = 0;
+}
+
+void f(A a) {
+ a.x = 0;
+ a.x += 0;
+ ++a.x;
+ a.x++;
+}
+''', [
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 64, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 75, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 89, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 96, 1),
+ ]);
+ }
+
+ test_prefixedIdentifier_staticField_externalFinal() async {
+ await assertErrorsInCode('''
+abstract class A {
+ external static final int x;
+}
+
+void f() {
+ A.x = 0;
+ A.x += 0;
+ ++A.x;
+ A.x++;
+}
+''', [
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 68, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 79, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 93, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 100, 1),
+ ]);
+ }
+
+ test_prefixedIdentifier_staticField_lateFinal() async {
+ await assertNoErrorsInCode('''
+abstract class A {
+ static late final int x;
+}
+
+void f() {
+ A.x = 0;
+ A.x += 0;
+ ++A.x;
+ A.x++;
+}
+''');
+ }
+
+ test_prefixedIdentifier_staticField_lateFinal_hasInitializer() async {
+ await assertErrorsInCode('''
+abstract class A {
+ static late final int x = 0;
+}
+
+void f() {
+ A.x = 0;
+ A.x += 0;
+ ++A.x;
+ A.x++;
+}
+''', [
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 68, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 79, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 93, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 100, 1),
+ ]);
+ }
+
+ test_propertyAccess_instanceField_lateFinal() async {
+ await assertNoErrorsInCode('''
+abstract class A {
+ late final int x;
+}
+
+void f(A a) {
+ (a).x = 0;
+ (a).x += 0;
+ ++(a).x;
+ (a).x++;
+}
+''');
+ }
+
+ test_propertyAccess_instanceField_lateFinal_hasInitializer() async {
+ await assertErrorsInCode('''
+abstract class A {
+ late final int x = 0;
+}
+
+void f(A a) {
+ (a).x = 0;
+ (a).x += 0;
+ ++(a).x;
+ (a).x++;
+}
+''', [
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 66, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 79, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 95, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 104, 1),
+ ]);
+ }
+
+ test_simpleIdentifier_instanceField_lateFinal() async {
+ await assertNoErrorsInCode('''
+abstract class A {
+ late final int x;
+
+ void f() {
+ x = 0;
+ x += 0;
+ ++x;
+ x++;
+ }
+}
+''');
+ }
+
+ test_simpleIdentifier_instanceField_lateFinal_hasInitializer() async {
+ await assertErrorsInCode('''
+abstract class A {
+ late final int x = 0;
+
+ void f() {
+ x = 0;
+ x += 0;
+ ++x;
+ x++;
+ }
}
''', [
error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 61, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 72, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 86, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 93, 1),
]);
}
- test_set_external_field_final_overridden_valid() async {
+ test_simpleIdentifier_staticField_lateFinal() async {
await assertNoErrorsInCode('''
-class A {
- external final int x;
-}
-abstract class B extends A {
- void set x(int value);
-}
-void f(B b, int x) {
- b.x = x; // ok because setter provided in derived class
+abstract class A {
+ static late final int x;
+
+ void f() {
+ x = 0;
+ x += 0;
+ ++x;
+ x++;
+ }
}
''');
}
- test_set_external_static_field_final_invalid() async {
+ test_simpleIdentifier_staticField_lateFinal_hasInitializer() async {
await assertErrorsInCode('''
-class A {
- external static final int x;
-}
-void f(int x) {
- A.x = x;
+abstract class A {
+ static late final int x = 0;
+
+ void f() {
+ x = 0;
+ x += 0;
+ ++x;
+ x++;
+ }
}
''', [
- error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 63, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 68, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 79, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 93, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 100, 1),
+ ]);
+ }
+
+ test_simpleIdentifier_topLevelVariable_external() async {
+ await assertNoErrorsInCode('''
+external int x;
+
+void f() {
+ x = 0;
+ x += 0;
+ ++x;
+ x++;
+}
+''');
+ }
+
+ test_simpleIdentifier_topLevelVariable_externalFinal() async {
+ await assertErrorsInCode('''
+external final x;
+
+void f() {
+ x = 0;
+ x += 0;
+ ++x;
+ x++;
+}
+''', [
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 32, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 41, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 53, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 58, 1),
+ ]);
+ }
+
+ test_simpleIdentifier_topLevelVariable_lateFinal() async {
+ await assertNoErrorsInCode('''
+late final int x;
+
+void f() {
+ x = 0;
+ x += 0;
+ ++x;
+ x++;
+}
+''');
+ }
+
+ test_simpleIdentifier_topLevelVariable_lateFinal_hasInitializer() async {
+ await assertErrorsInCode('''
+late final int x = 0;
+
+void f() {
+ x = 0;
+ x += 0;
+ ++x;
+ x++;
+}
+''', [
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 36, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 45, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 57, 1),
+ error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL, 62, 1),
]);
}
}
diff --git a/pkg/dartdev/lib/dartdev.dart b/pkg/dartdev/lib/dartdev.dart
index 1e0af75..4cc2964 100644
--- a/pkg/dartdev/lib/dartdev.dart
+++ b/pkg/dartdev/lib/dartdev.dart
@@ -81,9 +81,15 @@
// --launch-dds is provided by the VM if the VM service is to be enabled. In
// that case, we need to launch DDS as well.
- // TODO(bkonyi): add support for pub run (#42726)
- if (args.contains('--launch-dds')) {
+ final launchDdsArg = args.singleWhere(
+ (element) => element.startsWith('--launch-dds'),
+ orElse: () => null,
+ );
+ if (launchDdsArg != null) {
RunCommand.launchDds = true;
+ final ddsUrl = (launchDdsArg.split('=')[1]).split(':');
+ RunCommand.ddsHost = ddsUrl[0];
+ RunCommand.ddsPort = ddsUrl[1];
}
String commandName;
@@ -98,8 +104,8 @@
// Run also can't be called with '--launch-dds', remove it if it's
// contained in args.
- if (args.contains('--launch-dds')) {
- args = List.from(args)..remove('--launch-dds');
+ if (launchDdsArg != null) {
+ args = List.from(args)..remove(launchDdsArg);
}
// These flags have a format that can't be handled by package:args, so
diff --git a/pkg/dartdev/lib/src/commands/run.dart b/pkg/dartdev/lib/src/commands/run.dart
index 8f28c9f..feeb99c 100644
--- a/pkg/dartdev/lib/src/commands/run.dart
+++ b/pkg/dartdev/lib/src/commands/run.dart
@@ -18,6 +18,8 @@
class RunCommand extends DartdevCommand<int> {
static bool launchDds = false;
+ static String ddsHost;
+ static String ddsPort;
// kErrorExitCode, as defined in runtime/bin/error_exit.h
static const errorExitCode = 255;
@@ -209,9 +211,6 @@
// service intermediary which implements the VM service protocol and
// provides non-VM specific extensions (e.g., log caching, client
// synchronization).
- // TODO(bkonyi): Remove once DevTools supports DDS.
- // See https://github.com/flutter/flutter/issues/62507
- launchDds = false;
_DebuggingSession debugSession;
if (launchDds) {
debugSession = _DebuggingSession();
@@ -255,7 +254,9 @@
sdk.ddsSnapshot
else
absolute(dirname(sdk.dart), 'gen', 'dds.dart.snapshot'),
- serviceInfo.serverUri.toString()
+ serviceInfo.serverUri.toString(),
+ RunCommand.ddsHost,
+ RunCommand.ddsPort,
],
mode: ProcessStartMode.detachedWithStdio);
final completer = Completer<void>();
@@ -264,10 +265,20 @@
if (event == 'DDS started') {
sub.cancel();
completer.complete();
+ } else if (event.contains('Failed to start DDS')) {
+ sub.cancel();
+ completer.completeError(event.replaceAll(
+ 'Failed to start DDS',
+ 'Could not start Observatory HTTP server',
+ ));
}
});
-
- await completer.future;
- return true;
+ try {
+ await completer.future;
+ return true;
+ } catch (e) {
+ stderr.write(e);
+ return false;
+ }
}
}
diff --git a/pkg/dds/bin/dds.dart b/pkg/dds/bin/dds.dart
index 476e84b..ed683dd 100644
--- a/pkg/dds/bin/dds.dart
+++ b/pkg/dds/bin/dds.dart
@@ -9,10 +9,39 @@
/// A simple program which starts a [DartDevelopmentService] instance with a
/// basic configuration.
///
-/// Takes the VM service URI as its single argument.
+/// Takes the following positional arguments:
+/// - VM service URI
+/// - DDS bind address
+/// - DDS port
Future<void> main(List<String> args) async {
if (args.isEmpty) return;
+
+ // This URI is provided by the VM service directly so don't bother doing a
+ // lookup.
final remoteVmServiceUri = Uri.parse(args.first);
- await DartDevelopmentService.startDartDevelopmentService(remoteVmServiceUri);
- stderr.write('DDS started');
+
+ // Resolve the address which is potentially provided by the user.
+ InternetAddress address;
+ final addresses = await InternetAddress.lookup(args[1]);
+ // Prefer IPv4 addresses.
+ for (int i = 0; i < addresses.length; i++) {
+ address = addresses[i];
+ if (address.type == InternetAddressType.IPv4) break;
+ }
+ final serviceUri = Uri(
+ scheme: 'http',
+ host: address.address,
+ port: int.parse(args[2]),
+ );
+ try {
+ // TODO(bkonyi): add retry logic similar to that in vmservice_server.dart
+ // See https://github.com/dart-lang/sdk/issues/43192.
+ await DartDevelopmentService.startDartDevelopmentService(
+ remoteVmServiceUri,
+ serviceUri: serviceUri,
+ );
+ stderr.write('DDS started');
+ } catch (e) {
+ stderr.writeln('Failed to start DDS:\n$e');
+ }
}
diff --git a/pkg/dds/test/auth_codes_test.dart b/pkg/dds/test/auth_codes_test.dart
index 9e7ad8c..653ff41 100644
--- a/pkg/dds/test/auth_codes_test.dart
+++ b/pkg/dds/test/auth_codes_test.dart
@@ -37,7 +37,7 @@
final service = await vmServiceConnectUri(dds.wsUri.toString());
final version = await service.getVersion();
expect(version.major > 0, true);
- expect(version.minor > 0, true);
+ expect(version.minor >= 0, true);
// Ensure we can still make requests of the VM service via HTTP.
HttpClient client = HttpClient();
diff --git a/pkg/dds/test/smoke_test.dart b/pkg/dds/test/smoke_test.dart
index e7e5216..0da26db 100644
--- a/pkg/dds/test/smoke_test.dart
+++ b/pkg/dds/test/smoke_test.dart
@@ -41,7 +41,7 @@
final service = await vmServiceConnectUri(dds.wsUri.toString());
final version = await service.getVersion();
expect(version.major > 0, true);
- expect(version.minor > 0, true);
+ expect(version.minor >= 0, true);
expect(
dds.uri.pathSegments,
@@ -64,7 +64,7 @@
.single);
expect(jsonResponse['result']['type'], 'Version');
expect(jsonResponse['result']['major'] > 0, true);
- expect(jsonResponse['result']['minor'] > 0, true);
+ expect(jsonResponse['result']['minor'] >= 0, true);
},
);
}
diff --git a/pkg/vm_service/CHANGELOG.md b/pkg/vm_service/CHANGELOG.md
index 7be2213..466d85f 100644
--- a/pkg/vm_service/CHANGELOG.md
+++ b/pkg/vm_service/CHANGELOG.md
@@ -1,6 +1,11 @@
# Changelog
-## Unreleased
+## 5.0.0
+
+- **breaking**: Update to version `4.0.0` of the spec.
+ - Removes `ClientName` and `WebSocketTarget` objects
+ - Removes `getClientName`, `getWebSocketTarget`, `requirePermissionToResume`,
+ and `setClientName` RPCs.
- Added `isSystemIsolate` property to `IsolateRef` and `Isolate`.
- Added `isSystemIsolateGroup` property to `IsolateGroupRef` and `IsolateGroup`.
- Added `serviceIsolates` and `serviceIsolateGroups` properties to `VM`.
diff --git a/pkg/vm_service/example/vm_service_assert.dart b/pkg/vm_service/example/vm_service_assert.dart
index 4dc33b5..52746bd 100644
--- a/pkg/vm_service/example/vm_service_assert.dart
+++ b/pkg/vm_service/example/vm_service_assert.dart
@@ -367,13 +367,6 @@
return obj;
}
-vms.ClientName assertClientName(vms.ClientName obj) {
- assertNotNull(obj);
- assertString(obj.type);
- assertString(obj.name);
- return obj;
-}
-
vms.CodeRef assertCodeRef(vms.CodeRef obj) {
assertNotNull(obj);
assertString(obj.type);
@@ -1201,10 +1194,3 @@
assertListOfIsolateGroupRef(obj.systemIsolateGroups);
return obj;
}
-
-vms.WebSocketTarget assertWebSocketTarget(vms.WebSocketTarget obj) {
- assertNotNull(obj);
- assertString(obj.type);
- assertString(obj.uri);
- return obj;
-}
diff --git a/pkg/vm_service/java/.gitignore b/pkg/vm_service/java/.gitignore
index 4370934..fbcce7d 100644
--- a/pkg/vm_service/java/.gitignore
+++ b/pkg/vm_service/java/.gitignore
@@ -5,7 +5,6 @@
src/org/dartlang/vm/service/consumer/AddBreakpointConsumer.java
src/org/dartlang/vm/service/consumer/AddBreakpointWithScriptUriConsumer.java
src/org/dartlang/vm/service/consumer/ClearCpuSamplesConsumer.java
-src/org/dartlang/vm/service/consumer/ClientNameConsumer.java
src/org/dartlang/vm/service/consumer/EvaluateConsumer.java
src/org/dartlang/vm/service/consumer/EvaluateInFrameConsumer.java
src/org/dartlang/vm/service/consumer/FlagListConsumer.java
@@ -42,7 +41,6 @@
src/org/dartlang/vm/service/consumer/TimestampConsumer.java
src/org/dartlang/vm/service/consumer/VMConsumer.java
src/org/dartlang/vm/service/consumer/VersionConsumer.java
-src/org/dartlang/vm/service/consumer/WebSocketTargetConsumer.java
src/org/dartlang/vm/service/element/AllocationProfile.java
src/org/dartlang/vm/service/element/BoundField.java
src/org/dartlang/vm/service/element/BoundVariable.java
@@ -51,7 +49,6 @@
src/org/dartlang/vm/service/element/ClassList.java
src/org/dartlang/vm/service/element/ClassObj.java
src/org/dartlang/vm/service/element/ClassRef.java
-src/org/dartlang/vm/service/element/ClientName.java
src/org/dartlang/vm/service/element/Code.java
src/org/dartlang/vm/service/element/CodeKind.java
src/org/dartlang/vm/service/element/CodeRef.java
@@ -129,4 +126,3 @@
src/org/dartlang/vm/service/element/VM.java
src/org/dartlang/vm/service/element/VMRef.java
src/org/dartlang/vm/service/element/Version.java
-src/org/dartlang/vm/service/element/WebSocketTarget.java
diff --git a/pkg/vm_service/java/version.properties b/pkg/vm_service/java/version.properties
index 0fa4741..db1ef8e5 100644
--- a/pkg/vm_service/java/version.properties
+++ b/pkg/vm_service/java/version.properties
@@ -1 +1 @@
-version=3.38
+version=4.0
diff --git a/pkg/vm_service/lib/src/vm_service.dart b/pkg/vm_service/lib/src/vm_service.dart
index c9b4ec7..c518b25 100644
--- a/pkg/vm_service/lib/src/vm_service.dart
+++ b/pkg/vm_service/lib/src/vm_service.dart
@@ -28,7 +28,7 @@
HeapSnapshotObjectNoData,
HeapSnapshotObjectNullData;
-const String vmServiceVersion = '3.38.0';
+const String vmServiceVersion = '4.0.0';
/// @optional
const String optional = 'optional';
@@ -117,7 +117,6 @@
'Class': Class.parse,
'ClassHeapStats': ClassHeapStats.parse,
'ClassList': ClassList.parse,
- 'ClientName': ClientName.parse,
'@Code': CodeRef.parse,
'Code': Code.parse,
'@Context': ContextRef.parse,
@@ -186,7 +185,6 @@
'Version': Version.parse,
'@VM': VMRef.parse,
'VM': VM.parse,
- 'WebSocketTarget': WebSocketTarget.parse,
};
Map<String, List<String>> _methodReturnTypes = {
@@ -200,7 +198,6 @@
'evaluateInFrame': const ['InstanceRef', 'ErrorRef'],
'getAllocationProfile': const ['AllocationProfile'],
'getClassList': const ['ClassList'],
- 'getClientName': const ['ClientName'],
'getCpuSamples': const ['CpuSamples'],
'getFlagList': const ['FlagList'],
'getInboundReferences': const ['InboundReferences'],
@@ -221,16 +218,13 @@
'getVMTimeline': const ['Timeline'],
'getVMTimelineFlags': const ['TimelineFlags'],
'getVMTimelineMicros': const ['Timestamp'],
- 'getWebSocketTarget': const ['WebSocketTarget'],
'pause': const ['Success'],
'kill': const ['Success'],
'registerService': const ['Success'],
'reloadSources': const ['ReloadReport'],
'removeBreakpoint': const ['Success'],
'requestHeapSnapshot': const ['Success'],
- 'requirePermissionToResume': const ['Success'],
'resume': const ['Success'],
- 'setClientName': const ['Success'],
'setExceptionPauseMode': const ['Success'],
'setFlag': const ['Success', 'Error'],
'setLibraryDebuggable': const ['Success'],
@@ -518,13 +512,6 @@
/// returned.
Future<ClassList> getClassList(String isolateId);
- /// The `getClientName` RPC is used to retrieve the name associated with the
- /// currently connected VM service client. If no name was previously set
- /// through the [setClientName] RPC, a default name will be returned.
- ///
- /// See [ClientName].
- Future<ClientName> getClientName();
-
/// The `getCpuSamples` RPC is used to retrieve samples collected by the CPU
/// profiler. Only samples collected in the time range `[timeOriginMicros,
/// timeOriginMicros + timeExtentMicros]` will be reported.
@@ -854,13 +841,6 @@
/// See [Timestamp] and [getVMTimeline].
Future<Timestamp> getVMTimelineMicros();
- /// The `getWebSocketTarget` RPC returns the web socket URI that should be
- /// used by VM service clients with WebSocket implementations that do not
- /// follow redirects (e.g., `dart:html`'s [WebSocket]).
- ///
- /// See [WebSocketTarget].
- Future<WebSocketTarget> getWebSocketTarget();
-
/// The `pause` RPC is used to interrupt a running isolate. The RPC enqueues
/// the interrupt request and potentially returns before the isolate is
/// paused.
@@ -956,39 +936,6 @@
/// returned.
Future<Success> requestHeapSnapshot(String isolateId);
- /// The `requirePermissionToResume` RPC is used to change the pause/resume
- /// behavior of isolates by providing a way for the VM service to wait for
- /// approval to resume from some set of clients. This is useful for clients
- /// which want to perform some operation on an isolate after a pause without
- /// it being resumed by another client.
- ///
- /// If the `onPauseStart` parameter is `true`, isolates will not resume after
- /// pausing on start until the client sends a `resume` request and all other
- /// clients which need to provide resume approval for this pause type have
- /// done so.
- ///
- /// If the `onPauseReload` parameter is `true`, isolates will not resume after
- /// pausing after a reload until the client sends a `resume` request and all
- /// other clients which need to provide resume approval for this pause type
- /// have done so.
- ///
- /// If the `onPauseExit` parameter is `true`, isolates will not resume after
- /// pausing on exit until the client sends a `resume` request and all other
- /// clients which need to provide resume approval for this pause type have
- /// done so.
- ///
- /// **Important Notes:**
- ///
- /// - All clients with the same client name share resume permissions. Only a
- /// single client of a given name is required to provide resume approval.
- /// - When a client requiring approval disconnects from the service, a paused
- /// isolate may resume if all other clients requiring resume approval have
- /// already given approval. In the case that no other client requires resume
- /// approval for the current pause event, the isolate will be resumed if at
- /// least one other client has attempted to [resume] the isolate.
- Future<Success> requirePermissionToResume(
- {bool onPauseStart, bool onPauseReload, bool onPauseExit});
-
/// The `resume` RPC is used to resume execution of a paused isolate.
///
/// If the `step` parameter is not provided, the program will resume regular
@@ -1021,15 +968,6 @@
Future<Success> resume(String isolateId,
{/*StepOption*/ String step, int frameIndex});
- /// The `setClientName` RPC is used to set a name to be associated with the
- /// currently connected VM service client. If the `name` parameter is a
- /// non-empty string, `name` will become the new name associated with the
- /// client. If `name` is an empty string, the client's name will be reset to
- /// its default name.
- ///
- /// See [Success].
- Future<Success> setClientName(String name);
-
/// The `setExceptionPauseMode` RPC is used to control if an isolate pauses
/// when an exception is thrown.
///
@@ -1322,9 +1260,6 @@
params['isolateId'],
);
break;
- case 'getClientName':
- response = await _serviceImplementation.getClientName();
- break;
case 'getCpuSamples':
response = await _serviceImplementation.getCpuSamples(
params['isolateId'],
@@ -1428,9 +1363,6 @@
case 'getVMTimelineMicros':
response = await _serviceImplementation.getVMTimelineMicros();
break;
- case 'getWebSocketTarget':
- response = await _serviceImplementation.getWebSocketTarget();
- break;
case 'pause':
response = await _serviceImplementation.pause(
params['isolateId'],
@@ -1461,13 +1393,6 @@
params['isolateId'],
);
break;
- case 'requirePermissionToResume':
- response = await _serviceImplementation.requirePermissionToResume(
- onPauseStart: params['onPauseStart'],
- onPauseReload: params['onPauseReload'],
- onPauseExit: params['onPauseExit'],
- );
- break;
case 'resume':
response = await _serviceImplementation.resume(
params['isolateId'],
@@ -1475,11 +1400,6 @@
frameIndex: params['frameIndex'],
);
break;
- case 'setClientName':
- response = await _serviceImplementation.setClientName(
- params['name'],
- );
- break;
case 'setExceptionPauseMode':
response = await _serviceImplementation.setExceptionPauseMode(
params['isolateId'],
@@ -1792,9 +1712,6 @@
_call('getClassList', {'isolateId': isolateId});
@override
- Future<ClientName> getClientName() => _call('getClientName');
-
- @override
Future<CpuSamples> getCpuSamples(
String isolateId, int timeOriginMicros, int timeExtentMicros) =>
_call('getCpuSamples', {
@@ -1910,9 +1827,6 @@
Future<Timestamp> getVMTimelineMicros() => _call('getVMTimelineMicros');
@override
- Future<WebSocketTarget> getWebSocketTarget() => _call('getWebSocketTarget');
-
- @override
Future<Success> pause(String isolateId) =>
_call('pause', {'isolateId': isolateId});
@@ -1950,15 +1864,6 @@
_call('requestHeapSnapshot', {'isolateId': isolateId});
@override
- Future<Success> requirePermissionToResume(
- {bool onPauseStart, bool onPauseReload, bool onPauseExit}) =>
- _call('requirePermissionToResume', {
- if (onPauseStart != null) 'onPauseStart': onPauseStart,
- if (onPauseReload != null) 'onPauseReload': onPauseReload,
- if (onPauseExit != null) 'onPauseExit': onPauseExit,
- });
-
- @override
Future<Success> resume(String isolateId,
{/*StepOption*/ String step, int frameIndex}) =>
_call('resume', {
@@ -1968,10 +1873,6 @@
});
@override
- Future<Success> setClientName(String name) =>
- _call('setClientName', {'name': name});
-
- @override
Future<Success> setExceptionPauseMode(
String isolateId, /*ExceptionPauseMode*/ String mode) =>
_call('setExceptionPauseMode', {'isolateId': isolateId, 'mode': mode});
@@ -3074,35 +2975,6 @@
String toString() => '[ClassList type: ${type}, classes: ${classes}]';
}
-/// See [getClientName] and [setClientName].
-class ClientName extends Response {
- static ClientName parse(Map<String, dynamic> json) =>
- json == null ? null : ClientName._fromJson(json);
-
- /// The name of the currently connected VM service client.
- String name;
-
- ClientName({
- @required this.name,
- });
-
- ClientName._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
- name = json['name'];
- }
-
- @override
- Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
- json['type'] = 'ClientName';
- json.addAll({
- 'name': name,
- });
- return json;
- }
-
- String toString() => '[ClientName type: ${type}, name: ${name}]';
-}
-
/// `CodeRef` is a reference to a `Code` object.
class CodeRef extends ObjRef {
static CodeRef parse(Map<String, dynamic> json) =>
@@ -7171,32 +7043,3 @@
String toString() => '[VM]';
}
-
-/// See [getWebSocketTarget]
-class WebSocketTarget extends Response {
- static WebSocketTarget parse(Map<String, dynamic> json) =>
- json == null ? null : WebSocketTarget._fromJson(json);
-
- /// The web socket URI that should be used to connect to the service.
- String uri;
-
- WebSocketTarget({
- @required this.uri,
- });
-
- WebSocketTarget._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
- uri = json['uri'];
- }
-
- @override
- Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
- json['type'] = 'WebSocketTarget';
- json.addAll({
- 'uri': uri,
- });
- return json;
- }
-
- String toString() => '[WebSocketTarget type: ${type}, uri: ${uri}]';
-}
diff --git a/pkg/vm_service/pubspec.yaml b/pkg/vm_service/pubspec.yaml
index 6c4cda5..fff9595 100644
--- a/pkg/vm_service/pubspec.yaml
+++ b/pkg/vm_service/pubspec.yaml
@@ -2,7 +2,7 @@
description: >-
A library to communicate with a service implementing the Dart VM
service protocol.
-version: 4.2.0
+version: 5.0.0
homepage: https://github.com/dart-lang/sdk/tree/master/pkg/vm_service
diff --git a/pkg/vm_snapshot_analysis/lib/v8_profile.dart b/pkg/vm_snapshot_analysis/lib/v8_profile.dart
index 8419068..6f7db7b 100644
--- a/pkg/vm_snapshot_analysis/lib/v8_profile.dart
+++ b/pkg/vm_snapshot_analysis/lib/v8_profile.dart
@@ -412,7 +412,9 @@
case 'Function':
if (node.name != '<anonymous signature>') {
var owner = node['owner_'];
- if (node['data_'].type == 'ClosureData') {
+
+ // Artificial nodes will not have data_ field.
+ if (node['data_']?.type == 'ClosureData') {
owner = node['data_']['parent_function_'];
}
return makeInfoNode(node.index,
diff --git a/pkg/vm_snapshot_analysis/test/instruction_sizes_test.dart b/pkg/vm_snapshot_analysis/test/instruction_sizes_test.dart
index 78a1ac6..ee2a3d1 100644
--- a/pkg/vm_snapshot_analysis/test/instruction_sizes_test.dart
+++ b/pkg/vm_snapshot_analysis/test/instruction_sizes_test.dart
@@ -665,7 +665,7 @@
expect(findChild(treemap, 'package:input/input.dart'), isNotNull);
} else {
expect(childrenNames(findChild(treemap, 'package:input')),
- equals({'<self>', 'main.dart', 'input.dart'}));
+ equals({'main.dart', 'input.dart'}));
}
});
});
diff --git a/pkg/vm_snapshot_analysis/test/utils.dart b/pkg/vm_snapshot_analysis/test/utils.dart
index 2531279..acdf42f 100644
--- a/pkg/vm_snapshot_analysis/test/utils.dart
+++ b/pkg/vm_snapshot_analysis/test/utils.dart
@@ -46,7 +46,7 @@
'-o',
outputBinary,
'--packages=$packages',
- '--extra-gen-snapshot-options=$flag=$sizesJson',
+ '--extra-gen-snapshot-options=--dwarf-stack-traces,$flag=$sizesJson',
mainDart,
]);
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index 000855d..661dfaf 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -544,15 +544,23 @@
result = Dart_SetDeferredLoadHandler(Loader::DeferredLoadHandler);
CHECK_RESULT(result);
+ int vm_service_server_port = INVALID_VM_SERVICE_SERVER_PORT;
+ if (Options::disable_dart_dev()) {
+ vm_service_server_port = Options::vm_service_server_port();
+ } else if (Options::vm_service_server_port() !=
+ INVALID_VM_SERVICE_SERVER_PORT) {
+ vm_service_server_port = 0;
+ }
+
// Load embedder specific bits and return.
if (!VmService::Setup(
- Options::vm_service_server_ip(), Options::vm_service_server_port(),
- Options::vm_service_dev_mode(), Options::vm_service_auth_disabled(),
+ Options::disable_dart_dev() ? Options::vm_service_server_ip()
+ : DEFAULT_VM_SERVICE_SERVER_IP,
+ vm_service_server_port, Options::vm_service_dev_mode(),
+ Options::vm_service_auth_disabled(),
Options::vm_write_service_info_filename(), Options::trace_loading(),
Options::deterministic(), Options::enable_service_port_fallback(),
- // TODO(bkonyi): uncomment when DDS is re-enabled.
- // See https://github.com/flutter/flutter/issues/62507
- /*!Options::disable_dart_dev()*/ false)) {
+ !Options::disable_dart_dev())) {
*error = Utils::StrDup(VmService::GetErrorMessage());
return NULL;
}
diff --git a/runtime/bin/main_options.cc b/runtime/bin/main_options.cc
index 8fa4f79..f1d8649 100644
--- a/runtime/bin/main_options.cc
+++ b/runtime/bin/main_options.cc
@@ -284,10 +284,6 @@
return true;
}
-static const char* DEFAULT_VM_SERVICE_SERVER_IP = "localhost";
-static const int DEFAULT_VM_SERVICE_SERVER_PORT = 8181;
-static const int INVALID_VM_SERVICE_SERVER_PORT = -1;
-
const char* Options::vm_service_server_ip_ = DEFAULT_VM_SERVICE_SERVER_IP;
int Options::vm_service_server_port_ = INVALID_VM_SERVICE_SERVER_PORT;
bool Options::ProcessEnableVmServiceOption(const char* arg,
@@ -605,7 +601,15 @@
}
if (!Options::disable_dart_dev() && enable_vm_service_) {
- dart_options->AddArgument("--launch-dds");
+ const char* dds_format_str = "--launch-dds=%s:%d";
+ size_t size = snprintf(nullptr, 0, dds_format_str, vm_service_server_ip(),
+ vm_service_server_port());
+ // Make room for '\0'.
+ ++size;
+ char* dds_uri = new char[size];
+ snprintf(dds_uri, size, dds_format_str, vm_service_server_ip(),
+ vm_service_server_port());
+ dart_options->AddArgument(dds_uri);
}
// Verify consistency of arguments.
diff --git a/runtime/bin/main_options.h b/runtime/bin/main_options.h
index 76c50be..48553df 100644
--- a/runtime/bin/main_options.h
+++ b/runtime/bin/main_options.h
@@ -79,6 +79,10 @@
kAppJIT,
};
+static const char* DEFAULT_VM_SERVICE_SERVER_IP = "localhost";
+static const int DEFAULT_VM_SERVICE_SERVER_PORT = 8181;
+static const int INVALID_VM_SERVICE_SERVER_PORT = -1;
+
class Options {
public:
static int ParseArguments(int argc,
diff --git a/runtime/observatory/tests/service/client_name_rpc_test.dart b/runtime/observatory/tests/service/client_name_rpc_test.dart
index 92aa4c9..8f81da0 100644
--- a/runtime/observatory/tests/service/client_name_rpc_test.dart
+++ b/runtime/observatory/tests/service/client_name_rpc_test.dart
@@ -66,4 +66,5 @@
main(args) async => runVMTests(
args,
tests,
+ enableService: false,
);
diff --git a/runtime/observatory/tests/service/client_resume_approvals_approve_then_disconnect_test.dart b/runtime/observatory/tests/service/client_resume_approvals_approve_then_disconnect_test.dart
index 439f170..28715a4 100644
--- a/runtime/observatory/tests/service/client_resume_approvals_approve_then_disconnect_test.dart
+++ b/runtime/observatory/tests/service/client_resume_approvals_approve_then_disconnect_test.dart
@@ -66,4 +66,5 @@
testeeConcurrent: fooBar,
pause_on_start: true,
pause_on_exit: true,
+ enableService: false,
);
diff --git a/runtime/observatory/tests/service/client_resume_approvals_disconnect_test.dart b/runtime/observatory/tests/service/client_resume_approvals_disconnect_test.dart
index d82317a..1ef5273 100644
--- a/runtime/observatory/tests/service/client_resume_approvals_disconnect_test.dart
+++ b/runtime/observatory/tests/service/client_resume_approvals_disconnect_test.dart
@@ -64,4 +64,5 @@
testeeConcurrent: fooBar,
pause_on_start: true,
pause_on_exit: true,
+ enableService: false,
);
diff --git a/runtime/observatory/tests/service/client_resume_approvals_identical_names_test.dart b/runtime/observatory/tests/service/client_resume_approvals_identical_names_test.dart
index dbcc14a..06df948 100644
--- a/runtime/observatory/tests/service/client_resume_approvals_identical_names_test.dart
+++ b/runtime/observatory/tests/service/client_resume_approvals_identical_names_test.dart
@@ -46,4 +46,5 @@
testeeConcurrent: fooBar,
pause_on_start: true,
pause_on_exit: true,
+ enableService: false,
);
diff --git a/runtime/observatory/tests/service/client_resume_approvals_multiple_names_test.dart b/runtime/observatory/tests/service/client_resume_approvals_multiple_names_test.dart
index 88d217d..780fe61 100644
--- a/runtime/observatory/tests/service/client_resume_approvals_multiple_names_test.dart
+++ b/runtime/observatory/tests/service/client_resume_approvals_multiple_names_test.dart
@@ -64,4 +64,5 @@
testeeConcurrent: fooBar,
pause_on_start: true,
pause_on_exit: true,
+ enableService: false,
);
diff --git a/runtime/observatory/tests/service/client_resume_approvals_name_change_test.dart b/runtime/observatory/tests/service/client_resume_approvals_name_change_test.dart
index 0e1374e..dac6f2b 100644
--- a/runtime/observatory/tests/service/client_resume_approvals_name_change_test.dart
+++ b/runtime/observatory/tests/service/client_resume_approvals_name_change_test.dart
@@ -57,4 +57,5 @@
testeeConcurrent: fooBar,
pause_on_start: true,
pause_on_exit: true,
+ enableService: false,
);
diff --git a/runtime/observatory/tests/service/client_resume_approvals_reload_test.dart b/runtime/observatory/tests/service/client_resume_approvals_reload_test.dart
index 08fdc10..fcd7e72 100644
--- a/runtime/observatory/tests/service/client_resume_approvals_reload_test.dart
+++ b/runtime/observatory/tests/service/client_resume_approvals_reload_test.dart
@@ -65,4 +65,5 @@
hotReloadTest,
testeeConcurrent: fooBar,
pause_on_start: true,
+ enableService: false,
);
diff --git a/runtime/observatory/tests/service/get_client_name_rpc_test.dart b/runtime/observatory/tests/service/get_client_name_rpc_test.dart
index 25b7828..e9f6ae3 100644
--- a/runtime/observatory/tests/service/get_client_name_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_client_name_rpc_test.dart
@@ -41,4 +41,5 @@
args,
test,
testeeBefore: fooBar,
+ enableService: false,
);
diff --git a/runtime/observatory/tests/service/get_version_rpc_test.dart b/runtime/observatory/tests/service/get_version_rpc_test.dart
index 37c147a..7ee46a0 100644
--- a/runtime/observatory/tests/service/get_version_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_version_rpc_test.dart
@@ -11,8 +11,8 @@
(VM vm) async {
var result = await vm.invokeRpcNoUpgrade('getVersion', {});
expect(result['type'], equals('Version'));
- expect(result['major'], equals(3));
- expect(result['minor'], equals(38));
+ expect(result['major'], equals(4));
+ expect(result['minor'], equals(0));
expect(result['_privateMajor'], equals(0));
expect(result['_privateMinor'], equals(0));
},
diff --git a/runtime/observatory/tests/service/vm_service_dds_test.dart b/runtime/observatory/tests/service/vm_service_dds_test.dart
index c17cc6f..d2f2922 100644
--- a/runtime/observatory/tests/service/vm_service_dds_test.dart
+++ b/runtime/observatory/tests/service/vm_service_dds_test.dart
@@ -12,7 +12,7 @@
(VM vm, DartDevelopmentService dds) async {
final client = WebSocketVM(
WebSocketVMTarget(
- dds.remoteVmServiceWsUri.toString(),
+ dds.wsUri.toString(),
),
);
final result = await client.invokeRpcNoUpgrade('getSupportedProtocols', {});
diff --git a/runtime/vm/clustered_snapshot.cc b/runtime/vm/clustered_snapshot.cc
index 955226e..0040724 100644
--- a/runtime/vm/clustered_snapshot.cc
+++ b/runtime/vm/clustered_snapshot.cc
@@ -5553,9 +5553,15 @@
name = str.ToCString();
}
- TraceStartWritingObject(type, obj, name);
+ // CreateArtificalNodeIfNeeded might call TraceStartWritingObject
+ // and these calls don't nest, so we need to call this outside
+ // of the tracing scope created below.
if (owner != nullptr) {
CreateArtificalNodeIfNeeded(owner);
+ }
+
+ TraceStartWritingObject(type, obj, name);
+ if (owner != nullptr) {
AttributePropertyRef(owner, owner_ref_name,
/*permit_artificial_ref=*/true);
}
diff --git a/runtime/vm/service.h b/runtime/vm/service.h
index 896c695..b4f7acd 100644
--- a/runtime/vm/service.h
+++ b/runtime/vm/service.h
@@ -14,8 +14,8 @@
namespace dart {
-#define SERVICE_PROTOCOL_MAJOR_VERSION 3
-#define SERVICE_PROTOCOL_MINOR_VERSION 38
+#define SERVICE_PROTOCOL_MAJOR_VERSION 4
+#define SERVICE_PROTOCOL_MINOR_VERSION 0
class Array;
class EmbedderServiceHandler;
diff --git a/runtime/vm/service/service.md b/runtime/vm/service/service.md
index 4ba84da..5eeb755 100644
--- a/runtime/vm/service/service.md
+++ b/runtime/vm/service/service.md
@@ -1,8 +1,8 @@
-# Dart VM Service Protocol 3.38
+# Dart VM Service Protocol 4.0
> Please post feedback to the [observatory-discuss group][discuss-list]
-This document describes of _version 3.38_ of the Dart VM Service Protocol. This
+This document describes of _version 4.0_ of the Dart VM Service Protocol. This
protocol is used to communicate with a running Dart Virtual Machine.
To use the Service Protocol, start the VM with the *--observe* flag.
@@ -39,7 +39,6 @@
- [evaluate](#evaluate)
- [evaluateInFrame](#evaluateinframe)
- [getAllocationProfile](#getallocationprofile)
- - [getClientName](#getclientname)
- [getCpuSamples](#getcpusamples)
- [getFlagList](#getflaglist)
- [getInstances](#getinstances)
@@ -59,16 +58,13 @@
- [getVMTimeline](#getvmtimeline)
- [getVMTimelineFlags](#getvmtimelineflags)
- [getVMTimelineMicros](#getvmtimelinemicros)
- - [getWebSocketTarget](#getwebsockettarget)
- [invoke](#invoke)
- [pause](#pause)
- [kill](#kill)
- [registerService](#registerService)
- [reloadSources](#reloadsources)
- [removeBreakpoint](#removebreakpoint)
- - [requirePermissionToResume](#requirepermissiontoresume)
- [resume](#resume)
- - [setClientName](#setclientname)
- [setExceptionPauseMode](#setexceptionpausemode)
- [setFlag](#setflag)
- [setLibraryDebuggable](#setlibrarydebuggable)
@@ -743,21 +739,6 @@
See [ClassList](#classlist).
-### getClientName
-
-_**Note**: This method is deprecated and will be removed in v4.0 of the protocol.
-An equivalent can be found in the Dart Development Service (DDS) protocol._
-
-```
-ClientName getClientName()
-```
-
-The _getClientName_ RPC is used to retrieve the name associated with the currently
-connected VM service client. If no name was previously set through the
-[setClientName](#setclientname) RPC, a default name will be returned.
-
-See [ClientName](#clientname).
-
### getCpuSamples
```
@@ -1144,17 +1125,6 @@
See [Timestamp](#timestamp) and [getVMTimeline](#getvmtimeline).
-### getWebSocketTarget
-
-```
-WebSocketTarget getWebSocketTarget()
-```
-
-The _getWebSocketTarget_ RPC returns the web socket URI that should be used by VM service clients
-with WebSocket implementations that do not follow redirects (e.g., `dart:html`'s [WebSocket](https://api.dart.dev/dart-html/WebSocket-class.html)).
-
-See [WebSocketTarget](#websockettarget).
-
### pause
```
@@ -1260,44 +1230,6 @@
If _isolateId_ refers to an isolate which has exited, then the
_Collected_ [Sentinel](#sentinel) is returned.
-### requirePermissionToResume
-
-_**Note**: This method is deprecated and will be removed in v4.0 of the protocol.
-An equivalent can be found in the Dart Development Service (DDS) protocol._
-
-```
-Success requirePermissionToResume(bool onPauseStart [optional],
- bool onPauseReload[optional],
- bool onPauseExit [optional])
-```
-
-The _requirePermissionToResume_ RPC is used to change the pause/resume behavior
-of isolates by providing a way for the VM service to wait for approval to resume
-from some set of clients. This is useful for clients which want to perform some
-operation on an isolate after a pause without it being resumed by another client.
-
-If the _onPauseStart_ parameter is `true`, isolates will not resume after pausing
-on start until the client sends a `resume` request and all other clients which
-need to provide resume approval for this pause type have done so.
-
-If the _onPauseReload_ parameter is `true`, isolates will not resume after pausing
-after a reload until the client sends a `resume` request and all other clients
-which need to provide resume approval for this pause type have done so.
-
-If the _onPauseExit_ parameter is `true`, isolates will not resume after pausing
-on exit until the client sends a `resume` request and all other clients which
-need to provide resume approval for this pause type have done so.
-
-**Important Notes:**
-
-- All clients with the same client name share resume permissions. Only a
- single client of a given name is required to provide resume approval.
-- When a client requiring approval disconnects from the service, a paused
- isolate may resume if all other clients requiring resume approval have
- already given approval. In the case that no other client requires resume
- approval for the current pause event, the isolate will be resumed if at
- least one other client has attempted to [resume](#resume) the isolate.
-
### resume
```
@@ -1332,22 +1264,6 @@
See [Success](#success), [StepOption](#StepOption).
-### setClientName
-
-_**Note**: This method is deprecated and will be removed in v4.0 of the protocol.
-An equivalent can be found in the Dart Development Service (DDS) protocol._
-
-```
-Success setClientName(string name)
-```
-
-The _setClientName_ RPC is used to set a name to be associated with the currently
-connected VM service client. If the _name_ parameter is a non-empty string, _name_
-will become the new name associated with the client. If _name_ is an empty string,
-the client's name will be reset to its default name.
-
-See [Success](#success).
-
### setExceptionPauseMode
```
@@ -1783,20 +1699,6 @@
}
```
-### ClientName
-
-_**Note**: This class is deprecated and will be removed in v4.0 of the protocol.
-An equivalent can be found in the Dart Development Service (DDS) protocol._
-
-```
-class ClientName extends Response {
- // The name of the currently connected VM service client.
- string name;
-}
-```
-
-See [getClientName](#getclientname) and [setClientName](#setclientname).
-
### Code
```
@@ -3887,17 +3789,6 @@
}
```
-### WebSocketTarget
-
-```
-class WebSocketTarget extends Response {
- // The web socket URI that should be used to connect to the service.
- string uri;
-}
-```
-
-See [getWebSocketTarget](#getwebsockettarget)
-
## Revision History
version | comments
@@ -3935,15 +3826,14 @@
3.28 | TODO(aam): document changes from 3.28
3.29 | Add `getClientName`, `setClientName`, `requireResumeApproval`
3.30 | Updated return types of RPCs which require an `isolateId` to allow for `Sentinel` results if the target isolate has shutdown.
-3.31 | Added single client mode, which allows for the Dart Development Service (DDS) to become the sole client of
-the VM service.
+3.31 | Added single client mode, which allows for the Dart Development Service (DDS) to become the sole client of the VM service.
3.32 | Added `getClassList` RPC and `ClassList` object.
3.33 | Added deprecation notice for `getClientName`, `setClientName`, `requireResumeApproval`, and `ClientName`. These RPCs are moving to the DDS protocol and will be removed in v4.0 of the VM service protocol.
3.34 | Added `TimelineStreamSubscriptionsUpdate` event which is sent when `setVMTimelineFlags` is invoked.
3.35 | Added `getSupportedProtocols` RPC and `ProtocolList`, `Protocol` objects.
3.36 | Added `getProcessMemoryUsage` RPC and `ProcessMemoryUsage` and `ProcessMemoryItem` objects.
3.37 | Added `getWebSocketTarget` RPC and `WebSocketTarget` object.
-3.38 | Added `isSystemIsolate` property to `@Isolate` and `Isolate`, `isSystemIsolateGroup` property to `@IsolateGroup` and `IsolateGroup`,
-and properties `systemIsolates` and `systemIsolateGroups` to `VM`.
+3.38 | Added `isSystemIsolate` property to `@Isolate` and `Isolate`, `isSystemIsolateGroup` property to `@IsolateGroup` and `IsolateGroup`, and properties `systemIsolates` and `systemIsolateGroups` to `VM`.
+4.0 | Removed the following deprecated RPCs and objects: `getClientName`, `getWebSocketTarget`, `setClientName`, `requireResumeApproval`, `ClientName`, and `WebSocketTarget`.
[discuss-list]: https://groups.google.com/a/dartlang.org/forum/#!forum/observatory-discuss
diff --git a/runtime/vm/service_event.cc b/runtime/vm/service_event.cc
index 5b90440..18e06f9 100644
--- a/runtime/vm/service_event.cc
+++ b/runtime/vm/service_event.cc
@@ -184,9 +184,6 @@
if (kind() == kVMFlagUpdate) {
jsobj.AddProperty("flag", flag_name());
// For backwards compatibility, "new_value" is also provided.
- // TODO(bkonyi): remove when service protocol major version is incremented.
- ASSERT(SERVICE_PROTOCOL_MAJOR_VERSION == 3);
- jsobj.AddProperty("new_value", flag_new_value());
jsobj.AddProperty("newValue", flag_new_value());
}
if (kind() == kIsolateReload) {
diff --git a/sdk/lib/_internal/vm/bin/vmservice_io.dart b/sdk/lib/_internal/vm/bin/vmservice_io.dart
index 329e505..d1f8a5d 100644
--- a/sdk/lib/_internal/vm/bin/vmservice_io.dart
+++ b/sdk/lib/_internal/vm/bin/vmservice_io.dart
@@ -81,11 +81,20 @@
}
Future<void> ddsConnectedCallback() async {
+ final serviceAddress = server!.serverAddress.toString();
+ _notifyServerState(serviceAddress);
+ onServerAddressChange(serviceAddress);
if (_waitForDdsToAdvertiseService) {
await server!.outputConnectionInformation();
}
}
+Future<void> ddsDisconnectedCallback() async {
+ final serviceAddress = server!.serverAddress.toString();
+ _notifyServerState(serviceAddress);
+ onServerAddressChange(serviceAddress);
+}
+
Future<Uri> createTempDirCallback(String base) async {
final temp = await Directory.systemTemp.createTemp(base);
// Underneath the temporary directory, create a directory with the
@@ -257,6 +266,7 @@
VMServiceEmbedderHooks.cleanup = cleanupCallback;
VMServiceEmbedderHooks.createTempDir = createTempDirCallback;
VMServiceEmbedderHooks.ddsConnected = ddsConnectedCallback;
+ VMServiceEmbedderHooks.ddsDisconnected = ddsDisconnectedCallback;
VMServiceEmbedderHooks.deleteDir = deleteDirCallback;
VMServiceEmbedderHooks.writeFile = writeFileCallback;
VMServiceEmbedderHooks.writeStreamFile = writeStreamFileCallback;
diff --git a/sdk/lib/_internal/vm/bin/vmservice_server.dart b/sdk/lib/_internal/vm/bin/vmservice_server.dart
index f084f29..383b19b 100644
--- a/sdk/lib/_internal/vm/bin/vmservice_server.dart
+++ b/sdk/lib/_internal/vm/bin/vmservice_server.dart
@@ -158,9 +158,14 @@
/// Returns the server address including the auth token.
Uri? get serverAddress {
- if (!running) {
+ if (!running || _service.isExiting) {
return null;
}
+ // If DDS is connected it should be treated as the "true" VM service and be
+ // advertised as such.
+ if (_service.ddsUri != null) {
+ return _service.ddsUri;
+ }
final server = _server!;
final ip = server.address.address;
final port = server.port;
@@ -364,32 +369,11 @@
WebSocketClient(webSocket, _service);
});
} else {
- // Forward the websocket connection request to DDS.
- // The Javascript WebSocket implementation doesn't like websocket
- // connection requests being redirected. Instead of redirecting, we'll
- // just forward the connection manually if 'implicit-redirect' is
- // provided as a protocol.
- if (subprotocols != null) {
- if (subprotocols.contains('implicit-redirect')) {
- WebSocketTransformer.upgrade(request,
- protocolSelector: (_) => 'implicit-redirect',
- compression: CompressionOptions.compressionOff)
- .then((WebSocket webSocket) async {
- final ddsWs = await WebSocket.connect(
- _service.ddsUri!.replace(scheme: 'ws').toString());
- ddsWs.addStream(webSocket);
- webSocket.addStream(ddsWs);
- webSocket.done.then((_) {
- ddsWs.close();
- });
- ddsWs.done.then((_) {
- webSocket.close();
- });
- });
- return;
- }
- }
- request.response.redirect(_service.ddsUri!);
+ request.response.statusCode = HttpStatus.forbidden;
+ request.response.write('Cannot connect directly to the VM service as '
+ 'a Dart Development Service (DDS) instance has taken control and '
+ 'can be found at ${_service.ddsUri}.');
+ request.response.close();
}
return;
}
diff --git a/sdk/lib/vmservice/running_isolate.dart b/sdk/lib/vmservice/running_isolate.dart
index 029c6aa..8a6dd36 100644
--- a/sdk/lib/vmservice/running_isolate.dart
+++ b/sdk/lib/vmservice/running_isolate.dart
@@ -8,122 +8,13 @@
final int portId;
final SendPort sendPort;
final String name;
- final Set<String> _resumeApprovalsByName = {};
RunningIsolate(this.portId, this.sendPort, this.name);
String get serviceId => 'isolates/$portId';
- static const kInvalidPauseEvent = -1;
- static const kPauseOnStartMask = 1 << 0;
- static const kPauseOnReloadMask = 1 << 1;
- static const kPauseOnExitMask = 1 << 2;
- static const kDefaultResumePermissionMask =
- kPauseOnStartMask | kPauseOnReloadMask | kPauseOnExitMask;
-
- /// Resumes the isolate if all clients which need to approve a resume have
- /// done so. Called when the last client of a given name disconnects or
- /// changes name to ensure we don't deadlock waiting for approval to resume
- /// from a disconnected client.
- Future<void> maybeResumeAfterClientChange(
- VMService service, String disconnectedClientName) async {
- // Remove approvals from the disconnected client.
- _resumeApprovalsByName.remove(disconnectedClientName);
-
- // If we've received approval to resume from all clients who care, clear
- // approval state and resume.
- var pauseType;
- try {
- pauseType = await _isolatePauseType(service, portId.toString());
- } catch (_errorResponse) {
- // ignore errors when attempting to retrieve isolate pause type
- return;
- }
- if (pauseType != kInvalidPauseEvent &&
- _shouldResume(service, null, pauseType)) {
- _resumeApprovalsByName.clear();
- await Message.forMethod('resume')
- ..params.addAll({
- 'isolateId': portId,
- })
- ..sendToIsolate(sendPort);
- }
- }
-
- bool _shouldResume(VMService service, Client? client, int pauseType) {
- if (client != null) {
- // Mark the approval by the client.
- _resumeApprovalsByName.add(client.name);
- }
- final requiredClientApprovals = <String>{};
- final permissions = service.clientResumePermissions;
-
- // Determine which clients require approval for this pause type.
- permissions.forEach((name, clientNamePermissions) {
- if (clientNamePermissions.permissionsMask & pauseType != 0) {
- requiredClientApprovals.add(name);
- }
- });
-
- // We require at least a single client to resume, even if that client
- // doesn't require resume approval.
- if (_resumeApprovalsByName.isEmpty) {
- return false;
- }
-
- // If all the required approvals are present, we should resume.
- return _resumeApprovalsByName.containsAll(requiredClientApprovals);
- }
-
- Future<int> _isolatePauseType(VMService service, String isolateId) async {
- final getIsolateMessage = Message.forMethod('getIsolate')
- ..params.addAll({
- 'isolateId': isolateId,
- });
- final Response result = await routeRequest(service, getIsolateMessage);
- final resultJson = result.decodeJson();
- if (resultJson['result'] == null ||
- resultJson['result']['pauseEvent'] == null) {
- // Failed to send getIsolate message(due to isolate being de-registered
- // for example).
- throw result;
- }
- final pauseEvent = resultJson['result']['pauseEvent'];
- const pauseEvents = <String, int>{
- 'PauseStart': kPauseOnStartMask,
- 'PausePostRequest': kPauseOnReloadMask,
- 'PauseExit': kPauseOnExitMask,
- };
- final kind = pauseEvent['kind'];
- return pauseEvents[kind] ?? kInvalidPauseEvent;
- }
-
- Future<Response> _routeResumeRequest(
- VMService service, Message message) async {
- // If we've received approval to resume from all clients who care, clear
- // approval state and resume.
- var pauseType;
- try {
- pauseType = await _isolatePauseType(service, message.params['isolateId']);
- } on Response catch (errorResponse) {
- return errorResponse;
- }
- if (pauseType == kInvalidPauseEvent ||
- _shouldResume(service, message.client, pauseType)) {
- _resumeApprovalsByName.clear();
- return message.sendToIsolate(sendPort);
- }
-
- // We're still awaiting some approvals. Simply return success, but don't
- // resume yet.
- return Response(ResponsePayloadKind.String, encodeSuccess(message));
- }
-
@override
Future<Response> routeRequest(VMService service, Message message) {
- if (message.method == 'resume') {
- return _routeResumeRequest(service, message);
- }
// Send message to isolate.
return message.sendToIsolate(sendPort);
}
diff --git a/sdk/lib/vmservice/vmservice.dart b/sdk/lib/vmservice/vmservice.dart
index 1581e70..e0ccfaa 100644
--- a/sdk/lib/vmservice/vmservice.dart
+++ b/sdk/lib/vmservice/vmservice.dart
@@ -142,6 +142,9 @@
/// Called when DDS has connected.
typedef Future<void> DdsConnectedCallback();
+/// Called when DDS has disconnected.
+typedef Future<void> DdsDisconnectedCallback();
+
/// Called when the service is exiting.
typedef Future CleanupCallback();
@@ -182,6 +185,7 @@
static ServerStartCallback? serverStart;
static ServerStopCallback? serverStop;
static DdsConnectedCallback? ddsConnected;
+ static DdsDisconnectedCallback? ddsDisconnected;
static CleanupCallback? cleanup;
static CreateTempDirCallback? createTempDir;
static DeleteDirCallback? deleteDir;
@@ -224,8 +228,6 @@
final devfs = DevFS();
- Uri? vmServiceUri;
-
Uri? get ddsUri => _ddsUri;
Uri? _ddsUri;
@@ -254,117 +256,6 @@
return encodeSuccess(message);
}
- void _clearClientName(Client client) {
- final name = client.name;
- client.name = null;
- final clientsForName = clientResumePermissions[name];
- if (clientsForName != null) {
- clientsForName.clients.remove(client);
- // If this was the last client with a given name, cleanup resume
- // permissions.
- if (clientsForName.clients.isEmpty) {
- clientResumePermissions.remove(name);
-
- // Check to see if we need to resume any isolates now that the last
- // client of a given name has disconnected or changed names.
- //
- // An isolate will be resumed in this situation if:
- //
- // 1) This client required resume approvals for the current pause event
- // associated with the isolate and all other required resume approvals
- // have been provided by other clients.
- //
- // OR
- //
- // 2) This client required resume approvals for the current pause event
- // associated with the isolate, no other clients require resume approvals
- // for the current pause event, and at least one client has issued a resume
- // request.
- runningIsolates.isolates.forEach((_, isolate) async =>
- await isolate.maybeResumeAfterClientChange(this, name));
- }
- }
- }
-
- /// Sets the name associated with a [Client].
- ///
- /// If any resume approvals were set for this client previously they will
- /// need to be reset after a name change.
- String _setClientName(Message message) {
- final client = message.client!;
- if (!message.params.containsKey('name')) {
- return encodeRpcError(message, kInvalidParams,
- details: "setClientName: missing required parameter 'name'");
- }
- final name = message.params['name'];
- if (name is! String) {
- return encodeRpcError(message, kInvalidParams,
- details: "setClientName: invalid 'name' parameter: $name");
- }
- _setClientNameHelper(client, name);
- return encodeSuccess(message);
- }
-
- void _setClientNameHelper(Client client, String name) {
- _clearClientName(client);
- name = name.isEmpty ? client.defaultClientName : name;
- client.name = name;
- clientResumePermissions.putIfAbsent(
- client.name, () => _ClientResumePermissions());
- clientResumePermissions[name]!.clients.add(client);
- }
-
- String _getClientName(Message message) => encodeResult(message, {
- 'type': 'ClientName',
- 'name': message.client!.name,
- });
-
- String _requirePermissionToResume(Message message) {
- bool parsePermission(String argName) {
- final arg = message.params[argName];
- if (arg == null) {
- return false;
- }
- if (arg is! bool) {
- throw encodeRpcError(message, kInvalidParams,
- details: "requirePermissionToResume: invalid '$argName': $arg");
- }
- return arg;
- }
-
- final client = message.client!;
- int pauseTypeMask = 0;
- try {
- if (parsePermission('onPauseStart')) {
- pauseTypeMask |= RunningIsolate.kPauseOnStartMask;
- }
- if (parsePermission('onPauseReload')) {
- pauseTypeMask |= RunningIsolate.kPauseOnReloadMask;
- }
- if (parsePermission('onPauseExit')) {
- pauseTypeMask |= RunningIsolate.kPauseOnExitMask;
- }
- } on dynamic catch (rpcError) {
- return rpcError;
- }
-
- clientResumePermissions[client.name]!.permissionsMask = pauseTypeMask;
- return encodeSuccess(message);
- }
-
- String _getWebSocketTarget(Message message) {
- Uri uri = ((_ddsUri != null) ? _ddsUri : vmServiceUri)!;
- uri = uri.replace(scheme: 'ws', pathSegments: [
- // Strip empty path segment which causes an extra / to be inserted.
- ...uri.pathSegments.where((e) => e.isNotEmpty),
- 'ws',
- ]);
- return encodeResult(message, {
- 'type': 'WebSocketTarget',
- 'uri': uri.toString(),
- });
- }
-
void _addClient(Client client) {
assert(client.streams.isEmpty);
assert(client.services.isEmpty);
@@ -380,9 +271,6 @@
}
}
- // Clean up client approvals state.
- _clearClientName(client);
-
for (final service in client.services.keys) {
_eventMessageHandler(
'Service',
@@ -411,8 +299,9 @@
final acceptNewWebSocketConnections =
VMServiceEmbedderHooks.acceptNewWebSocketConnections;
if (_ddsUri != null && acceptNewWebSocketConnections != null) {
- acceptNewWebSocketConnections(true);
_ddsUri = null;
+ VMServiceEmbedderHooks.ddsDisconnected!();
+ acceptNewWebSocketConnections(true);
}
}
}
@@ -581,11 +470,9 @@
}
Client? _findFirstClientThatHandlesService(String service) {
- if (clients != null) {
- for (Client c in clients) {
- if (c.services.containsKey(service)) {
- return c;
- }
+ for (Client c in clients) {
+ if (c.services.containsKey(service)) {
+ return c;
}
}
return null;
@@ -707,22 +594,20 @@
final namespace = _getNamespace(message.method!);
final method = _getMethod(message.method!);
final client = clients[namespace];
- if (client != null) {
- if (client.services.containsKey(method)) {
- final id = _serviceRequests.newId();
- final oldId = message.serial;
- final completer = Completer<String>();
- client.serviceHandles[id] = (Message? m) {
- if (m != null) {
- completer.complete(json.encode(m.forwardToJson({'id': oldId})));
- } else {
- completer.complete(encodeRpcError(message, kServiceDisappeared));
- }
- };
- client.post(
- Response.json(message.forwardToJson({'id': id, 'method': method})));
- return completer.future;
- }
+ if (client.services.containsKey(method)) {
+ final id = _serviceRequests.newId();
+ final oldId = message.serial;
+ final completer = Completer<String>();
+ client.serviceHandles[id] = (Message? m) {
+ if (m != null) {
+ completer.complete(json.encode(m.forwardToJson({'id': oldId})));
+ } else {
+ completer.complete(encodeRpcError(message, kServiceDisappeared));
+ }
+ };
+ client.post(
+ Response.json(message.forwardToJson({'id': id, 'method': method})));
+ return completer.future;
}
return encodeRpcError(message, kMethodNotFound,
details: 'Unknown service: ${message.method}');
@@ -774,21 +659,9 @@
if (message.method == 'registerService') {
return await _registerService(message);
}
- if (message.method == 'setClientName') {
- return _setClientName(message);
- }
- if (message.method == 'getClientName') {
- return _getClientName(message);
- }
- if (message.method == 'requirePermissionToResume') {
- return _requirePermissionToResume(message);
- }
if (message.method == 'getSupportedProtocols') {
return await _getSupportedProtocols(message);
}
- if (message.method == 'getWebSocketTarget') {
- return _getWebSocketTarget(message);
- }
if (devfs.shouldHandleMessage(message)) {
return await devfs.handleMessage(message);
}
@@ -834,7 +707,6 @@
/// Notify the VM that the server's address has changed.
void onServerAddressChange(String? address) {
- VMService().vmServiceUri = (address != null) ? Uri.parse(address) : null;
_onServerAddressChange(address);
}
diff --git a/tools/VERSION b/tools/VERSION
index f93499e..be4759b 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 10
PATCH 0
-PRERELEASE 94
+PRERELEASE 95
PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/spec_parser/Dart.g b/tools/spec_parser/Dart.g
index 039e65f..08a433e 100644
--- a/tools/spec_parser/Dart.g
+++ b/tools/spec_parser/Dart.g
@@ -493,12 +493,17 @@
| SUPER unconditionalAssignableSelector
| constObjectExpression
| newExpression
+ | constructorInvocation
| functionPrimary
| '(' expression ')'
| literal
| identifier
;
+constructorInvocation
+ : typeName typeArguments '.' identifier arguments
+ ;
+
literal
: nullLiteral
| booleanLiteral
@@ -812,14 +817,9 @@
postfixExpression
: assignableExpression postfixOperator
- | constructorInvocation selector*
| primary selector*
;
-constructorInvocation
- : typeName typeArguments '.' identifier arguments
- ;
-
postfixOperator
: incrementOperator
;
@@ -841,7 +841,6 @@
assignableExpression
: SUPER unconditionalAssignableSelector
- | constructorInvocation assignableSelectorPart
| primary assignableSelectorPart
| identifier
;