Version 2.12.0-208.0.dev
Merge commit '8c2ab1d04f747d990fd9f97a29cc90e805bc086b' into 'dev'
diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json
index 9b2a9f2..3e6b7cb 100644
--- a/.dart_tool/package_config.json
+++ b/.dart_tool/package_config.json
@@ -722,7 +722,7 @@
"name": "vm_service",
"rootUri": "../pkg/vm_service",
"packageUri": "lib/",
- "languageVersion": "2.6"
+ "languageVersion": "2.12"
},
{
"name": "vm_snapshot_analysis",
diff --git a/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart b/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
index 2ef2bf1..d5be3ee 100644
--- a/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
@@ -12,7 +12,7 @@
///
/// Changing this value to `true` will cause some dead code warnings to appear
/// for code that only exists to support the old behavior.
-const bool allowLocalBooleanVarsToPromoteByDefault = false;
+const bool allowLocalBooleanVarsToPromoteByDefault = true;
/// [AssignedVariables] is a helper class capable of computing the set of
/// variables that are potentially written to, and potentially captured by
diff --git a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
index 896fd20..5e2ac34 100644
--- a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
@@ -5937,39 +5937,6 @@
tip: r"""Try replacing them with normal or optional parameters.""");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-const Template<
- Message Function(
- String name,
- String name2,
- String
- string3)> templateJsInteropNativeClassInAnnotation = const Template<
- Message Function(String name, String name2, String string3)>(
- messageTemplate:
- r"""JS interop class '#name' conflicts with natively supported class '#name2' in '#string3'.""",
- withArguments: _withArgumentsJsInteropNativeClassInAnnotation);
-
-// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-const Code<Message Function(String name, String name2, String string3)>
- codeJsInteropNativeClassInAnnotation =
- const Code<Message Function(String name, String name2, String string3)>(
- "JsInteropNativeClassInAnnotation",
-);
-
-// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-Message _withArgumentsJsInteropNativeClassInAnnotation(
- String name, String name2, String string3) {
- if (name.isEmpty) throw 'No name provided';
- name = demangleMixinApplicationName(name);
- if (name2.isEmpty) throw 'No name provided';
- name2 = demangleMixinApplicationName(name2);
- if (string3.isEmpty) throw 'No string provided';
- return new Message(codeJsInteropNativeClassInAnnotation,
- message:
- """JS interop class '${name}' conflicts with natively supported class '${name2}' in '${string3}'.""",
- arguments: {'name': name, 'name2': name2, 'string3': string3});
-}
-
-// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Null> codeJsInteropNonExternalConstructor =
messageJsInteropNonExternalConstructor;
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart
index f8c1de7..9cb2e59 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart
@@ -3868,194 +3868,6 @@
});
});
- group('restrict', () {
- test('reachability', () {
- var h = Harness();
- var reachable = FlowModel<Var, Type>(Reachability.initial);
- var unreachable = reachable.setUnreachable();
- expect(reachable.restrict(h, reachable, Set()), same(reachable));
- expect(reachable.restrict(h, unreachable, Set()), same(unreachable));
- expect(unreachable.restrict(h, reachable, Set()), same(unreachable));
- expect(unreachable.restrict(h, unreachable, Set()), same(unreachable));
- });
-
- test('assignments', () {
- var h = Harness();
- var a = Var('a', 'int');
- var b = Var('b', 'int');
- var c = Var('c', 'int');
- var d = Var('d', 'int');
- var s0 = FlowModel<Var, Type>(Reachability.initial)
- .declare(a, false)
- .declare(b, false)
- .declare(c, false)
- .declare(d, false);
- var s1 = s0
- .write(a, Type('int'), new SsaNode<Var, Type>(null), h)
- .write(b, Type('int'), new SsaNode<Var, Type>(null), h);
- var s2 = s1
- .write(a, Type('int'), new SsaNode<Var, Type>(null), h)
- .write(c, Type('int'), new SsaNode<Var, Type>(null), h);
- var result = s2.restrict(h, s1, Set());
- expect(result.infoFor(a).assigned, true);
- expect(result.infoFor(b).assigned, true);
- expect(result.infoFor(c).assigned, true);
- expect(result.infoFor(d).assigned, false);
- });
-
- test('write captured', () {
- var h = Harness();
- var a = Var('a', 'int');
- var b = Var('b', 'int');
- var c = Var('c', 'int');
- var d = Var('d', 'int');
- var s0 = FlowModel<Var, Type>(Reachability.initial)
- .declare(a, false)
- .declare(b, false)
- .declare(c, false)
- .declare(d, false);
- // In s1, a and b are write captured. In s2, a and c are.
- var s1 = s0.conservativeJoin([a, b], [a, b]);
- var s2 = s1.conservativeJoin([a, c], [a, c]);
- var result = s2.restrict(h, s1, Set());
- expect(
- result.infoFor(a),
- _matchVariableModel(writeCaptured: true, unassigned: false),
- );
- expect(
- result.infoFor(b),
- _matchVariableModel(writeCaptured: true, unassigned: false),
- );
- expect(
- result.infoFor(c),
- _matchVariableModel(writeCaptured: true, unassigned: false),
- );
- expect(
- result.infoFor(d),
- _matchVariableModel(writeCaptured: false, unassigned: true),
- );
- });
-
- test('promotion', () {
- void _check(String? thisType, String? otherType, bool unsafe,
- List<String>? expectedChain) {
- var h = Harness();
- var x = Var('x', 'Object?');
- var s0 = FlowModel<Var, Type>(Reachability.initial).declare(x, true);
- var s1 = thisType == null
- ? s0
- : s0.tryPromoteForTypeCheck(h, x, Type(thisType)).ifTrue;
- var s2 = otherType == null
- ? s0
- : s0.tryPromoteForTypeCheck(h, x, Type(otherType)).ifTrue;
- var result = s1.restrict(h, s2, unsafe ? [x].toSet() : Set());
- if (expectedChain == null) {
- expect(result.variableInfo, contains(x));
- expect(result.infoFor(x).promotedTypes, isNull);
- } else {
- expect(result.infoFor(x).promotedTypes!.map((t) => t.type).toList(),
- expectedChain);
- }
- }
-
- _check(null, null, false, null);
- _check(null, null, true, null);
- _check('int', null, false, ['int']);
- _check('int', null, true, ['int']);
- _check(null, 'int', false, ['int']);
- _check(null, 'int', true, null);
- _check('int?', 'int', false, ['int']);
- _check('int', 'int?', false, ['int?', 'int']);
- _check('int', 'String', false, ['String']);
- _check('int?', 'int', true, ['int?']);
- _check('int', 'int?', true, ['int']);
- _check('int', 'String', true, ['int']);
- });
-
- test('promotion chains', () {
- // Verify that the given promotion chain matches the expected list of
- // strings.
- void _checkChain(List<Type>? chain, List<String> expected) {
- var strings = (chain ?? <Type>[]).map((t) => t.type).toList();
- expect(strings, expected);
- }
-
- // Test the following scenario:
- // - Prior to the try/finally block, the sequence of promotions in
- // [before] is done.
- // - During the try block, the sequence of promotions in [inTry] is
- // done.
- // - During the finally block, the sequence of promotions in
- // [inFinally] is done.
- // - After calling `restrict` to refine the state from the finally
- // block, the expected promotion chain is [expectedResult].
- void _check(List<String> before, List<String> inTry,
- List<String> inFinally, List<String> expectedResult) {
- var h = Harness();
- var x = Var('x', 'Object?');
- var initialModel =
- FlowModel<Var, Type>(Reachability.initial).declare(x, true);
- for (var t in before) {
- initialModel =
- initialModel.tryPromoteForTypeCheck(h, x, Type(t)).ifTrue;
- }
- _checkChain(initialModel.infoFor(x).promotedTypes, before);
- var tryModel = initialModel;
- for (var t in inTry) {
- tryModel = tryModel.tryPromoteForTypeCheck(h, x, Type(t)).ifTrue;
- }
- var expectedTryChain = before.toList()..addAll(inTry);
- _checkChain(tryModel.infoFor(x).promotedTypes, expectedTryChain);
- var finallyModel = initialModel;
- for (var t in inFinally) {
- finallyModel =
- finallyModel.tryPromoteForTypeCheck(h, x, Type(t)).ifTrue;
- }
- var expectedFinallyChain = before.toList()..addAll(inFinally);
- _checkChain(
- finallyModel.infoFor(x).promotedTypes, expectedFinallyChain);
- var result = finallyModel.restrict(h, tryModel, {});
- _checkChain(result.infoFor(x).promotedTypes, expectedResult);
- // And verify that the inputs are unchanged.
- _checkChain(initialModel.infoFor(x).promotedTypes, before);
- _checkChain(tryModel.infoFor(x).promotedTypes, expectedTryChain);
- _checkChain(
- finallyModel.infoFor(x).promotedTypes, expectedFinallyChain);
- }
-
- _check(['Object'], ['Iterable', 'List'], ['num', 'int'],
- ['Object', 'Iterable', 'List']);
- _check([], ['Iterable', 'List'], ['num', 'int'], ['Iterable', 'List']);
- _check(['Object'], ['Iterable', 'List'], [],
- ['Object', 'Iterable', 'List']);
- _check([], ['Iterable', 'List'], [], ['Iterable', 'List']);
- _check(['Object'], [], ['num', 'int'], ['Object', 'num', 'int']);
- _check([], [], ['num', 'int'], ['num', 'int']);
- _check(['Object'], [], [], ['Object']);
- _check([], [], [], []);
- _check(
- [], ['Object', 'Iterable'], ['num', 'int'], ['Object', 'Iterable']);
- _check([], ['Object'], ['num', 'int'], ['Object', 'num', 'int']);
- _check([], ['num', 'int'], ['Object', 'Iterable'], ['num', 'int']);
- _check([], ['num', 'int'], ['Object'], ['num', 'int']);
- _check([], ['Object', 'int'], ['num'], ['Object', 'int']);
- _check([], ['Object', 'num'], ['int'], ['Object', 'num', 'int']);
- _check([], ['num'], ['Object', 'int'], ['num', 'int']);
- _check([], ['int'], ['Object', 'num'], ['int']);
- });
-
- test('variable present in one state but not the other', () {
- var h = Harness();
- var x = Var('x', 'Object?');
- var s0 = FlowModel<Var, Type>(Reachability.initial);
- var s1 = s0.declare(x, true);
- expect(s0.restrict(h, s1, {}), same(s0));
- expect(s0.restrict(h, s1, {x}), same(s0));
- expect(s1.restrict(h, s0, {}), same(s0));
- expect(s1.restrict(h, s0, {x}), same(s0));
- });
- });
-
group('rebaseForward', () {
test('reachability', () {
var h = Harness();
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/nullability/data/local_boolean.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/nullability/data/local_boolean.dart
new file mode 100644
index 0000000..4c7b408
--- /dev/null
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/nullability/data/local_boolean.dart
@@ -0,0 +1,149 @@
+// 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.
+
+finalLocalBool(int? x) {
+ final bool b = x == null;
+ if (!b) {
+ /*nonNullable*/ x;
+ } else {
+ x;
+ }
+}
+
+localBool(int? x) {
+ bool b = x == null;
+ if (!b) {
+ /*nonNullable*/ x;
+ } else {
+ x;
+ }
+}
+
+localBool_assigned(int? x, bool b1) {
+ bool b2 = b1;
+ b2 = x == null;
+ if (!b2) {
+ /*nonNullable*/ x;
+ } else {
+ x;
+ }
+}
+
+localBool_assignedDynamic(int? x, bool b1) {
+ dynamic b2 = b1;
+ b2 = x == null;
+ if (!b2) {
+ /*nonNullable*/ x;
+ } else {
+ x;
+ }
+}
+
+parameter_assigned(int? x, bool b) {
+ b = x == null;
+ if (!b) {
+ /*nonNullable*/ x;
+ } else {
+ x;
+ }
+}
+
+parameter_assignedDynamic(int? x, dynamic b) {
+ b = x == null;
+ if (!b) {
+ /*nonNullable*/ x;
+ } else {
+ x;
+ }
+}
+
+lateFinalLocalBool(int? x) {
+ late final bool b = x == null;
+ if (!b) {
+ // We don't promote based on the initializers of late locals because we
+ // don't know when they execute.
+ x;
+ } else {
+ x;
+ }
+}
+
+lateLocalBool(int? x) {
+ late bool b = x == null;
+ if (!b) {
+ // We don't promote based on the initializers of late locals because we
+ // don't know when they execute.
+ x;
+ } else {
+ x;
+ }
+}
+
+lateLocalBool_assignedAndInitialized(int? x, bool b1) {
+ late bool b2 = b1;
+ b2 = x == null;
+ if (!b2) {
+ /*nonNullable*/ x;
+ } else {
+ x;
+ }
+}
+
+lateLocalBool_assignedButNotInitialized(int? x) {
+ late bool b;
+ b = x == null;
+ if (!b) {
+ /*nonNullable*/ x;
+ } else {
+ x;
+ }
+}
+
+rebaseWithDemotion(int? x, int? y, int? z, int? a) {
+ x;
+ y;
+ z;
+ if (y == null) return;
+ x;
+ /*nonNullable*/ y;
+ z;
+ bool b = x == null;
+ x;
+ /*nonNullable*/ y;
+ z;
+ if (z == null) return;
+ x;
+ /*nonNullable*/ y;
+ /*nonNullable*/ z;
+ y = a;
+ x;
+ y;
+ /*nonNullable*/ z;
+ if (b) return;
+ /*nonNullable*/ x;
+ y;
+ /*nonNullable*/ z;
+}
+
+compoundAssignment(int? x, dynamic b) {
+ b += x == null;
+ if (!b) {
+ // It's not safe to promote, because there's no guarantee that value of `b`
+ // has anything to do with the result of `x == null`.
+ x;
+ } else {
+ x;
+ }
+}
+
+ifNullAssignment(int? x, dynamic b) {
+ b ??= x == null;
+ if (!b) {
+ // It's not safe to promote, because there's no guarantee that value of `b`
+ // has anything to do with the result of `x == null`.
+ x;
+ } else {
+ x;
+ }
+}
diff --git a/pkg/_js_interop_checks/lib/js_interop_checks.dart b/pkg/_js_interop_checks/lib/js_interop_checks.dart
index 91405e5..8bb8c6d 100644
--- a/pkg/_js_interop_checks/lib/js_interop_checks.dart
+++ b/pkg/_js_interop_checks/lib/js_interop_checks.dart
@@ -17,22 +17,17 @@
messageJsInteropNonExternalConstructor,
messageJsInteropNonExternalMember,
templateJsInteropDartClassExtendsJSClass,
- templateJsInteropJSClassExtendsDartClass,
- templateJsInteropNativeClassInAnnotation;
+ templateJsInteropJSClassExtendsDartClass;
import 'src/js_interop.dart';
class JsInteropChecks extends RecursiveVisitor<void> {
final CoreTypes _coreTypes;
final DiagnosticReporter<Message, LocatedMessage> _diagnosticsReporter;
- final Map<String, Class> _nativeClasses;
bool _classHasJSAnnotation = false;
- bool _classHasAnonymousAnnotation = false;
bool _libraryHasJSAnnotation = false;
- bool _libraryIsGlobalNamespace = false;
- JsInteropChecks(
- this._coreTypes, this._diagnosticsReporter, this._nativeClasses);
+ JsInteropChecks(this._coreTypes, this._diagnosticsReporter);
@override
void defaultMember(Member member) {
@@ -45,7 +40,6 @@
@override
void visitClass(Class cls) {
_classHasJSAnnotation = hasJSInteropAnnotation(cls);
- _classHasAnonymousAnnotation = hasAnonymousAnnotation(cls);
var superclass = cls.superclass;
if (superclass != null && superclass != _coreTypes.objectClass) {
var superHasJSAnnotation = hasJSInteropAnnotation(superclass);
@@ -65,53 +59,14 @@
cls.location.file);
}
}
- if (_classHasJSAnnotation &&
- !_classHasAnonymousAnnotation &&
- _libraryIsGlobalNamespace) {
- var jsClass = getJSName(cls);
- if (jsClass.isEmpty) {
- // No rename, take the name of the class directly.
- jsClass = cls.name;
- } else {
- // Remove any global prefixes. Regex here is greedy and will only return
- // a value for `className` that doesn't start with 'self.' or 'window.'.
- var classRegexp = new RegExp(r'^((self|window)\.)*(?<className>.*)$');
- var matches = classRegexp.allMatches(jsClass);
- jsClass = matches.first.namedGroup('className');
- }
- if (_nativeClasses.containsKey(jsClass)) {
- var nativeClass = _nativeClasses[jsClass];
- _diagnosticsReporter.report(
- templateJsInteropNativeClassInAnnotation.withArguments(
- cls.name,
- nativeClass.name,
- nativeClass.enclosingLibrary.importUri.toString()),
- cls.fileOffset,
- cls.name.length,
- cls.location.file);
- }
- }
super.visitClass(cls);
- _classHasAnonymousAnnotation = false;
_classHasJSAnnotation = false;
}
@override
void visitLibrary(Library lib) {
_libraryHasJSAnnotation = hasJSInteropAnnotation(lib);
- _libraryIsGlobalNamespace = false;
- if (_libraryHasJSAnnotation) {
- var libraryAnnotation = getJSName(lib);
- var globalRegexp = new RegExp(r'^(self|window)(\.(self|window))*$');
- if (libraryAnnotation.isEmpty ||
- globalRegexp.hasMatch(libraryAnnotation)) {
- _libraryIsGlobalNamespace = true;
- }
- } else {
- _libraryIsGlobalNamespace = true;
- }
super.visitLibrary(lib);
- _libraryIsGlobalNamespace = false;
_libraryHasJSAnnotation = false;
}
@@ -143,7 +98,7 @@
}
var isAnonymousFactory =
- _classHasAnonymousAnnotation && procedure.isFactory;
+ isAnonymousClassMember(procedure) && procedure.isFactory;
if (isAnonymousFactory) {
if (procedure.function != null &&
diff --git a/pkg/_js_interop_checks/lib/src/js_interop.dart b/pkg/_js_interop_checks/lib/src/js_interop.dart
index 7831f2d..33ab00b 100644
--- a/pkg/_js_interop_checks/lib/src/js_interop.dart
+++ b/pkg/_js_interop_checks/lib/src/js_interop.dart
@@ -9,48 +9,15 @@
bool hasJSInteropAnnotation(Annotatable a) =>
a.annotations.any(_isPublicJSAnnotation);
-/// Returns true iff the node has an `@anonymous(...)` annotation from
-/// `package:js` or from the internal `dart:_js_annotations`.
-bool hasAnonymousAnnotation(Annotatable a) =>
- a.annotations.any(_isAnonymousAnnotation);
-
-/// If [a] has a `@JS('...')` annotation, returns the value inside the
-/// parentheses.
-///
-/// If there is none or the class does not have a `@JS()` annotation, returns
-/// an empty String.
-String getJSName(Annotatable a) {
- String jsClass = '';
- for (var annotation in a.annotations) {
- if (_isPublicJSAnnotation(annotation)) {
- var jsClasses = _stringAnnotationValues(annotation);
- if (jsClasses.length > 0) {
- jsClass = jsClasses[0];
- }
- }
- }
- return jsClass;
-}
-
-/// If [a] has a `@Native('...')` annotation, returns the values inside the
-/// parentheses.
-///
-/// If there are none or the class does not have a `@Native()` annotation,
-/// returns an empty list. Unlike `@JS()`, the string within `@Native()` is
-/// allowed to contain several classes separated by a `,`.
-List<String> getNativeNames(Annotatable a) {
- List<String> nativeClasses = [];
- for (var annotation in a.annotations) {
- if (_isNativeAnnotation(annotation)) {
- nativeClasses.addAll(_stringAnnotationValues(annotation));
- }
- }
- return nativeClasses;
+/// Returns true if [m] belongs to an anonymous class.
+bool isAnonymousClassMember(Member m) {
+ var enclosingClass = m.enclosingClass;
+ if (enclosingClass == null) return false;
+ return enclosingClass.annotations.any(_isAnonymousAnnotation);
}
final _packageJs = Uri.parse('package:js/js.dart');
final _internalJs = Uri.parse('dart:_js_annotations');
-final _jsHelper = Uri.parse('dart:_js_helper');
/// Returns true if [value] is the `JS` annotation from `package:js` or from
/// `dart:_js_annotations`.
@@ -72,20 +39,12 @@
c.enclosingLibrary.importUri == _internalJs);
}
-bool _isNativeAnnotation(Expression value) {
- var c = _annotationClass(value);
- return c != null &&
- c.name == 'Native' &&
- c.enclosingLibrary.importUri == _jsHelper;
-}
-
/// Returns the class of the instance referred to by metadata annotation [node].
///
/// For example:
///
/// - `@JS()` would return the "JS" class in "package:js".
/// - `@anonymous` would return the "_Anonymous" class in "package:js".
-/// - `@Native` would return the "Native" class in "dart:_js_helper".
///
/// This function works regardless of whether the CFE is evaluating constants,
/// or whether the constant is a field reference (such as "anonymous" above).
@@ -101,40 +60,3 @@
}
return null;
}
-
-/// Returns the string values inside of a metadata annotation [node].
-///
-/// For example:
-/// - `@JS('Foo')` would return ['Foo'].
-/// - `@Native('Foo,Bar')` would return ['Foo', 'Bar'].
-///
-/// [node] is expected to be an annotation with either StringConstants or
-/// StringLiterals that can be made up of multiple values. If there are none,
-/// this method returns an empty list. This method throws an assertion if there
-/// are multiple arguments or a named arg in the annotation.
-List<String> _stringAnnotationValues(Expression node) {
- List<String> values = [];
- if (node is ConstantExpression) {
- var constant = node.constant;
- if (constant is InstanceConstant) {
- var argLength = constant.fieldValues.values.length;
- if (argLength == 1) {
- var value = constant.fieldValues.values.elementAt(0);
- if (value is StringConstant) values.addAll(value.value.split(','));
- } else if (argLength > 1) {
- throw new ArgumentError('Method expects annotation with at most one '
- 'positional argument: $node.');
- }
- }
- } else if (node is ConstructorInvocation) {
- var argLength = node.arguments.positional.length;
- if (argLength > 1 || node.arguments.named.length > 0) {
- throw new ArgumentError('Method expects annotation with at most one '
- 'positional argument: $node.');
- } else if (argLength == 1) {
- var value = node.arguments.positional[0];
- if (value is StringLiteral) values.addAll(value.value.split(','));
- }
- }
- return values;
-}
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/add_null_check.dart b/pkg/analysis_server/lib/src/services/correction/dart/add_null_check.dart
index 4c04dd2..c297b3c 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/add_null_check.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/add_null_check.dart
@@ -43,6 +43,30 @@
toType = target.staticParameterElement.type;
} else if (parent is IndexExpression) {
toType = parent.realTarget.staticType;
+ } else if (parent is ForEachPartsWithDeclaration) {
+ toType =
+ typeProvider.iterableType2(parent.loopVariable.declaredElement.type);
+ } else if (parent is ForEachPartsWithIdentifier) {
+ toType = typeProvider.iterableType2(parent.identifier.staticType);
+ } else if (parent is SpreadElement) {
+ var literal = parent.thisOrAncestorOfType<TypedLiteral>();
+ if (literal is ListLiteral) {
+ toType = literal.staticType.asInstanceOf(typeProvider.iterableElement);
+ } else if (literal is SetOrMapLiteral) {
+ toType = literal.staticType.isDartCoreSet
+ ? literal.staticType.asInstanceOf(typeProvider.iterableElement)
+ : literal.staticType.asInstanceOf(typeProvider.mapElement);
+ }
+ } else if (parent is YieldStatement) {
+ var enclosingExecutable =
+ parent.thisOrAncestorOfType<FunctionBody>().parent;
+ if (enclosingExecutable is FunctionDeclaration) {
+ toType = enclosingExecutable.returnType?.type;
+ } else if (enclosingExecutable is MethodDeclaration) {
+ toType = enclosingExecutable.returnType?.type;
+ } else if (enclosingExecutable is FunctionExpression) {
+ toType = enclosingExecutable.declaredElement.returnType;
+ }
} else if ((parent is PrefixedIdentifier && target == parent.prefix) ||
(parent is PropertyAccess && target == parent.target) ||
(parent is MethodInvocation && target == parent.target) ||
@@ -54,7 +78,7 @@
}
if (toType != null &&
!typeSystem.isAssignableTo(
- toType, typeSystem.promoteToNonNull(fromType))) {
+ typeSystem.promoteToNonNull(fromType), toType)) {
// The reason that `fromType` can't be assigned to `toType` is more than
// just because it's nullable, in which case a null check won't fix the
// problem.
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index 832147a..7d7ee48 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -819,9 +819,33 @@
CreateClass.newInstance,
CreateMixin.newInstance,
],
+ CompileTimeErrorCode.UNCHECKED_INVOCATION_OF_NULLABLE_VALUE: [
+ AddNullCheck.newInstance,
+ ],
+ CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE: [
+ AddNullCheck.newInstance,
+ ],
+ CompileTimeErrorCode.UNCHECKED_OPERATOR_INVOCATION_OF_NULLABLE_VALUE: [
+ AddNullCheck.newInstance,
+ ],
+ CompileTimeErrorCode.UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE: [
+ AddNullCheck.newInstance,
+ ],
CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE: [
AddNullCheck.newInstance,
],
+ CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_AS_CONDITION: [
+ AddNullCheck.newInstance,
+ ],
+ CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_AS_ITERATOR: [
+ AddNullCheck.newInstance,
+ ],
+ CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_IN_SPREAD: [
+ AddNullCheck.newInstance,
+ ],
+ CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_IN_YIELD_EACH: [
+ AddNullCheck.newInstance,
+ ],
CompileTimeErrorCode.UNDEFINED_ANNOTATION: [
ChangeTo.annotation,
CreateClass.newInstance,
diff --git a/pkg/analysis_server/test/src/services/correction/fix/add_null_check_test.dart b/pkg/analysis_server/test/src/services/correction/fix/add_null_check_test.dart
index b445c7e..09750df 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/add_null_check_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/add_null_check_test.dart
@@ -3,6 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/services/correction/fix.dart';
+import 'package:analyzer/error/error.dart';
+import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -97,6 +99,55 @@
''');
}
+ Future<void> test_forEachWithDeclarationCondition() async {
+ await resolveTestCode('''
+void f (List<String>? args) {
+ for (var e in args) print(e);
+}
+''');
+ await assertHasFix('''
+void f (List<String>? args) {
+ for (var e in args!) print(e);
+}
+''');
+ }
+
+ Future<void>
+ test_forEachWithDeclarationCondition_differByMoreThanNullability() async {
+ await resolveTestCode('''
+void f (List<int>? args) {
+ for (String e in args) print(e);
+}
+''');
+ await assertNoFix();
+ }
+
+ Future<void> test_forEachWithIdentifierCondition() async {
+ await resolveTestCode('''
+void f (List<String>? args) {
+ String s = "";
+ for (s in args) print(s);
+}
+''');
+ await assertHasFix('''
+void f (List<String>? args) {
+ String s = "";
+ for (s in args!) print(s);
+}
+''');
+ }
+
+ Future<void>
+ test_forEachWithIdentifierCondition_differByMoreThanNullability() async {
+ await resolveTestCode('''
+void f (List<int>? args) {
+ String s = "";
+ for (s in args) print(s);
+}
+''');
+ await assertNoFix();
+ }
+
Future<void> test_functionExpressionInvocation() async {
await resolveTestCode('''
int f(C c) => c.func();
@@ -140,6 +191,21 @@
''');
}
+ Future<void> test_initializer_assignable() async {
+ await resolveTestCode('''
+void f(int? x) {
+ num y = x;
+ print(y);
+}
+''');
+ await assertHasFix('''
+void f(int? x) {
+ num y = x!;
+ print(y);
+}
+''');
+ }
+
Future<void> test_initializer_differByMoreThanNullability() async {
await resolveTestCode('''
void f(String x) {
@@ -176,4 +242,130 @@
int f(String? s) => (s)!.length;
''');
}
+
+ Future<void> test_spreadList() async {
+ await resolveTestCode('''
+void f (List<String>? args) {
+ [...args];
+}
+''');
+ await assertHasFix('''
+void f (List<String>? args) {
+ [...args!];
+}
+''');
+ }
+
+ Future<void> test_spreadList_differByMoreThanNullability() async {
+ await resolveTestCode('''
+void f (List<int>? args) {
+ <String>[...args];
+}
+''');
+ await assertNoFix(
+ errorFilter: (AnalysisError error) =>
+ error.errorCode !=
+ CompileTimeErrorCode.LIST_ELEMENT_TYPE_NOT_ASSIGNABLE);
+ }
+
+ Future<void> test_spreadMap() async {
+ await resolveTestCode('''
+void f (Map<int, String>? args) {
+ print({...args});
+}
+''');
+ await assertHasFix('''
+void f (Map<int, String>? args) {
+ print({...args!});
+}
+''');
+ }
+
+ Future<void> test_spreadSet() async {
+ await resolveTestCode('''
+void f (List<String>? args) {
+ print({...args});
+}
+''');
+ await assertHasFix('''
+void f (List<String>? args) {
+ print({...args!});
+}
+''');
+ }
+
+ Future<void> test_yieldEach_closure() async {
+ await resolveTestCode('''
+g(Iterable<String> Function() cb) {}
+f(List<String>? args) {
+ g(() sync* {
+ yield* args;
+ });
+}
+''');
+ await assertHasFix('''
+g(Iterable<String> Function() cb) {}
+f(List<String>? args) {
+ g(() sync* {
+ yield* args!;
+ });
+}
+''',
+ errorFilter: (AnalysisError error) =>
+ error.errorCode != CompileTimeErrorCode.YIELD_OF_INVALID_TYPE);
+ }
+
+ Future<void> test_yieldEach_localFunction() async {
+ await resolveTestCode('''
+g() {
+ Iterable<String> f(List<String>? args) sync* {
+ yield* args;
+ }
+}
+''');
+ await assertHasFix('''
+g() {
+ Iterable<String> f(List<String>? args) sync* {
+ yield* args!;
+ }
+}
+''',
+ errorFilter: (AnalysisError error) =>
+ error.errorCode ==
+ CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_IN_YIELD_EACH);
+ }
+
+ Future<void> test_yieldEach_method() async {
+ await resolveTestCode('''
+class C {
+ Iterable<String> f(List<String>? args) sync* {
+ yield* args;
+ }
+}
+''');
+ await assertHasFix('''
+class C {
+ Iterable<String> f(List<String>? args) sync* {
+ yield* args!;
+ }
+}
+''',
+ errorFilter: (AnalysisError error) =>
+ error.errorCode != CompileTimeErrorCode.YIELD_OF_INVALID_TYPE);
+ }
+
+ Future<void> test_yieldEach_topLevel() async {
+ await resolveTestCode('''
+Iterable<String> f(List<String>? args) sync* {
+ yield* args;
+}
+''');
+ await assertHasFix('''
+Iterable<String> f(List<String>? args) sync* {
+ yield* args!;
+}
+''',
+ errorFilter: (AnalysisError error) =>
+ error.errorCode != CompileTimeErrorCode.YIELD_OF_INVALID_TYPE);
+ }
}
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index ba3d969..6bfabd4 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -405,7 +405,15 @@
CompileTimeErrorCode.TYPE_PARAMETER_SUPERTYPE_OF_ITS_BOUND,
CompileTimeErrorCode.TYPE_TEST_WITH_NON_TYPE,
CompileTimeErrorCode.TYPE_TEST_WITH_UNDEFINED_NAME,
+ CompileTimeErrorCode.UNCHECKED_INVOCATION_OF_NULLABLE_VALUE,
+ CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+ CompileTimeErrorCode.UNCHECKED_OPERATOR_INVOCATION_OF_NULLABLE_VALUE,
+ CompileTimeErrorCode.UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE,
CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE,
+ CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_AS_CONDITION,
+ CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_AS_ITERATOR,
+ CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_IN_SPREAD,
+ CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_IN_YIELD_EACH,
CompileTimeErrorCode.UNDEFINED_ANNOTATION,
CompileTimeErrorCode.UNDEFINED_CLASS,
CompileTimeErrorCode.UNDEFINED_CLASS_BOOLEAN,
diff --git a/pkg/analyzer/lib/src/dart/resolver/for_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/for_resolver.dart
index 8946ab4..b4f7848 100644
--- a/pkg/analyzer/lib/src/dart/resolver/for_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/for_resolver.dart
@@ -11,6 +11,7 @@
import 'package:analyzer/src/dart/element/type_schema.dart';
import 'package:analyzer/src/dart/resolver/assignment_expression_resolver.dart';
import 'package:analyzer/src/dart/resolver/flow_analysis_visitor.dart';
+import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/generated/resolver.dart';
import 'package:meta/meta.dart';
@@ -118,7 +119,9 @@
iterable?.accept(_resolver);
iterable = forEachParts.iterable;
- _resolver.nullableDereferenceVerifier.expression(iterable);
+ _resolver.nullableDereferenceVerifier.expression(iterable,
+ errorCode:
+ CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_AS_ITERATOR);
loopVariable?.accept(_resolver);
var elementType = _computeForEachElementType(iterable, isAsync);
diff --git a/pkg/analyzer/lib/src/dart/resolver/function_expression_invocation_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/function_expression_invocation_resolver.dart
index 9c98040..28cd2ec 100644
--- a/pkg/analyzer/lib/src/dart/resolver/function_expression_invocation_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/function_expression_invocation_resolver.dart
@@ -43,7 +43,8 @@
return;
}
- _nullableDereferenceVerifier.expression(function);
+ _nullableDereferenceVerifier.expression(function,
+ errorCode: CompileTimeErrorCode.UNCHECKED_INVOCATION_OF_NULLABLE_VALUE);
var receiverType = function.staticType;
if (receiverType is FunctionType) {
diff --git a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
index 3413ad8..a3349c3 100644
--- a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
@@ -466,7 +466,9 @@
);
} else {
_setDynamicResolution(node);
- _resolver.nullableDereferenceVerifier.report(receiver, receiverType);
+ _resolver.nullableDereferenceVerifier.report(receiver, receiverType,
+ errorCode: CompileTimeErrorCode
+ .UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE);
}
return;
}
diff --git a/pkg/analyzer/lib/src/dart/resolver/type_property_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/type_property_resolver.dart
index dc990de..b12e424 100644
--- a/pkg/analyzer/lib/src/dart/resolver/type_property_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/type_property_resolver.dart
@@ -12,6 +12,7 @@
import 'package:analyzer/src/dart/element/type_system.dart';
import 'package:analyzer/src/dart/resolver/extension_member_resolver.dart';
import 'package:analyzer/src/dart/resolver/resolution_result.dart';
+import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/generated/resolver.dart';
import 'package:meta/meta.dart';
@@ -91,10 +92,34 @@
return _toResult();
}
+ var parentExpression = (receiver ?? receiverErrorNode).parent;
+ CompileTimeErrorCode errorCode;
+ if (parentExpression == null) {
+ errorCode = CompileTimeErrorCode.UNCHECKED_INVOCATION_OF_NULLABLE_VALUE;
+ } else {
+ if (parentExpression is CascadeExpression) {
+ parentExpression =
+ (parentExpression as CascadeExpression).cascadeSections.first;
+ }
+ if (parentExpression is BinaryExpression) {
+ errorCode = CompileTimeErrorCode
+ .UNCHECKED_OPERATOR_INVOCATION_OF_NULLABLE_VALUE;
+ } else if (parentExpression is MethodInvocation ||
+ parentExpression is MethodReferenceExpression) {
+ errorCode = CompileTimeErrorCode
+ .UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE;
+ } else if (parentExpression is FunctionExpressionInvocation) {
+ errorCode =
+ CompileTimeErrorCode.UNCHECKED_INVOCATION_OF_NULLABLE_VALUE;
+ } else {
+ errorCode =
+ CompileTimeErrorCode.UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE;
+ }
+ }
+
_resolver.nullableDereferenceVerifier.report(
- receiverErrorNode,
- receiverType,
- );
+ receiverErrorNode, receiverType,
+ errorCode: errorCode, arguments: [name]);
_reportedGetterError = true;
_reportedSetterError = true;
diff --git a/pkg/analyzer/lib/src/dart/resolver/yield_statement_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/yield_statement_resolver.dart
index e79edc9..672ed6f 100644
--- a/pkg/analyzer/lib/src/dart/resolver/yield_statement_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/yield_statement_resolver.dart
@@ -135,7 +135,9 @@
node.expression.accept(_resolver);
if (node.star != null) {
- _resolver.nullableDereferenceVerifier.expression(node.expression);
+ _resolver.nullableDereferenceVerifier.expression(node.expression,
+ errorCode: CompileTimeErrorCode
+ .UNCHECKED_USE_OF_NULLABLE_VALUE_IN_YIELD_EACH);
}
_resolver.inferenceContext.bodyContext?.addYield(node);
diff --git a/pkg/analyzer/lib/src/error/bool_expression_verifier.dart b/pkg/analyzer/lib/src/error/bool_expression_verifier.dart
index 05eb039..c5a7253 100644
--- a/pkg/analyzer/lib/src/error/bool_expression_verifier.dart
+++ b/pkg/analyzer/lib/src/error/bool_expression_verifier.dart
@@ -51,7 +51,9 @@
if (!_checkForUseOfVoidResult(expression) &&
!_typeSystem.isAssignableTo2(type, _boolType)) {
if (type.element == _boolElement) {
- _nullableDereferenceVerifier.report(expression, type);
+ _nullableDereferenceVerifier.report(expression, type,
+ errorCode: CompileTimeErrorCode
+ .UNCHECKED_USE_OF_NULLABLE_VALUE_AS_CONDITION);
} else {
_errorReporter.reportErrorForNode(errorCode, expression, arguments);
}
diff --git a/pkg/analyzer/lib/src/error/codes.dart b/pkg/analyzer/lib/src/error/codes.dart
index 320b554..108a361 100644
--- a/pkg/analyzer/lib/src/error/codes.dart
+++ b/pkg/analyzer/lib/src/error/codes.dart
@@ -9738,6 +9738,44 @@
"creating a type with the name '{0}'.",
hasPublishedDocs: true);
+ static const CompileTimeErrorCode UNCHECKED_INVOCATION_OF_NULLABLE_VALUE =
+ CompileTimeErrorCode('UNCHECKED_USE_OF_NULLABLE_VALUE',
+ "The function can't be unconditionally invoked because it can be 'null'.",
+ correction: "Try adding a null check ('!').",
+ hasPublishedDocs: true,
+ uniqueName: 'UNCHECKED_INVOCATION_OF_NULLABLE_VALUE');
+
+ static const CompileTimeErrorCode
+ UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE = CompileTimeErrorCode(
+ 'UNCHECKED_USE_OF_NULLABLE_VALUE',
+ "The method '{0}' can't be unconditionally invoked because the "
+ "receiver can be 'null'.",
+ correction:
+ "Try making the call conditional (using '?.') or adding a null "
+ "check to the target ('!').",
+ hasPublishedDocs: true,
+ uniqueName: 'UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE');
+
+ static const CompileTimeErrorCode
+ UNCHECKED_OPERATOR_INVOCATION_OF_NULLABLE_VALUE = CompileTimeErrorCode(
+ 'UNCHECKED_USE_OF_NULLABLE_VALUE',
+ "The operator '{0}' can't be unconditionally invoked because the "
+ "receiver can be 'null'.",
+ correction: "Try adding a null check to the target ('!').",
+ hasPublishedDocs: true,
+ uniqueName: 'UNCHECKED_OPERATOR_INVOCATION_OF_NULLABLE_VALUE');
+
+ static const CompileTimeErrorCode
+ UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE = CompileTimeErrorCode(
+ 'UNCHECKED_USE_OF_NULLABLE_VALUE',
+ "The property '{0}' can't be unconditionally accessed because the "
+ "receiver can be 'null'.",
+ correction:
+ "Try making the access conditional (using '?.') or adding a null "
+ "check to the target ('!').",
+ hasPublishedDocs: true,
+ uniqueName: 'UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE');
+
/**
* No parameters.
*/
@@ -9806,6 +9844,46 @@
"it.",
hasPublishedDocs: true);
+ static const CompileTimeErrorCode
+ UNCHECKED_USE_OF_NULLABLE_VALUE_AS_CONDITION = CompileTimeErrorCode(
+ 'UNCHECKED_USE_OF_NULLABLE_VALUE',
+ "A nullable expression can't be used as a condition.",
+ correction:
+ "Try checking that the value isn't 'null' before using it as a "
+ 'condition.',
+ hasPublishedDocs: true,
+ uniqueName: 'UNCHECKED_USE_OF_NULLABLE_VALUE_AS_CONDITION');
+
+ static const CompileTimeErrorCode
+ UNCHECKED_USE_OF_NULLABLE_VALUE_AS_ITERATOR = CompileTimeErrorCode(
+ 'UNCHECKED_USE_OF_NULLABLE_VALUE',
+ "A nullable expression can't be used as an iterator in a for-in "
+ 'loop.',
+ correction:
+ "Try checking that the value isn't 'null' before using it as an "
+ 'iterator.',
+ hasPublishedDocs: true,
+ uniqueName: 'UNCHECKED_USE_OF_NULLABLE_VALUE_AS_ITERATOR');
+
+ static const CompileTimeErrorCode UNCHECKED_USE_OF_NULLABLE_VALUE_IN_SPREAD =
+ CompileTimeErrorCode('UNCHECKED_USE_OF_NULLABLE_VALUE',
+ "A nullable expression can't be used in a spread.",
+ correction:
+ "Try checking that the value isn't 'null' before using it in a "
+ 'spread, or use a null-aware spread.',
+ hasPublishedDocs: true,
+ uniqueName: 'UNCHECKED_USE_OF_NULLABLE_VALUE_IN_SPREAD');
+
+ static const CompileTimeErrorCode
+ UNCHECKED_USE_OF_NULLABLE_VALUE_IN_YIELD_EACH = CompileTimeErrorCode(
+ 'UNCHECKED_USE_OF_NULLABLE_VALUE',
+ "A nullable expression can't be used in a yield-each statement.",
+ correction:
+ "Try checking that the value isn't 'null' before using it in a "
+ 'yield-each statement.',
+ hasPublishedDocs: true,
+ uniqueName: 'UNCHECKED_USE_OF_NULLABLE_VALUE_IN_YIELD_EACH');
+
/**
* No parameters.
*/
diff --git a/pkg/analyzer/lib/src/error/nullable_dereference_verifier.dart b/pkg/analyzer/lib/src/error/nullable_dereference_verifier.dart
index 26dae7d..1ed2687 100644
--- a/pkg/analyzer/lib/src/error/nullable_dereference_verifier.dart
+++ b/pkg/analyzer/lib/src/error/nullable_dereference_verifier.dart
@@ -4,6 +4,7 @@
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/error/error.dart';
import 'package:analyzer/error/listener.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/dart/element/type_system.dart';
@@ -21,33 +22,38 @@
}) : _typeSystem = typeSystem,
_errorReporter = errorReporter;
- bool expression(Expression expression, {DartType type}) {
+ bool expression(Expression expression, {DartType type, ErrorCode errorCode}) {
if (!_typeSystem.isNonNullableByDefault) {
return false;
}
type ??= expression.staticType;
- return _check(expression, type);
+ return _check(expression, type, errorCode: errorCode);
}
- void report(AstNode errorNode, DartType receiverType) {
- var errorCode = receiverType == _typeSystem.typeProvider.nullType
- ? CompileTimeErrorCode.INVALID_USE_OF_NULL_VALUE
- : CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE;
- _errorReporter.reportErrorForNode(errorCode, errorNode);
+ void report(AstNode errorNode, DartType receiverType,
+ {ErrorCode errorCode, List<String> arguments = const <String>[]}) {
+ if (receiverType == _typeSystem.typeProvider.nullType) {
+ errorCode = CompileTimeErrorCode.INVALID_USE_OF_NULL_VALUE;
+ } else {
+ errorCode ??= CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE;
+ }
+ _errorReporter.reportErrorForNode(errorCode, errorNode, arguments);
}
/// If the [receiverType] is potentially nullable, report it.
///
/// The [errorNode] is usually the receiver of the invocation, but if the
/// receiver is the implicit `this`, the name of the invocation.
- bool _check(AstNode errorNode, DartType receiverType) {
+ ///
+ /// Returns whether [receiverType] was reported.
+ bool _check(AstNode errorNode, DartType receiverType, {ErrorCode errorCode}) {
if (identical(receiverType, DynamicTypeImpl.instance) ||
!_typeSystem.isPotentiallyNullable(receiverType)) {
return false;
}
- report(errorNode, receiverType);
+ report(errorNode, receiverType, errorCode: errorCode);
return true;
}
}
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index fed64ed..4ffeb7e 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -1868,7 +1868,9 @@
super.visitSpreadElement(node);
if (!node.isNullAware) {
- nullableDereferenceVerifier.expression(node.expression);
+ nullableDereferenceVerifier.expression(node.expression,
+ errorCode:
+ CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_IN_SPREAD);
}
}
diff --git a/pkg/analyzer/test/id_tests/nullability_test.dart b/pkg/analyzer/test/id_tests/nullability_test.dart
index 1490e2e..19c6869 100644
--- a/pkg/analyzer/test/id_tests/nullability_test.dart
+++ b/pkg/analyzer/test/id_tests/nullability_test.dart
@@ -10,6 +10,7 @@
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/null_safety_understanding_flag.dart';
+import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/dart/element/type_system.dart';
import 'package:analyzer/src/dart/analysis/testing_data.dart';
import 'package:analyzer/src/dart/element/type.dart';
@@ -78,9 +79,9 @@
!node.inDeclarationContext()) {
var element = node.staticElement;
if (element is LocalVariableElement || element is ParameterElement) {
- TypeImpl promotedType = node.staticType;
+ TypeImpl promotedType = _readType(node);
TypeImpl declaredType = (element as VariableElement).type;
- var isPromoted = promotedType != declaredType;
+ var isPromoted = promotedType != null && promotedType != declaredType;
if (isPromoted &&
_typeSystem.isPotentiallyNullable(declaredType) &&
!_typeSystem.isPotentiallyNullable(promotedType)) {
@@ -90,6 +91,19 @@
}
return null;
}
+
+ static DartType _readType(SimpleIdentifier node) {
+ var parent = node.parent;
+ if (parent is AssignmentExpression && parent.leftHandSide == node) {
+ return parent.readType;
+ } else if (parent is PostfixExpression) {
+ return parent.readType;
+ } else if (parent is PrefixExpression) {
+ return parent.readType;
+ } else {
+ return node.staticType;
+ }
+ }
}
class _NullabilityDataInterpreter implements DataInterpreter<String> {
diff --git a/pkg/analyzer/test/src/dart/resolution/function_expression_invocation_test.dart b/pkg/analyzer/test/src/dart/resolution/function_expression_invocation_test.dart
index a1bfdde..8e76124 100644
--- a/pkg/analyzer/test/src/dart/resolution/function_expression_invocation_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/function_expression_invocation_test.dart
@@ -164,7 +164,7 @@
x<int>(1 + 2);
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 21, 1),
+ error(CompileTimeErrorCode.UNCHECKED_INVOCATION_OF_NULLABLE_VALUE, 21, 1),
]);
assertFunctionExpressionInvocation(
diff --git a/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart b/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart
index 9750759..7ed306d 100644
--- a/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart
@@ -1099,7 +1099,8 @@
}
''', [
if (typeToStringWithNullability)
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 61, 5),
+ error(
+ CompileTimeErrorCode.UNCHECKED_INVOCATION_OF_NULLABLE_VALUE, 61, 5),
error(CompileTimeErrorCode.USE_OF_VOID_RESULT, 61, 5),
]);
@@ -1122,7 +1123,8 @@
}
''', [
if (typeToStringWithNullability)
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 23, 3),
+ error(
+ CompileTimeErrorCode.UNCHECKED_INVOCATION_OF_NULLABLE_VALUE, 23, 3),
error(CompileTimeErrorCode.USE_OF_VOID_RESULT, 23, 3),
]);
@@ -1145,7 +1147,8 @@
}
''', [
if (typeToStringWithNullability)
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 26, 5),
+ error(
+ CompileTimeErrorCode.UNCHECKED_INVOCATION_OF_NULLABLE_VALUE, 26, 5),
error(CompileTimeErrorCode.USE_OF_VOID_RESULT, 26, 3),
]);
assertMethodInvocation(
@@ -1164,7 +1167,8 @@
}
''', [
if (typeToStringWithNullability)
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 22, 3),
+ error(
+ CompileTimeErrorCode.UNCHECKED_INVOCATION_OF_NULLABLE_VALUE, 22, 3),
error(CompileTimeErrorCode.USE_OF_VOID_RESULT, 22, 3),
]);
@@ -2466,7 +2470,8 @@
foo.call();
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 26, 3),
+ error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+ 26, 3),
]);
assertMethodInvocation2(
@@ -2517,7 +2522,8 @@
a.foo();
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 46, 1),
+ error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+ 46, 1),
]);
assertMethodInvocation2(
@@ -2543,7 +2549,8 @@
a.foo();
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 84, 1),
+ error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+ 84, 1),
]);
assertMethodInvocation2(
@@ -2610,7 +2617,8 @@
a.foo();
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 29, 1),
+ error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+ 29, 1),
]);
assertMethodInvocation2(
@@ -2634,7 +2642,8 @@
a.foo();
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 67, 1),
+ error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+ 67, 1),
]);
assertMethodInvocation2(
diff --git a/pkg/analyzer/test/src/dart/resolution/prefix_expression_test.dart b/pkg/analyzer/test/src/dart/resolution/prefix_expression_test.dart
index 33a2b3c..b263cdf 100644
--- a/pkg/analyzer/test/src/dart/resolution/prefix_expression_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/prefix_expression_test.dart
@@ -648,7 +648,8 @@
!a?.foo;
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 55, 6),
+ error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_AS_CONDITION,
+ 55, 6),
]);
assertPrefixExpression(
@@ -672,7 +673,8 @@
-a?.foo;
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 51, 6),
+ error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+ 51, 6),
]);
assertPrefixExpression(
@@ -746,7 +748,8 @@
~a?.foo;
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 51, 6),
+ error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+ 51, 6),
]);
assertPrefixExpression(
diff --git a/pkg/analyzer/test/src/dart/resolution/property_access_test.dart b/pkg/analyzer/test/src/dart/resolution/property_access_test.dart
index c6e60f7..63ab662 100644
--- a/pkg/analyzer/test/src/dart/resolution/property_access_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/property_access_test.dart
@@ -520,7 +520,8 @@
''');
assertErrorsInResult(expectedErrorsByNullability(
nullable: [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 33, 3),
+ error(CompileTimeErrorCode.UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE,
+ 33, 3),
],
legacy: [
error(CompileTimeErrorCode.UNDEFINED_GETTER, 37, 3),
diff --git a/pkg/analyzer/test/src/diagnostics/null_safety_read_write_test.dart b/pkg/analyzer/test/src/diagnostics/null_safety_read_write_test.dart
index 8729624..2920519 100644
--- a/pkg/analyzer/test/src/diagnostics/null_safety_read_write_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/null_safety_read_write_test.dart
@@ -515,7 +515,8 @@
''', [
error(CompileTimeErrorCode.DEFINITELY_UNASSIGNED_LATE_LOCAL_VARIABLE, 68,
1),
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 68, 1),
+ error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+ 68, 1),
]);
_assertAssigned('x +=', assigned: false, unassigned: true);
}
@@ -530,7 +531,8 @@
''', [
error(CompileTimeErrorCode.DEFINITELY_UNASSIGNED_LATE_LOCAL_VARIABLE, 68,
1),
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 68, 1),
+ error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+ 68, 1),
]);
_assertAssigned('x++', assigned: false, unassigned: true);
}
@@ -545,7 +547,8 @@
''', [
error(CompileTimeErrorCode.DEFINITELY_UNASSIGNED_LATE_LOCAL_VARIABLE, 70,
1),
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 70, 1),
+ error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+ 70, 1),
]);
_assertAssigned('x; // 0', assigned: false, unassigned: true);
}
@@ -581,7 +584,8 @@
x += 1;
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 90, 1),
+ error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+ 90, 1),
]);
_assertAssigned('x +=', assigned: false, unassigned: false);
}
@@ -595,7 +599,8 @@
x++;
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 90, 1),
+ error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+ 90, 1),
]);
_assertAssigned('x++', assigned: false, unassigned: false);
}
@@ -609,7 +614,8 @@
++x; // 0
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 92, 1),
+ error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+ 92, 1),
]);
_assertAssigned('x; // 0', assigned: false, unassigned: false);
}
diff --git a/pkg/analyzer/test/src/diagnostics/receiver_of_type_never_test.dart b/pkg/analyzer/test/src/diagnostics/receiver_of_type_never_test.dart
index 00ed468..1bb51ac 100644
--- a/pkg/analyzer/test/src/diagnostics/receiver_of_type_never_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/receiver_of_type_never_test.dart
@@ -77,7 +77,10 @@
x + (1 + 2);
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 21, 1),
+ error(
+ CompileTimeErrorCode.UNCHECKED_OPERATOR_INVOCATION_OF_NULLABLE_VALUE,
+ 21,
+ 1),
]);
assertBinaryExpression(
@@ -121,7 +124,7 @@
x();
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 21, 1),
+ error(CompileTimeErrorCode.UNCHECKED_INVOCATION_OF_NULLABLE_VALUE, 21, 1),
]);
}
@@ -201,7 +204,8 @@
x[0];
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 21, 1),
+ error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+ 21, 1),
]);
assertIndexExpression(
@@ -218,7 +222,8 @@
x[0] += 1 + 2;
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 21, 1),
+ error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+ 21, 1),
]);
assertAssignment(
@@ -249,7 +254,8 @@
x[0] = 1 + 2;
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 21, 1),
+ error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+ 21, 1),
]);
assertIndexExpression(
@@ -358,7 +364,8 @@
x++;
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 21, 1),
+ error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+ 21, 1),
]);
assertPostfixExpression(
@@ -399,7 +406,8 @@
++x;
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 23, 1),
+ error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+ 23, 1),
]);
assertPrefixExpression(
@@ -509,7 +517,8 @@
x.foo;
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 21, 1),
+ error(CompileTimeErrorCode.UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE,
+ 21, 1),
]);
assertSimpleIdentifier(
diff --git a/pkg/analyzer/test/src/diagnostics/use_of_nullable_value_test.dart b/pkg/analyzer/test/src/diagnostics/use_of_nullable_value_test.dart
index 5c1a04d..5e0338c 100644
--- a/pkg/analyzer/test/src/diagnostics/use_of_nullable_value_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/use_of_nullable_value_test.dart
@@ -161,8 +161,10 @@
}
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 126, 4),
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 154, 4),
+ error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+ 126, 4),
+ error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+ 154, 4),
]);
}
@@ -202,8 +204,10 @@
}
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 68, 3),
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 79, 4),
+ error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+ 68, 3),
+ error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+ 79, 4),
]);
}
@@ -233,7 +237,8 @@
}
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 78, 4),
+ error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+ 78, 4),
]);
}
@@ -277,8 +282,10 @@
}
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 93, 3),
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 102, 4),
+ error(CompileTimeErrorCode.UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE,
+ 93, 3),
+ error(CompileTimeErrorCode.UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE,
+ 102, 4),
]);
}
@@ -322,8 +329,10 @@
}
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 93, 3),
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 106, 4),
+ error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+ 93, 3),
+ error(CompileTimeErrorCode.UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE,
+ 106, 4),
]);
}
}
@@ -347,7 +356,8 @@
if(x && true) {}
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 22, 1),
+ error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_AS_CONDITION,
+ 22, 1),
]);
}
@@ -376,7 +386,8 @@
assert(x);
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 26, 1),
+ error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_AS_CONDITION,
+ 26, 1),
]);
}
@@ -397,7 +408,8 @@
b.a.x = 2;
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 100, 3),
+ error(CompileTimeErrorCode.UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE,
+ 100, 3),
]);
assertAssignment(
@@ -482,7 +494,8 @@
b.a.y += 0;
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 109, 5),
+ error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+ 109, 5),
]);
assertAssignment(
@@ -536,7 +549,8 @@
b.a.x += 2;
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 101, 3),
+ error(CompileTimeErrorCode.UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE,
+ 101, 3),
]);
assertAssignment(
@@ -580,7 +594,8 @@
y += 0;
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 31, 1),
+ error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+ 31, 1),
]);
var assignment1 = findNode.assignment('x +=');
var assignment2 = findNode.assignment('y +=');
@@ -651,7 +666,8 @@
x..[0] = 1;
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 24, 1),
+ error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+ 24, 1),
]);
}
@@ -671,7 +687,8 @@
x..abs();
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 18, 1),
+ error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+ 18, 1),
]);
}
@@ -691,7 +708,8 @@
x..isEven;
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 18, 1),
+ error(CompileTimeErrorCode.UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE,
+ 18, 1),
]);
}
@@ -732,7 +750,8 @@
}
''', [
error(HintCode.UNUSED_LOCAL_VARIABLE, 28, 1),
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 33, 1),
+ error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_AS_ITERATOR,
+ 33, 1),
]);
}
@@ -746,7 +765,8 @@
x.foo;
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 58, 1),
+ error(CompileTimeErrorCode.UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE,
+ 58, 1),
]);
}
@@ -766,7 +786,8 @@
if (x) {}
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 23, 1),
+ error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_AS_CONDITION,
+ 23, 1),
]);
}
@@ -786,7 +807,8 @@
x[0];
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 19, 1),
+ error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+ 19, 1),
]);
}
@@ -806,7 +828,7 @@
x();
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 23, 1),
+ error(CompileTimeErrorCode.UNCHECKED_INVOCATION_OF_NULLABLE_VALUE, 23, 1),
]);
}
@@ -826,7 +848,7 @@
x();
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 25, 1),
+ error(CompileTimeErrorCode.UNCHECKED_INVOCATION_OF_NULLABLE_VALUE, 25, 1),
]);
}
@@ -882,7 +904,8 @@
x.isEven;
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 18, 1),
+ error(CompileTimeErrorCode.UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE,
+ 18, 1),
]);
assertSimpleIdentifier(
findNode.simple('isEven'),
@@ -907,7 +930,8 @@
(x).isEven;
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 18, 3),
+ error(CompileTimeErrorCode.UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE,
+ 18, 3),
]);
}
@@ -926,7 +950,8 @@
x.isEven;
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 27, 1),
+ error(CompileTimeErrorCode.UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE,
+ 27, 1),
]);
}
@@ -936,7 +961,7 @@
x.first();
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 38, 7),
+ error(CompileTimeErrorCode.UNCHECKED_INVOCATION_OF_NULLABLE_VALUE, 38, 7),
]);
}
@@ -982,7 +1007,8 @@
x.round();
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 18, 1),
+ error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+ 18, 1),
]);
}
@@ -996,7 +1022,8 @@
x.foo();
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 54, 1),
+ error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+ 54, 1),
]);
}
@@ -1031,7 +1058,8 @@
x.call();
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 19, 1),
+ error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+ 19, 1),
]);
}
@@ -1054,17 +1082,20 @@
}
''', [
error(HintCode.UNUSED_LOCAL_VARIABLE, 13, 1),
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 18, 1),
+ error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+ 18, 1),
]);
}
test_not_nonNullable() async {
- await assertNoErrorsInCode(r'''
+ await assertErrorsInCode(r'''
m() {
bool x = true;
if(!x) {}
}
-''');
+''', [
+ error(HintCode.DEAD_CODE, 32, 2),
+ ]);
}
test_not_nullable() async {
@@ -1074,7 +1105,8 @@
if(!x) {}
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 23, 1),
+ error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_AS_CONDITION,
+ 23, 1),
]);
}
@@ -1131,7 +1163,10 @@
x - 3;
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 18, 1),
+ error(
+ CompileTimeErrorCode.UNCHECKED_OPERATOR_INVOCATION_OF_NULLABLE_VALUE,
+ 18,
+ 1),
]);
}
@@ -1151,7 +1186,10 @@
x + 3;
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 18, 1),
+ error(
+ CompileTimeErrorCode.UNCHECKED_OPERATOR_INVOCATION_OF_NULLABLE_VALUE,
+ 18,
+ 1),
]);
}
@@ -1174,7 +1212,8 @@
}
''', [
error(HintCode.UNUSED_LOCAL_VARIABLE, 13, 1),
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 18, 1),
+ error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+ 18, 1),
]);
}
@@ -1192,7 +1231,8 @@
x++;
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 14, 1),
+ error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+ 14, 1),
]);
}
@@ -1208,7 +1248,8 @@
x++;
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 77, 1),
+ error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+ 77, 1),
]);
}
@@ -1231,7 +1272,8 @@
}
''', [
error(HintCode.UNUSED_LOCAL_VARIABLE, 13, 1),
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 20, 1),
+ error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+ 20, 1),
]);
}
@@ -1249,7 +1291,8 @@
++x;
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 16, 1),
+ error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+ 16, 1),
]);
}
@@ -1272,7 +1315,8 @@
}
''', [
error(HintCode.UNUSED_LOCAL_VARIABLE, 13, 1),
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 19, 1),
+ error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+ 19, 1),
]);
}
@@ -1288,17 +1332,20 @@
-x;
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 73, 1),
+ error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+ 73, 1),
]);
}
test_or_nonNullable() async {
- await assertNoErrorsInCode(r'''
+ await assertErrorsInCode(r'''
m() {
bool x = true;
if(x || false) {}
}
-''');
+''', [
+ error(HintCode.DEAD_CODE, 33, 5),
+ ]);
}
test_or_nullable() async {
@@ -1308,7 +1355,8 @@
if(x || false) {}
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 22, 1),
+ error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_AS_CONDITION,
+ 22, 1),
]);
}
@@ -1326,7 +1374,8 @@
x += 1;
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 14, 1),
+ error(CompileTimeErrorCode.UNCHECKED_METHOD_INVOCATION_OF_NULLABLE_VALUE,
+ 14, 1),
]);
}
@@ -1342,7 +1391,8 @@
a.x; // 2
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 66, 1),
+ error(CompileTimeErrorCode.UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE,
+ 66, 1),
]);
var propertyAccess1 = findNode.propertyAccess('a?.x; // 1');
var propertyAccess2 = findNode.prefixed('a.x; // 2');
@@ -1373,7 +1423,8 @@
b.a.x; // 2
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 101, 3),
+ error(CompileTimeErrorCode.UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE,
+ 101, 3),
]);
var propertyAccess1 = findNode.propertyAccess('b.a?.x; // 1');
var propertyAccess2 = findNode.propertyAccess('b.a.x; // 2');
@@ -1404,7 +1455,8 @@
b.a.x; // 2
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 101, 1),
+ error(CompileTimeErrorCode.UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE,
+ 101, 1),
]);
var propertyAccess1 = findNode.propertyAccess('x; // 1');
var propertyAccess2 = findNode.propertyAccess('x; // 2');
@@ -1440,7 +1492,8 @@
c.b.a.x; // 2
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 142, 5),
+ error(CompileTimeErrorCode.UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE,
+ 142, 5),
]);
var propertyAccess1 = findNode.propertyAccess('x; // 1');
var propertyAccess2 = findNode.propertyAccess('x; // 2');
@@ -1476,7 +1529,8 @@
c.b.a.x; // 2
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 148, 3),
+ error(CompileTimeErrorCode.UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE,
+ 148, 3),
]);
var propertyAccess1 = findNode.propertyAccess('x; // 1');
var propertyAccess2 = findNode.propertyAccess('x; // 2');
@@ -1510,7 +1564,8 @@
[...list];
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 26, 4),
+ error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_IN_SPREAD, 26,
+ 4),
]);
}
@@ -1530,7 +1585,8 @@
x ? 0 : 1;
}
''', [
- error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE, 19, 1),
+ error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_AS_CONDITION,
+ 19, 1),
]);
}
@@ -1551,4 +1607,26 @@
}
''');
}
+
+ test_yieldEach_nonNullable() async {
+ await assertNoErrorsInCode(r'''
+m() sync* {
+ List<int> x = [];
+ yield* x;
+}
+''');
+ }
+
+ test_yieldEach_nullable() async {
+ await assertErrorsInCode(r'''
+m() sync* {
+ List<int>? x;
+ yield* x;
+}
+''', [
+ error(CompileTimeErrorCode.YIELD_OF_INVALID_TYPE, 37, 1),
+ error(CompileTimeErrorCode.UNCHECKED_USE_OF_NULLABLE_VALUE_IN_YIELD_EACH,
+ 37, 1),
+ ]);
+ }
}
diff --git a/pkg/analyzer/tool/diagnostics/diagnostics.md b/pkg/analyzer/tool/diagnostics/diagnostics.md
index 3dd7497..d395869 100644
--- a/pkg/analyzer/tool/diagnostics/diagnostics.md
+++ b/pkg/analyzer/tool/diagnostics/diagnostics.md
@@ -8408,9 +8408,28 @@
### unchecked_use_of_nullable_value
+_A nullable expression can't be used as a condition._
+
+_A nullable expression can't be used as an iterator in a for-in loop._
+
+_A nullable expression can't be used in a spread._
+
+_A nullable expression can't be used in a yield-each statement._
+
_An expression whose value can be 'null' must be null-checked before it can be
dereferenced._
+_The function can't be unconditionally invoked because it can be 'null'._
+
+_The method '{0}' can't be unconditionally invoked because the receiver can be
+'null'._
+
+_The operator '{0}' can't be unconditionally invoked because the receiver can be
+'null'._
+
+_The property '{0}' can't be unconditionally accessed because the receiver can
+be 'null'._
+
#### Description
The analyzer produces this diagnostic when an expression whose type is
diff --git a/pkg/compiler/lib/src/kernel/dart2js_target.dart b/pkg/compiler/lib/src/kernel/dart2js_target.dart
index 7af0873..49923c1 100644
--- a/pkg/compiler/lib/src/kernel/dart2js_target.dart
+++ b/pkg/compiler/lib/src/kernel/dart2js_target.dart
@@ -9,7 +9,6 @@
import 'package:_fe_analyzer_shared/src/messages/codes.dart'
show Message, LocatedMessage;
import 'package:_js_interop_checks/js_interop_checks.dart';
-import 'package:_js_interop_checks/src/js_interop.dart';
import 'package:kernel/ast.dart' as ir;
import 'package:kernel/class_hierarchy.dart';
import 'package:kernel/core_types.dart';
@@ -125,20 +124,9 @@
ReferenceFromIndex referenceFromIndex,
{void logger(String msg),
ChangedStructureNotifier changedStructureNotifier}) {
- var nativeClasses = <String, ir.Class>{};
- for (var library in component.libraries) {
- for (var cls in library.classes) {
- var nativeNames = getNativeNames(cls);
- for (var nativeName in nativeNames) {
- nativeClasses[nativeName] = cls;
- }
- }
- }
for (var library in libraries) {
- JsInteropChecks(
- coreTypes,
- diagnosticReporter as DiagnosticReporter<Message, LocatedMessage>,
- nativeClasses)
+ JsInteropChecks(coreTypes,
+ diagnosticReporter as DiagnosticReporter<Message, LocatedMessage>)
.visitLibrary(library);
}
lowering.transformLibraries(
diff --git a/pkg/dds/lib/vm_service_extensions.dart b/pkg/dds/lib/vm_service_extensions.dart
index 5b540da..8373b87 100644
--- a/pkg/dds/lib/vm_service_extensions.dart
+++ b/pkg/dds/lib/vm_service_extensions.dart
@@ -145,10 +145,12 @@
)
.toList()
.cast<Event>() {
- type = json['type'];
this.json = json;
}
+ @override
+ String get type => 'StreamHistory';
+
/// Historical [Event]s for a stream.
List<Event> get history => UnmodifiableListView(_history);
final List<Event> _history;
diff --git a/pkg/dev_compiler/lib/src/kernel/target.dart b/pkg/dev_compiler/lib/src/kernel/target.dart
index 9f3e929..ca82d2e 100644
--- a/pkg/dev_compiler/lib/src/kernel/target.dart
+++ b/pkg/dev_compiler/lib/src/kernel/target.dart
@@ -17,7 +17,6 @@
import 'package:kernel/target/targets.dart';
import 'package:kernel/transformations/track_widget_constructor_locations.dart';
import 'package:_js_interop_checks/js_interop_checks.dart';
-import 'package:_js_interop_checks/src/js_interop.dart';
import 'constants.dart' show DevCompilerConstantsBackend;
import 'kernel_helpers.dart';
@@ -153,21 +152,10 @@
ReferenceFromIndex referenceFromIndex,
{void Function(String msg) logger,
ChangedStructureNotifier changedStructureNotifier}) {
- var nativeClasses = <String, Class>{};
- for (var library in component.libraries) {
- for (var cls in library.classes) {
- var nativeNames = getNativeNames(cls);
- for (var nativeName in nativeNames) {
- nativeClasses[nativeName] = cls;
- }
- }
- }
for (var library in libraries) {
_CovarianceTransformer(library).transform();
- JsInteropChecks(
- coreTypes,
- diagnosticReporter as DiagnosticReporter<Message, LocatedMessage>,
- nativeClasses)
+ JsInteropChecks(coreTypes,
+ diagnosticReporter as DiagnosticReporter<Message, LocatedMessage>)
.visitLibrary(library);
}
}
diff --git a/pkg/front_end/messages.status b/pkg/front_end/messages.status
index afaa87e..c275e1e 100644
--- a/pkg/front_end/messages.status
+++ b/pkg/front_end/messages.status
@@ -488,8 +488,6 @@
JsInteropJSClassExtendsDartClass/example: Fail # Web compiler specific
JsInteropNamedParameters/analyzerCode: Fail # Web compiler specific
JsInteropNamedParameters/example: Fail # Web compiler specific
-JsInteropNativeClassInAnnotation/analyzerCode: Fail # Web compiler specific
-JsInteropNativeClassInAnnotation/example: Fail # Web compiler specific
JsInteropNonExternalConstructor/analyzerCode: Fail # Web compiler specific
JsInteropNonExternalConstructor/example: Fail # Web compiler specific
JsInteropNonExternalMember/analyzerCode: Fail # Web compiler specific
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index 83af639..db4e95d 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -4667,9 +4667,6 @@
template: "Named parameters for JS interop functions are only allowed in a factory constructor of an @anonymous JS class."
tip: "Try replacing them with normal or optional parameters."
-JsInteropNativeClassInAnnotation:
- template: "JS interop class '#name' conflicts with natively supported class '#name2' in '#string3'."
-
JsInteropNonExternalConstructor:
template: "JS interop classes do not support non-external constructors."
tip: "Try annotating with `external`."
@@ -4931,4 +4928,4 @@
exampleAllowMoreCodes: true
analyzerCode: UNEXPECTED_TOKEN
script:
- - "late int x;"
+ - "late int x;"
\ No newline at end of file
diff --git a/pkg/front_end/test/spell_checking_list_messages.txt b/pkg/front_end/test/spell_checking_list_messages.txt
index d926797..debea18 100644
--- a/pkg/front_end/test/spell_checking_list_messages.txt
+++ b/pkg/front_end/test/spell_checking_list_messages.txt
@@ -40,7 +40,6 @@
name.stack
nameokempty
native('native
-natively
nativetype
nnbd
nosuchmethod
diff --git a/pkg/vm_service/CHANGELOG.md b/pkg/vm_service/CHANGELOG.md
index 8c80c4f..14bcf2c 100644
--- a/pkg/vm_service/CHANGELOG.md
+++ b/pkg/vm_service/CHANGELOG.md
@@ -1,4 +1,6 @@
# Changelog
+## 6.0.0-nullsafety-dev
+- Migrate to use null safety.
## 5.5.1
- Fix issue where `VmService.onDone` could complete before the provided `DisposeHandler` had finished executing.
diff --git a/pkg/vm_service/example/vm_service_assert.dart b/pkg/vm_service/example/vm_service_assert.dart
index 0243d12..365cb7f 100644
--- a/pkg/vm_service/example/vm_service_assert.dart
+++ b/pkg/vm_service/example/vm_service_assert.dart
@@ -14,17 +14,14 @@
}
bool assertBool(bool obj) {
- assertNotNull(obj);
return obj;
}
int assertInt(int obj) {
- assertNotNull(obj);
return obj;
}
double assertDouble(double obj) {
- assertNotNull(obj);
return obj;
}
@@ -55,13 +52,11 @@
}
String assertString(String obj) {
- assertNotNull(obj);
if (obj.isEmpty) throw 'expected non-zero length string';
return obj;
}
vms.Success assertSuccess(vms.Success obj) {
- assertNotNull(obj);
if (obj.type != 'Success') throw 'expected Success';
return obj;
}
@@ -75,10 +70,10 @@
event.kind == vms.EventKind.kBreakpointAdded ||
event.kind == vms.EventKind.kBreakpointRemoved ||
event.kind == vms.EventKind.kBreakpointResolved) {
- assertBreakpoint(event.breakpoint);
+ assertBreakpoint(event.breakpoint!);
}
if (event.kind == vms.EventKind.kPauseBreakpoint) {
- for (vms.Breakpoint elem in event.pauseBreakpoints) {
+ for (vms.Breakpoint elem in event.pauseBreakpoints!) {
assertBreakpoint(elem);
}
}
@@ -94,18 +89,18 @@
if (event.topFrame != null ||
(event.kind != vms.EventKind.kPauseInterrupted &&
event.kind != vms.EventKind.kResume)) {
- assertFrame(event.topFrame);
+ assertFrame(event.topFrame!);
}
}
if (event.kind == vms.EventKind.kPauseException) {
- assertInstanceRef(event.exception);
+ assertInstanceRef(event.exception!);
}
if (event.kind == vms.EventKind.kPauseBreakpoint ||
event.kind == vms.EventKind.kPauseInterrupted) {
- assertBool(event.atAsyncSuspension);
+ assertBool(event.atAsyncSuspension!);
}
if (event.kind == vms.EventKind.kInspect) {
- assertInstanceRef(event.inspectee);
+ assertInstanceRef(event.inspectee!);
}
return event;
}
@@ -115,7 +110,7 @@
vms.Event assertIsolateEvent(vms.Event event) {
assertEvent(event);
if (event.kind == vms.EventKind.kServiceExtensionAdded) {
- assertString(event.extensionRPC);
+ assertString(event.extensionRPC!);
}
return event;
}
@@ -250,7 +245,6 @@
vms.AllocationProfile assertAllocationProfile(vms.AllocationProfile obj) {
assertNotNull(obj);
- assertString(obj.type);
assertListOfClassHeapStats(obj.members);
assertMemoryUsage(obj.memoryUsage);
return obj;
@@ -271,7 +265,6 @@
vms.BoundVariable assertBoundVariable(vms.BoundVariable obj) {
assertNotNull(obj);
- assertString(obj.type);
assertString(obj.name);
if (obj.value is vms.InstanceRef) {
assertInstanceRef(obj.value);
@@ -298,7 +291,6 @@
vms.Breakpoint assertBreakpoint(vms.Breakpoint obj) {
assertNotNull(obj);
- assertString(obj.type);
assertString(obj.id);
assertInt(obj.breakpointNumber);
assertBool(obj.resolved);
@@ -321,7 +313,6 @@
vms.ClassRef assertClassRef(vms.ClassRef obj) {
assertNotNull(obj);
- assertString(obj.type);
assertString(obj.id);
assertString(obj.name);
return obj;
@@ -336,7 +327,6 @@
vms.Class assertClass(vms.Class obj) {
assertNotNull(obj);
- assertString(obj.type);
assertString(obj.id);
assertString(obj.name);
assertBool(obj.isAbstract);
@@ -351,7 +341,6 @@
vms.ClassHeapStats assertClassHeapStats(vms.ClassHeapStats obj) {
assertNotNull(obj);
- assertString(obj.type);
assertClassRef(obj.classRef);
assertInt(obj.accumulatedSize);
assertInt(obj.bytesCurrent);
@@ -370,14 +359,12 @@
vms.ClassList assertClassList(vms.ClassList obj) {
assertNotNull(obj);
- assertString(obj.type);
assertListOfClassRef(obj.classes);
return obj;
}
vms.CodeRef assertCodeRef(vms.CodeRef obj) {
assertNotNull(obj);
- assertString(obj.type);
assertString(obj.id);
assertString(obj.name);
assertCodeKind(obj.kind);
@@ -393,7 +380,6 @@
vms.Code assertCode(vms.Code obj) {
assertNotNull(obj);
- assertString(obj.type);
assertString(obj.id);
assertString(obj.name);
assertCodeKind(obj.kind);
@@ -402,7 +388,6 @@
vms.ContextRef assertContextRef(vms.ContextRef obj) {
assertNotNull(obj);
- assertString(obj.type);
assertString(obj.id);
assertInt(obj.length);
return obj;
@@ -417,7 +402,6 @@
vms.Context assertContext(vms.Context obj) {
assertNotNull(obj);
- assertString(obj.type);
assertString(obj.id);
assertInt(obj.length);
assertListOfContextElement(obj.variables);
@@ -446,7 +430,6 @@
vms.CpuSamples assertCpuSamples(vms.CpuSamples obj) {
assertNotNull(obj);
- assertString(obj.type);
assertInt(obj.samplePeriod);
assertInt(obj.maxStackDepth);
assertInt(obj.sampleCount);
@@ -476,7 +459,6 @@
vms.ErrorRef assertErrorRef(vms.ErrorRef obj) {
assertNotNull(obj);
- assertString(obj.type);
assertString(obj.id);
assertErrorKind(obj.kind);
assertString(obj.message);
@@ -492,7 +474,6 @@
vms.Error assertError(vms.Error obj) {
assertNotNull(obj);
- assertString(obj.type);
assertString(obj.id);
assertErrorKind(obj.kind);
assertString(obj.message);
@@ -501,7 +482,6 @@
vms.Event assertEvent(vms.Event obj) {
assertNotNull(obj);
- assertString(obj.type);
assertEventKind(obj.kind);
assertInt(obj.timestamp);
return obj;
@@ -514,7 +494,6 @@
vms.FieldRef assertFieldRef(vms.FieldRef obj) {
assertNotNull(obj);
- assertString(obj.type);
assertString(obj.id);
assertString(obj.name);
assertObjRef(obj.owner);
@@ -534,7 +513,6 @@
vms.Field assertField(vms.Field obj) {
assertNotNull(obj);
- assertString(obj.type);
assertString(obj.id);
assertString(obj.name);
assertObjRef(obj.owner);
@@ -562,14 +540,12 @@
vms.FlagList assertFlagList(vms.FlagList obj) {
assertNotNull(obj);
- assertString(obj.type);
assertListOfFlag(obj.flags);
return obj;
}
vms.Frame assertFrame(vms.Frame obj) {
assertNotNull(obj);
- assertString(obj.type);
assertInt(obj.index);
return obj;
}
@@ -583,7 +559,6 @@
vms.FuncRef assertFuncRef(vms.FuncRef obj) {
assertNotNull(obj);
- assertString(obj.type);
assertString(obj.id);
assertString(obj.name);
if (obj.owner is vms.LibraryRef) {
@@ -609,7 +584,6 @@
vms.Func assertFunc(vms.Func obj) {
assertNotNull(obj);
- assertString(obj.type);
assertString(obj.id);
assertString(obj.name);
if (obj.owner is vms.LibraryRef) {
@@ -628,7 +602,6 @@
vms.InstanceRef assertInstanceRef(vms.InstanceRef obj) {
assertNotNull(obj);
- assertString(obj.type);
assertString(obj.id);
assertInstanceKind(obj.kind);
assertClassRef(obj.classRef);
@@ -644,7 +617,6 @@
vms.Instance assertInstance(vms.Instance obj) {
assertNotNull(obj);
- assertString(obj.type);
assertString(obj.id);
assertInstanceKind(obj.kind);
assertClassRef(obj.classRef);
@@ -653,7 +625,6 @@
vms.IsolateRef assertIsolateRef(vms.IsolateRef obj) {
assertNotNull(obj);
- assertString(obj.type);
assertString(obj.id);
assertString(obj.number);
assertString(obj.name);
@@ -670,7 +641,6 @@
vms.Isolate assertIsolate(vms.Isolate obj) {
assertNotNull(obj);
- assertString(obj.type);
assertString(obj.id);
assertString(obj.number);
assertString(obj.name);
@@ -696,7 +666,6 @@
vms.IsolateGroupRef assertIsolateGroupRef(vms.IsolateGroupRef obj) {
assertNotNull(obj);
- assertString(obj.type);
assertString(obj.id);
assertString(obj.number);
assertString(obj.name);
@@ -714,7 +683,6 @@
vms.IsolateGroup assertIsolateGroup(vms.IsolateGroup obj) {
assertNotNull(obj);
- assertString(obj.type);
assertString(obj.id);
assertString(obj.number);
assertString(obj.name);
@@ -725,7 +693,6 @@
vms.InboundReferences assertInboundReferences(vms.InboundReferences obj) {
assertNotNull(obj);
- assertString(obj.type);
assertListOfInboundReference(obj.references);
return obj;
}
@@ -746,7 +713,6 @@
vms.InstanceSet assertInstanceSet(vms.InstanceSet obj) {
assertNotNull(obj);
- assertString(obj.type);
assertInt(obj.totalCount);
assertListOfObjRef(obj.instances);
return obj;
@@ -754,7 +720,6 @@
vms.LibraryRef assertLibraryRef(vms.LibraryRef obj) {
assertNotNull(obj);
- assertString(obj.type);
assertString(obj.id);
assertString(obj.name);
assertString(obj.uri);
@@ -770,7 +735,6 @@
vms.Library assertLibrary(vms.Library obj) {
assertNotNull(obj);
- assertString(obj.type);
assertString(obj.id);
assertString(obj.name);
assertString(obj.uri);
@@ -802,7 +766,6 @@
vms.LogRecord assertLogRecord(vms.LogRecord obj) {
assertNotNull(obj);
- assertString(obj.type);
assertInstanceRef(obj.message);
assertInt(obj.time);
assertInt(obj.level);
@@ -835,7 +798,6 @@
vms.MemoryUsage assertMemoryUsage(vms.MemoryUsage obj) {
assertNotNull(obj);
- assertString(obj.type);
assertInt(obj.externalUsage);
assertInt(obj.heapCapacity);
assertInt(obj.heapUsage);
@@ -844,7 +806,6 @@
vms.Message assertMessage(vms.Message obj) {
assertNotNull(obj);
- assertString(obj.type);
assertInt(obj.index);
assertString(obj.name);
assertString(obj.messageObjectId);
@@ -867,7 +828,6 @@
vms.NullValRef assertNullValRef(vms.NullValRef obj) {
assertNotNull(obj);
- assertString(obj.type);
assertString(obj.id);
assertInstanceKind(obj.kind);
assertClassRef(obj.classRef);
@@ -884,7 +844,6 @@
vms.NullVal assertNullVal(vms.NullVal obj) {
assertNotNull(obj);
- assertString(obj.type);
assertString(obj.id);
assertInstanceKind(obj.kind);
assertClassRef(obj.classRef);
@@ -894,7 +853,6 @@
vms.ObjRef assertObjRef(vms.ObjRef obj) {
assertNotNull(obj);
- assertString(obj.type);
assertString(obj.id);
return obj;
}
@@ -908,14 +866,12 @@
vms.Obj assertObj(vms.Obj obj) {
assertNotNull(obj);
- assertString(obj.type);
assertString(obj.id);
return obj;
}
vms.PortList assertPortList(vms.PortList obj) {
assertNotNull(obj);
- assertString(obj.type);
assertListOfInstanceRef(obj.ports);
return obj;
}
@@ -940,7 +896,6 @@
vms.ProtocolList assertProtocolList(vms.ProtocolList obj) {
assertNotNull(obj);
- assertString(obj.type);
assertListOfProtocol(obj.protocols);
return obj;
}
@@ -962,7 +917,6 @@
vms.ProcessMemoryUsage assertProcessMemoryUsage(vms.ProcessMemoryUsage obj) {
assertNotNull(obj);
- assertString(obj.type);
assertProcessMemoryItem(obj.root);
return obj;
}
@@ -986,7 +940,6 @@
vms.ReloadReport assertReloadReport(vms.ReloadReport obj) {
assertNotNull(obj);
- assertString(obj.type);
assertBool(obj.success);
return obj;
}
@@ -1007,7 +960,6 @@
vms.RetainingPath assertRetainingPath(vms.RetainingPath obj) {
assertNotNull(obj);
- assertString(obj.type);
assertInt(obj.length);
assertString(obj.gcRootType);
assertListOfRetainingObject(obj.elements);
@@ -1016,13 +968,11 @@
vms.Response assertResponse(vms.Response obj) {
assertNotNull(obj);
- assertString(obj.type);
return obj;
}
vms.Sentinel assertSentinel(vms.Sentinel obj) {
assertNotNull(obj);
- assertString(obj.type);
assertSentinelKind(obj.kind);
assertString(obj.valueAsString);
return obj;
@@ -1030,7 +980,6 @@
vms.ScriptRef assertScriptRef(vms.ScriptRef obj) {
assertNotNull(obj);
- assertString(obj.type);
assertString(obj.id);
assertString(obj.uri);
return obj;
@@ -1045,7 +994,6 @@
vms.Script assertScript(vms.Script obj) {
assertNotNull(obj);
- assertString(obj.type);
assertString(obj.id);
assertString(obj.uri);
assertLibraryRef(obj.library);
@@ -1054,14 +1002,12 @@
vms.ScriptList assertScriptList(vms.ScriptList obj) {
assertNotNull(obj);
- assertString(obj.type);
assertListOfScriptRef(obj.scripts);
return obj;
}
vms.SourceLocation assertSourceLocation(vms.SourceLocation obj) {
assertNotNull(obj);
- assertString(obj.type);
assertScriptRef(obj.script);
assertInt(obj.tokenPos);
return obj;
@@ -1069,7 +1015,6 @@
vms.SourceReport assertSourceReport(vms.SourceReport obj) {
assertNotNull(obj);
- assertString(obj.type);
assertListOfSourceReportRange(obj.ranges);
assertListOfScriptRef(obj.scripts);
return obj;
@@ -1102,7 +1047,6 @@
vms.Stack assertStack(vms.Stack obj) {
assertNotNull(obj);
- assertString(obj.type);
assertListOfFrame(obj.frames);
assertListOfMessage(obj.messages);
assertBool(obj.truncated);
@@ -1111,7 +1055,6 @@
vms.Timeline assertTimeline(vms.Timeline obj) {
assertNotNull(obj);
- assertString(obj.type);
assertListOfTimelineEvent(obj.traceEvents);
assertInt(obj.timeOriginMicros);
assertInt(obj.timeExtentMicros);
@@ -1133,7 +1076,6 @@
vms.TimelineFlags assertTimelineFlags(vms.TimelineFlags obj) {
assertNotNull(obj);
- assertString(obj.type);
assertString(obj.recorderName);
assertListOfString(obj.availableStreams);
assertListOfString(obj.recordedStreams);
@@ -1142,14 +1084,12 @@
vms.Timestamp assertTimestamp(vms.Timestamp obj) {
assertNotNull(obj);
- assertString(obj.type);
assertInt(obj.timestamp);
return obj;
}
vms.TypeArgumentsRef assertTypeArgumentsRef(vms.TypeArgumentsRef obj) {
assertNotNull(obj);
- assertString(obj.type);
assertString(obj.id);
assertString(obj.name);
return obj;
@@ -1165,7 +1105,6 @@
vms.TypeArguments assertTypeArguments(vms.TypeArguments obj) {
assertNotNull(obj);
- assertString(obj.type);
assertString(obj.id);
assertString(obj.name);
assertListOfInstanceRef(obj.types);
@@ -1175,13 +1114,11 @@
vms.UnresolvedSourceLocation assertUnresolvedSourceLocation(
vms.UnresolvedSourceLocation obj) {
assertNotNull(obj);
- assertString(obj.type);
return obj;
}
vms.Version assertVersion(vms.Version obj) {
assertNotNull(obj);
- assertString(obj.type);
assertInt(obj.major);
assertInt(obj.minor);
return obj;
@@ -1189,7 +1126,6 @@
vms.VMRef assertVMRef(vms.VMRef obj) {
assertNotNull(obj);
- assertString(obj.type);
assertString(obj.name);
return obj;
}
@@ -1203,7 +1139,6 @@
vms.VM assertVM(vms.VM obj) {
assertNotNull(obj);
- assertString(obj.type);
assertString(obj.name);
assertInt(obj.architectureBits);
assertString(obj.hostCPU);
diff --git a/pkg/vm_service/example/vm_service_tester.dart b/pkg/vm_service/example/vm_service_tester.dart
index 75e94a5..e22d5fc 100644
--- a/pkg/vm_service/example/vm_service_tester.dart
+++ b/pkg/vm_service/example/vm_service_tester.dart
@@ -18,10 +18,10 @@
final String host = 'localhost';
final int port = 7575;
-VmService serviceClient;
+late VmService serviceClient;
void main() {
- Process process;
+ Process? process;
tearDown(() {
process?.kill();
@@ -43,11 +43,11 @@
print('dart process started');
// ignore: unawaited_futures
- process.exitCode.then((code) => print('vm exited: ${code}'));
+ process!.exitCode.then((code) => print('vm exited: ${code}'));
// ignore: strong_mode_down_cast_composite
- process.stdout.transform(utf8.decoder).listen(print);
+ process!.stdout.transform(utf8.decoder).listen(print);
// ignore: strong_mode_down_cast_composite
- process.stderr.transform(utf8.decoder).listen(print);
+ process!.stderr.transform(utf8.decoder).listen(print);
await Future.delayed(Duration(milliseconds: 500));
@@ -70,7 +70,7 @@
// reserialize it back to the same exact representation (minus private
// fields).
var json = jsonDecode(str);
- var originalJson = json['result'] as Map<String, dynamic>;
+ var originalJson = json['result'] as Map<String, dynamic>?;
if (originalJson == null && json['method'] == 'streamNotify') {
originalJson = json['params']['event'];
}
@@ -84,7 +84,7 @@
var reserializedJson = (instance as dynamic).toJson();
- forEachNestedMap(originalJson, (obj) {
+ forEachNestedMap(originalJson!, (obj) {
// Private fields that we don't reproduce
obj.removeWhere((k, v) => k.startsWith('_'));
// Extra fields that aren't specified and we don't reproduce
@@ -169,11 +169,11 @@
otherClient.onEvent('Service').listen((e) async {
if (e.service == serviceName && e.kind == EventKind.kServiceRegistered) {
assert(e.alias == serviceAlias);
- Response response = await serviceClient.callMethod(
- e.method,
+ Response? response = await serviceClient.callMethod(
+ e.method!,
args: <String, dynamic>{'input': movedValue},
);
- assert(response.json['output'] == movedValue);
+ assert(response.json!['output'] == movedValue);
completer.complete();
}
});
@@ -184,23 +184,23 @@
Future testScriptParse(IsolateRef isolateRef) async {
final Isolate isolate = await serviceClient.getIsolate(isolateRef.id);
- final Library rootLibrary =
- await serviceClient.getObject(isolateRef.id, isolate.rootLib.id);
+ final Library rootLibrary = await serviceClient.getObject(
+ isolateRef.id, isolate.rootLib!.id) as Library;
final ScriptRef scriptRef = rootLibrary.scripts.first;
final Script script =
- await serviceClient.getObject(isolateRef.id, scriptRef.id);
+ await serviceClient.getObject(isolateRef.id, scriptRef.id) as Script;
print(script);
print(script.uri);
print(script.library);
- print(script.source.length);
- print(script.tokenPosTable.length);
+ print(script.source!.length);
+ print(script.tokenPosTable!.length);
}
Future testSourceReport(IsolateRef isolateRef) async {
final Isolate isolate = await serviceClient.getIsolate(isolateRef.id);
- final Library rootLibrary =
- await serviceClient.getObject(isolateRef.id, isolate.rootLib.id);
+ final Library rootLibrary = await serviceClient.getObject(
+ isolateRef.id, isolate.rootLib!.id) as Library;
final ScriptRef scriptRef = rootLibrary.scripts.first;
// make sure some code has run
diff --git a/pkg/vm_service/lib/src/dart_io_extensions.dart b/pkg/vm_service/lib/src/dart_io_extensions.dart
index c184d3c..acbca2d 100644
--- a/pkg/vm_service/lib/src/dart_io_extensions.dart
+++ b/pkg/vm_service/lib/src/dart_io_extensions.dart
@@ -6,7 +6,6 @@
import 'dart:collection';
-import 'package:meta/meta.dart';
import 'package:vm_service/vm_service.dart';
import 'vm_service.dart';
@@ -16,10 +15,12 @@
static Map<String, Version> _isolateVersion = {};
Future<Version> _version(String isolateId) async {
- if (_isolateVersion[isolateId] == null) {
- _isolateVersion[isolateId] = await getDartIOVersion(isolateId);
+ Version? version = _isolateVersion[isolateId];
+ if (version == null) {
+ version = await getDartIOVersion(isolateId);
+ _isolateVersion[isolateId] = version;
}
- return _isolateVersion[isolateId];
+ return version;
}
/// The `getDartIOVersion` RPC returns the available version of the dart:io
@@ -46,7 +47,7 @@
/// If the state of the socket profiler is changed, a `SocketProfilingStateChange`
/// event will be sent on the `Extension` stream.
Future<SocketProfilingState> socketProfilingEnabled(String isolateId,
- [bool enabled]) async {
+ [bool? enabled]) async {
return _callHelper('ext.dart.io.socketProfilingEnabled', isolateId, args: {
if (enabled != null) 'enabled': enabled,
});
@@ -90,7 +91,7 @@
/// If the value of `HttpClient.enableTimelineLogging` is changed, a
/// `HttpTimelineLoggingStateChange` event will be sent on the `Extension` stream.
Future<HttpTimelineLoggingState> httpEnableTimelineLogging(String isolateId,
- [bool enabled]) async {
+ [bool? enabled]) async {
final version = await _version(isolateId);
// Parameter name changed in version 1.4.
final enableKey =
@@ -139,7 +140,7 @@
},
);
- Future<T> _callHelper<T>(String method, String isolateId,
+ Future<T> _callHelper<T>(String method, String? isolateId,
{Map args = const {}}) {
if (!_factoriesRegistered) {
_registerFactories();
@@ -170,7 +171,7 @@
}
class SocketStatistic {
- static SocketStatistic parse(Map json) =>
+ static SocketStatistic? parse(Map<String, dynamic>? json) =>
json == null ? null : SocketStatistic._fromJson(json);
/// The unique ID associated with this socket.
@@ -219,43 +220,54 @@
/// A [SocketProfile] provides information about statistics of sockets.
class SocketProfile extends Response {
- static SocketProfile parse(Map json) =>
+ static SocketProfile? parse(Map<String, dynamic>? json) =>
json == null ? null : SocketProfile._fromJson(json);
- /// List of socket statistics.
- List<SocketStatistic> sockets;
+ @override
+ String get type => 'SocketProfile';
- SocketProfile({@required this.sockets});
+ /// List of socket statistics.
+ late final List<SocketStatistic> sockets;
+
+ SocketProfile({required this.sockets});
SocketProfile._fromJson(Map<String, dynamic> json) {
// TODO(bkonyi): make this part of the vm_service.dart library so we can
// call super._fromJson.
- type = json['type'];
sockets = List<SocketStatistic>.from(
- createServiceObject(json['sockets'], const ['SocketStatistic']) ?? []);
+ createServiceObject(json['sockets'], const ['SocketStatistic'])
+ as List? ??
+ []);
}
}
/// A [Response] containing the enabled state of a service extension.
abstract class _State extends Response {
- _State({@required this.enabled});
+ _State({required this.enabled}) : _type = 'State';
// TODO(bkonyi): make this part of the vm_service.dart library so we can
// call super._fromJson.
- _State._fromJson(Map<String, dynamic> json) : enabled = json['enabled'] {
- type = json['type'];
- }
+ _State._fromJson(Map<String, dynamic> json)
+ : enabled = json['enabled'],
+ _type = json['type'];
+
+ @override
+ String get type => _type;
final bool enabled;
+ final String _type;
}
/// A [HttpTimelineLoggingState] provides information about the current state of HTTP
/// request logging for a given isolate.
class HttpTimelineLoggingState extends _State {
- static HttpTimelineLoggingState parse(Map json) =>
+ static HttpTimelineLoggingState? parse(Map<String, dynamic>? json) =>
json == null ? null : HttpTimelineLoggingState._fromJson(json);
- HttpTimelineLoggingState({@required bool enabled}) : super(enabled: enabled);
+ @override
+ String get type => 'HttpTimelineLoggingState';
+
+ HttpTimelineLoggingState({required bool enabled}) : super(enabled: enabled);
HttpTimelineLoggingState._fromJson(Map<String, dynamic> json)
: super._fromJson(json);
@@ -264,10 +276,10 @@
/// A [SocketProfilingState] provides information about the current state of
/// socket profiling for a given isolate.
class SocketProfilingState extends _State {
- static SocketProfilingState parse(Map json) =>
+ static SocketProfilingState? parse(Map<String, dynamic>? json) =>
json == null ? null : SocketProfilingState._fromJson(json);
- SocketProfilingState({@required bool enabled}) : super(enabled: enabled);
+ SocketProfilingState({required bool enabled}) : super(enabled: enabled);
SocketProfilingState._fromJson(Map<String, dynamic> json)
: super._fromJson(json);
@@ -275,12 +287,12 @@
/// A [SpawnedProcessRef] contains identifying information about a spawned process.
class SpawnedProcessRef {
- static SpawnedProcessRef parse(Map json) =>
+ static SpawnedProcessRef? parse(Map<String, dynamic>? json) =>
json == null ? null : SpawnedProcessRef._fromJson(json);
SpawnedProcessRef({
- @required this.id,
- @required this.name,
+ required this.id,
+ required this.name,
});
SpawnedProcessRef._fromJson(Map<String, dynamic> json)
@@ -301,16 +313,16 @@
/// A [SpawnedProcess] contains startup information of a spawned process.
class SpawnedProcess extends Response implements SpawnedProcessRef {
- static SpawnedProcess parse(Map json) =>
+ static SpawnedProcess? parse(Map<String, dynamic>? json) =>
json == null ? null : SpawnedProcess._fromJson(json);
SpawnedProcess({
- @required this.id,
- @required this.name,
- @required this.pid,
- @required this.startedAt,
- @required List<String> arguments,
- @required this.workingDirectory,
+ required this.id,
+ required this.name,
+ required this.pid,
+ required this.startedAt,
+ required List<String> arguments,
+ required this.workingDirectory,
}) : _arguments = arguments;
SpawnedProcess._fromJson(Map<String, dynamic> json)
@@ -322,11 +334,11 @@
pid = json['pid'],
startedAt = json['startedAt'],
_arguments = List<String>.from(
- createServiceObject(json['arguments'], const ['String']) as List ??
- []),
- workingDirectory = json['workingDirectory'] {
- type = json['type'];
- }
+ createServiceObject(json['arguments'], const ['String']) as List),
+ workingDirectory = json['workingDirectory'];
+
+ @override
+ String get type => 'SpawnedProcess';
/// The unique ID associated with this process.
final int id;
@@ -349,10 +361,10 @@
}
class SpawnedProcessList extends Response {
- static SpawnedProcessList parse(Map json) =>
+ static SpawnedProcessList? parse(Map<String, dynamic>? json) =>
json == null ? null : SpawnedProcessList._fromJson(json);
- SpawnedProcessList({@required List<SpawnedProcessRef> processes})
+ SpawnedProcessList({required List<SpawnedProcessRef> processes})
: _processes = processes;
SpawnedProcessList._fromJson(Map<String, dynamic> json)
@@ -361,10 +373,10 @@
// call super._fromJson.
_processes = List<SpawnedProcessRef>.from(
createServiceObject(json['processes'], const ['SpawnedProcessRef'])
- as List ??
- []) {
- type = json['type'];
- }
+ as List);
+
+ @override
+ String get type => 'SpawnedProcessList';
/// A list of processes spawned through dart:io on a given isolate.
List<SpawnedProcessRef> get processes => UnmodifiableListView(_processes);
@@ -373,12 +385,12 @@
/// A [OpenFileRef] contains identifying information about a currently opened file.
class OpenFileRef {
- static OpenFileRef parse(Map json) =>
+ static OpenFileRef? parse(Map<String, dynamic>? json) =>
json == null ? null : OpenFileRef._fromJson(json);
OpenFileRef({
- @required this.id,
- @required this.name,
+ required this.id,
+ required this.name,
});
OpenFileRef._fromJson(Map<String, dynamic> json)
@@ -399,18 +411,18 @@
/// A [File] contains information about reads and writes to a currently opened file.
class OpenFile extends Response implements OpenFileRef {
- static OpenFile parse(Map json) =>
+ static OpenFile? parse(Map<String, dynamic>? json) =>
json == null ? null : OpenFile._fromJson(json);
OpenFile({
- @required this.id,
- @required this.name,
- @required this.readBytes,
- @required this.writeBytes,
- @required this.readCount,
- @required this.writeCount,
- @required this.lastReadTime,
- @required this.lastWriteTime,
+ required this.id,
+ required this.name,
+ required this.readBytes,
+ required this.writeBytes,
+ required this.readCount,
+ required this.writeCount,
+ required this.lastReadTime,
+ required this.lastWriteTime,
});
OpenFile._fromJson(Map<String, dynamic> json)
@@ -426,9 +438,10 @@
lastReadTime =
DateTime.fromMillisecondsSinceEpoch(json['lastReadTime']),
lastWriteTime =
- DateTime.fromMillisecondsSinceEpoch(json['lastWriteTime']) {
- type = json['type'];
- }
+ DateTime.fromMillisecondsSinceEpoch(json['lastWriteTime']);
+
+ @override
+ String get type => 'OpenFile';
/// The unique ID associated with this file.
final int id;
@@ -456,20 +469,20 @@
}
class OpenFileList extends Response {
- static OpenFileList parse(Map json) =>
+ static OpenFileList? parse(Map<String, dynamic>? json) =>
json == null ? null : OpenFileList._fromJson(json);
- OpenFileList({@required List<OpenFileRef> files}) : _files = files;
+ OpenFileList({required List<OpenFileRef> files}) : _files = files;
OpenFileList._fromJson(Map<String, dynamic> json)
:
// TODO(bkonyi): make this part of the vm_service.dart library so we can
// call super._fromJson.
_files = List<OpenFileRef>.from(
- createServiceObject(json['files'], const ['OpenFileRef']) as List ??
- []) {
- type = json['type'];
- }
+ createServiceObject(json['files'], const ['OpenFileRef']) as List);
+
+ @override
+ String get type => 'OpenFileList';
/// A list of all files opened through dart:io on a given isolate.
List<OpenFileRef> get files => UnmodifiableListView(_files);
diff --git a/pkg/vm_service/lib/src/helpers.dart b/pkg/vm_service/lib/src/helpers.dart
index 0d14c16..a92c70b 100644
--- a/pkg/vm_service/lib/src/helpers.dart
+++ b/pkg/vm_service/lib/src/helpers.dart
@@ -6,7 +6,7 @@
class IsolateHelper {
static List<TagCounter> getTagCounters(Isolate isolate) {
- Map m = isolate.json['_tagCounters'];
+ Map m = isolate.json!['_tagCounters']!;
List<String> names = m['names'];
List<int> counters = m['counters'];
diff --git a/pkg/vm_service/lib/src/service_extension_registry.dart b/pkg/vm_service/lib/src/service_extension_registry.dart
index 9ec1514..6de71cd 100644
--- a/pkg/vm_service/lib/src/service_extension_registry.dart
+++ b/pkg/vm_service/lib/src/service_extension_registry.dart
@@ -44,7 +44,7 @@
///
/// The result of this function should not be stored, because clients may
/// shut down at any time.
- VmServerConnection clientFor(String extension) =>
+ VmServerConnection? clientFor(String extension) =>
_extensionToConnection[extension];
/// All of the currently registered extensions
diff --git a/pkg/vm_service/lib/src/snapshot_graph.dart b/pkg/vm_service/lib/src/snapshot_graph.dart
index bad549e..e237dd7 100644
--- a/pkg/vm_service/lib/src/snapshot_graph.dart
+++ b/pkg/vm_service/lib/src/snapshot_graph.dart
@@ -100,8 +100,8 @@
/// The name of the field.
String get name => _name;
- int _index;
- String _name;
+ int _index = -1;
+ String _name = '';
HeapSnapshotField._read(_ReadStream reader) {
// flags (reserved)
@@ -129,10 +129,10 @@
/// The list of fields in the class.
List<HeapSnapshotField> get fields => _fields;
- String _name;
- String _libraryName;
- Uri _libraryUri;
- List<HeapSnapshotField> _fields = <HeapSnapshotField>[];
+ String _name = '';
+ String _libraryName = '';
+ late final Uri _libraryUri;
+ final List<HeapSnapshotField> _fields = <HeapSnapshotField>[];
HeapSnapshotClass._read(_ReadStream reader) {
// flags (reserved).
@@ -170,10 +170,10 @@
/// A list of 1-origin indicies into [HeapSnapshotGraph.objects].
List<int> get references => _references;
- int _classId;
- int _shallowSize;
- dynamic _data;
- List<int> _references = <int>[];
+ int _classId = -1;
+ int _shallowSize = -1;
+ late final dynamic _data;
+ final List<int> _references = <int>[];
HeapSnapshotObject._read(_ReadStream reader) {
_classId = reader.readUnsigned();
@@ -238,15 +238,15 @@
List<HeapSnapshotExternalProperty> get externalProperties =>
_externalProperties;
- String _name;
- int _flags;
- int _shallowSize;
- int _capacity;
- int _externalSize;
- List<HeapSnapshotClass> _classes = <HeapSnapshotClass>[];
- int _referenceCount;
- List<HeapSnapshotObject> _objects = <HeapSnapshotObject>[];
- List<HeapSnapshotExternalProperty> _externalProperties =
+ String _name = '';
+ int _flags = -1;
+ int _shallowSize = -1;
+ int _capacity = -1;
+ int _externalSize = -1;
+ final List<HeapSnapshotClass> _classes = <HeapSnapshotClass>[];
+ int _referenceCount = -1;
+ final List<HeapSnapshotObject> _objects = <HeapSnapshotObject>[];
+ final List<HeapSnapshotExternalProperty> _externalProperties =
<HeapSnapshotExternalProperty>[];
/// Requests a heap snapshot for a given isolate and builds a
@@ -260,10 +260,10 @@
final completer = Completer<HeapSnapshotGraph>();
final chunks = <ByteData>[];
- StreamSubscription streamSubscription;
+ late StreamSubscription streamSubscription;
streamSubscription = service.onHeapSnapshotEvent.listen((e) async {
- chunks.add(e.data);
- if (e.last) {
+ chunks.add(e.data!);
+ if (e.last!) {
await service.streamCancel(EventStreams.kHeapSnapshot);
await streamSubscription.cancel();
completer.complete(HeapSnapshotGraph.fromChunks(chunks));
diff --git a/pkg/vm_service/lib/src/stream_helpers.dart b/pkg/vm_service/lib/src/stream_helpers.dart
index 474c417..b7b5515 100644
--- a/pkg/vm_service/lib/src/stream_helpers.dart
+++ b/pkg/vm_service/lib/src/stream_helpers.dart
@@ -35,12 +35,12 @@
? _next.asBroadcastStream()
: _next;
- StreamSubscription<T> subscription;
+ StreamSubscription<T>? subscription;
var currentStream = first;
var firstDone = false;
var secondDone = false;
- Function currentDoneHandler;
+ late Function currentDoneHandler;
listen() {
subscription = currentStream.listen(controller.add,
@@ -64,21 +64,22 @@
controller.onListen = () {
assert(subscription == null);
listen();
+ final sub = subscription!;
if (!first.isBroadcast) {
controller
..onPause = () {
- if (!firstDone || !next.isBroadcast) return subscription.pause();
- subscription.cancel();
+ if (!firstDone || !next.isBroadcast) return sub.pause();
+ sub.cancel();
subscription = null;
}
..onResume = () {
- if (!firstDone || !next.isBroadcast) return subscription.resume();
+ if (!firstDone || !next.isBroadcast) return sub.resume();
listen();
};
}
controller.onCancel = () {
if (secondDone) return null;
- var toCancel = subscription;
+ var toCancel = subscription!;
subscription = null;
return toCancel.cancel();
};
diff --git a/pkg/vm_service/lib/src/vm_service.dart b/pkg/vm_service/lib/src/vm_service.dart
index 446c5e4..12d1b61 100644
--- a/pkg/vm_service/lib/src/vm_service.dart
+++ b/pkg/vm_service/lib/src/vm_service.dart
@@ -12,8 +12,6 @@
import 'dart:convert' show base64, jsonDecode, jsonEncode, utf8;
import 'dart:typed_data';
-import 'package:meta/meta.dart';
-
import 'service_extension_registry.dart';
export 'service_extension_registry.dart' show ServiceExtensionRegistry;
@@ -41,13 +39,13 @@
bool _isNullInstance(Map json) =>
((json['type'] == '@Instance') && (json['kind'] == 'Null'));
-Object createServiceObject(dynamic json, List<String> expectedTypes) {
+Object? createServiceObject(dynamic json, List<String> expectedTypes) {
if (json == null) return null;
if (json is List) {
return json.map((e) => createServiceObject(e, expectedTypes)).toList();
} else if (json is Map) {
- String type = json['type'];
+ String? type = json['type'];
// Not a Response type.
if (type == null) {
@@ -62,10 +60,11 @@
// be returned.
return null;
}
- if (_typeFactories[type] == null) {
+ final typeFactory = _typeFactories[type];
+ if (typeFactory == null) {
return null;
} else {
- return _typeFactories[type](json);
+ return typeFactory(json);
}
} else {
// Handle simple types.
@@ -89,7 +88,7 @@
}
}
-void _setIfNotNull(Map<String, Object> json, String key, Object value) {
+void _setIfNotNull(Map<String, dynamic> json, String key, Object? value) {
if (value == null) return;
json[key] = value;
}
@@ -250,7 +249,7 @@
/// Handler for calling extra service extensions.
Future<Response> callServiceExtension(String method,
- {String isolateId, Map args});
+ {String? isolateId, Map<String, dynamic>? args});
/// The `addBreakpoint` RPC is used to add a breakpoint at a specific line of
/// some script.
@@ -284,7 +283,7 @@
String isolateId,
String scriptId,
int line, {
- int column,
+ int? column,
});
/// The `addBreakpoint` RPC is used to add a breakpoint at a specific line of
@@ -321,7 +320,7 @@
String isolateId,
String scriptUri,
int line, {
- int column,
+ int? column,
});
/// The `addBreakpointAtEntry` RPC is used to add a breakpoint at the
@@ -398,7 +397,7 @@
String targetId,
String selector,
List<String> argumentIds, {
- bool disableBreakpoints,
+ bool? disableBreakpoints,
});
/// The `evaluate` RPC is used to evaluate an expression in the context of
@@ -443,8 +442,8 @@
String isolateId,
String targetId,
String expression, {
- Map<String, String> scope,
- bool disableBreakpoints,
+ Map<String, String>? scope,
+ bool? disableBreakpoints,
});
/// The `evaluateInFrame` RPC is used to evaluate an expression in the context
@@ -481,8 +480,8 @@
String isolateId,
int frameIndex,
String expression, {
- Map<String, String> scope,
- bool disableBreakpoints,
+ Map<String, String>? scope,
+ bool? disableBreakpoints,
});
/// The `getAllocationProfile` RPC is used to retrieve allocation information
@@ -501,7 +500,7 @@
/// This method will throw a [SentinelException] in the case a [Sentinel] is
/// returned.
Future<AllocationProfile> getAllocationProfile(String isolateId,
- {bool reset, bool gc});
+ {bool? reset, bool? gc});
/// The `getClassList` RPC is used to retrieve a `ClassList` containing all
/// classes for an isolate based on the isolate's `isolateId`.
@@ -686,8 +685,8 @@
Future<Obj> getObject(
String isolateId,
String objectId, {
- int offset,
- int count,
+ int? offset,
+ int? count,
});
/// The `getPorts` RPC is used to retrieve the list of `ReceivePort` instances
@@ -746,7 +745,7 @@
///
/// This method will throw a [SentinelException] in the case a [Sentinel] is
/// returned.
- Future<Stack> getStack(String isolateId, {int limit});
+ Future<Stack> getStack(String isolateId, {int? limit});
/// The `getSupportedProtocols` RPC is used to determine which protocols are
/// supported by the current server.
@@ -801,10 +800,10 @@
String isolateId,
/*List<SourceReportKind>*/
List<String> reports, {
- String scriptId,
- int tokenPos,
- int endTokenPos,
- bool forceCompile,
+ String? scriptId,
+ int? tokenPos,
+ int? endTokenPos,
+ bool? forceCompile,
});
/// The `getVersion` RPC is used to determine what version of the Service
@@ -838,7 +837,8 @@
/// or Macos or Systrace, an [RPC error] with error code `114`, `invalid
/// timeline request`, will be returned as timeline events are handled by the
/// OS in these modes.
- Future<Timeline> getVMTimeline({int timeOriginMicros, int timeExtentMicros});
+ Future<Timeline> getVMTimeline(
+ {int? timeOriginMicros, int? timeExtentMicros});
/// The `getVMTimelineFlags` RPC returns information about the current VM
/// timeline configuration.
@@ -917,10 +917,10 @@
/// returned.
Future<ReloadReport> reloadSources(
String isolateId, {
- bool force,
- bool pause,
- String rootLibUri,
- String packagesUri,
+ bool? force,
+ bool? pause,
+ String? rootLibUri,
+ String? packagesUri,
});
/// The `removeBreakpoint` RPC is used to remove a breakpoint by its `id`.
@@ -981,7 +981,7 @@
/// This method will throw a [SentinelException] in the case a [Sentinel] is
/// returned.
Future<Success> resume(String isolateId,
- {/*StepOption*/ String step, int frameIndex});
+ {/*StepOption*/ String? step, int? frameIndex});
/// The `setExceptionPauseMode` RPC is used to control if an isolate pauses
/// when an exception is thrown.
@@ -1120,14 +1120,14 @@
}
class _PendingServiceRequest {
- Future<Map<String, Object>> get future => _completer.future;
- final _completer = Completer<Map<String, Object>>();
+ Future<Map<String, Object?>> get future => _completer.future;
+ final _completer = Completer<Map<String, Object?>>();
final dynamic originalId;
_PendingServiceRequest(this.originalId);
- void complete(Map<String, Object> response) {
+ void complete(Map<String, Object?> response) {
response['id'] = originalId;
_completer.complete(response);
}
@@ -1141,7 +1141,7 @@
/// instances.
class VmServerConnection {
final Stream<Map<String, Object>> _requestStream;
- final StreamSink<Map<String, Object>> _responseSink;
+ final StreamSink<Map<String, Object?>> _responseSink;
final ServiceExtensionRegistry _serviceExtensionRegistry;
final VmServiceInterface _serviceImplementation;
@@ -1152,8 +1152,8 @@
final _streamSubscriptions = <String, StreamSubscription>{};
/// Completes when [_requestStream] is done.
- Future get done => _doneCompleter.future;
- final _doneCompleter = Completer<Null>();
+ Future<void> get done => _doneCompleter.future;
+ final _doneCompleter = Completer<void>();
/// Pending service extension requests to this client by id.
final _pendingServiceExtensionRequests = <dynamic, _PendingServiceRequest>{};
@@ -1170,13 +1170,13 @@
///
/// We don't attempt to do any serialization or deserialization of the
/// request or response in this case
- Future<Map<String, Object>> _forwardServiceExtensionRequest(
- Map<String, Object> request) {
- var originalId = request['id'];
- request = Map.of(request);
+ Future<Map<String, Object?>> _forwardServiceExtensionRequest(
+ Map<String, Object?> request) {
+ final originalId = request['id'];
+ request = Map<String, Object?>.of(request);
// Modify the request ID to ensure we don't have conflicts between
// multiple clients ids.
- var newId = '${_nextServiceRequestId++}:$originalId';
+ final newId = '${_nextServiceRequestId++}:$originalId';
request['id'] = newId;
var pendingRequest = _PendingServiceRequest(originalId);
_pendingServiceExtensionRequests[newId] = pendingRequest;
@@ -1184,31 +1184,31 @@
return pendingRequest.future;
}
- void _delegateRequest(Map<String, Object> request) async {
+ void _delegateRequest(Map<String, Object?> request) async {
try {
var id = request['id'];
// Check if this is actually a response to a pending request.
if (_pendingServiceExtensionRequests.containsKey(id)) {
- final pending = _pendingServiceExtensionRequests[id];
- pending.complete(Map.of(request));
+ final pending = _pendingServiceExtensionRequests[id]!;
+ pending.complete(Map<String, Object?>.of(request));
return;
}
- var method = request['method'] as String;
+ final method = request['method'] as String?;
if (method == null) {
throw RPCError(
null, RPCError.kInvalidRequest, 'Invalid Request', request);
}
- var params = request['params'] as Map;
- Response response;
+ final params = request['params'] as Map<String, dynamic>?;
+ late Response response;
switch (method) {
case 'registerService':
- _serviceExtensionRegistry.registerExtension(params['service'], this);
+ _serviceExtensionRegistry.registerExtension(params!['service'], this);
response = Success();
break;
case 'addBreakpoint':
response = await _serviceImplementation.addBreakpoint(
- params['isolateId'],
+ params!['isolateId'],
params['scriptId'],
params['line'],
column: params['column'],
@@ -1216,7 +1216,7 @@
break;
case 'addBreakpointWithScriptUri':
response = await _serviceImplementation.addBreakpointWithScriptUri(
- params['isolateId'],
+ params!['isolateId'],
params['scriptUri'],
params['line'],
column: params['column'],
@@ -1224,13 +1224,13 @@
break;
case 'addBreakpointAtEntry':
response = await _serviceImplementation.addBreakpointAtEntry(
- params['isolateId'],
+ params!['isolateId'],
params['functionId'],
);
break;
case 'clearCpuSamples':
response = await _serviceImplementation.clearCpuSamples(
- params['isolateId'],
+ params!['isolateId'],
);
break;
case 'clearVMTimeline':
@@ -1238,7 +1238,7 @@
break;
case 'invoke':
response = await _serviceImplementation.invoke(
- params['isolateId'],
+ params!['isolateId'],
params['targetId'],
params['selector'],
List<String>.from(params['argumentIds'] ?? []),
@@ -1247,7 +1247,7 @@
break;
case 'evaluate':
response = await _serviceImplementation.evaluate(
- params['isolateId'],
+ params!['isolateId'],
params['targetId'],
params['expression'],
scope: params['scope']?.cast<String, String>(),
@@ -1256,7 +1256,7 @@
break;
case 'evaluateInFrame':
response = await _serviceImplementation.evaluateInFrame(
- params['isolateId'],
+ params!['isolateId'],
params['frameIndex'],
params['expression'],
scope: params['scope']?.cast<String, String>(),
@@ -1265,19 +1265,19 @@
break;
case 'getAllocationProfile':
response = await _serviceImplementation.getAllocationProfile(
- params['isolateId'],
+ params!['isolateId'],
reset: params['reset'],
gc: params['gc'],
);
break;
case 'getClassList':
response = await _serviceImplementation.getClassList(
- params['isolateId'],
+ params!['isolateId'],
);
break;
case 'getCpuSamples':
response = await _serviceImplementation.getCpuSamples(
- params['isolateId'],
+ params!['isolateId'],
params['timeOriginMicros'],
params['timeExtentMicros'],
);
@@ -1287,46 +1287,46 @@
break;
case 'getInboundReferences':
response = await _serviceImplementation.getInboundReferences(
- params['isolateId'],
+ params!['isolateId'],
params['targetId'],
params['limit'],
);
break;
case 'getInstances':
response = await _serviceImplementation.getInstances(
- params['isolateId'],
+ params!['isolateId'],
params['objectId'],
params['limit'],
);
break;
case 'getIsolate':
response = await _serviceImplementation.getIsolate(
- params['isolateId'],
+ params!['isolateId'],
);
break;
case 'getIsolateGroup':
response = await _serviceImplementation.getIsolateGroup(
- params['isolateGroupId'],
+ params!['isolateGroupId'],
);
break;
case 'getMemoryUsage':
response = await _serviceImplementation.getMemoryUsage(
- params['isolateId'],
+ params!['isolateId'],
);
break;
case 'getIsolateGroupMemoryUsage':
response = await _serviceImplementation.getIsolateGroupMemoryUsage(
- params['isolateGroupId'],
+ params!['isolateGroupId'],
);
break;
case 'getScripts':
response = await _serviceImplementation.getScripts(
- params['isolateId'],
+ params!['isolateId'],
);
break;
case 'getObject':
response = await _serviceImplementation.getObject(
- params['isolateId'],
+ params!['isolateId'],
params['objectId'],
offset: params['offset'],
count: params['count'],
@@ -1334,12 +1334,12 @@
break;
case 'getPorts':
response = await _serviceImplementation.getPorts(
- params['isolateId'],
+ params!['isolateId'],
);
break;
case 'getRetainingPath':
response = await _serviceImplementation.getRetainingPath(
- params['isolateId'],
+ params!['isolateId'],
params['targetId'],
params['limit'],
);
@@ -1349,7 +1349,7 @@
break;
case 'getStack':
response = await _serviceImplementation.getStack(
- params['isolateId'],
+ params!['isolateId'],
limit: params['limit'],
);
break;
@@ -1358,7 +1358,7 @@
break;
case 'getSourceReport':
response = await _serviceImplementation.getSourceReport(
- params['isolateId'],
+ params!['isolateId'],
List<String>.from(params['reports'] ?? []),
scriptId: params['scriptId'],
tokenPos: params['tokenPos'],
@@ -1374,7 +1374,7 @@
break;
case 'getVMTimeline':
response = await _serviceImplementation.getVMTimeline(
- timeOriginMicros: params['timeOriginMicros'],
+ timeOriginMicros: params!['timeOriginMicros'],
timeExtentMicros: params['timeExtentMicros'],
);
break;
@@ -1386,17 +1386,17 @@
break;
case 'pause':
response = await _serviceImplementation.pause(
- params['isolateId'],
+ params!['isolateId'],
);
break;
case 'kill':
response = await _serviceImplementation.kill(
- params['isolateId'],
+ params!['isolateId'],
);
break;
case 'reloadSources':
response = await _serviceImplementation.reloadSources(
- params['isolateId'],
+ params!['isolateId'],
force: params['force'],
pause: params['pause'],
rootLibUri: params['rootLibUri'],
@@ -1405,59 +1405,59 @@
break;
case 'removeBreakpoint':
response = await _serviceImplementation.removeBreakpoint(
- params['isolateId'],
+ params!['isolateId'],
params['breakpointId'],
);
break;
case 'requestHeapSnapshot':
response = await _serviceImplementation.requestHeapSnapshot(
- params['isolateId'],
+ params!['isolateId'],
);
break;
case 'resume':
response = await _serviceImplementation.resume(
- params['isolateId'],
+ params!['isolateId'],
step: params['step'],
frameIndex: params['frameIndex'],
);
break;
case 'setExceptionPauseMode':
response = await _serviceImplementation.setExceptionPauseMode(
- params['isolateId'],
+ params!['isolateId'],
params['mode'],
);
break;
case 'setFlag':
response = await _serviceImplementation.setFlag(
- params['name'],
+ params!['name'],
params['value'],
);
break;
case 'setLibraryDebuggable':
response = await _serviceImplementation.setLibraryDebuggable(
- params['isolateId'],
+ params!['isolateId'],
params['libraryId'],
params['isDebuggable'],
);
break;
case 'setName':
response = await _serviceImplementation.setName(
- params['isolateId'],
+ params!['isolateId'],
params['name'],
);
break;
case 'setVMName':
response = await _serviceImplementation.setVMName(
- params['name'],
+ params!['name'],
);
break;
case 'setVMTimelineFlags':
response = await _serviceImplementation.setVMTimelineFlags(
- List<String>.from(params['recordedStreams'] ?? []),
+ List<String>.from(params!['recordedStreams'] ?? []),
);
break;
case 'streamCancel':
- var id = params['streamId'];
+ var id = params!['streamId'];
var existing = _streamSubscriptions.remove(id);
if (existing == null) {
throw RPCError.withDetails(
@@ -1471,7 +1471,7 @@
response = Success();
break;
case 'streamListen':
- var id = params['streamId'];
+ var id = params!['streamId'];
if (_streamSubscriptions.containsKey(id)) {
throw RPCError.withDetails(
'streamListen',
@@ -1497,7 +1497,7 @@
response = Success();
break;
default:
- var registeredClient = _serviceExtensionRegistry.clientFor(method);
+ final registeredClient = _serviceExtensionRegistry.clientFor(method);
if (registeredClient != null) {
// Check for any client which has registered this extension, if we
// have one then delegate the request to that client.
@@ -1509,8 +1509,9 @@
} else if (method.startsWith('ext.')) {
// Remaining methods with `ext.` are assumed to be registered via
// dart:developer, which the service implementation handles.
- var args = params == null ? null : Map.of(params);
- var isolateId = args?.remove('isolateId');
+ final args =
+ params == null ? null : Map<String, dynamic>.of(params);
+ final isolateId = args?.remove('isolateId');
response = await _serviceImplementation.callServiceExtension(method,
isolateId: isolateId, args: args);
} else {
@@ -1518,16 +1519,13 @@
method, RPCError.kMethodNotFound, 'Method not found', request);
}
}
- if (response == null) {
- throw StateError('Invalid null response from service');
- }
_responseSink.add({
'jsonrpc': '2.0',
'id': id,
'result': response.toJson(),
});
} catch (e, st) {
- var error = e is RPCError
+ final error = e is RPCError
? e.toMap()
: {
'code': RPCError.kInternalError,
@@ -1544,13 +1542,13 @@
}
class VmService implements VmServiceInterface {
- StreamSubscription _streamSub;
- Function _writeMessage;
+ late final StreamSubscription _streamSub;
+ late final Function _writeMessage;
int _id = 0;
Map<String, Completer> _completers = {};
Map<String, String> _methodCalls = {};
Map<String, ServiceCallback> _services = {};
- Log _log;
+ late final Log _log;
StreamController<String> _onSend = StreamController.broadcast(sync: true);
StreamController<String> _onReceive = StreamController.broadcast(sync: true);
@@ -1560,7 +1558,7 @@
Map<String, StreamController<Event>> _eventControllers = {};
StreamController<Event> _getEventController(String eventName) {
- StreamController<Event> controller = _eventControllers[eventName];
+ StreamController<Event>? controller = _eventControllers[eventName];
if (controller == null) {
controller = StreamController.broadcast();
_eventControllers[eventName] = controller;
@@ -1568,14 +1566,14 @@
return controller;
}
- DisposeHandler _disposeHandler;
+ late final DisposeHandler? _disposeHandler;
VmService(
Stream<dynamic> /*String|List<int>*/ inStream,
void writeMessage(String message), {
- Log log,
- DisposeHandler disposeHandler,
- Future streamClosed,
+ Log? log,
+ DisposeHandler? disposeHandler,
+ Future? streamClosed,
}) {
_streamSub = inStream.listen(_processMessage,
onDone: () => _onDoneCompleter.complete());
@@ -1632,7 +1630,7 @@
String isolateId,
String scriptId,
int line, {
- int column,
+ int? column,
}) =>
_call('addBreakpoint', {
'isolateId': isolateId,
@@ -1646,7 +1644,7 @@
String isolateId,
String scriptUri,
int line, {
- int column,
+ int? column,
}) =>
_call('addBreakpointWithScriptUri', {
'isolateId': isolateId,
@@ -1674,7 +1672,7 @@
String targetId,
String selector,
List<String> argumentIds, {
- bool disableBreakpoints,
+ bool? disableBreakpoints,
}) =>
_call('invoke', {
'isolateId': isolateId,
@@ -1690,8 +1688,8 @@
String isolateId,
String targetId,
String expression, {
- Map<String, String> scope,
- bool disableBreakpoints,
+ Map<String, String>? scope,
+ bool? disableBreakpoints,
}) =>
_call('evaluate', {
'isolateId': isolateId,
@@ -1707,8 +1705,8 @@
String isolateId,
int frameIndex,
String expression, {
- Map<String, String> scope,
- bool disableBreakpoints,
+ Map<String, String>? scope,
+ bool? disableBreakpoints,
}) =>
_call('evaluateInFrame', {
'isolateId': isolateId,
@@ -1721,7 +1719,7 @@
@override
Future<AllocationProfile> getAllocationProfile(String isolateId,
- {bool reset, bool gc}) =>
+ {bool? reset, bool? gc}) =>
_call('getAllocationProfile', {
'isolateId': isolateId,
if (reset != null && reset) 'reset': reset,
@@ -1780,8 +1778,8 @@
Future<Obj> getObject(
String isolateId,
String objectId, {
- int offset,
- int count,
+ int? offset,
+ int? count,
}) =>
_call('getObject', {
'isolateId': isolateId,
@@ -1805,7 +1803,7 @@
_call('getProcessMemoryUsage');
@override
- Future<Stack> getStack(String isolateId, {int limit}) => _call('getStack', {
+ Future<Stack> getStack(String isolateId, {int? limit}) => _call('getStack', {
'isolateId': isolateId,
if (limit != null) 'limit': limit,
});
@@ -1819,10 +1817,10 @@
String isolateId,
/*List<SourceReportKind>*/
List<String> reports, {
- String scriptId,
- int tokenPos,
- int endTokenPos,
- bool forceCompile,
+ String? scriptId,
+ int? tokenPos,
+ int? endTokenPos,
+ bool? forceCompile,
}) =>
_call('getSourceReport', {
'isolateId': isolateId,
@@ -1841,7 +1839,7 @@
@override
Future<Timeline> getVMTimeline(
- {int timeOriginMicros, int timeExtentMicros}) =>
+ {int? timeOriginMicros, int? timeExtentMicros}) =>
_call('getVMTimeline', {
if (timeOriginMicros != null) 'timeOriginMicros': timeOriginMicros,
if (timeExtentMicros != null) 'timeExtentMicros': timeExtentMicros,
@@ -1868,10 +1866,10 @@
@override
Future<ReloadReport> reloadSources(
String isolateId, {
- bool force,
- bool pause,
- String rootLibUri,
- String packagesUri,
+ bool? force,
+ bool? pause,
+ String? rootLibUri,
+ String? packagesUri,
}) =>
_call('reloadSources', {
'isolateId': isolateId,
@@ -1892,7 +1890,7 @@
@override
Future<Success> resume(String isolateId,
- {/*StepOption*/ String step, int frameIndex}) =>
+ {/*StepOption*/ String? step, int? frameIndex}) =>
_call('resume', {
'isolateId': isolateId,
if (step != null) 'step': step,
@@ -1938,7 +1936,8 @@
/// Call an arbitrary service protocol method. This allows clients to call
/// methods not explicitly exposed by this library.
- Future<Response> callMethod(String method, {String isolateId, Map args}) {
+ Future<Response> callMethod(String method,
+ {String? isolateId, Map<String, dynamic>? args}) {
return callServiceExtension(method, isolateId: isolateId, args: args);
}
@@ -1947,11 +1946,11 @@
/// See https://api.dart.dev/stable/dart-developer/dart-developer-library.html.
@override
Future<Response> callServiceExtension(String method,
- {String isolateId, Map args}) {
+ {String? isolateId, Map<String, dynamic>? args}) {
if (args == null && isolateId == null) {
return _call(method);
} else if (args == null) {
- return _call(method, {'isolateId': isolateId});
+ return _call(method, {'isolateId': isolateId!});
} else {
args = Map.from(args);
if (isolateId != null) {
@@ -1974,7 +1973,7 @@
});
_completers.clear();
if (_disposeHandler != null) {
- await _disposeHandler();
+ await _disposeHandler!();
}
if (!_onDoneCompleter.isCompleted) {
_onDoneCompleter.complete();
@@ -2032,22 +2031,21 @@
bytes.buffer, bytes.offsetInBytes + metaOffset, metaLength));
final data = ByteData.view(
bytes.buffer, bytes.offsetInBytes + dataOffset, dataLength);
- dynamic map = jsonDecode(meta);
- if (map != null && map['method'] == 'streamNotify') {
+ dynamic map = jsonDecode(meta)!;
+ if (map['method'] == 'streamNotify') {
String streamId = map['params']['streamId'];
Map event = map['params']['event'];
event['data'] = data;
_getEventController(streamId)
- .add(createServiceObject(event, const ['Event']));
+ .add(createServiceObject(event, const ['Event'])! as Event);
}
}
void _processMessageStr(String message) {
- var json;
+ late Map<String, dynamic> json;
try {
_onReceive.add(message);
-
- json = jsonDecode(message);
+ json = jsonDecode(message)!;
} catch (e, s) {
_log.severe('unable to decode message: ${message}, ${e}\n${s}');
return;
@@ -2068,9 +2066,9 @@
}
void _processResponse(Map<String, dynamic> json) {
- Completer completer = _completers.remove(json['id']);
- String methodName = _methodCalls.remove(json['id']);
- List<String> returnTypes = _methodReturnTypes[methodName];
+ Completer? completer = _completers.remove(json['id']);
+ String methodName = _methodCalls.remove(json['id'])!;
+ List<String> returnTypes = _methodReturnTypes[methodName] ?? [];
if (completer == null) {
_log.severe('unmatched request response: ${jsonEncode(json)}');
} else if (json['error'] != null) {
@@ -2100,25 +2098,26 @@
Future _processNotification(Map<String, dynamic> json) async {
final String method = json['method'];
- final Map params = json['params'] ?? <String, dynamic>{};
+ final Map<String, dynamic> params = json['params'] ?? <String, dynamic>{};
if (method == 'streamNotify') {
String streamId = params['streamId'];
_getEventController(streamId)
- .add(createServiceObject(params['event'], const ['Event']));
+ .add(createServiceObject(params['event'], const ['Event'])! as Event);
} else {
await _routeRequest(method, params);
}
}
Future<Map> _routeRequest(String method, Map<String, dynamic> params) async {
- if (!_services.containsKey(method)) {
+ final service = _services[method];
+ if (service == null) {
RPCError error = RPCError(
method, RPCError.kMethodNotFound, 'method not found \'$method\'');
return {'error': error.toMap()};
}
try {
- return await _services[method](params);
+ return await service(params);
} catch (e, st) {
RPCError error = RPCError.withDetails(
method,
@@ -2153,22 +2152,22 @@
return RPCError(callingMethod, json['code'], json['message'], json['data']);
}
- final String callingMethod;
+ final String? callingMethod;
final int code;
final String message;
- final Map data;
+ final Map? data;
RPCError(this.callingMethod, this.code, this.message, [this.data]);
RPCError.withDetails(this.callingMethod, this.code, this.message,
- {Object details})
+ {Object? details})
: data = details == null ? null : <String, dynamic>{} {
if (details != null) {
- data['details'] = details;
+ data!['details'] = details;
}
}
- String get details => data == null ? null : data['details'];
+ String? get details => data == null ? null : data!['details'];
/// Return a map representation of this error suitable for converstion to
/// json.
@@ -2198,17 +2197,17 @@
final Sentinel sentinel;
SentinelException.parse(this.callingMethod, Map<String, dynamic> data)
- : sentinel = Sentinel.parse(data);
+ : sentinel = Sentinel.parse(data)!;
String toString() => '$sentinel from ${callingMethod}()';
}
/// An `ExtensionData` is an arbitrary map that can have any contents.
class ExtensionData {
- static ExtensionData parse(Map json) =>
+ static ExtensionData? parse(Map<String, dynamic>? json) =>
json == null ? null : ExtensionData._fromJson(json);
- final Map data;
+ final Map<String, dynamic> data;
ExtensionData() : data = {};
@@ -2535,30 +2534,30 @@
// types
class AllocationProfile extends Response {
- static AllocationProfile parse(Map<String, dynamic> json) =>
+ static AllocationProfile? parse(Map<String, dynamic>? json) =>
json == null ? null : AllocationProfile._fromJson(json);
/// Allocation information for all class types.
- List<ClassHeapStats> members;
+ late final List<ClassHeapStats> members;
/// Information about memory usage for the isolate.
- MemoryUsage memoryUsage;
+ late final MemoryUsage memoryUsage;
/// The timestamp of the last accumulator reset.
///
/// If the accumulators have not been reset, this field is not present.
@optional
- int dateLastAccumulatorReset;
+ late final int? dateLastAccumulatorReset;
/// The timestamp of the last manually triggered GC.
///
/// If a GC has not been triggered manually, this field is not present.
@optional
- int dateLastServiceGC;
+ late final int? dateLastServiceGC;
AllocationProfile({
- @required this.members,
- @required this.memoryUsage,
+ required this.members,
+ required this.memoryUsage,
this.dateLastAccumulatorReset,
this.dateLastServiceGC,
});
@@ -2566,9 +2565,12 @@
AllocationProfile._fromJson(Map<String, dynamic> json)
: super._fromJson(json) {
members = List<ClassHeapStats>.from(
- createServiceObject(json['members'], const ['ClassHeapStats']) ?? []);
+ createServiceObject(json['members'], const ['ClassHeapStats'])
+ as List? ??
+ []);
memoryUsage =
- createServiceObject(json['memoryUsage'], const ['MemoryUsage']);
+ createServiceObject(json['memoryUsage']!, const ['MemoryUsage'])
+ as MemoryUsage;
dateLastAccumulatorReset = json['dateLastAccumulatorReset'] is String
? int.parse(json['dateLastAccumulatorReset'])
: json['dateLastAccumulatorReset'];
@@ -2578,9 +2580,12 @@
}
@override
+ String get type => 'AllocationProfile';
+
+ @override
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
- json['type'] = 'AllocationProfile';
+ final json = <String, dynamic>{};
+ json['type'] = type;
json.addAll({
'members': members.map((f) => f.toJson()).toList(),
'memoryUsage': memoryUsage.toJson(),
@@ -2590,8 +2595,8 @@
return json;
}
- String toString() => '[AllocationProfile ' //
- 'type: ${type}, members: ${members}, memoryUsage: ${memoryUsage}]';
+ String toString() =>
+ '[AllocationProfile members: ${members}, memoryUsage: ${memoryUsage}]';
}
/// A `BoundField` represents a field bound to a particular value in an
@@ -2603,27 +2608,28 @@
/// If the field is being initialized, the `value` will be the
/// `BeingInitialized` [Sentinel].
class BoundField {
- static BoundField parse(Map<String, dynamic> json) =>
+ static BoundField? parse(Map<String, dynamic>? json) =>
json == null ? null : BoundField._fromJson(json);
- FieldRef decl;
+ late final FieldRef decl;
/// [value] can be one of [InstanceRef] or [Sentinel].
- dynamic value;
+ late final dynamic value;
BoundField({
- @required this.decl,
- @required this.value,
+ required this.decl,
+ required this.value,
});
BoundField._fromJson(Map<String, dynamic> json) {
- decl = createServiceObject(json['decl'], const ['FieldRef']);
+ decl = createServiceObject(json['decl']!, const ['FieldRef']) as FieldRef;
value =
- createServiceObject(json['value'], const ['InstanceRef', 'Sentinel']);
+ createServiceObject(json['value']!, const ['InstanceRef', 'Sentinel'])
+ as dynamic;
}
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
+ final json = <String, dynamic>{};
json.addAll({
'decl': decl.toJson(),
'value': value.toJson(),
@@ -2646,44 +2652,47 @@
/// If the variable has been optimized out by the compiler, the `value` will be
/// the `OptimizedOut` [Sentinel].
class BoundVariable extends Response {
- static BoundVariable parse(Map<String, dynamic> json) =>
+ static BoundVariable? parse(Map<String, dynamic>? json) =>
json == null ? null : BoundVariable._fromJson(json);
- String name;
+ late final String name;
/// [value] can be one of [InstanceRef], [TypeArgumentsRef] or [Sentinel].
- dynamic value;
+ late final dynamic value;
/// The token position where this variable was declared.
- int declarationTokenPos;
+ late final int declarationTokenPos;
/// The first token position where this variable is visible to the scope.
- int scopeStartTokenPos;
+ late final int scopeStartTokenPos;
/// The last token position where this variable is visible to the scope.
- int scopeEndTokenPos;
+ late final int scopeEndTokenPos;
BoundVariable({
- @required this.name,
- @required this.value,
- @required this.declarationTokenPos,
- @required this.scopeStartTokenPos,
- @required this.scopeEndTokenPos,
+ required this.name,
+ required this.value,
+ required this.declarationTokenPos,
+ required this.scopeStartTokenPos,
+ required this.scopeEndTokenPos,
});
BoundVariable._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
- name = json['name'];
- value = createServiceObject(
- json['value'], const ['InstanceRef', 'TypeArgumentsRef', 'Sentinel']);
- declarationTokenPos = json['declarationTokenPos'];
- scopeStartTokenPos = json['scopeStartTokenPos'];
- scopeEndTokenPos = json['scopeEndTokenPos'];
+ name = json['name'] ?? '';
+ value = createServiceObject(json['value']!,
+ const ['InstanceRef', 'TypeArgumentsRef', 'Sentinel']) as dynamic;
+ declarationTokenPos = json['declarationTokenPos'] ?? -1;
+ scopeStartTokenPos = json['scopeStartTokenPos'] ?? -1;
+ scopeEndTokenPos = json['scopeEndTokenPos'] ?? -1;
}
@override
+ String get type => 'BoundVariable';
+
+ @override
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
- json['type'] = 'BoundVariable';
+ final json = <String, dynamic>{};
+ json['type'] = type;
json.addAll({
'name': name,
'value': value.toJson(),
@@ -2695,7 +2704,7 @@
}
String toString() => '[BoundVariable ' //
- 'type: ${type}, name: ${name}, value: ${value}, declarationTokenPos: ${declarationTokenPos}, ' //
+ 'name: ${name}, value: ${value}, declarationTokenPos: ${declarationTokenPos}, ' //
'scopeStartTokenPos: ${scopeStartTokenPos}, scopeEndTokenPos: ${scopeEndTokenPos}]';
}
@@ -2706,46 +2715,51 @@
/// yet been compiled or in a library which has not been loaded (i.e. a deferred
/// library).
class Breakpoint extends Obj {
- static Breakpoint parse(Map<String, dynamic> json) =>
+ static Breakpoint? parse(Map<String, dynamic>? json) =>
json == null ? null : Breakpoint._fromJson(json);
/// A number identifying this breakpoint to the user.
- int breakpointNumber;
+ late final int breakpointNumber;
/// Has this breakpoint been assigned to a specific program location?
- bool resolved;
+ late final bool resolved;
/// Is this a breakpoint that was added synthetically as part of a step
/// OverAsyncSuspension resume command?
@optional
- bool isSyntheticAsyncContinuation;
+ late final bool? isSyntheticAsyncContinuation;
/// SourceLocation when breakpoint is resolved, UnresolvedSourceLocation when
/// a breakpoint is not resolved.
///
/// [location] can be one of [SourceLocation] or [UnresolvedSourceLocation].
- dynamic location;
+ late final dynamic location;
Breakpoint({
- @required this.breakpointNumber,
- @required this.resolved,
- @required this.location,
- @required String id,
+ required this.breakpointNumber,
+ required this.resolved,
+ required this.location,
+ required String id,
this.isSyntheticAsyncContinuation,
- }) : super(id: id);
+ }) : super(
+ id: id,
+ );
Breakpoint._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
- breakpointNumber = json['breakpointNumber'];
- resolved = json['resolved'];
+ breakpointNumber = json['breakpointNumber'] ?? -1;
+ resolved = json['resolved'] ?? false;
isSyntheticAsyncContinuation = json['isSyntheticAsyncContinuation'];
- location = createServiceObject(
- json['location'], const ['SourceLocation', 'UnresolvedSourceLocation']);
+ location = createServiceObject(json['location']!,
+ const ['SourceLocation', 'UnresolvedSourceLocation']) as dynamic;
}
@override
+ String get type => 'Breakpoint';
+
+ @override
Map<String, dynamic> toJson() {
- var json = super.toJson();
- json['type'] = 'Breakpoint';
+ final json = super.toJson();
+ json['type'] = type;
json.addAll({
'breakpointNumber': breakpointNumber,
'resolved': resolved,
@@ -2761,31 +2775,36 @@
operator ==(other) => other is Breakpoint && id == other.id;
String toString() => '[Breakpoint ' //
- 'type: ${type}, id: ${id}, breakpointNumber: ${breakpointNumber}, ' //
- 'resolved: ${resolved}, location: ${location}]';
+ 'id: ${id}, breakpointNumber: ${breakpointNumber}, resolved: ${resolved}, ' //
+ 'location: ${location}]';
}
/// `ClassRef` is a reference to a `Class`.
class ClassRef extends ObjRef {
- static ClassRef parse(Map<String, dynamic> json) =>
+ static ClassRef? parse(Map<String, dynamic>? json) =>
json == null ? null : ClassRef._fromJson(json);
/// The name of this class.
- String name;
+ late final String name;
ClassRef({
- @required this.name,
- @required String id,
- }) : super(id: id);
+ required this.name,
+ required String id,
+ }) : super(
+ id: id,
+ );
ClassRef._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
- name = json['name'];
+ name = json['name'] ?? '';
}
@override
+ String get type => 'ClassRef';
+
+ @override
Map<String, dynamic> toJson() {
- var json = super.toJson();
- json['type'] = '@Class';
+ final json = super.toJson();
+ json['type'] = type;
json.addAll({
'name': name,
});
@@ -2796,106 +2815,120 @@
operator ==(other) => other is ClassRef && id == other.id;
- String toString() => '[ClassRef type: ${type}, id: ${id}, name: ${name}]';
+ String toString() => '[ClassRef id: ${id}, name: ${name}]';
}
/// A `Class` provides information about a Dart language class.
class Class extends Obj implements ClassRef {
- static Class parse(Map<String, dynamic> json) =>
+ static Class? parse(Map<String, dynamic>? json) =>
json == null ? null : Class._fromJson(json);
/// The name of this class.
- String name;
+ late final String name;
/// The error which occurred during class finalization, if it exists.
@optional
- ErrorRef error;
+ late final ErrorRef? error;
/// Is this an abstract class?
- bool isAbstract;
+ late final bool isAbstract;
/// Is this a const class?
- bool isConst;
+ late final bool isConst;
/// The library which contains this class.
- LibraryRef library;
+ late final LibraryRef library;
/// The location of this class in the source code.
@optional
- SourceLocation location;
+ late final SourceLocation? location;
/// The superclass of this class, if any.
@optional
- ClassRef superClass;
+ late final ClassRef? superClass;
/// The supertype for this class, if any.
///
/// The value will be of the kind: Type.
@optional
- InstanceRef superType;
+ late final InstanceRef? superType;
/// A list of interface types for this class.
///
/// The values will be of the kind: Type.
- List<InstanceRef> interfaces;
+ late final List<InstanceRef> interfaces;
/// The mixin type for this class, if any.
///
/// The value will be of the kind: Type.
@optional
- InstanceRef mixin;
+ late final InstanceRef? mixin;
/// A list of fields in this class. Does not include fields from superclasses.
- List<FieldRef> fields;
+ late final List<FieldRef> fields;
/// A list of functions in this class. Does not include functions from
/// superclasses.
- List<FuncRef> functions;
+ late final List<FuncRef> functions;
/// A list of subclasses of this class.
- List<ClassRef> subclasses;
+ late final List<ClassRef> subclasses;
Class({
- @required this.name,
- @required this.isAbstract,
- @required this.isConst,
- @required this.library,
- @required this.interfaces,
- @required this.fields,
- @required this.functions,
- @required this.subclasses,
- @required String id,
+ required this.name,
+ required this.isAbstract,
+ required this.isConst,
+ required this.library,
+ required this.interfaces,
+ required this.fields,
+ required this.functions,
+ required this.subclasses,
+ required String id,
this.error,
this.location,
this.superClass,
this.superType,
this.mixin,
- }) : super(id: id);
+ }) : super(
+ id: id,
+ );
Class._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
- name = json['name'];
- error = createServiceObject(json['error'], const ['ErrorRef']);
- isAbstract = json['abstract'];
- isConst = json['const'];
- library = createServiceObject(json['library'], const ['LibraryRef']);
- location = createServiceObject(json['location'], const ['SourceLocation']);
- superClass = createServiceObject(json['super'], const ['ClassRef']);
- superType = createServiceObject(json['superType'], const ['InstanceRef']);
+ name = json['name'] ?? '';
+ error = createServiceObject(json['error'], const ['ErrorRef']) as ErrorRef?;
+ isAbstract = json['abstract'] ?? false;
+ isConst = json['const'] ?? false;
+ library = createServiceObject(json['library']!, const ['LibraryRef'])
+ as LibraryRef;
+ location = createServiceObject(json['location'], const ['SourceLocation'])
+ as SourceLocation?;
+ superClass =
+ createServiceObject(json['super'], const ['ClassRef']) as ClassRef?;
+ superType = createServiceObject(json['superType'], const ['InstanceRef'])
+ as InstanceRef?;
interfaces = List<InstanceRef>.from(
- createServiceObject(json['interfaces'], const ['InstanceRef']) ?? []);
- mixin = createServiceObject(json['mixin'], const ['InstanceRef']);
+ createServiceObject(json['interfaces'], const ['InstanceRef'])
+ as List? ??
+ []);
+ mixin = createServiceObject(json['mixin'], const ['InstanceRef'])
+ as InstanceRef?;
fields = List<FieldRef>.from(
- createServiceObject(json['fields'], const ['FieldRef']) ?? []);
+ createServiceObject(json['fields'], const ['FieldRef']) as List? ?? []);
functions = List<FuncRef>.from(
- createServiceObject(json['functions'], const ['FuncRef']) ?? []);
+ createServiceObject(json['functions'], const ['FuncRef']) as List? ??
+ []);
subclasses = List<ClassRef>.from(
- createServiceObject(json['subclasses'], const ['ClassRef']) ?? []);
+ createServiceObject(json['subclasses'], const ['ClassRef']) as List? ??
+ []);
}
@override
+ String get type => 'Class';
+
+ @override
Map<String, dynamic> toJson() {
- var json = super.toJson();
- json['type'] = 'Class';
+ final json = super.toJson();
+ json['type'] = type;
json.addAll({
'name': name,
'abstract': isAbstract,
@@ -2922,46 +2955,50 @@
}
class ClassHeapStats extends Response {
- static ClassHeapStats parse(Map<String, dynamic> json) =>
+ static ClassHeapStats? parse(Map<String, dynamic>? json) =>
json == null ? null : ClassHeapStats._fromJson(json);
/// The class for which this memory information is associated.
- ClassRef classRef;
+ late final ClassRef classRef;
/// The number of bytes allocated for instances of class since the accumulator
/// was last reset.
- int accumulatedSize;
+ late final int accumulatedSize;
/// The number of bytes currently allocated for instances of class.
- int bytesCurrent;
+ late final int bytesCurrent;
/// The number of instances of class which have been allocated since the
/// accumulator was last reset.
- int instancesAccumulated;
+ late final int instancesAccumulated;
/// The number of instances of class which are currently alive.
- int instancesCurrent;
+ late final int instancesCurrent;
ClassHeapStats({
- @required this.classRef,
- @required this.accumulatedSize,
- @required this.bytesCurrent,
- @required this.instancesAccumulated,
- @required this.instancesCurrent,
+ required this.classRef,
+ required this.accumulatedSize,
+ required this.bytesCurrent,
+ required this.instancesAccumulated,
+ required this.instancesCurrent,
});
ClassHeapStats._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
- classRef = createServiceObject(json['class'], const ['ClassRef']);
- accumulatedSize = json['accumulatedSize'];
- bytesCurrent = json['bytesCurrent'];
- instancesAccumulated = json['instancesAccumulated'];
- instancesCurrent = json['instancesCurrent'];
+ classRef =
+ createServiceObject(json['class']!, const ['ClassRef']) as ClassRef;
+ accumulatedSize = json['accumulatedSize'] ?? -1;
+ bytesCurrent = json['bytesCurrent'] ?? -1;
+ instancesAccumulated = json['instancesAccumulated'] ?? -1;
+ instancesCurrent = json['instancesCurrent'] ?? -1;
}
@override
+ String get type => 'ClassHeapStats';
+
+ @override
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
- json['type'] = 'ClassHeapStats';
+ final json = <String, dynamic>{};
+ json['type'] = type;
json.addAll({
'class': classRef.toJson(),
'accumulatedSize': accumulatedSize,
@@ -2973,64 +3010,73 @@
}
String toString() => '[ClassHeapStats ' //
- 'type: ${type}, classRef: ${classRef}, accumulatedSize: ${accumulatedSize}, ' //
+ 'classRef: ${classRef}, accumulatedSize: ${accumulatedSize}, ' //
'bytesCurrent: ${bytesCurrent}, instancesAccumulated: ${instancesAccumulated}, instancesCurrent: ${instancesCurrent}]';
}
class ClassList extends Response {
- static ClassList parse(Map<String, dynamic> json) =>
+ static ClassList? parse(Map<String, dynamic>? json) =>
json == null ? null : ClassList._fromJson(json);
- List<ClassRef> classes;
+ late final List<ClassRef> classes;
ClassList({
- @required this.classes,
+ required this.classes,
});
ClassList._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
classes = List<ClassRef>.from(
- createServiceObject(json['classes'], const ['ClassRef']) ?? []);
+ createServiceObject(json['classes'], const ['ClassRef']) as List? ??
+ []);
}
@override
+ String get type => 'ClassList';
+
+ @override
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
- json['type'] = 'ClassList';
+ final json = <String, dynamic>{};
+ json['type'] = type;
json.addAll({
'classes': classes.map((f) => f.toJson()).toList(),
});
return json;
}
- String toString() => '[ClassList type: ${type}, classes: ${classes}]';
+ String toString() => '[ClassList classes: ${classes}]';
}
/// `CodeRef` is a reference to a `Code` object.
class CodeRef extends ObjRef {
- static CodeRef parse(Map<String, dynamic> json) =>
+ static CodeRef? parse(Map<String, dynamic>? json) =>
json == null ? null : CodeRef._fromJson(json);
/// A name for this code object.
- String name;
+ late final String name;
/// What kind of code object is this?
- /*CodeKind*/ String kind;
+ late final /*CodeKind*/ String kind;
CodeRef({
- @required this.name,
- @required this.kind,
- @required String id,
- }) : super(id: id);
+ required this.name,
+ required this.kind,
+ required String id,
+ }) : super(
+ id: id,
+ );
CodeRef._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
- name = json['name'];
- kind = json['kind'];
+ name = json['name'] ?? '';
+ kind = json['kind'] ?? '';
}
@override
+ String get type => 'CodeRef';
+
+ @override
Map<String, dynamic> toJson() {
- var json = super.toJson();
- json['type'] = '@Code';
+ final json = super.toJson();
+ json['type'] = type;
json.addAll({
'name': name,
'kind': kind,
@@ -3042,36 +3088,40 @@
operator ==(other) => other is CodeRef && id == other.id;
- String toString() =>
- '[CodeRef type: ${type}, id: ${id}, name: ${name}, kind: ${kind}]';
+ String toString() => '[CodeRef id: ${id}, name: ${name}, kind: ${kind}]';
}
/// A `Code` object represents compiled code in the Dart VM.
class Code extends ObjRef implements CodeRef {
- static Code parse(Map<String, dynamic> json) =>
+ static Code? parse(Map<String, dynamic>? json) =>
json == null ? null : Code._fromJson(json);
/// A name for this code object.
- String name;
+ late final String name;
/// What kind of code object is this?
- /*CodeKind*/ String kind;
+ late final /*CodeKind*/ String kind;
Code({
- @required this.name,
- @required this.kind,
- @required String id,
- }) : super(id: id);
+ required this.name,
+ required this.kind,
+ required String id,
+ }) : super(
+ id: id,
+ );
Code._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
- name = json['name'];
- kind = json['kind'];
+ name = json['name'] ?? '';
+ kind = json['kind'] ?? '';
}
@override
+ String get type => 'Code';
+
+ @override
Map<String, dynamic> toJson() {
- var json = super.toJson();
- json['type'] = 'Code';
+ final json = super.toJson();
+ json['type'] = type;
json.addAll({
'name': name,
'kind': kind,
@@ -3083,30 +3133,34 @@
operator ==(other) => other is Code && id == other.id;
- String toString() =>
- '[Code type: ${type}, id: ${id}, name: ${name}, kind: ${kind}]';
+ String toString() => '[Code id: ${id}, name: ${name}, kind: ${kind}]';
}
class ContextRef extends ObjRef {
- static ContextRef parse(Map<String, dynamic> json) =>
+ static ContextRef? parse(Map<String, dynamic>? json) =>
json == null ? null : ContextRef._fromJson(json);
/// The number of variables in this context.
- int length;
+ late final int length;
ContextRef({
- @required this.length,
- @required String id,
- }) : super(id: id);
+ required this.length,
+ required String id,
+ }) : super(
+ id: id,
+ );
ContextRef._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
- length = json['length'];
+ length = json['length'] ?? -1;
}
@override
+ String get type => 'ContextRef';
+
+ @override
Map<String, dynamic> toJson() {
- var json = super.toJson();
- json['type'] = '@Context';
+ final json = super.toJson();
+ json['type'] = type;
json.addAll({
'length': length,
});
@@ -3117,44 +3171,50 @@
operator ==(other) => other is ContextRef && id == other.id;
- String toString() =>
- '[ContextRef type: ${type}, id: ${id}, length: ${length}]';
+ String toString() => '[ContextRef id: ${id}, length: ${length}]';
}
/// A `Context` is a data structure which holds the captured variables for some
/// closure.
class Context extends Obj implements ContextRef {
- static Context parse(Map<String, dynamic> json) =>
+ static Context? parse(Map<String, dynamic>? json) =>
json == null ? null : Context._fromJson(json);
/// The number of variables in this context.
- int length;
+ late final int length;
/// The enclosing context for this context.
@optional
- Context parent;
+ late final Context? parent;
/// The variables in this context object.
- List<ContextElement> variables;
+ late final List<ContextElement> variables;
Context({
- @required this.length,
- @required this.variables,
- @required String id,
+ required this.length,
+ required this.variables,
+ required String id,
this.parent,
- }) : super(id: id);
+ }) : super(
+ id: id,
+ );
Context._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
- length = json['length'];
- parent = createServiceObject(json['parent'], const ['Context']);
+ length = json['length'] ?? -1;
+ parent = createServiceObject(json['parent'], const ['Context']) as Context?;
variables = List<ContextElement>.from(
- createServiceObject(json['variables'], const ['ContextElement']) ?? []);
+ createServiceObject(json['variables'], const ['ContextElement'])
+ as List? ??
+ []);
}
@override
+ String get type => 'Context';
+
+ @override
Map<String, dynamic> toJson() {
- var json = super.toJson();
- json['type'] = 'Context';
+ final json = super.toJson();
+ json['type'] = type;
json.addAll({
'length': length,
'variables': variables.map((f) => f.toJson()).toList(),
@@ -3167,28 +3227,29 @@
operator ==(other) => other is Context && id == other.id;
- String toString() => '[Context ' //
- 'type: ${type}, id: ${id}, length: ${length}, variables: ${variables}]';
+ String toString() =>
+ '[Context id: ${id}, length: ${length}, variables: ${variables}]';
}
class ContextElement {
- static ContextElement parse(Map<String, dynamic> json) =>
+ static ContextElement? parse(Map<String, dynamic>? json) =>
json == null ? null : ContextElement._fromJson(json);
/// [value] can be one of [InstanceRef] or [Sentinel].
- dynamic value;
+ late final dynamic value;
ContextElement({
- @required this.value,
+ required this.value,
});
ContextElement._fromJson(Map<String, dynamic> json) {
value =
- createServiceObject(json['value'], const ['InstanceRef', 'Sentinel']);
+ createServiceObject(json['value']!, const ['InstanceRef', 'Sentinel'])
+ as dynamic;
}
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
+ final json = <String, dynamic>{};
json.addAll({
'value': value.toJson(),
});
@@ -3200,71 +3261,76 @@
/// See [getCpuSamples] and [CpuSample].
class CpuSamples extends Response {
- static CpuSamples parse(Map<String, dynamic> json) =>
+ static CpuSamples? parse(Map<String, dynamic>? json) =>
json == null ? null : CpuSamples._fromJson(json);
/// The sampling rate for the profiler in microseconds.
- int samplePeriod;
+ late final int samplePeriod;
/// The maximum possible stack depth for samples.
- int maxStackDepth;
+ late final int maxStackDepth;
/// The number of samples returned.
- int sampleCount;
+ late final int sampleCount;
/// The timespan the set of returned samples covers, in microseconds.
- int timeSpan;
+ late final int timeSpan;
/// The start of the period of time in which the returned samples were
/// collected.
- int timeOriginMicros;
+ late final int timeOriginMicros;
/// The duration of time covered by the returned samples.
- int timeExtentMicros;
+ late final int timeExtentMicros;
/// The process ID for the VM.
- int pid;
+ late final int pid;
/// A list of functions seen in the relevant samples. These references can be
/// looked up using the indicies provided in a `CpuSample` `stack` to
/// determine which function was on the stack.
- List<ProfileFunction> functions;
+ late final List<ProfileFunction> functions;
/// A list of samples collected in the range `[timeOriginMicros,
/// timeOriginMicros + timeExtentMicros]`
- List<CpuSample> samples;
+ late final List<CpuSample> samples;
CpuSamples({
- @required this.samplePeriod,
- @required this.maxStackDepth,
- @required this.sampleCount,
- @required this.timeSpan,
- @required this.timeOriginMicros,
- @required this.timeExtentMicros,
- @required this.pid,
- @required this.functions,
- @required this.samples,
+ required this.samplePeriod,
+ required this.maxStackDepth,
+ required this.sampleCount,
+ required this.timeSpan,
+ required this.timeOriginMicros,
+ required this.timeExtentMicros,
+ required this.pid,
+ required this.functions,
+ required this.samples,
});
CpuSamples._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
- samplePeriod = json['samplePeriod'];
- maxStackDepth = json['maxStackDepth'];
- sampleCount = json['sampleCount'];
- timeSpan = json['timeSpan'];
- timeOriginMicros = json['timeOriginMicros'];
- timeExtentMicros = json['timeExtentMicros'];
- pid = json['pid'];
+ samplePeriod = json['samplePeriod'] ?? -1;
+ maxStackDepth = json['maxStackDepth'] ?? -1;
+ sampleCount = json['sampleCount'] ?? -1;
+ timeSpan = json['timeSpan'] ?? -1;
+ timeOriginMicros = json['timeOriginMicros'] ?? -1;
+ timeExtentMicros = json['timeExtentMicros'] ?? -1;
+ pid = json['pid'] ?? -1;
functions = List<ProfileFunction>.from(
- createServiceObject(json['functions'], const ['ProfileFunction']) ??
+ createServiceObject(json['functions'], const ['ProfileFunction'])
+ as List? ??
[]);
samples = List<CpuSample>.from(
- createServiceObject(json['samples'], const ['CpuSample']) ?? []);
+ createServiceObject(json['samples'], const ['CpuSample']) as List? ??
+ []);
}
@override
+ String get type => 'CpuSamples';
+
+ @override
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
- json['type'] = 'CpuSamples';
+ final json = <String, dynamic>{};
+ json['type'] = type;
json.addAll({
'samplePeriod': samplePeriod,
'maxStackDepth': maxStackDepth,
@@ -3284,30 +3350,30 @@
/// See [getCpuSamples] and [CpuSamples].
class CpuSample {
- static CpuSample parse(Map<String, dynamic> json) =>
+ static CpuSample? parse(Map<String, dynamic>? json) =>
json == null ? null : CpuSample._fromJson(json);
/// The thread ID representing the thread on which this sample was collected.
- int tid;
+ late final int tid;
/// The time this sample was collected in microseconds.
- int timestamp;
+ late final int timestamp;
/// The name of VM tag set when this sample was collected. Omitted if the VM
/// tag for the sample is not considered valid.
@optional
- String vmTag;
+ late final String? vmTag;
/// The name of the User tag set when this sample was collected. Omitted if no
/// User tag was set when this sample was collected.
@optional
- String userTag;
+ late final String? userTag;
/// Provided and set to true if the sample's stack was truncated. This can
/// happen if the stack is deeper than the `stackDepth` in the `CpuSamples`
/// response.
@optional
- bool truncated;
+ late final bool? truncated;
/// The call stack at the time this sample was collected. The stack is to be
/// interpreted as top to bottom. Each element in this array is a key into the
@@ -3317,20 +3383,20 @@
///
/// `functions[stack[0]] = @Function(bar())` `functions[stack[1]] =
/// @Function(foo())` `functions[stack[2]] = @Function(main())`
- List<int> stack;
+ late final List<int> stack;
CpuSample({
- @required this.tid,
- @required this.timestamp,
- @required this.stack,
+ required this.tid,
+ required this.timestamp,
+ required this.stack,
this.vmTag,
this.userTag,
this.truncated,
});
CpuSample._fromJson(Map<String, dynamic> json) {
- tid = json['tid'];
- timestamp = json['timestamp'];
+ tid = json['tid'] ?? -1;
+ timestamp = json['timestamp'] ?? -1;
vmTag = json['vmTag'];
userTag = json['userTag'];
truncated = json['truncated'];
@@ -3338,7 +3404,7 @@
}
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
+ final json = <String, dynamic>{};
json.addAll({
'tid': tid,
'timestamp': timestamp,
@@ -3356,30 +3422,35 @@
/// `ErrorRef` is a reference to an `Error`.
class ErrorRef extends ObjRef {
- static ErrorRef parse(Map<String, dynamic> json) =>
+ static ErrorRef? parse(Map<String, dynamic>? json) =>
json == null ? null : ErrorRef._fromJson(json);
/// What kind of error is this?
- /*ErrorKind*/ String kind;
+ late final /*ErrorKind*/ String kind;
/// A description of the error.
- String message;
+ late final String message;
ErrorRef({
- @required this.kind,
- @required this.message,
- @required String id,
- }) : super(id: id);
+ required this.kind,
+ required this.message,
+ required String id,
+ }) : super(
+ id: id,
+ );
ErrorRef._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
- kind = json['kind'];
- message = json['message'];
+ kind = json['kind'] ?? '';
+ message = json['message'] ?? '';
}
@override
+ String get type => 'ErrorRef';
+
+ @override
Map<String, dynamic> toJson() {
- var json = super.toJson();
- json['type'] = '@Error';
+ final json = super.toJson();
+ json['type'] = type;
json.addAll({
'kind': kind,
'message': message,
@@ -3392,50 +3463,57 @@
operator ==(other) => other is ErrorRef && id == other.id;
String toString() =>
- '[ErrorRef type: ${type}, id: ${id}, kind: ${kind}, message: ${message}]';
+ '[ErrorRef id: ${id}, kind: ${kind}, message: ${message}]';
}
/// An `Error` represents a Dart language level error. This is distinct from an
/// [RPC error].
class Error extends Obj implements ErrorRef {
- static Error parse(Map<String, dynamic> json) =>
+ static Error? parse(Map<String, dynamic>? json) =>
json == null ? null : Error._fromJson(json);
/// What kind of error is this?
- /*ErrorKind*/ String kind;
+ late final /*ErrorKind*/ String kind;
/// A description of the error.
- String message;
+ late final String message;
/// If this error is due to an unhandled exception, this is the exception
/// thrown.
@optional
- InstanceRef exception;
+ late final InstanceRef? exception;
/// If this error is due to an unhandled exception, this is the stacktrace
/// object.
@optional
- InstanceRef stacktrace;
+ late final InstanceRef? stacktrace;
Error({
- @required this.kind,
- @required this.message,
- @required String id,
+ required this.kind,
+ required this.message,
+ required String id,
this.exception,
this.stacktrace,
- }) : super(id: id);
+ }) : super(
+ id: id,
+ );
Error._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
- kind = json['kind'];
- message = json['message'];
- exception = createServiceObject(json['exception'], const ['InstanceRef']);
- stacktrace = createServiceObject(json['stacktrace'], const ['InstanceRef']);
+ kind = json['kind'] ?? '';
+ message = json['message'] ?? '';
+ exception = createServiceObject(json['exception'], const ['InstanceRef'])
+ as InstanceRef?;
+ stacktrace = createServiceObject(json['stacktrace'], const ['InstanceRef'])
+ as InstanceRef?;
}
@override
+ String get type => 'Error';
+
+ @override
Map<String, dynamic> toJson() {
- var json = super.toJson();
- json['type'] = 'Error';
+ final json = super.toJson();
+ json['type'] = type;
json.addAll({
'kind': kind,
'message': message,
@@ -3449,8 +3527,7 @@
operator ==(other) => other is Error && id == other.id;
- String toString() =>
- '[Error type: ${type}, id: ${id}, kind: ${kind}, message: ${message}]';
+ String toString() => '[Error id: ${id}, kind: ${kind}, message: ${message}]';
}
/// An `Event` is an asynchronous notification from the VM. It is delivered only
@@ -3459,31 +3536,31 @@
///
/// For more information, see [events].
class Event extends Response {
- static Event parse(Map<String, dynamic> json) =>
+ static Event? parse(Map<String, dynamic>? json) =>
json == null ? null : Event._fromJson(json);
/// What kind of event is this?
- /*EventKind*/ String kind;
+ late final /*EventKind*/ String kind;
/// The isolate with which this event is associated.
///
/// This is provided for all event kinds except for:
/// - VMUpdate, VMFlagUpdate
@optional
- IsolateRef isolate;
+ late final IsolateRef? isolate;
/// The vm with which this event is associated.
///
/// This is provided for the event kind:
/// - VMUpdate, VMFlagUpdate
@optional
- VMRef vm;
+ late final VMRef? vm;
/// The timestamp (in milliseconds since the epoch) associated with this
/// event. For some isolate pause events, the timestamp is from when the
/// isolate was paused. For other events, the timestamp is from when the event
/// was created.
- int timestamp;
+ late final int timestamp;
/// The breakpoint which was added, removed, or resolved.
///
@@ -3493,7 +3570,7 @@
/// - BreakpointRemoved
/// - BreakpointResolved
@optional
- Breakpoint breakpoint;
+ late final Breakpoint? breakpoint;
/// The list of breakpoints at which we are currently paused for a
/// PauseBreakpoint event.
@@ -3507,7 +3584,7 @@
/// This is provided for the event kinds:
/// - PauseBreakpoint
@optional
- List<Breakpoint> pauseBreakpoints;
+ late final List<Breakpoint>? pauseBreakpoints;
/// The top stack frame associated with this event, if applicable.
///
@@ -3523,54 +3600,54 @@
/// the initial resume event that is delivered when an isolate begins
/// execution.
@optional
- Frame topFrame;
+ late final Frame? topFrame;
/// The exception associated with this event, if this is a PauseException
/// event.
@optional
- InstanceRef exception;
+ late final InstanceRef? exception;
/// An array of bytes, encoded as a base64 string.
///
/// This is provided for the WriteEvent event.
@optional
- String bytes;
+ late final String? bytes;
/// The argument passed to dart:developer.inspect.
///
/// This is provided for the Inspect event.
@optional
- InstanceRef inspectee;
+ late final InstanceRef? inspectee;
/// The RPC name of the extension that was added.
///
/// This is provided for the ServiceExtensionAdded event.
@optional
- String extensionRPC;
+ late final String? extensionRPC;
/// The extension event kind.
///
/// This is provided for the Extension event.
@optional
- String extensionKind;
+ late final String? extensionKind;
/// The extension event data.
///
/// This is provided for the Extension event.
@optional
- ExtensionData extensionData;
+ late final ExtensionData? extensionData;
/// An array of TimelineEvents
///
/// This is provided for the TimelineEvents event.
@optional
- List<TimelineEvent> timelineEvents;
+ late final List<TimelineEvent>? timelineEvents;
/// The new set of recorded timeline streams.
///
/// This is provided for the TimelineStreamSubscriptionsUpdate event.
@optional
- List<String> updatedStreams;
+ late final List<String>? updatedStreams;
/// Is the isolate paused at an await, yield, or yield* statement?
///
@@ -3578,19 +3655,19 @@
/// - PauseBreakpoint
/// - PauseInterrupted
@optional
- bool atAsyncSuspension;
+ late final bool? atAsyncSuspension;
/// The status (success or failure) related to the event. This is provided for
/// the event kinds:
/// - IsolateReloaded
@optional
- String status;
+ late final String? status;
/// LogRecord data.
///
/// This is provided for the Logging event.
@optional
- LogRecord logRecord;
+ late final LogRecord? logRecord;
/// The service identifier.
///
@@ -3598,7 +3675,7 @@
/// - ServiceRegistered
/// - ServiceUnregistered
@optional
- String service;
+ late final String? service;
/// The RPC method that should be used to invoke the service.
///
@@ -3606,46 +3683,46 @@
/// - ServiceRegistered
/// - ServiceUnregistered
@optional
- String method;
+ late final String? method;
/// The alias of the registered service.
///
/// This is provided for the event kinds:
/// - ServiceRegistered
@optional
- String alias;
+ late final String? alias;
/// The name of the changed flag.
///
/// This is provided for the event kinds:
/// - VMFlagUpdate
@optional
- String flag;
+ late final String? flag;
/// The new value of the changed flag.
///
/// This is provided for the event kinds:
/// - VMFlagUpdate
@optional
- String newValue;
+ late final String? newValue;
/// Specifies whether this event is the last of a group of events.
///
/// This is provided for the event kinds:
/// - HeapSnapshot
@optional
- bool last;
+ late final bool? last;
/// Binary data associated with the event.
///
/// This is provided for the event kinds:
/// - HeapSnapshot
@optional
- ByteData data;
+ late final ByteData? data;
Event({
- @required this.kind,
- @required this.timestamp,
+ required this.kind,
+ required this.timestamp,
this.isolate,
this.vm,
this.breakpoint,
@@ -3672,32 +3749,38 @@
});
Event._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
- kind = json['kind'];
- isolate = createServiceObject(json['isolate'], const ['IsolateRef']);
- vm = createServiceObject(json['vm'], const ['VMRef']);
- timestamp = json['timestamp'];
- breakpoint = createServiceObject(json['breakpoint'], const ['Breakpoint']);
+ kind = json['kind'] ?? '';
+ isolate = createServiceObject(json['isolate'], const ['IsolateRef'])
+ as IsolateRef?;
+ vm = createServiceObject(json['vm'], const ['VMRef']) as VMRef?;
+ timestamp = json['timestamp'] ?? -1;
+ breakpoint = createServiceObject(json['breakpoint'], const ['Breakpoint'])
+ as Breakpoint?;
pauseBreakpoints = json['pauseBreakpoints'] == null
? null
- : List<Breakpoint>.from(createServiceObject(
- json['pauseBreakpoints'], const ['Breakpoint']));
- topFrame = createServiceObject(json['topFrame'], const ['Frame']);
- exception = createServiceObject(json['exception'], const ['InstanceRef']);
+ : List<Breakpoint>.from(
+ createServiceObject(json['pauseBreakpoints'], const ['Breakpoint'])!
+ as List);
+ topFrame = createServiceObject(json['topFrame'], const ['Frame']) as Frame?;
+ exception = createServiceObject(json['exception'], const ['InstanceRef'])
+ as InstanceRef?;
bytes = json['bytes'];
- inspectee = createServiceObject(json['inspectee'], const ['InstanceRef']);
+ inspectee = createServiceObject(json['inspectee'], const ['InstanceRef'])
+ as InstanceRef?;
extensionRPC = json['extensionRPC'];
extensionKind = json['extensionKind'];
extensionData = ExtensionData.parse(json['extensionData']);
timelineEvents = json['timelineEvents'] == null
? null
: List<TimelineEvent>.from(createServiceObject(
- json['timelineEvents'], const ['TimelineEvent']));
+ json['timelineEvents'], const ['TimelineEvent'])! as List);
updatedStreams = json['updatedStreams'] == null
? null
: List<String>.from(json['updatedStreams']);
atAsyncSuspension = json['atAsyncSuspension'];
status = json['status'];
- logRecord = createServiceObject(json['logRecord'], const ['LogRecord']);
+ logRecord = createServiceObject(json['logRecord'], const ['LogRecord'])
+ as LogRecord?;
service = json['service'];
method = json['method'];
alias = json['alias'];
@@ -3708,9 +3791,12 @@
}
@override
+ String get type => 'Event';
+
+ @override
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
- json['type'] = 'Event';
+ final json = <String, dynamic>{};
+ json['type'] = type;
json.addAll({
'kind': kind,
'timestamp': timestamp,
@@ -3719,7 +3805,7 @@
_setIfNotNull(json, 'vm', vm?.toJson());
_setIfNotNull(json, 'breakpoint', breakpoint?.toJson());
_setIfNotNull(json, 'pauseBreakpoints',
- pauseBreakpoints?.map((f) => f?.toJson())?.toList());
+ pauseBreakpoints?.map((f) => f.toJson()).toList());
_setIfNotNull(json, 'topFrame', topFrame?.toJson());
_setIfNotNull(json, 'exception', exception?.toJson());
_setIfNotNull(json, 'bytes', bytes);
@@ -3728,9 +3814,9 @@
_setIfNotNull(json, 'extensionKind', extensionKind);
_setIfNotNull(json, 'extensionData', extensionData?.data);
_setIfNotNull(json, 'timelineEvents',
- timelineEvents?.map((f) => f?.toJson())?.toList());
+ timelineEvents?.map((f) => f.toJson()).toList());
_setIfNotNull(
- json, 'updatedStreams', updatedStreams?.map((f) => f)?.toList());
+ json, 'updatedStreams', updatedStreams?.map((f) => f).toList());
_setIfNotNull(json, 'atAsyncSuspension', atAsyncSuspension);
_setIfNotNull(json, 'status', status);
_setIfNotNull(json, 'logRecord', logRecord?.toJson());
@@ -3744,60 +3830,65 @@
return json;
}
- String toString() =>
- '[Event type: ${type}, kind: ${kind}, timestamp: ${timestamp}]';
+ String toString() => '[Event kind: ${kind}, timestamp: ${timestamp}]';
}
/// An `FieldRef` is a reference to a `Field`.
class FieldRef extends ObjRef {
- static FieldRef parse(Map<String, dynamic> json) =>
+ static FieldRef? parse(Map<String, dynamic>? json) =>
json == null ? null : FieldRef._fromJson(json);
/// The name of this field.
- String name;
+ late final String name;
/// The owner of this field, which can be either a Library or a Class.
- ObjRef owner;
+ late final ObjRef owner;
/// The declared type of this field.
///
/// The value will always be of one of the kinds: Type, TypeRef,
/// TypeParameter, BoundedType.
- InstanceRef declaredType;
+ late final InstanceRef declaredType;
/// Is this field const?
- bool isConst;
+ late final bool isConst;
/// Is this field final?
- bool isFinal;
+ late final bool isFinal;
/// Is this field static?
- bool isStatic;
+ late final bool isStatic;
FieldRef({
- @required this.name,
- @required this.owner,
- @required this.declaredType,
- @required this.isConst,
- @required this.isFinal,
- @required this.isStatic,
- @required String id,
- }) : super(id: id);
+ required this.name,
+ required this.owner,
+ required this.declaredType,
+ required this.isConst,
+ required this.isFinal,
+ required this.isStatic,
+ required String id,
+ }) : super(
+ id: id,
+ );
FieldRef._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
- name = json['name'];
- owner = createServiceObject(json['owner'], const ['ObjRef']);
+ name = json['name'] ?? '';
+ owner = createServiceObject(json['owner']!, const ['ObjRef']) as ObjRef;
declaredType =
- createServiceObject(json['declaredType'], const ['InstanceRef']);
- isConst = json['const'];
- isFinal = json['final'];
- isStatic = json['static'];
+ createServiceObject(json['declaredType']!, const ['InstanceRef'])
+ as InstanceRef;
+ isConst = json['const'] ?? false;
+ isFinal = json['final'] ?? false;
+ isStatic = json['static'] ?? false;
}
@override
+ String get type => 'FieldRef';
+
+ @override
Map<String, dynamic> toJson() {
- var json = super.toJson();
- json['type'] = '@Field';
+ final json = super.toJson();
+ json['type'] = type;
json.addAll({
'name': name,
'owner': owner.toJson(),
@@ -3813,72 +3904,82 @@
operator ==(other) => other is FieldRef && id == other.id;
- String toString() => '[FieldRef]';
+ String toString() => '[FieldRef ' //
+ 'id: ${id}, name: ${name}, owner: ${owner}, declaredType: ${declaredType}, ' //
+ 'isConst: ${isConst}, isFinal: ${isFinal}, isStatic: ${isStatic}]';
}
/// A `Field` provides information about a Dart language field or variable.
class Field extends Obj implements FieldRef {
- static Field parse(Map<String, dynamic> json) =>
+ static Field? parse(Map<String, dynamic>? json) =>
json == null ? null : Field._fromJson(json);
/// The name of this field.
- String name;
+ late final String name;
/// The owner of this field, which can be either a Library or a Class.
- ObjRef owner;
+ late final ObjRef owner;
/// The declared type of this field.
///
/// The value will always be of one of the kinds: Type, TypeRef,
/// TypeParameter, BoundedType.
- InstanceRef declaredType;
+ late final InstanceRef declaredType;
/// Is this field const?
- bool isConst;
+ late final bool isConst;
/// Is this field final?
- bool isFinal;
+ late final bool isFinal;
/// Is this field static?
- bool isStatic;
+ late final bool isStatic;
/// The value of this field, if the field is static.
@optional
- InstanceRef staticValue;
+ late final InstanceRef? staticValue;
/// The location of this field in the source code.
@optional
- SourceLocation location;
+ late final SourceLocation? location;
Field({
- @required this.name,
- @required this.owner,
- @required this.declaredType,
- @required this.isConst,
- @required this.isFinal,
- @required this.isStatic,
- @required String id,
+ required this.name,
+ required this.owner,
+ required this.declaredType,
+ required this.isConst,
+ required this.isFinal,
+ required this.isStatic,
+ required String id,
this.staticValue,
this.location,
- }) : super(id: id);
+ }) : super(
+ id: id,
+ );
Field._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
- name = json['name'];
- owner = createServiceObject(json['owner'], const ['ObjRef']);
+ name = json['name'] ?? '';
+ owner = createServiceObject(json['owner']!, const ['ObjRef']) as ObjRef;
declaredType =
- createServiceObject(json['declaredType'], const ['InstanceRef']);
- isConst = json['const'];
- isFinal = json['final'];
- isStatic = json['static'];
+ createServiceObject(json['declaredType']!, const ['InstanceRef'])
+ as InstanceRef;
+ isConst = json['const'] ?? false;
+ isFinal = json['final'] ?? false;
+ isStatic = json['static'] ?? false;
staticValue =
- createServiceObject(json['staticValue'], const ['InstanceRef']);
- location = createServiceObject(json['location'], const ['SourceLocation']);
+ createServiceObject(json['staticValue'], const ['InstanceRef'])
+ as InstanceRef?;
+ location = createServiceObject(json['location'], const ['SourceLocation'])
+ as SourceLocation?;
}
@override
+ String get type => 'Field';
+
+ @override
Map<String, dynamic> toJson() {
- var json = super.toJson();
- json['type'] = 'Field';
+ final json = super.toJson();
+ json['type'] = type;
json.addAll({
'name': name,
'owner': owner.toJson(),
@@ -3896,45 +3997,47 @@
operator ==(other) => other is Field && id == other.id;
- String toString() => '[Field]';
+ String toString() => '[Field ' //
+ 'id: ${id}, name: ${name}, owner: ${owner}, declaredType: ${declaredType}, ' //
+ 'isConst: ${isConst}, isFinal: ${isFinal}, isStatic: ${isStatic}]';
}
/// A `Flag` represents a single VM command line flag.
class Flag {
- static Flag parse(Map<String, dynamic> json) =>
+ static Flag? parse(Map<String, dynamic>? json) =>
json == null ? null : Flag._fromJson(json);
/// The name of the flag.
- String name;
+ late final String name;
/// A description of the flag.
- String comment;
+ late final String comment;
/// Has this flag been modified from its default setting?
- bool modified;
+ late final bool modified;
/// The value of this flag as a string.
///
/// If this property is absent, then the value of the flag was NULL.
@optional
- String valueAsString;
+ late final String? valueAsString;
Flag({
- @required this.name,
- @required this.comment,
- @required this.modified,
+ required this.name,
+ required this.comment,
+ required this.modified,
this.valueAsString,
});
Flag._fromJson(Map<String, dynamic> json) {
- name = json['name'];
- comment = json['comment'];
- modified = json['modified'];
+ name = json['name'] ?? '';
+ comment = json['comment'] ?? '';
+ modified = json['modified'] ?? false;
valueAsString = json['valueAsString'];
}
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
+ final json = <String, dynamic>{};
json.addAll({
'name': name,
'comment': comment,
@@ -3950,58 +4053,60 @@
/// A `FlagList` represents the complete set of VM command line flags.
class FlagList extends Response {
- static FlagList parse(Map<String, dynamic> json) =>
+ static FlagList? parse(Map<String, dynamic>? json) =>
json == null ? null : FlagList._fromJson(json);
/// A list of all flags in the VM.
- List<Flag> flags;
+ late final List<Flag> flags;
FlagList({
- @required this.flags,
+ required this.flags,
});
FlagList._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
flags = List<Flag>.from(
- createServiceObject(json['flags'], const ['Flag']) ?? []);
+ createServiceObject(json['flags'], const ['Flag']) as List? ?? []);
}
@override
+ String get type => 'FlagList';
+
+ @override
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
- json['type'] = 'FlagList';
+ final json = <String, dynamic>{};
+ json['type'] = type;
json.addAll({
'flags': flags.map((f) => f.toJson()).toList(),
});
return json;
}
- String toString() => '[FlagList type: ${type}, flags: ${flags}]';
+ String toString() => '[FlagList flags: ${flags}]';
}
class Frame extends Response {
- static Frame parse(Map<String, dynamic> json) =>
+ static Frame? parse(Map<String, dynamic>? json) =>
json == null ? null : Frame._fromJson(json);
- int index;
+ late final int index;
@optional
- FuncRef function;
+ late final FuncRef? function;
@optional
- CodeRef code;
+ late final CodeRef? code;
@optional
- SourceLocation location;
+ late final SourceLocation? location;
@optional
- List<BoundVariable> vars;
+ late final List<BoundVariable>? vars;
@optional
- /*FrameKind*/
- String kind;
+ late final /*FrameKind*/ String? kind;
Frame({
- @required this.index,
+ required this.index,
this.function,
this.code,
this.location,
@@ -4010,74 +4115,85 @@
});
Frame._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
- index = json['index'];
- function = createServiceObject(json['function'], const ['FuncRef']);
- code = createServiceObject(json['code'], const ['CodeRef']);
- location = createServiceObject(json['location'], const ['SourceLocation']);
+ index = json['index'] ?? -1;
+ function =
+ createServiceObject(json['function'], const ['FuncRef']) as FuncRef?;
+ code = createServiceObject(json['code'], const ['CodeRef']) as CodeRef?;
+ location = createServiceObject(json['location'], const ['SourceLocation'])
+ as SourceLocation?;
vars = json['vars'] == null
? null
: List<BoundVariable>.from(
- createServiceObject(json['vars'], const ['BoundVariable']));
+ createServiceObject(json['vars'], const ['BoundVariable'])!
+ as List);
kind = json['kind'];
}
@override
+ String get type => 'Frame';
+
+ @override
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
- json['type'] = 'Frame';
+ final json = <String, dynamic>{};
+ json['type'] = type;
json.addAll({
'index': index,
});
_setIfNotNull(json, 'function', function?.toJson());
_setIfNotNull(json, 'code', code?.toJson());
_setIfNotNull(json, 'location', location?.toJson());
- _setIfNotNull(json, 'vars', vars?.map((f) => f?.toJson())?.toList());
+ _setIfNotNull(json, 'vars', vars?.map((f) => f.toJson()).toList());
_setIfNotNull(json, 'kind', kind);
return json;
}
- String toString() => '[Frame type: ${type}, index: ${index}]';
+ String toString() => '[Frame index: ${index}]';
}
/// An `FuncRef` is a reference to a `Func`.
class FuncRef extends ObjRef {
- static FuncRef parse(Map<String, dynamic> json) =>
+ static FuncRef? parse(Map<String, dynamic>? json) =>
json == null ? null : FuncRef._fromJson(json);
/// The name of this function.
- String name;
+ late final String name;
/// The owner of this function, which can be a Library, Class, or a Function.
///
/// [owner] can be one of [LibraryRef], [ClassRef] or [FuncRef].
- dynamic owner;
+ late final dynamic owner;
/// Is this function static?
- bool isStatic;
+ late final bool isStatic;
/// Is this function const?
- bool isConst;
+ late final bool isConst;
FuncRef({
- @required this.name,
- @required this.owner,
- @required this.isStatic,
- @required this.isConst,
- @required String id,
- }) : super(id: id);
+ required this.name,
+ required this.owner,
+ required this.isStatic,
+ required this.isConst,
+ required String id,
+ }) : super(
+ id: id,
+ );
FuncRef._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
- name = json['name'];
+ name = json['name'] ?? '';
owner = createServiceObject(
- json['owner'], const ['LibraryRef', 'ClassRef', 'FuncRef']);
- isStatic = json['static'];
- isConst = json['const'];
+ json['owner']!, const ['LibraryRef', 'ClassRef', 'FuncRef']) as dynamic;
+ isStatic = json['static'] ?? false;
+ isConst = json['const'] ?? false;
}
@override
+ String get type => 'FuncRef';
+
+ @override
Map<String, dynamic> toJson() {
- var json = super.toJson();
- json['type'] = '@Function';
+ final json = super.toJson();
+ json['type'] = type;
json.addAll({
'name': name,
'owner': owner.toJson(),
@@ -4092,61 +4208,67 @@
operator ==(other) => other is FuncRef && id == other.id;
String toString() => '[FuncRef ' //
- 'type: ${type}, id: ${id}, name: ${name}, owner: ${owner}, ' //
- 'isStatic: ${isStatic}, isConst: ${isConst}]';
+ 'id: ${id}, name: ${name}, owner: ${owner}, isStatic: ${isStatic}, ' //
+ 'isConst: ${isConst}]';
}
/// A `Func` represents a Dart language function.
class Func extends Obj implements FuncRef {
- static Func parse(Map<String, dynamic> json) =>
+ static Func? parse(Map<String, dynamic>? json) =>
json == null ? null : Func._fromJson(json);
/// The name of this function.
- String name;
+ late final String name;
/// The owner of this function, which can be a Library, Class, or a Function.
///
/// [owner] can be one of [LibraryRef], [ClassRef] or [FuncRef].
- dynamic owner;
+ late final dynamic owner;
/// Is this function static?
- bool isStatic;
+ late final bool isStatic;
/// Is this function const?
- bool isConst;
+ late final bool isConst;
/// The location of this function in the source code.
@optional
- SourceLocation location;
+ late final SourceLocation? location;
/// The compiled code associated with this function.
@optional
- CodeRef code;
+ late final CodeRef? code;
Func({
- @required this.name,
- @required this.owner,
- @required this.isStatic,
- @required this.isConst,
- @required String id,
+ required this.name,
+ required this.owner,
+ required this.isStatic,
+ required this.isConst,
+ required String id,
this.location,
this.code,
- }) : super(id: id);
+ }) : super(
+ id: id,
+ );
Func._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
- name = json['name'];
+ name = json['name'] ?? '';
owner = createServiceObject(
- json['owner'], const ['LibraryRef', 'ClassRef', 'FuncRef']);
- isStatic = json['static'];
- isConst = json['const'];
- location = createServiceObject(json['location'], const ['SourceLocation']);
- code = createServiceObject(json['code'], const ['CodeRef']);
+ json['owner']!, const ['LibraryRef', 'ClassRef', 'FuncRef']) as dynamic;
+ isStatic = json['static'] ?? false;
+ isConst = json['const'] ?? false;
+ location = createServiceObject(json['location'], const ['SourceLocation'])
+ as SourceLocation?;
+ code = createServiceObject(json['code'], const ['CodeRef']) as CodeRef?;
}
@override
+ String get type => 'Func';
+
+ @override
Map<String, dynamic> toJson() {
- var json = super.toJson();
- json['type'] = 'Function';
+ final json = super.toJson();
+ json['type'] = type;
json.addAll({
'name': name,
'owner': owner.toJson(),
@@ -4163,20 +4285,20 @@
operator ==(other) => other is Func && id == other.id;
String toString() => '[Func ' //
- 'type: ${type}, id: ${id}, name: ${name}, owner: ${owner}, ' //
- 'isStatic: ${isStatic}, isConst: ${isConst}]';
+ 'id: ${id}, name: ${name}, owner: ${owner}, isStatic: ${isStatic}, ' //
+ 'isConst: ${isConst}]';
}
/// `InstanceRef` is a reference to an `Instance`.
class InstanceRef extends ObjRef {
- static InstanceRef parse(Map<String, dynamic> json) =>
+ static InstanceRef? parse(Map<String, dynamic>? json) =>
json == null ? null : InstanceRef._fromJson(json);
/// What kind of instance is this?
- /*InstanceKind*/ String kind;
+ late final /*InstanceKind*/ String kind;
/// Instance references always include their class.
- ClassRef classRef;
+ late final ClassRef classRef;
/// The value of this instance as a string.
///
@@ -4191,14 +4313,14 @@
/// - Int32x4
/// - StackTrace
@optional
- String valueAsString;
+ late final String? valueAsString;
/// The valueAsString for String references may be truncated. If so, this
/// property is added with the value 'true'.
///
/// New code should use 'length' and 'count' instead.
@optional
- bool valueAsStringIsTruncated;
+ late final bool? valueAsStringIsTruncated;
/// The length of a List or the number of associations in a Map or the number
/// of codeunits in a String.
@@ -4222,28 +4344,28 @@
/// - Float32x4List
/// - Float64x2List
@optional
- int length;
+ late final int? length;
/// The name of a Type instance.
///
/// Provided for instance kinds:
/// - Type
@optional
- String name;
+ late final String? name;
/// The corresponding Class if this Type has a resolved typeClass.
///
/// Provided for instance kinds:
/// - Type
@optional
- ClassRef typeClass;
+ late final ClassRef? typeClass;
/// The parameterized class of a type parameter:
///
/// Provided for instance kinds:
/// - TypeParameter
@optional
- ClassRef parameterizedClass;
+ late final ClassRef? parameterizedClass;
/// The pattern of a RegExp instance.
///
@@ -4252,47 +4374,47 @@
/// Provided for instance kinds:
/// - RegExp
@optional
- InstanceRef pattern;
+ late final InstanceRef? pattern;
/// The function associated with a Closure instance.
///
/// Provided for instance kinds:
/// - Closure
@optional
- FuncRef closureFunction;
+ late final FuncRef? closureFunction;
/// The context associated with a Closure instance.
///
/// Provided for instance kinds:
/// - Closure
@optional
- ContextRef closureContext;
+ late final ContextRef? closureContext;
/// The port ID for a ReceivePort.
///
/// Provided for instance kinds:
/// - ReceivePort
@optional
- int portId;
+ late final int? portId;
/// The stack trace associated with the allocation of a ReceivePort.
///
/// Provided for instance kinds:
/// - ReceivePort
@optional
- InstanceRef allocationLocation;
+ late final InstanceRef? allocationLocation;
/// A name associated with a ReceivePort used for debugging purposes.
///
/// Provided for instance kinds:
/// - ReceivePort
@optional
- String debugName;
+ late final String? debugName;
InstanceRef({
- @required this.kind,
- @required this.classRef,
- @required String id,
+ required this.kind,
+ required this.classRef,
+ required String id,
this.valueAsString,
this.valueAsStringIsTruncated,
this.length,
@@ -4305,33 +4427,45 @@
this.portId,
this.allocationLocation,
this.debugName,
- }) : super(id: id);
+ }) : super(
+ id: id,
+ );
InstanceRef._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
- kind = json['kind'];
- classRef = createServiceObject(json['class'], const ['ClassRef']);
+ kind = json['kind'] ?? '';
+ classRef =
+ createServiceObject(json['class']!, const ['ClassRef']) as ClassRef;
valueAsString = json['valueAsString'];
valueAsStringIsTruncated = json['valueAsStringIsTruncated'];
length = json['length'];
name = json['name'];
- typeClass = createServiceObject(json['typeClass'], const ['ClassRef']);
+ typeClass =
+ createServiceObject(json['typeClass'], const ['ClassRef']) as ClassRef?;
parameterizedClass =
- createServiceObject(json['parameterizedClass'], const ['ClassRef']);
- pattern = createServiceObject(json['pattern'], const ['InstanceRef']);
+ createServiceObject(json['parameterizedClass'], const ['ClassRef'])
+ as ClassRef?;
+ pattern = createServiceObject(json['pattern'], const ['InstanceRef'])
+ as InstanceRef?;
closureFunction =
- createServiceObject(json['closureFunction'], const ['FuncRef']);
+ createServiceObject(json['closureFunction'], const ['FuncRef'])
+ as FuncRef?;
closureContext =
- createServiceObject(json['closureContext'], const ['ContextRef']);
+ createServiceObject(json['closureContext'], const ['ContextRef'])
+ as ContextRef?;
portId = json['portId'];
allocationLocation =
- createServiceObject(json['allocationLocation'], const ['InstanceRef']);
+ createServiceObject(json['allocationLocation'], const ['InstanceRef'])
+ as InstanceRef?;
debugName = json['debugName'];
}
@override
+ String get type => 'InstanceRef';
+
+ @override
Map<String, dynamic> toJson() {
- var json = super.toJson();
- json['type'] = '@Instance';
+ final json = super.toJson();
+ json['type'] = type;
json.addAll({
'kind': kind,
'class': classRef.toJson(),
@@ -4355,21 +4489,21 @@
operator ==(other) => other is InstanceRef && id == other.id;
- String toString() => '[InstanceRef ' //
- 'type: ${type}, id: ${id}, kind: ${kind}, classRef: ${classRef}]';
+ String toString() =>
+ '[InstanceRef id: ${id}, kind: ${kind}, classRef: ${classRef}]';
}
/// An `Instance` represents an instance of the Dart language class `Obj`.
class Instance extends Obj implements InstanceRef {
- static Instance parse(Map<String, dynamic> json) =>
+ static Instance? parse(Map<String, dynamic>? json) =>
json == null ? null : Instance._fromJson(json);
/// What kind of instance is this?
- /*InstanceKind*/ String kind;
+ late final /*InstanceKind*/ String kind;
/// Instance references always include their class.
@override
- ClassRef classRef;
+ covariant late final ClassRef classRef;
/// The value of this instance as a string.
///
@@ -4380,14 +4514,14 @@
/// - String (value may be truncated)
/// - StackTrace
@optional
- String valueAsString;
+ late final String? valueAsString;
/// The valueAsString for String references may be truncated. If so, this
/// property is added with the value 'true'.
///
/// New code should use 'length' and 'count' instead.
@optional
- bool valueAsStringIsTruncated;
+ late final bool? valueAsStringIsTruncated;
/// The length of a List or the number of associations in a Map or the number
/// of codeunits in a String.
@@ -4411,7 +4545,7 @@
/// - Float32x4List
/// - Float64x2List
@optional
- int length;
+ late final int? length;
/// The index of the first element or association or codeunit returned. This
/// is only provided when it is non-zero.
@@ -4435,7 +4569,7 @@
/// - Float32x4List
/// - Float64x2List
@optional
- int offset;
+ late final int? offset;
/// The number of elements or associations or codeunits returned. This is only
/// provided when it is less than length.
@@ -4459,46 +4593,46 @@
/// - Float32x4List
/// - Float64x2List
@optional
- int count;
+ late final int? count;
/// The name of a Type instance.
///
/// Provided for instance kinds:
/// - Type
@optional
- String name;
+ late final String? name;
/// The corresponding Class if this Type is canonical.
///
/// Provided for instance kinds:
/// - Type
@optional
- ClassRef typeClass;
+ late final ClassRef? typeClass;
/// The parameterized class of a type parameter:
///
/// Provided for instance kinds:
/// - TypeParameter
@optional
- ClassRef parameterizedClass;
+ late final ClassRef? parameterizedClass;
/// The fields of this Instance.
@optional
- List<BoundField> fields;
+ late final List<BoundField>? fields;
/// The elements of a List instance.
///
/// Provided for instance kinds:
/// - List
@optional
- List<dynamic> elements;
+ late final List<dynamic>? elements;
/// The elements of a Map instance.
///
/// Provided for instance kinds:
/// - Map
@optional
- List<MapAssociation> associations;
+ late final List<MapAssociation>? associations;
/// The bytes of a TypedData instance.
///
@@ -4520,77 +4654,77 @@
/// - Float32x4List
/// - Float64x2List
@optional
- String bytes;
+ late final String? bytes;
/// The referent of a MirrorReference instance.
///
/// Provided for instance kinds:
/// - MirrorReference
@optional
- InstanceRef mirrorReferent;
+ late final InstanceRef? mirrorReferent;
/// The pattern of a RegExp instance.
///
/// Provided for instance kinds:
/// - RegExp
@optional
- InstanceRef pattern;
+ late final InstanceRef? pattern;
/// The function associated with a Closure instance.
///
/// Provided for instance kinds:
/// - Closure
@optional
- FuncRef closureFunction;
+ late final FuncRef? closureFunction;
/// The context associated with a Closure instance.
///
/// Provided for instance kinds:
/// - Closure
@optional
- ContextRef closureContext;
+ late final ContextRef? closureContext;
/// Whether this regular expression is case sensitive.
///
/// Provided for instance kinds:
/// - RegExp
@optional
- bool isCaseSensitive;
+ late final bool? isCaseSensitive;
/// Whether this regular expression matches multiple lines.
///
/// Provided for instance kinds:
/// - RegExp
@optional
- bool isMultiLine;
+ late final bool? isMultiLine;
/// The key for a WeakProperty instance.
///
/// Provided for instance kinds:
/// - WeakProperty
@optional
- InstanceRef propertyKey;
+ late final InstanceRef? propertyKey;
/// The key for a WeakProperty instance.
///
/// Provided for instance kinds:
/// - WeakProperty
@optional
- InstanceRef propertyValue;
+ late final InstanceRef? propertyValue;
/// The type arguments for this type.
///
/// Provided for instance kinds:
/// - Type
@optional
- TypeArgumentsRef typeArguments;
+ late final TypeArgumentsRef? typeArguments;
/// The index of a TypeParameter instance.
///
/// Provided for instance kinds:
/// - TypeParameter
@optional
- int parameterIndex;
+ late final int? parameterIndex;
/// The type bounded by a BoundedType instance - or - the referent of a
/// TypeRef instance.
@@ -4602,7 +4736,7 @@
/// - BoundedType
/// - TypeRef
@optional
- InstanceRef targetType;
+ late final InstanceRef? targetType;
/// The bound of a TypeParameter or BoundedType.
///
@@ -4613,33 +4747,33 @@
/// - BoundedType
/// - TypeParameter
@optional
- InstanceRef bound;
+ late final InstanceRef? bound;
/// The port ID for a ReceivePort.
///
/// Provided for instance kinds:
/// - ReceivePort
@optional
- int portId;
+ late final int? portId;
/// The stack trace associated with the allocation of a ReceivePort.
///
/// Provided for instance kinds:
/// - ReceivePort
@optional
- InstanceRef allocationLocation;
+ late final InstanceRef? allocationLocation;
/// A name associated with a ReceivePort used for debugging purposes.
///
/// Provided for instance kinds:
/// - ReceivePort
@optional
- String debugName;
+ late final String? debugName;
Instance({
- @required this.kind,
- @required this.classRef,
- @required String id,
+ required this.kind,
+ required this.classRef,
+ required String id,
this.valueAsString,
this.valueAsStringIsTruncated,
this.length,
@@ -4667,61 +4801,38 @@
this.portId,
this.allocationLocation,
this.debugName,
- }) : super(id: id);
+ }) : super(
+ id: id,
+ classRef: classRef,
+ );
Instance._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
- kind = json['kind'];
- classRef = createServiceObject(json['class'], const ['ClassRef']);
+ kind = json['kind'] ?? '';
valueAsString = json['valueAsString'];
valueAsStringIsTruncated = json['valueAsStringIsTruncated'];
length = json['length'];
offset = json['offset'];
count = json['count'];
name = json['name'];
- typeClass = createServiceObject(json['typeClass'], const ['ClassRef']);
- parameterizedClass =
- createServiceObject(json['parameterizedClass'], const ['ClassRef']);
- fields = json['fields'] == null
- ? null
- : List<BoundField>.from(
- createServiceObject(json['fields'], const ['BoundField']));
- elements = json['elements'] == null
- ? null
- : List<dynamic>.from(
- createServiceObject(json['elements'], const ['dynamic']));
associations = json['associations'] == null
? null
: List<MapAssociation>.from(
_createSpecificObject(json['associations'], MapAssociation.parse));
bytes = json['bytes'];
- mirrorReferent =
- createServiceObject(json['mirrorReferent'], const ['InstanceRef']);
- pattern = createServiceObject(json['pattern'], const ['InstanceRef']);
- closureFunction =
- createServiceObject(json['closureFunction'], const ['FuncRef']);
- closureContext =
- createServiceObject(json['closureContext'], const ['ContextRef']);
isCaseSensitive = json['isCaseSensitive'];
isMultiLine = json['isMultiLine'];
- propertyKey =
- createServiceObject(json['propertyKey'], const ['InstanceRef']);
- propertyValue =
- createServiceObject(json['propertyValue'], const ['InstanceRef']);
- typeArguments =
- createServiceObject(json['typeArguments'], const ['TypeArgumentsRef']);
parameterIndex = json['parameterIndex'];
- targetType = createServiceObject(json['targetType'], const ['InstanceRef']);
- bound = createServiceObject(json['bound'], const ['InstanceRef']);
portId = json['portId'];
- allocationLocation =
- createServiceObject(json['allocationLocation'], const ['InstanceRef']);
debugName = json['debugName'];
}
@override
+ String get type => 'Instance';
+
+ @override
Map<String, dynamic> toJson() {
- var json = super.toJson();
- json['type'] = 'Instance';
+ final json = super.toJson();
+ json['type'] = type;
json.addAll({
'kind': kind,
'class': classRef.toJson(),
@@ -4734,11 +4845,10 @@
_setIfNotNull(json, 'name', name);
_setIfNotNull(json, 'typeClass', typeClass?.toJson());
_setIfNotNull(json, 'parameterizedClass', parameterizedClass?.toJson());
- _setIfNotNull(json, 'fields', fields?.map((f) => f?.toJson())?.toList());
+ _setIfNotNull(json, 'fields', fields?.map((f) => f.toJson()).toList());
+ _setIfNotNull(json, 'elements', elements?.map((f) => f.toJson()).toList());
_setIfNotNull(
- json, 'elements', elements?.map((f) => f?.toJson())?.toList());
- _setIfNotNull(
- json, 'associations', associations?.map((f) => f?.toJson())?.toList());
+ json, 'associations', associations?.map((f) => f.toJson()).toList());
_setIfNotNull(json, 'bytes', bytes);
_setIfNotNull(json, 'mirrorReferent', mirrorReferent?.toJson());
_setIfNotNull(json, 'pattern', pattern?.toJson());
@@ -4762,46 +4872,49 @@
operator ==(other) => other is Instance && id == other.id;
- String toString() => '[Instance ' //
- 'type: ${type}, id: ${id}, kind: ${kind}, classRef: ${classRef}]';
+ String toString() =>
+ '[Instance id: ${id}, kind: ${kind}, classRef: ${classRef}]';
}
/// `IsolateRef` is a reference to an `Isolate` object.
class IsolateRef extends Response {
- static IsolateRef parse(Map<String, dynamic> json) =>
+ static IsolateRef? parse(Map<String, dynamic>? json) =>
json == null ? null : IsolateRef._fromJson(json);
/// The id which is passed to the getIsolate RPC to load this isolate.
- String id;
+ late final String id;
/// A numeric id for this isolate, represented as a string. Unique.
- String number;
+ late final String number;
/// A name identifying this isolate. Not guaranteed to be unique.
- String name;
+ late final String name;
/// Specifies whether the isolate was spawned by the VM or embedder for
/// internal use. If `false`, this isolate is likely running user code.
- bool isSystemIsolate;
+ late final bool isSystemIsolate;
IsolateRef({
- @required this.id,
- @required this.number,
- @required this.name,
- @required this.isSystemIsolate,
+ required this.id,
+ required this.number,
+ required this.name,
+ required this.isSystemIsolate,
});
IsolateRef._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
- id = json['id'];
- number = json['number'];
- name = json['name'];
- isSystemIsolate = json['isSystemIsolate'];
+ id = json['id'] ?? '';
+ number = json['number'] ?? '';
+ name = json['name'] ?? '';
+ isSystemIsolate = json['isSystemIsolate'] ?? false;
}
@override
+ String get type => 'IsolateRef';
+
+ @override
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
- json['type'] = '@Isolate';
+ final json = <String, dynamic>{};
+ json['type'] = type;
json.addAll({
'id': id,
'number': number,
@@ -4816,123 +4929,132 @@
operator ==(other) => other is IsolateRef && id == other.id;
String toString() => '[IsolateRef ' //
- 'type: ${type}, id: ${id}, number: ${number}, name: ${name}, ' //
- 'isSystemIsolate: ${isSystemIsolate}]';
+ 'id: ${id}, number: ${number}, name: ${name}, isSystemIsolate: ${isSystemIsolate}]';
}
/// An `Isolate` object provides information about one isolate in the VM.
class Isolate extends Response implements IsolateRef {
- static Isolate parse(Map<String, dynamic> json) =>
+ static Isolate? parse(Map<String, dynamic>? json) =>
json == null ? null : Isolate._fromJson(json);
/// The id which is passed to the getIsolate RPC to reload this isolate.
- String id;
+ late final String id;
/// A numeric id for this isolate, represented as a string. Unique.
- String number;
+ late final String number;
/// A name identifying this isolate. Not guaranteed to be unique.
- String name;
+ late final String name;
/// Specifies whether the isolate was spawned by the VM or embedder for
/// internal use. If `false`, this isolate is likely running user code.
- bool isSystemIsolate;
+ late final bool isSystemIsolate;
/// The list of isolate flags provided to this isolate. See Dart_IsolateFlags
/// in dart_api.h for the list of accepted isolate flags.
- List<IsolateFlag> isolateFlags;
+ late final List<IsolateFlag> isolateFlags;
/// The time that the VM started in milliseconds since the epoch.
///
/// Suitable to pass to DateTime.fromMillisecondsSinceEpoch.
- int startTime;
+ late final int startTime;
/// Is the isolate in a runnable state?
- bool runnable;
+ late final bool runnable;
/// The number of live ports for this isolate.
- int livePorts;
+ late final int livePorts;
/// Will this isolate pause when exiting?
- bool pauseOnExit;
+ late final bool pauseOnExit;
/// The last pause event delivered to the isolate. If the isolate is running,
/// this will be a resume event.
- Event pauseEvent;
+ late final Event pauseEvent;
/// The root library for this isolate.
///
/// Guaranteed to be initialized when the IsolateRunnable event fires.
@optional
- LibraryRef rootLib;
+ late final LibraryRef? rootLib;
/// A list of all libraries for this isolate.
///
/// Guaranteed to be initialized when the IsolateRunnable event fires.
- List<LibraryRef> libraries;
+ late final List<LibraryRef> libraries;
/// A list of all breakpoints for this isolate.
- List<Breakpoint> breakpoints;
+ late final List<Breakpoint> breakpoints;
/// The error that is causing this isolate to exit, if applicable.
@optional
- Error error;
+ late final Error? error;
/// The current pause on exception mode for this isolate.
- /*ExceptionPauseMode*/ String exceptionPauseMode;
+ late final /*ExceptionPauseMode*/ String exceptionPauseMode;
/// The list of service extension RPCs that are registered for this isolate,
/// if any.
@optional
- List<String> extensionRPCs;
+ late final List<String>? extensionRPCs;
Isolate({
- @required this.id,
- @required this.number,
- @required this.name,
- @required this.isSystemIsolate,
- @required this.isolateFlags,
- @required this.startTime,
- @required this.runnable,
- @required this.livePorts,
- @required this.pauseOnExit,
- @required this.pauseEvent,
- @required this.libraries,
- @required this.breakpoints,
- @required this.exceptionPauseMode,
+ required this.id,
+ required this.number,
+ required this.name,
+ required this.isSystemIsolate,
+ required this.isolateFlags,
+ required this.startTime,
+ required this.runnable,
+ required this.livePorts,
+ required this.pauseOnExit,
+ required this.pauseEvent,
+ required this.libraries,
+ required this.breakpoints,
+ required this.exceptionPauseMode,
this.rootLib,
this.error,
this.extensionRPCs,
});
Isolate._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
- id = json['id'];
- number = json['number'];
- name = json['name'];
- isSystemIsolate = json['isSystemIsolate'];
+ id = json['id'] ?? '';
+ number = json['number'] ?? '';
+ name = json['name'] ?? '';
+ isSystemIsolate = json['isSystemIsolate'] ?? false;
isolateFlags = List<IsolateFlag>.from(
- createServiceObject(json['isolateFlags'], const ['IsolateFlag']) ?? []);
- startTime = json['startTime'];
- runnable = json['runnable'];
- livePorts = json['livePorts'];
- pauseOnExit = json['pauseOnExit'];
- pauseEvent = createServiceObject(json['pauseEvent'], const ['Event']);
- rootLib = createServiceObject(json['rootLib'], const ['LibraryRef']);
+ createServiceObject(json['isolateFlags'], const ['IsolateFlag'])
+ as List? ??
+ []);
+ startTime = json['startTime'] ?? -1;
+ runnable = json['runnable'] ?? false;
+ livePorts = json['livePorts'] ?? -1;
+ pauseOnExit = json['pauseOnExit'] ?? false;
+ pauseEvent =
+ createServiceObject(json['pauseEvent']!, const ['Event']) as Event;
+ rootLib = createServiceObject(json['rootLib'], const ['LibraryRef'])
+ as LibraryRef?;
libraries = List<LibraryRef>.from(
- createServiceObject(json['libraries'], const ['LibraryRef']) ?? []);
+ createServiceObject(json['libraries'], const ['LibraryRef']) as List? ??
+ []);
breakpoints = List<Breakpoint>.from(
- createServiceObject(json['breakpoints'], const ['Breakpoint']) ?? []);
- error = createServiceObject(json['error'], const ['Error']);
- exceptionPauseMode = json['exceptionPauseMode'];
+ createServiceObject(json['breakpoints'], const ['Breakpoint'])
+ as List? ??
+ []);
+ error = createServiceObject(json['error'], const ['Error']) as Error?;
+ exceptionPauseMode = json['exceptionPauseMode'] ?? '';
extensionRPCs = json['extensionRPCs'] == null
? null
: List<String>.from(json['extensionRPCs']);
}
@override
+ String get type => 'Isolate';
+
+ @override
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
- json['type'] = 'Isolate';
+ final json = <String, dynamic>{};
+ json['type'] = type;
json.addAll({
'id': id,
'number': number,
@@ -4950,8 +5072,7 @@
});
_setIfNotNull(json, 'rootLib', rootLib?.toJson());
_setIfNotNull(json, 'error', error?.toJson());
- _setIfNotNull(
- json, 'extensionRPCs', extensionRPCs?.map((f) => f)?.toList());
+ _setIfNotNull(json, 'extensionRPCs', extensionRPCs?.map((f) => f).toList());
return json;
}
@@ -4964,27 +5085,27 @@
/// Represents the value of a single isolate flag. See [Isolate].
class IsolateFlag {
- static IsolateFlag parse(Map<String, dynamic> json) =>
+ static IsolateFlag? parse(Map<String, dynamic>? json) =>
json == null ? null : IsolateFlag._fromJson(json);
/// The name of the flag.
- String name;
+ late final String name;
/// The value of this flag as a string.
- String valueAsString;
+ late final String valueAsString;
IsolateFlag({
- @required this.name,
- @required this.valueAsString,
+ required this.name,
+ required this.valueAsString,
});
IsolateFlag._fromJson(Map<String, dynamic> json) {
- name = json['name'];
- valueAsString = json['valueAsString'];
+ name = json['name'] ?? '';
+ valueAsString = json['valueAsString'] ?? '';
}
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
+ final json = <String, dynamic>{};
json.addAll({
'name': name,
'valueAsString': valueAsString,
@@ -4998,41 +5119,44 @@
/// `IsolateGroupRef` is a reference to an `IsolateGroup` object.
class IsolateGroupRef extends Response {
- static IsolateGroupRef parse(Map<String, dynamic> json) =>
+ static IsolateGroupRef? parse(Map<String, dynamic>? json) =>
json == null ? null : IsolateGroupRef._fromJson(json);
/// The id which is passed to the getIsolateGroup RPC to load this isolate
/// group.
- String id;
+ late final String id;
/// A numeric id for this isolate group, represented as a string. Unique.
- String number;
+ late final String number;
/// A name identifying this isolate group. Not guaranteed to be unique.
- String name;
+ late final String name;
/// Specifies whether the isolate group was spawned by the VM or embedder for
/// internal use. If `false`, this isolate group is likely running user code.
- bool isSystemIsolateGroup;
+ late final bool isSystemIsolateGroup;
IsolateGroupRef({
- @required this.id,
- @required this.number,
- @required this.name,
- @required this.isSystemIsolateGroup,
+ required this.id,
+ required this.number,
+ required this.name,
+ required this.isSystemIsolateGroup,
});
IsolateGroupRef._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
- id = json['id'];
- number = json['number'];
- name = json['name'];
- isSystemIsolateGroup = json['isSystemIsolateGroup'];
+ id = json['id'] ?? '';
+ number = json['number'] ?? '';
+ name = json['name'] ?? '';
+ isSystemIsolateGroup = json['isSystemIsolateGroup'] ?? false;
}
@override
+ String get type => 'IsolateGroupRef';
+
+ @override
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
- json['type'] = '@IsolateGroup';
+ final json = <String, dynamic>{};
+ json['type'] = type;
json.addAll({
'id': id,
'number': number,
@@ -5047,52 +5171,55 @@
operator ==(other) => other is IsolateGroupRef && id == other.id;
String toString() => '[IsolateGroupRef ' //
- 'type: ${type}, id: ${id}, number: ${number}, name: ${name}, ' //
- 'isSystemIsolateGroup: ${isSystemIsolateGroup}]';
+ 'id: ${id}, number: ${number}, name: ${name}, isSystemIsolateGroup: ${isSystemIsolateGroup}]';
}
/// An `Isolate` object provides information about one isolate in the VM.
class IsolateGroup extends Response implements IsolateGroupRef {
- static IsolateGroup parse(Map<String, dynamic> json) =>
+ static IsolateGroup? parse(Map<String, dynamic>? json) =>
json == null ? null : IsolateGroup._fromJson(json);
/// The id which is passed to the getIsolate RPC to reload this isolate.
- String id;
+ late final String id;
/// A numeric id for this isolate, represented as a string. Unique.
- String number;
+ late final String number;
/// A name identifying this isolate. Not guaranteed to be unique.
- String name;
+ late final String name;
/// Specifies whether the isolate group was spawned by the VM or embedder for
/// internal use. If `false`, this isolate group is likely running user code.
- bool isSystemIsolateGroup;
+ late final bool isSystemIsolateGroup;
/// A list of all isolates in this isolate group.
- List<IsolateRef> isolates;
+ late final List<IsolateRef> isolates;
IsolateGroup({
- @required this.id,
- @required this.number,
- @required this.name,
- @required this.isSystemIsolateGroup,
- @required this.isolates,
+ required this.id,
+ required this.number,
+ required this.name,
+ required this.isSystemIsolateGroup,
+ required this.isolates,
});
IsolateGroup._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
- id = json['id'];
- number = json['number'];
- name = json['name'];
- isSystemIsolateGroup = json['isSystemIsolateGroup'];
+ id = json['id'] ?? '';
+ number = json['number'] ?? '';
+ name = json['name'] ?? '';
+ isSystemIsolateGroup = json['isSystemIsolateGroup'] ?? false;
isolates = List<IsolateRef>.from(
- createServiceObject(json['isolates'], const ['IsolateRef']) ?? []);
+ createServiceObject(json['isolates'], const ['IsolateRef']) as List? ??
+ []);
}
@override
+ String get type => 'IsolateGroup';
+
+ @override
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
- json['type'] = 'IsolateGroup';
+ final json = <String, dynamic>{};
+ json['type'] = type;
json.addAll({
'id': id,
'number': number,
@@ -5108,75 +5235,79 @@
operator ==(other) => other is IsolateGroup && id == other.id;
String toString() => '[IsolateGroup ' //
- 'type: ${type}, id: ${id}, number: ${number}, name: ${name}, ' //
- 'isSystemIsolateGroup: ${isSystemIsolateGroup}, isolates: ${isolates}]';
+ 'id: ${id}, number: ${number}, name: ${name}, isSystemIsolateGroup: ${isSystemIsolateGroup}, ' //
+ 'isolates: ${isolates}]';
}
/// See [getInboundReferences].
class InboundReferences extends Response {
- static InboundReferences parse(Map<String, dynamic> json) =>
+ static InboundReferences? parse(Map<String, dynamic>? json) =>
json == null ? null : InboundReferences._fromJson(json);
/// An array of inbound references to an object.
- List<InboundReference> references;
+ late final List<InboundReference> references;
InboundReferences({
- @required this.references,
+ required this.references,
});
InboundReferences._fromJson(Map<String, dynamic> json)
: super._fromJson(json) {
references = List<InboundReference>.from(
- createServiceObject(json['references'], const ['InboundReference']) ??
+ createServiceObject(json['references'], const ['InboundReference'])
+ as List? ??
[]);
}
@override
+ String get type => 'InboundReferences';
+
+ @override
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
- json['type'] = 'InboundReferences';
+ final json = <String, dynamic>{};
+ json['type'] = type;
json.addAll({
'references': references.map((f) => f.toJson()).toList(),
});
return json;
}
- String toString() =>
- '[InboundReferences type: ${type}, references: ${references}]';
+ String toString() => '[InboundReferences references: ${references}]';
}
/// See [getInboundReferences].
class InboundReference {
- static InboundReference parse(Map<String, dynamic> json) =>
+ static InboundReference? parse(Map<String, dynamic>? json) =>
json == null ? null : InboundReference._fromJson(json);
/// The object holding the inbound reference.
- ObjRef source;
+ late final ObjRef source;
/// If source is a List, parentListIndex is the index of the inbound
/// reference.
@optional
- int parentListIndex;
+ late final int? parentListIndex;
/// If source is a field of an object, parentField is the field containing the
/// inbound reference.
@optional
- FieldRef parentField;
+ late final FieldRef? parentField;
InboundReference({
- @required this.source,
+ required this.source,
this.parentListIndex,
this.parentField,
});
InboundReference._fromJson(Map<String, dynamic> json) {
- source = createServiceObject(json['source'], const ['ObjRef']);
+ source = createServiceObject(json['source']!, const ['ObjRef']) as ObjRef;
parentListIndex = json['parentListIndex'];
- parentField = createServiceObject(json['parentField'], const ['FieldRef']);
+ parentField = createServiceObject(json['parentField'], const ['FieldRef'])
+ as FieldRef?;
}
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
+ final json = <String, dynamic>{};
json.addAll({
'source': source.toJson(),
});
@@ -5190,30 +5321,34 @@
/// See [getInstances].
class InstanceSet extends Response {
- static InstanceSet parse(Map<String, dynamic> json) =>
+ static InstanceSet? parse(Map<String, dynamic>? json) =>
json == null ? null : InstanceSet._fromJson(json);
/// The number of instances of the requested type currently allocated.
- int totalCount;
+ late final int totalCount;
/// An array of instances of the requested type.
- List<ObjRef> instances;
+ late final List<ObjRef> instances;
InstanceSet({
- @required this.totalCount,
- @required this.instances,
+ required this.totalCount,
+ required this.instances,
});
InstanceSet._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
- totalCount = json['totalCount'];
+ totalCount = json['totalCount'] ?? -1;
instances = List<ObjRef>.from(createServiceObject(
- json['instances'] ?? json['samples'], const ['ObjRef']));
+ (json['instances'] ?? json['samples']!) as List, const ['ObjRef'])!
+ as List);
}
@override
+ String get type => 'InstanceSet';
+
+ @override
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
- json['type'] = 'InstanceSet';
+ final json = <String, dynamic>{};
+ json['type'] = type;
json.addAll({
'totalCount': totalCount,
'instances': instances.map((f) => f.toJson()).toList(),
@@ -5221,36 +5356,41 @@
return json;
}
- String toString() => '[InstanceSet ' //
- 'type: ${type}, totalCount: ${totalCount}, instances: ${instances}]';
+ String toString() =>
+ '[InstanceSet totalCount: ${totalCount}, instances: ${instances}]';
}
/// `LibraryRef` is a reference to a `Library`.
class LibraryRef extends ObjRef {
- static LibraryRef parse(Map<String, dynamic> json) =>
+ static LibraryRef? parse(Map<String, dynamic>? json) =>
json == null ? null : LibraryRef._fromJson(json);
/// The name of this library.
- String name;
+ late final String name;
/// The uri of this library.
- String uri;
+ late final String uri;
LibraryRef({
- @required this.name,
- @required this.uri,
- @required String id,
- }) : super(id: id);
+ required this.name,
+ required this.uri,
+ required String id,
+ }) : super(
+ id: id,
+ );
LibraryRef._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
- name = json['name'];
- uri = json['uri'];
+ name = json['name'] ?? '';
+ uri = json['uri'] ?? '';
}
@override
+ String get type => 'LibraryRef';
+
+ @override
Map<String, dynamic> toJson() {
- var json = super.toJson();
- json['type'] = '@Library';
+ final json = super.toJson();
+ json['type'] = type;
json.addAll({
'name': name,
'uri': uri,
@@ -5262,73 +5402,81 @@
operator ==(other) => other is LibraryRef && id == other.id;
- String toString() =>
- '[LibraryRef type: ${type}, id: ${id}, name: ${name}, uri: ${uri}]';
+ String toString() => '[LibraryRef id: ${id}, name: ${name}, uri: ${uri}]';
}
/// A `Library` provides information about a Dart language library.
///
/// See [setLibraryDebuggable].
class Library extends Obj implements LibraryRef {
- static Library parse(Map<String, dynamic> json) =>
+ static Library? parse(Map<String, dynamic>? json) =>
json == null ? null : Library._fromJson(json);
/// The name of this library.
- String name;
+ late final String name;
/// The uri of this library.
- String uri;
+ late final String uri;
/// Is this library debuggable? Default true.
- bool debuggable;
+ late final bool debuggable;
/// A list of the imports for this library.
- List<LibraryDependency> dependencies;
+ late final List<LibraryDependency> dependencies;
/// A list of the scripts which constitute this library.
- List<ScriptRef> scripts;
+ late final List<ScriptRef> scripts;
/// A list of the top-level variables in this library.
- List<FieldRef> variables;
+ late final List<FieldRef> variables;
/// A list of the top-level functions in this library.
- List<FuncRef> functions;
+ late final List<FuncRef> functions;
/// A list of all classes in this library.
- List<ClassRef> classes;
+ late final List<ClassRef> classes;
Library({
- @required this.name,
- @required this.uri,
- @required this.debuggable,
- @required this.dependencies,
- @required this.scripts,
- @required this.variables,
- @required this.functions,
- @required this.classes,
- @required String id,
- }) : super(id: id);
+ required this.name,
+ required this.uri,
+ required this.debuggable,
+ required this.dependencies,
+ required this.scripts,
+ required this.variables,
+ required this.functions,
+ required this.classes,
+ required String id,
+ }) : super(
+ id: id,
+ );
Library._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
- name = json['name'];
- uri = json['uri'];
- debuggable = json['debuggable'];
+ name = json['name'] ?? '';
+ uri = json['uri'] ?? '';
+ debuggable = json['debuggable'] ?? false;
dependencies = List<LibraryDependency>.from(
- _createSpecificObject(json['dependencies'], LibraryDependency.parse));
+ _createSpecificObject(json['dependencies']!, LibraryDependency.parse));
scripts = List<ScriptRef>.from(
- createServiceObject(json['scripts'], const ['ScriptRef']) ?? []);
+ createServiceObject(json['scripts'], const ['ScriptRef']) as List? ??
+ []);
variables = List<FieldRef>.from(
- createServiceObject(json['variables'], const ['FieldRef']) ?? []);
+ createServiceObject(json['variables'], const ['FieldRef']) as List? ??
+ []);
functions = List<FuncRef>.from(
- createServiceObject(json['functions'], const ['FuncRef']) ?? []);
+ createServiceObject(json['functions'], const ['FuncRef']) as List? ??
+ []);
classes = List<ClassRef>.from(
- createServiceObject(json['classes'], const ['ClassRef']) ?? []);
+ createServiceObject(json['classes'], const ['ClassRef']) as List? ??
+ []);
}
@override
+ String get type => 'Library';
+
+ @override
Map<String, dynamic> toJson() {
- var json = super.toJson();
- json['type'] = 'Library';
+ final json = super.toJson();
+ json['type'] = type;
json.addAll({
'name': name,
'uri': uri,
@@ -5351,37 +5499,38 @@
/// A `LibraryDependency` provides information about an import or export.
class LibraryDependency {
- static LibraryDependency parse(Map<String, dynamic> json) =>
+ static LibraryDependency? parse(Map<String, dynamic>? json) =>
json == null ? null : LibraryDependency._fromJson(json);
/// Is this dependency an import (rather than an export)?
- bool isImport;
+ late final bool isImport;
/// Is this dependency deferred?
- bool isDeferred;
+ late final bool isDeferred;
/// The prefix of an 'as' import, or null.
- String prefix;
+ late final String prefix;
/// The library being imported or exported.
- LibraryRef target;
+ late final LibraryRef target;
LibraryDependency({
- @required this.isImport,
- @required this.isDeferred,
- @required this.prefix,
- @required this.target,
+ required this.isImport,
+ required this.isDeferred,
+ required this.prefix,
+ required this.target,
});
LibraryDependency._fromJson(Map<String, dynamic> json) {
- isImport = json['isImport'];
- isDeferred = json['isDeferred'];
- prefix = json['prefix'];
- target = createServiceObject(json['target'], const ['LibraryRef']);
+ isImport = json['isImport'] ?? false;
+ isDeferred = json['isDeferred'] ?? false;
+ prefix = json['prefix'] ?? '';
+ target = createServiceObject(json['target']!, const ['LibraryRef'])
+ as LibraryRef;
}
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
+ final json = <String, dynamic>{};
json.addAll({
'isImport': isImport,
'isDeferred': isDeferred,
@@ -5397,62 +5546,70 @@
}
class LogRecord extends Response {
- static LogRecord parse(Map<String, dynamic> json) =>
+ static LogRecord? parse(Map<String, dynamic>? json) =>
json == null ? null : LogRecord._fromJson(json);
/// The log message.
- InstanceRef message;
+ late final InstanceRef message;
/// The timestamp.
- int time;
+ late final int time;
/// The severity level (a value between 0 and 2000).
///
/// See the package:logging `Level` class for an overview of the possible
/// values.
- int level;
+ late final int level;
/// A monotonically increasing sequence number.
- int sequenceNumber;
+ late final int sequenceNumber;
/// The name of the source of the log message.
- InstanceRef loggerName;
+ late final InstanceRef loggerName;
/// The zone where the log was emitted.
- InstanceRef zone;
+ late final InstanceRef zone;
/// An error object associated with this log event.
- InstanceRef error;
+ late final InstanceRef error;
/// A stack trace associated with this log event.
- InstanceRef stackTrace;
+ late final InstanceRef stackTrace;
LogRecord({
- @required this.message,
- @required this.time,
- @required this.level,
- @required this.sequenceNumber,
- @required this.loggerName,
- @required this.zone,
- @required this.error,
- @required this.stackTrace,
+ required this.message,
+ required this.time,
+ required this.level,
+ required this.sequenceNumber,
+ required this.loggerName,
+ required this.zone,
+ required this.error,
+ required this.stackTrace,
});
LogRecord._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
- message = createServiceObject(json['message'], const ['InstanceRef']);
- time = json['time'];
- level = json['level'];
- sequenceNumber = json['sequenceNumber'];
- loggerName = createServiceObject(json['loggerName'], const ['InstanceRef']);
- zone = createServiceObject(json['zone'], const ['InstanceRef']);
- error = createServiceObject(json['error'], const ['InstanceRef']);
- stackTrace = createServiceObject(json['stackTrace'], const ['InstanceRef']);
+ message = createServiceObject(json['message']!, const ['InstanceRef'])
+ as InstanceRef;
+ time = json['time'] ?? -1;
+ level = json['level'] ?? -1;
+ sequenceNumber = json['sequenceNumber'] ?? -1;
+ loggerName = createServiceObject(json['loggerName']!, const ['InstanceRef'])
+ as InstanceRef;
+ zone = createServiceObject(json['zone']!, const ['InstanceRef'])
+ as InstanceRef;
+ error = createServiceObject(json['error']!, const ['InstanceRef'])
+ as InstanceRef;
+ stackTrace = createServiceObject(json['stackTrace']!, const ['InstanceRef'])
+ as InstanceRef;
}
@override
+ String get type => 'LogRecord';
+
+ @override
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
- json['type'] = 'LogRecord';
+ final json = <String, dynamic>{};
+ json['type'] = type;
json.addAll({
'message': message.toJson(),
'time': time,
@@ -5470,28 +5627,30 @@
}
class MapAssociation {
- static MapAssociation parse(Map<String, dynamic> json) =>
+ static MapAssociation? parse(Map<String, dynamic>? json) =>
json == null ? null : MapAssociation._fromJson(json);
/// [key] can be one of [InstanceRef] or [Sentinel].
- dynamic key;
+ late final dynamic key;
/// [value] can be one of [InstanceRef] or [Sentinel].
- dynamic value;
+ late final dynamic value;
MapAssociation({
- @required this.key,
- @required this.value,
+ required this.key,
+ required this.value,
});
MapAssociation._fromJson(Map<String, dynamic> json) {
- key = createServiceObject(json['key'], const ['InstanceRef', 'Sentinel']);
+ key = createServiceObject(json['key']!, const ['InstanceRef', 'Sentinel'])
+ as dynamic;
value =
- createServiceObject(json['value'], const ['InstanceRef', 'Sentinel']);
+ createServiceObject(json['value']!, const ['InstanceRef', 'Sentinel'])
+ as dynamic;
}
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
+ final json = <String, dynamic>{};
json.addAll({
'key': key.toJson(),
'value': value.toJson(),
@@ -5505,7 +5664,7 @@
/// A `MemoryUsage` object provides heap usage information for a specific
/// isolate at a given point in time.
class MemoryUsage extends Response {
- static MemoryUsage parse(Map<String, dynamic> json) =>
+ static MemoryUsage? parse(Map<String, dynamic>? json) =>
json == null ? null : MemoryUsage._fromJson(json);
/// The amount of non-Dart memory that is retained by Dart objects. For
@@ -5515,32 +5674,35 @@
/// supplied to these APIs from the VM embedder or native extensions. This
/// external memory applies GC pressure, but is separate from heapUsage and
/// heapCapacity.
- int externalUsage;
+ late final int externalUsage;
/// The total capacity of the heap in bytes. This is the amount of memory used
/// by the Dart heap from the perspective of the operating system.
- int heapCapacity;
+ late final int heapCapacity;
/// The current heap memory usage in bytes. Heap usage is always less than or
/// equal to the heap capacity.
- int heapUsage;
+ late final int heapUsage;
MemoryUsage({
- @required this.externalUsage,
- @required this.heapCapacity,
- @required this.heapUsage,
+ required this.externalUsage,
+ required this.heapCapacity,
+ required this.heapUsage,
});
MemoryUsage._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
- externalUsage = json['externalUsage'];
- heapCapacity = json['heapCapacity'];
- heapUsage = json['heapUsage'];
+ externalUsage = json['externalUsage'] ?? -1;
+ heapCapacity = json['heapCapacity'] ?? -1;
+ heapUsage = json['heapUsage'] ?? -1;
}
@override
+ String get type => 'MemoryUsage';
+
+ @override
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
- json['type'] = 'MemoryUsage';
+ final json = <String, dynamic>{};
+ json['type'] = type;
json.addAll({
'externalUsage': externalUsage,
'heapCapacity': heapCapacity,
@@ -5550,60 +5712,65 @@
}
String toString() => '[MemoryUsage ' //
- 'type: ${type}, externalUsage: ${externalUsage}, heapCapacity: ${heapCapacity}, ' //
+ 'externalUsage: ${externalUsage}, heapCapacity: ${heapCapacity}, ' //
'heapUsage: ${heapUsage}]';
}
/// A `Message` provides information about a pending isolate message and the
/// function that will be invoked to handle it.
class Message extends Response {
- static Message parse(Map<String, dynamic> json) =>
+ static Message? parse(Map<String, dynamic>? json) =>
json == null ? null : Message._fromJson(json);
/// The index in the isolate's message queue. The 0th message being the next
/// message to be processed.
- int index;
+ late final int index;
/// An advisory name describing this message.
- String name;
+ late final String name;
/// An instance id for the decoded message. This id can be passed to other
/// RPCs, for example, getObject or evaluate.
- String messageObjectId;
+ late final String messageObjectId;
/// The size (bytes) of the encoded message.
- int size;
+ late final int size;
/// A reference to the function that will be invoked to handle this message.
@optional
- FuncRef handler;
+ late final FuncRef? handler;
/// The source location of handler.
@optional
- SourceLocation location;
+ late final SourceLocation? location;
Message({
- @required this.index,
- @required this.name,
- @required this.messageObjectId,
- @required this.size,
+ required this.index,
+ required this.name,
+ required this.messageObjectId,
+ required this.size,
this.handler,
this.location,
});
Message._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
- index = json['index'];
- name = json['name'];
- messageObjectId = json['messageObjectId'];
- size = json['size'];
- handler = createServiceObject(json['handler'], const ['FuncRef']);
- location = createServiceObject(json['location'], const ['SourceLocation']);
+ index = json['index'] ?? -1;
+ name = json['name'] ?? '';
+ messageObjectId = json['messageObjectId'] ?? '';
+ size = json['size'] ?? -1;
+ handler =
+ createServiceObject(json['handler'], const ['FuncRef']) as FuncRef?;
+ location = createServiceObject(json['location'], const ['SourceLocation'])
+ as SourceLocation?;
}
@override
+ String get type => 'Message';
+
+ @override
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
- json['type'] = 'Message';
+ final json = <String, dynamic>{};
+ json['type'] = type;
json.addAll({
'index': index,
'name': name,
@@ -5616,29 +5783,29 @@
}
String toString() => '[Message ' //
- 'type: ${type}, index: ${index}, name: ${name}, messageObjectId: ${messageObjectId}, ' //
+ 'index: ${index}, name: ${name}, messageObjectId: ${messageObjectId}, ' //
'size: ${size}]';
}
/// A `NativeFunction` object is used to represent native functions in profiler
/// samples. See [CpuSamples];
class NativeFunction {
- static NativeFunction parse(Map<String, dynamic> json) =>
+ static NativeFunction? parse(Map<String, dynamic>? json) =>
json == null ? null : NativeFunction._fromJson(json);
/// The name of the native function this object represents.
- String name;
+ late final String name;
NativeFunction({
- @required this.name,
+ required this.name,
});
NativeFunction._fromJson(Map<String, dynamic> json) {
- name = json['name'];
+ name = json['name'] ?? '';
}
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
+ final json = <String, dynamic>{};
json.addAll({
'name': name,
});
@@ -5650,25 +5817,35 @@
/// `NullValRef` is a reference to an a `NullVal`.
class NullValRef extends InstanceRef {
- static NullValRef parse(Map<String, dynamic> json) =>
+ static NullValRef? parse(Map<String, dynamic>? json) =>
json == null ? null : NullValRef._fromJson(json);
/// Always 'null'.
@override
- String valueAsString;
+ covariant late final String valueAsString;
NullValRef({
- @required this.valueAsString,
- });
+ required this.valueAsString,
+ }) : super(
+ id: 'instance/null',
+ kind: InstanceKind.kNull,
+ classRef: ClassRef(
+ id: 'class/null',
+ name: 'Null',
+ ),
+ );
NullValRef._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
- valueAsString = json['valueAsString'];
+ valueAsString = json['valueAsString'] ?? '';
}
@override
+ String get type => 'NullValRef';
+
+ @override
Map<String, dynamic> toJson() {
- var json = super.toJson();
- json['type'] = '@Null';
+ final json = super.toJson();
+ json['type'] = type;
json.addAll({
'valueAsString': valueAsString,
});
@@ -5680,31 +5857,40 @@
operator ==(other) => other is NullValRef && id == other.id;
String toString() => '[NullValRef ' //
- 'type: ${type}, id: ${id}, kind: ${kind}, classRef: ${classRef}, ' //
- 'valueAsString: ${valueAsString}]';
+ 'id: ${id}, kind: ${kind}, classRef: ${classRef}, valueAsString: ${valueAsString}]';
}
/// A `NullVal` object represents the Dart language value null.
class NullVal extends Instance implements NullValRef {
- static NullVal parse(Map<String, dynamic> json) =>
+ static NullVal? parse(Map<String, dynamic>? json) =>
json == null ? null : NullVal._fromJson(json);
/// Always 'null'.
@override
- String valueAsString;
+ covariant late final String valueAsString;
NullVal({
- @required this.valueAsString,
- });
+ required this.valueAsString,
+ }) : super(
+ id: 'instance/null',
+ kind: InstanceKind.kNull,
+ classRef: ClassRef(
+ id: 'class/null',
+ name: 'Null',
+ ),
+ );
NullVal._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
- valueAsString = json['valueAsString'];
+ valueAsString = json['valueAsString'] ?? '';
}
@override
+ String get type => 'NullVal';
+
+ @override
Map<String, dynamic> toJson() {
- var json = super.toJson();
- json['type'] = 'Null';
+ final json = super.toJson();
+ json['type'] = type;
json.addAll({
'valueAsString': valueAsString,
});
@@ -5716,39 +5902,41 @@
operator ==(other) => other is NullVal && id == other.id;
String toString() => '[NullVal ' //
- 'type: ${type}, id: ${id}, kind: ${kind}, classRef: ${classRef}, ' //
- 'valueAsString: ${valueAsString}]';
+ 'id: ${id}, kind: ${kind}, classRef: ${classRef}, valueAsString: ${valueAsString}]';
}
/// `ObjRef` is a reference to a `Obj`.
class ObjRef extends Response {
- static ObjRef parse(Map<String, dynamic> json) =>
+ static ObjRef? parse(Map<String, dynamic>? json) =>
json == null ? null : ObjRef._fromJson(json);
/// A unique identifier for an Object. Passed to the getObject RPC to load
/// this Object.
- String id;
+ late final String id;
/// Provided and set to true if the id of an Object is fixed. If true, the id
/// of an Object is guaranteed not to change or expire. The object may,
/// however, still be _Collected_.
@optional
- bool fixedId;
+ late final bool? fixedId;
ObjRef({
- @required this.id,
+ required this.id,
this.fixedId,
});
ObjRef._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
- id = json['id'];
+ id = json['id'] ?? '';
fixedId = json['fixedId'];
}
@override
+ String get type => 'ObjRef';
+
+ @override
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
- json['type'] = '@Object';
+ final json = <String, dynamic>{};
+ json['type'] = type;
json.addAll({
'id': id,
});
@@ -5760,25 +5948,25 @@
operator ==(other) => other is ObjRef && id == other.id;
- String toString() => '[ObjRef type: ${type}, id: ${id}]';
+ String toString() => '[ObjRef id: ${id}]';
}
/// An `Obj` is a persistent object that is owned by some isolate.
class Obj extends Response implements ObjRef {
- static Obj parse(Map<String, dynamic> json) =>
+ static Obj? parse(Map<String, dynamic>? json) =>
json == null ? null : Obj._fromJson(json);
/// A unique identifier for an Object. Passed to the getObject RPC to reload
/// this Object.
///
/// Some objects may get a new id when they are reloaded.
- String id;
+ late final String id;
/// Provided and set to true if the id of an Object is fixed. If true, the id
/// of an Object is guaranteed not to change or expire. The object may,
/// however, still be _Collected_.
@optional
- bool fixedId;
+ late final bool? fixedId;
/// If an object is allocated in the Dart heap, it will have a corresponding
/// class object.
@@ -5789,7 +5977,7 @@
/// Moving an Object into or out of the heap is considered a backwards
/// compatible change for types other than Instance.
@optional
- ClassRef classRef;
+ late final ClassRef? classRef;
/// The size of this object in the heap.
///
@@ -5799,26 +5987,30 @@
/// implementation, this occurs for small integers, which are stored entirely
/// within their object pointers.
@optional
- int size;
+ late final int? size;
Obj({
- @required this.id,
+ required this.id,
this.fixedId,
this.classRef,
this.size,
});
Obj._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
- id = json['id'];
+ id = json['id'] ?? '';
fixedId = json['fixedId'];
- classRef = createServiceObject(json['class'], const ['ClassRef']);
+ classRef =
+ createServiceObject(json['class'], const ['ClassRef']) as ClassRef?;
size = json['size'];
}
@override
+ String get type => 'Obj';
+
+ @override
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
- json['type'] = 'Object';
+ final json = <String, dynamic>{};
+ json['type'] = type;
json.addAll({
'id': id,
});
@@ -5832,38 +6024,42 @@
operator ==(other) => other is Obj && id == other.id;
- String toString() => '[Obj type: ${type}, id: ${id}]';
+ String toString() => '[Obj id: ${id}]';
}
/// A `PortList` contains a list of ports associated with some isolate.
///
/// See [getPort].
class PortList extends Response {
- static PortList parse(Map<String, dynamic> json) =>
+ static PortList? parse(Map<String, dynamic>? json) =>
json == null ? null : PortList._fromJson(json);
- List<InstanceRef> ports;
+ late final List<InstanceRef> ports;
PortList({
- @required this.ports,
+ required this.ports,
});
PortList._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
ports = List<InstanceRef>.from(
- createServiceObject(json['ports'], const ['InstanceRef']) ?? []);
+ createServiceObject(json['ports'], const ['InstanceRef']) as List? ??
+ []);
}
@override
+ String get type => 'PortList';
+
+ @override
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
- json['type'] = 'PortList';
+ final json = <String, dynamic>{};
+ json['type'] = type;
json.addAll({
'ports': ports.map((f) => f.toJson()).toList(),
});
return json;
}
- String toString() => '[PortList type: ${type}, ports: ${ports}]';
+ String toString() => '[PortList ports: ${ports}]';
}
/// A `ProfileFunction` contains profiling information about a Dart or native
@@ -5871,43 +6067,44 @@
///
/// See [CpuSamples].
class ProfileFunction {
- static ProfileFunction parse(Map<String, dynamic> json) =>
+ static ProfileFunction? parse(Map<String, dynamic>? json) =>
json == null ? null : ProfileFunction._fromJson(json);
/// The kind of function this object represents.
- String kind;
+ late final String kind;
/// The number of times function appeared on the stack during sampling events.
- int inclusiveTicks;
+ late final int inclusiveTicks;
/// The number of times function appeared on the top of the stack during
/// sampling events.
- int exclusiveTicks;
+ late final int exclusiveTicks;
/// The resolved URL for the script containing function.
- String resolvedUrl;
+ late final String resolvedUrl;
/// The function captured during profiling.
- dynamic function;
+ late final dynamic function;
ProfileFunction({
- @required this.kind,
- @required this.inclusiveTicks,
- @required this.exclusiveTicks,
- @required this.resolvedUrl,
- @required this.function,
+ required this.kind,
+ required this.inclusiveTicks,
+ required this.exclusiveTicks,
+ required this.resolvedUrl,
+ required this.function,
});
ProfileFunction._fromJson(Map<String, dynamic> json) {
- kind = json['kind'];
- inclusiveTicks = json['inclusiveTicks'];
- exclusiveTicks = json['exclusiveTicks'];
- resolvedUrl = json['resolvedUrl'];
- function = createServiceObject(json['function'], const ['dynamic']);
+ kind = json['kind'] ?? '';
+ inclusiveTicks = json['inclusiveTicks'] ?? -1;
+ exclusiveTicks = json['exclusiveTicks'] ?? -1;
+ resolvedUrl = json['resolvedUrl'] ?? '';
+ function =
+ createServiceObject(json['function']!, const ['dynamic']) as dynamic;
}
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
+ final json = <String, dynamic>{};
json.addAll({
'kind': kind,
'inclusiveTicks': inclusiveTicks,
@@ -5928,62 +6125,66 @@
///
/// See [Protocol] and [getSupportedProtocols].
class ProtocolList extends Response {
- static ProtocolList parse(Map<String, dynamic> json) =>
+ static ProtocolList? parse(Map<String, dynamic>? json) =>
json == null ? null : ProtocolList._fromJson(json);
/// A list of supported protocols provided by this service.
- List<Protocol> protocols;
+ late final List<Protocol> protocols;
ProtocolList({
- @required this.protocols,
+ required this.protocols,
});
ProtocolList._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
protocols = List<Protocol>.from(
- createServiceObject(json['protocols'], const ['Protocol']) ?? []);
+ createServiceObject(json['protocols'], const ['Protocol']) as List? ??
+ []);
}
@override
+ String get type => 'ProtocolList';
+
+ @override
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
- json['type'] = 'ProtocolList';
+ final json = <String, dynamic>{};
+ json['type'] = type;
json.addAll({
'protocols': protocols.map((f) => f.toJson()).toList(),
});
return json;
}
- String toString() => '[ProtocolList type: ${type}, protocols: ${protocols}]';
+ String toString() => '[ProtocolList protocols: ${protocols}]';
}
/// See [getSupportedProtocols].
class Protocol {
- static Protocol parse(Map<String, dynamic> json) =>
+ static Protocol? parse(Map<String, dynamic>? json) =>
json == null ? null : Protocol._fromJson(json);
/// The name of the supported protocol.
- String protocolName;
+ late final String protocolName;
/// The major revision of the protocol.
- int major;
+ late final int major;
/// The minor revision of the protocol.
- int minor;
+ late final int minor;
Protocol({
- @required this.protocolName,
- @required this.major,
- @required this.minor,
+ required this.protocolName,
+ required this.major,
+ required this.minor,
});
Protocol._fromJson(Map<String, dynamic> json) {
- protocolName = json['protocolName'];
- major = json['major'];
- minor = json['minor'];
+ protocolName = json['protocolName'] ?? '';
+ major = json['major'] ?? -1;
+ minor = json['minor'] ?? -1;
}
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
+ final json = <String, dynamic>{};
json.addAll({
'protocolName': protocolName,
'major': major,
@@ -5998,68 +6199,73 @@
/// Set [getProcessMemoryUsage].
class ProcessMemoryUsage extends Response {
- static ProcessMemoryUsage parse(Map<String, dynamic> json) =>
+ static ProcessMemoryUsage? parse(Map<String, dynamic>? json) =>
json == null ? null : ProcessMemoryUsage._fromJson(json);
- ProcessMemoryItem root;
+ late final ProcessMemoryItem root;
ProcessMemoryUsage({
- @required this.root,
+ required this.root,
});
ProcessMemoryUsage._fromJson(Map<String, dynamic> json)
: super._fromJson(json) {
- root = createServiceObject(json['root'], const ['ProcessMemoryItem']);
+ root = createServiceObject(json['root']!, const ['ProcessMemoryItem'])
+ as ProcessMemoryItem;
}
@override
+ String get type => 'ProcessMemoryUsage';
+
+ @override
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
- json['type'] = 'ProcessMemoryUsage';
+ final json = <String, dynamic>{};
+ json['type'] = type;
json.addAll({
'root': root.toJson(),
});
return json;
}
- String toString() => '[ProcessMemoryUsage type: ${type}, root: ${root}]';
+ String toString() => '[ProcessMemoryUsage root: ${root}]';
}
class ProcessMemoryItem {
- static ProcessMemoryItem parse(Map<String, dynamic> json) =>
+ static ProcessMemoryItem? parse(Map<String, dynamic>? json) =>
json == null ? null : ProcessMemoryItem._fromJson(json);
/// A short name for this bucket of memory.
- String name;
+ late final String name;
/// A longer description for this item.
- String description;
+ late final String description;
/// The amount of memory in bytes. This is a retained size, not a shallow
/// size. That is, it includes the size of children.
- int size;
+ late final int size;
/// Subdivisons of this bucket of memory.
- List<ProcessMemoryItem> children;
+ late final List<ProcessMemoryItem> children;
ProcessMemoryItem({
- @required this.name,
- @required this.description,
- @required this.size,
- @required this.children,
+ required this.name,
+ required this.description,
+ required this.size,
+ required this.children,
});
ProcessMemoryItem._fromJson(Map<String, dynamic> json) {
- name = json['name'];
- description = json['description'];
- size = json['size'];
+ name = json['name'] ?? '';
+ description = json['description'] ?? '';
+ size = json['size'] ?? -1;
children = List<ProcessMemoryItem>.from(
- createServiceObject(json['children'], const ['ProcessMemoryItem']) ??
+ createServiceObject(json['children'], const ['ProcessMemoryItem'])
+ as List? ??
[]);
}
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
+ final json = <String, dynamic>{};
json.addAll({
'name': name,
'description': description,
@@ -6075,69 +6281,73 @@
}
class ReloadReport extends Response {
- static ReloadReport parse(Map<String, dynamic> json) =>
+ static ReloadReport? parse(Map<String, dynamic>? json) =>
json == null ? null : ReloadReport._fromJson(json);
/// Did the reload succeed or fail?
- bool success;
+ late final bool success;
ReloadReport({
- @required this.success,
+ required this.success,
});
ReloadReport._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
- success = json['success'];
+ success = json['success'] ?? false;
}
@override
+ String get type => 'ReloadReport';
+
+ @override
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
- json['type'] = 'ReloadReport';
+ final json = <String, dynamic>{};
+ json['type'] = type;
json.addAll({
'success': success,
});
return json;
}
- String toString() => '[ReloadReport type: ${type}, success: ${success}]';
+ String toString() => '[ReloadReport success: ${success}]';
}
/// See [RetainingPath].
class RetainingObject {
- static RetainingObject parse(Map<String, dynamic> json) =>
+ static RetainingObject? parse(Map<String, dynamic>? json) =>
json == null ? null : RetainingObject._fromJson(json);
/// An object that is part of a retaining path.
- ObjRef value;
+ late final ObjRef value;
/// The offset of the retaining object in a containing list.
@optional
- int parentListIndex;
+ late final int? parentListIndex;
/// The key mapping to the retaining object in a containing map.
@optional
- ObjRef parentMapKey;
+ late final ObjRef? parentMapKey;
/// The name of the field containing the retaining object within an object.
@optional
- String parentField;
+ late final String? parentField;
RetainingObject({
- @required this.value,
+ required this.value,
this.parentListIndex,
this.parentMapKey,
this.parentField,
});
RetainingObject._fromJson(Map<String, dynamic> json) {
- value = createServiceObject(json['value'], const ['ObjRef']);
+ value = createServiceObject(json['value']!, const ['ObjRef']) as ObjRef;
parentListIndex = json['parentListIndex'];
- parentMapKey = createServiceObject(json['parentMapKey'], const ['ObjRef']);
+ parentMapKey =
+ createServiceObject(json['parentMapKey'], const ['ObjRef']) as ObjRef?;
parentField = json['parentField'];
}
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
+ final json = <String, dynamic>{};
json.addAll({
'value': value.toJson(),
});
@@ -6152,37 +6362,42 @@
/// See [getRetainingPath].
class RetainingPath extends Response {
- static RetainingPath parse(Map<String, dynamic> json) =>
+ static RetainingPath? parse(Map<String, dynamic>? json) =>
json == null ? null : RetainingPath._fromJson(json);
/// The length of the retaining path.
- int length;
+ late final int length;
/// The type of GC root which is holding a reference to the specified object.
/// Possible values include: * class table * local handle * persistent
/// handle * stack * user global * weak persistent handle * unknown
- String gcRootType;
+ late final String gcRootType;
/// The chain of objects which make up the retaining path.
- List<RetainingObject> elements;
+ late final List<RetainingObject> elements;
RetainingPath({
- @required this.length,
- @required this.gcRootType,
- @required this.elements,
+ required this.length,
+ required this.gcRootType,
+ required this.elements,
});
RetainingPath._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
- length = json['length'];
- gcRootType = json['gcRootType'];
+ length = json['length'] ?? -1;
+ gcRootType = json['gcRootType'] ?? '';
elements = List<RetainingObject>.from(
- createServiceObject(json['elements'], const ['RetainingObject']) ?? []);
+ createServiceObject(json['elements'], const ['RetainingObject'])
+ as List? ??
+ []);
}
@override
+ String get type => 'RetainingPath';
+
+ @override
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
- json['type'] = 'RetainingPath';
+ final json = <String, dynamic>{};
+ json['type'] = type;
json.addAll({
'length': length,
'gcRootType': gcRootType,
@@ -6192,38 +6407,34 @@
}
String toString() => '[RetainingPath ' //
- 'type: ${type}, length: ${length}, gcRootType: ${gcRootType}, ' //
- 'elements: ${elements}]';
+ 'length: ${length}, gcRootType: ${gcRootType}, elements: ${elements}]';
}
/// Every non-error response returned by the Service Protocol extends
/// `Response`. By using the `type` property, the client can determine which
/// [type] of response has been provided.
class Response {
- static Response parse(Map<String, dynamic> json) =>
+ static Response? parse(Map<String, dynamic>? json) =>
json == null ? null : Response._fromJson(json);
- Map<String, dynamic> json;
+ Map<String, dynamic>? json;
- /// Every response returned by the VM Service has the type property. This
- /// allows the client distinguish between different kinds of responses.
- String type;
+ Response();
- Response({
- @required this.type,
- });
+ Response._fromJson(this.json);
- Response._fromJson(this.json) {
- type = json['type'];
- }
+ String get type => 'Response';
Map<String, dynamic> toJson() {
- var result = json == null ? <String, dynamic>{} : Map.of(json);
- result['type'] = type ?? 'Response';
+ final localJson = json;
+ final result = localJson == null
+ ? <String, dynamic>{}
+ : Map<String, dynamic>.of(localJson);
+ result['type'] = type;
return result;
}
- String toString() => '[Response type: ${type}]';
+ String toString() => '[Response]';
}
/// A `Sentinel` is used to indicate that the normal response is not available.
@@ -6231,29 +6442,32 @@
/// We use a `Sentinel` instead of an [error] for these cases because they do
/// not represent a problematic condition. They are normal.
class Sentinel extends Response {
- static Sentinel parse(Map<String, dynamic> json) =>
+ static Sentinel? parse(Map<String, dynamic>? json) =>
json == null ? null : Sentinel._fromJson(json);
/// What kind of sentinel is this?
- /*SentinelKind*/ String kind;
+ late final /*SentinelKind*/ String kind;
/// A reasonable string representation of this sentinel.
- String valueAsString;
+ late final String valueAsString;
Sentinel({
- @required this.kind,
- @required this.valueAsString,
+ required this.kind,
+ required this.valueAsString,
});
Sentinel._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
- kind = json['kind'];
- valueAsString = json['valueAsString'];
+ kind = json['kind'] ?? '';
+ valueAsString = json['valueAsString'] ?? '';
}
@override
+ String get type => 'Sentinel';
+
+ @override
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
- json['type'] = 'Sentinel';
+ final json = <String, dynamic>{};
+ json['type'] = type;
json.addAll({
'kind': kind,
'valueAsString': valueAsString,
@@ -6261,31 +6475,36 @@
return json;
}
- String toString() => '[Sentinel ' //
- 'type: ${type}, kind: ${kind}, valueAsString: ${valueAsString}]';
+ String toString() =>
+ '[Sentinel kind: ${kind}, valueAsString: ${valueAsString}]';
}
/// `ScriptRef` is a reference to a `Script`.
class ScriptRef extends ObjRef {
- static ScriptRef parse(Map<String, dynamic> json) =>
+ static ScriptRef? parse(Map<String, dynamic>? json) =>
json == null ? null : ScriptRef._fromJson(json);
/// The uri from which this script was loaded.
- String uri;
+ late final String uri;
ScriptRef({
- @required this.uri,
- @required String id,
- }) : super(id: id);
+ required this.uri,
+ required String id,
+ }) : super(
+ id: id,
+ );
ScriptRef._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
- uri = json['uri'];
+ uri = json['uri'] ?? '';
}
@override
+ String get type => 'ScriptRef';
+
+ @override
Map<String, dynamic> toJson() {
- var json = super.toJson();
- json['type'] = '@Script';
+ final json = super.toJson();
+ json['type'] = type;
json.addAll({
'uri': uri,
});
@@ -6296,7 +6515,7 @@
operator ==(other) => other is ScriptRef && id == other.id;
- String toString() => '[ScriptRef type: ${type}, id: ${id}, uri: ${uri}]';
+ String toString() => '[ScriptRef id: ${id}, uri: ${uri}]';
}
/// A `Script` provides information about a Dart language script.
@@ -6330,71 +6549,75 @@
/// 101 | 1 | 8
/// 102 | 2 | 7
class Script extends Obj implements ScriptRef {
- static Script parse(Map<String, dynamic> json) =>
+ static Script? parse(Map<String, dynamic>? json) =>
json == null ? null : Script._fromJson(json);
final _tokenToLine = <int, int>{};
final _tokenToColumn = <int, int>{};
/// The uri from which this script was loaded.
- String uri;
+ late final String uri;
/// The library which owns this script.
- LibraryRef library;
+ late final LibraryRef library;
@optional
- int lineOffset;
+ late final int? lineOffset;
@optional
- int columnOffset;
+ late final int? columnOffset;
/// The source code for this script. This can be null for certain built-in
/// scripts.
@optional
- String source;
+ late final String? source;
/// A table encoding a mapping from token position to line and column. This
/// field is null if sources aren't available.
@optional
- List<List<int>> tokenPosTable;
+ late final List<List<int>>? tokenPosTable;
Script({
- @required this.uri,
- @required this.library,
- @required String id,
+ required this.uri,
+ required this.library,
+ required String id,
this.lineOffset,
this.columnOffset,
this.source,
this.tokenPosTable,
- }) : super(id: id);
+ }) : super(
+ id: id,
+ );
Script._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
- uri = json['uri'];
- library = createServiceObject(json['library'], const ['LibraryRef']);
+ uri = json['uri'] ?? '';
+ library = createServiceObject(json['library']!, const ['LibraryRef'])
+ as LibraryRef;
lineOffset = json['lineOffset'];
columnOffset = json['columnOffset'];
source = json['source'];
tokenPosTable = json['tokenPosTable'] == null
? null
: List<List<int>>.from(
- json['tokenPosTable'].map((dynamic list) => List<int>.from(list)));
+ json['tokenPosTable']!.map((dynamic list) => List<int>.from(list)));
_parseTokenPosTable();
}
/// This function maps a token position to a line number.
/// The VM considers the first line to be line 1.
- int getLineNumberFromTokenPos(int tokenPos) => _tokenToLine[tokenPos];
+ int? getLineNumberFromTokenPos(int tokenPos) => _tokenToLine[tokenPos];
/// This function maps a token position to a column number.
/// The VM considers the first column to be column 1.
- int getColumnNumberFromTokenPos(int tokenPos) => _tokenToColumn[tokenPos];
+ int? getColumnNumberFromTokenPos(int tokenPos) => _tokenToColumn[tokenPos];
void _parseTokenPosTable() {
- if (tokenPosTable == null) {
+ final tokenPositionTable = tokenPosTable;
+ if (tokenPositionTable == null) {
return;
}
- final lineSet = Set<int>();
- for (List line in tokenPosTable) {
+ final lineSet = <int>{};
+ for (List line in tokenPositionTable) {
// Each entry begins with a line number...
int lineNumber = line[0];
lineSet.add(lineNumber);
@@ -6409,9 +6632,12 @@
}
@override
+ String get type => 'Script';
+
+ @override
Map<String, dynamic> toJson() {
- var json = super.toJson();
- json['type'] = 'Script';
+ final json = super.toJson();
+ json['type'] = type;
json.addAll({
'uri': uri,
'library': library.toJson(),
@@ -6419,8 +6645,8 @@
_setIfNotNull(json, 'lineOffset', lineOffset);
_setIfNotNull(json, 'columnOffset', columnOffset);
_setIfNotNull(json, 'source', source);
- _setIfNotNull(json, 'tokenPosTable',
- tokenPosTable?.map((f) => f?.toList())?.toList());
+ _setIfNotNull(
+ json, 'tokenPosTable', tokenPosTable?.map((f) => f.toList()).toList());
return json;
}
@@ -6428,70 +6654,77 @@
operator ==(other) => other is Script && id == other.id;
- String toString() =>
- '[Script type: ${type}, id: ${id}, uri: ${uri}, library: ${library}]';
+ String toString() => '[Script id: ${id}, uri: ${uri}, library: ${library}]';
}
class ScriptList extends Response {
- static ScriptList parse(Map<String, dynamic> json) =>
+ static ScriptList? parse(Map<String, dynamic>? json) =>
json == null ? null : ScriptList._fromJson(json);
- List<ScriptRef> scripts;
+ late final List<ScriptRef> scripts;
ScriptList({
- @required this.scripts,
+ required this.scripts,
});
ScriptList._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
scripts = List<ScriptRef>.from(
- createServiceObject(json['scripts'], const ['ScriptRef']) ?? []);
+ createServiceObject(json['scripts'], const ['ScriptRef']) as List? ??
+ []);
}
@override
+ String get type => 'ScriptList';
+
+ @override
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
- json['type'] = 'ScriptList';
+ final json = <String, dynamic>{};
+ json['type'] = type;
json.addAll({
'scripts': scripts.map((f) => f.toJson()).toList(),
});
return json;
}
- String toString() => '[ScriptList type: ${type}, scripts: ${scripts}]';
+ String toString() => '[ScriptList scripts: ${scripts}]';
}
/// The `SourceLocation` class is used to designate a position or range in some
/// script.
class SourceLocation extends Response {
- static SourceLocation parse(Map<String, dynamic> json) =>
+ static SourceLocation? parse(Map<String, dynamic>? json) =>
json == null ? null : SourceLocation._fromJson(json);
/// The script containing the source location.
- ScriptRef script;
+ late final ScriptRef script;
/// The first token of the location.
- int tokenPos;
+ late final int tokenPos;
/// The last token of the location if this is a range.
@optional
- int endTokenPos;
+ late final int? endTokenPos;
SourceLocation({
- @required this.script,
- @required this.tokenPos,
+ required this.script,
+ required this.tokenPos,
this.endTokenPos,
});
SourceLocation._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
- script = createServiceObject(json['script'], const ['ScriptRef']);
- tokenPos = json['tokenPos'];
+ script =
+ createServiceObject(json['script']!, const ['ScriptRef']) as ScriptRef;
+ tokenPos = json['tokenPos'] ?? -1;
endTokenPos = json['endTokenPos'];
}
@override
+ String get type => 'SourceLocation';
+
+ @override
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
- json['type'] = 'SourceLocation';
+ final json = <String, dynamic>{};
+ json['type'] = type;
json.addAll({
'script': script.toJson(),
'tokenPos': tokenPos,
@@ -6501,13 +6734,13 @@
}
String toString() =>
- '[SourceLocation type: ${type}, script: ${script}, tokenPos: ${tokenPos}]';
+ '[SourceLocation script: ${script}, tokenPos: ${tokenPos}]';
}
/// The `SourceReport` class represents a set of reports tied to source
/// locations in an isolate.
class SourceReport extends Response {
- static SourceReport parse(Map<String, dynamic> json) =>
+ static SourceReport? parse(Map<String, dynamic>? json) =>
json == null ? null : SourceReport._fromJson(json);
/// A list of ranges in the program source. These ranges correspond to ranges
@@ -6518,27 +6751,31 @@
/// functions.
///
/// Note that ranges may be duplicated, in the case of mixins.
- List<SourceReportRange> ranges;
+ late final List<SourceReportRange> ranges;
/// A list of scripts, referenced by index in the report's ranges.
- List<ScriptRef> scripts;
+ late final List<ScriptRef> scripts;
SourceReport({
- @required this.ranges,
- @required this.scripts,
+ required this.ranges,
+ required this.scripts,
});
SourceReport._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
ranges = List<SourceReportRange>.from(
- _createSpecificObject(json['ranges'], SourceReportRange.parse));
+ _createSpecificObject(json['ranges']!, SourceReportRange.parse));
scripts = List<ScriptRef>.from(
- createServiceObject(json['scripts'], const ['ScriptRef']) ?? []);
+ createServiceObject(json['scripts'], const ['ScriptRef']) as List? ??
+ []);
}
@override
+ String get type => 'SourceReport';
+
+ @override
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
- json['type'] = 'SourceReport';
+ final json = <String, dynamic>{};
+ json['type'] = type;
json.addAll({
'ranges': ranges.map((f) => f.toJson()).toList(),
'scripts': scripts.map((f) => f.toJson()).toList(),
@@ -6546,8 +6783,7 @@
return json;
}
- String toString() =>
- '[SourceReport type: ${type}, ranges: ${ranges}, scripts: ${scripts}]';
+ String toString() => '[SourceReport ranges: ${ranges}, scripts: ${scripts}]';
}
/// The `SourceReportCoverage` class represents coverage information for one
@@ -6556,20 +6792,20 @@
/// Note that `SourceReportCoverage` does not extend [Response] and therefore
/// will not contain a `type` property.
class SourceReportCoverage {
- static SourceReportCoverage parse(Map<String, dynamic> json) =>
+ static SourceReportCoverage? parse(Map<String, dynamic>? json) =>
json == null ? null : SourceReportCoverage._fromJson(json);
/// A list of token positions in a SourceReportRange which have been executed.
/// The list is sorted.
- List<int> hits;
+ late final List<int> hits;
/// A list of token positions in a SourceReportRange which have not been
/// executed. The list is sorted.
- List<int> misses;
+ late final List<int> misses;
SourceReportCoverage({
- @required this.hits,
- @required this.misses,
+ required this.hits,
+ required this.misses,
});
SourceReportCoverage._fromJson(Map<String, dynamic> json) {
@@ -6578,7 +6814,7 @@
}
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
+ final json = <String, dynamic>{};
json.addAll({
'hits': hits.map((f) => f).toList(),
'misses': misses.map((f) => f).toList(),
@@ -6597,64 +6833,64 @@
/// Note that `SourceReportRange` does not extend [Response] and therefore will
/// not contain a `type` property.
class SourceReportRange {
- static SourceReportRange parse(Map<String, dynamic> json) =>
+ static SourceReportRange? parse(Map<String, dynamic>? json) =>
json == null ? null : SourceReportRange._fromJson(json);
/// An index into the script table of the SourceReport, indicating which
/// script contains this range of code.
- int scriptIndex;
+ late final int scriptIndex;
/// The token position at which this range begins.
- int startPos;
+ late final int startPos;
/// The token position at which this range ends. Inclusive.
- int endPos;
+ late final int endPos;
/// Has this range been compiled by the Dart VM?
- bool compiled;
+ late final bool compiled;
/// The error while attempting to compile this range, if this report was
/// generated with forceCompile=true.
@optional
- ErrorRef error;
+ late final ErrorRef? error;
/// Code coverage information for this range. Provided only when the Coverage
/// report has been requested and the range has been compiled.
@optional
- SourceReportCoverage coverage;
+ late final SourceReportCoverage? coverage;
/// Possible breakpoint information for this range, represented as a sorted
/// list of token positions. Provided only when the when the
/// PossibleBreakpoint report has been requested and the range has been
/// compiled.
@optional
- List<int> possibleBreakpoints;
+ late final List<int>? possibleBreakpoints;
SourceReportRange({
- @required this.scriptIndex,
- @required this.startPos,
- @required this.endPos,
- @required this.compiled,
+ required this.scriptIndex,
+ required this.startPos,
+ required this.endPos,
+ required this.compiled,
this.error,
this.coverage,
this.possibleBreakpoints,
});
SourceReportRange._fromJson(Map<String, dynamic> json) {
- scriptIndex = json['scriptIndex'];
- startPos = json['startPos'];
- endPos = json['endPos'];
- compiled = json['compiled'];
- error = createServiceObject(json['error'], const ['ErrorRef']);
+ scriptIndex = json['scriptIndex'] ?? -1;
+ startPos = json['startPos'] ?? -1;
+ endPos = json['endPos'] ?? -1;
+ compiled = json['compiled'] ?? false;
+ error = createServiceObject(json['error'], const ['ErrorRef']) as ErrorRef?;
coverage =
- _createSpecificObject(json['coverage'], SourceReportCoverage.parse);
+ _createSpecificObject(json['coverage']!, SourceReportCoverage.parse);
possibleBreakpoints = json['possibleBreakpoints'] == null
? null
: List<int>.from(json['possibleBreakpoints']);
}
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
+ final json = <String, dynamic>{};
json.addAll({
'scriptIndex': scriptIndex,
'startPos': startPos,
@@ -6664,7 +6900,7 @@
_setIfNotNull(json, 'error', error?.toJson());
_setIfNotNull(json, 'coverage', coverage?.toJson());
_setIfNotNull(json, 'possibleBreakpoints',
- possibleBreakpoints?.map((f) => f)?.toList());
+ possibleBreakpoints?.map((f) => f).toList());
return json;
}
@@ -6678,80 +6914,85 @@
///
/// See [getStack].
class Stack extends Response {
- static Stack parse(Map<String, dynamic> json) =>
+ static Stack? parse(Map<String, dynamic>? json) =>
json == null ? null : Stack._fromJson(json);
/// A list of frames that make up the synchronous stack, rooted at the message
/// loop (i.e., the frames since the last asynchronous gap or the isolate's
/// entrypoint).
- List<Frame> frames;
+ late final List<Frame> frames;
/// A list of frames representing the asynchronous path. Comparable to
/// `awaiterFrames`, if provided, although some frames may be different.
@optional
- List<Frame> asyncCausalFrames;
+ late final List<Frame>? asyncCausalFrames;
/// A list of frames representing the asynchronous path. Comparable to
/// `asyncCausalFrames`, if provided, although some frames may be different.
@optional
- List<Frame> awaiterFrames;
+ late final List<Frame>? awaiterFrames;
/// A list of messages in the isolate's message queue.
- List<Message> messages;
+ late final List<Message> messages;
/// Specifies whether or not this stack is complete or has been artificially
/// truncated.
- bool truncated;
+ late final bool truncated;
Stack({
- @required this.frames,
- @required this.messages,
- @required this.truncated,
+ required this.frames,
+ required this.messages,
+ required this.truncated,
this.asyncCausalFrames,
this.awaiterFrames,
});
Stack._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
frames = List<Frame>.from(
- createServiceObject(json['frames'], const ['Frame']) ?? []);
+ createServiceObject(json['frames'], const ['Frame']) as List? ?? []);
asyncCausalFrames = json['asyncCausalFrames'] == null
? null
: List<Frame>.from(
- createServiceObject(json['asyncCausalFrames'], const ['Frame']));
+ createServiceObject(json['asyncCausalFrames'], const ['Frame'])!
+ as List);
awaiterFrames = json['awaiterFrames'] == null
? null
: List<Frame>.from(
- createServiceObject(json['awaiterFrames'], const ['Frame']));
+ createServiceObject(json['awaiterFrames'], const ['Frame'])!
+ as List);
messages = List<Message>.from(
- createServiceObject(json['messages'], const ['Message']) ?? []);
- truncated = json['truncated'];
+ createServiceObject(json['messages'], const ['Message']) as List? ??
+ []);
+ truncated = json['truncated'] ?? false;
}
@override
+ String get type => 'Stack';
+
+ @override
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
- json['type'] = 'Stack';
+ final json = <String, dynamic>{};
+ json['type'] = type;
json.addAll({
'frames': frames.map((f) => f.toJson()).toList(),
'messages': messages.map((f) => f.toJson()).toList(),
'truncated': truncated,
});
_setIfNotNull(json, 'asyncCausalFrames',
- asyncCausalFrames?.map((f) => f?.toJson())?.toList());
- _setIfNotNull(json, 'awaiterFrames',
- awaiterFrames?.map((f) => f?.toJson())?.toList());
+ asyncCausalFrames?.map((f) => f.toJson()).toList());
+ _setIfNotNull(
+ json, 'awaiterFrames', awaiterFrames?.map((f) => f.toJson()).toList());
return json;
}
String toString() => '[Stack ' //
- 'type: ${type}, frames: ${frames}, messages: ${messages}, ' //
- 'truncated: ${truncated}]';
+ 'frames: ${frames}, messages: ${messages}, truncated: ${truncated}]';
}
/// The `Success` type is used to indicate that an operation completed
/// successfully.
class Success extends Response {
- static Success parse(Map<String, dynamic> json) =>
+ static Success? parse(Map<String, dynamic>? json) =>
json == null ? null : Success._fromJson(json);
Success();
@@ -6759,48 +7000,55 @@
Success._fromJson(Map<String, dynamic> json) : super._fromJson(json);
@override
+ String get type => 'Success';
+
+ @override
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
- json['type'] = 'Success';
+ final json = <String, dynamic>{};
+ json['type'] = type;
return json;
}
- String toString() => '[Success type: ${type}]';
+ String toString() => '[Success]';
}
class Timeline extends Response {
- static Timeline parse(Map<String, dynamic> json) =>
+ static Timeline? parse(Map<String, dynamic>? json) =>
json == null ? null : Timeline._fromJson(json);
/// A list of timeline events. No order is guarenteed for these events; in
/// particular, these events may be unordered with respect to their
/// timestamps.
- List<TimelineEvent> traceEvents;
+ late final List<TimelineEvent> traceEvents;
/// The start of the period of time in which traceEvents were collected.
- int timeOriginMicros;
+ late final int timeOriginMicros;
/// The duration of time covered by the timeline.
- int timeExtentMicros;
+ late final int timeExtentMicros;
Timeline({
- @required this.traceEvents,
- @required this.timeOriginMicros,
- @required this.timeExtentMicros,
+ required this.traceEvents,
+ required this.timeOriginMicros,
+ required this.timeExtentMicros,
});
Timeline._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
traceEvents = List<TimelineEvent>.from(
- createServiceObject(json['traceEvents'], const ['TimelineEvent']) ??
+ createServiceObject(json['traceEvents'], const ['TimelineEvent'])
+ as List? ??
[]);
- timeOriginMicros = json['timeOriginMicros'];
- timeExtentMicros = json['timeExtentMicros'];
+ timeOriginMicros = json['timeOriginMicros'] ?? -1;
+ timeExtentMicros = json['timeExtentMicros'] ?? -1;
}
@override
+ String get type => 'Timeline';
+
+ @override
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
- json['type'] = 'Timeline';
+ final json = <String, dynamic>{};
+ json['type'] = type;
json.addAll({
'traceEvents': traceEvents.map((f) => f.toJson()).toList(),
'timeOriginMicros': timeOriginMicros,
@@ -6810,62 +7058,68 @@
}
String toString() => '[Timeline ' //
- 'type: ${type}, traceEvents: ${traceEvents}, timeOriginMicros: ${timeOriginMicros}, ' //
+ 'traceEvents: ${traceEvents}, timeOriginMicros: ${timeOriginMicros}, ' //
'timeExtentMicros: ${timeExtentMicros}]';
}
/// An `TimelineEvent` is an arbitrary map that contains a [Trace Event Format]
/// event.
class TimelineEvent {
- static TimelineEvent parse(Map<String, dynamic> json) =>
+ static TimelineEvent? parse(Map<String, dynamic>? json) =>
json == null ? null : TimelineEvent._fromJson(json);
- Map<String, dynamic> json;
+ Map<String, dynamic>? json;
TimelineEvent();
TimelineEvent._fromJson(this.json);
Map<String, dynamic> toJson() {
- var result = json == null ? <String, dynamic>{} : Map.of(json);
+ final localJson = json;
+ final result = localJson == null
+ ? <String, dynamic>{}
+ : Map<String, dynamic>.of(localJson);
result['type'] = 'TimelineEvent';
return result;
}
- String toString() => '[TimelineEvent ]';
+ String toString() => '[TimelineEvent]';
}
class TimelineFlags extends Response {
- static TimelineFlags parse(Map<String, dynamic> json) =>
+ static TimelineFlags? parse(Map<String, dynamic>? json) =>
json == null ? null : TimelineFlags._fromJson(json);
/// The name of the recorder currently in use. Recorder types include, but are
/// not limited to: Callback, Endless, Fuchsia, Macos, Ring, Startup, and
/// Systrace. Set to "null" if no recorder is currently set.
- String recorderName;
+ late final String recorderName;
/// The list of all available timeline streams.
- List<String> availableStreams;
+ late final List<String> availableStreams;
/// The list of timeline streams that are currently enabled.
- List<String> recordedStreams;
+ late final List<String> recordedStreams;
TimelineFlags({
- @required this.recorderName,
- @required this.availableStreams,
- @required this.recordedStreams,
+ required this.recorderName,
+ required this.availableStreams,
+ required this.recordedStreams,
});
TimelineFlags._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
- recorderName = json['recorderName'];
+ recorderName = json['recorderName'] ?? '';
availableStreams = List<String>.from(json['availableStreams']);
recordedStreams = List<String>.from(json['recordedStreams']);
}
@override
+ String get type => 'TimelineFlags';
+
+ @override
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
- json['type'] = 'TimelineFlags';
+ final json = <String, dynamic>{};
+ json['type'] = type;
json.addAll({
'recorderName': recorderName,
'availableStreams': availableStreams.map((f) => f).toList(),
@@ -6875,60 +7129,68 @@
}
String toString() => '[TimelineFlags ' //
- 'type: ${type}, recorderName: ${recorderName}, availableStreams: ${availableStreams}, ' //
+ 'recorderName: ${recorderName}, availableStreams: ${availableStreams}, ' //
'recordedStreams: ${recordedStreams}]';
}
class Timestamp extends Response {
- static Timestamp parse(Map<String, dynamic> json) =>
+ static Timestamp? parse(Map<String, dynamic>? json) =>
json == null ? null : Timestamp._fromJson(json);
/// A timestamp in microseconds since epoch.
- int timestamp;
+ late final int timestamp;
Timestamp({
- @required this.timestamp,
+ required this.timestamp,
});
Timestamp._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
- timestamp = json['timestamp'];
+ timestamp = json['timestamp'] ?? -1;
}
@override
+ String get type => 'Timestamp';
+
+ @override
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
- json['type'] = 'Timestamp';
+ final json = <String, dynamic>{};
+ json['type'] = type;
json.addAll({
'timestamp': timestamp,
});
return json;
}
- String toString() => '[Timestamp type: ${type}, timestamp: ${timestamp}]';
+ String toString() => '[Timestamp timestamp: ${timestamp}]';
}
/// `TypeArgumentsRef` is a reference to a `TypeArguments` object.
class TypeArgumentsRef extends ObjRef {
- static TypeArgumentsRef parse(Map<String, dynamic> json) =>
+ static TypeArgumentsRef? parse(Map<String, dynamic>? json) =>
json == null ? null : TypeArgumentsRef._fromJson(json);
/// A name for this type argument list.
- String name;
+ late final String name;
TypeArgumentsRef({
- @required this.name,
- @required String id,
- }) : super(id: id);
+ required this.name,
+ required String id,
+ }) : super(
+ id: id,
+ );
TypeArgumentsRef._fromJson(Map<String, dynamic> json)
: super._fromJson(json) {
- name = json['name'];
+ name = json['name'] ?? '';
}
@override
+ String get type => 'TypeArgumentsRef';
+
+ @override
Map<String, dynamic> toJson() {
- var json = super.toJson();
- json['type'] = '@TypeArguments';
+ final json = super.toJson();
+ json['type'] = type;
json.addAll({
'name': name,
});
@@ -6939,41 +7201,46 @@
operator ==(other) => other is TypeArgumentsRef && id == other.id;
- String toString() =>
- '[TypeArgumentsRef type: ${type}, id: ${id}, name: ${name}]';
+ String toString() => '[TypeArgumentsRef id: ${id}, name: ${name}]';
}
/// A `TypeArguments` object represents the type argument vector for some
/// instantiated generic type.
class TypeArguments extends Obj implements TypeArgumentsRef {
- static TypeArguments parse(Map<String, dynamic> json) =>
+ static TypeArguments? parse(Map<String, dynamic>? json) =>
json == null ? null : TypeArguments._fromJson(json);
/// A name for this type argument list.
- String name;
+ late final String name;
/// A list of types.
///
/// The value will always be one of the kinds: Type, TypeRef, TypeParameter,
/// BoundedType.
- List<InstanceRef> types;
+ late final List<InstanceRef> types;
TypeArguments({
- @required this.name,
- @required this.types,
- @required String id,
- }) : super(id: id);
+ required this.name,
+ required this.types,
+ required String id,
+ }) : super(
+ id: id,
+ );
TypeArguments._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
- name = json['name'];
+ name = json['name'] ?? '';
types = List<InstanceRef>.from(
- createServiceObject(json['types'], const ['InstanceRef']) ?? []);
+ createServiceObject(json['types'], const ['InstanceRef']) as List? ??
+ []);
}
@override
+ String get type => 'TypeArguments';
+
+ @override
Map<String, dynamic> toJson() {
- var json = super.toJson();
- json['type'] = 'TypeArguments';
+ final json = super.toJson();
+ json['type'] = type;
json.addAll({
'name': name,
'types': types.map((f) => f.toJson()).toList(),
@@ -6986,7 +7253,7 @@
operator ==(other) => other is TypeArguments && id == other.id;
String toString() =>
- '[TypeArguments type: ${type}, id: ${id}, name: ${name}, types: ${types}]';
+ '[TypeArguments id: ${id}, name: ${name}, types: ${types}]';
}
/// The `UnresolvedSourceLocation` class is used to refer to an unresolved
@@ -7000,32 +7267,32 @@
/// The `column` field will only be present when the breakpoint was specified
/// with a specific column number.
class UnresolvedSourceLocation extends Response {
- static UnresolvedSourceLocation parse(Map<String, dynamic> json) =>
+ static UnresolvedSourceLocation? parse(Map<String, dynamic>? json) =>
json == null ? null : UnresolvedSourceLocation._fromJson(json);
/// The script containing the source location if the script has been loaded.
@optional
- ScriptRef script;
+ late final ScriptRef? script;
/// The uri of the script containing the source location if the script has yet
/// to be loaded.
@optional
- String scriptUri;
+ late final String? scriptUri;
/// An approximate token position for the source location. This may change
/// when the location is resolved.
@optional
- int tokenPos;
+ late final int? tokenPos;
/// An approximate line number for the source location. This may change when
/// the location is resolved.
@optional
- int line;
+ late final int? line;
/// An approximate column number for the source location. This may change when
/// the location is resolved.
@optional
- int column;
+ late final int? column;
UnresolvedSourceLocation({
this.script,
@@ -7037,7 +7304,8 @@
UnresolvedSourceLocation._fromJson(Map<String, dynamic> json)
: super._fromJson(json) {
- script = createServiceObject(json['script'], const ['ScriptRef']);
+ script =
+ createServiceObject(json['script'], const ['ScriptRef']) as ScriptRef?;
scriptUri = json['scriptUri'];
tokenPos = json['tokenPos'];
line = json['line'];
@@ -7045,9 +7313,12 @@
}
@override
+ String get type => 'UnresolvedSourceLocation';
+
+ @override
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
- json['type'] = 'UnresolvedSourceLocation';
+ final json = <String, dynamic>{};
+ json['type'] = type;
_setIfNotNull(json, 'script', script?.toJson());
_setIfNotNull(json, 'scriptUri', scriptUri);
_setIfNotNull(json, 'tokenPos', tokenPos);
@@ -7056,36 +7327,39 @@
return json;
}
- String toString() => '[UnresolvedSourceLocation type: ${type}]';
+ String toString() => '[UnresolvedSourceLocation]';
}
/// See [Versioning].
class Version extends Response {
- static Version parse(Map<String, dynamic> json) =>
+ static Version? parse(Map<String, dynamic>? json) =>
json == null ? null : Version._fromJson(json);
/// The major version number is incremented when the protocol is changed in a
/// potentially incompatible way.
- int major;
+ late final int major;
/// The minor version number is incremented when the protocol is changed in a
/// backwards compatible way.
- int minor;
+ late final int minor;
Version({
- @required this.major,
- @required this.minor,
+ required this.major,
+ required this.minor,
});
Version._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
- major = json['major'];
- minor = json['minor'];
+ major = json['major'] ?? -1;
+ minor = json['minor'] ?? -1;
}
@override
+ String get type => 'Version';
+
+ @override
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
- json['type'] = 'Version';
+ final json = <String, dynamic>{};
+ json['type'] = type;
json.addAll({
'major': major,
'minor': minor,
@@ -7093,122 +7367,130 @@
return json;
}
- String toString() =>
- '[Version type: ${type}, major: ${major}, minor: ${minor}]';
+ String toString() => '[Version major: ${major}, minor: ${minor}]';
}
/// `VMRef` is a reference to a `VM` object.
class VMRef extends Response {
- static VMRef parse(Map<String, dynamic> json) =>
+ static VMRef? parse(Map<String, dynamic>? json) =>
json == null ? null : VMRef._fromJson(json);
/// A name identifying this vm. Not guaranteed to be unique.
- String name;
+ late final String name;
VMRef({
- @required this.name,
+ required this.name,
});
VMRef._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
- name = json['name'];
+ name = json['name'] ?? '';
}
@override
+ String get type => 'VMRef';
+
+ @override
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
- json['type'] = '@VM';
+ final json = <String, dynamic>{};
+ json['type'] = type;
json.addAll({
'name': name,
});
return json;
}
- String toString() => '[VMRef type: ${type}, name: ${name}]';
+ String toString() => '[VMRef name: ${name}]';
}
class VM extends Response implements VMRef {
- static VM parse(Map<String, dynamic> json) =>
+ static VM? parse(Map<String, dynamic>? json) =>
json == null ? null : VM._fromJson(json);
/// A name identifying this vm. Not guaranteed to be unique.
- String name;
+ late final String name;
/// Word length on target architecture (e.g. 32, 64).
- int architectureBits;
+ late final int architectureBits;
/// The CPU we are actually running on.
- String hostCPU;
+ late final String hostCPU;
/// The operating system we are running on.
- String operatingSystem;
+ late final String operatingSystem;
/// The CPU we are generating code for.
- String targetCPU;
+ late final String targetCPU;
/// The Dart VM version string.
- String version;
+ late final String version;
/// The process id for the VM.
- int pid;
+ late final int pid;
/// The time that the VM started in milliseconds since the epoch.
///
/// Suitable to pass to DateTime.fromMillisecondsSinceEpoch.
- int startTime;
+ late final int startTime;
/// A list of isolates running in the VM.
- List<IsolateRef> isolates;
+ late final List<IsolateRef> isolates;
/// A list of isolate groups running in the VM.
- List<IsolateGroupRef> isolateGroups;
+ late final List<IsolateGroupRef> isolateGroups;
/// A list of system isolates running in the VM.
- List<IsolateRef> systemIsolates;
+ late final List<IsolateRef> systemIsolates;
/// A list of isolate groups which contain system isolates running in the VM.
- List<IsolateGroupRef> systemIsolateGroups;
+ late final List<IsolateGroupRef> systemIsolateGroups;
VM({
- @required this.name,
- @required this.architectureBits,
- @required this.hostCPU,
- @required this.operatingSystem,
- @required this.targetCPU,
- @required this.version,
- @required this.pid,
- @required this.startTime,
- @required this.isolates,
- @required this.isolateGroups,
- @required this.systemIsolates,
- @required this.systemIsolateGroups,
+ required this.name,
+ required this.architectureBits,
+ required this.hostCPU,
+ required this.operatingSystem,
+ required this.targetCPU,
+ required this.version,
+ required this.pid,
+ required this.startTime,
+ required this.isolates,
+ required this.isolateGroups,
+ required this.systemIsolates,
+ required this.systemIsolateGroups,
});
VM._fromJson(Map<String, dynamic> json) : super._fromJson(json) {
- name = json['name'];
- architectureBits = json['architectureBits'];
- hostCPU = json['hostCPU'];
- operatingSystem = json['operatingSystem'];
- targetCPU = json['targetCPU'];
- version = json['version'];
- pid = json['pid'];
- startTime = json['startTime'];
+ name = json['name'] ?? '';
+ architectureBits = json['architectureBits'] ?? -1;
+ hostCPU = json['hostCPU'] ?? '';
+ operatingSystem = json['operatingSystem'] ?? '';
+ targetCPU = json['targetCPU'] ?? '';
+ version = json['version'] ?? '';
+ pid = json['pid'] ?? -1;
+ startTime = json['startTime'] ?? -1;
isolates = List<IsolateRef>.from(
- createServiceObject(json['isolates'], const ['IsolateRef']) ?? []);
+ createServiceObject(json['isolates'], const ['IsolateRef']) as List? ??
+ []);
isolateGroups = List<IsolateGroupRef>.from(
- createServiceObject(json['isolateGroups'], const ['IsolateGroupRef']) ??
+ createServiceObject(json['isolateGroups'], const ['IsolateGroupRef'])
+ as List? ??
[]);
systemIsolates = List<IsolateRef>.from(
- createServiceObject(json['systemIsolates'], const ['IsolateRef']) ??
+ createServiceObject(json['systemIsolates'], const ['IsolateRef'])
+ as List? ??
[]);
systemIsolateGroups = List<IsolateGroupRef>.from(createServiceObject(
- json['systemIsolateGroups'], const ['IsolateGroupRef']) ??
+ json['systemIsolateGroups'], const ['IsolateGroupRef']) as List? ??
[]);
}
@override
+ String get type => 'VM';
+
+ @override
Map<String, dynamic> toJson() {
- var json = <String, dynamic>{};
- json['type'] = 'VM';
+ final json = <String, dynamic>{};
+ json['type'] = type;
json.addAll({
'name': name,
'architectureBits': architectureBits,
diff --git a/pkg/vm_service/lib/utils.dart b/pkg/vm_service/lib/utils.dart
index dd6ffbc..9f65a66 100644
--- a/pkg/vm_service/lib/utils.dart
+++ b/pkg/vm_service/lib/utils.dart
@@ -2,12 +2,10 @@
// 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:meta/meta.dart';
-
/// Map the URI to a WebSocket URI for the VM service protocol.
///
/// If the URI is already a VM Service WebSocket URI it will not be modified.
-Uri convertToWebSocketUrl({@required Uri serviceProtocolUrl}) {
+Uri convertToWebSocketUrl({required Uri serviceProtocolUrl}) {
final isSecure = serviceProtocolUrl.isScheme('wss') ||
serviceProtocolUrl.isScheme('https');
final scheme = isSecure ? 'wss' : 'ws';
diff --git a/pkg/vm_service/lib/vm_service_io.dart b/pkg/vm_service/lib/vm_service_io.dart
index 00597af..0db488b 100644
--- a/pkg/vm_service/lib/vm_service_io.dart
+++ b/pkg/vm_service/lib/vm_service_io.dart
@@ -8,7 +8,7 @@
import 'vm_service.dart';
@Deprecated('Prefer vmServiceConnectUri')
-Future<VmService> vmServiceConnect(String host, int port, {Log log}) async {
+Future<VmService> vmServiceConnect(String host, int port, {Log? log}) async {
final WebSocket socket = await WebSocket.connect('ws://$host:$port/ws');
final StreamController<dynamic> controller = StreamController();
final Completer streamClosedCompleter = Completer();
@@ -28,7 +28,7 @@
}
/// Connect to the given uri and return a new [VmService] instance.
-Future<VmService> vmServiceConnectUri(String wsUri, {Log log}) async {
+Future<VmService> vmServiceConnectUri(String wsUri, {Log? log}) async {
final WebSocket socket = await WebSocket.connect(wsUri);
final StreamController<dynamic> controller = StreamController();
final Completer streamClosedCompleter = Completer();
diff --git a/pkg/vm_service/pubspec.yaml b/pkg/vm_service/pubspec.yaml
index 7f1f7af..e4ff937 100644
--- a/pkg/vm_service/pubspec.yaml
+++ b/pkg/vm_service/pubspec.yaml
@@ -2,21 +2,21 @@
description: >-
A library to communicate with a service implementing the Dart VM
service protocol.
-version: 5.5.1
+
+version: 6.0.0-nullsafety-dev
homepage: https://github.com/dart-lang/sdk/tree/master/pkg/vm_service
environment:
- sdk: '>=2.6.0 <3.0.0'
+ sdk: '>=2.12.0-0 <3.0.0'
dependencies:
- meta: ^1.0.2
dev_dependencies:
- async: ^2.0.0
- markdown: ^2.0.0
- mockito: ^4.0.0
- path: ^1.0.0
- pedantic: ^1.7.0
- pub_semver: ^1.0.0
- test: ^1.0.0
+ async: ^2.5.0-nullsafety.3
+ markdown: ^4.0.0-nullsafety.0
+ mockito: ^5.0.0-nullsafety.1
+ path: ^1.8.0-nullsafety.3
+ pedantic: ^1.10.0-nullsafety.3
+ pub_semver: ^2.0.0-nullsafety.0
+ test: ^1.16.0-nullsafety.13
diff --git a/pkg/vm_service/test/async_generator_breakpoint_test.dart b/pkg/vm_service/test/async_generator_breakpoint_test.dart
index e709594..d6e8e65 100644
--- a/pkg/vm_service/test/async_generator_breakpoint_test.dart
+++ b/pkg/vm_service/test/async_generator_breakpoint_test.dart
@@ -47,7 +47,8 @@
Future testAsync(VmService service, IsolateRef isolateRef) async {
final isolate = await service.getIsolate(isolateRef.id);
- final Library lib = await service.getObject(isolate.id, isolate.rootLib.id);
+ final Library lib =
+ (await service.getObject(isolate.id, isolate.rootLib!.id)) as Library;
final script = lib.scripts[0];
final bp1 = await service.addBreakpoint(isolate.id, script.id, 11);
@@ -85,8 +86,8 @@
final stream = service.onDebugEvent;
await for (Event event in stream) {
if (event.kind == EventKind.kPauseBreakpoint) {
- assert(event.pauseBreakpoints.isNotEmpty);
- final bp = event.pauseBreakpoints.first;
+ assert(event.pauseBreakpoints!.isNotEmpty);
+ final bp = event.pauseBreakpoints!.first;
hits.add(bp);
await service.resume(isolate.id);
diff --git a/pkg/vm_service/test/async_scope_test.dart b/pkg/vm_service/test/async_scope_test.dart
index 9573e69..4304553 100644
--- a/pkg/vm_service/test/async_scope_test.dart
+++ b/pkg/vm_service/test/async_scope_test.dart
@@ -34,20 +34,20 @@
}
Future<void> checkAsyncVarDescriptors(
- VmService service, IsolateRef isolateRef) async {
- final stack = await service.getStack(isolateRef.id);
+ VmService? service, IsolateRef? isolateRef) async {
+ final stack = await service!.getStack(isolateRef!.id);
expect(stack.frames.length, greaterThanOrEqualTo(1));
final frame = stack.frames[0];
- final vars = frame.vars.map((v) => v.name).join(' ');
+ final vars = frame.vars!.map((v) => v.name).join(' ');
expect(vars, 'param1 local1'); // no :async_op et al
}
Future checkAsyncStarVarDescriptors(
- VmService service, IsolateRef isolateRef) async {
- final stack = await service.getStack(isolateRef.id);
+ VmService? service, IsolateRef? isolateRef) async {
+ final stack = await service!.getStack(isolateRef!.id);
expect(stack.frames.length, greaterThanOrEqualTo(1));
final frame = stack.frames[0];
- final vars = frame.vars.map((v) => v.name).join(' ');
+ final vars = frame.vars!.map((v) => v.name).join(' ');
expect(vars, 'param2 local2'); // no :async_op et al
}
diff --git a/pkg/vm_service/test/common/service_test_common.dart b/pkg/vm_service/test/common/service_test_common.dart
index 56a6304..e54d930 100644
--- a/pkg/vm_service/test/common/service_test_common.dart
+++ b/pkg/vm_service/test/common/service_test_common.dart
@@ -15,11 +15,10 @@
Future<void> smartNext(VmService service, IsolateRef isolateRef) async {
print('smartNext');
final isolate = await service.getIsolate(isolateRef.id);
- if ((isolate.pauseEvent != null) &&
- (isolate.pauseEvent.kind == EventKind.kPauseBreakpoint)) {
+ if ((isolate.pauseEvent.kind == EventKind.kPauseBreakpoint)) {
Event event = isolate.pauseEvent;
// TODO(bkonyi): remove needless refetching of isolate object.
- if (event?.atAsyncSuspension ?? false) {
+ if (event.atAsyncSuspension ?? false) {
return asyncNext(service, isolateRef);
} else {
return syncNext(service, isolateRef);
@@ -32,13 +31,12 @@
Future<void> asyncNext(VmService service, IsolateRef isolateRef) async {
print('asyncNext');
final isolate = await service.getIsolate(isolateRef.id);
- if ((isolate.pauseEvent != null) &&
- (isolate.pauseEvent.kind == EventKind.kPauseBreakpoint)) {
+ if ((isolate.pauseEvent.kind == EventKind.kPauseBreakpoint)) {
dynamic event = isolate.pauseEvent;
if (!event.atAsyncSuspension) {
throw 'No async continuation at this location';
} else {
- return service.resume(isolateRef.id, step: 'OverAsyncSuspension');
+ await service.resume(isolateRef.id, step: 'OverAsyncSuspension');
}
} else {
throw 'The program is already running';
@@ -48,9 +46,8 @@
Future<void> syncNext(VmService service, IsolateRef isolateRef) async {
print('syncNext');
final isolate = await service.getIsolate(isolateRef.id);
- if ((isolate.pauseEvent != null) &&
- (isolate.pauseEvent.kind == EventKind.kPauseBreakpoint)) {
- return service.resume(isolate.id, step: 'Over');
+ if ((isolate.pauseEvent.kind == EventKind.kPauseBreakpoint)) {
+ await service.resume(isolate.id, step: 'Over');
} else {
throw 'The program is already running';
}
@@ -58,10 +55,10 @@
Future<void> hasPausedFor(
VmService service, IsolateRef isolateRef, String kind) async {
- var completer = Completer();
- var subscription;
+ Completer<dynamic>? completer = Completer();
+ late var subscription;
subscription = service.onDebugEvent.listen((event) async {
- if ((isolateRef.id == event.isolate.id) && (event.kind == kind)) {
+ if ((isolateRef.id == event.isolate!.id) && (event.kind == kind)) {
if (completer != null) {
try {
await service.streamCancel(EventStreams.kDebug);
@@ -78,7 +75,7 @@
// Pause may have happened before we subscribed.
final isolate = await service.getIsolate(isolateRef.id);
- if ((isolate.pauseEvent != null) && (isolate.pauseEvent.kind == kind)) {
+ if ((isolate.pauseEvent.kind == kind)) {
if (completer != null) {
try {
await service.streamCancel(EventStreams.kDebug);
@@ -117,7 +114,8 @@
return (VmService service, IsolateRef isolateRef) async {
print("Setting breakpoint for line $line");
final isolate = await service.getIsolate(isolateRef.id);
- final Library lib = await service.getObject(isolate.id, isolate.rootLib.id);
+ final Library lib =
+ (await service.getObject(isolate.id, isolate.rootLib!.id)) as Library;
final script = lib.scripts.first;
Breakpoint bpt = await service.addBreakpoint(isolate.id, script.id, line);
@@ -139,9 +137,9 @@
expect(frames.length, greaterThanOrEqualTo(1));
final top = frames[0];
- final Script script =
- await service.getObject(isolate.id, top.location.script.id);
- int actualLine = script.getLineNumberFromTokenPos(top.location.tokenPos);
+ final Script script = (await service.getObject(
+ isolate.id, top.location!.script.id)) as Script;
+ int actualLine = script.getLineNumberFromTokenPos(top.location!.tokenPos)!;
if (actualLine != line) {
print("Actual: $actualLine Line: $line");
final sb = StringBuffer();
@@ -149,7 +147,7 @@
sb.write("\nFull stack trace:\n");
for (Frame f in stack.frames) {
sb.write(
- " $f [${script.getLineNumberFromTokenPos(f.location.tokenPos)}]\n");
+ " $f [${script.getLineNumberFromTokenPos(f.location!.tokenPos)}]\n");
}
throw sb.toString();
} else {
@@ -160,7 +158,7 @@
Future<void> resumeIsolate(VmService service, IsolateRef isolate) async {
Completer completer = Completer();
- var subscription;
+ late var subscription;
subscription = service.onDebugEvent.listen((event) async {
if (event.kind == EventKind.kResume) {
try {
diff --git a/pkg/vm_service/test/common/test_helper.dart b/pkg/vm_service/test/common/test_helper.dart
index 48d5941..72ae563 100644
--- a/pkg/vm_service/test/common/test_helper.dart
+++ b/pkg/vm_service/test/common/test_helper.dart
@@ -18,8 +18,8 @@
/// Will be set to the http address of the VM's service protocol before
/// any tests are invoked.
-String serviceHttpAddress;
-String serviceWebsocketAddress;
+late String serviceHttpAddress;
+late String serviceWebsocketAddress;
const String _TESTEE_ENV_KEY = 'SERVICE_TEST_TESTEE';
const Map<String, String> _TESTEE_SPAWN_ENV = {_TESTEE_ENV_KEY: 'true'};
@@ -33,7 +33,7 @@
// We'll need to parse the actual URI out...
final fileRegExp = RegExp(r'file:\/\/\/.*\.dart');
final path =
- fileRegExp.stringMatch(io.Platform.script.data.contentAsString());
+ fileRegExp.stringMatch(io.Platform.script.data!.contentAsString());
if (path == null) {
throw 'Unable to determine file path for script!';
}
@@ -45,8 +45,8 @@
class _ServiceTesteeRunner {
Future run(
- {Function() testeeBefore,
- Function() testeeConcurrent,
+ {Function()? testeeBefore,
+ Function()? testeeConcurrent,
bool pause_on_start = false,
bool pause_on_exit = false}) async {
if (!pause_on_start) {
@@ -72,8 +72,8 @@
}
void runSync(
- {void Function() testeeBeforeSync,
- void Function() testeeConcurrentSync,
+ {void Function()? testeeBeforeSync,
+ void Function()? testeeConcurrentSync,
bool pause_on_start = false,
bool pause_on_exit = false}) {
if (!pause_on_start) {
@@ -93,7 +93,7 @@
}
class _ServiceTesteeLauncher {
- io.Process process;
+ io.Process? process;
List<String> args;
bool killedByTester = false;
@@ -106,13 +106,8 @@
bool pause_on_unhandled_exceptions,
bool testeeControlsServer,
bool useAuthToken,
- List<String> extraArgs,
+ List<String>? extraArgs,
) {
- assert(pause_on_start != null);
- assert(pause_on_exit != null);
- assert(pause_on_unhandled_exceptions != null);
- assert(testeeControlsServer != null);
- assert(useAuthToken != null);
return _spawnDartProcess(
pause_on_start,
pause_on_exit,
@@ -128,7 +123,7 @@
bool pause_on_unhandled_exceptions,
bool testeeControlsServer,
bool useAuthToken,
- List<String> extraArgs) {
+ List<String>? extraArgs) {
String dartExecutable = io.Platform.executable;
var fullArgs = <String>[
@@ -160,16 +155,14 @@
return _spawnCommon(dartExecutable, fullArgs, <String, String>{});
}
- Future<io.Process> _spawnCommon(String executable, List<String> arguments,
- Map<String, String> dartEnvironment) {
+ Future<io.Process> _spawnCommon(String executable,
+ List<String> /*!*/ arguments, Map<String, String> dartEnvironment) {
var environment = _TESTEE_SPAWN_ENV;
var bashEnvironment = StringBuffer();
environment.forEach((k, v) => bashEnvironment.write("$k=$v "));
- if (dartEnvironment != null) {
- dartEnvironment.forEach((k, v) {
- arguments.insert(0, '-D$k=$v');
- });
- }
+ dartEnvironment.forEach((k, v) {
+ arguments.insert(0, '-D$k=$v');
+ });
print('** Launching $bashEnvironment$executable ${arguments.join(' ')}');
return io.Process.start(executable, arguments, environment: environment);
}
@@ -180,7 +173,7 @@
bool pause_on_unhandled_exceptions,
bool testeeControlsServer,
bool useAuthToken,
- List<String> extraArgs) {
+ List<String>? extraArgs) {
return _spawnProcess(
pause_on_start,
pause_on_exit,
@@ -191,10 +184,10 @@
.then((p) {
Completer<Uri> completer = Completer<Uri>();
process = p;
- Uri uri;
+ Uri? uri;
var blank;
var first = true;
- process.stdout
+ process!.stdout
.transform(utf8.decoder)
.transform(LineSplitter())
.listen((line) {
@@ -214,15 +207,15 @@
}
io.stdout.write('>testee>out> ${line}\n');
});
- process.stderr
+ process!.stderr
.transform(utf8.decoder)
.transform(LineSplitter())
.listen((line) {
io.stdout.write('>testee>err> ${line}\n');
});
- process.exitCode.then((exitCode) {
+ process!.exitCode.then((exitCode) {
if ((io.exitCode != 0) && !killedByTester) {
- throw "Testee io.exited with $exitCode";
+ throw "Testee exited with $exitCode";
}
print("** Process exited");
});
@@ -233,14 +226,14 @@
void requestExit() {
if (process != null) {
print('** Killing script');
- if (process.kill()) {
+ if (process!.kill()) {
killedByTester = true;
}
}
}
}
-void setupAddresses(Uri serverAddress) {
+void setupAddresses(Uri /*!*/ serverAddress) {
serviceWebsocketAddress =
'ws://${serverAddress.authority}${serverAddress.path}ws';
serviceHttpAddress = 'http://${serverAddress.authority}${serverAddress.path}';
@@ -248,10 +241,10 @@
class _ServiceTesterRunner {
Future run(
- {List<String> mainArgs,
- List<String> extraArgs,
- List<VMTest> vmTests,
- List<IsolateTest> isolateTests,
+ {List<String>? mainArgs,
+ List<String>? extraArgs,
+ List<VMTest>? vmTests,
+ List<IsolateTest>? isolateTests,
bool pause_on_start = false,
bool pause_on_exit = false,
bool verbose_vm = false,
@@ -259,15 +252,15 @@
bool testeeControlsServer = false,
bool useAuthToken = false}) async {
var process = _ServiceTesteeLauncher();
- VmService vm;
- IsolateRef isolate;
+ late VmService vm;
+ late IsolateRef isolate;
setUp(() async {
await process
.launch(pause_on_start, pause_on_exit, pause_on_unhandled_exceptions,
testeeControlsServer, useAuthToken, extraArgs)
.then((Uri serverAddress) async {
- if (mainArgs.contains("--gdb")) {
- var pid = process.process.pid;
+ if (mainArgs!.contains("--gdb")) {
+ var pid = process.process!.pid;
var wait = Duration(seconds: 10);
print("Testee has pid $pid, waiting $wait before continuing");
io.sleep(wait);
@@ -322,8 +315,8 @@
if (vm.isolates.isNotEmpty) {
return vm.isolates.first;
}
- var completer = Completer();
- StreamSubscription subscription;
+ Completer<dynamic>? completer = Completer();
+ late StreamSubscription subscription;
subscription = service.onIsolateEvent.listen((Event event) async {
if (completer == null) {
await subscription.cancel();
@@ -333,7 +326,7 @@
vm = await service.getVM();
assert(vm.isolates.isNotEmpty);
await subscription.cancel();
- completer.complete(vm.isolates.first);
+ completer!.complete(vm.isolates.first);
completer = null;
}
});
@@ -342,10 +335,10 @@
vm = await service.getVM();
if (vm.isolates.isNotEmpty) {
await subscription.cancel();
- completer.complete(vm.isolates.first);
+ completer!.complete(vm.isolates.first);
completer = null;
}
- return await completer.future;
+ return await (completer!.future as FutureOr<IsolateRef>);
}
}
@@ -356,15 +349,15 @@
Future<void> runIsolateTests(
List<String> mainArgs,
List<IsolateTest> tests, {
- testeeBefore(),
- testeeConcurrent(),
+ testeeBefore()?,
+ testeeConcurrent()?,
bool pause_on_start = false,
bool pause_on_exit = false,
bool verbose_vm = false,
bool pause_on_unhandled_exceptions = false,
bool testeeControlsServer = false,
bool useAuthToken = false,
- List<String> extraArgs,
+ List<String>? extraArgs,
}) async {
assert(!pause_on_start || testeeBefore == null);
if (_isTestee()) {
@@ -399,13 +392,13 @@
void runIsolateTestsSynchronous(
List<String> mainArgs,
List<IsolateTest> tests, {
- void testeeBefore(),
- void testeeConcurrent(),
+ void testeeBefore()?,
+ void testeeConcurrent()?,
bool pause_on_start = false,
bool pause_on_exit = false,
bool verbose_vm = false,
bool pause_on_unhandled_exceptions = false,
- List<String> extraArgs,
+ List<String>? extraArgs,
}) {
assert(!pause_on_start || testeeBefore == null);
if (_isTestee()) {
@@ -433,13 +426,13 @@
Future<void> runVMTests(
List<String> mainArgs,
List<VMTest> tests, {
- testeeBefore(),
- testeeConcurrent(),
+ testeeBefore()?,
+ testeeConcurrent()?,
bool pause_on_start = false,
bool pause_on_exit = false,
bool verbose_vm = false,
bool pause_on_unhandled_exceptions = false,
- List<String> extraArgs,
+ List<String>? extraArgs,
}) async {
if (_isTestee()) {
await _ServiceTesteeRunner().run(
diff --git a/pkg/vm_service/test/coverage_leaf_function_test.dart b/pkg/vm_service/test/coverage_leaf_function_test.dart
index eac959f..42cd1a0 100644
--- a/pkg/vm_service/test/coverage_leaf_function_test.dart
+++ b/pkg/vm_service/test/coverage_leaf_function_test.dart
@@ -35,10 +35,10 @@
// Make sure we are in the right place.
expect(stack.frames.length, greaterThanOrEqualTo(1));
- expect(stack.frames[0].function.name, 'testFunction');
+ expect(stack.frames[0].function!.name, 'testFunction');
final Library root =
- await service.getObject(isolate.id, isolate.rootLib.id);
+ await service.getObject(isolate.id, isolate.rootLib!.id) as Library;
FuncRef funcRef =
root.functions.singleWhere((f) => f.name == 'leafFunction');
Func func = await service.getObject(isolate.id, funcRef.id) as Func;
@@ -53,12 +53,13 @@
'misses': [397]
}
};
+ final location = func.location!;
final report = await service.getSourceReport(
isolate.id, [SourceReportKind.kCoverage],
- scriptId: func.location.script.id,
- tokenPos: func.location.tokenPos,
- endTokenPos: func.location.endTokenPos,
+ scriptId: location.script.id,
+ tokenPos: location.tokenPos,
+ endTokenPos: location.endTokenPos,
forceCompile: true);
expect(report.ranges.length, 1);
expect(report.ranges[0].toJson(), expectedRange);
@@ -73,10 +74,10 @@
// Make sure we are in the right place.
expect(stack.frames.length, greaterThanOrEqualTo(1));
- expect(stack.frames[0].function.name, 'testFunction');
+ expect(stack.frames[0].function!.name, 'testFunction');
final Library root =
- await service.getObject(isolate.id, isolate.rootLib.id);
+ await service.getObject(isolate.id, isolate.rootLib!.id) as Library;
FuncRef funcRef =
root.functions.singleWhere((f) => f.name == 'leafFunction');
Func func = await service.getObject(isolate.id, funcRef.id) as Func;
@@ -92,11 +93,12 @@
}
};
+ final location = func.location!;
final report = await service.getSourceReport(
isolate.id, [SourceReportKind.kCoverage],
- scriptId: func.location.script.id,
- tokenPos: func.location.tokenPos,
- endTokenPos: func.location.endTokenPos,
+ scriptId: location.script.id,
+ tokenPos: location.tokenPos,
+ endTokenPos: location.endTokenPos,
forceCompile: true);
expect(report.ranges.length, 1);
expect(report.ranges[0].toJson(), expectedRange);
diff --git a/pkg/vm_service/test/debugging_test.dart b/pkg/vm_service/test/debugging_test.dart
index d5c1b9e..068af19 100644
--- a/pkg/vm_service/test/debugging_test.dart
+++ b/pkg/vm_service/test/debugging_test.dart
@@ -25,14 +25,14 @@
}
int getLineNumberFromTokenPos(Script s, int token) =>
- s.tokenPosTable[token].first;
+ s.tokenPosTable![token].first;
var tests = <IsolateTest>[
// Pause
- (VmService service, IsolateRef isolateRef) async {
+ (VmService? service, IsolateRef? isolateRef) async {
Completer completer = Completer();
- var stream = service.onDebugEvent;
- var subscription;
+ var stream = service!.onDebugEvent;
+ late var subscription;
subscription = stream.listen((Event event) {
if (event.kind == EventKind.kPauseInterrupted) {
subscription.cancel();
@@ -40,7 +40,7 @@
}
});
await service.streamListen(EventStreams.kDebug);
- await service.pause(isolateRef.id);
+ await service.pause(isolateRef!.id);
await completer.future;
await service.streamCancel(EventStreams.kDebug);
},
@@ -49,7 +49,7 @@
(VmService service, IsolateRef isolate) async {
Completer completer = Completer();
var stream = service.onDebugEvent;
- var subscription;
+ late var subscription;
subscription = stream.listen((Event event) {
if (event.kind == EventKind.kResume) {
subscription.cancel();
@@ -66,12 +66,12 @@
(VmService service, IsolateRef isolateRef) async {
Isolate isolate = await service.getIsolate(isolateRef.id);
final Library rootLib =
- await service.getObject(isolate.id, isolate.rootLib.id);
+ (await service.getObject(isolate.id, isolate.rootLib!.id)) as Library;
// Set up a listener to wait for breakpoint events.
Completer completer = Completer();
var stream = service.onDebugEvent;
- var subscription;
+ late var subscription;
subscription = stream.listen((Event event) {
if (event.kind == EventKind.kPauseBreakpoint) {
print('Breakpoint reached');
@@ -80,8 +80,8 @@
}
});
await service.streamListen(EventStreams.kDebug);
- final Script script =
- await service.getObject(isolate.id, rootLib.scripts.first.id);
+ final Script script = (await service.getObject(
+ isolate.id, rootLib.scripts.first.id)) as Script;
// Add the breakpoint.
final Breakpoint bpt =
await service.addBreakpoint(isolate.id, script.id, 16);
@@ -100,10 +100,10 @@
final stack = await service.getStack(isolateRef.id);
expect(stack.frames.length, greaterThanOrEqualTo(1));
- Script script = await service.getObject(
- isolateRef.id, stack.frames[0].location.script.id);
+ Script script = (await service.getObject(
+ isolateRef.id, stack.frames[0].location!.script.id)) as Script;
expect(script.uri, endsWith('debugging_test.dart'));
- expect(script.getLineNumberFromTokenPos(stack.frames[0].location.tokenPos),
+ expect(script.getLineNumberFromTokenPos(stack.frames[0].location!.tokenPos),
16);
},
@@ -112,7 +112,7 @@
// Set up a listener to wait for breakpoint events.
final completer = Completer();
var stream = service.onDebugEvent;
- var subscription;
+ late var subscription;
subscription = stream.listen((Event event) {
if (event.kind == EventKind.kPauseBreakpoint) {
print('Breakpoint reached');
@@ -131,10 +131,10 @@
final stack = await service.getStack(isolateRef.id);
expect(stack.frames.length, greaterThanOrEqualTo(1));
- final Script script = await service.getObject(
- isolateRef.id, stack.frames[0].location.script.id);
+ final Script script = (await service.getObject(
+ isolateRef.id, stack.frames[0].location!.script.id)) as Script;
expect(script.uri, endsWith('debugging_test.dart'));
- expect(script.getLineNumberFromTokenPos(stack.frames[0].location.tokenPos),
+ expect(script.getLineNumberFromTokenPos(stack.frames[0].location!.tokenPos),
17);
},
// Remove breakpoint
@@ -142,7 +142,7 @@
// Set up a listener to wait for breakpoint events.
final completer = Completer();
var stream = service.onDebugEvent;
- var subscription;
+ late var subscription;
subscription = stream.listen((Event event) async {
if (event.kind == EventKind.kBreakpointRemoved) {
print('Breakpoint removed');
@@ -165,7 +165,7 @@
(VmService service, IsolateRef isolate) async {
final completer = Completer();
var stream = service.onDebugEvent;
- var subscription;
+ late var subscription;
subscription = stream.listen((Event event) {
if (event.kind == EventKind.kResume) {
subscription.cancel();
@@ -181,7 +181,7 @@
// Set up a listener to wait for breakpoint events.
final completer = Completer();
var stream = service.onDebugEvent;
- var subscription;
+ late var subscription;
subscription = stream.listen((Event event) {
if (event.kind == EventKind.kPauseBreakpoint) {
print('Breakpoint reached');
@@ -192,7 +192,7 @@
await service.streamListen(EventStreams.kDebug);
final Library rootLib =
- await service.getObject(isolate.id, isolate.rootLib.id);
+ (await service.getObject(isolate.id, isolate.rootLib!.id)) as Library;
// Find a specific function.
final FuncRef function =
@@ -202,7 +202,7 @@
// Add the breakpoint at function entry
final bpt = await service.addBreakpointAtEntry(isolate.id, function.id);
final Script script =
- await service.getObject(isolate.id, bpt.location.script.id);
+ (await service.getObject(isolate.id, bpt.location.script.id)) as Script;
expect(script.uri, endsWith('debugging_test.dart'));
expect(script.getLineNumberFromTokenPos(bpt.location.tokenPos), 14);
@@ -217,10 +217,10 @@
final stack = await service.getStack(isolateRef.id);
expect(stack.frames.length, greaterThanOrEqualTo(1));
- final Script script = await service.getObject(
- isolateRef.id, stack.frames[0].location.script.id);
+ final Script script = (await service.getObject(
+ isolateRef.id, stack.frames[0].location!.script.id)) as Script;
expect(script.uri, endsWith('debugging_test.dart'));
- expect(script.getLineNumberFromTokenPos(stack.frames[0].location.tokenPos),
+ expect(script.getLineNumberFromTokenPos(stack.frames[0].location!.tokenPos),
14);
},
];
diff --git a/pkg/vm_service/test/eval_test.dart b/pkg/vm_service/test/eval_test.dart
index ba30330..031b1a9e 100644
--- a/pkg/vm_service/test/eval_test.dart
+++ b/pkg/vm_service/test/eval_test.dart
@@ -44,12 +44,12 @@
// Make sure we are in the right place.
expect(stack.frames.length, greaterThanOrEqualTo(2));
- expect(stack.frames[0].function.name, 'method');
- expect((stack.frames[0].function.owner as ClassRef).name, 'MyClass');
+ expect(stack.frames[0].function!.name, 'method');
+ expect((stack.frames[0].function!.owner as ClassRef).name, 'MyClass');
- final LibraryRef lib = isolate.rootLib;
- final ClassRef cls = stack.frames[0].function.owner;
- final InstanceRef instance = stack.frames[0].vars[0].value;
+ final LibraryRef lib = isolate.rootLib!;
+ final ClassRef cls = stack.frames[0].function!.owner;
+ final InstanceRef instance = stack.frames[0].vars![0].value;
dynamic result =
await service.evaluate(isolate.id, lib.id, 'globalVar + 5');
@@ -80,13 +80,13 @@
// Make sure we are in the right place.
expect(stack.frames.length, greaterThanOrEqualTo(2));
- expect(stack.frames[0].function.name, 'foo');
- expect((stack.frames[0].function.owner as ClassRef).name, '_MyClass');
+ expect(stack.frames[0].function!.name, 'foo');
+ expect((stack.frames[0].function!.owner as ClassRef).name, '_MyClass');
- final ClassRef cls = stack.frames[0].function.owner;
+ final ClassRef cls = stack.frames[0].function!.owner;
final InstanceRef result =
- await service.evaluate(isolate.id, cls.id, "1+1");
+ await service.evaluate(isolate.id, cls.id, "1+1") as InstanceRef;
print(result);
expect(result.valueAsString, "2");
}
diff --git a/pkg/vm_service/test/evaluate_with_scope_test.dart b/pkg/vm_service/test/evaluate_with_scope_test.dart
index 8dfd4d4..4d04f7c 100644
--- a/pkg/vm_service/test/evaluate_with_scope_test.dart
+++ b/pkg/vm_service/test/evaluate_with_scope_test.dart
@@ -6,8 +6,8 @@
import 'package:test/test.dart';
import 'common/test_helper.dart';
-int thing1;
-int thing2;
+int? thing1;
+int? thing2;
testeeMain() {
thing1 = 3;
@@ -20,15 +20,18 @@
final tests = <IsolateTest>[
(VmService service, IsolateRef isolateRef) async {
final isolate = await service.getIsolate(isolateRef.id);
- final Library lib = await service.getObject(isolate.id, isolate.rootLib.id);
+ final Library lib =
+ (await service.getObject(isolate.id, isolate.rootLib!.id)) as Library;
- final Field field1 = await service.getObject(
- isolate.id, lib.variables.singleWhere((v) => v.name == 'thing1').id);
- final thing1 = (await service.getObject(isolate.id, field1.staticValue.id));
+ final Field field1 = (await service.getObject(isolate.id,
+ lib.variables.singleWhere((v) => v.name == 'thing1').id)) as Field;
+ final thing1 =
+ (await service.getObject(isolate.id, field1.staticValue!.id));
- final Field field2 = await service.getObject(
- isolate.id, lib.variables.singleWhere((v) => v.name == 'thing2').id);
- final thing2 = (await service.getObject(isolate.id, field2.staticValue.id));
+ final Field field2 = (await service.getObject(isolate.id,
+ lib.variables.singleWhere((v) => v.name == 'thing2').id)) as Field;
+ final thing2 =
+ (await service.getObject(isolate.id, field2.staticValue!.id));
var result = await evaluate(service, isolate, lib, thing1, thing2);
expect(result.valueAsString, equals('7'));
diff --git a/pkg/vm_service/test/get_cpu_samples_rpc_test.dart b/pkg/vm_service/test/get_cpu_samples_rpc_test.dart
index 8b9b143..321a01c 100644
--- a/pkg/vm_service/test/get_cpu_samples_rpc_test.dart
+++ b/pkg/vm_service/test/get_cpu_samples_rpc_test.dart
@@ -47,7 +47,7 @@
}
var tests = <IsolateTest>[
- (VmService service, IsolateRef i) => checkSamples(service, i),
+ ((VmService service, IsolateRef i) => checkSamples(service, i)),
];
var vmArgs = [
diff --git a/pkg/vm_service/test/get_flag_list_rpc_test.dart b/pkg/vm_service/test/get_flag_list_rpc_test.dart
index 8b6c337..791687d 100644
--- a/pkg/vm_service/test/get_flag_list_rpc_test.dart
+++ b/pkg/vm_service/test/get_flag_list_rpc_test.dart
@@ -22,14 +22,15 @@
var tests = <VMTest>[
// Modify a flag which does not exist.
(VmService service) async {
- final Error result = await service.setFlag('does_not_exist', 'true');
+ final Error result =
+ (await service.setFlag('does_not_exist', 'true')) as Error;
expect(result.message, 'Cannot set flag: flag not found');
},
// Modify a flag with the wrong value type.
(VmService service) async {
- final Error result =
- await service.setFlag('pause_isolates_on_start', 'not-boolean');
+ final Error result = (await service.setFlag(
+ 'pause_isolates_on_start', 'not-boolean')) as Error;
expect(result.message, equals('Cannot set flag: invalid value'));
},
@@ -41,7 +42,7 @@
// Modify a flag which cannot be set at runtime.
(VmService service) async {
- final Error result = await service.setFlag('random_seed', '42');
+ final Error result = (await service.setFlag('random_seed', '42')) as Error;
expect(result.message, 'Cannot set flag: cannot change at runtime');
},
@@ -52,7 +53,7 @@
expect(await getFlagValue(service, kProfilePeriod), '1000');
final completer = Completer();
final stream = await service.onVMEvent;
- var subscription;
+ late var subscription;
subscription = stream.listen((Event event) {
print(event);
if (event.kind == EventKind.kVMFlagUpdate) {
diff --git a/pkg/vm_service/test/get_isolate_group_memory_usage.dart b/pkg/vm_service/test/get_isolate_group_memory_usage.dart
index e6323a1..c59608a 100644
--- a/pkg/vm_service/test/get_isolate_group_memory_usage.dart
+++ b/pkg/vm_service/test/get_isolate_group_memory_usage.dart
@@ -17,7 +17,7 @@
expect(result.externalUsage, isNonNegative);
},
(VmService service) async {
- bool caughtException;
+ bool? caughtException;
try {
await service.getMemoryUsage('badid');
fail('Unreachable');
diff --git a/pkg/vm_service/test/get_isolate_rpc_test.dart b/pkg/vm_service/test/get_isolate_rpc_test.dart
index 6df4ec0..bb7dfed 100644
--- a/pkg/vm_service/test/get_isolate_rpc_test.dart
+++ b/pkg/vm_service/test/get_isolate_rpc_test.dart
@@ -16,7 +16,7 @@
expect(result.isolateFlags, isNotNull);
expect(result.isolateFlags.length, isPositive);
expect(result.isSystemIsolate, isFalse);
- expect(result.json['_originNumber'], result.number);
+ expect(result.json!['_originNumber'], result.number);
expect(result.startTime, isPositive);
expect(result.livePorts, isPositive);
expect(result.pauseOnExit, isFalse);
@@ -26,12 +26,12 @@
expect(result.libraries.length, isPositive);
expect(result.libraries[0], isNotNull);
expect(result.breakpoints.length, isZero);
- expect(result.json['_heaps']['new']['type'], 'HeapSpace');
- expect(result.json['_heaps']['old']['type'], 'HeapSpace');
+ expect(result.json!['_heaps']['new']['type'], 'HeapSpace');
+ expect(result.json!['_heaps']['old']['type'], 'HeapSpace');
},
(VmService service) async {
- bool caughtException;
+ bool caughtException = false;
try {
await service.getIsolate('badid');
expect(false, isTrue, reason: 'Unreachable');
diff --git a/pkg/vm_service/test/get_memory_usage.dart b/pkg/vm_service/test/get_memory_usage.dart
index 76cac44..b6adbef 100644
--- a/pkg/vm_service/test/get_memory_usage.dart
+++ b/pkg/vm_service/test/get_memory_usage.dart
@@ -16,7 +16,7 @@
expect(result.externalUsage, isPositive);
},
(VmService service) async {
- bool caughtException;
+ bool? caughtException;
try {
await service.getMemoryUsage('badid');
fail('Unreachable');
diff --git a/pkg/vm_service/test/heap_snapshot_graph_test.dart b/pkg/vm_service/test/heap_snapshot_graph_test.dart
index 7b035cc..b9fbe10 100644
--- a/pkg/vm_service/test/heap_snapshot_graph_test.dart
+++ b/pkg/vm_service/test/heap_snapshot_graph_test.dart
@@ -13,9 +13,9 @@
dynamic right;
}
-Foo r;
+late Foo r;
-List lst;
+late List lst;
void script() {
// Create 3 instances of Foo, with out-degrees
diff --git a/pkg/vm_service/test/http_enable_timeline_logging_service_test.dart b/pkg/vm_service/test/http_enable_timeline_logging_service_test.dart
index 10157d5..a4f88f7 100644
--- a/pkg/vm_service/test/http_enable_timeline_logging_service_test.dart
+++ b/pkg/vm_service/test/http_enable_timeline_logging_service_test.dart
@@ -25,11 +25,11 @@
{bool useSetter = true}) async {
final completer = Completer<void>();
final isolateId = isolateRef.id;
- StreamSubscription sub;
+ late StreamSubscription sub;
sub = service.onExtensionEvent.listen((event) {
expect(event.extensionKind, 'HttpTimelineLoggingStateChange');
- expect(event.extensionData.data['isolateId'], isolateRef.id);
- expect(event.extensionData.data['enabled'], state);
+ expect(event.extensionData!.data['isolateId'], isolateRef.id);
+ expect(event.extensionData!.data['enabled'], state);
sub.cancel();
completer.complete();
});
@@ -49,12 +49,12 @@
(VmService service, IsolateRef isolateRef) async {
final isolate = await service.getIsolate(isolateRef.id);
// Ensure all HTTP service extensions are registered.
- expect(isolate.extensionRPCs.length, greaterThanOrEqualTo(2));
+ expect(isolate.extensionRPCs!.length, greaterThanOrEqualTo(2));
expect(
- isolate.extensionRPCs.contains(kGetHttpEnableTimelineLogging), isTrue);
+ isolate.extensionRPCs!.contains(kGetHttpEnableTimelineLogging), isTrue);
expect(
- isolate.extensionRPCs.contains(kSetHttpEnableTimelineLogging), isTrue);
- expect(isolate.extensionRPCs.contains(kHttpEnableTimelineLogging), isTrue);
+ isolate.extensionRPCs!.contains(kSetHttpEnableTimelineLogging), isTrue);
+ expect(isolate.extensionRPCs!.contains(kHttpEnableTimelineLogging), isTrue);
},
(VmService service, IsolateRef isolateRef) async {
final isolateId = isolateRef.id;
diff --git a/pkg/vm_service/test/invoke_test.dart b/pkg/vm_service/test/invoke_test.dart
index 651e39e..47d7f8c 100644
--- a/pkg/vm_service/test/invoke_test.dart
+++ b/pkg/vm_service/test/invoke_test.dart
@@ -31,19 +31,21 @@
hasStoppedAtBreakpoint,
(VmService service, IsolateRef isolateRef) async {
final isolate = await service.getIsolate(isolateRef.id);
- final Library lib = await service.getObject(isolate.id, isolate.rootLib.id);
+ final Library lib =
+ await service.getObject(isolate.id, isolate.rootLib!.id) as Library;
final cls = lib.classes.singleWhere((cls) => cls.name == "Klass");
FieldRef fieldRef =
lib.variables.singleWhere((field) => field.name == "instance");
- Field field = await service.getObject(isolate.id, fieldRef.id);
- final instance = await service.getObject(isolate.id, field.staticValue.id);
+ Field field = await service.getObject(isolate.id, fieldRef.id) as Field;
+ final instance = await service.getObject(isolate.id, field.staticValue!.id);
fieldRef = lib.variables.singleWhere((field) => field.name == "apple");
- field = await service.getObject(isolate.id, fieldRef.id);
- final apple = await service.getObject(isolate.id, field.staticValue.id);
+ field = await service.getObject(isolate.id, fieldRef.id) as Field;
+ final apple = await service.getObject(isolate.id, field.staticValue!.id);
fieldRef = lib.variables.singleWhere((field) => field.name == "banana");
- field = await service.getObject(isolate.id, fieldRef.id);
- Instance banana = await service.getObject(isolate.id, field.staticValue.id);
+ field = await service.getObject(isolate.id, fieldRef.id) as Field;
+ Instance banana =
+ await service.getObject(isolate.id, field.staticValue!.id) as Instance;
dynamic result =
await service.invoke(isolate.id, lib.id, 'libraryFunction', []);
@@ -69,7 +71,7 @@
expectError(func) async {
dynamic result = await func();
- expect(result.type == 'Error' || result.type == '@Error', isTrue);
+ expect(result.type == 'Error' || result.type == 'ErrorRef', isTrue);
}
main([args = const <String>[]]) =>
diff --git a/pkg/vm_service/test/network_profiling_test.dart b/pkg/vm_service/test/network_profiling_test.dart
index d554d81..1463fbe 100644
--- a/pkg/vm_service/test/network_profiling_test.dart
+++ b/pkg/vm_service/test/network_profiling_test.dart
@@ -29,11 +29,11 @@
{bool useSetter = true}) async {
final completer = Completer<void>();
final isolateId = isolateRef.id;
- StreamSubscription sub;
+ late StreamSubscription sub;
sub = service.onExtensionEvent.listen((event) {
expect(event.extensionKind, 'SocketProfilingStateChange');
- expect(event.extensionData.data['isolateId'], isolateRef.id);
- expect(event.extensionData.data['enabled'], state);
+ expect(event.extensionData!.data['isolateId'], isolateRef.id);
+ expect(event.extensionData!.data['enabled'], state);
sub.cancel();
completer.complete();
});
@@ -60,7 +60,7 @@
var socket = await io.Socket.connect(localhost, serverSocket.port);
socket.write(content);
await socket.flush();
- await socket.destroy();
+ socket.destroy();
// rawDatagram
final doneCompleter = Completer<void>();
@@ -88,13 +88,13 @@
(VmService service, IsolateRef isolateRef) async {
final isolate = await service.getIsolate(isolateRef.id);
// Ensure all network profiling service extensions are registered.
- expect(isolate.extensionRPCs.length, greaterThanOrEqualTo(5));
- expect(isolate.extensionRPCs.contains(kClearSocketProfileRPC), isTrue);
- expect(isolate.extensionRPCs.contains(kGetVersionRPC), isTrue);
- expect(isolate.extensionRPCs.contains(kPauseSocketProfilingRPC), isTrue);
- expect(isolate.extensionRPCs.contains(kStartSocketProfilingRPC), isTrue);
- expect(isolate.extensionRPCs.contains(kPauseSocketProfilingRPC), isTrue);
- expect(isolate.extensionRPCs.contains(kSocketProfilingEnabledRPC), isTrue);
+ expect(isolate.extensionRPCs!.length, greaterThanOrEqualTo(5));
+ expect(isolate.extensionRPCs!.contains(kClearSocketProfileRPC), isTrue);
+ expect(isolate.extensionRPCs!.contains(kGetVersionRPC), isTrue);
+ expect(isolate.extensionRPCs!.contains(kPauseSocketProfilingRPC), isTrue);
+ expect(isolate.extensionRPCs!.contains(kStartSocketProfilingRPC), isTrue);
+ expect(isolate.extensionRPCs!.contains(kPauseSocketProfilingRPC), isTrue);
+ expect(isolate.extensionRPCs!.contains(kSocketProfilingEnabledRPC), isTrue);
},
// Test getSocketProfiler
diff --git a/pkg/vm_service/test/process_service_test.dart b/pkg/vm_service/test/process_service_test.dart
index a47359a..d8f63ea 100644
--- a/pkg/vm_service/test/process_service_test.dart
+++ b/pkg/vm_service/test/process_service_test.dart
@@ -24,19 +24,19 @@
'--pause_isolates_on_start',
io.Platform.script.toFilePath(),
];
- io.Process process1;
- io.Process process2;
- io.Process process3;
+ io.Process? process1;
+ io.Process? process2;
+ io.Process? process3;
void closeDown() {
if (process1 != null) {
- process1.kill();
+ process1!.kill();
}
if (process2 != null) {
- process2.kill();
+ process2!.kill();
}
if (process3 != null) {
- process3.kill();
+ process3!.kill();
}
dir.deleteSync(recursive: true);
}
@@ -70,14 +70,14 @@
final result = jsonEncode({
'type': 'foobar',
- 'pids': [process1.pid, process2.pid, process3.pid]
+ 'pids': [process1!.pid, process2!.pid, process3!.pid]
});
return Future.value(ServiceExtensionResponse.result(result));
}
Future<ServiceExtensionResponse> closeStdin(ignored_a, ignored_b) {
- process3.stdin.close();
- return process3.exitCode.then<ServiceExtensionResponse>((int exit) {
+ process3!.stdin.close();
+ return process3!.exitCode.then<ServiceExtensionResponse>((int exit) {
final result = jsonEncode({'type': 'foobar'});
return ServiceExtensionResponse.result(result);
});
@@ -105,7 +105,7 @@
);
expect(first.name, io.Platform.executable);
- expect(first.pid, equals(setup.json['pids'][0]));
+ expect(first.pid, equals(setup.json!['pids']![0]));
expect(first.arguments.contains('foobar'), isFalse);
expect(first.startedAt, greaterThan(0));
@@ -115,7 +115,7 @@
);
expect(second.name, io.Platform.executable);
- expect(second.pid, equals(setup.json['pids'][1]));
+ expect(second.pid, equals(setup.json!['pids']![1]));
expect(second.arguments.contains('foobar'), isTrue);
expect(second.pid != first.pid, isTrue);
expect(second.startedAt, greaterThan(0));
@@ -127,7 +127,7 @@
);
expect(third.name, dartJITBinary);
- expect(third.pid, equals(setup.json['pids'][2]));
+ expect(third.pid, equals(setup.json!['pids']![2]));
expect(third.pid != first.pid, isTrue);
expect(third.pid != second.pid, isTrue);
expect(third.startedAt, greaterThanOrEqualTo(second.startedAt));
diff --git a/pkg/vm_service/test/server_test.dart b/pkg/vm_service/test/server_test.dart
index 2362c93..97b0aed 100644
--- a/pkg/vm_service/test/server_test.dart
+++ b/pkg/vm_service/test/server_test.dart
@@ -2,6 +2,8 @@
// 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.
+// @dart = 2.10
+
@TestOn('vm')
import 'dart:async';
import 'dart:convert';
@@ -110,7 +112,7 @@
test('with no params or isolateId', () {
var extension = 'ext.cool';
var request = rpcRequest(extension, params: null);
- var response = Response(type: '')..json = {"hello": "world"};
+ var response = Response()..json = {"hello": "world"};
when(serviceMock.callServiceExtension(
extension,
isolateId: argThat(isNull, named: 'isolateId'),
@@ -127,7 +129,7 @@
test('with isolateId and no other params', () {
var extension = 'ext.cool';
var request = rpcRequest(extension, params: {'isolateId': '1'});
- var response = Response(type: '')..json = {"hello": "world"};
+ var response = Response()..json = {"hello": "world"};
when(serviceMock.callServiceExtension(
extension,
isolateId: argThat(equals('1'), named: 'isolateId'),
@@ -145,7 +147,7 @@
var extension = 'ext.cool';
var params = {'cool': 'option'};
var request = rpcRequest(extension, params: params);
- var response = Response(type: '')..json = {"hello": "world"};
+ var response = Response()..json = {"hello": "world"};
when(serviceMock.callServiceExtension(
extension,
isolateId: argThat(isNull, named: 'isolateId'),
@@ -164,7 +166,7 @@
var params = {'cool': 'option'};
var request =
rpcRequest(extension, params: Map.of(params)..['isolateId'] = '1');
- var response = Response(type: '')..json = {"hello": "world"};
+ var response = Response()..json = {"hello": "world"};
when(serviceMock.callServiceExtension(
extension,
isolateId: argThat(equals("1"), named: 'isolateId'),
@@ -214,7 +216,7 @@
when(serviceMock.streamListen(streamId))
.thenAnswer((_) => Future.value(response));
requestsController.add(request);
- await expect(responseQueue, emitsThrough(rpcResponse(response)));
+ await expectLater(responseQueue, emitsThrough(rpcResponse(response)));
eventController = serviceMock.streamControllers[streamId];
@@ -229,7 +231,7 @@
)
];
events.forEach(eventController.add);
- await expect(
+ await expectLater(
responseQueue,
emitsInOrder(
events.map((event) => streamNotifyResponse(streamId, event))));
@@ -241,7 +243,7 @@
when(serviceMock.streamListen(streamId))
.thenAnswer((_) => Future.value(response));
requestsController.add(request);
- await expect(responseQueue, emitsThrough(rpcResponse(response)));
+ await expectLater(responseQueue, emitsThrough(rpcResponse(response)));
var nextEvent = Event(
kind: EventKind.kIsolateReload,
@@ -329,7 +331,7 @@
rpcRequest('streamListen', params: {'streamId': serviceStream}));
requestsController
.add(rpcRequest('registerService', params: {'service': serviceId}));
- await expect(
+ await expectLater(
responsesController.stream
.map((Map response) => stripEventTimestamp(response)),
emitsThrough(serviceRegisteredEvent));
@@ -343,8 +345,12 @@
responsesController2.close();
});
- VmServerConnection(requestsController2.stream,
- responsesController2.sink, serviceRegistry, null);
+ VmServerConnection(
+ requestsController2.stream,
+ responsesController2.sink,
+ serviceRegistry,
+ VmService(Stream.empty(), (String _) => null),
+ );
expect(
responsesController2.stream
@@ -367,8 +373,12 @@
var requestsController3 = StreamController<Map<String, Object>>();
var responsesController3 = StreamController<Map<String, Object>>();
- VmServerConnection(requestsController3.stream,
- responsesController3.sink, serviceRegistry, null);
+ VmServerConnection(
+ requestsController3.stream,
+ responsesController3.sink,
+ serviceRegistry,
+ VmService(Stream.empty(), (String _) => null),
+ );
expect(
responsesController3.stream,
neverEmits(
@@ -402,13 +412,13 @@
clientInputController.sink, serviceRegistry, serviceMock);
var requestParams = {'foo': 'bar'};
- var expectedResponse = Response(type: '')..json = {'zap': 'zip'};
- await client.registerService(serviceId, null);
+ var expectedResponse = Response()..json = {'zap': 'zip'};
+ await client.registerService(serviceId, 'service');
// Duplicate registrations should fail.
- expect(client.registerService(serviceId, null),
+ expect(client.registerService(serviceId, 'service'),
throwsA(const TypeMatcher<RPCError>()));
- await client.registerServiceCallback(serviceId, (request) async {
+ client.registerServiceCallback(serviceId, (request) async {
expect(request, equals(requestParams));
return {'result': expectedResponse.toJson()};
});
@@ -424,7 +434,7 @@
// This should complete as well.
await clientConnection.done;
- var mockResponse = Response(type: '')..json = {'mock': 'response'};
+ var mockResponse = Response()..json = {'mock': 'response'};
when(serviceMock.callServiceExtension(serviceId,
args: argThat(equals(requestParams), named: 'args'),
isolateId: argThat(isNull, named: 'isolateId')))
@@ -490,7 +500,7 @@
response['params'].containsKey('event')) {
response['params']['event']['timestamp'] = 0;
}
- return response;
+ return response as Map<String, Object>;
}
class MockVmService extends Mock implements VmServiceInterface {
diff --git a/pkg/vm_service/tool/common/generate_common.dart b/pkg/vm_service/tool/common/generate_common.dart
index f250c55..d91e730 100644
--- a/pkg/vm_service/tool/common/generate_common.dart
+++ b/pkg/vm_service/tool/common/generate_common.dart
@@ -4,6 +4,9 @@
library generate_vm_service_common;
+// TODO(bkonyi): remove once markdown and pub_semver deps are updated to null
+// safety for the SDK.
+// ignore_for_file: import_of_legacy_library_into_null_safe
import 'package:markdown/markdown.dart';
import 'package:pub_semver/pub_semver.dart';
@@ -19,9 +22,9 @@
final RegExp regex = RegExp(r'[\d.]+');
// Extract version from header: `# Dart VM Service Protocol 2.0`.
- Element node = nodes.firstWhere((n) => isH1(n));
- Text text = node.children[0];
- Match match = regex.firstMatch(text.text);
+ Element node = nodes.firstWhere((n) => isH1(n)) as Element;
+ Text text = node.children[0] as Text;
+ Match? match = regex.firstMatch(text.text);
if (match == null) throw 'Unable to locate service protocol version';
// Append a `.0`.
diff --git a/pkg/vm_service/tool/common/parser.dart b/pkg/vm_service/tool/common/parser.dart
index 3a58340..08d3709 100644
--- a/pkg/vm_service/tool/common/parser.dart
+++ b/pkg/vm_service/tool/common/parser.dart
@@ -7,21 +7,21 @@
class Token {
static final RegExp _alpha = RegExp(r'^[0-9a-zA-Z_\-@]+$');
- final String text;
- Token next;
+ final String? text;
+ Token? next;
Token(this.text);
bool get eof => text == null;
bool get isName {
- if (text == null || text.isEmpty) return false;
- return _alpha.hasMatch(text);
+ if (text == null || text!.isEmpty) return false;
+ return _alpha.hasMatch(text!);
}
- bool get isComment => text != null && text.startsWith('//');
+ bool get isComment => text != null && text!.startsWith('//');
- String toString() => text == null ? 'EOF' : text;
+ String toString() => text == null ? 'EOF' : text!;
}
class Tokenizer {
@@ -30,12 +30,12 @@
static final whitespace = ' \n\t\r';
String text;
- Token _head;
- Token _last;
+ Token? _head;
+ Token? _last;
Tokenizer(this.text);
- Token tokenize() {
+ Token? tokenize() {
_emit(null);
for (int i = 0; i < text.length; i++) {
@@ -63,15 +63,15 @@
_emit(null);
- _head = _head.next;
+ _head = _head!.next;
return _head;
}
- void _emit(String value) {
+ void _emit(String? value) {
Token token = Token(value);
if (_head == null) _head = token;
- if (_last != null) _last.next = token;
+ if (_last != null) _last!.next = token;
_last = token;
}
@@ -83,12 +83,12 @@
String toString() {
StringBuffer buf = StringBuffer();
- Token t = _head;
+ Token t = _head!;
buf.write('[${t}]\n');
while (!t.eof) {
- t = t.next;
+ t = t.next!;
buf.write('[${t}]\n');
}
@@ -97,20 +97,20 @@
}
abstract class Parser {
- final Token startToken;
+ final Token? startToken;
- Token current;
+ Token? current;
Parser(this.startToken);
Token expect(String text) {
- Token t = advance();
+ Token t = advance()!;
if (text != t.text) fail('expected ${text}, got ${t}');
return t;
}
bool consume(String text) {
- if (peek().text == text) {
+ if (peek()!.text == text) {
advance();
return true;
} else {
@@ -118,31 +118,34 @@
}
}
- Token peek() =>
- current == null ? startToken : current.eof ? current : current.next;
+ Token? peek() => current == null
+ ? startToken
+ : current!.eof
+ ? current
+ : current!.next;
Token expectName() {
- Token t = advance();
+ Token t = advance()!;
if (!t.isName) fail('expected name token, got ${t}');
return t;
}
- Token advance() {
+ Token? advance() {
if (current == null) {
current = startToken;
- } else if (!current.eof) {
- current = current.next;
+ } else if (!current!.eof) {
+ current = current!.next;
}
return current;
}
- String collectComments() {
+ String? collectComments() {
StringBuffer buf = StringBuffer();
- while (peek().isComment) {
- Token t = advance();
- String str = t.text.substring(2);
+ while (peek()!.isComment) {
+ Token t = advance()!;
+ String str = t.text!.substring(2);
if (str.startsWith(' ')) str = str.substring(1);
diff --git a/pkg/vm_service/tool/common/src_gen_common.dart b/pkg/vm_service/tool/common/src_gen_common.dart
index cb5a9fd..4fd8313 100644
--- a/pkg/vm_service/tool/common/src_gen_common.dart
+++ b/pkg/vm_service/tool/common/src_gen_common.dart
@@ -4,6 +4,9 @@
library src_gen_common;
+// TODO(bkonyi): remove once markdown and pub_semver deps are updated to null
+// safety for the SDK.
+// ignore_for_file: import_of_legacy_library_into_null_safe
import 'package:markdown/markdown.dart';
const int RUNE_SPACE = 32;
@@ -36,7 +39,7 @@
String lowerTitleCase(String str) =>
str.substring(0, 1).toLowerCase() + str.substring(1);
-String joinLast(Iterable<String> strs, String join, [String last]) {
+String joinLast(Iterable<String> strs, String join, [String? last]) {
if (strs.isEmpty) return '';
List list = strs.toList();
if (list.length == 1) return list.first;
diff --git a/pkg/vm_service/tool/dart/generate_dart.dart b/pkg/vm_service/tool/dart/generate_dart.dart
index e8dabfe..95a57cb 100644
--- a/pkg/vm_service/tool/dart/generate_dart.dart
+++ b/pkg/vm_service/tool/dart/generate_dart.dart
@@ -4,6 +4,9 @@
library generate_vm_service_dart;
+// TODO(bkonyi): remove once markdown and pub_semver deps are updated to null
+// safety for the SDK.
+// ignore_for_file: import_of_legacy_library_into_null_safe
import 'package:markdown/markdown.dart';
import '../common/generate_common.dart';
@@ -13,9 +16,9 @@
export 'src_gen_dart.dart' show DartGenerator;
-Api api;
+late Api api;
-String _coerceRefType(String typeName) {
+String? _coerceRefType(String? typeName) {
if (typeName == 'Object') typeName = 'Obj';
if (typeName == '@Object') typeName = 'ObjRef';
if (typeName == 'Null') typeName = 'NullVal';
@@ -23,7 +26,7 @@
if (typeName == 'Function') typeName = 'Func';
if (typeName == '@Function') typeName = 'FuncRef';
- if (typeName.startsWith('@')) typeName = typeName.substring(1) + 'Ref';
+ if (typeName!.startsWith('@')) typeName = typeName.substring(1) + 'Ref';
if (typeName == 'string') typeName = 'String';
if (typeName == 'map') typeName = 'Map';
@@ -32,7 +35,7 @@
}
String _typeRefListToString(List<TypeRef> types) =>
- 'const [' + types.map((e) => "'" + e.name + "'").join(',') + ']';
+ 'const [' + types.map((e) => "'" + e.name! + "'").join(',') + ']';
final String _headerCode = r'''
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
@@ -49,8 +52,6 @@
import 'dart:convert' show base64, jsonDecode, jsonEncode, utf8;
import 'dart:typed_data';
-import 'package:meta/meta.dart';
-
import 'service_extension_registry.dart';
export 'service_extension_registry.dart' show ServiceExtensionRegistry;
@@ -69,8 +70,8 @@
/// Call an arbitrary service protocol method. This allows clients to call
/// methods not explicitly exposed by this library.
Future<Response> callMethod(String method, {
- String isolateId,
- Map args
+ String? isolateId,
+ Map<String, dynamic>? args
}) {
return callServiceExtension(method, isolateId: isolateId, args: args);
}
@@ -80,13 +81,13 @@
/// See https://api.dart.dev/stable/dart-developer/dart-developer-library.html.
@override
Future<Response> callServiceExtension(String method, {
- String isolateId,
- Map args
+ String? isolateId,
+ Map<String, dynamic>? args
}) {
if (args == null && isolateId == null) {
return _call(method);
} else if (args == null) {
- return _call(method, {'isolateId': isolateId});
+ return _call(method, {'isolateId': isolateId!});
} else {
args = Map.from(args);
if (isolateId != null) {
@@ -109,7 +110,7 @@
});
_completers.clear();
if (_disposeHandler != null) {
- await _disposeHandler();
+ await _disposeHandler!();
}
if (!_onDoneCompleter.isCompleted) {
_onDoneCompleter.complete();
@@ -162,22 +163,21 @@
bytes.buffer, bytes.offsetInBytes + metaOffset, metaLength));
final data = ByteData.view(
bytes.buffer, bytes.offsetInBytes + dataOffset, dataLength);
- dynamic map = jsonDecode(meta);
- if (map != null && map['method'] == 'streamNotify') {
+ dynamic map = jsonDecode(meta)!;
+ if (map['method'] == 'streamNotify') {
String streamId = map['params']['streamId'];
Map event = map['params']['event'];
event['data'] = data;
_getEventController(streamId)
- .add(createServiceObject(event, const ['Event']));
+ .add(createServiceObject(event, const ['Event'])! as Event);
}
}
void _processMessageStr(String message) {
- var json;
+ late Map<String, dynamic> json;
try {
_onReceive.add(message);
-
- json = jsonDecode(message);
+ json = jsonDecode(message)!;
} catch (e, s) {
_log.severe('unable to decode message: ${message}, ${e}\n${s}');
return;
@@ -199,9 +199,9 @@
}
void _processResponse(Map<String, dynamic> json) {
- Completer completer = _completers.remove(json['id']);
- String methodName = _methodCalls.remove(json['id']);
- List<String> returnTypes = _methodReturnTypes[methodName];
+ Completer? completer = _completers.remove(json['id']);
+ String methodName = _methodCalls.remove(json['id'])!;
+ List<String> returnTypes = _methodReturnTypes[methodName] ?? [];
if (completer == null) {
_log.severe('unmatched request response: ${jsonEncode(json)}');
} else if (json['error'] != null) {
@@ -230,24 +230,25 @@
Future _processNotification(Map<String, dynamic> json) async {
final String method = json['method'];
- final Map params = json['params'] ?? <String, dynamic>{};
+ final Map<String, dynamic> params = json['params'] ?? <String, dynamic>{};
if (method == 'streamNotify') {
String streamId = params['streamId'];
- _getEventController(streamId).add(createServiceObject(params['event'], const ['Event']));
+ _getEventController(streamId).add(createServiceObject(params['event'], const ['Event'])! as Event);
} else {
await _routeRequest(method, params);
}
}
Future<Map> _routeRequest(String method, Map<String, dynamic> params) async{
- if (!_services.containsKey(method)) {
+ final service = _services[method];
+ if (service == null) {
RPCError error = RPCError(
method, RPCError.kMethodNotFound, 'method not found \'$method\'');
return {'error': error.toMap()};
}
try {
- return await _services[method](params);
+ return await service(params);
} catch (e, st) {
RPCError error = RPCError.withDetails(
method, RPCError.kServerError, '$e', details: '$st',);
@@ -281,22 +282,22 @@
return RPCError(callingMethod, json['code'], json['message'], json['data']);
}
- final String callingMethod;
+ final String? callingMethod;
final int code;
final String message;
- final Map data;
+ final Map? data;
RPCError(this.callingMethod, this.code, this.message, [this.data]);
RPCError.withDetails(this.callingMethod, this.code, this.message,
- {Object details})
+ {Object? details})
: data = details == null ? null : <String, dynamic>{} {
if (details != null) {
- data['details'] = details;
+ data!['details'] = details;
}
}
- String get details => data == null ? null : data['details'];
+ String? get details => data == null ? null : data!['details'];
/// Return a map representation of this error suitable for converstion to
/// json.
@@ -326,17 +327,17 @@
final Sentinel sentinel;
SentinelException.parse(this.callingMethod, Map<String, dynamic> data) :
- sentinel = Sentinel.parse(data);
+ sentinel = Sentinel.parse(data)!;
String toString() => '$sentinel from ${callingMethod}()';
}
/// An `ExtensionData` is an arbitrary map that can have any contents.
class ExtensionData {
- static ExtensionData parse(Map json) =>
+ static ExtensionData? parse(Map<String, dynamic>? json) =>
json == null ? null : ExtensionData._fromJson(json);
- final Map data;
+ final Map<String, dynamic> data;
ExtensionData() : data = {};
@@ -362,11 +363,11 @@
''';
final _registerServiceImpl = '''
-_serviceExtensionRegistry.registerExtension(params['service'], this);
+_serviceExtensionRegistry.registerExtension(params!['service'], this);
response = Success();''';
final _streamListenCaseImpl = '''
-var id = params['streamId'];
+var id = params!['streamId'];
if (_streamSubscriptions.containsKey(id)) {
throw RPCError.withDetails(
'streamListen', 103, 'Stream already subscribed',
@@ -390,7 +391,7 @@
response = Success();''';
final _streamCancelCaseImpl = '''
-var id = params['streamId'];
+var id = params!['streamId'];
var existing = _streamSubscriptions.remove(id);
if (existing == null) {
throw RPCError.withDetails(
@@ -402,22 +403,22 @@
response = Success();''';
abstract class Member {
- String get name;
+ String? get name;
- String get docs => null;
+ String? get docs => null;
void generate(DartGenerator gen);
bool get hasDocs => docs != null;
- String toString() => name;
+ String toString() => name!;
}
class Api extends Member with ApiParseUtil {
- String serviceVersion;
+ String? serviceVersion;
List<Method> methods = [];
List<Enum> enums = [];
- List<Type> types = [];
+ List<Type?> types = [];
List<StreamCategory> streamCategories = [];
void parse(List<Node> nodes) {
@@ -427,19 +428,19 @@
// the pre following it is the definition
// the optional p following that is the documentation
- String h3Name;
+ String? h3Name;
for (int i = 0; i < nodes.length; i++) {
Node node = nodes[i];
if (isPre(node) && h3Name != null) {
String definition = textForCode(node);
- String docs = '';
+ String? docs = '';
while (i + 1 < nodes.length &&
(isPara(nodes[i + 1]) || isBlockquote(nodes[i + 1])) ||
isList(nodes[i + 1])) {
- Element p = nodes[++i];
+ Element p = nodes[++i] as Element;
String str = TextOutputVisitor.printText(p);
if (!str.contains('|') &&
!str.contains('``') &&
@@ -449,7 +450,7 @@
docs = '${docs}\n\n${str}';
}
- docs = docs.trim();
+ docs = docs!.trim();
if (docs.isEmpty) docs = null;
_parse(h3Name, definition, docs);
@@ -460,20 +461,20 @@
}
}
- for (Type type in types) {
- type.calculateFieldOverrides();
+ for (Type? type in types) {
+ type!.calculateFieldOverrides();
}
Method streamListenMethod =
methods.singleWhere((method) => method.name == 'streamListen');
- _parseStreamListenDocs(streamListenMethod.docs);
+ _parseStreamListenDocs(streamListenMethod.docs!);
}
String get name => 'api';
- String get docs => null;
+ String? get docs => null;
- void _parse(String name, String definition, [String docs]) {
+ void _parse(String name, String definition, [String? docs]) {
name = name.trim();
definition = definition.trim();
// clean markdown introduced changes
@@ -518,13 +519,13 @@
bool _isNullInstance(Map json) => ((json['type'] == '@Instance') &&
(json['kind'] == 'Null'));
-Object createServiceObject(dynamic json, List<String> expectedTypes) {
+Object? createServiceObject(dynamic json, List<String> expectedTypes) {
if (json == null) return null;
if (json is List) {
return json.map((e) => createServiceObject(e, expectedTypes)).toList();
} else if (json is Map) {
- String type = json['type'];
+ String? type = json['type'];
// Not a Response type.
if (type == null) {
@@ -539,10 +540,11 @@
// be returned.
return null;
}
- if (_typeFactories[type] == null) {
+ final typeFactory = _typeFactories[type];
+ if (typeFactory == null) {
return null;
} else {
- return _typeFactories[type](json);
+ return typeFactory(json);
}
} else {
// Handle simple types.
@@ -566,7 +568,7 @@
}
}
-void _setIfNotNull(Map<String, Object> json, String key, Object value) {
+void _setIfNotNull(Map<String, dynamic> json, String key, Object? value) {
if (value == null) return;
json[key] = value;
}
@@ -588,8 +590,8 @@
''');
gen.writeln();
gen.writeln('Map<String, Function> _typeFactories = {');
- types.forEach((Type type) {
- gen.writeln("'${type.rawName}': ${type.name}.parse,");
+ types.forEach((Type? type) {
+ gen.writeln("'${type!.rawName}': ${type.name}.parse,");
});
gen.writeln('};');
gen.writeln();
@@ -615,7 +617,7 @@
Stream<Event> onEvent(String streamId);
/// Handler for calling extra service extensions.
- Future<Response> callServiceExtension(String method, {String isolateId, Map args});
+ Future<Response> callServiceExtension(String method, {String? isolateId, Map<String, dynamic>? args});
''');
methods.forEach((m) {
m.generateDefinition(gen);
@@ -628,14 +630,14 @@
// automatically.
gen.write('''
class _PendingServiceRequest {
- Future<Map<String, Object>> get future => _completer.future;
- final _completer = Completer<Map<String, Object>>();
+ Future<Map<String, Object?>> get future => _completer.future;
+ final _completer = Completer<Map<String, Object?>>();
final dynamic originalId;
_PendingServiceRequest(this.originalId);
- void complete(Map<String, Object> response) {
+ void complete(Map<String, Object?> response) {
response['id'] = originalId;
_completer.complete(response);
}
@@ -649,7 +651,7 @@
/// instances.
class VmServerConnection {
final Stream<Map<String, Object>> _requestStream;
- final StreamSink<Map<String, Object>> _responseSink;
+ final StreamSink<Map<String, Object?>> _responseSink;
final ServiceExtensionRegistry _serviceExtensionRegistry;
final VmServiceInterface _serviceImplementation;
/// Used to create unique ids when acting as a proxy between clients.
@@ -659,8 +661,8 @@
final _streamSubscriptions = <String, StreamSubscription>{};
/// Completes when [_requestStream] is done.
- Future get done => _doneCompleter.future;
- final _doneCompleter = Completer<Null>();
+ Future<void> get done => _doneCompleter.future;
+ final _doneCompleter = Completer<void>();
/// Pending service extension requests to this client by id.
final _pendingServiceExtensionRequests = <dynamic, _PendingServiceRequest>{};
@@ -678,13 +680,13 @@
///
/// We don't attempt to do any serialization or deserialization of the
/// request or response in this case
- Future<Map<String, Object>> _forwardServiceExtensionRequest(
- Map<String, Object> request) {
- var originalId = request['id'];
- request = Map.of(request);
+ Future<Map<String, Object?>> _forwardServiceExtensionRequest(
+ Map<String, Object?> request) {
+ final originalId = request['id'];
+ request = Map<String, Object?>.of(request);
// Modify the request ID to ensure we don't have conflicts between
// multiple clients ids.
- var newId = '\${_nextServiceRequestId++}:\$originalId';
+ final newId = '\${_nextServiceRequestId++}:\$originalId';
request['id'] = newId;
var pendingRequest = _PendingServiceRequest(originalId);
_pendingServiceExtensionRequests[newId] = pendingRequest;
@@ -692,22 +694,22 @@
return pendingRequest.future;
}
- void _delegateRequest(Map<String, Object> request) async {
+ void _delegateRequest(Map<String, Object?> request) async {
try {
var id = request['id'];
// Check if this is actually a response to a pending request.
if (_pendingServiceExtensionRequests.containsKey(id)) {
- final pending = _pendingServiceExtensionRequests[id];
- pending.complete(Map.of(request));
+ final pending = _pendingServiceExtensionRequests[id]!;
+ pending.complete(Map<String, Object?>.of(request));
return;
}
- var method = request['method'] as String;
+ final method = request['method'] as String?;
if (method == null) {
throw RPCError(
null, RPCError.kInvalidRequest, 'Invalid Request', request);
}
- var params = request['params'] as Map;
- Response response;
+ final params = request['params'] as Map<String, dynamic>?;
+ late Response response;
switch(method) {
case 'registerService':
@@ -722,14 +724,22 @@
} else if (m.name == 'streamCancel') {
gen.writeln(_streamCancelCaseImpl);
} else {
+ bool firstParam = true;
+ final nullCheck = () {
+ final result = firstParam ? '!' : '';
+ if (firstParam) {
+ firstParam = false;
+ }
+ return result;
+ };
gen.write("response = await _serviceImplementation.${m.name}(");
// Positional args
m.args.where((arg) => !arg.optional).forEach((MethodArg arg) {
if (arg.type.isArray) {
gen.write(
- "${arg.type.listCreationRef}.from(params['${arg.name}'] ?? []), ");
+ "${arg.type.listCreationRef}.from(params${nullCheck()}['${arg.name}'] ?? []), ");
} else {
- gen.write("params['${arg.name}'], ");
+ gen.write("params${nullCheck()}['${arg.name}'], ");
}
});
// Optional named args
@@ -738,9 +748,10 @@
namedArgs.forEach((arg) {
if (arg.name == 'scope') {
gen.writeln(
- "${arg.name}: params['${arg.name}']?.cast<String, String>(), ");
+ "${arg.name}: params${nullCheck()}['${arg.name}']?.cast<String, String>(), ");
} else {
- gen.writeln("${arg.name}: params['${arg.name}'], ");
+ gen.writeln(
+ "${arg.name}: params${nullCheck()}['${arg.name}'], ");
}
});
}
@@ -752,7 +763,7 @@
// Handle service extensions
gen.writeln('default:');
gen.writeln('''
- var registeredClient = _serviceExtensionRegistry.clientFor(method);
+ final registeredClient = _serviceExtensionRegistry.clientFor(method);
if (registeredClient != null) {
// Check for any client which has registered this extension, if we
// have one then delegate the request to that client.
@@ -764,8 +775,8 @@
} else if (method.startsWith('ext.')) {
// Remaining methods with `ext.` are assumed to be registered via
// dart:developer, which the service implementation handles.
- var args = params == null ? null : Map.of(params);
- var isolateId = args?.remove('isolateId');
+ final args = params == null ? null : Map<String, dynamic>.of(params);
+ final isolateId = args?.remove('isolateId');
response = await _serviceImplementation.callServiceExtension(method,
isolateId: isolateId, args: args);
} else {
@@ -775,13 +786,6 @@
// Terminate the switch
gen.writeln('}');
- // Handle null responses
- gen.write('''
- if (response == null) {
- throw StateError('Invalid null response from service');
- }
- ''');
-
// Generate the json success response
gen.write("""_responseSink.add({
'jsonrpc': '2.0',
@@ -793,7 +797,7 @@
// Close the try block, handle errors
gen.write(r'''
} catch (e, st) {
- var error = e is RPCError
+ final error = e is RPCError
? e.toMap()
: {
'code': RPCError.kInternalError,
@@ -817,13 +821,13 @@
// The client side service implementation.
gen.writeStatement('class VmService implements VmServiceInterface {');
- gen.writeStatement('StreamSubscription _streamSub;');
- gen.writeStatement('Function _writeMessage;');
+ gen.writeStatement('late final StreamSubscription _streamSub;');
+ gen.writeStatement('late final Function _writeMessage;');
gen.writeStatement('int _id = 0;');
gen.writeStatement('Map<String, Completer> _completers = {};');
gen.writeStatement('Map<String, String> _methodCalls = {};');
gen.writeStatement('Map<String, ServiceCallback> _services = {};');
- gen.writeStatement('Log _log;');
+ gen.writeStatement('late final Log _log;');
gen.write('''
StreamController<String> _onSend = StreamController.broadcast(sync: true);
@@ -834,7 +838,7 @@
Map<String, StreamController<Event>> _eventControllers = {};
StreamController<Event> _getEventController(String eventName) {
- StreamController<Event> controller = _eventControllers[eventName];
+ StreamController<Event>? controller = _eventControllers[eventName];
if (controller == null) {
controller = StreamController.broadcast();
_eventControllers[eventName] = controller;
@@ -842,12 +846,12 @@
return controller;
}
-DisposeHandler _disposeHandler;
+late final DisposeHandler? _disposeHandler;
VmService(Stream<dynamic> /*String|List<int>*/ inStream, void writeMessage(String message), {
- Log log,
- DisposeHandler disposeHandler,
- Future streamClosed,
+ Log? log,
+ DisposeHandler? disposeHandler,
+ Future? streamClosed,
}) {
_streamSub = inStream.listen(_processMessage, onDone: ()=> _onDoneCompleter.complete());
_writeMessage = writeMessage;
@@ -882,7 +886,7 @@
});
gen.writeln();
gen.writeln('// types');
- types.where((t) => !t.skip).forEach((t) => t.generate(gen));
+ types.where((t) => !t!.skip).forEach((t) => t!.generate(gen));
}
void generateAsserts(DartGenerator gen) {
@@ -903,17 +907,14 @@
}
bool assertBool(bool obj) {
- assertNotNull(obj);
return obj;
}
int assertInt(int obj) {
- assertNotNull(obj);
return obj;
}
double assertDouble(double obj) {
- assertNotNull(obj);
return obj;
}
@@ -944,13 +945,11 @@
}
String assertString(String obj) {
- assertNotNull(obj);
if (obj.isEmpty) throw 'expected non-zero length string';
return obj;
}
vms.Success assertSuccess(vms.Success obj) {
- assertNotNull(obj);
if (obj.type != 'Success') throw 'expected Success';
return obj;
}
@@ -964,10 +963,10 @@
event.kind == vms.EventKind.kBreakpointAdded ||
event.kind == vms.EventKind.kBreakpointRemoved ||
event.kind == vms.EventKind.kBreakpointResolved) {
- assertBreakpoint(event.breakpoint);
+ assertBreakpoint(event.breakpoint!);
}
if (event.kind == vms.EventKind.kPauseBreakpoint) {
- for (vms.Breakpoint elem in event.pauseBreakpoints) {
+ for (vms.Breakpoint elem in event.pauseBreakpoints!) {
assertBreakpoint(elem);
}
}
@@ -983,18 +982,18 @@
if (event.topFrame != null ||
(event.kind != vms.EventKind.kPauseInterrupted &&
event.kind != vms.EventKind.kResume)) {
- assertFrame(event.topFrame);
+ assertFrame(event.topFrame!);
}
}
if (event.kind == vms.EventKind.kPauseException) {
- assertInstanceRef(event.exception);
+ assertInstanceRef(event.exception!);
}
if (event.kind == vms.EventKind.kPauseBreakpoint ||
event.kind == vms.EventKind.kPauseInterrupted) {
- assertBool(event.atAsyncSuspension);
+ assertBool(event.atAsyncSuspension!);
}
if (event.kind == vms.EventKind.kInspect) {
- assertInstanceRef(event.inspectee);
+ assertInstanceRef(event.inspectee!);
}
return event;
}
@@ -1004,7 +1003,7 @@
vms.Event assertIsolateEvent(vms.Event event) {
assertEvent(event);
if (event.kind == vms.EventKind.kServiceExtensionAdded) {
- assertString(event.extensionRPC);
+ assertString(event.extensionRPC!);
}
return event;
}
@@ -1013,10 +1012,10 @@
for (Enum e in enums) {
e.generateAssert(gen);
}
- for (Type type in types) {
- if (type.name == 'Success') continue;
+ for (Type? type in types) {
+ if (type!.name == 'Success') continue;
type.generateAssert(gen);
- if (type.name.endsWith('Ref') ||
+ if (type.name!.endsWith('Ref') ||
[
'BoundVariable',
'Breakpoint',
@@ -1029,6 +1028,7 @@
'InboundReference',
'LibraryDependency',
'Message',
+ 'ProcessMemoryItem',
'ProfileFunction',
'ProcessMemoryItem',
'Protocol',
@@ -1043,16 +1043,17 @@
void setDefaultValue(String typeName, String fieldName, String defaultValue) {
types
- .firstWhere((t) => t.name == typeName)
+ .firstWhere((t) => t!.name == typeName)!
.fields
.firstWhere((f) => f.name == fieldName)
.defaultValue = defaultValue;
}
- bool isEnumName(String typeName) => enums.any((Enum e) => e.name == typeName);
+ bool isEnumName(String? typeName) =>
+ enums.any((Enum e) => e.name == typeName);
- Type getType(String name) =>
- types.firstWhere((t) => t.name == name, orElse: () => null);
+ Type? getType(String? name) =>
+ types.firstWhere((t) => t!.name == name, orElse: () => null);
void _parseStreamListenDocs(String docs) {
Iterator<String> lines = docs.split('\n').map((l) => l.trim()).iterator;
@@ -1090,8 +1091,8 @@
}
class StreamCategory {
- String _name;
- List<String> _events;
+ String? _name;
+ List<String>? _events;
StreamCategory(String line) {
// Debug | PauseStart, PauseExit, ...
@@ -1101,13 +1102,13 @@
_events = line.split(',').map((w) => w.trim()).toList();
}
- String get name => _name;
+ String? get name => _name;
- List<String> get events => _events;
+ List<String>? get events => _events;
void generate(DartGenerator gen) {
gen.writeln();
- gen.writeln('// ${events.join(', ')}');
+ gen.writeln('// ${events!.join(', ')}');
gen.writeln(
"Stream<Event> get on${name}Event => _getEventController('$name').stream;");
}
@@ -1117,7 +1118,7 @@
class Method extends Member {
final String name;
- final String docs;
+ final String? docs;
MemberType returnType = MemberType();
List<MethodArg> args = [];
@@ -1142,7 +1143,7 @@
.join());
args.where((MethodArg a) => a.optional).forEach((MethodArg arg) {
- String valueRef = arg.name;
+ String? valueRef = arg.name;
// Special case for `getAllocationProfile`. We do not want to add these
// params if they are false.
if (name == 'getAllocationProfile') {
@@ -1173,7 +1174,7 @@
{bool withDocs = true, bool withOverrides = false}) {
gen.writeln();
if (withDocs && docs != null) {
- String _docs = docs == null ? '' : docs;
+ String _docs = docs == null ? '' : docs!;
if (returnType.isMultipleReturns) {
_docs += '\n\nThe return value can be one of '
'${joinLast(returnType.types.map((t) => '[${t}]'), ', ', ' or ')}.';
@@ -1190,7 +1191,7 @@
gen.write('Future<${returnType.name}> ${name}(');
bool startedOptional = false;
gen.write(args.map((MethodArg arg) {
- String typeName;
+ String? typeName;
if (api.isEnumName(arg.type.name)) {
if (arg.type.isArray) {
typeName = typeName = '/*${arg.type}*/ List<String>';
@@ -1200,12 +1201,12 @@
} else {
typeName = arg.type.ref;
}
-
+ final nullable = arg.optional ? '?' : '';
if (arg.optional && !startedOptional) {
startedOptional = true;
- return '{${typeName} ${arg.name}';
+ return '{${typeName}$nullable ${arg.name}';
} else {
- return '${typeName} ${arg.name}';
+ return '${typeName}$nullable ${arg.name}';
}
}).join(', '));
if (args.length >= 4) gen.write(',');
@@ -1213,7 +1214,7 @@
gen.write(') ');
}
- void _parse(Token token) => MethodParser(token).parseInto(this);
+ void _parse(Token? token) => MethodParser(token).parseInto(this);
}
class MemberType extends Member {
@@ -1229,7 +1230,7 @@
while (loop) {
if (parser.consume('(')) {
- while (parser.peek().text != ')') {
+ while (parser.peek()!.text != ')') {
// @Instance | Sentinel
parser.advance();
}
@@ -1258,7 +1259,7 @@
}
}
- String get name {
+ String? get name {
if (types.isEmpty) return '';
if (types.length == 1) return types.first.ref;
if (isReturnType) return 'Response';
@@ -1276,25 +1277,25 @@
bool get isArray => types.length == 1 && types.first.isArray;
- void generate(DartGenerator gen) => gen.write(name);
+ void generate(DartGenerator gen) => gen.write(name!);
}
class TypeRef {
- String name;
+ String? name;
int arrayDepth = 0;
- List<TypeRef> genericTypes;
+ List<TypeRef>? genericTypes;
TypeRef(this.name);
- String get ref {
+ String? get ref {
if (arrayDepth == 2) {
return 'List<List<${name}>>';
} else if (arrayDepth == 1) {
return 'List<${name}>';
} else if (genericTypes != null) {
- return '$name<${genericTypes.join(', ')}>';
+ return '$name<${genericTypes!.join(', ')}>';
} else {
- return name.startsWith('_') ? name.substring(1) : name;
+ return name!.startsWith('_') ? name!.substring(1) : name;
}
}
@@ -1308,7 +1309,7 @@
}
}
- String get listTypeArg => arrayDepth == 2 ? 'List<$name>' : name;
+ String? get listTypeArg => arrayDepth == 2 ? 'List<$name>' : name;
bool get isArray => arrayDepth > 0;
@@ -1330,13 +1331,13 @@
name == 'double' ||
name == 'ByteData');
- String toString() => ref;
+ String toString() => ref!;
}
class MethodArg extends Member {
final Method parent;
TypeRef type;
- String name;
+ String? name;
bool optional = false;
MethodArg(this.parent, this.type, this.name);
@@ -1350,10 +1351,10 @@
class Type extends Member {
final Api parent;
- String rawName;
- String name;
- String superName;
- final String docs;
+ String? rawName;
+ String? name;
+ String? superName;
+ final String? docs;
List<TypeField> fields = [];
Type(this.parent, String categoryName, String definition, [this.docs]) {
@@ -1364,11 +1365,11 @@
factory Type.merge(Type t1, Type t2) {
final Api parent = t1.parent;
- final String rawName = t1.rawName;
- final String name = t1.name;
- final String superName = t1.superName;
+ final String? rawName = t1.rawName;
+ final String? name = t1.name;
+ final String? superName = t1.superName;
final String docs = [t1.docs, t2.docs].where((e) => e != null).join('\n');
- final Map<String, TypeField> map = <String, TypeField>{};
+ final Map<String?, TypeField> map = <String?, TypeField>{};
for (TypeField f in t2.fields.reversed) {
map[f.name] = f;
}
@@ -1385,17 +1386,17 @@
bool get isResponse {
if (superName == null) return false;
if (name == 'Response' || superName == 'Response') return true;
- return parent.getType(superName).isResponse;
+ return parent.getType(superName)!.isResponse;
}
- bool get isRef => name.endsWith('Ref');
+ bool get isRef => name!.endsWith('Ref');
bool get supportsIdentity {
if (fields.any((f) => f.name == 'id')) return true;
- return superName == null ? false : getSuper().supportsIdentity;
+ return superName == null ? false : getSuper()!.supportsIdentity;
}
- Type getSuper() => superName == null ? null : api.getType(superName);
+ Type? getSuper() => superName == null ? null : api.getType(superName);
List<TypeField> getAllFields() {
if (superName == null) return fields;
@@ -1403,7 +1404,7 @@
List<TypeField> all = [];
all.insertAll(0, fields);
- Type s = getSuper();
+ Type? s = getSuper();
while (s != null) {
all.insertAll(0, s.fields);
s = s.getSuper();
@@ -1418,7 +1419,7 @@
gen.writeln();
if (docs != null) gen.writeDocs(docs);
gen.write('class ${name} ');
- Type superType;
+ Type? superType;
if (superName != null) {
superType = parent.getType(superName);
gen.write('extends ${superName} ');
@@ -1427,12 +1428,12 @@
gen.write('implements ${name}Ref ');
}
gen.writeln('{');
- gen.writeln('static ${name} parse(Map<String, dynamic> json) => '
+ gen.writeln('static ${name}? parse(Map<String, dynamic>? json) => '
'json == null ? null : ${name}._fromJson(json);');
gen.writeln();
if (name == 'Response' || name == 'TimelineEvent') {
- gen.writeln('Map<String, dynamic> json;');
+ gen.writeln('Map<String, dynamic>? json;');
}
if (name == 'Script') {
gen.writeln('final _tokenToLine = <int, int>{};');
@@ -1451,11 +1452,12 @@
gen.write('${name}(');
if (fields.isNotEmpty) {
gen.write('{');
- fields
- .where((field) => !field.optional)
- .forEach((field) => field.generateNamedParameter(gen));
+ fields.where((field) => !field.optional).forEach((field) {
+ final fromParent = (name == 'Instance' && field.name == 'classRef');
+ field.generateNamedParameter(gen, fromParent: fromParent);
+ });
if (hasRequiredParentFields) {
- superType.fields.where((field) => !field.optional).forEach(
+ superType!.fields.where((field) => !field.optional).forEach(
(field) => field.generateNamedParameter(gen, fromParent: true));
}
fields
@@ -1466,12 +1468,23 @@
gen.write(')');
if (hasRequiredParentFields) {
gen.write(' : super(');
- superType.fields.where((field) => !field.optional).forEach((field) {
- String name = field.generatableName;
- gen.write('$name: $name');
+ superType!.fields.where((field) => !field.optional).forEach((field) {
+ String? name = field.generatableName;
+ gen.writeln('$name: $name,');
});
+ if (name == 'Instance') {
+ gen.writeln('classRef: classRef,');
+ }
gen.write(')');
+ } else if (name!.contains('NullVal')) {
+ gen.writeln(' : super(');
+ gen.writeln("id: 'instance/null',");
+ gen.writeln('kind: InstanceKind.kNull,');
+ gen.writeln("classRef: ClassRef(id: 'class/null',");
+ gen.writeln("name: 'Null',),");
+ gen.writeln(')');
}
+
gen.writeln(';');
// Build from JSON.
@@ -1501,6 +1514,37 @@
}
if (field.defaultValue != null) {
gen.write(' ?? ${field.defaultValue}');
+ } else if (!field.optional) {
+ // If a default isn't provided and the field is required, generate a
+ // sane default initializer to avoid TypeErrors at runtime when
+ // running in a null-safe context.
+ dynamic defaultValue;
+ switch (field.type.name) {
+ case 'int':
+ case 'num':
+ case 'double':
+ defaultValue = -1;
+ break;
+ case 'bool':
+ defaultValue = false;
+ break;
+ case 'String':
+ defaultValue = "''";
+ break;
+ case 'ByteData':
+ defaultValue = "ByteData(0)";
+ break;
+ default:
+ {
+ if (field.type.isEnum) {
+ // TODO(bkonyi): Figure out if there's a more correct way to
+ // determine a default value for enums.
+ defaultValue = "''";
+ }
+ break;
+ }
+ }
+ gen.write(' ?? $defaultValue');
}
gen.writeln(';');
// } else if (field.type.isEnum) {
@@ -1512,31 +1556,35 @@
// Special case `Event.extensionData`.
gen.writeln(
"extensionData = ExtensionData.parse(json['extensionData']);");
- } else if (name == 'Instance' && field.name == 'associations') {
- // Special case `Instance.associations`.
- gen.writeln("associations = json['associations'] == null "
- "? null : List<MapAssociation>.from("
- "_createSpecificObject(json['associations'], MapAssociation.parse));");
+ } else if (name == 'Instance') {
+ if (field.name == 'associations') {
+ // Special case `Instance.associations`.
+ gen.writeln("associations = json['associations'] == null "
+ "? null : List<MapAssociation>.from("
+ "_createSpecificObject(json['associations'], MapAssociation.parse));");
+ } else if (field.name == 'classRef') {
+ // This is populated by `Obj`
+ }
} else if (name == '_CpuProfile' && field.name == 'codes') {
// Special case `_CpuProfile.codes`.
gen.writeln("codes = List<CodeRegion>.from("
- "_createSpecificObject(json['codes'], CodeRegion.parse));");
+ "_createSpecificObject(json['codes']!, CodeRegion.parse));");
} else if (name == '_CpuProfile' && field.name == 'functions') {
// Special case `_CpuProfile.functions`.
gen.writeln("functions = List<ProfileFunction>.from("
- "_createSpecificObject(json['functions'], ProfileFunction.parse));");
+ "_createSpecificObject(json['functions']!, ProfileFunction.parse));");
} else if (name == 'SourceReport' && field.name == 'ranges') {
// Special case `SourceReport.ranges`.
gen.writeln("ranges = List<SourceReportRange>.from("
- "_createSpecificObject(json['ranges'], SourceReportRange.parse));");
+ "_createSpecificObject(json['ranges']!, SourceReportRange.parse));");
} else if (name == 'SourceReportRange' && field.name == 'coverage') {
// Special case `SourceReportRange.coverage`.
gen.writeln("coverage = _createSpecificObject("
- "json['coverage'], SourceReportCoverage.parse);");
+ "json['coverage']!, SourceReportCoverage.parse);");
} else if (name == 'Library' && field.name == 'dependencies') {
// Special case `Library.dependencies`.
gen.writeln("dependencies = List<LibraryDependency>.from("
- "_createSpecificObject(json['dependencies'], "
+ "_createSpecificObject(json['dependencies']!, "
"LibraryDependency.parse));");
} else if (name == 'Script' && field.name == 'tokenPosTable') {
// Special case `Script.tokenPosTable`.
@@ -1544,7 +1592,7 @@
if (field.optional) {
gen.write("json['tokenPosTable'] == null ? null : ");
}
- gen.writeln("List<List<int>>.from(json['tokenPosTable'].map"
+ gen.writeln("List<List<int>>.from(json['tokenPosTable']!.map"
"((dynamic list) => List<int>.from(list)));");
gen.writeln('_parseTokenPosTable();');
} else if (field.type.isArray) {
@@ -1557,7 +1605,7 @@
"List<${fieldType.listTypeArg}>.from($ref);");
} else {
gen.writeln("${field.generatableName} = $ref == null ? null : "
- "List<${fieldType.listTypeArg}>.from(createServiceObject($ref, $typesList));");
+ "List<${fieldType.listTypeArg}>.from(createServiceObject($ref, $typesList)! as List);");
}
} else {
if (fieldType.isListTypeSimple) {
@@ -1575,17 +1623,18 @@
// field named 'samples' instead of 'instances'.
if (name == 'InstanceSet') {
gen.writeln("${field.generatableName} = "
- "List<${fieldType.listTypeArg}>.from(createServiceObject($ref ?? json['samples'], $typesList));");
+ "List<${fieldType.listTypeArg}>.from(createServiceObject(($ref ?? json['samples']!) as List, $typesList)! as List);");
} else {
gen.writeln("${field.generatableName} = "
- "List<${fieldType.listTypeArg}>.from(createServiceObject($ref, $typesList) ?? []);");
+ "List<${fieldType.listTypeArg}>.from(createServiceObject($ref, $typesList) as List? ?? []);");
}
}
}
} else {
String typesList = _typeRefListToString(field.type.types);
gen.writeln("${field.generatableName} = "
- "createServiceObject(json['${field.name}'], $typesList);");
+ "createServiceObject(json['${field.name}']${field.optional ? '' : '!'}, "
+ "$typesList) as ${field.type.name}${field.optional ? '?' : ''};");
}
});
if (fields.isNotEmpty) {
@@ -1599,10 +1648,13 @@
// toJson support, the base Response type is not supported
if (name == 'Response') {
+ gen.writeln("String get type => 'Response';");
+ gen.writeln();
gen.writeln('''
Map<String, dynamic> toJson() {
- var result = json == null ? <String, dynamic>{} : Map.of(json);
- result['type'] = type ?? 'Response';
+ final localJson = json;
+ final result = localJson == null ? <String, dynamic>{} : Map<String, dynamic>.of(localJson);
+ result['type'] = type;
return result;
}''');
} else if (name == 'TimelineEvent') {
@@ -1610,7 +1662,8 @@
// fairly dynamic. Return the json directly.
gen.writeln('''
Map<String, dynamic> toJson() {
- var result = json == null ? <String, dynamic>{} : Map.of(json);
+ final localJson = json;
+ final result = localJson == null ? <String, dynamic>{} : Map<String, dynamic>.of(localJson);
result['type'] = 'TimelineEvent';
return result;
}
@@ -1618,19 +1671,25 @@
} else {
if (isResponse) {
gen.writeln('@override');
+ gen.writeln("String get type => '$name';");
+ gen.writeln();
+ }
+
+ if (isResponse) {
+ gen.writeln('@override');
}
gen.writeln('Map<String, dynamic> toJson() {');
if (superName == null || superName == 'Response') {
// The base Response type doesn't have a toJson
- gen.writeln('var json = <String, dynamic>{};');
+ gen.writeln('final json = <String, dynamic>{};');
} else {
- gen.writeln('var json = super.toJson();');
+ gen.writeln('final json = super.toJson();');
}
// Only Response objects have a `type` field, as defined by protocol.
if (isResponse) {
// Overwrites "type" from the super class if we had one.
- gen.writeln("json['type'] = '$rawName';");
+ gen.writeln("json['type'] = type;");
}
var requiredFields = fields.where((f) => !f.optional);
@@ -1682,7 +1741,8 @@
}
gen.writeln("String toString() => '[${name} ' //\n'${properties}]';");
} else {
- gen.writeln("String toString() => '[${name} ${properties}]';");
+ final formattedProperties = (properties.isEmpty) ? '' : ' $properties';
+ gen.writeln("String toString() => '[$name$formattedProperties]';");
}
} else {
gen.writeln("String toString() => '[${name}]';");
@@ -1696,20 +1756,21 @@
gen.writeDocs('''This function maps a token position to a line number.
The VM considers the first line to be line 1.''');
gen.writeln(
- 'int getLineNumberFromTokenPos(int tokenPos) => _tokenToLine[tokenPos];');
+ 'int? getLineNumberFromTokenPos(int tokenPos) => _tokenToLine[tokenPos];');
gen.writeln();
gen.writeDocs('''This function maps a token position to a column number.
The VM considers the first column to be column 1.''');
gen.writeln(
- 'int getColumnNumberFromTokenPos(int tokenPos) => _tokenToColumn[tokenPos];');
+ 'int? getColumnNumberFromTokenPos(int tokenPos) => _tokenToColumn[tokenPos];');
gen.writeln();
gen.writeln('''
void _parseTokenPosTable() {
- if (tokenPosTable == null) {
+ final tokenPositionTable = tokenPosTable;
+ if (tokenPositionTable == null) {
return;
}
- final lineSet = Set<int>();
- for (List line in tokenPosTable) {
+ final lineSet = <int>{};
+ for (List line in tokenPositionTable) {
// Each entry begins with a line number...
int lineNumber = line[0];
lineSet.add(lineNumber);
@@ -1739,11 +1800,11 @@
gen.write('${field.generatableName}$nullAware.map((f) => f');
// Special case `tokenPosTable` which is a List<List<int>>.
if (field.name == 'tokenPosTable') {
- gen.write('$nullAware.toList()');
+ gen.write('.toList()');
} else if (!field.type.types.first.isListTypeSimple) {
- gen.write('$nullAware.toJson()');
+ gen.write('.toJson()');
}
- gen.write(')$nullAware.toList()');
+ gen.write(').toList()');
} else {
gen.write('${field.generatableName}$nullAware.toJson()');
}
@@ -1759,8 +1820,8 @@
TypeRef arrayType = type.types.first;
if (arrayType.arrayDepth == 1) {
String assertMethodName = 'assertListOf' +
- arrayType.name.substring(0, 1).toUpperCase() +
- arrayType.name.substring(1);
+ arrayType.name!.substring(0, 1).toUpperCase() +
+ arrayType.name!.substring(1);
gen.writeln('$assertMethodName(obj.${field.generatableName});');
} else {
gen.writeln(
@@ -1774,8 +1835,8 @@
gen.writeln(
'if (obj.${field.generatableName} is vms.${typeRef.name}) {');
String assertMethodName = 'assert' +
- typeRef.name.substring(0, 1).toUpperCase() +
- typeRef.name.substring(1);
+ typeRef.name!.substring(0, 1).toUpperCase() +
+ typeRef.name!.substring(1);
gen.writeln('$assertMethodName(obj.${field.generatableName});');
}
gen.writeln('} else {');
@@ -1784,8 +1845,8 @@
gen.writeln('}');
} else {
String assertMethodName = 'assert' +
- type.name.substring(0, 1).toUpperCase() +
- type.name.substring(1);
+ type.name!.substring(0, 1).toUpperCase() +
+ type.name!.substring(1);
gen.writeln('$assertMethodName(obj.${field.generatableName});');
}
}
@@ -1806,19 +1867,19 @@
gen.writeln('');
}
- void _parse(Token token) => TypeParser(token).parseInto(this);
+ void _parse(Token? token) => TypeParser(token).parseInto(this);
void calculateFieldOverrides() {
for (TypeField field in fields.toList()) {
if (superName == null) continue;
- if (getSuper().hasField(field.name)) {
+ if (getSuper()!.hasField(field.name)) {
field.setOverrides();
}
}
}
- bool hasField(String name) {
+ bool hasField(String? name) {
if (fields.any((field) => field.name == name)) return true;
return getSuper()?.hasField(name) ?? false;
}
@@ -1836,19 +1897,19 @@
};
final Type parent;
- final String _docs;
+ final String? _docs;
MemberType type = MemberType();
- String name;
+ String? name;
bool optional = false;
- String defaultValue;
+ String? defaultValue;
bool overrides = false;
TypeField(this.parent, this._docs);
void setOverrides() => overrides = true;
- String get docs {
- String str = _docs == null ? '' : _docs;
+ String? get docs {
+ String str = _docs == null ? '' : _docs!;
if (type.isMultipleReturns) {
str += '\n\n[${generatableName}] can be one of '
'${joinLast(type.types.map((t) => '[${t}]'), ', ', ' or ')}.';
@@ -1857,26 +1918,39 @@
return str;
}
- String get generatableName {
+ String? get generatableName {
return _nameRemap[name] != null ? _nameRemap[name] : name;
}
void generate(DartGenerator gen) {
- if (docs.isNotEmpty) gen.writeDocs(docs);
+ if (docs!.isNotEmpty) gen.writeDocs(docs);
if (optional) gen.write('@optional ');
if (overrides) gen.write('@override ');
- String typeName =
- api.isEnumName(type.name) ? '/*${type.name}*/ String' : type.name;
- gen.writeStatement('${typeName} ${generatableName};');
- if (parent.fields.any((field) => field.hasDocs)) gen.writeln();
+ // Special case where Instance extends Obj, but 'classRef' is not optional
+ // for Instance although it is for Obj.
+ if (parent.name == 'Instance' && generatableName == 'classRef') {
+ gen.writeStatement('covariant late final ClassRef classRef;');
+ } else if (parent.name!.contains('NullVal') &&
+ generatableName == 'valueAsString') {
+ gen.writeStatement('covariant late final String valueAsString;');
+ } else {
+ String? typeName =
+ api.isEnumName(type.name) ? '/*${type.name}*/ String' : type.name;
+ if (optional) {
+ typeName = '$typeName?';
+ }
+ typeName = 'late final $typeName';
+ gen.writeStatement('${typeName} ${generatableName};');
+ if (parent.fields.any((field) => field.hasDocs)) gen.writeln();
+ }
}
void generateNamedParameter(DartGenerator gen, {bool fromParent = false}) {
if (!optional) {
- gen.write('@required ');
+ gen.write('required ');
}
if (fromParent) {
- String typeName =
+ String? typeName =
api.isEnumName(type.name) ? '/*${type.name}*/ String' : type.name;
gen.writeStatement('$typeName ${generatableName},');
} else {
@@ -1887,7 +1961,7 @@
class Enum extends Member {
final String name;
- final String docs;
+ final String? docs;
List<EnumValue> enums = [];
@@ -1900,7 +1974,7 @@
factory Enum.merge(Enum e1, Enum e2) {
final String name = e1.name;
final String docs = [e1.docs, e2.docs].where((e) => e != null).join('\n');
- final Map<String, EnumValue> map = <String, EnumValue>{};
+ final Map<String?, EnumValue> map = <String?, EnumValue>{};
for (EnumValue e in e2.enums.reversed) {
map[e.name] = e;
}
@@ -1930,7 +2004,7 @@
void generateAssert(DartGenerator gen) {
gen.writeln('String assert${name}(String obj) {');
List<EnumValue> sorted = enums.toList()
- ..sort((EnumValue e1, EnumValue e2) => e1.name.compareTo(e2.name));
+ ..sort((EnumValue e1, EnumValue e2) => e1.name!.compareTo(e2.name!));
for (EnumValue value in sorted) {
gen.writeln(' if (obj == "${value.name}") return obj;');
}
@@ -1939,13 +2013,13 @@
gen.writeln('');
}
- void _parse(Token token) => EnumParser(token).parseInto(this);
+ void _parse(Token? token) => EnumParser(token).parseInto(this);
}
class EnumValue extends Member {
final Enum parent;
- final String name;
- final String docs;
+ final String? name;
+ final String? docs;
EnumValue(this.parent, this.name, [this.docs]);
@@ -1996,7 +2070,7 @@
}
void visitText(Text text) {
- String t = text.text;
+ String? t = text.text;
if (_em) {
t = _coerceRefType(t);
} else if (_href) {
@@ -2039,7 +2113,7 @@
// string targetId [optional],
// string expression)
class MethodParser extends Parser {
- MethodParser(Token startToken) : super(startToken);
+ MethodParser(Token? startToken) : super(startToken);
void parseInto(Method method) {
// method is return type, name, (, args )
@@ -2053,21 +2127,21 @@
expect('(');
- while (peek().text != ')') {
+ while (peek()!.text != ')') {
Token type = expectName();
TypeRef ref = TypeRef(_coerceRefType(type.text));
- if (peek().text == '[') {
+ if (peek()!.text == '[') {
while (consume('[')) {
expect(']');
ref.arrayDepth++;
}
- } else if (peek().text == '<') {
+ } else if (peek()!.text == '<') {
// handle generics
expect('<');
ref.genericTypes = [];
- while (peek().text != '>') {
+ while (peek()!.text != '>') {
Token genericTypeName = expectName();
- ref.genericTypes.add(TypeRef(_coerceRefType(genericTypeName.text)));
+ ref.genericTypes!.add(TypeRef(_coerceRefType(genericTypeName.text)));
consume(',');
}
expect('>');
@@ -2095,7 +2169,7 @@
}
class TypeParser extends Parser {
- TypeParser(Token startToken) : super(startToken);
+ TypeParser(Token? startToken) : super(startToken);
void parseInto(Type type) {
// class ClassList extends Response {
@@ -2114,7 +2188,7 @@
expect('{');
- while (peek().text != '}') {
+ while (peek()!.text != '}') {
TypeField field = TypeField(type, collectComments());
field.type.parse(this);
field.name = expectName().text;
@@ -2137,6 +2211,8 @@
dataField.name = 'data';
dataField.optional = true;
type.fields.add(dataField);
+ } else if (type.rawName == 'Response') {
+ type.fields.removeWhere((field) => field.name == 'type');
}
expect('}');
@@ -2144,7 +2220,7 @@
}
class EnumParser extends Parser {
- EnumParser(Token startToken) : super(startToken);
+ EnumParser(Token? startToken) : super(startToken);
void parseInto(Enum e) {
// enum ErrorKind { UnhandledException, Foo, Bar }
@@ -2157,7 +2233,7 @@
while (!t.eof) {
if (consume('}')) break;
- String docs = collectComments();
+ String? docs = collectComments();
t = expectName();
consume(',');
diff --git a/pkg/vm_service/tool/dart/src_gen_dart.dart b/pkg/vm_service/tool/dart/src_gen_dart.dart
index 15cf723..e343e37 100644
--- a/pkg/vm_service/tool/dart/src_gen_dart.dart
+++ b/pkg/vm_service/tool/dart/src_gen_dart.dart
@@ -25,7 +25,7 @@
/// Write out the given dartdoc text, wrapping lines as necessary to flow
/// along the column boundary. If [preferSingle] is true, and the docs would
/// fit on a single line, use `///` dartdoc style.
- void writeDocs(String docs) {
+ void writeDocs(String? docs) {
if (docs == null) return;
docs = wrap(docs.trim(), colBoundary - _indent.length - 4);
diff --git a/pkg/vm_service/tool/generate.dart b/pkg/vm_service/tool/generate.dart
index 28dc548..bea71f8 100644
--- a/pkg/vm_service/tool/generate.dart
+++ b/pkg/vm_service/tool/generate.dart
@@ -4,6 +4,9 @@
import 'dart:io';
+// TODO(bkonyi): remove once markdown and pub_semver deps are updated to null
+// safety for the SDK.
+// ignore_for_file: import_of_legacy_library_into_null_safe
import 'package:markdown/markdown.dart';
import 'package:path/path.dart';
import 'package:pub_semver/pub_semver.dart';
@@ -132,8 +135,8 @@
if (line.startsWith(pattern)) {
found = true;
Version v = Version.parse(line.substring(pattern.length));
- String pre = v.preRelease.isEmpty ? null : v.preRelease.join('-');
- String build = v.build.isEmpty ? null : v.build.join('+');
+ String? pre = v.preRelease.isEmpty ? null : v.preRelease.join('-');
+ String? build = v.build.isEmpty ? null : v.build.join('+');
v = Version(version.major, version.minor, v.patch,
pre: pre, build: build);
return '${pattern}${v.toString()}';
diff --git a/pkg/vm_service/tool/java/generate_java.dart b/pkg/vm_service/tool/java/generate_java.dart
index 675ce5b..3a3567a 100644
--- a/pkg/vm_service/tool/java/generate_java.dart
+++ b/pkg/vm_service/tool/java/generate_java.dart
@@ -4,6 +4,9 @@
library generate_vm_service_java;
+// TODO(bkonyi): remove once markdown and pub_semver deps are updated to null
+// safety for the SDK.
+// ignore_for_file: import_of_legacy_library_into_null_safe
import 'package:markdown/markdown.dart';
import 'package:pub_semver/pub_semver.dart';
@@ -50,11 +53,11 @@
from within any {@link Consumer} method.
''';
-Api api;
+late Api api;
/// Convert documentation references
/// from spec style of [className] to javadoc style {@link className}
-String convertDocLinks(String doc) {
+String? convertDocLinks(String? doc) {
if (doc == null) return null;
var sb = StringBuffer();
int start = 0;
@@ -78,14 +81,14 @@
return sb.toString();
}
-String _coerceRefType(String typeName) {
+String? _coerceRefType(String? typeName) {
if (typeName == 'Class') typeName = 'ClassObj';
if (typeName == 'Error') typeName = 'ErrorObj';
if (typeName == 'Object') typeName = 'Obj';
if (typeName == '@Object') typeName = 'ObjRef';
if (typeName == 'Function') typeName = 'Func';
if (typeName == '@Function') typeName = 'FuncRef';
- if (typeName.startsWith('@')) typeName = typeName.substring(1) + 'Ref';
+ if (typeName!.startsWith('@')) typeName = typeName.substring(1) + 'Ref';
if (typeName == 'string') typeName = 'String';
if (typeName == 'bool') typeName = 'boolean';
if (typeName == 'num') typeName = 'BigDecimal';
@@ -94,20 +97,20 @@
}
class Api extends Member with ApiParseUtil {
- int serviceMajor;
- int serviceMinor;
- String serviceVersion;
+ int? serviceMajor;
+ int? serviceMinor;
+ String? serviceVersion;
List<Method> methods = [];
- List<Enum> enums = [];
- List<Type> types = [];
+ List<Enum?> enums = [];
+ List<Type?> types = [];
Map<String, List<String>> streamIdMap = {};
- String get docs => null;
+ String? get docs => null;
String get name => 'api';
- void addProperty(String typeName, String propertyName, {String javadoc}) {
- var t = types.firstWhere((t) => t.name == typeName);
+ void addProperty(String typeName, String propertyName, {String? javadoc}) {
+ var t = types.firstWhere((t) => t!.name == typeName)!;
for (var f in t.fields) {
if (f.name == propertyName) {
print('$typeName already has $propertyName field');
@@ -133,13 +136,13 @@
for (var m in methods) {
for (var a in m.args) {
if (a.hasDocs) continue;
- var t = types.firstWhere((Type t) => t.name == a.type.name,
+ var t = types.firstWhere((Type? t) => t!.name == a.type.name,
orElse: () => null);
if (t != null) {
a.docs = t.docs;
continue;
}
- var e = enums.firstWhere((Enum e) => e.name == a.type.name,
+ var e = enums.firstWhere((Enum? e) => e!.name == a.type.name,
orElse: () => null);
if (e != null) {
a.docs = e.docs;
@@ -234,17 +237,18 @@
m.generateConsumerInterface(gen);
}
for (var t in types) {
- t.generateElement(gen);
+ t!.generateElement(gen);
}
for (var e in enums) {
- e.generateEnum(gen);
+ e!.generateEnum(gen);
}
}
- Type getType(String name) =>
- types.firstWhere((t) => t.name == name, orElse: () => null);
+ Type? getType(String? name) =>
+ types.firstWhere((t) => t!.name == name, orElse: () => null);
- bool isEnumName(String typeName) => enums.any((Enum e) => e.name == typeName);
+ bool isEnumName(String? typeName) =>
+ enums.any((Enum? e) => e!.name == typeName);
void parse(List<Node> nodes) {
Version version = ApiParseUtil.parseVersionSemVer(nodes);
@@ -256,17 +260,17 @@
// the pre following it is the definition
// the optional p following that is the documentation
- String h3Name;
+ String? h3Name;
for (int i = 0; i < nodes.length; i++) {
Node node = nodes[i];
if (isPre(node) && h3Name != null) {
String definition = textForCode(node);
- String docs;
+ String? docs;
if (i + 1 < nodes.length && isPara(nodes[i + 1])) {
- Element p = nodes[++i];
+ Element p = nodes[++i] as Element;
docs = collapseWhitespace(TextOutputVisitor.printText(p));
}
@@ -288,18 +292,18 @@
}
}
}
- for (Type type in types) {
- type.calculateFieldOverrides();
+ for (Type? type in types) {
+ type!.calculateFieldOverrides();
}
}
void setDefaultValue(String typeName, String propertyName) {
- var type = types.firstWhere((t) => t.name == typeName);
+ var type = types.firstWhere((t) => t!.name == typeName)!;
var field = type.fields.firstWhere((f) => f.name == propertyName);
field.defaultValue = 'false';
}
- void _parse(String name, String definition, [String docs]) {
+ void _parse(String name, String definition, [String? docs]) {
name = name.trim();
definition = definition.trim();
// clean markdown introduced changes
@@ -361,7 +365,7 @@
class Enum extends Member {
final String name;
- final String docs;
+ final String? docs;
List<EnumValue> enums = [];
@@ -375,7 +379,7 @@
gen.writeType(elementTypeName, (TypeWriter writer) {
writer.javadoc = convertDocLinks(docs);
writer.isEnum = true;
- enums.sort((v1, v2) => v1.name.compareTo(v2.name));
+ enums.sort((v1, v2) => v1.name!.compareTo(v2.name!));
for (var value in enums) {
writer.addEnumValue(value.name, javadoc: value.docs);
}
@@ -386,13 +390,13 @@
});
}
- void _parse(Token token) {
+ void _parse(Token? token) {
EnumParser(token).parseInto(this);
}
}
class EnumParser extends Parser {
- EnumParser(Token startToken) : super(startToken);
+ EnumParser(Token? startToken) : super(startToken);
void parseInto(Enum e) {
// enum ErrorKind { UnhandledException, Foo, Bar }
@@ -405,7 +409,7 @@
while (!t.eof) {
if (consume('}')) break;
- String docs = collectComments();
+ String? docs = collectComments();
t = expectName();
consume(',');
@@ -416,8 +420,8 @@
class EnumValue extends Member {
final Enum parent;
- final String name;
- final String docs;
+ final String? name;
+ final String? docs;
EnumValue(this.parent, this.name, [this.docs]);
@@ -425,13 +429,13 @@
}
abstract class Member {
- String get docs => null;
+ String? get docs => null;
bool get hasDocs => docs != null;
- String get name;
+ String? get name;
- String toString() => name;
+ String toString() => name!;
}
class MemberType extends Member {
@@ -449,13 +453,13 @@
bool get isValueAndSentinel => types.length == 2 && hasSentinel;
- String get name {
+ String? get name {
if (types.isEmpty) return '';
if (types.length == 1) return types.first.ref;
return 'dynamic';
}
- TypeRef get valueType {
+ TypeRef? get valueType {
if (types.length == 1) return types.first;
if (isValueAndSentinel) {
return types.firstWhere((t) => t.name != 'Sentinel');
@@ -492,7 +496,7 @@
class Method extends Member {
final String name;
- final String docs;
+ final String? docs;
MemberType returnType = MemberType();
List<MethodArg> args = [];
@@ -502,7 +506,7 @@
}
String get consumerTypeName {
- String prefix;
+ String? prefix;
if (returnType.isMultipleReturns) {
prefix = titleCase(name);
} else {
@@ -531,13 +535,13 @@
void generateVmServiceForward(StatementWriter writer) {
var consumerName = classNameFor(consumerTypeName);
writer.addLine('if (consumer instanceof $consumerName) {');
- List<Type> types = List.from(returnType.types.map((ref) => ref.type));
+ List<Type?> types = List.from(returnType.types.map((ref) => ref.type));
for (int index = 0; index < types.length; ++index) {
- types.addAll(types[index].subtypes);
+ types.addAll(types[index]!.subtypes);
}
- types.sort((t1, t2) => t1.name.compareTo(t2.name));
+ types.sort((t1, t2) => t1!.name!.compareTo(t2!.name!));
for (var t in types) {
- var responseName = classNameFor(t.elementTypeName);
+ var responseName = classNameFor(t!.elementTypeName!);
writer.addLine(' if (responseType.equals("${t.rawName}")) {');
writer.addLine(
' (($consumerName) consumer).received(new $responseName(json));');
@@ -557,7 +561,7 @@
// }
// Update method docs
- var javadoc = StringBuffer(docs == null ? '' : docs);
+ var javadoc = StringBuffer(docs == null ? '' : docs!);
bool firstParamDoc = true;
for (var a in args) {
if (!includeOptional && a.optional) continue;
@@ -611,7 +615,7 @@
}, javadoc: javadoc.toString());
}
- void _parse(Token token) {
+ void _parse(Token? token) {
MethodParser(token).parseInto(this);
}
}
@@ -619,8 +623,8 @@
class MethodArg extends Member {
final Method parent;
final TypeRef type;
- String name;
- String docs;
+ String? name;
+ String? docs;
bool optional = false;
MethodArg(this.parent, this.type, this.name);
@@ -643,7 +647,7 @@
}
class MethodParser extends Parser {
- MethodParser(Token startToken) : super(startToken);
+ MethodParser(Token? startToken) : super(startToken);
void parseInto(Method method) {
// method is return type, name, (, args )
@@ -657,21 +661,21 @@
expect('(');
- while (peek().text != ')') {
+ while (peek()!.text != ')') {
Token type = expectName();
TypeRef ref = TypeRef(_coerceRefType(type.text));
- if (peek().text == '[') {
+ if (peek()!.text == '[') {
while (consume('[')) {
expect(']');
ref.arrayDepth++;
}
- } else if (peek().text == '<') {
+ } else if (peek()!.text == '<') {
// handle generics
expect('<');
ref.genericTypes = [];
- while (peek().text != '>') {
+ while (peek()!.text != '>') {
Token genericTypeName = expectName();
- ref.genericTypes.add(TypeRef(_coerceRefType(genericTypeName.text)));
+ ref.genericTypes!.add(TypeRef(_coerceRefType(genericTypeName.text)));
consume(',');
}
expect('>');
@@ -719,7 +723,7 @@
}
void visitText(Text text) {
- String t = text.text;
+ String? t = text.text;
if (_inRef) t = _coerceRefType(t);
buf.write(t);
}
@@ -742,27 +746,27 @@
class Type extends Member {
final Api parent;
- String rawName;
- String name;
- String superName;
- final String docs;
+ String? rawName;
+ String? name;
+ String? superName;
+ final String? docs;
List<TypeField> fields = [];
Type(this.parent, String categoryName, String definition, [this.docs]) {
_parse(Tokenizer(definition).tokenize());
}
- String get elementTypeName {
+ String? get elementTypeName {
if (isSimple) return null;
return '$servicePackage.element.$name';
}
- bool get isRef => name.endsWith('Ref');
+ bool get isRef => name!.endsWith('Ref');
bool get isResponse {
if (superName == null) return false;
if (name == 'Response' || superName == 'Response') return true;
- return parent.getType(superName).isResponse;
+ return parent.getType(superName)!.isResponse;
}
bool get isSimple => simpleTypes.contains(name);
@@ -773,8 +777,8 @@
return name;
}
- Iterable<Type> get subtypes =>
- api.types.toList()..retainWhere((t) => t.superName == name);
+ Iterable<Type?> get subtypes =>
+ api.types.toList()..retainWhere((t) => t!.superName == name);
void generateElement(JavaGenerator gen) {
gen.writeType('$servicePackage.element.$name', (TypeWriter writer) {
@@ -814,7 +818,7 @@
List<TypeField> all = [];
all.insertAll(0, fields);
- Type s = getSuper();
+ Type? s = getSuper();
while (s != null) {
all.insertAll(0, s.fields);
s = s.getSuper();
@@ -823,14 +827,14 @@
return all;
}
- Type getSuper() => superName == null ? null : api.getType(superName);
+ Type? getSuper() => superName == null ? null : api.getType(superName);
- bool hasField(String name) {
+ bool hasField(String? name) {
if (fields.any((field) => field.name == name)) return true;
return getSuper()?.hasField(name) ?? false;
}
- void _parse(Token token) {
+ void _parse(Token? token) {
TypeParser(token).parseInto(this);
}
@@ -838,7 +842,7 @@
for (TypeField field in fields.toList()) {
if (superName == null) continue;
- if (getSuper().hasField(field.name)) {
+ if (getSuper()!.hasField(field.name)) {
field.setOverrides();
}
}
@@ -860,11 +864,11 @@
};
final Type parent;
- final String _docs;
+ final String? _docs;
MemberType type = MemberType();
- String name;
+ String? name;
bool optional = false;
- String defaultValue;
+ String? defaultValue;
bool overrides = false;
TypeField(this.parent, this._docs);
@@ -880,11 +884,11 @@
} else {
remappedName = name;
}
- return 'get${titleCase(remappedName)}';
+ return 'get${titleCase(remappedName!)}';
}
- String get docs {
- String str = _docs == null ? '' : _docs;
+ String? get docs {
+ String str = _docs == null ? '' : _docs!;
if (type.isMultipleReturns) {
str += '\n\n@return one of '
'${joinLast(type.types.map((t) => '<code>${t}</code>'), ', ', ' or ')}';
@@ -904,7 +908,7 @@
w.addLine('final JsonObject elem = (JsonObject)json.get("$name");');
w.addLine('if (elem == null) return null;\n');
for (TypeRef t in type.types) {
- String refName = t.name;
+ String refName = t.name!;
if (refName.endsWith('Ref')) {
refName = "@" + refName.substring(0, refName.length - 3);
}
@@ -914,7 +918,7 @@
w.addLine('return null;');
}, javadoc: docs, returnType: 'Object');
} else {
- String returnType = type.valueType.ref;
+ String? returnType = type.valueType!.ref;
if (name == 'timestamp') {
returnType = 'long';
}
@@ -923,7 +927,7 @@
accessorName,
[],
(StatementWriter writer) {
- type.valueType.generateAccessStatements(
+ type.valueType!.generateAccessStatements(
writer,
name,
canBeSentinel: type.isValueAndSentinel,
@@ -940,7 +944,7 @@
}
class TypeParser extends Parser {
- TypeParser(Token startToken) : super(startToken);
+ TypeParser(Token? startToken) : super(startToken);
void parseInto(Type type) {
// class ClassList extends Response {
@@ -959,7 +963,7 @@
expect('{');
- while (peek().text != '}') {
+ while (peek()!.text != '}') {
TypeField field = TypeField(type, collectComments());
field.type.parse(this);
field.name = expectName().text;
@@ -977,13 +981,13 @@
}
class TypeRef {
- String name;
+ String? name;
int arrayDepth = 0;
- List<TypeRef> genericTypes;
+ List<TypeRef>? genericTypes;
TypeRef(this.name);
- String get elementTypeName {
+ String? get elementTypeName {
if (isSimple) return null;
return '$servicePackage.element.$name';
}
@@ -991,20 +995,20 @@
bool get isArray => arrayDepth > 0;
/// Hacked enum determination
- bool get isEnum => name.endsWith('Kind') || name.endsWith('Mode');
+ bool get isEnum => name!.endsWith('Kind') || name!.endsWith('Mode');
bool get isSimple => simpleTypes.contains(name);
- String get javaBoxedName {
+ String? get javaBoxedName {
if (name == 'boolean') return 'Boolean';
if (name == 'int') return 'Integer';
if (name == 'double') return 'Double';
return name;
}
- String get ref {
+ String? get ref {
if (genericTypes != null) {
- return '$name<${genericTypes.join(', ')}>';
+ return '$name<${genericTypes!.join(', ')}>';
} else if (isSimple) {
if (arrayDepth == 2) return 'List<List<${javaBoxedName}>>';
if (arrayDepth == 1) return 'List<${javaBoxedName}>';
@@ -1015,13 +1019,13 @@
return name;
}
- Type get type => api.types.firstWhere((t) => t.name == name);
+ Type? get type => api.types.firstWhere((t) => t!.name == name);
void generateAccessStatements(
StatementWriter writer,
- String propertyName, {
+ String? propertyName, {
bool canBeSentinel = false,
- String defaultValue,
+ String? defaultValue,
bool optional = false,
}) {
if (name == 'boolean') {
@@ -1144,5 +1148,5 @@
}
}
- String toString() => ref;
+ String toString() => ref!;
}
diff --git a/pkg/vm_service/tool/java/src_gen_java.dart b/pkg/vm_service/tool/java/src_gen_java.dart
index 91b71e2..b67c203 100644
--- a/pkg/vm_service/tool/java/src_gen_java.dart
+++ b/pkg/vm_service/tool/java/src_gen_java.dart
@@ -15,7 +15,7 @@
int colBoundary = 100;
/// The header for every generated file.
-String fileHeader;
+String? fileHeader;
String classNameFor(String typeName) {
// Convert ElementList<Foo> param declarations to List<Foo> declarations.
@@ -71,8 +71,8 @@
}
class JavaMethodArg {
- final String name;
- final String typeName;
+ final String? name;
+ final String? typeName;
JavaMethodArg(this.name, this.typeName);
}
@@ -115,10 +115,10 @@
final String className;
bool isInterface = false;
bool isEnum = false;
- String javadoc;
+ String? javadoc;
String modifiers = 'public';
final Set<String> _imports = Set<String>();
- String superclassName;
+ String? superclassName;
List<String> interfaceNames = <String>[];
final StringBuffer _content = StringBuffer();
final List<String> _fields = <String>[];
@@ -135,7 +135,7 @@
}
void addConstructor(Iterable<JavaMethodArg> args, WriteStatements write,
- {String javadoc, String modifiers = 'public'}) {
+ {String? javadoc, String modifiers = 'public'}) {
_content.writeln();
if (javadoc != null && javadoc.isNotEmpty) {
_content.writeln(' /**');
@@ -146,22 +146,18 @@
}
_content.write(' $modifiers $className(');
_content.write(
- args.map((a) => '${classNameFor(a.typeName)} ${a.name}').join(', '));
+ args.map((a) => '${classNameFor(a.typeName!)} ${a.name}').join(', '));
_content.write(')');
- if (write != null) {
- _content.writeln(' {');
- StatementWriter writer = StatementWriter(this);
- write(writer);
- _content.write(writer.toSource());
- _content.writeln(' }');
- } else {
- _content.writeln(';');
- }
+ _content.writeln(' {');
+ StatementWriter writer = StatementWriter(this);
+ write(writer);
+ _content.write(writer.toSource());
+ _content.writeln(' }');
}
void addEnumValue(
- String name, {
- String javadoc,
+ String? name, {
+ String? javadoc,
bool isLast = false,
}) {
_content.writeln();
@@ -181,7 +177,7 @@
}
void addField(String name, String typeName,
- {String modifiers = 'public', String value, String javadoc}) {
+ {String modifiers = 'public', String? value, String? javadoc}) {
var fieldDecl = StringBuffer();
if (javadoc != null && javadoc.isNotEmpty) {
fieldDecl.writeln(' /**');
@@ -191,7 +187,7 @@
fieldDecl.writeln(' */');
}
fieldDecl.write(' ');
- if (modifiers != null && modifiers.isNotEmpty) {
+ if (modifiers.isNotEmpty) {
fieldDecl.write('$modifiers ');
}
fieldDecl.write('$typeName $name');
@@ -202,7 +198,7 @@
_fields.add(fieldDecl.toString());
}
- void addImport(String typeName) {
+ void addImport(String? typeName) {
if (typeName == null || typeName.isEmpty) return;
var pkgName = pkgNameFor(typeName);
if (pkgName.isNotEmpty && pkgName != this.pkgName) {
@@ -213,10 +209,10 @@
void addMethod(
String name,
Iterable<JavaMethodArg> args,
- WriteStatements write, {
- String javadoc,
- String modifiers = 'public',
- String returnType = 'void',
+ WriteStatements? write, {
+ String? javadoc,
+ String? modifiers = 'public',
+ String? returnType = 'void',
bool isOverride = false,
}) {
var methodDecl = StringBuffer();
@@ -238,7 +234,8 @@
}
methodDecl.write('$returnType $name(');
methodDecl.write(args
- .map((JavaMethodArg arg) => '${classNameFor(arg.typeName)} ${arg.name}')
+ .map(
+ (JavaMethodArg arg) => '${classNameFor(arg.typeName!)} ${arg.name}')
.join(', '));
methodDecl.write(')');
if (write != null) {
@@ -260,10 +257,8 @@
String toSource() {
var buffer = StringBuffer();
if (fileHeader != null) buffer.write(fileHeader);
- if (pkgName != null) {
- buffer.writeln('package $pkgName;');
- buffer.writeln();
- }
+ buffer.writeln('package $pkgName;');
+ buffer.writeln();
buffer.writeln('// This is a generated file.');
buffer.writeln();
addImport(superclassName);
@@ -275,9 +270,9 @@
}
buffer.writeln();
}
- if (javadoc != null && javadoc.isNotEmpty) {
+ if (javadoc != null && javadoc!.isNotEmpty) {
buffer.writeln('/**');
- wrap(javadoc.trim(), colBoundary - 4)
+ wrap(javadoc!.trim(), colBoundary - 4)
.split('\n')
.forEach((line) => buffer.writeln(' * $line'));
buffer.writeln(' */');
@@ -287,7 +282,7 @@
buffer.write('$modifiers $kind $className');
if (superclassName != null) {
- buffer.write(' extends ${classNameFor(superclassName)}');
+ buffer.write(' extends ${classNameFor(superclassName!)}');
}
if (interfaceNames.isNotEmpty) {
var classNames = interfaceNames.map((t) => classNameFor(t));
diff --git a/runtime/tests/vm/dart/regress_42067_test.dart b/runtime/tests/vm/dart/regress_42067_test.dart
new file mode 100644
index 0000000..21f87c8
--- /dev/null
+++ b/runtime/tests/vm/dart/regress_42067_test.dart
@@ -0,0 +1,47 @@
+// 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.
+
+// VMOptions=--deterministic --optimization_counter_threshold=100
+
+// Verifies correct code is generated for Float64x2.fromFloat32x4 in case of
+// high register pressure.
+// Regression test for https://github.com/dart-lang/sdk/issues/42067.
+
+import 'dart:typed_data';
+
+import 'package:expect/expect.dart';
+
+@pragma('vm:never-inline')
+doTest(double x) {
+ Float32x4 a0 = Float32x4.splat(x + 1);
+ Float32x4 a1 = Float32x4.splat(x + 2);
+ Float32x4 a2 = Float32x4.splat(x + 3);
+ Float32x4 a3 = Float32x4.splat(x + 4);
+ Float32x4 a4 = Float32x4.splat(x + 5);
+ Float32x4 a5 = Float32x4.splat(x + 6);
+ Float32x4 a6 = Float32x4.splat(x + 7);
+ Float32x4 a7 = Float32x4.splat(x + 8);
+ return Float64x2.fromFloat32x4(a0) +
+ Float64x2.fromFloat32x4(a1) +
+ Float64x2.fromFloat32x4(a2) +
+ Float64x2.fromFloat32x4(a3) +
+ Float64x2.fromFloat32x4(a4) +
+ Float64x2.fromFloat32x4(a5) +
+ Float64x2.fromFloat32x4(a6) +
+ Float64x2.fromFloat32x4(a7) +
+ Float64x2.fromFloat32x4(a0) +
+ Float64x2.fromFloat32x4(a1) +
+ Float64x2.fromFloat32x4(a2) +
+ Float64x2.fromFloat32x4(a3) +
+ Float64x2.fromFloat32x4(a4) +
+ Float64x2.fromFloat32x4(a5) +
+ Float64x2.fromFloat32x4(a6) +
+ Float64x2.fromFloat32x4(a7);
+}
+
+void main() {
+ for (int i = 0; i < 200; ++i) {
+ Expect.approxEquals(88.0, doTest(1.0).x);
+ }
+}
diff --git a/runtime/tests/vm/dart/split_literals.dart b/runtime/tests/vm/dart/split_literals.dart
new file mode 100644
index 0000000..b71e9bd
--- /dev/null
+++ b/runtime/tests/vm/dart/split_literals.dart
@@ -0,0 +1,21 @@
+// 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 "split_literals_deferred.dart" deferred as lib;
+
+class Box {
+ final contents;
+ const Box(this.contents);
+ String toString() => "Box($contents)";
+}
+
+main() async {
+ print("Root literal!");
+ print(const <String>["Root literal in a list!"]);
+ print(const <String, String>{"key": "Root literal in a map!"});
+ print(const Box("Root literal in a box!"));
+
+ await lib.loadLibrary();
+ lib.foo();
+}
diff --git a/runtime/tests/vm/dart/split_literals_deferred.dart b/runtime/tests/vm/dart/split_literals_deferred.dart
new file mode 100644
index 0000000..015ae1d
--- /dev/null
+++ b/runtime/tests/vm/dart/split_literals_deferred.dart
@@ -0,0 +1,12 @@
+// 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 "split_literals.dart";
+
+void foo() {
+ print("Deferred literal!");
+ print(const <String>["Deferred literal in a list!"]);
+ print(const <String, String>{"key": "Deferred literal in a map!"});
+ print(const Box("Deferred literal in a box!"));
+}
diff --git a/runtime/tests/vm/dart/split_literals_test.dart b/runtime/tests/vm/dart/split_literals_test.dart
new file mode 100644
index 0000000..40ecf01
--- /dev/null
+++ b/runtime/tests/vm/dart/split_literals_test.dart
@@ -0,0 +1,114 @@
+// 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 "dart:convert";
+import "dart:io";
+
+import "package:expect/expect.dart";
+import "package:path/path.dart" as path;
+
+import "use_flag_test_helper.dart";
+
+main(List<String> args) async {
+ if (!isAOTRuntime) {
+ return; // Running in JIT: AOT binaries not available.
+ }
+
+ if (Platform.isAndroid) {
+ return; // SDK tree not available on the test device.
+ }
+
+ // These are the tools we need to be available to run on a given platform:
+ if (!File(platformDill).existsSync()) {
+ throw "Cannot run test as $platformDill does not exist";
+ }
+ if (!await testExecutable(genSnapshot)) {
+ throw "Cannot run test as $genSnapshot not available";
+ }
+
+ sanitizedPartitioning(manifest) {
+ // Filter core libraries, relativize URIs, and sort to make the results less
+ // sensitive to compiler or test harness changes.
+ print(manifest);
+ var units = <List<String>>[];
+ for (var unit in manifest['loadingUnits']) {
+ var uris = <String>[];
+ for (var uri in unit['libraries']) {
+ if (uri.startsWith("dart:")) continue;
+ uris.add(Uri.parse(uri).pathSegments.last);
+ }
+ uris.sort((a, b) => a.compareTo(b));
+ units.add(uris);
+ }
+ units.sort((a, b) => a.first.compareTo(b.first));
+ print(units);
+ return units;
+ }
+
+ await withTempDir("split-literals-test", (String tempDir) async {
+ final source =
+ path.join(sdkDir, "runtime/tests/vm/dart_2/split_literals.dart");
+ final dill = path.join(tempDir, "split_literals.dart.dill");
+ final snapshot = path.join(tempDir, "split_literals.so");
+ final manifest = path.join(tempDir, "split_literals.txt");
+ final deferredSnapshot = snapshot + "-2.part.so";
+
+ // Compile source to kernel.
+ await run(genKernel, <String>[
+ "--aot",
+ "--platform=$platformDill",
+ "-o",
+ dill,
+ source,
+ ]);
+
+ // Compile kernel to ELF.
+ await run(genSnapshot, <String>[
+ "--use_bare_instructions=false",
+ "--snapshot-kind=app-aot-elf",
+ "--elf=$snapshot",
+ "--loading-unit-manifest=$manifest",
+ dill,
+ ]);
+ var manifestContent = jsonDecode(await new File(manifest).readAsString());
+ Expect.equals(2, manifestContent["loadingUnits"].length);
+ // Note package:expect doesn't do deep equals on collections.
+ Expect.equals(
+ "[[split_literals.dart],"
+ " [split_literals_deferred.dart]]",
+ sanitizedPartitioning(manifestContent).toString());
+ Expect.isTrue(await new File(deferredSnapshot).exists());
+
+ bool containsSubsequence(haystack, needle) {
+ outer:
+ for (var i = 0, n = haystack.length - needle.length; i < n; i++) {
+ for (var j = 0; j < needle.length; j++) {
+ if (haystack[i + j] != needle.codeUnitAt(j)) continue outer;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ var unit_1 = await new File(snapshot).readAsBytes();
+ Expect.isTrue(containsSubsequence(unit_1, "Root literal!"));
+ Expect.isTrue(containsSubsequence(unit_1, "Root literal in a list!"));
+ Expect.isTrue(containsSubsequence(unit_1, "Root literal in a map!"));
+ Expect.isTrue(containsSubsequence(unit_1, "Root literal in a box!"));
+ Expect.isTrue(!containsSubsequence(unit_1, "Deferred literal!"));
+ Expect.isTrue(!containsSubsequence(unit_1, "Deferred literal in a list!"));
+ Expect.isTrue(!containsSubsequence(unit_1, "Deferred literal in a map!"));
+ Expect.isTrue(!containsSubsequence(unit_1, "Deferred literal in a box!"));
+
+ var unit_2 = await new File(deferredSnapshot).readAsBytes();
+ Expect.isTrue(!containsSubsequence(unit_2, "Root literal!"));
+ Expect.isTrue(!containsSubsequence(unit_2, "Root literal in a list!"));
+ Expect.isTrue(!containsSubsequence(unit_2, "Root literal in a map!"));
+ Expect.isTrue(!containsSubsequence(unit_2, "Root literal in a box!"));
+ Expect.isTrue(containsSubsequence(unit_2, "Deferred literal!"));
+ Expect.isTrue(containsSubsequence(unit_2, "Deferred literal in a list!"));
+ Expect.isTrue(containsSubsequence(unit_2, "Deferred literal in a map!"));
+ Expect.isTrue(containsSubsequence(unit_2, "Deferred literal in a box!"));
+ });
+}
diff --git a/runtime/tests/vm/dart_2/regress_42067_test.dart b/runtime/tests/vm/dart_2/regress_42067_test.dart
new file mode 100644
index 0000000..21f87c8
--- /dev/null
+++ b/runtime/tests/vm/dart_2/regress_42067_test.dart
@@ -0,0 +1,47 @@
+// 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.
+
+// VMOptions=--deterministic --optimization_counter_threshold=100
+
+// Verifies correct code is generated for Float64x2.fromFloat32x4 in case of
+// high register pressure.
+// Regression test for https://github.com/dart-lang/sdk/issues/42067.
+
+import 'dart:typed_data';
+
+import 'package:expect/expect.dart';
+
+@pragma('vm:never-inline')
+doTest(double x) {
+ Float32x4 a0 = Float32x4.splat(x + 1);
+ Float32x4 a1 = Float32x4.splat(x + 2);
+ Float32x4 a2 = Float32x4.splat(x + 3);
+ Float32x4 a3 = Float32x4.splat(x + 4);
+ Float32x4 a4 = Float32x4.splat(x + 5);
+ Float32x4 a5 = Float32x4.splat(x + 6);
+ Float32x4 a6 = Float32x4.splat(x + 7);
+ Float32x4 a7 = Float32x4.splat(x + 8);
+ return Float64x2.fromFloat32x4(a0) +
+ Float64x2.fromFloat32x4(a1) +
+ Float64x2.fromFloat32x4(a2) +
+ Float64x2.fromFloat32x4(a3) +
+ Float64x2.fromFloat32x4(a4) +
+ Float64x2.fromFloat32x4(a5) +
+ Float64x2.fromFloat32x4(a6) +
+ Float64x2.fromFloat32x4(a7) +
+ Float64x2.fromFloat32x4(a0) +
+ Float64x2.fromFloat32x4(a1) +
+ Float64x2.fromFloat32x4(a2) +
+ Float64x2.fromFloat32x4(a3) +
+ Float64x2.fromFloat32x4(a4) +
+ Float64x2.fromFloat32x4(a5) +
+ Float64x2.fromFloat32x4(a6) +
+ Float64x2.fromFloat32x4(a7);
+}
+
+void main() {
+ for (int i = 0; i < 200; ++i) {
+ Expect.approxEquals(88.0, doTest(1.0).x);
+ }
+}
diff --git a/runtime/tests/vm/dart_2/split_literals.dart b/runtime/tests/vm/dart_2/split_literals.dart
new file mode 100644
index 0000000..b71e9bd
--- /dev/null
+++ b/runtime/tests/vm/dart_2/split_literals.dart
@@ -0,0 +1,21 @@
+// 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 "split_literals_deferred.dart" deferred as lib;
+
+class Box {
+ final contents;
+ const Box(this.contents);
+ String toString() => "Box($contents)";
+}
+
+main() async {
+ print("Root literal!");
+ print(const <String>["Root literal in a list!"]);
+ print(const <String, String>{"key": "Root literal in a map!"});
+ print(const Box("Root literal in a box!"));
+
+ await lib.loadLibrary();
+ lib.foo();
+}
diff --git a/runtime/tests/vm/dart_2/split_literals_deferred.dart b/runtime/tests/vm/dart_2/split_literals_deferred.dart
new file mode 100644
index 0000000..015ae1d
--- /dev/null
+++ b/runtime/tests/vm/dart_2/split_literals_deferred.dart
@@ -0,0 +1,12 @@
+// 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 "split_literals.dart";
+
+void foo() {
+ print("Deferred literal!");
+ print(const <String>["Deferred literal in a list!"]);
+ print(const <String, String>{"key": "Deferred literal in a map!"});
+ print(const Box("Deferred literal in a box!"));
+}
diff --git a/runtime/tests/vm/dart_2/split_literals_test.dart b/runtime/tests/vm/dart_2/split_literals_test.dart
new file mode 100644
index 0000000..40ecf01
--- /dev/null
+++ b/runtime/tests/vm/dart_2/split_literals_test.dart
@@ -0,0 +1,114 @@
+// 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 "dart:convert";
+import "dart:io";
+
+import "package:expect/expect.dart";
+import "package:path/path.dart" as path;
+
+import "use_flag_test_helper.dart";
+
+main(List<String> args) async {
+ if (!isAOTRuntime) {
+ return; // Running in JIT: AOT binaries not available.
+ }
+
+ if (Platform.isAndroid) {
+ return; // SDK tree not available on the test device.
+ }
+
+ // These are the tools we need to be available to run on a given platform:
+ if (!File(platformDill).existsSync()) {
+ throw "Cannot run test as $platformDill does not exist";
+ }
+ if (!await testExecutable(genSnapshot)) {
+ throw "Cannot run test as $genSnapshot not available";
+ }
+
+ sanitizedPartitioning(manifest) {
+ // Filter core libraries, relativize URIs, and sort to make the results less
+ // sensitive to compiler or test harness changes.
+ print(manifest);
+ var units = <List<String>>[];
+ for (var unit in manifest['loadingUnits']) {
+ var uris = <String>[];
+ for (var uri in unit['libraries']) {
+ if (uri.startsWith("dart:")) continue;
+ uris.add(Uri.parse(uri).pathSegments.last);
+ }
+ uris.sort((a, b) => a.compareTo(b));
+ units.add(uris);
+ }
+ units.sort((a, b) => a.first.compareTo(b.first));
+ print(units);
+ return units;
+ }
+
+ await withTempDir("split-literals-test", (String tempDir) async {
+ final source =
+ path.join(sdkDir, "runtime/tests/vm/dart_2/split_literals.dart");
+ final dill = path.join(tempDir, "split_literals.dart.dill");
+ final snapshot = path.join(tempDir, "split_literals.so");
+ final manifest = path.join(tempDir, "split_literals.txt");
+ final deferredSnapshot = snapshot + "-2.part.so";
+
+ // Compile source to kernel.
+ await run(genKernel, <String>[
+ "--aot",
+ "--platform=$platformDill",
+ "-o",
+ dill,
+ source,
+ ]);
+
+ // Compile kernel to ELF.
+ await run(genSnapshot, <String>[
+ "--use_bare_instructions=false",
+ "--snapshot-kind=app-aot-elf",
+ "--elf=$snapshot",
+ "--loading-unit-manifest=$manifest",
+ dill,
+ ]);
+ var manifestContent = jsonDecode(await new File(manifest).readAsString());
+ Expect.equals(2, manifestContent["loadingUnits"].length);
+ // Note package:expect doesn't do deep equals on collections.
+ Expect.equals(
+ "[[split_literals.dart],"
+ " [split_literals_deferred.dart]]",
+ sanitizedPartitioning(manifestContent).toString());
+ Expect.isTrue(await new File(deferredSnapshot).exists());
+
+ bool containsSubsequence(haystack, needle) {
+ outer:
+ for (var i = 0, n = haystack.length - needle.length; i < n; i++) {
+ for (var j = 0; j < needle.length; j++) {
+ if (haystack[i + j] != needle.codeUnitAt(j)) continue outer;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ var unit_1 = await new File(snapshot).readAsBytes();
+ Expect.isTrue(containsSubsequence(unit_1, "Root literal!"));
+ Expect.isTrue(containsSubsequence(unit_1, "Root literal in a list!"));
+ Expect.isTrue(containsSubsequence(unit_1, "Root literal in a map!"));
+ Expect.isTrue(containsSubsequence(unit_1, "Root literal in a box!"));
+ Expect.isTrue(!containsSubsequence(unit_1, "Deferred literal!"));
+ Expect.isTrue(!containsSubsequence(unit_1, "Deferred literal in a list!"));
+ Expect.isTrue(!containsSubsequence(unit_1, "Deferred literal in a map!"));
+ Expect.isTrue(!containsSubsequence(unit_1, "Deferred literal in a box!"));
+
+ var unit_2 = await new File(deferredSnapshot).readAsBytes();
+ Expect.isTrue(!containsSubsequence(unit_2, "Root literal!"));
+ Expect.isTrue(!containsSubsequence(unit_2, "Root literal in a list!"));
+ Expect.isTrue(!containsSubsequence(unit_2, "Root literal in a map!"));
+ Expect.isTrue(!containsSubsequence(unit_2, "Root literal in a box!"));
+ Expect.isTrue(containsSubsequence(unit_2, "Deferred literal!"));
+ Expect.isTrue(containsSubsequence(unit_2, "Deferred literal in a list!"));
+ Expect.isTrue(containsSubsequence(unit_2, "Deferred literal in a map!"));
+ Expect.isTrue(containsSubsequence(unit_2, "Deferred literal in a box!"));
+ });
+}
diff --git a/runtime/vm/clustered_snapshot.cc b/runtime/vm/clustered_snapshot.cc
index ac7df11..d8c12f3 100644
--- a/runtime/vm/clustered_snapshot.cc
+++ b/runtime/vm/clustered_snapshot.cc
@@ -289,7 +289,7 @@
ClassDeserializationCluster() : DeserializationCluster("Class") {}
~ClassDeserializationCluster() {}
- void ReadAlloc(Deserializer* d, bool is_canonical) {
+ void ReadAlloc(Deserializer* d, bool stamp_canonical) {
predefined_start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
intptr_t count = d->ReadUnsigned();
@@ -311,7 +311,7 @@
stop_index_ = d->next_index();
}
- void ReadFill(Deserializer* d, bool is_canonical) {
+ void ReadFill(Deserializer* d, bool stamp_canonical) {
ClassTable* table = d->isolate_group()->class_table();
for (intptr_t id = predefined_start_index_; id < predefined_stop_index_;
@@ -464,7 +464,7 @@
: DeserializationCluster("TypeArguments") {}
~TypeArgumentsDeserializationCluster() {}
- void ReadAlloc(Deserializer* d, bool is_canonical) {
+ void ReadAlloc(Deserializer* d, bool stamp_canonical) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
const intptr_t count = d->ReadUnsigned();
@@ -476,13 +476,13 @@
stop_index_ = d->next_index();
}
- void ReadFill(Deserializer* d, bool is_canonical) {
+ void ReadFill(Deserializer* d, bool stamp_canonical) {
for (intptr_t id = start_index_; id < stop_index_; id++) {
TypeArgumentsPtr type_args = static_cast<TypeArgumentsPtr>(d->Ref(id));
const intptr_t length = d->ReadUnsigned();
Deserializer::InitializeHeader(type_args, kTypeArgumentsCid,
TypeArguments::InstanceSize(length),
- is_canonical);
+ stamp_canonical);
type_args->ptr()->length_ = Smi::New(length);
type_args->ptr()->hash_ = Smi::New(d->Read<int32_t>());
type_args->ptr()->nullability_ = Smi::New(d->ReadUnsigned());
@@ -494,22 +494,15 @@
}
}
- void PostLoad(Deserializer* d, const Array& refs, bool is_canonical) {
- if (is_canonical && (d->isolate() != Dart::vm_isolate())) {
- CanonicalTypeArgumentsSet table(
- d->zone(),
- d->isolate_group()->object_store()->canonical_type_arguments());
+ void PostLoad(Deserializer* d, const Array& refs, bool canonicalize) {
+ if (canonicalize) {
+ Thread* thread = Thread::Current();
TypeArguments& type_arg = TypeArguments::Handle(d->zone());
for (intptr_t i = start_index_; i < stop_index_; i++) {
type_arg ^= refs.At(i);
- ASSERT(type_arg.IsCanonical());
- bool present = table.Insert(type_arg);
- // Two recursive types with different topology (and hashes) may be
- // equal.
- ASSERT(!present || type_arg.IsRecursive());
+ type_arg = type_arg.Canonicalize(thread, nullptr);
+ refs.SetAt(i, type_arg);
}
- d->isolate_group()->object_store()->set_canonical_type_arguments(
- table.Release());
}
}
};
@@ -558,7 +551,7 @@
PatchClassDeserializationCluster() : DeserializationCluster("PatchClass") {}
~PatchClassDeserializationCluster() {}
- void ReadAlloc(Deserializer* d, bool is_canonical) {
+ void ReadAlloc(Deserializer* d, bool stamp_canonical) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
const intptr_t count = d->ReadUnsigned();
@@ -569,7 +562,8 @@
stop_index_ = d->next_index();
}
- void ReadFill(Deserializer* d, bool is_canonical) {
+ void ReadFill(Deserializer* d, bool stamp_canonical) {
+ ASSERT(!stamp_canonical); // Never canonical.
for (intptr_t id = start_index_; id < stop_index_; id++) {
PatchClassPtr cls = static_cast<PatchClassPtr>(d->Ref(id));
Deserializer::InitializeHeader(cls, kPatchClassCid,
@@ -667,7 +661,7 @@
FunctionDeserializationCluster() : DeserializationCluster("Function") {}
~FunctionDeserializationCluster() {}
- void ReadAlloc(Deserializer* d, bool is_canonical) {
+ void ReadAlloc(Deserializer* d, bool stamp_canonical) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
const intptr_t count = d->ReadUnsigned();
@@ -677,7 +671,8 @@
stop_index_ = d->next_index();
}
- void ReadFill(Deserializer* d, bool is_canonical) {
+ void ReadFill(Deserializer* d, bool stamp_canonical) {
+ ASSERT(!stamp_canonical); // Never canonical.
Snapshot::Kind kind = d->kind();
for (intptr_t id = start_index_; id < stop_index_; id++) {
@@ -725,7 +720,7 @@
}
}
- void PostLoad(Deserializer* d, const Array& refs, bool is_canonical) {
+ void PostLoad(Deserializer* d, const Array& refs, bool canonicalize) {
if (d->kind() == Snapshot::kFullAOT) {
Function& func = Function::Handle(d->zone());
for (intptr_t i = start_index_; i < stop_index_; i++) {
@@ -816,7 +811,7 @@
ClosureDataDeserializationCluster() : DeserializationCluster("ClosureData") {}
~ClosureDataDeserializationCluster() {}
- void ReadAlloc(Deserializer* d, bool is_canonical) {
+ void ReadAlloc(Deserializer* d, bool stamp_canonical) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
const intptr_t count = d->ReadUnsigned();
@@ -827,7 +822,8 @@
stop_index_ = d->next_index();
}
- void ReadFill(Deserializer* d, bool is_canonical) {
+ void ReadFill(Deserializer* d, bool stamp_canonical) {
+ ASSERT(!stamp_canonical); // Never canonical.
for (intptr_t id = start_index_; id < stop_index_; id++) {
ClosureDataPtr data = static_cast<ClosureDataPtr>(d->Ref(id));
Deserializer::InitializeHeader(data, kClosureDataCid,
@@ -897,7 +893,7 @@
: DeserializationCluster("FfiTrampolineData") {}
~FfiTrampolineDataDeserializationCluster() {}
- void ReadAlloc(Deserializer* d, bool is_canonical) {
+ void ReadAlloc(Deserializer* d, bool stamp_canonical) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
const intptr_t count = d->ReadUnsigned();
@@ -908,7 +904,8 @@
stop_index_ = d->next_index();
}
- void ReadFill(Deserializer* d, bool is_canonical) {
+ void ReadFill(Deserializer* d, bool stamp_canonical) {
+ ASSERT(!stamp_canonical); // Never canonical.
for (intptr_t id = start_index_; id < stop_index_; id++) {
FfiTrampolineDataPtr data = static_cast<FfiTrampolineDataPtr>(d->Ref(id));
Deserializer::InitializeHeader(data, kFfiTrampolineDataCid,
@@ -920,7 +917,6 @@
}
};
-
#if !defined(DART_PRECOMPILED_RUNTIME)
class FieldSerializationCluster : public SerializationCluster {
public:
@@ -1016,7 +1012,7 @@
FieldDeserializationCluster() : DeserializationCluster("Field") {}
~FieldDeserializationCluster() {}
- void ReadAlloc(Deserializer* d, bool is_canonical) {
+ void ReadAlloc(Deserializer* d, bool stamp_canonical) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
const intptr_t count = d->ReadUnsigned();
@@ -1026,7 +1022,8 @@
stop_index_ = d->next_index();
}
- void ReadFill(Deserializer* d, bool is_canonical) {
+ void ReadFill(Deserializer* d, bool stamp_canonical) {
+ ASSERT(!stamp_canonical); // Never canonical.
Snapshot::Kind kind = d->kind();
for (intptr_t id = start_index_; id < stop_index_; id++) {
@@ -1067,7 +1064,7 @@
}
}
- void PostLoad(Deserializer* d, const Array& refs, bool is_canonical) {
+ void PostLoad(Deserializer* d, const Array& refs, bool canonicalize) {
Field& field = Field::Handle(d->zone());
if (!IsolateGroup::Current()->use_field_guards()) {
for (intptr_t i = start_index_; i < stop_index_; i++) {
@@ -1142,7 +1139,7 @@
ScriptDeserializationCluster() : DeserializationCluster("Script") {}
~ScriptDeserializationCluster() {}
- void ReadAlloc(Deserializer* d, bool is_canonical) {
+ void ReadAlloc(Deserializer* d, bool stamp_canonical) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
const intptr_t count = d->ReadUnsigned();
@@ -1152,7 +1149,8 @@
stop_index_ = d->next_index();
}
- void ReadFill(Deserializer* d, bool is_canonical) {
+ void ReadFill(Deserializer* d, bool stamp_canonical) {
+ ASSERT(!stamp_canonical); // Never canonical.
for (intptr_t id = start_index_; id < stop_index_; id++) {
ScriptPtr script = static_cast<ScriptPtr>(d->Ref(id));
Deserializer::InitializeHeader(script, kScriptCid,
@@ -1217,7 +1215,7 @@
LibraryDeserializationCluster() : DeserializationCluster("Library") {}
~LibraryDeserializationCluster() {}
- void ReadAlloc(Deserializer* d, bool is_canonical) {
+ void ReadAlloc(Deserializer* d, bool stamp_canonical) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
const intptr_t count = d->ReadUnsigned();
@@ -1227,7 +1225,8 @@
stop_index_ = d->next_index();
}
- void ReadFill(Deserializer* d, bool is_canonical) {
+ void ReadFill(Deserializer* d, bool stamp_canonical) {
+ ASSERT(!stamp_canonical); // Never canonical.
for (intptr_t id = start_index_; id < stop_index_; id++) {
LibraryPtr lib = static_cast<LibraryPtr>(d->Ref(id));
Deserializer::InitializeHeader(lib, kLibraryCid, Library::InstanceSize());
@@ -1289,7 +1288,7 @@
NamespaceDeserializationCluster() : DeserializationCluster("Namespace") {}
~NamespaceDeserializationCluster() {}
- void ReadAlloc(Deserializer* d, bool is_canonical) {
+ void ReadAlloc(Deserializer* d, bool stamp_canonical) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
const intptr_t count = d->ReadUnsigned();
@@ -1299,7 +1298,8 @@
stop_index_ = d->next_index();
}
- void ReadFill(Deserializer* d, bool is_canonical) {
+ void ReadFill(Deserializer* d, bool stamp_canonical) {
+ ASSERT(!stamp_canonical); // Never canonical.
for (intptr_t id = start_index_; id < stop_index_; id++) {
NamespacePtr ns = static_cast<NamespacePtr>(d->Ref(id));
Deserializer::InitializeHeader(ns, kNamespaceCid,
@@ -1355,7 +1355,7 @@
: DeserializationCluster("KernelProgramInfo") {}
~KernelProgramInfoDeserializationCluster() {}
- void ReadAlloc(Deserializer* d, bool is_canonical) {
+ void ReadAlloc(Deserializer* d, bool stamp_canonical) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
const intptr_t count = d->ReadUnsigned();
@@ -1366,7 +1366,8 @@
stop_index_ = d->next_index();
}
- void ReadFill(Deserializer* d, bool is_canonical) {
+ void ReadFill(Deserializer* d, bool stamp_canonical) {
+ ASSERT(!stamp_canonical); // Never canonical.
for (intptr_t id = start_index_; id < stop_index_; id++) {
KernelProgramInfoPtr info = static_cast<KernelProgramInfoPtr>(d->Ref(id));
Deserializer::InitializeHeader(info, kKernelProgramInfoCid,
@@ -1376,7 +1377,7 @@
}
}
- void PostLoad(Deserializer* d, const Array& refs, bool is_canonical) {
+ void PostLoad(Deserializer* d, const Array& refs, bool canonicalize) {
Array& array = Array::Handle(d->zone());
KernelProgramInfo& info = KernelProgramInfo::Handle(d->zone());
for (intptr_t id = start_index_; id < stop_index_; id++) {
@@ -1403,7 +1404,9 @@
}
if (!(s->kind() == Snapshot::kFullAOT && FLAG_use_bare_instructions)) {
- s->Push(code->ptr()->object_pool_);
+ if (s->InCurrentLoadingUnit(code->ptr()->object_pool_)) {
+ s->Push(code->ptr()->object_pool_);
+ }
}
s->Push(code->ptr()->owner_);
s->Push(code->ptr()->exception_handlers_);
@@ -1518,7 +1521,8 @@
void WriteAlloc(Serializer* s) {
Sort(&objects_);
auto loading_units = s->loading_units();
- if (loading_units != nullptr) {
+ if ((loading_units != nullptr) &&
+ (s->current_loading_unit_id() == LoadingUnit::kRootId)) {
for (intptr_t i = LoadingUnit::kRootId + 1; i < loading_units->length();
i++) {
auto unit_objects = loading_units->At(i)->deferred_objects();
@@ -1590,7 +1594,11 @@
// No need to write object pool out if we are producing full AOT
// snapshot with bare instructions.
if (!(kind == Snapshot::kFullAOT && FLAG_use_bare_instructions)) {
- WriteField(code, object_pool_);
+ if (s->InCurrentLoadingUnit(code->ptr()->object_pool_)) {
+ WriteField(code, object_pool_);
+ } else {
+ WriteFieldValue(object_pool_, ObjectPool::null());
+ }
#if defined(DART_PRECOMPILER)
} else if (FLAG_write_v8_snapshot_profile_to != nullptr &&
code->ptr()->object_pool_ != ObjectPool::null()) {
@@ -1716,7 +1724,7 @@
CodeDeserializationCluster() : DeserializationCluster("Code") {}
~CodeDeserializationCluster() {}
- void ReadAlloc(Deserializer* d, bool is_canonical) {
+ void ReadAlloc(Deserializer* d, bool stamp_canonical) {
PageSpace* old_space = d->heap()->old_space();
start_index_ = d->next_index();
const intptr_t count = d->ReadUnsigned();
@@ -1734,7 +1742,8 @@
deferred_stop_index_ = d->next_index();
}
- void ReadFill(Deserializer* d, bool is_canonical) {
+ void ReadFill(Deserializer* d, bool stamp_canonical) {
+ ASSERT(!stamp_canonical); // Never canonical.
for (intptr_t id = start_index_; id < stop_index_; id++) {
ReadFill(d, id, false);
}
@@ -1786,7 +1795,7 @@
code->ptr()->state_bits_ = d->Read<int32_t>();
}
- void PostLoad(Deserializer* d, const Array& refs, bool is_canonical) {
+ void PostLoad(Deserializer* d, const Array& refs, bool canonicalize) {
d->EndInstructions(refs, start_index_, stop_index_);
#if !defined(PRODUCT)
@@ -1907,7 +1916,7 @@
ObjectPoolDeserializationCluster() : DeserializationCluster("ObjectPool") {}
~ObjectPoolDeserializationCluster() {}
- void ReadAlloc(Deserializer* d, bool is_canonical) {
+ void ReadAlloc(Deserializer* d, bool stamp_canonical) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
const intptr_t count = d->ReadUnsigned();
@@ -1919,7 +1928,10 @@
stop_index_ = d->next_index();
}
- void ReadFill(Deserializer* d, bool is_canonical) {
+ void ReadFill(Deserializer* d, bool stamp_canonical) {
+ ASSERT(!stamp_canonical); // Never canonical.
+ fill_position_ = d->position();
+
for (intptr_t id = start_index_; id < stop_index_; id += 1) {
const intptr_t length = d->ReadUnsigned();
ObjectPoolPtr pool = static_cast<ObjectPoolPtr>(d->Ref(id + 0));
@@ -1949,6 +1961,41 @@
}
}
}
+
+ void PostLoad(Deserializer* d, const Array& refs, bool canonicalize) {
+ intptr_t restore_position = d->position();
+ d->set_position(fill_position_);
+
+ ObjectPool& pool = ObjectPool::Handle();
+ Object& entry = Object::Handle();
+ for (intptr_t id = start_index_; id < stop_index_; id += 1) {
+ pool ^= refs.At(id);
+ const intptr_t length = d->ReadUnsigned();
+ for (intptr_t j = 0; j < length; j++) {
+ const uint8_t entry_bits = d->Read<uint8_t>();
+ switch (ObjectPool::TypeBits::decode(entry_bits)) {
+ case ObjectPool::EntryType::kTaggedObject:
+ entry = refs.At(d->ReadUnsigned());
+ pool.SetObjectAt(j, entry);
+ break;
+ case ObjectPool::EntryType::kImmediate:
+ d->Read<intptr_t>();
+ break;
+ case ObjectPool::EntryType::kNativeFunction: {
+ // Read nothing.
+ break;
+ }
+ default:
+ UNREACHABLE();
+ }
+ }
+ }
+
+ d->set_position(restore_position);
+ }
+
+ private:
+ intptr_t fill_position_ = 0;
};
#if defined(DART_PRECOMPILER)
@@ -2071,7 +2118,7 @@
: DeserializationCluster("WeakSerializationReference") {}
~WeakSerializationReferenceDeserializationCluster() {}
- void ReadAlloc(Deserializer* d, bool is_canonical) {
+ void ReadAlloc(Deserializer* d, bool stamp_canonical) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
const intptr_t count = d->ReadUnsigned();
@@ -2085,7 +2132,8 @@
stop_index_ = d->next_index();
}
- void ReadFill(Deserializer* d, bool is_canonical) {
+ void ReadFill(Deserializer* d, bool stamp_canonical) {
+ ASSERT(!stamp_canonical); // Never canonical.
for (intptr_t id = start_index_; id < stop_index_; id++) {
auto const ref = static_cast<WeakSerializationReferencePtr>(d->Ref(id));
Deserializer::InitializeHeader(
@@ -2144,7 +2192,7 @@
: DeserializationCluster("PcDescriptors") {}
~PcDescriptorsDeserializationCluster() {}
- void ReadAlloc(Deserializer* d, bool is_canonical) {
+ void ReadAlloc(Deserializer* d, bool stamp_canonical) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
const intptr_t count = d->ReadUnsigned();
@@ -2156,7 +2204,8 @@
stop_index_ = d->next_index();
}
- void ReadFill(Deserializer* d, bool is_canonical) {
+ void ReadFill(Deserializer* d, bool stamp_canonical) {
+ ASSERT(!stamp_canonical); // Never canonical.
for (intptr_t id = start_index_; id < stop_index_; id += 1) {
const intptr_t length = d->ReadUnsigned();
PcDescriptorsPtr desc = static_cast<PcDescriptorsPtr>(d->Ref(id));
@@ -2238,7 +2287,7 @@
: DeserializationCluster("ROData"), cid_(cid) {}
~RODataDeserializationCluster() {}
- void ReadAlloc(Deserializer* d, bool is_canonical) {
+ void ReadAlloc(Deserializer* d, bool stamp_canonical) {
start_index_ = d->next_index();
intptr_t count = d->ReadUnsigned();
uint32_t running_offset = 0;
@@ -2249,21 +2298,25 @@
stop_index_ = d->next_index();
}
- void ReadFill(Deserializer* d, bool is_canonical) {
+ void ReadFill(Deserializer* d, bool stamp_canonical) {
// No-op.
}
- void PostLoad(Deserializer* d, const Array& refs, bool is_canonical) {
- if (is_canonical && IsStringClassId(cid_) &&
- (d->isolate() != Dart::vm_isolate())) {
+ void PostLoad(Deserializer* d, const Array& refs, bool canonicalize) {
+ if (canonicalize && IsStringClassId(cid_)) {
CanonicalStringSet table(
d->zone(), d->isolate_group()->object_store()->symbol_table());
String& str = String::Handle(d->zone());
+ String& str2 = String::Handle(d->zone());
for (intptr_t i = start_index_; i < stop_index_; i++) {
str ^= refs.At(i);
- ASSERT(str.IsCanonical());
- bool present = table.Insert(str);
- ASSERT(!present);
+ str2 ^= table.InsertOrGet(str);
+ if (str.raw() == str2.raw()) {
+ // str.SetCanonical();
+ } else {
+ FATAL("Lost canonicalization race");
+ refs.SetAt(i, str2);
+ }
}
d->isolate_group()->object_store()->set_symbol_table(table.Release());
}
@@ -2330,7 +2383,7 @@
: DeserializationCluster("ExceptionHandlers") {}
~ExceptionHandlersDeserializationCluster() {}
- void ReadAlloc(Deserializer* d, bool is_canonical) {
+ void ReadAlloc(Deserializer* d, bool stamp_canonical) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
const intptr_t count = d->ReadUnsigned();
@@ -2342,7 +2395,8 @@
stop_index_ = d->next_index();
}
- void ReadFill(Deserializer* d, bool is_canonical) {
+ void ReadFill(Deserializer* d, bool stamp_canonical) {
+ ASSERT(!stamp_canonical); // Never canonical.
for (intptr_t id = start_index_; id < stop_index_; id++) {
ExceptionHandlersPtr handlers =
static_cast<ExceptionHandlersPtr>(d->Ref(id));
@@ -2418,7 +2472,7 @@
ContextDeserializationCluster() : DeserializationCluster("Context") {}
~ContextDeserializationCluster() {}
- void ReadAlloc(Deserializer* d, bool is_canonical) {
+ void ReadAlloc(Deserializer* d, bool stamp_canonical) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
const intptr_t count = d->ReadUnsigned();
@@ -2430,7 +2484,8 @@
stop_index_ = d->next_index();
}
- void ReadFill(Deserializer* d, bool is_canonical) {
+ void ReadFill(Deserializer* d, bool stamp_canonical) {
+ ASSERT(!stamp_canonical); // Never canonical.
for (intptr_t id = start_index_; id < stop_index_; id++) {
ContextPtr context = static_cast<ContextPtr>(d->Ref(id));
const intptr_t length = d->ReadUnsigned();
@@ -2495,7 +2550,7 @@
: DeserializationCluster("ContextScope") {}
~ContextScopeDeserializationCluster() {}
- void ReadAlloc(Deserializer* d, bool is_canonical) {
+ void ReadAlloc(Deserializer* d, bool stamp_canonical) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
const intptr_t count = d->ReadUnsigned();
@@ -2507,7 +2562,8 @@
stop_index_ = d->next_index();
}
- void ReadFill(Deserializer* d, bool is_canonical) {
+ void ReadFill(Deserializer* d, bool stamp_canonical) {
+ ASSERT(!stamp_canonical); // Never canonical.
for (intptr_t id = start_index_; id < stop_index_; id++) {
ContextScopePtr scope = static_cast<ContextScopePtr>(d->Ref(id));
const intptr_t length = d->ReadUnsigned();
@@ -2563,7 +2619,7 @@
: DeserializationCluster("UnlinkedCall") {}
~UnlinkedCallDeserializationCluster() {}
- void ReadAlloc(Deserializer* d, bool is_canonical) {
+ void ReadAlloc(Deserializer* d, bool stamp_canonical) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
const intptr_t count = d->ReadUnsigned();
@@ -2574,7 +2630,8 @@
stop_index_ = d->next_index();
}
- void ReadFill(Deserializer* d, bool is_canonical) {
+ void ReadFill(Deserializer* d, bool stamp_canonical) {
+ ASSERT(!stamp_canonical); // Never canonical.
for (intptr_t id = start_index_; id < stop_index_; id++) {
UnlinkedCallPtr unlinked = static_cast<UnlinkedCallPtr>(d->Ref(id));
Deserializer::InitializeHeader(unlinked, kUnlinkedCallCid,
@@ -2631,7 +2688,7 @@
ICDataDeserializationCluster() : DeserializationCluster("ICData") {}
~ICDataDeserializationCluster() {}
- void ReadAlloc(Deserializer* d, bool is_canonical) {
+ void ReadAlloc(Deserializer* d, bool stamp_canonical) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
const intptr_t count = d->ReadUnsigned();
@@ -2641,7 +2698,8 @@
stop_index_ = d->next_index();
}
- void ReadFill(Deserializer* d, bool is_canonical) {
+ void ReadFill(Deserializer* d, bool stamp_canonical) {
+ ASSERT(!stamp_canonical); // Never canonical.
for (intptr_t id = start_index_; id < stop_index_; id++) {
ICDataPtr ic = static_cast<ICDataPtr>(d->Ref(id));
Deserializer::InitializeHeader(ic, kICDataCid, ICData::InstanceSize());
@@ -2696,7 +2754,7 @@
: DeserializationCluster("MegamorphicCache") {}
~MegamorphicCacheDeserializationCluster() {}
- void ReadAlloc(Deserializer* d, bool is_canonical) {
+ void ReadAlloc(Deserializer* d, bool stamp_canonical) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
const intptr_t count = d->ReadUnsigned();
@@ -2707,7 +2765,8 @@
stop_index_ = d->next_index();
}
- void ReadFill(Deserializer* d, bool is_canonical) {
+ void ReadFill(Deserializer* d, bool stamp_canonical) {
+ ASSERT(!stamp_canonical); // Never canonical.
for (intptr_t id = start_index_; id < stop_index_; id++) {
MegamorphicCachePtr cache = static_cast<MegamorphicCachePtr>(d->Ref(id));
Deserializer::InitializeHeader(cache, kMegamorphicCacheCid,
@@ -2718,7 +2777,7 @@
}
#if defined(DART_PRECOMPILED_RUNTIME)
- void PostLoad(Deserializer* d, const Array& refs, bool is_canonical) {
+ void PostLoad(Deserializer* d, const Array& refs, bool canonicalize) {
if (FLAG_use_bare_instructions) {
// By default, every megamorphic call site will load the target
// [Function] from the hash table and call indirectly via loading the
@@ -2787,7 +2846,7 @@
: DeserializationCluster("SubtypeTestCache") {}
~SubtypeTestCacheDeserializationCluster() {}
- void ReadAlloc(Deserializer* d, bool is_canonical) {
+ void ReadAlloc(Deserializer* d, bool stamp_canonical) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
const intptr_t count = d->ReadUnsigned();
@@ -2798,7 +2857,8 @@
stop_index_ = d->next_index();
}
- void ReadFill(Deserializer* d, bool is_canonical) {
+ void ReadFill(Deserializer* d, bool stamp_canonical) {
+ ASSERT(!stamp_canonical); // Never canonical.
for (intptr_t id = start_index_; id < stop_index_; id++) {
SubtypeTestCachePtr cache = static_cast<SubtypeTestCachePtr>(d->Ref(id));
Deserializer::InitializeHeader(cache, kSubtypeTestCacheCid,
@@ -2850,7 +2910,7 @@
LoadingUnitDeserializationCluster() : DeserializationCluster("LoadingUnit") {}
~LoadingUnitDeserializationCluster() {}
- void ReadAlloc(Deserializer* d, bool is_canonical) {
+ void ReadAlloc(Deserializer* d, bool stamp_canonical) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
const intptr_t count = d->ReadUnsigned();
@@ -2861,7 +2921,8 @@
stop_index_ = d->next_index();
}
- void ReadFill(Deserializer* d, bool is_canonical) {
+ void ReadFill(Deserializer* d, bool stamp_canonical) {
+ ASSERT(!stamp_canonical); // Never canonical.
for (intptr_t id = start_index_; id < stop_index_; id++) {
LoadingUnitPtr unit = static_cast<LoadingUnitPtr>(d->Ref(id));
Deserializer::InitializeHeader(unit, kLoadingUnitCid,
@@ -2920,7 +2981,7 @@
: DeserializationCluster("LanguageError") {}
~LanguageErrorDeserializationCluster() {}
- void ReadAlloc(Deserializer* d, bool is_canonical) {
+ void ReadAlloc(Deserializer* d, bool stamp_canonical) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
const intptr_t count = d->ReadUnsigned();
@@ -2931,7 +2992,8 @@
stop_index_ = d->next_index();
}
- void ReadFill(Deserializer* d, bool is_canonical) {
+ void ReadFill(Deserializer* d, bool stamp_canonical) {
+ ASSERT(!stamp_canonical); // Never canonical.
for (intptr_t id = start_index_; id < stop_index_; id++) {
LanguageErrorPtr error = static_cast<LanguageErrorPtr>(d->Ref(id));
Deserializer::InitializeHeader(error, kLanguageErrorCid,
@@ -2987,7 +3049,7 @@
: DeserializationCluster("UnhandledException") {}
~UnhandledExceptionDeserializationCluster() {}
- void ReadAlloc(Deserializer* d, bool is_canonical) {
+ void ReadAlloc(Deserializer* d, bool stamp_canonical) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
const intptr_t count = d->ReadUnsigned();
@@ -2998,7 +3060,8 @@
stop_index_ = d->next_index();
}
- void ReadFill(Deserializer* d, bool is_canonical) {
+ void ReadFill(Deserializer* d, bool stamp_canonical) {
+ ASSERT(!stamp_canonical); // Never canonical.
for (intptr_t id = start_index_; id < stop_index_; id++) {
UnhandledExceptionPtr exception =
static_cast<UnhandledExceptionPtr>(d->Ref(id));
@@ -3106,13 +3169,35 @@
};
#endif // !DART_PRECOMPILED_RUNTIME
-class InstanceDeserializationCluster : public DeserializationCluster {
+class AbstractInstanceDeserializationCluster : public DeserializationCluster {
+ protected:
+ explicit AbstractInstanceDeserializationCluster(const char* name)
+ : DeserializationCluster(name) {}
+
+ public:
+ void PostLoad(Deserializer* d, const Array& refs, bool canonicalize) {
+ if (canonicalize) {
+ Thread* thread = Thread::Current();
+ SafepointMutexLocker ml(
+ thread->isolate_group()->constant_canonicalization_mutex());
+ Instance& instance = Instance::Handle(d->zone());
+ for (intptr_t i = start_index_; i < stop_index_; i++) {
+ instance ^= refs.At(i);
+ instance = instance.CanonicalizeLocked(thread);
+ refs.SetAt(i, instance);
+ }
+ }
+ }
+};
+
+class InstanceDeserializationCluster
+ : public AbstractInstanceDeserializationCluster {
public:
explicit InstanceDeserializationCluster(intptr_t cid)
- : DeserializationCluster("Instance"), cid_(cid) {}
+ : AbstractInstanceDeserializationCluster("Instance"), cid_(cid) {}
~InstanceDeserializationCluster() {}
- void ReadAlloc(Deserializer* d, bool is_canonical) {
+ void ReadAlloc(Deserializer* d, bool stamp_canonical) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
const intptr_t count = d->ReadUnsigned();
@@ -3126,7 +3211,7 @@
stop_index_ = d->next_index();
}
- void ReadFill(Deserializer* d, bool is_canonical) {
+ void ReadFill(Deserializer* d, bool stamp_canonical) {
intptr_t next_field_offset = next_field_offset_in_words_ << kWordSizeLog2;
intptr_t instance_size =
Object::RoundedAllocationSize(instance_size_in_words_ * kWordSize);
@@ -3135,7 +3220,7 @@
for (intptr_t id = start_index_; id < stop_index_; id++) {
InstancePtr instance = static_cast<InstancePtr>(d->Ref(id));
Deserializer::InitializeHeader(instance, cid_, instance_size,
- is_canonical);
+ stamp_canonical);
intptr_t offset = Instance::NextFieldOffset();
while (offset < next_field_offset) {
if (unboxed_fields_bitmap.Get(offset / kWordSize)) {
@@ -3210,7 +3295,7 @@
: DeserializationCluster("LibraryPrefix") {}
~LibraryPrefixDeserializationCluster() {}
- void ReadAlloc(Deserializer* d, bool is_canonical) {
+ void ReadAlloc(Deserializer* d, bool stamp_canonical) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
const intptr_t count = d->ReadUnsigned();
@@ -3221,7 +3306,8 @@
stop_index_ = d->next_index();
}
- void ReadFill(Deserializer* d, bool is_canonical) {
+ void ReadFill(Deserializer* d, bool stamp_canonical) {
+ ASSERT(!stamp_canonical); // Never canonical.
for (intptr_t id = start_index_; id < stop_index_; id++) {
LibraryPrefixPtr prefix = static_cast<LibraryPrefixPtr>(d->Ref(id));
Deserializer::InitializeHeader(prefix, kLibraryPrefixCid,
@@ -3303,7 +3389,7 @@
TypeDeserializationCluster() : DeserializationCluster("Type") {}
~TypeDeserializationCluster() {}
- void ReadAlloc(Deserializer* d, bool is_canonical) {
+ void ReadAlloc(Deserializer* d, bool stamp_canonical) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
const intptr_t count = d->ReadUnsigned();
@@ -3313,11 +3399,11 @@
stop_index_ = d->next_index();
}
- void ReadFill(Deserializer* d, bool is_canonical) {
+ void ReadFill(Deserializer* d, bool stamp_canonical) {
for (intptr_t id = start_index_; id < stop_index_; id++) {
TypePtr type = static_cast<TypePtr>(d->Ref(id));
Deserializer::InitializeHeader(type, kTypeCid, Type::InstanceSize(),
- is_canonical);
+ stamp_canonical);
ReadFromTo(type);
const uint8_t combined = d->Read<uint8_t>();
type->ptr()->type_state_ = combined >> kNullabilityBitSize;
@@ -3325,20 +3411,15 @@
}
}
- void PostLoad(Deserializer* d, const Array& refs, bool is_canonical) {
- if (is_canonical && (d->isolate() != Dart::vm_isolate())) {
- CanonicalTypeSet table(
- d->zone(), d->isolate_group()->object_store()->canonical_types());
- Type& type = Type::Handle(d->zone());
+ void PostLoad(Deserializer* d, const Array& refs, bool canonicalize) {
+ if (canonicalize) {
+ Thread* thread = Thread::Current();
+ AbstractType& type = AbstractType::Handle(d->zone());
for (intptr_t i = start_index_; i < stop_index_; i++) {
type ^= refs.At(i);
- ASSERT(type.IsCanonical());
- bool present = table.Insert(type);
- // Two recursive types with different topology (and hashes) may be
- // equal.
- ASSERT(!present || type.IsRecursive());
+ type = type.Canonicalize(thread, nullptr);
+ refs.SetAt(i, type);
}
- d->isolate_group()->object_store()->set_canonical_types(table.Release());
}
Type& type = Type::Handle(d->zone());
@@ -3417,7 +3498,7 @@
: DeserializationCluster("FunctionType") {}
~FunctionTypeDeserializationCluster() {}
- void ReadAlloc(Deserializer* d, bool is_canonical) {
+ void ReadAlloc(Deserializer* d, bool stamp_canonical) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
const intptr_t count = d->ReadUnsigned();
@@ -3428,11 +3509,12 @@
stop_index_ = d->next_index();
}
- void ReadFill(Deserializer* d, bool is_canonical) {
+ void ReadFill(Deserializer* d, bool stamp_canonical) {
for (intptr_t id = start_index_; id < stop_index_; id++) {
FunctionTypePtr type = static_cast<FunctionTypePtr>(d->Ref(id));
- Deserializer::InitializeHeader(
- type, kFunctionTypeCid, FunctionType::InstanceSize(), is_canonical);
+ Deserializer::InitializeHeader(type, kFunctionTypeCid,
+ FunctionType::InstanceSize(),
+ stamp_canonical);
ReadFromTo(type);
const uint8_t combined = d->Read<uint8_t>();
type->ptr()->type_state_ = combined >> kNullabilityBitSize;
@@ -3441,22 +3523,15 @@
}
}
- void PostLoad(Deserializer* d, const Array& refs, bool is_canonical) {
- if (is_canonical && (d->isolate() != Dart::vm_isolate())) {
- CanonicalFunctionTypeSet table(
- d->zone(),
- d->isolate_group()->object_store()->canonical_function_types());
- FunctionType& type = FunctionType::Handle(d->zone());
+ void PostLoad(Deserializer* d, const Array& refs, bool canonicalize) {
+ if (canonicalize) {
+ Thread* thread = Thread::Current();
+ AbstractType& type = AbstractType::Handle(d->zone());
for (intptr_t i = start_index_; i < stop_index_; i++) {
type ^= refs.At(i);
- ASSERT(type.IsCanonical());
- bool present = table.Insert(type);
- // Two recursive types with different topology (and hashes) may be
- // equal.
- ASSERT(!present || type.IsRecursive());
+ type = type.Canonicalize(thread, nullptr);
+ refs.SetAt(i, type);
}
- d->isolate_group()->object_store()->set_canonical_function_types(
- table.Release());
}
FunctionType& type = FunctionType::Handle(d->zone());
@@ -3519,7 +3594,7 @@
TypeRefDeserializationCluster() : DeserializationCluster("TypeRef") {}
~TypeRefDeserializationCluster() {}
- void ReadAlloc(Deserializer* d, bool is_canonical) {
+ void ReadAlloc(Deserializer* d, bool stamp_canonical) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
const intptr_t count = d->ReadUnsigned();
@@ -3529,16 +3604,16 @@
stop_index_ = d->next_index();
}
- void ReadFill(Deserializer* d, bool is_canonical) {
+ void ReadFill(Deserializer* d, bool stamp_canonical) {
for (intptr_t id = start_index_; id < stop_index_; id++) {
TypeRefPtr type = static_cast<TypeRefPtr>(d->Ref(id));
- Deserializer::InitializeHeader(type, kTypeRefCid,
- TypeRef::InstanceSize());
+ Deserializer::InitializeHeader(type, kTypeRefCid, TypeRef::InstanceSize(),
+ stamp_canonical);
ReadFromTo(type);
}
}
- void PostLoad(Deserializer* d, const Array& refs, bool is_canonical) {
+ void PostLoad(Deserializer* d, const Array& refs, bool canonicalize) {
TypeRef& type_ref = TypeRef::Handle(d->zone());
Code& stub = Code::Handle(d->zone());
@@ -3618,7 +3693,7 @@
: DeserializationCluster("TypeParameter") {}
~TypeParameterDeserializationCluster() {}
- void ReadAlloc(Deserializer* d, bool is_canonical) {
+ void ReadAlloc(Deserializer* d, bool stamp_canonical) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
const intptr_t count = d->ReadUnsigned();
@@ -3629,11 +3704,12 @@
stop_index_ = d->next_index();
}
- void ReadFill(Deserializer* d, bool is_canonical) {
+ void ReadFill(Deserializer* d, bool stamp_canonical) {
for (intptr_t id = start_index_; id < stop_index_; id++) {
TypeParameterPtr type = static_cast<TypeParameterPtr>(d->Ref(id));
- Deserializer::InitializeHeader(
- type, kTypeParameterCid, TypeParameter::InstanceSize(), is_canonical);
+ Deserializer::InitializeHeader(type, kTypeParameterCid,
+ TypeParameter::InstanceSize(),
+ stamp_canonical);
ReadFromTo(type);
type->ptr()->parameterized_class_id_ = d->Read<int32_t>();
type->ptr()->base_ = d->Read<uint16_t>();
@@ -3644,20 +3720,15 @@
}
}
- void PostLoad(Deserializer* d, const Array& refs, bool is_canonical) {
- if (is_canonical && (d->isolate() != Dart::vm_isolate())) {
- CanonicalTypeParameterSet table(
- d->zone(),
- d->isolate_group()->object_store()->canonical_type_parameters());
+ void PostLoad(Deserializer* d, const Array& refs, bool canonicalize) {
+ if (canonicalize) {
+ Thread* thread = Thread::Current();
TypeParameter& type_param = TypeParameter::Handle(d->zone());
for (intptr_t i = start_index_; i < stop_index_; i++) {
type_param ^= refs.At(i);
- ASSERT(type_param.IsCanonical());
- bool present = table.Insert(type_param);
- ASSERT(!present);
+ type_param ^= type_param.Canonicalize(thread, nullptr);
+ refs.SetAt(i, type_param);
}
- d->isolate_group()->object_store()->set_canonical_type_parameters(
- table.Release());
}
TypeParameter& type_param = TypeParameter::Handle(d->zone());
@@ -3716,12 +3787,14 @@
};
#endif // !DART_PRECOMPILED_RUNTIME
-class ClosureDeserializationCluster : public DeserializationCluster {
+class ClosureDeserializationCluster
+ : public AbstractInstanceDeserializationCluster {
public:
- ClosureDeserializationCluster() : DeserializationCluster("Closure") {}
+ ClosureDeserializationCluster()
+ : AbstractInstanceDeserializationCluster("Closure") {}
~ClosureDeserializationCluster() {}
- void ReadAlloc(Deserializer* d, bool is_canonical) {
+ void ReadAlloc(Deserializer* d, bool stamp_canonical) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
const intptr_t count = d->ReadUnsigned();
@@ -3731,11 +3804,11 @@
stop_index_ = d->next_index();
}
- void ReadFill(Deserializer* d, bool is_canonical) {
+ void ReadFill(Deserializer* d, bool stamp_canonical) {
for (intptr_t id = start_index_; id < stop_index_; id++) {
ClosurePtr closure = static_cast<ClosurePtr>(d->Ref(id));
Deserializer::InitializeHeader(closure, kClosureCid,
- Closure::InstanceSize(), is_canonical);
+ Closure::InstanceSize(), stamp_canonical);
ReadFromTo(closure);
}
}
@@ -3788,7 +3861,7 @@
MintDeserializationCluster() : DeserializationCluster("int") {}
~MintDeserializationCluster() {}
- void ReadAlloc(Deserializer* d, bool is_canonical) {
+ void ReadAlloc(Deserializer* d, bool stamp_canonical) {
PageSpace* old_space = d->heap()->old_space();
start_index_ = d->next_index();
@@ -3801,7 +3874,7 @@
MintPtr mint = static_cast<MintPtr>(
AllocateUninitialized(old_space, Mint::InstanceSize()));
Deserializer::InitializeHeader(mint, kMintCid, Mint::InstanceSize(),
- is_canonical);
+ stamp_canonical);
mint->ptr()->value_ = value;
d->AssignRef(mint);
}
@@ -3809,19 +3882,24 @@
stop_index_ = d->next_index();
}
- void ReadFill(Deserializer* d, bool is_canonical) {}
+ void ReadFill(Deserializer* d, bool stamp_canonical) {}
- void PostLoad(Deserializer* d, const Array& refs, bool is_canonical) {
- if (is_canonical && (d->isolate() != Dart::vm_isolate())) {
+ void PostLoad(Deserializer* d, const Array& refs, bool canonicalize) {
+ if (canonicalize) {
const Class& mint_cls = Class::Handle(
- d->zone(), IsolateGroup::Current()->object_store()->mint_class());
- mint_cls.set_constants(Object::null_array());
+ d->zone(), d->isolate_group()->object_store()->mint_class());
Object& number = Object::Handle(d->zone());
+ Mint& number2 = Mint::Handle(d->zone());
for (intptr_t i = start_index_; i < stop_index_; i++) {
number = refs.At(i);
- if (number.IsMint()) {
- ASSERT(number.IsCanonical());
+ if (!number.IsMint()) continue;
+ number2 =
+ mint_cls.LookupCanonicalMint(d->zone(), Mint::Cast(number).value());
+ if (number2.IsNull()) {
+ number.SetCanonical();
mint_cls.InsertCanonicalMint(d->zone(), Mint::Cast(number));
+ } else {
+ refs.SetAt(i, number2);
}
}
}
@@ -3868,7 +3946,7 @@
DoubleDeserializationCluster() : DeserializationCluster("double") {}
~DoubleDeserializationCluster() {}
- void ReadAlloc(Deserializer* d, bool is_canonical) {
+ void ReadAlloc(Deserializer* d, bool stamp_canonical) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
const intptr_t count = d->ReadUnsigned();
@@ -3878,14 +3956,35 @@
stop_index_ = d->next_index();
}
- void ReadFill(Deserializer* d, bool is_canonical) {
+ void ReadFill(Deserializer* d, bool stamp_canonical) {
for (intptr_t id = start_index_; id < stop_index_; id++) {
DoublePtr dbl = static_cast<DoublePtr>(d->Ref(id));
Deserializer::InitializeHeader(dbl, kDoubleCid, Double::InstanceSize(),
- is_canonical);
+ stamp_canonical);
dbl->ptr()->value_ = d->Read<double>();
}
}
+
+ void PostLoad(Deserializer* d, const Array& refs, bool canonicalize) {
+ if (canonicalize) {
+ const Class& cls = Class::Handle(
+ d->zone(), d->isolate_group()->object_store()->double_class());
+ SafepointMutexLocker ml(
+ d->isolate_group()->constant_canonicalization_mutex());
+ Double& dbl = Double::Handle(d->zone());
+ Double& dbl2 = Double::Handle(d->zone());
+ for (intptr_t i = start_index_; i < stop_index_; i++) {
+ dbl ^= refs.At(i);
+ dbl2 = cls.LookupCanonicalDouble(d->zone(), dbl.value());
+ if (dbl2.IsNull()) {
+ dbl.SetCanonical();
+ cls.InsertCanonicalDouble(d->zone(), dbl);
+ } else {
+ refs.SetAt(i, dbl2);
+ }
+ }
+ }
+ }
};
#if !defined(DART_PRECOMPILED_RUNTIME)
@@ -3932,7 +4031,7 @@
: DeserializationCluster("GrowableObjectArray") {}
~GrowableObjectArrayDeserializationCluster() {}
- void ReadAlloc(Deserializer* d, bool is_canonical) {
+ void ReadAlloc(Deserializer* d, bool stamp_canonical) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
const intptr_t count = d->ReadUnsigned();
@@ -3943,13 +4042,13 @@
stop_index_ = d->next_index();
}
- void ReadFill(Deserializer* d, bool is_canonical) {
+ void ReadFill(Deserializer* d, bool stamp_canonical) {
for (intptr_t id = start_index_; id < stop_index_; id++) {
GrowableObjectArrayPtr list =
static_cast<GrowableObjectArrayPtr>(d->Ref(id));
Deserializer::InitializeHeader(list, kGrowableObjectArrayCid,
GrowableObjectArray::InstanceSize(),
- is_canonical);
+ stamp_canonical);
ReadFromTo(list);
}
}
@@ -4005,7 +4104,7 @@
: DeserializationCluster("TypedData"), cid_(cid) {}
~TypedDataDeserializationCluster() {}
- void ReadAlloc(Deserializer* d, bool is_canonical) {
+ void ReadAlloc(Deserializer* d, bool stamp_canonical) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
const intptr_t count = d->ReadUnsigned();
@@ -4018,15 +4117,17 @@
stop_index_ = d->next_index();
}
- void ReadFill(Deserializer* d, bool is_canonical) {
+ void ReadFill(Deserializer* d, bool stamp_canonical) {
+ ASSERT(!stamp_canonical); // Never canonical.
intptr_t element_size = TypedData::ElementSizeInBytes(cid_);
for (intptr_t id = start_index_; id < stop_index_; id++) {
TypedDataPtr data = static_cast<TypedDataPtr>(d->Ref(id));
const intptr_t length = d->ReadUnsigned();
const intptr_t length_in_bytes = length * element_size;
- Deserializer::InitializeHeader(
- data, cid_, TypedData::InstanceSize(length_in_bytes), is_canonical);
+ Deserializer::InitializeHeader(data, cid_,
+ TypedData::InstanceSize(length_in_bytes),
+ stamp_canonical);
data->ptr()->length_ = Smi::New(length);
data->ptr()->RecomputeDataField();
uint8_t* cdata = reinterpret_cast<uint8_t*>(data->ptr()->data());
@@ -4083,7 +4184,7 @@
: DeserializationCluster("TypedDataView"), cid_(cid) {}
~TypedDataViewDeserializationCluster() {}
- void ReadAlloc(Deserializer* d, bool is_canonical) {
+ void ReadAlloc(Deserializer* d, bool stamp_canonical) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
const intptr_t count = d->ReadUnsigned();
@@ -4094,16 +4195,17 @@
stop_index_ = d->next_index();
}
- void ReadFill(Deserializer* d, bool is_canonical) {
+ void ReadFill(Deserializer* d, bool stamp_canonical) {
+ ASSERT(!stamp_canonical); // Never canonical.
for (intptr_t id = start_index_; id < stop_index_; id++) {
TypedDataViewPtr view = static_cast<TypedDataViewPtr>(d->Ref(id));
- Deserializer::InitializeHeader(view, cid_, TypedDataView::InstanceSize(),
- is_canonical);
+ Deserializer::InitializeHeader(view, cid_, TypedDataView::InstanceSize());
ReadFromTo(view);
}
}
- void PostLoad(Deserializer* d, const Array& refs, bool is_canonical) {
+ void PostLoad(Deserializer* d, const Array& refs, bool canonicalize) {
+ ASSERT(!canonicalize);
auto& view = TypedDataView::Handle(d->zone());
for (intptr_t id = start_index_; id < stop_index_; id++) {
view ^= refs.At(id);
@@ -4163,7 +4265,7 @@
: DeserializationCluster("ExternalTypedData"), cid_(cid) {}
~ExternalTypedDataDeserializationCluster() {}
- void ReadAlloc(Deserializer* d, bool is_canonical) {
+ void ReadAlloc(Deserializer* d, bool stamp_canonical) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
const intptr_t count = d->ReadUnsigned();
@@ -4174,7 +4276,8 @@
stop_index_ = d->next_index();
}
- void ReadFill(Deserializer* d, bool is_canonical) {
+ void ReadFill(Deserializer* d, bool stamp_canonical) {
+ ASSERT(!stamp_canonical); // Never canonical.
intptr_t element_size = ExternalTypedData::ElementSizeInBytes(cid_);
for (intptr_t id = start_index_; id < stop_index_; id++) {
@@ -4235,7 +4338,7 @@
StackTraceDeserializationCluster() : DeserializationCluster("StackTrace") {}
~StackTraceDeserializationCluster() {}
- void ReadAlloc(Deserializer* d, bool is_canonical) {
+ void ReadAlloc(Deserializer* d, bool stamp_canonical) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
const intptr_t count = d->ReadUnsigned();
@@ -4246,7 +4349,8 @@
stop_index_ = d->next_index();
}
- void ReadFill(Deserializer* d, bool is_canonical) {
+ void ReadFill(Deserializer* d, bool stamp_canonical) {
+ ASSERT(!stamp_canonical); // Never canonical.
for (intptr_t id = start_index_; id < stop_index_; id++) {
StackTracePtr trace = static_cast<StackTracePtr>(d->Ref(id));
Deserializer::InitializeHeader(trace, kStackTraceCid,
@@ -4300,7 +4404,7 @@
RegExpDeserializationCluster() : DeserializationCluster("RegExp") {}
~RegExpDeserializationCluster() {}
- void ReadAlloc(Deserializer* d, bool is_canonical) {
+ void ReadAlloc(Deserializer* d, bool stamp_canonical) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
const intptr_t count = d->ReadUnsigned();
@@ -4310,7 +4414,8 @@
stop_index_ = d->next_index();
}
- void ReadFill(Deserializer* d, bool is_canonical) {
+ void ReadFill(Deserializer* d, bool stamp_canonical) {
+ ASSERT(!stamp_canonical); // Never canonical.
for (intptr_t id = start_index_; id < stop_index_; id++) {
RegExpPtr regexp = static_cast<RegExpPtr>(d->Ref(id));
Deserializer::InitializeHeader(regexp, kRegExpCid,
@@ -4365,7 +4470,7 @@
: DeserializationCluster("WeakProperty") {}
~WeakPropertyDeserializationCluster() {}
- void ReadAlloc(Deserializer* d, bool is_canonical) {
+ void ReadAlloc(Deserializer* d, bool stamp_canonical) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
const intptr_t count = d->ReadUnsigned();
@@ -4376,7 +4481,8 @@
stop_index_ = d->next_index();
}
- void ReadFill(Deserializer* d, bool is_canonical) {
+ void ReadFill(Deserializer* d, bool stamp_canonical) {
+ ASSERT(!stamp_canonical); // Never canonical.
for (intptr_t id = start_index_; id < stop_index_; id++) {
WeakPropertyPtr property = static_cast<WeakPropertyPtr>(d->Ref(id));
Deserializer::InitializeHeader(property, kWeakPropertyCid,
@@ -4455,13 +4561,14 @@
};
#endif // !DART_PRECOMPILED_RUNTIME
-class LinkedHashMapDeserializationCluster : public DeserializationCluster {
+class LinkedHashMapDeserializationCluster
+ : public AbstractInstanceDeserializationCluster {
public:
LinkedHashMapDeserializationCluster()
- : DeserializationCluster("LinkedHashMap") {}
+ : AbstractInstanceDeserializationCluster("LinkedHashMap") {}
~LinkedHashMapDeserializationCluster() {}
- void ReadAlloc(Deserializer* d, bool is_canonical) {
+ void ReadAlloc(Deserializer* d, bool stamp_canonical) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
const intptr_t count = d->ReadUnsigned();
@@ -4472,13 +4579,14 @@
stop_index_ = d->next_index();
}
- void ReadFill(Deserializer* d, bool is_canonical) {
+ void ReadFill(Deserializer* d, bool stamp_canonical) {
PageSpace* old_space = d->heap()->old_space();
for (intptr_t id = start_index_; id < stop_index_; id++) {
LinkedHashMapPtr map = static_cast<LinkedHashMapPtr>(d->Ref(id));
- Deserializer::InitializeHeader(
- map, kLinkedHashMapCid, LinkedHashMap::InstanceSize(), is_canonical);
+ Deserializer::InitializeHeader(map, kLinkedHashMapCid,
+ LinkedHashMap::InstanceSize(),
+ stamp_canonical);
map->ptr()->type_arguments_ = static_cast<TypeArgumentsPtr>(d->ReadRef());
@@ -4561,13 +4669,14 @@
};
#endif // !DART_PRECOMPILED_RUNTIME
-class ArrayDeserializationCluster : public DeserializationCluster {
+class ArrayDeserializationCluster
+ : public AbstractInstanceDeserializationCluster {
public:
explicit ArrayDeserializationCluster(intptr_t cid)
- : DeserializationCluster("Array"), cid_(cid) {}
+ : AbstractInstanceDeserializationCluster("Array"), cid_(cid) {}
~ArrayDeserializationCluster() {}
- void ReadAlloc(Deserializer* d, bool is_canonical) {
+ void ReadAlloc(Deserializer* d, bool stamp_canonical) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
const intptr_t count = d->ReadUnsigned();
@@ -4579,12 +4688,12 @@
stop_index_ = d->next_index();
}
- void ReadFill(Deserializer* d, bool is_canonical) {
+ void ReadFill(Deserializer* d, bool stamp_canonical) {
for (intptr_t id = start_index_; id < stop_index_; id++) {
ArrayPtr array = static_cast<ArrayPtr>(d->Ref(id));
const intptr_t length = d->ReadUnsigned();
Deserializer::InitializeHeader(array, cid_, Array::InstanceSize(length),
- is_canonical);
+ stamp_canonical);
array->ptr()->type_arguments_ =
static_cast<TypeArgumentsPtr>(d->ReadRef());
array->ptr()->length_ = Smi::New(length);
@@ -4639,13 +4748,40 @@
};
#endif // !DART_PRECOMPILED_RUNTIME
-class OneByteStringDeserializationCluster : public DeserializationCluster {
+class StringDeserializationCluster : public DeserializationCluster {
+ protected:
+ explicit StringDeserializationCluster(const char* name)
+ : DeserializationCluster(name) {}
+
+ public:
+ void PostLoad(Deserializer* d, const Array& refs, bool canonicalize) {
+ if (canonicalize) {
+ CanonicalStringSet table(
+ d->zone(), d->isolate_group()->object_store()->symbol_table());
+ String& str = String::Handle(d->zone());
+ String& str2 = String::Handle(d->zone());
+ for (intptr_t i = start_index_; i < stop_index_; i++) {
+ str ^= refs.At(i);
+ str2 ^= table.InsertOrGet(str);
+ if (str.raw() == str2.raw()) {
+ str.SetCanonical();
+ } else {
+ refs.SetAt(i, str2);
+ }
+ }
+ d->isolate_group()->object_store()->set_symbol_table(table.Release());
+ }
+ }
+};
+
+class OneByteStringDeserializationCluster
+ : public StringDeserializationCluster {
public:
OneByteStringDeserializationCluster()
- : DeserializationCluster("OneByteString") {}
+ : StringDeserializationCluster("OneByteString") {}
~OneByteStringDeserializationCluster() {}
- void ReadAlloc(Deserializer* d, bool is_canonical) {
+ void ReadAlloc(Deserializer* d, bool stamp_canonical) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
const intptr_t count = d->ReadUnsigned();
@@ -4657,13 +4793,13 @@
stop_index_ = d->next_index();
}
- void ReadFill(Deserializer* d, bool is_canonical) {
+ void ReadFill(Deserializer* d, bool stamp_canonical) {
for (intptr_t id = start_index_; id < stop_index_; id++) {
OneByteStringPtr str = static_cast<OneByteStringPtr>(d->Ref(id));
const intptr_t length = d->ReadUnsigned();
Deserializer::InitializeHeader(str, kOneByteStringCid,
OneByteString::InstanceSize(length),
- is_canonical);
+ stamp_canonical);
str->ptr()->length_ = Smi::New(length);
StringHasher hasher;
for (intptr_t j = 0; j < length; j++) {
@@ -4674,21 +4810,6 @@
String::SetCachedHash(str, hasher.Finalize());
}
}
-
- void PostLoad(Deserializer* d, const Array& refs, bool is_canonical) {
- if (is_canonical && (d->isolate() != Dart::vm_isolate())) {
- CanonicalStringSet table(
- d->zone(), d->isolate_group()->object_store()->symbol_table());
- String& str = String::Handle(d->zone());
- for (intptr_t i = start_index_; i < stop_index_; i++) {
- str ^= refs.At(i);
- ASSERT(str.IsCanonical());
- bool present = table.Insert(str);
- ASSERT(!present);
- }
- d->isolate_group()->object_store()->set_symbol_table(table.Release());
- }
- }
};
#if !defined(DART_PRECOMPILED_RUNTIME)
@@ -4732,13 +4853,14 @@
};
#endif // !DART_PRECOMPILED_RUNTIME
-class TwoByteStringDeserializationCluster : public DeserializationCluster {
+class TwoByteStringDeserializationCluster
+ : public StringDeserializationCluster {
public:
TwoByteStringDeserializationCluster()
- : DeserializationCluster("TwoByteString") {}
+ : StringDeserializationCluster("TwoByteString") {}
~TwoByteStringDeserializationCluster() {}
- void ReadAlloc(Deserializer* d, bool is_canonical) {
+ void ReadAlloc(Deserializer* d, bool stamp_canonical) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
const intptr_t count = d->ReadUnsigned();
@@ -4750,13 +4872,13 @@
stop_index_ = d->next_index();
}
- void ReadFill(Deserializer* d, bool is_canonical) {
+ void ReadFill(Deserializer* d, bool stamp_canonical) {
for (intptr_t id = start_index_; id < stop_index_; id++) {
TwoByteStringPtr str = static_cast<TwoByteStringPtr>(d->Ref(id));
const intptr_t length = d->ReadUnsigned();
Deserializer::InitializeHeader(str, kTwoByteStringCid,
TwoByteString::InstanceSize(length),
- is_canonical);
+ stamp_canonical);
str->ptr()->length_ = Smi::New(length);
StringHasher hasher;
for (intptr_t j = 0; j < length; j++) {
@@ -4768,21 +4890,6 @@
String::SetCachedHash(str, hasher.Finalize());
}
}
-
- void PostLoad(Deserializer* d, const Array& refs, bool is_canonical) {
- if (is_canonical && (d->isolate() != Dart::vm_isolate())) {
- CanonicalStringSet table(
- d->zone(), d->isolate_group()->object_store()->symbol_table());
- String& str = String::Handle(d->zone());
- for (intptr_t i = start_index_; i < stop_index_; i++) {
- str ^= refs.At(i);
- ASSERT(str.IsCanonical());
- bool present = table.Insert(str);
- ASSERT(!present);
- }
- d->isolate_group()->object_store()->set_symbol_table(table.Release());
- }
- }
};
#if !defined(DART_PRECOMPILED_RUNTIME)
@@ -5162,6 +5269,9 @@
const Object* deferred_object = (*unit_->deferred_objects())[i];
ASSERT(deferred_object->IsCode());
CodePtr code = static_cast<CodePtr>(deferred_object->raw());
+ if (!FLAG_use_bare_instructions) {
+ s->Push(code->ptr()->object_pool_);
+ }
s->Push(code->ptr()->compressed_stackmaps_);
s->Push(code->ptr()->code_source_map_);
}
@@ -5191,6 +5301,9 @@
ASSERT(s->RefId(code) == (start_index + i));
s->WriteInstructions(code->ptr()->instructions_,
code->ptr()->unchecked_offset_, code, false);
+ if (!FLAG_use_bare_instructions) {
+ s->WriteRootRef(code->ptr()->object_pool_, "deferred-code");
+ }
s->WriteRootRef(code->ptr()->compressed_stackmaps_, "deferred-code");
s->WriteRootRef(code->ptr()->code_source_map_, "deferred-code");
}
@@ -5229,10 +5342,19 @@
ASSERT(unchecked_entry_point != 0);
func->ptr()->unchecked_entry_point_ = unchecked_entry_point;
}
+ if (!FLAG_use_bare_instructions) {
+ code->ptr()->object_pool_ = static_cast<ObjectPoolPtr>(d->ReadRef());
+ }
code->ptr()->compressed_stackmaps_ =
static_cast<CompressedStackMapsPtr>(d->ReadRef());
code->ptr()->code_source_map_ =
static_cast<CodeSourceMapPtr>(d->ReadRef());
+
+ // TODO(rmacnak): Should we finalize any pending GC before deserializing
+ // instead?
+ if (d->thread()->is_marking()) {
+ d->thread()->DeferredMarkingStackAddObject(code);
+ }
}
// Reinitialize the dispatch table by rereading the table's serialization
@@ -5647,6 +5769,9 @@
// TODO(41974): Are these always type testing stubs?
unit_id = LoadingUnit::kRootId;
}
+ if (unit_id == LoadingUnit::kRootId) {
+ return true;
+ }
if (unit_id != current_loading_unit_id_) {
if (record) {
(*loading_units_)[unit_id]->AddDeferredObject(static_cast<CodePtr>(obj));
@@ -5869,6 +5994,22 @@
}
GrowableArray<SerializationCluster*> canonical_clusters;
+ // The order that PostLoad runs matters for some classes. Explicitly place
+ // these clusters first, then add the rest ordered by class id.
+#define ADD_NEXT(cid) \
+ if (canonical_clusters_by_cid_[cid] != nullptr) { \
+ canonical_clusters.Add(canonical_clusters_by_cid_[cid]); \
+ canonical_clusters_by_cid_[cid] = nullptr; \
+ }
+ ADD_NEXT(kOneByteStringCid)
+ ADD_NEXT(kTwoByteStringCid)
+ ADD_NEXT(kMintCid)
+ ADD_NEXT(kDoubleCid)
+ ADD_NEXT(kTypeParameterCid)
+ ADD_NEXT(kTypeCid)
+ ADD_NEXT(kTypeArgumentsCid)
+ ADD_NEXT(kClosureCid)
+#undef ADD_NEXT
for (intptr_t cid = 0; cid < num_cids_; cid++) {
if (canonical_clusters_by_cid_[cid] != nullptr) {
canonical_clusters.Add(canonical_clusters_by_cid_[cid]);
@@ -6690,18 +6831,17 @@
ASSERT_EQUAL(next_ref_index_ - kFirstReference, num_objects_);
{
- TIMELINE_DURATION(thread(), Isolate, "ReadFill");
+ TIMELINE_DURATION(thread(), Isolate, "PostLoad");
for (intptr_t i = 0; i < num_canonical_clusters_; i++) {
- TIMELINE_DURATION(thread(), Isolate, canonical_clusters_[i]->name());
- canonical_clusters_[i]->ReadFill(this, /*is_canonical*/ true);
+ bool stamp_canonical = isolate() == Dart::vm_isolate();
+ canonical_clusters_[i]->ReadFill(this, stamp_canonical);
#if defined(DEBUG)
int32_t section_marker = Read<int32_t>();
ASSERT(section_marker == kSectionMarker);
#endif
}
for (intptr_t i = 0; i < num_clusters_; i++) {
- TIMELINE_DURATION(thread(), Isolate, clusters_[i]->name());
- clusters_[i]->ReadFill(this, /*is_canonical*/ false);
+ clusters_[i]->ReadFill(this, /*stamp_canonical*/ false);
#if defined(DEBUG)
int32_t section_marker = Read<int32_t>();
ASSERT(section_marker == kSectionMarker);
@@ -6723,26 +6863,22 @@
roots->PostLoad(this, refs);
#if defined(DEBUG)
- Isolate* isolate = thread()->isolate();
- isolate->ValidateClassTable();
- if (isolate != Dart::vm_isolate()) {
- isolate->group()->heap()->Verify();
+ isolate()->ValidateClassTable();
+ if (isolate() != Dart::vm_isolate()) {
+ isolate_group()->heap()->Verify();
}
#endif
- // TODO(rmacnak): When splitting literals, load clusters requiring
- // canonicalization first, canonicalize and update the ref array, the load
- // the remaining clusters to avoid a full heap walk to update references to
- // the losers of any canonicalization races.
{
TIMELINE_DURATION(thread(), Isolate, "PostLoad");
for (intptr_t i = 0; i < num_canonical_clusters_; i++) {
TIMELINE_DURATION(thread(), Isolate, canonical_clusters_[i]->name());
- canonical_clusters_[i]->PostLoad(this, refs, /*is_canonical*/ true);
+ bool canonicalize = isolate() != Dart::vm_isolate();
+ canonical_clusters_[i]->PostLoad(this, refs, canonicalize);
}
for (intptr_t i = 0; i < num_clusters_; i++) {
TIMELINE_DURATION(thread(), Isolate, clusters_[i]->name());
- clusters_[i]->PostLoad(this, refs, /*is_canonical*/ false);
+ clusters_[i]->PostLoad(this, refs, /*canonicalize*/ false);
}
}
}
diff --git a/runtime/vm/clustered_snapshot.h b/runtime/vm/clustered_snapshot.h
index 07a7b1e..d3471b6 100644
--- a/runtime/vm/clustered_snapshot.h
+++ b/runtime/vm/clustered_snapshot.h
@@ -116,16 +116,20 @@
// Allocate memory for all objects in the cluster and write their addresses
// into the ref array. Do not touch this memory.
- virtual void ReadAlloc(Deserializer* deserializer, bool is_canonical) = 0;
+ virtual void ReadAlloc(Deserializer* deserializer, bool stamp_canonical) = 0;
// Initialize the cluster's objects. Do not touch the memory of other objects.
- virtual void ReadFill(Deserializer* deserializer, bool is_canonical) = 0;
+ virtual void ReadFill(Deserializer* deserializer, bool stamp_canonical) = 0;
// Complete any action that requires the full graph to be deserialized, such
// as rehashing.
virtual void PostLoad(Deserializer* deserializer,
const Array& refs,
- bool is_canonical) {}
+ bool canonicalize) {
+ if (canonicalize) {
+ FATAL1("%s needs canonicalization but doesn't define PostLoad", name());
+ }
+ }
const char* name() const { return name_; }
@@ -380,6 +384,7 @@
void set_loading_units(GrowableArray<LoadingUnitSerializationData*>* units) {
loading_units_ = units;
}
+ intptr_t current_loading_unit_id() { return current_loading_unit_id_; }
void set_current_loading_unit_id(intptr_t id) {
current_loading_unit_id_ = id;
}
@@ -573,6 +578,8 @@
uword ReadWordWith32BitReads() { return stream_.ReadWordWith32BitReads(); }
+ intptr_t position() const { return stream_.Position(); }
+ void set_position(intptr_t p) { stream_.SetPosition(p); }
const uint8_t* CurrentBufferAddress() const {
return stream_.AddressOfCurrentPosition();
}
diff --git a/runtime/vm/compiler/backend/il_arm.cc b/runtime/vm/compiler/backend/il_arm.cc
index 5ff3ed1..e354b26 100644
--- a/runtime/vm/compiler/backend/il_arm.cc
+++ b/runtime/vm/compiler/backend/il_arm.cc
@@ -5530,9 +5530,9 @@
__ vcvtsd(r.s(1), q.d(1));
}
-// Low (< 7) Q registers are needed for the vcvtsd instruction.
+// Low (< 7) Q registers are needed for the vcvtds instruction.
// TODO(dartbug.com/30953) support register range constraints in the regalloc.
-DEFINE_EMIT(Float32x4ToFloat64x2, (FixedQRegisterView<Q6> r, QRegisterView q)) {
+DEFINE_EMIT(Float32x4ToFloat64x2, (QRegisterView r, FixedQRegisterView<Q6> q)) {
// Set X.
__ vcvtds(r.d(0), q.s(0));
// Set Y.
diff --git a/runtime/vm/compiler/runtime_offsets_extracted.h b/runtime/vm/compiler/runtime_offsets_extracted.h
index eb7276a..30ae528 100644
--- a/runtime/vm/compiler/runtime_offsets_extracted.h
+++ b/runtime/vm/compiler/runtime_offsets_extracted.h
@@ -86,7 +86,7 @@
static constexpr dart::compiler::target::word Array_tags_offset = 0;
static constexpr dart::compiler::target::word Array_type_arguments_offset = 4;
static constexpr dart::compiler::target::word Class_declaration_type_offset =
- 52;
+ 48;
static constexpr dart::compiler::target::word Class_num_type_arguments_offset =
88;
static constexpr dart::compiler::target::word Class_super_type_offset = 44;
@@ -611,7 +611,7 @@
static constexpr dart::compiler::target::word Array_tags_offset = 0;
static constexpr dart::compiler::target::word Array_type_arguments_offset = 8;
static constexpr dart::compiler::target::word Class_declaration_type_offset =
- 104;
+ 96;
static constexpr dart::compiler::target::word Class_num_type_arguments_offset =
164;
static constexpr dart::compiler::target::word Class_super_type_offset = 88;
@@ -1140,7 +1140,7 @@
static constexpr dart::compiler::target::word Array_tags_offset = 0;
static constexpr dart::compiler::target::word Array_type_arguments_offset = 4;
static constexpr dart::compiler::target::word Class_declaration_type_offset =
- 52;
+ 48;
static constexpr dart::compiler::target::word Class_num_type_arguments_offset =
88;
static constexpr dart::compiler::target::word Class_super_type_offset = 44;
@@ -1662,7 +1662,7 @@
static constexpr dart::compiler::target::word Array_tags_offset = 0;
static constexpr dart::compiler::target::word Array_type_arguments_offset = 8;
static constexpr dart::compiler::target::word Class_declaration_type_offset =
- 104;
+ 96;
static constexpr dart::compiler::target::word Class_num_type_arguments_offset =
164;
static constexpr dart::compiler::target::word Class_super_type_offset = 88;
@@ -2194,7 +2194,7 @@
static constexpr dart::compiler::target::word Array_tags_offset = 0;
static constexpr dart::compiler::target::word Array_type_arguments_offset = 4;
static constexpr dart::compiler::target::word Class_declaration_type_offset =
- 52;
+ 48;
static constexpr dart::compiler::target::word Class_num_type_arguments_offset =
88;
static constexpr dart::compiler::target::word Class_super_type_offset = 44;
@@ -2713,7 +2713,7 @@
static constexpr dart::compiler::target::word Array_tags_offset = 0;
static constexpr dart::compiler::target::word Array_type_arguments_offset = 8;
static constexpr dart::compiler::target::word Class_declaration_type_offset =
- 104;
+ 96;
static constexpr dart::compiler::target::word Class_num_type_arguments_offset =
164;
static constexpr dart::compiler::target::word Class_super_type_offset = 88;
@@ -3236,7 +3236,7 @@
static constexpr dart::compiler::target::word Array_tags_offset = 0;
static constexpr dart::compiler::target::word Array_type_arguments_offset = 4;
static constexpr dart::compiler::target::word Class_declaration_type_offset =
- 52;
+ 48;
static constexpr dart::compiler::target::word Class_num_type_arguments_offset =
88;
static constexpr dart::compiler::target::word Class_super_type_offset = 44;
@@ -3752,7 +3752,7 @@
static constexpr dart::compiler::target::word Array_tags_offset = 0;
static constexpr dart::compiler::target::word Array_type_arguments_offset = 8;
static constexpr dart::compiler::target::word Class_declaration_type_offset =
- 104;
+ 96;
static constexpr dart::compiler::target::word Class_num_type_arguments_offset =
164;
static constexpr dart::compiler::target::word Class_super_type_offset = 88;
@@ -4280,7 +4280,7 @@
static constexpr dart::compiler::target::word AOT_Array_type_arguments_offset =
4;
static constexpr dart::compiler::target::word
- AOT_Class_declaration_type_offset = 52;
+ AOT_Class_declaration_type_offset = 48;
static constexpr dart::compiler::target::word
AOT_Class_num_type_arguments_offset = 88;
static constexpr dart::compiler::target::word AOT_Class_super_type_offset = 44;
@@ -4864,7 +4864,7 @@
static constexpr dart::compiler::target::word AOT_Array_type_arguments_offset =
8;
static constexpr dart::compiler::target::word
- AOT_Class_declaration_type_offset = 104;
+ AOT_Class_declaration_type_offset = 96;
static constexpr dart::compiler::target::word
AOT_Class_num_type_arguments_offset = 164;
static constexpr dart::compiler::target::word AOT_Class_super_type_offset = 88;
@@ -5454,7 +5454,7 @@
static constexpr dart::compiler::target::word AOT_Array_type_arguments_offset =
8;
static constexpr dart::compiler::target::word
- AOT_Class_declaration_type_offset = 104;
+ AOT_Class_declaration_type_offset = 96;
static constexpr dart::compiler::target::word
AOT_Class_num_type_arguments_offset = 164;
static constexpr dart::compiler::target::word AOT_Class_super_type_offset = 88;
@@ -6043,7 +6043,7 @@
static constexpr dart::compiler::target::word AOT_Array_type_arguments_offset =
4;
static constexpr dart::compiler::target::word
- AOT_Class_declaration_type_offset = 52;
+ AOT_Class_declaration_type_offset = 48;
static constexpr dart::compiler::target::word
AOT_Class_num_type_arguments_offset = 88;
static constexpr dart::compiler::target::word AOT_Class_super_type_offset = 44;
@@ -6620,7 +6620,7 @@
static constexpr dart::compiler::target::word AOT_Array_type_arguments_offset =
8;
static constexpr dart::compiler::target::word
- AOT_Class_declaration_type_offset = 104;
+ AOT_Class_declaration_type_offset = 96;
static constexpr dart::compiler::target::word
AOT_Class_num_type_arguments_offset = 164;
static constexpr dart::compiler::target::word AOT_Class_super_type_offset = 88;
@@ -7203,7 +7203,7 @@
static constexpr dart::compiler::target::word AOT_Array_type_arguments_offset =
8;
static constexpr dart::compiler::target::word
- AOT_Class_declaration_type_offset = 104;
+ AOT_Class_declaration_type_offset = 96;
static constexpr dart::compiler::target::word
AOT_Class_num_type_arguments_offset = 164;
static constexpr dart::compiler::target::word AOT_Class_super_type_offset = 88;
diff --git a/runtime/vm/instructions_arm64.cc b/runtime/vm/instructions_arm64.cc
index 80ee77a..1ebd214 100644
--- a/runtime/vm/instructions_arm64.cc
+++ b/runtime/vm/instructions_arm64.cc
@@ -53,8 +53,8 @@
native_function_pool_index_(-1),
target_code_pool_index_(-1) {
ASSERT(code.ContainsInstructionAt(pc));
- // Last instruction: blr ip0.
- ASSERT(*(reinterpret_cast<uint32_t*>(end_) - 1) == 0xd63f0200);
+ // Last instruction: blr lr.
+ ASSERT(*(reinterpret_cast<uint32_t*>(end_) - 1) == 0xd63f03c0);
Register reg;
uword native_function_load_end = InstructionPattern::DecodeLoadWordFromPool(
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 36a2155..a220f97 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -20132,9 +20132,11 @@
}
}
ASSERT(this->Equals(type));
- ASSERT(type.IsCanonical());
- ASSERT(type.IsOld());
- return type.raw();
+ // TODO(rmacnak): Revisit immediately returning type after to changes to
+ // recanonicalization on load for literal splitting.
+ if (type.IsCanonical()) {
+ return type.raw();
+ }
}
Type& type = Type::Handle(zone);
diff --git a/runtime/vm/program_visitor.cc b/runtime/vm/program_visitor.cc
index aecd13b..6e81fb3 100644
--- a/runtime/vm/program_visitor.cc
+++ b/runtime/vm/program_visitor.cc
@@ -1371,9 +1371,15 @@
MergeAssignment(obj_, id);
obj_ = code.compressed_stackmaps();
MergeAssignment(obj_, id);
+ if (!FLAG_use_bare_instructions) {
+ obj_ = code.object_pool();
+ MergeAssignment(obj_, id);
+ }
}
void MergeAssignment(const Object& obj, intptr_t id) {
+ if (obj.IsNull()) return;
+
intptr_t old_id = heap_->GetLoadingUnit(obj_.raw());
if (old_id == WeakTable::kNoValue) {
heap_->SetLoadingUnit(obj_.raw(), id);
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 06e736a..5b4a2fd 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -819,8 +819,6 @@
POINTER_FIELD(LibraryPtr, library)
POINTER_FIELD(TypeArgumentsPtr, type_parameters) // Array of TypeParameter.
POINTER_FIELD(AbstractTypePtr, super_type)
- POINTER_FIELD(ArrayPtr,
- constants) // Canonicalized const instances of this class.
POINTER_FIELD(TypePtr, declaration_type) // Declaration type for this class.
POINTER_FIELD(ArrayPtr,
invocation_dispatcher_cache) // Cache for dispatcher functions.
@@ -830,7 +828,9 @@
direct_implementors) // Array of Class.
POINTER_FIELD(GrowableObjectArrayPtr, direct_subclasses) // Array of Class.
POINTER_FIELD(ArrayPtr, dependent_code) // CHA optimized codes.
- VISIT_TO(ObjectPtr, dependent_code)
+ POINTER_FIELD(ArrayPtr,
+ constants) // Canonicalized const instances of this class.
+ VISIT_TO(ObjectPtr, constants)
ObjectPtr* to_snapshot(Snapshot::Kind kind) {
switch (kind) {
case Snapshot::kFullAOT:
diff --git a/tests/dart2js/native/bound_closure_super_test.dart b/tests/dart2js/native/bound_closure_super_test.dart
deleted file mode 100644
index d97d8e1..0000000
--- a/tests/dart2js/native/bound_closure_super_test.dart
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (c) 2013, 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.
-
-// Test calling convention of property extraction closures (super edition).
-library bound_closure_super_test;
-
-import 'package:expect/expect.dart';
-
-import 'bound_closure_test.dart' as bound_closure_test;
-
-import 'bound_closure_test.dart' show inscrutable, makeCC;
-
-main() {
- // Calling main from bound_closure_test.dart to set up native code.
- bound_closure_test.main();
-
- var c = inscrutable(makeCC)();
- var csfoo = inscrutable(c).superfoo;
-
- Expect.equals('BB.foo(1, B)', csfoo(1));
- Expect.equals('BB.foo(2, 3)', csfoo(2, 3));
-}
diff --git a/tests/dart2js_2/native/bound_closure_super_test.dart b/tests/dart2js_2/native/bound_closure_super_test.dart
deleted file mode 100644
index 67c36ed..0000000
--- a/tests/dart2js_2/native/bound_closure_super_test.dart
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) 2013, 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.
-
-// @dart = 2.7
-
-// Test calling convention of property extraction closures (super edition).
-library bound_closure_super_test;
-
-import 'package:expect/expect.dart';
-
-import 'bound_closure_test.dart' as bound_closure_test;
-
-import 'bound_closure_test.dart' show inscrutable, makeCC;
-
-main() {
- // Calling main from bound_closure_test.dart to set up native code.
- bound_closure_test.main();
-
- var c = inscrutable(makeCC)();
- var csfoo = inscrutable(c).superfoo;
-
- Expect.equals('BB.foo(1, B)', csfoo(1));
- Expect.equals('BB.foo(2, 3)', csfoo(2, 3));
-}
diff --git a/tests/language/nnbd/flow_analysis/boolean_parameter_test.dart b/tests/language/nnbd/flow_analysis/boolean_parameter_test.dart
new file mode 100644
index 0000000..e0f753c
--- /dev/null
+++ b/tests/language/nnbd/flow_analysis/boolean_parameter_test.dart
@@ -0,0 +1,141 @@
+// 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 '../../static_type_helper.dart';
+
+// This test checks whether a function parameter can be used to perform type
+// promotion, for various ways of declaring it.
+//
+// We test all combinations of:
+// - top level function, method, local named function, or function expression
+// - type `bool`, `Object`, `Object?`, or `dynamic`
+
+topLevelFunction_bool(int? x, bool b) {
+ b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+}
+
+topLevelFunction_Object(int? x, Object b) {
+ b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+}
+
+topLevelFunction_ObjectQ(int? x, Object? b) {
+ b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+}
+
+topLevelFunction_dynamic(int? x, dynamic b) {
+ b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+}
+
+class C {
+ method_bool(int? x, bool b) {
+ b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+
+ method_Object(int? x, Object b) {
+ b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+
+ method_ObjectQ(int? x, Object? b) {
+ b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+
+ method_dynamic(int? x, dynamic b) {
+ b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+}
+
+localTest(int? x) {
+ localNamedFunction_bool(bool b) {
+ b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+
+ localNamedFunction_bool(false);
+
+ localNamedFunction_Object(Object b) {
+ b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+
+ localNamedFunction_Object(Object());
+
+ localNamedFunction_ObjectQ(Object? b) {
+ b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+
+ localNamedFunction_ObjectQ(null);
+
+ localNamedFunction_dynamic(dynamic b) {
+ b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+
+ localNamedFunction_dynamic('foo');
+
+ (bool b) {
+ b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ }(false);
+
+ (Object b) {
+ b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }(Object());
+
+ (Object? b) {
+ b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }(null);
+
+ (dynamic b) {
+ b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ }('foo');
+}
+
+main() {
+ topLevelFunction_bool(null, false);
+ topLevelFunction_bool(0, false);
+ topLevelFunction_Object(null, Object());
+ topLevelFunction_Object(0, Object());
+ topLevelFunction_ObjectQ(null, null);
+ topLevelFunction_ObjectQ(0, null);
+ topLevelFunction_dynamic(null, 'foo');
+ topLevelFunction_dynamic(0, 'foo');
+ C().method_bool(null, false);
+ C().method_bool(0, false);
+ C().method_Object(null, Object());
+ C().method_Object(0, Object());
+ C().method_ObjectQ(null, null);
+ C().method_ObjectQ(0, null);
+ C().method_dynamic(null, 'foo');
+ C().method_dynamic(0, 'foo');
+ localTest(null);
+ localTest(0);
+}
diff --git a/tests/language/nnbd/flow_analysis/local_boolean_compound_assignment_test.dart b/tests/language/nnbd/flow_analysis/local_boolean_compound_assignment_test.dart
new file mode 100644
index 0000000..b76b066
--- /dev/null
+++ b/tests/language/nnbd/flow_analysis/local_boolean_compound_assignment_test.dart
@@ -0,0 +1,251 @@
+// 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 '../../static_type_helper.dart';
+
+// This test checks that local boolean variables cannot be used to perform type
+// promotion in the presence of compound assignments.
+//
+// We test the following kinds of compound assignments:
+// - Ordinary (e.g. `+=`)
+// - Prefix increment/decrement (e.g. `++<variable>`)
+// - Postfix increment/decrement (e.g. `<variable>++`)
+// - Null-aware (`??=`)
+//
+// We test both the side effect of the assignment and the evaluated value of the
+// assignment expression.
+
+testSideEffect(int? x) {
+ {
+ dynamic b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ b /= x != null;
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ dynamic b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ b ~/= x != null;
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ dynamic b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ b %= x != null;
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ dynamic b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ b += x != null;
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ dynamic b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ b -= x != null;
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ dynamic b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ b <<= x != null;
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ dynamic b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ b >>= x != null;
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ dynamic b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ b &= x != null;
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ dynamic b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ b ^= x != null;
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ dynamic b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ b |= x != null;
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ dynamic b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ b ??= x != null;
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ dynamic b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ ++b;
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ dynamic b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ --b;
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ dynamic b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ b++;
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ dynamic b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ b--;
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+}
+
+testValue(int? x) {
+ {
+ dynamic b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ if (b /= x != null) {
+ x.expectStaticType<Exactly<int?>>();
+ }
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ dynamic b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ if (b ~/= x != null) {
+ x.expectStaticType<Exactly<int?>>();
+ }
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ dynamic b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ if (b %= x != null) {
+ x.expectStaticType<Exactly<int?>>();
+ }
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ dynamic b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ if (b += x != null) {
+ x.expectStaticType<Exactly<int?>>();
+ }
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ dynamic b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ if (b -= x != null) {
+ x.expectStaticType<Exactly<int?>>();
+ }
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ dynamic b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ if (b <<= x != null) {
+ x.expectStaticType<Exactly<int?>>();
+ }
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ dynamic b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ if (b >>= x != null) {
+ x.expectStaticType<Exactly<int?>>();
+ }
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ dynamic b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ if (b &= x != null) {
+ x.expectStaticType<Exactly<int?>>();
+ }
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ dynamic b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ if (b ^= x != null) {
+ x.expectStaticType<Exactly<int?>>();
+ }
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ dynamic b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ if (b |= x != null) {
+ x.expectStaticType<Exactly<int?>>();
+ }
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ dynamic b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ if (b ??= x != null) {
+ x.expectStaticType<Exactly<int?>>();
+ }
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ dynamic b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ if (++b) {
+ x.expectStaticType<Exactly<int?>>();
+ }
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ dynamic b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ if (--b) {
+ x.expectStaticType<Exactly<int?>>();
+ }
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ dynamic b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ if (b++) {
+ // Note: arguably we could promote here (since the value of `b++` is the
+ // same as the value that `b` had before the "increment") but given that
+ // incrementing booleans doesn't work at runtime anyhow, it doesn't seem
+ // worth it.
+ x.expectStaticType<Exactly<int?>>();
+ }
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ dynamic b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ if (b--) {
+ // Note: arguably we could promote here (since the value of `b--` is the
+ // same as the value that `b` had before the "decrement") but given that
+ // decrementing booleans doesn't work at runtime anyhow, it doesn't seem
+ // worth it.
+ x.expectStaticType<Exactly<int?>>();
+ }
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+}
+
+bool _alwaysFalse() => false;
+
+main() {
+ // Because of the use of dynamic in these tests, they're not expected to
+ // succeed at runtime; we just want to check the compile-time behavior. So we
+ // reference the test functions but don't call them.
+ if (_alwaysFalse()) testSideEffect(0);
+ if (_alwaysFalse()) testValue(0);
+}
diff --git a/tests/language/nnbd/flow_analysis/local_boolean_defeated_by_assignment_test.dart b/tests/language/nnbd/flow_analysis/local_boolean_defeated_by_assignment_test.dart
new file mode 100644
index 0000000..649155a
--- /dev/null
+++ b/tests/language/nnbd/flow_analysis/local_boolean_defeated_by_assignment_test.dart
@@ -0,0 +1,642 @@
+// 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 '../../static_type_helper.dart';
+
+// This test checks various scenarios in which the use of a local variable for
+// type promotion is defeated, either by an assignment to the local variable
+// itself or an assignment to the variable that would be promoted.
+
+direct_toConditionVar(int? x) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ b = true;
+ if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+direct_toPromotedVar(int? x, int? y) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ x = y;
+ if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+lateInitializer_toConditionalVar(int? x) {
+ bool b = x != null;
+ late final y = b ? x.expectStaticType<Exactly<int?>>() : 3;
+ b = true;
+}
+
+lateInitializer_toPromotedVar(int? x, int? y) {
+ bool b = x != null;
+ late final y = b ? x.expectStaticType<Exactly<int?>>() : 3;
+ x = y;
+}
+
+afterConditionalThen_toConditionVar(int? x, bool b2) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ b2 ? b = true : null;
+ if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterConditionalThen_toPromotedVar(int? x, bool b2, int? y) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ b2 ? x = y : null;
+ if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterConditionalElse_toConditionVar(int? x, bool b2) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ b2 ? null : b = true;
+ if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterConditionalElse_toPromotedVar(int? x, bool b2, int? y) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ b2 ? null : x = y;
+ if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterIfStatementThen_toConditionVar(int? x, bool b2) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ if (b2) b = true;
+ if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterIfStatementThen_toPromotedVar(int? x, bool b2, int? y) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ if (b2) x = y;
+ if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterIfStatementElse_toConditionVar(int? x, bool b2) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ if (b2) {
+ } else {
+ b = true;
+ }
+ if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterIfStatementElse_toPromotedVar(int? x, bool b2, int? y) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ if (b2) {
+ } else {
+ x = y;
+ }
+ if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterIfListThen_toConditionVar(int? x, bool b2) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ [if (b2) b = true];
+ if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterIfListThen_toPromotedVar(int? x, bool b2, int? y) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ [if (b2) x = y];
+ if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterIfListElse_toConditionVar(int? x, bool b2) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ [if (b2) null else b = true];
+ if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterIfListElse_toPromotedVar(int? x, bool b2, int? y) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ [if (b2) null else x = y];
+ if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterIfSetThen_toConditionVar(int? x, bool b2) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ ({if (b2) b = true});
+ if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterIfSetThen_toPromotedVar(int? x, bool b2, int? y) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ ({if (b2) x = y});
+ if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterIfSetElse_toConditionVar(int? x, bool b2) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ ({if (b2) null else b = true});
+ if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterIfSetElse_toPromotedVar(int? x, bool b2, int? y) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ ({if (b2) null else x = y});
+ if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterIfMapKeyThen_toConditionVar(int? x, bool b2) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ ({if (b2) b = true: null});
+ if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterIfMapKeyThen_toPromotedVar(int? x, bool b2, int? y) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ ({if (b2) x = y: null});
+ if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterIfMapKeyElse_toConditionVar(int? x, bool b2) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ ({if (b2) null: null else b = true: null});
+ if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterIfMapKeyElse_toPromotedVar(int? x, bool b2, int? y) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ ({if (b2) null: null else x = y: null});
+ if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterIfMapValueThen_toConditionVar(int? x, bool b2) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ ({if (b2) null: b = true});
+ if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterIfMapValueThen_toPromotedVar(int? x, bool b2, int? y) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ ({if (b2) null: x = y});
+ if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterIfMapValueElse_toConditionVar(int? x, bool b2) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ ({if (b2) null: null else null: b = true});
+ if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterIfMapValueElse_toPromotedVar(int? x, bool b2, int? y) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ ({if (b2) null: null else null: x = y});
+ if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+doLater_toConditionalVar(int? x, int i) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ do {
+ if (b) x.expectStaticType<Exactly<int?>>();
+ b = true;
+ } while (i-- > 0);
+}
+
+doLater_toPromotedVar(int? x, int i, int? y) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ do {
+ if (b) x.expectStaticType<Exactly<int?>>();
+ x = y;
+ } while (i-- > 0);
+}
+
+forLater_toConditionalVar(int? x, int i) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ for (int j = 0; j < i; j++) {
+ if (b) x.expectStaticType<Exactly<int?>>();
+ b = true;
+ }
+}
+
+forLater_toPromotedVar(int? x, int i, int? y) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ for (int j = 0; j < i; j++) {
+ if (b) x.expectStaticType<Exactly<int?>>();
+ x = y;
+ }
+}
+
+forEachLater_toConditionalVar(int? x) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ for (var v in [null]) {
+ if (b) x.expectStaticType<Exactly<int?>>();
+ b = true;
+ }
+}
+
+forEachLater_toPromotedVar(int? x, int? y) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ for (var v in [null]) {
+ if (b) x.expectStaticType<Exactly<int?>>();
+ x = y;
+ }
+}
+
+whileLater_toConditionalVar(int? x, int i) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ while (i-- > 0) {
+ if (b) x.expectStaticType<Exactly<int?>>();
+ b = true;
+ }
+}
+
+whileLater_toPromotedVar(int? x, int i, int? y) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ while (i-- > 0) {
+ if (b) x.expectStaticType<Exactly<int?>>();
+ x = y;
+ }
+}
+
+switchLaterLabeled_toConditionalVar(int? x, int i) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ switch (i) {
+ L:
+ case 0:
+ if (b) x.expectStaticType<Exactly<int?>>();
+ break;
+ case 1:
+ b = true;
+ continue L;
+ }
+}
+
+switchLaterLabeled_toPromotedVar(int? x, int i, int? y) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ switch (i) {
+ L:
+ case 0:
+ if (b) x.expectStaticType<Exactly<int?>>();
+ break;
+ case 1:
+ x = y;
+ continue L;
+ }
+}
+
+afterDo_toConditionalVar(int? x, int i) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ do {
+ b = true;
+ } while (i-- > 0);
+ if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterDo_toPromotedVar(int? x, int i, int? y) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ do {
+ x = y;
+ } while (i-- > 0);
+ if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterFor_toConditionalVar(int? x, int i) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ for (int j = 0; j < i; j++) {
+ b = true;
+ }
+ if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterFor_toPromotedVar(int? x, int i, int? y) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ for (int j = 0; j < i; j++) {
+ x = y;
+ }
+ if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterForEach_toConditionalVar(int? x, Iterable i) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ for (var v in i) {
+ b = true;
+ }
+ if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterForEach_toPromotedVar(int? x, Iterable i, int? y) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ for (var v in i) {
+ x = y;
+ }
+ if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterWhile_toConditionalVar(int? x, int i) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ while (i-- > 0) {
+ b = true;
+ }
+ if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterWhile_toPromotedVar(int? x, int i, int? y) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ while (i-- > 0) {
+ x = y;
+ }
+ if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterSwitch_toConditionalVar(int? x, int i) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ switch (i) {
+ case 0:
+ b = true;
+ break;
+ case 1:
+ break;
+ }
+ if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterSwitch_toPromotedVar(int? x, int i, int? y) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ switch (i) {
+ case 0:
+ x = y;
+ break;
+ case 1:
+ break;
+ }
+ if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+tryCatchCatch_toConditionalVar(int? x) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ try {
+ b = true;
+ } catch (_) {
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+}
+
+tryCatchCatch_toPromotedVar(int? x, int? y) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ try {
+ x = y;
+ } catch (_) {
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+}
+
+afterTryCatchTry_toConditionalVar(int? x) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ try {
+ b = true;
+ } catch (_) {}
+ if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterTryCatchTry_toPromotedVar(int? x, int? y) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ try {
+ x = y;
+ } catch (_) {}
+ if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterTryCatchCatch_toConditionalVar(int? x) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ try {} catch (_) {
+ b = true;
+ }
+ if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterTryCatchCatch_toPromotedVar(int? x, int? y) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ try {} catch (_) {
+ x = y;
+ }
+ if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+tryFinallyFinally_toConditionalVar(int? x) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ try {
+ b = true;
+ } finally {
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+}
+
+tryFinallyFinally_toPromotedVar(int? x, int? y) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ try {
+ x = y;
+ } finally {
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+}
+
+afterTryFinallyTry_toConditionalVar(int? x) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ try {
+ b = true;
+ } finally {}
+ if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterTryFinallyTry_toPromotedVar(int? x, int? y) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ try {
+ x = y;
+ } finally {}
+ if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterTryFinallyFinally_toConditionalVar(int? x) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ try {} finally {
+ b = true;
+ }
+ if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+afterTryFinallyFinally_toPromotedVar(int? x, int? y) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ try {} finally {
+ x = y;
+ }
+ if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+main() {
+ direct_toConditionVar(0);
+ direct_toConditionVar(null);
+ direct_toPromotedVar(0, null);
+ direct_toPromotedVar(null, null);
+ lateInitializer_toConditionalVar(0);
+ lateInitializer_toConditionalVar(null);
+ lateInitializer_toPromotedVar(0, null);
+ lateInitializer_toPromotedVar(null, null);
+ afterConditionalThen_toConditionVar(0, true);
+ afterConditionalThen_toConditionVar(null, true);
+ afterConditionalThen_toPromotedVar(0, true, null);
+ afterConditionalThen_toPromotedVar(null, true, null);
+ afterConditionalElse_toConditionVar(0, false);
+ afterConditionalElse_toConditionVar(null, false);
+ afterConditionalElse_toPromotedVar(0, false, null);
+ afterConditionalElse_toPromotedVar(null, false, null);
+ afterIfStatementThen_toConditionVar(0, true);
+ afterIfStatementThen_toConditionVar(null, true);
+ afterIfStatementThen_toPromotedVar(0, true, null);
+ afterIfStatementThen_toPromotedVar(null, true, null);
+ afterIfStatementElse_toConditionVar(0, false);
+ afterIfStatementElse_toConditionVar(null, false);
+ afterIfStatementElse_toPromotedVar(0, false, null);
+ afterIfStatementElse_toPromotedVar(null, false, null);
+ afterIfListThen_toConditionVar(0, true);
+ afterIfListThen_toConditionVar(null, true);
+ afterIfListThen_toPromotedVar(0, true, null);
+ afterIfListThen_toPromotedVar(null, true, null);
+ afterIfListElse_toConditionVar(0, false);
+ afterIfListElse_toConditionVar(null, false);
+ afterIfListElse_toPromotedVar(0, false, null);
+ afterIfListElse_toPromotedVar(null, false, null);
+ afterIfSetThen_toConditionVar(0, true);
+ afterIfSetThen_toConditionVar(null, true);
+ afterIfSetThen_toPromotedVar(0, true, null);
+ afterIfSetThen_toPromotedVar(null, true, null);
+ afterIfSetElse_toConditionVar(0, false);
+ afterIfSetElse_toConditionVar(null, false);
+ afterIfSetElse_toPromotedVar(0, false, null);
+ afterIfSetElse_toPromotedVar(null, false, null);
+ afterIfMapKeyThen_toConditionVar(0, true);
+ afterIfMapKeyThen_toConditionVar(null, true);
+ afterIfMapKeyThen_toPromotedVar(0, true, null);
+ afterIfMapKeyThen_toPromotedVar(null, true, null);
+ afterIfMapKeyElse_toConditionVar(0, false);
+ afterIfMapKeyElse_toConditionVar(null, false);
+ afterIfMapKeyElse_toPromotedVar(0, false, null);
+ afterIfMapKeyElse_toPromotedVar(null, false, null);
+ afterIfMapValueThen_toConditionVar(0, true);
+ afterIfMapValueThen_toConditionVar(null, true);
+ afterIfMapValueThen_toPromotedVar(0, true, null);
+ afterIfMapValueThen_toPromotedVar(null, true, null);
+ afterIfMapValueElse_toConditionVar(0, false);
+ afterIfMapValueElse_toConditionVar(null, false);
+ afterIfMapValueElse_toPromotedVar(0, false, null);
+ afterIfMapValueElse_toPromotedVar(null, false, null);
+ doLater_toConditionalVar(0, 1);
+ doLater_toConditionalVar(null, 1);
+ doLater_toPromotedVar(0, 1, null);
+ doLater_toPromotedVar(null, 1, null);
+ forLater_toConditionalVar(0, 1);
+ forLater_toConditionalVar(null, 1);
+ forLater_toPromotedVar(0, 1, null);
+ forLater_toPromotedVar(null, 1, null);
+ forEachLater_toConditionalVar(0);
+ forEachLater_toConditionalVar(null);
+ forEachLater_toPromotedVar(0, null);
+ forEachLater_toPromotedVar(null, null);
+ whileLater_toConditionalVar(0, 1);
+ whileLater_toConditionalVar(null, 1);
+ whileLater_toPromotedVar(0, 1, null);
+ whileLater_toPromotedVar(null, 1, null);
+ switchLaterLabeled_toConditionalVar(0, 1);
+ switchLaterLabeled_toConditionalVar(null, 1);
+ switchLaterLabeled_toPromotedVar(0, 1, null);
+ switchLaterLabeled_toPromotedVar(null, 1, null);
+ afterDo_toConditionalVar(0, 1);
+ afterDo_toConditionalVar(null, 1);
+ afterDo_toPromotedVar(0, 1, null);
+ afterDo_toPromotedVar(null, 1, null);
+ afterFor_toConditionalVar(0, 1);
+ afterFor_toConditionalVar(null, 1);
+ afterFor_toPromotedVar(0, 1, null);
+ afterFor_toPromotedVar(null, 1, null);
+ afterForEach_toConditionalVar(0, [null]);
+ afterForEach_toConditionalVar(null, [null]);
+ afterForEach_toPromotedVar(0, [null], null);
+ afterForEach_toPromotedVar(null, [null], null);
+ afterWhile_toConditionalVar(0, 1);
+ afterWhile_toConditionalVar(null, 1);
+ afterWhile_toPromotedVar(0, 1, null);
+ afterWhile_toPromotedVar(null, 1, null);
+ afterSwitch_toConditionalVar(0, 0);
+ afterSwitch_toConditionalVar(null, 0);
+ afterSwitch_toPromotedVar(0, 0, null);
+ afterSwitch_toPromotedVar(null, 0, null);
+ tryCatchCatch_toConditionalVar(0);
+ tryCatchCatch_toConditionalVar(null);
+ tryCatchCatch_toPromotedVar(0, null);
+ tryCatchCatch_toPromotedVar(null, null);
+ afterTryCatchTry_toConditionalVar(0);
+ afterTryCatchTry_toConditionalVar(null);
+ afterTryCatchTry_toPromotedVar(0, null);
+ afterTryCatchTry_toPromotedVar(null, null);
+ afterTryCatchCatch_toConditionalVar(0);
+ afterTryCatchCatch_toConditionalVar(null);
+ afterTryCatchCatch_toPromotedVar(0, null);
+ afterTryCatchCatch_toPromotedVar(null, null);
+ tryFinallyFinally_toConditionalVar(0);
+ tryFinallyFinally_toConditionalVar(null);
+ tryFinallyFinally_toPromotedVar(0, null);
+ tryFinallyFinally_toPromotedVar(null, null);
+ afterTryFinallyTry_toConditionalVar(0);
+ afterTryFinallyTry_toConditionalVar(null);
+ afterTryFinallyTry_toPromotedVar(0, null);
+ afterTryFinallyTry_toPromotedVar(null, null);
+ afterTryFinallyFinally_toConditionalVar(0);
+ afterTryFinallyFinally_toConditionalVar(null);
+ afterTryFinallyFinally_toPromotedVar(0, null);
+ afterTryFinallyFinally_toPromotedVar(null, null);
+}
diff --git a/tests/language/nnbd/flow_analysis/local_boolean_defeated_by_capture_test.dart b/tests/language/nnbd/flow_analysis/local_boolean_defeated_by_capture_test.dart
new file mode 100644
index 0000000..b46d8c9
--- /dev/null
+++ b/tests/language/nnbd/flow_analysis/local_boolean_defeated_by_capture_test.dart
@@ -0,0 +1,79 @@
+// 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 '../../static_type_helper.dart';
+
+// This test checks various scenarios in which the use of a local variable for
+// type promotion is defeated by write capture of either the local variable
+// itself or the variable that would be promoted.
+
+capture_conditionVar_prior_to_assignment(int? x) {
+ bool b;
+ (bool b2) => b = b2;
+ b = x != null;
+ if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+capture_conditionVar_prior_to_assignment_from_other_condition(int? x) {
+ bool b1 = x != null;
+ bool b3;
+ (bool b2) => b3 = b2;
+ b3 = b1;
+ if (b3) x.expectStaticType<Exactly<int?>>();
+}
+
+capture_promotedVar_prior_to_assignment(int? x) {
+ int? y;
+ (int? z) => y = z;
+ y = x;
+ bool b = y != null;
+ if (b) y.expectStaticType<Exactly<int?>>();
+}
+
+capture_conditionVar_after_assignment(int? x) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ (bool b2) => b = b2;
+ if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+capture_conditionVar_after_assignment_from_other_condition(int? x) {
+ bool b1 = x != null;
+ bool b3 = b1;
+ if (b3) x.expectStaticType<Exactly<int>>();
+ (bool b2) => b3 = b2;
+ if (b3) x.expectStaticType<Exactly<int?>>();
+}
+
+capture_conditionVar_after_assignment_then_copy_to_other_condition(int? x) {
+ bool b1 = x != null;
+ bool b3;
+ (bool b2) => b1 = b2;
+ b3 = b1;
+ if (b3) x.expectStaticType<Exactly<int?>>();
+}
+
+capture_promotedVar_after_assignment(int? x) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ (int? y) => x = y;
+ if (b) x.expectStaticType<Exactly<int?>>();
+}
+
+main() {
+ capture_conditionVar_prior_to_assignment(null);
+ capture_conditionVar_prior_to_assignment(0);
+ capture_conditionVar_prior_to_assignment_from_other_condition(null);
+ capture_conditionVar_prior_to_assignment_from_other_condition(0);
+ capture_promotedVar_prior_to_assignment(null);
+ capture_promotedVar_prior_to_assignment(0);
+ capture_conditionVar_after_assignment(null);
+ capture_conditionVar_after_assignment(0);
+ capture_conditionVar_after_assignment_from_other_condition(null);
+ capture_conditionVar_after_assignment_from_other_condition(0);
+ capture_conditionVar_after_assignment_then_copy_to_other_condition(null);
+ capture_conditionVar_after_assignment_then_copy_to_other_condition(0);
+ capture_promotedVar_after_assignment(null);
+ capture_promotedVar_after_assignment(0);
+}
diff --git a/tests/language/nnbd/flow_analysis/local_boolean_does_not_detect_aliases_test.dart b/tests/language/nnbd/flow_analysis/local_boolean_does_not_detect_aliases_test.dart
new file mode 100644
index 0000000..8449b67
--- /dev/null
+++ b/tests/language/nnbd/flow_analysis/local_boolean_does_not_detect_aliases_test.dart
@@ -0,0 +1,106 @@
+// 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 '../../static_type_helper.dart';
+
+// This test checks that type promotion via local variables does not promote
+// based on knowledge that two potentially promoted variables are "aliases" of
+// each other (both are known to contain the same value).
+//
+// Note, however, that if one condition variable is assigned to another, the
+// promotions *do* carry over; this is a side effect of "promote via local
+// booleans" mechanism and doesn't rely on detecting aliasing.
+//
+// We test both the situation where the variables have the same value due to
+// initialization as well as assignment. We test both final and non-final
+// variables.
+
+promotedVar(int? x) {
+ {
+ int? y = x;
+ bool b = x != null;
+ if (b) {
+ x.expectStaticType<Exactly<int>>();
+ y.expectStaticType<Exactly<int?>>();
+ }
+ }
+ {
+ final int? y = x;
+ bool b = x != null;
+ if (b) {
+ x.expectStaticType<Exactly<int>>();
+ y.expectStaticType<Exactly<int?>>();
+ }
+ }
+ {
+ int? y;
+ y = x;
+ bool b = x != null;
+ if (b) {
+ x.expectStaticType<Exactly<int>>();
+ y.expectStaticType<Exactly<int?>>();
+ }
+ }
+ {
+ final int? y;
+ y = x;
+ bool b = x != null;
+ if (b) {
+ x.expectStaticType<Exactly<int>>();
+ y.expectStaticType<Exactly<int?>>();
+ }
+ }
+}
+
+conditionalVar(int? x) {
+ {
+ bool b1 = x != null;
+ bool b2 = b1;
+ if (b1) {
+ x.expectStaticType<Exactly<int>>();
+ }
+ if (b2) {
+ x.expectStaticType<Exactly<int>>();
+ }
+ }
+ {
+ bool b1 = x != null;
+ final bool b2 = b1;
+ if (b1) {
+ x.expectStaticType<Exactly<int>>();
+ }
+ if (b2) {
+ x.expectStaticType<Exactly<int>>();
+ }
+ }
+ {
+ bool b1 = x != null;
+ bool b2;
+ b2 = b1;
+ if (b1) {
+ x.expectStaticType<Exactly<int>>();
+ }
+ if (b2) {
+ x.expectStaticType<Exactly<int>>();
+ }
+ }
+ {
+ bool b1 = x != null;
+ final bool b2;
+ b2 = b1;
+ if (b1) {
+ x.expectStaticType<Exactly<int>>();
+ }
+ if (b2) {
+ x.expectStaticType<Exactly<int>>();
+ }
+ }
+}
+
+main() {
+ promotedVar(0);
+ promotedVar(null);
+ conditionalVar(0);
+ conditionalVar(null);
+}
diff --git a/tests/language/nnbd/flow_analysis/local_boolean_expression_types_test.dart b/tests/language/nnbd/flow_analysis/local_boolean_expression_types_test.dart
new file mode 100644
index 0000000..5f37e8e
--- /dev/null
+++ b/tests/language/nnbd/flow_analysis/local_boolean_expression_types_test.dart
@@ -0,0 +1,774 @@
+// 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 '../../static_type_helper.dart';
+
+// This test checks whether a local boolean variable can be used to perform type
+// promotion, for various kinds of boolean expressions that we expect to cause
+// promotions, and various contexts in which those boolean variables could be
+// used.
+//
+// For the boolean variable, we test the forms:
+// - `<variable> is <Type>`
+// - `<variable> is! <Type>`
+// - `!<expr>`
+// - `<variable> == null`
+// - `<variable> != null`
+// - `null == <variable>`
+// - `null != <variable>`
+// - `<expr> && <expr>`
+// - `<expr> || <expr>`
+// - `<variable> is <Type> ? true : false`
+// - `<variable> = <expr>`
+// For the use site, we test the forms:
+// - `(<variable>)`
+// - `!<variable>`
+// - `<variable> && <expr>`
+// - `<expr> && <variable>`
+// - `<variable> || <expr>`
+// - `<expr> || <variable>`
+// - `<variable> ? <expr> : <expr>`
+// - `if (<variable>) ...`
+// - `while (<variable>) ...`
+// - `do ... while (<variable>)`
+// - `for (...; <variable>; ...) ...`
+
+bool _alwaysTrue(Object? x) => true;
+
+bool _alwaysFalse(Object? x) => false;
+
+is_(Object x) {
+ bool b = x is int;
+ if ((b)) {
+ x.expectStaticType<Exactly<int>>();
+ } else {
+ x.expectStaticType<Exactly<Object>>();
+ }
+ if (!b) {
+ x.expectStaticType<Exactly<Object>>();
+ } else {
+ x.expectStaticType<Exactly<int>>();
+ }
+ if (b && _alwaysTrue(x.expectStaticType<Exactly<int>>())) {
+ x.expectStaticType<Exactly<int>>();
+ } else {
+ x.expectStaticType<Exactly<Object>>();
+ }
+ if (_alwaysTrue(x.expectStaticType<Exactly<Object>>()) && b) {
+ x.expectStaticType<Exactly<int>>();
+ } else {
+ x.expectStaticType<Exactly<Object>>();
+ }
+ if (b || _alwaysFalse(x.expectStaticType<Exactly<Object>>())) {
+ x.expectStaticType<Exactly<Object>>();
+ } else {
+ x.expectStaticType<Exactly<Object>>();
+ }
+ if (_alwaysFalse(x.expectStaticType<Exactly<Object>>()) || b) {
+ x.expectStaticType<Exactly<Object>>();
+ } else {
+ x.expectStaticType<Exactly<Object>>();
+ }
+ if (b) {
+ x.expectStaticType<Exactly<int>>();
+ } else {
+ x.expectStaticType<Exactly<Object>>();
+ }
+ while (b) {
+ x.expectStaticType<Exactly<int>>();
+ if (_alwaysTrue(null)) break;
+ }
+ x.expectStaticType<Exactly<Object>>();
+ do {
+ x.expectStaticType<Exactly<Object>>();
+ if (_alwaysTrue(null)) break;
+ } while (b);
+ x.expectStaticType<Exactly<Object>>();
+ for (x.expectStaticType<Exactly<Object>>();
+ b;
+ x.expectStaticType<Exactly<int>>()) {
+ x.expectStaticType<Exactly<int>>();
+ if (_alwaysTrue(null)) break;
+ }
+}
+
+isNot(Object x) {
+ bool b = x is! int;
+ if ((b)) {
+ x.expectStaticType<Exactly<Object>>();
+ } else {
+ x.expectStaticType<Exactly<int>>();
+ }
+ if (!b) {
+ x.expectStaticType<Exactly<int>>();
+ } else {
+ x.expectStaticType<Exactly<Object>>();
+ }
+ if (b && _alwaysTrue(x.expectStaticType<Exactly<Object>>())) {
+ x.expectStaticType<Exactly<Object>>();
+ } else {
+ x.expectStaticType<Exactly<Object>>();
+ }
+ if (_alwaysTrue(x.expectStaticType<Exactly<Object>>()) && b) {
+ x.expectStaticType<Exactly<Object>>();
+ } else {
+ x.expectStaticType<Exactly<Object>>();
+ }
+ if (b || _alwaysFalse(x.expectStaticType<Exactly<int>>())) {
+ x.expectStaticType<Exactly<Object>>();
+ } else {
+ x.expectStaticType<Exactly<int>>();
+ }
+ if (_alwaysFalse(x.expectStaticType<Exactly<Object>>()) || b) {
+ x.expectStaticType<Exactly<Object>>();
+ } else {
+ x.expectStaticType<Exactly<int>>();
+ }
+ if (b) {
+ x.expectStaticType<Exactly<Object>>();
+ } else {
+ x.expectStaticType<Exactly<int>>();
+ }
+ while (b) {
+ x.expectStaticType<Exactly<Object>>();
+ if (_alwaysTrue(null)) break;
+ }
+ x.expectStaticType<Exactly<Object>>();
+ if (_alwaysFalse(null)) {
+ // We test this at compile time only because we don't want to have an
+ // infinite loop
+ do {
+ x.expectStaticType<Exactly<Object>>();
+ } while (b);
+ x.expectStaticType<Exactly<int>>();
+ }
+ x.expectStaticType<Exactly<Object>>();
+ for (x.expectStaticType<Exactly<Object>>();
+ b;
+ x.expectStaticType<Exactly<Object>>()) {
+ x.expectStaticType<Exactly<Object>>();
+ if (_alwaysTrue(null)) break;
+ }
+}
+
+not(Object x) {
+ bool b = !(x is int);
+ if ((b)) {
+ x.expectStaticType<Exactly<Object>>();
+ } else {
+ x.expectStaticType<Exactly<int>>();
+ }
+ if (!b) {
+ x.expectStaticType<Exactly<int>>();
+ } else {
+ x.expectStaticType<Exactly<Object>>();
+ }
+ if (b && _alwaysTrue(x.expectStaticType<Exactly<Object>>())) {
+ x.expectStaticType<Exactly<Object>>();
+ } else {
+ x.expectStaticType<Exactly<Object>>();
+ }
+ if (_alwaysTrue(x.expectStaticType<Exactly<Object>>()) && b) {
+ x.expectStaticType<Exactly<Object>>();
+ } else {
+ x.expectStaticType<Exactly<Object>>();
+ }
+ if (b || _alwaysFalse(x.expectStaticType<Exactly<int>>())) {
+ x.expectStaticType<Exactly<Object>>();
+ } else {
+ x.expectStaticType<Exactly<int>>();
+ }
+ if (_alwaysFalse(x.expectStaticType<Exactly<Object>>()) || b) {
+ x.expectStaticType<Exactly<Object>>();
+ } else {
+ x.expectStaticType<Exactly<int>>();
+ }
+ if (b) {
+ x.expectStaticType<Exactly<Object>>();
+ } else {
+ x.expectStaticType<Exactly<int>>();
+ }
+ while (b) {
+ x.expectStaticType<Exactly<Object>>();
+ if (_alwaysTrue(null)) break;
+ }
+ x.expectStaticType<Exactly<Object>>();
+ if (_alwaysFalse(null)) {
+ // We test this at compile time only because we don't want to have an
+ // infinite loop
+ do {
+ x.expectStaticType<Exactly<Object>>();
+ } while (b);
+ x.expectStaticType<Exactly<int>>();
+ }
+ x.expectStaticType<Exactly<Object>>();
+ for (x.expectStaticType<Exactly<Object>>();
+ b;
+ x.expectStaticType<Exactly<Object>>()) {
+ x.expectStaticType<Exactly<Object>>();
+ if (_alwaysTrue(null)) break;
+ }
+}
+
+eqNull(int? x) {
+ bool b = (x == null);
+ if ((b)) {
+ x.expectStaticType<Exactly<int?>>();
+ } else {
+ x.expectStaticType<Exactly<int>>();
+ }
+ if (!b) {
+ x.expectStaticType<Exactly<int>>();
+ } else {
+ x.expectStaticType<Exactly<int?>>();
+ }
+ if (b && _alwaysTrue(x.expectStaticType<Exactly<int?>>())) {
+ x.expectStaticType<Exactly<int?>>();
+ } else {
+ x.expectStaticType<Exactly<int?>>();
+ }
+ if (_alwaysTrue(x.expectStaticType<Exactly<int?>>()) && b) {
+ x.expectStaticType<Exactly<int?>>();
+ } else {
+ x.expectStaticType<Exactly<int?>>();
+ }
+ if (b || _alwaysFalse(x.expectStaticType<Exactly<int>>())) {
+ x.expectStaticType<Exactly<int?>>();
+ } else {
+ x.expectStaticType<Exactly<int>>();
+ }
+ if (_alwaysFalse(x.expectStaticType<Exactly<int?>>()) || b) {
+ x.expectStaticType<Exactly<int?>>();
+ } else {
+ x.expectStaticType<Exactly<int>>();
+ }
+ if (b) {
+ x.expectStaticType<Exactly<int?>>();
+ } else {
+ x.expectStaticType<Exactly<int>>();
+ }
+ while (b) {
+ x.expectStaticType<Exactly<int?>>();
+ if (_alwaysTrue(null)) break;
+ }
+ x.expectStaticType<Exactly<int?>>();
+ if (_alwaysFalse(null)) {
+ // We test this at compile time only because we don't want to have an
+ // infinite loop
+ do {
+ x.expectStaticType<Exactly<int?>>();
+ } while (b);
+ x.expectStaticType<Exactly<int>>();
+ }
+ x.expectStaticType<Exactly<int?>>();
+ for (x.expectStaticType<Exactly<int?>>();
+ b;
+ x.expectStaticType<Exactly<int?>>()) {
+ x.expectStaticType<Exactly<int?>>();
+ if (_alwaysTrue(null)) break;
+ }
+}
+
+notEqNull(int? x) {
+ bool b = x != null;
+ if ((b)) {
+ x.expectStaticType<Exactly<int>>();
+ } else {
+ x.expectStaticType<Exactly<int?>>();
+ }
+ if (!b) {
+ x.expectStaticType<Exactly<int?>>();
+ } else {
+ x.expectStaticType<Exactly<int>>();
+ }
+ if (b && _alwaysTrue(x.expectStaticType<Exactly<int>>())) {
+ x.expectStaticType<Exactly<int>>();
+ } else {
+ x.expectStaticType<Exactly<int?>>();
+ }
+ if (_alwaysTrue(x.expectStaticType<Exactly<int?>>()) && b) {
+ x.expectStaticType<Exactly<int>>();
+ } else {
+ x.expectStaticType<Exactly<int?>>();
+ }
+ if (b || _alwaysFalse(x.expectStaticType<Exactly<int?>>())) {
+ x.expectStaticType<Exactly<int?>>();
+ } else {
+ x.expectStaticType<Exactly<int?>>();
+ }
+ if (_alwaysFalse(x.expectStaticType<Exactly<int?>>()) || b) {
+ x.expectStaticType<Exactly<int?>>();
+ } else {
+ x.expectStaticType<Exactly<int?>>();
+ }
+ if (b) {
+ x.expectStaticType<Exactly<int>>();
+ } else {
+ x.expectStaticType<Exactly<int?>>();
+ }
+ while (b) {
+ x.expectStaticType<Exactly<int>>();
+ if (_alwaysTrue(null)) break;
+ }
+ x.expectStaticType<Exactly<int?>>();
+ do {
+ x.expectStaticType<Exactly<int?>>();
+ if (_alwaysTrue(null)) break;
+ } while (b);
+ x.expectStaticType<Exactly<int?>>();
+ for (x.expectStaticType<Exactly<int?>>();
+ b;
+ x.expectStaticType<Exactly<int>>()) {
+ x.expectStaticType<Exactly<int>>();
+ if (_alwaysTrue(null)) break;
+ }
+}
+
+nullEq(int? x) {
+ bool b = (null == x);
+ if ((b)) {
+ x.expectStaticType<Exactly<int?>>();
+ } else {
+ x.expectStaticType<Exactly<int>>();
+ }
+ if (!b) {
+ x.expectStaticType<Exactly<int>>();
+ } else {
+ x.expectStaticType<Exactly<int?>>();
+ }
+ if (b && _alwaysTrue(x.expectStaticType<Exactly<int?>>())) {
+ x.expectStaticType<Exactly<int?>>();
+ } else {
+ x.expectStaticType<Exactly<int?>>();
+ }
+ if (_alwaysTrue(x.expectStaticType<Exactly<int?>>()) && b) {
+ x.expectStaticType<Exactly<int?>>();
+ } else {
+ x.expectStaticType<Exactly<int?>>();
+ }
+ if (b || _alwaysFalse(x.expectStaticType<Exactly<int>>())) {
+ x.expectStaticType<Exactly<int?>>();
+ } else {
+ x.expectStaticType<Exactly<int>>();
+ }
+ if (_alwaysFalse(x.expectStaticType<Exactly<int?>>()) || b) {
+ x.expectStaticType<Exactly<int?>>();
+ } else {
+ x.expectStaticType<Exactly<int>>();
+ }
+ if (b) {
+ x.expectStaticType<Exactly<int?>>();
+ } else {
+ x.expectStaticType<Exactly<int>>();
+ }
+ while (b) {
+ x.expectStaticType<Exactly<int?>>();
+ if (_alwaysTrue(null)) break;
+ }
+ x.expectStaticType<Exactly<int?>>();
+ if (_alwaysFalse(null)) {
+ // We test this at compile time only because we don't want to have an
+ // infinite loop
+ do {
+ x.expectStaticType<Exactly<int?>>();
+ } while (b);
+ x.expectStaticType<Exactly<int>>();
+ }
+ x.expectStaticType<Exactly<int?>>();
+ for (x.expectStaticType<Exactly<int?>>();
+ b;
+ x.expectStaticType<Exactly<int?>>()) {
+ x.expectStaticType<Exactly<int?>>();
+ if (_alwaysTrue(null)) break;
+ }
+}
+
+nullNotEq(int? x) {
+ bool b = null != x;
+ if ((b)) {
+ x.expectStaticType<Exactly<int>>();
+ } else {
+ x.expectStaticType<Exactly<int?>>();
+ }
+ if (!b) {
+ x.expectStaticType<Exactly<int?>>();
+ } else {
+ x.expectStaticType<Exactly<int>>();
+ }
+ if (b && _alwaysTrue(x.expectStaticType<Exactly<int>>())) {
+ x.expectStaticType<Exactly<int>>();
+ } else {
+ x.expectStaticType<Exactly<int?>>();
+ }
+ if (_alwaysTrue(x.expectStaticType<Exactly<int?>>()) && b) {
+ x.expectStaticType<Exactly<int>>();
+ } else {
+ x.expectStaticType<Exactly<int?>>();
+ }
+ if (b || _alwaysFalse(x.expectStaticType<Exactly<int?>>())) {
+ x.expectStaticType<Exactly<int?>>();
+ } else {
+ x.expectStaticType<Exactly<int?>>();
+ }
+ if (_alwaysFalse(x.expectStaticType<Exactly<int?>>()) || b) {
+ x.expectStaticType<Exactly<int?>>();
+ } else {
+ x.expectStaticType<Exactly<int?>>();
+ }
+ if (b) {
+ x.expectStaticType<Exactly<int>>();
+ } else {
+ x.expectStaticType<Exactly<int?>>();
+ }
+ while (b) {
+ x.expectStaticType<Exactly<int>>();
+ if (_alwaysTrue(null)) break;
+ }
+ x.expectStaticType<Exactly<int?>>();
+ do {
+ x.expectStaticType<Exactly<int?>>();
+ if (_alwaysTrue(null)) break;
+ } while (b);
+ x.expectStaticType<Exactly<int?>>();
+ for (x.expectStaticType<Exactly<int?>>();
+ b;
+ x.expectStaticType<Exactly<int>>()) {
+ x.expectStaticType<Exactly<int>>();
+ if (_alwaysTrue(null)) break;
+ }
+}
+
+and(Object x, Object y) {
+ bool b = x is int && y is int;
+ if ((b)) {
+ x.expectStaticType<Exactly<int>>();
+ y.expectStaticType<Exactly<int>>();
+ } else {
+ x.expectStaticType<Exactly<Object>>();
+ y.expectStaticType<Exactly<Object>>();
+ }
+ if (!b) {
+ x.expectStaticType<Exactly<Object>>();
+ y.expectStaticType<Exactly<Object>>();
+ } else {
+ x.expectStaticType<Exactly<int>>();
+ y.expectStaticType<Exactly<int>>();
+ }
+ if (b &&
+ _alwaysTrue([
+ x.expectStaticType<Exactly<int>>(),
+ y.expectStaticType<Exactly<int>>()
+ ])) {
+ x.expectStaticType<Exactly<int>>();
+ y.expectStaticType<Exactly<int>>();
+ } else {
+ x.expectStaticType<Exactly<Object>>();
+ y.expectStaticType<Exactly<Object>>();
+ }
+ if (_alwaysTrue([
+ x.expectStaticType<Exactly<Object>>(),
+ y.expectStaticType<Exactly<Object>>()
+ ]) &&
+ b) {
+ x.expectStaticType<Exactly<int>>();
+ y.expectStaticType<Exactly<int>>();
+ } else {
+ x.expectStaticType<Exactly<Object>>();
+ y.expectStaticType<Exactly<Object>>();
+ }
+ if (b ||
+ _alwaysFalse([
+ x.expectStaticType<Exactly<Object>>(),
+ y.expectStaticType<Exactly<Object>>()
+ ])) {
+ x.expectStaticType<Exactly<Object>>();
+ y.expectStaticType<Exactly<Object>>();
+ } else {
+ x.expectStaticType<Exactly<Object>>();
+ y.expectStaticType<Exactly<Object>>();
+ }
+ if (_alwaysFalse([
+ x.expectStaticType<Exactly<Object>>(),
+ y.expectStaticType<Exactly<Object>>()
+ ]) ||
+ b) {
+ x.expectStaticType<Exactly<Object>>();
+ y.expectStaticType<Exactly<Object>>();
+ } else {
+ x.expectStaticType<Exactly<Object>>();
+ y.expectStaticType<Exactly<Object>>();
+ }
+ if (b) {
+ x.expectStaticType<Exactly<int>>();
+ y.expectStaticType<Exactly<int>>();
+ } else {
+ x.expectStaticType<Exactly<Object>>();
+ y.expectStaticType<Exactly<Object>>();
+ }
+ while (b) {
+ x.expectStaticType<Exactly<int>>();
+ y.expectStaticType<Exactly<int>>();
+ if (_alwaysTrue(null)) break;
+ }
+ x.expectStaticType<Exactly<Object>>();
+ y.expectStaticType<Exactly<Object>>();
+ do {
+ x.expectStaticType<Exactly<Object>>();
+ y.expectStaticType<Exactly<Object>>();
+ if (_alwaysTrue(null)) break;
+ } while (b);
+ x.expectStaticType<Exactly<Object>>();
+ y.expectStaticType<Exactly<Object>>();
+ for ([
+ x.expectStaticType<Exactly<Object>>(),
+ y.expectStaticType<Exactly<Object>>()
+ ];
+ b;
+ x.expectStaticType<Exactly<int>>(), y.expectStaticType<Exactly<int>>()) {
+ x.expectStaticType<Exactly<int>>();
+ y.expectStaticType<Exactly<int>>();
+ if (_alwaysTrue(null)) break;
+ }
+}
+
+or(Object x, Object y) {
+ bool b = x is! int || y is! int;
+ if ((b)) {
+ x.expectStaticType<Exactly<Object>>();
+ y.expectStaticType<Exactly<Object>>();
+ } else {
+ x.expectStaticType<Exactly<int>>();
+ y.expectStaticType<Exactly<int>>();
+ }
+ if (!b) {
+ x.expectStaticType<Exactly<int>>();
+ y.expectStaticType<Exactly<int>>();
+ } else {
+ x.expectStaticType<Exactly<Object>>();
+ y.expectStaticType<Exactly<Object>>();
+ }
+ if (b &&
+ _alwaysTrue([
+ x.expectStaticType<Exactly<Object>>(),
+ y.expectStaticType<Exactly<Object>>()
+ ])) {
+ x.expectStaticType<Exactly<Object>>();
+ y.expectStaticType<Exactly<Object>>();
+ } else {
+ x.expectStaticType<Exactly<Object>>();
+ y.expectStaticType<Exactly<Object>>();
+ }
+ if (_alwaysTrue([
+ x.expectStaticType<Exactly<Object>>(),
+ y.expectStaticType<Exactly<Object>>()
+ ]) &&
+ b) {
+ x.expectStaticType<Exactly<Object>>();
+ y.expectStaticType<Exactly<Object>>();
+ } else {
+ x.expectStaticType<Exactly<Object>>();
+ y.expectStaticType<Exactly<Object>>();
+ }
+ if (b ||
+ _alwaysFalse([
+ x.expectStaticType<Exactly<int>>(),
+ y.expectStaticType<Exactly<int>>()
+ ])) {
+ x.expectStaticType<Exactly<Object>>();
+ y.expectStaticType<Exactly<Object>>();
+ } else {
+ x.expectStaticType<Exactly<int>>();
+ y.expectStaticType<Exactly<int>>();
+ }
+ if (_alwaysFalse([
+ x.expectStaticType<Exactly<Object>>(),
+ y.expectStaticType<Exactly<Object>>()
+ ]) ||
+ b) {
+ x.expectStaticType<Exactly<Object>>();
+ y.expectStaticType<Exactly<Object>>();
+ } else {
+ x.expectStaticType<Exactly<int>>();
+ y.expectStaticType<Exactly<int>>();
+ }
+ if (b) {
+ x.expectStaticType<Exactly<Object>>();
+ y.expectStaticType<Exactly<Object>>();
+ } else {
+ x.expectStaticType<Exactly<int>>();
+ y.expectStaticType<Exactly<int>>();
+ }
+ while (b) {
+ x.expectStaticType<Exactly<Object>>();
+ y.expectStaticType<Exactly<Object>>();
+ if (_alwaysTrue(null)) break;
+ }
+ x.expectStaticType<Exactly<Object>>();
+ y.expectStaticType<Exactly<Object>>();
+ if (_alwaysFalse(null)) {
+ // We test this at compile time only because we don't want to have an
+ // infinite loop
+ do {
+ x.expectStaticType<Exactly<Object>>();
+ y.expectStaticType<Exactly<Object>>();
+ } while (b);
+ x.expectStaticType<Exactly<int>>();
+ y.expectStaticType<Exactly<int>>();
+ }
+ x.expectStaticType<Exactly<Object>>();
+ y.expectStaticType<Exactly<Object>>();
+ for ([
+ x.expectStaticType<Exactly<Object>>(),
+ y.expectStaticType<Exactly<Object>>()
+ ];
+ b;
+ x.expectStaticType<Exactly<Object>>(),
+ y.expectStaticType<Exactly<Object>>()) {
+ x.expectStaticType<Exactly<Object>>();
+ y.expectStaticType<Exactly<Object>>();
+ if (_alwaysTrue(null)) break;
+ }
+}
+
+conditional(Object x) {
+ bool b = x is int ? true : false;
+ if ((b)) {
+ x.expectStaticType<Exactly<int>>();
+ } else {
+ x.expectStaticType<Exactly<Object>>();
+ }
+ if (!b) {
+ x.expectStaticType<Exactly<Object>>();
+ } else {
+ x.expectStaticType<Exactly<int>>();
+ }
+ if (b && _alwaysTrue(x.expectStaticType<Exactly<int>>())) {
+ x.expectStaticType<Exactly<int>>();
+ } else {
+ x.expectStaticType<Exactly<Object>>();
+ }
+ if (_alwaysTrue(x.expectStaticType<Exactly<Object>>()) && b) {
+ x.expectStaticType<Exactly<int>>();
+ } else {
+ x.expectStaticType<Exactly<Object>>();
+ }
+ if (b || _alwaysFalse(x.expectStaticType<Exactly<Object>>())) {
+ x.expectStaticType<Exactly<Object>>();
+ } else {
+ x.expectStaticType<Exactly<Object>>();
+ }
+ if (_alwaysFalse(x.expectStaticType<Exactly<Object>>()) || b) {
+ x.expectStaticType<Exactly<Object>>();
+ } else {
+ x.expectStaticType<Exactly<Object>>();
+ }
+ if (b) {
+ x.expectStaticType<Exactly<int>>();
+ } else {
+ x.expectStaticType<Exactly<Object>>();
+ }
+ while (b) {
+ x.expectStaticType<Exactly<int>>();
+ if (_alwaysTrue(null)) break;
+ }
+ x.expectStaticType<Exactly<Object>>();
+ do {
+ x.expectStaticType<Exactly<Object>>();
+ if (_alwaysTrue(null)) break;
+ } while (b);
+ x.expectStaticType<Exactly<Object>>();
+ for (x.expectStaticType<Exactly<Object>>();
+ b;
+ x.expectStaticType<Exactly<int>>()) {
+ x.expectStaticType<Exactly<int>>();
+ if (_alwaysTrue(null)) break;
+ }
+}
+
+assignment(Object x) {
+ // Note: flow analysis currently doesn't understand that `x = y` has the same
+ // value as `y`, so no promotion happens in this test.
+ bool b1;
+ bool b2 = b1 = x is int;
+ if ((b2)) {
+ x.expectStaticType<Exactly<Object>>();
+ } else {
+ x.expectStaticType<Exactly<Object>>();
+ }
+ if (!b2) {
+ x.expectStaticType<Exactly<Object>>();
+ } else {
+ x.expectStaticType<Exactly<Object>>();
+ }
+ if (b2 && _alwaysTrue(x.expectStaticType<Exactly<Object>>())) {
+ x.expectStaticType<Exactly<Object>>();
+ } else {
+ x.expectStaticType<Exactly<Object>>();
+ }
+ if (_alwaysTrue(x.expectStaticType<Exactly<Object>>()) && b2) {
+ x.expectStaticType<Exactly<Object>>();
+ } else {
+ x.expectStaticType<Exactly<Object>>();
+ }
+ if (b2 || _alwaysFalse(x.expectStaticType<Exactly<Object>>())) {
+ x.expectStaticType<Exactly<Object>>();
+ } else {
+ x.expectStaticType<Exactly<Object>>();
+ }
+ if (_alwaysFalse(x.expectStaticType<Exactly<Object>>()) || b2) {
+ x.expectStaticType<Exactly<Object>>();
+ } else {
+ x.expectStaticType<Exactly<Object>>();
+ }
+ if (b2) {
+ x.expectStaticType<Exactly<Object>>();
+ } else {
+ x.expectStaticType<Exactly<Object>>();
+ }
+ while (b2) {
+ x.expectStaticType<Exactly<Object>>();
+ if (_alwaysTrue(null)) break;
+ }
+ x.expectStaticType<Exactly<Object>>();
+ do {
+ x.expectStaticType<Exactly<Object>>();
+ if (_alwaysTrue(null)) break;
+ } while (b2);
+ x.expectStaticType<Exactly<Object>>();
+ for (x.expectStaticType<Exactly<Object>>();
+ b2;
+ x.expectStaticType<Exactly<Object>>()) {
+ x.expectStaticType<Exactly<Object>>();
+ if (_alwaysTrue(null)) break;
+ }
+}
+
+main() {
+ is_('foo');
+ is_(0);
+ isNot('foo');
+ isNot(0);
+ not('foo');
+ not(0);
+ eqNull(null);
+ eqNull(0);
+ notEqNull(null);
+ notEqNull(0);
+ nullEq(null);
+ nullEq(0);
+ nullNotEq(null);
+ nullNotEq(0);
+ and('foo', 'bar');
+ and('foo', 1);
+ and(0, 'bar');
+ and(0, 1);
+ or('foo', 'bar');
+ or('foo', 1);
+ or(0, 'bar');
+ or(0, 1);
+ conditional('foo');
+ conditional(0);
+ assignment('foo');
+ assignment(0);
+}
diff --git a/tests/language/nnbd/flow_analysis/local_boolean_join_equivalent_test.dart b/tests/language/nnbd/flow_analysis/local_boolean_join_equivalent_test.dart
new file mode 100644
index 0000000..4158001
--- /dev/null
+++ b/tests/language/nnbd/flow_analysis/local_boolean_join_equivalent_test.dart
@@ -0,0 +1,264 @@
+// 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 '../../static_type_helper.dart';
+
+// This test verifies that when control flow paths are joined, flow analysis
+// does not recognize and coalesce distinct but equivalent assignments of test
+// expressions to a boolean. So for example, even though this promotes:
+//
+// bool b;
+// b = x != null;
+// if (b) { /* x is promoted to non-nullable */ }
+//
+// This does not:
+//
+// bool b;
+// if (...) {
+// b = x != null;
+// } else {
+// b = x != null;
+// }
+// if (b) { /* x is not promoted */ }
+//
+// We test all flow control constructs where a join might occur, including:
+// - At the end of an if/else construct or conditional expression
+// - At the end of a loop where the "break" control flow path joins the main
+// control flow path
+// - At the point in a "do" or "for" loop where the "continue" control flow path
+// joins the main control flow path
+// - Inside a loop where multiple "break" or "continue" paths are implicitly
+// joined
+// - Inside a switch statement where multiple "break" paths are implicitly
+// joined
+// - At the end of an exhaustive switch statement where the last case is
+// implicitly joined to the "break" path
+// - After a "catch" where the main control flow path is resumed
+// - After a labeled statement where the "break" control flow path is joined to
+// the main control flow path
+
+enum E { E1, E2 }
+
+bool _alwaysFalse(dynamic d) => false;
+
+dynamic _alwaysThrow(dynamic d) {
+ throw 'foo';
+}
+
+test(int? x, bool b1, E e) {
+ {
+ bool b2;
+ b1
+ ? [b2 = x != null, b2 ? x.expectStaticType<Exactly<int>>() : null]
+ : [b2 = x != null, b2 ? x.expectStaticType<Exactly<int>>() : null];
+ if (b2) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ bool b2;
+ if (b1) {
+ b2 = x != null;
+ if (b2) x.expectStaticType<Exactly<int>>();
+ } else {
+ b2 = x != null;
+ if (b2) x.expectStaticType<Exactly<int>>();
+ }
+ if (b2) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ bool b2;
+ [
+ if (b1)
+ [b2 = x != null, b2 ? x.expectStaticType<Exactly<int>>() : null]
+ else
+ [b2 = x != null, b2 ? x.expectStaticType<Exactly<int>>() : null]
+ ];
+ if (b2) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ bool b2;
+ ({
+ if (b1)
+ [b2 = x != null, b2 ? x.expectStaticType<Exactly<int>>() : null]
+ else
+ [b2 = x != null, b2 ? x.expectStaticType<Exactly<int>>() : null]
+ });
+ if (b2) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ bool b2;
+ ({
+ if (b1)
+ [b2 = x != null, b2 ? x.expectStaticType<Exactly<int>>() : null]: null
+ else
+ [b2 = x != null, b2 ? x.expectStaticType<Exactly<int>>() : null]: null
+ });
+ if (b2) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ bool b2;
+ ({
+ if (b1)
+ null: [b2 = x != null, b2 ? x.expectStaticType<Exactly<int>>() : null]
+ else
+ null: [b2 = x != null, b2 ? x.expectStaticType<Exactly<int>>() : null]
+ });
+ if (b2) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ bool b2;
+ do {
+ if (b1) {
+ b2 = x != null;
+ if (b2) x.expectStaticType<Exactly<int>>();
+ break;
+ }
+ b2 = x != null;
+ if (b2) x.expectStaticType<Exactly<int>>();
+ } while (false);
+ if (b2) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ bool b2 = false;
+ for (int i = 0; i < 1; i++) {
+ if (b1) {
+ b2 = x != null;
+ if (b2) x.expectStaticType<Exactly<int>>();
+ break;
+ }
+ b2 = x != null;
+ if (b2) x.expectStaticType<Exactly<int>>();
+ }
+ if (b2) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ bool b2 = false;
+ int i = 0;
+ while (i < 1) {
+ if (b1) {
+ b2 = x != null;
+ if (b2) x.expectStaticType<Exactly<int>>();
+ break;
+ }
+ b2 = x != null;
+ if (b2) x.expectStaticType<Exactly<int>>();
+ i++;
+ }
+ if (b2) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ bool b2;
+ do {
+ if (b1) {
+ b2 = x != null;
+ if (b2) x.expectStaticType<Exactly<int>>();
+ continue;
+ }
+ b2 = x != null;
+ if (b2) x.expectStaticType<Exactly<int>>();
+ } while (_alwaysFalse(b2 ? x.expectStaticType<Exactly<int?>>() : null));
+ }
+ {
+ try {
+ bool b2;
+ for (;; _alwaysThrow(b2 ? x.expectStaticType<Exactly<int?>>() : null)) {
+ if (b1) {
+ b2 = x != null;
+ if (b2) x.expectStaticType<Exactly<int>>();
+ continue;
+ }
+ b2 = x != null;
+ if (b2) x.expectStaticType<Exactly<int>>();
+ }
+ } catch (_) {}
+ }
+ {
+ bool b2;
+ while (true) {
+ if (b1) {
+ b2 = x != null;
+ if (b2) x.expectStaticType<Exactly<int>>();
+ break;
+ } else {
+ b2 = x != null;
+ if (b2) x.expectStaticType<Exactly<int>>();
+ break;
+ }
+ }
+ if (b2) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ bool b2;
+ do {
+ if (b1) {
+ b2 = x != null;
+ if (b2) x.expectStaticType<Exactly<int>>();
+ continue;
+ } else {
+ b2 = x != null;
+ if (b2) x.expectStaticType<Exactly<int>>();
+ continue;
+ }
+ } while (_alwaysFalse(b2 ? x.expectStaticType<Exactly<int?>>() : null));
+ }
+ {
+ bool b2;
+ switch (e) {
+ case E.E1:
+ b2 = x != null;
+ if (b2) x.expectStaticType<Exactly<int>>();
+ break;
+ case E.E2:
+ b2 = x != null;
+ if (b2) x.expectStaticType<Exactly<int>>();
+ break;
+ }
+ if (b2) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ bool b2;
+ switch (e) {
+ case E.E1:
+ b2 = x != null;
+ if (b2) x.expectStaticType<Exactly<int>>();
+ break;
+ case E.E2:
+ b2 = x != null;
+ if (b2) x.expectStaticType<Exactly<int>>();
+ }
+ if (b2) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ bool b2;
+ try {
+ if (b1) throw 'foo';
+ b2 = x != null;
+ if (b2) x.expectStaticType<Exactly<int>>();
+ } catch (_) {
+ b2 = x != null;
+ if (b2) x.expectStaticType<Exactly<int>>();
+ }
+ if (b2) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ bool b2;
+ label:
+ {
+ if (b1) {
+ b2 = x != null;
+ if (b2) x.expectStaticType<Exactly<int>>();
+ break label;
+ }
+ b2 = x != null;
+ if (b2) x.expectStaticType<Exactly<int>>();
+ }
+ if (b2) x.expectStaticType<Exactly<int?>>();
+ }
+}
+
+main() {
+ test(null, false, E.E1);
+ test(null, true, E.E2);
+ test(1, false, E.E1);
+ test(1, true, E.E2);
+}
diff --git a/tests/language/nnbd/flow_analysis/local_boolean_logical_op_test.dart b/tests/language/nnbd/flow_analysis/local_boolean_logical_op_test.dart
new file mode 100644
index 0000000..07ffdac
--- /dev/null
+++ b/tests/language/nnbd/flow_analysis/local_boolean_logical_op_test.dart
@@ -0,0 +1,471 @@
+// 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 '../../static_type_helper.dart';
+
+// This test checks that local boolean variables can be used to perform type
+// promotion even when combined using logical operators. It also verifies that
+// these type promotions are appropriately invalidated by reassignments.
+
+testAnd(int? x, int? y, int? z, bool b) {
+ {
+ bool b1 = x is int;
+ bool b2 = y is int;
+ if (b1 && b2) {
+ x.expectStaticType<Exactly<int>>();
+ y.expectStaticType<Exactly<int>>();
+ }
+ }
+ {
+ bool b1 = x is int;
+ x = z;
+ bool b2 = y is int;
+ if (b1 && b2) {
+ x.expectStaticType<Exactly<int?>>();
+ y.expectStaticType<Exactly<int>>();
+ }
+ }
+ {
+ bool b1 = x is int;
+ y = z;
+ bool b2 = y is int;
+ if (b1 && b2) {
+ x.expectStaticType<Exactly<int>>();
+ y.expectStaticType<Exactly<int>>();
+ }
+ }
+ {
+ bool b1 = x is int;
+ b1 = b;
+ bool b2 = y is int;
+ if (b1 && b2) {
+ x.expectStaticType<Exactly<int?>>();
+ y.expectStaticType<Exactly<int>>();
+ }
+ }
+ {
+ bool b1 = x is int;
+ bool b2 = y is int;
+ x = z;
+ if (b1 && b2) {
+ x.expectStaticType<Exactly<int?>>();
+ y.expectStaticType<Exactly<int>>();
+ }
+ }
+ {
+ bool b1 = x is int;
+ bool b2 = y is int;
+ y = z;
+ if (b1 && b2) {
+ x.expectStaticType<Exactly<int>>();
+ y.expectStaticType<Exactly<int?>>();
+ }
+ }
+ {
+ bool b1 = x is int;
+ bool b2 = y is int;
+ b1 = b;
+ if (b1 && b2) {
+ x.expectStaticType<Exactly<int?>>();
+ y.expectStaticType<Exactly<int>>();
+ }
+ }
+ {
+ bool b1 = x is int;
+ bool b2 = y is int;
+ b2 = b;
+ if (b1 && b2) {
+ x.expectStaticType<Exactly<int>>();
+ y.expectStaticType<Exactly<int?>>();
+ }
+ }
+ {
+ bool b1 = x is int;
+ bool b2 = y is int;
+ bool b3 = b1 && b2;
+ if (b3) {
+ x.expectStaticType<Exactly<int>>();
+ y.expectStaticType<Exactly<int>>();
+ }
+ }
+ {
+ bool b1 = x is int;
+ x = z;
+ bool b2 = y is int;
+ bool b3 = b1 && b2;
+ if (b3) {
+ x.expectStaticType<Exactly<int?>>();
+ y.expectStaticType<Exactly<int>>();
+ }
+ }
+ {
+ bool b1 = x is int;
+ y = z;
+ bool b2 = y is int;
+ bool b3 = b1 && b2;
+ if (b3) {
+ x.expectStaticType<Exactly<int>>();
+ y.expectStaticType<Exactly<int>>();
+ }
+ }
+ {
+ bool b1 = x is int;
+ b1 = b;
+ bool b2 = y is int;
+ bool b3 = b1 && b2;
+ if (b3) {
+ x.expectStaticType<Exactly<int?>>();
+ y.expectStaticType<Exactly<int>>();
+ }
+ }
+ {
+ bool b1 = x is int;
+ bool b2 = y is int;
+ x = z;
+ bool b3 = b1 && b2;
+ if (b3) {
+ x.expectStaticType<Exactly<int?>>();
+ y.expectStaticType<Exactly<int>>();
+ }
+ }
+ {
+ bool b1 = x is int;
+ bool b2 = y is int;
+ y = z;
+ bool b3 = b1 && b2;
+ if (b3) {
+ x.expectStaticType<Exactly<int>>();
+ y.expectStaticType<Exactly<int?>>();
+ }
+ }
+ {
+ bool b1 = x is int;
+ bool b2 = y is int;
+ b1 = b;
+ bool b3 = b1 && b2;
+ if (b3) {
+ x.expectStaticType<Exactly<int?>>();
+ y.expectStaticType<Exactly<int>>();
+ }
+ }
+ {
+ bool b1 = x is int;
+ bool b2 = y is int;
+ b2 = b;
+ bool b3 = b1 && b2;
+ if (b3) {
+ x.expectStaticType<Exactly<int>>();
+ y.expectStaticType<Exactly<int?>>();
+ }
+ }
+ {
+ bool b1 = x is int;
+ bool b2 = y is int;
+ bool b3 = b1 && b2;
+ x = z;
+ if (b3) {
+ x.expectStaticType<Exactly<int?>>();
+ y.expectStaticType<Exactly<int>>();
+ }
+ }
+ {
+ bool b1 = x is int;
+ bool b2 = y is int;
+ bool b3 = b1 && b2;
+ y = z;
+ if (b3) {
+ x.expectStaticType<Exactly<int>>();
+ y.expectStaticType<Exactly<int?>>();
+ }
+ }
+ {
+ bool b1 = x is int;
+ bool b2 = y is int;
+ bool b3 = b1 && b2;
+ b1 = b;
+ if (b3) {
+ x.expectStaticType<Exactly<int>>();
+ y.expectStaticType<Exactly<int>>();
+ }
+ }
+ {
+ bool b1 = x is int;
+ bool b2 = y is int;
+ bool b3 = b1 && b2;
+ b2 = b;
+ if (b3) {
+ x.expectStaticType<Exactly<int>>();
+ y.expectStaticType<Exactly<int>>();
+ }
+ }
+ {
+ bool b1 = x is int;
+ bool b2 = y is int;
+ bool b3 = b1 && b2;
+ b3 = b;
+ if (b3) {
+ x.expectStaticType<Exactly<int?>>();
+ y.expectStaticType<Exactly<int?>>();
+ }
+ }
+}
+
+testOr(int? x, int? y, int? z, bool b) {
+ {
+ bool b1 = x is! int;
+ bool b2 = y is! int;
+ if (b1 || b2) {
+ } else {
+ x.expectStaticType<Exactly<int>>();
+ y.expectStaticType<Exactly<int>>();
+ }
+ }
+ {
+ bool b1 = x is! int;
+ x = z;
+ bool b2 = y is! int;
+ if (b1 || b2) {
+ } else {
+ x.expectStaticType<Exactly<int?>>();
+ y.expectStaticType<Exactly<int>>();
+ }
+ }
+ {
+ bool b1 = x is! int;
+ y = z;
+ bool b2 = y is! int;
+ if (b1 || b2) {
+ } else {
+ x.expectStaticType<Exactly<int>>();
+ y.expectStaticType<Exactly<int>>();
+ }
+ }
+ {
+ bool b1 = x is! int;
+ b1 = b;
+ bool b2 = y is! int;
+ if (b1 || b2) {
+ } else {
+ x.expectStaticType<Exactly<int?>>();
+ y.expectStaticType<Exactly<int>>();
+ }
+ }
+ {
+ bool b1 = x is! int;
+ bool b2 = y is! int;
+ x = z;
+ if (b1 || b2) {
+ } else {
+ x.expectStaticType<Exactly<int?>>();
+ y.expectStaticType<Exactly<int>>();
+ }
+ }
+ {
+ bool b1 = x is! int;
+ bool b2 = y is! int;
+ y = z;
+ if (b1 || b2) {
+ } else {
+ x.expectStaticType<Exactly<int>>();
+ y.expectStaticType<Exactly<int?>>();
+ }
+ }
+ {
+ bool b1 = x is! int;
+ bool b2 = y is! int;
+ b1 = b;
+ if (b1 || b2) {
+ } else {
+ x.expectStaticType<Exactly<int?>>();
+ y.expectStaticType<Exactly<int>>();
+ }
+ }
+ {
+ bool b1 = x is! int;
+ bool b2 = y is! int;
+ b2 = b;
+ if (b1 || b2) {
+ } else {
+ x.expectStaticType<Exactly<int>>();
+ y.expectStaticType<Exactly<int?>>();
+ }
+ }
+ {
+ bool b1 = x is! int;
+ bool b2 = y is! int;
+ bool b3 = b1 || b2;
+ if (b3) {
+ } else {
+ x.expectStaticType<Exactly<int>>();
+ y.expectStaticType<Exactly<int>>();
+ }
+ }
+ {
+ bool b1 = x is! int;
+ x = z;
+ bool b2 = y is! int;
+ bool b3 = b1 || b2;
+ if (b3) {
+ } else {
+ x.expectStaticType<Exactly<int?>>();
+ y.expectStaticType<Exactly<int>>();
+ }
+ }
+ {
+ bool b1 = x is! int;
+ y = z;
+ bool b2 = y is! int;
+ bool b3 = b1 || b2;
+ if (b3) {
+ } else {
+ x.expectStaticType<Exactly<int>>();
+ y.expectStaticType<Exactly<int>>();
+ }
+ }
+ {
+ bool b1 = x is! int;
+ b1 = b;
+ bool b2 = y is! int;
+ bool b3 = b1 || b2;
+ if (b3) {
+ } else {
+ x.expectStaticType<Exactly<int?>>();
+ y.expectStaticType<Exactly<int>>();
+ }
+ }
+ {
+ bool b1 = x is! int;
+ bool b2 = y is! int;
+ x = z;
+ bool b3 = b1 || b2;
+ if (b3) {
+ } else {
+ x.expectStaticType<Exactly<int?>>();
+ y.expectStaticType<Exactly<int>>();
+ }
+ }
+ {
+ bool b1 = x is! int;
+ bool b2 = y is! int;
+ y = z;
+ bool b3 = b1 || b2;
+ if (b3) {
+ } else {
+ x.expectStaticType<Exactly<int>>();
+ y.expectStaticType<Exactly<int?>>();
+ }
+ }
+ {
+ bool b1 = x is! int;
+ bool b2 = y is! int;
+ b1 = b;
+ bool b3 = b1 || b2;
+ if (b3) {
+ } else {
+ x.expectStaticType<Exactly<int?>>();
+ y.expectStaticType<Exactly<int>>();
+ }
+ }
+ {
+ bool b1 = x is! int;
+ bool b2 = y is! int;
+ b2 = b;
+ bool b3 = b1 || b2;
+ if (b3) {
+ } else {
+ x.expectStaticType<Exactly<int>>();
+ y.expectStaticType<Exactly<int?>>();
+ }
+ }
+ {
+ bool b1 = x is! int;
+ bool b2 = y is! int;
+ bool b3 = b1 || b2;
+ x = z;
+ if (b3) {
+ } else {
+ x.expectStaticType<Exactly<int?>>();
+ y.expectStaticType<Exactly<int>>();
+ }
+ }
+ {
+ bool b1 = x is! int;
+ bool b2 = y is! int;
+ bool b3 = b1 || b2;
+ y = z;
+ if (b3) {
+ } else {
+ x.expectStaticType<Exactly<int>>();
+ y.expectStaticType<Exactly<int?>>();
+ }
+ }
+ {
+ bool b1 = x is! int;
+ bool b2 = y is! int;
+ bool b3 = b1 || b2;
+ b1 = b;
+ if (b3) {
+ } else {
+ x.expectStaticType<Exactly<int>>();
+ y.expectStaticType<Exactly<int>>();
+ }
+ }
+ {
+ bool b1 = x is! int;
+ bool b2 = y is! int;
+ bool b3 = b1 || b2;
+ b2 = b;
+ if (b3) {
+ } else {
+ x.expectStaticType<Exactly<int>>();
+ y.expectStaticType<Exactly<int>>();
+ }
+ }
+ {
+ bool b1 = x is! int;
+ bool b2 = y is! int;
+ bool b3 = b1 || b2;
+ b3 = b;
+ if (b3) {
+ } else {
+ x.expectStaticType<Exactly<int?>>();
+ y.expectStaticType<Exactly<int?>>();
+ }
+ }
+}
+
+main() {
+ testAnd(1, 2, 3, true);
+ testAnd(1, 2, 3, false);
+ testAnd(1, 2, null, true);
+ testAnd(1, 2, null, false);
+ testAnd(1, null, 3, true);
+ testAnd(1, null, 3, false);
+ testAnd(1, null, null, true);
+ testAnd(1, null, null, false);
+ testAnd(null, 2, 3, true);
+ testAnd(null, 2, 3, false);
+ testAnd(null, 2, null, true);
+ testAnd(null, 2, null, false);
+ testAnd(null, null, 3, true);
+ testAnd(null, null, 3, false);
+ testAnd(null, null, null, true);
+ testAnd(null, null, null, false);
+ testOr(1, 2, 3, true);
+ testOr(1, 2, 3, false);
+ testOr(1, 2, null, true);
+ testOr(1, 2, null, false);
+ testOr(1, null, 3, true);
+ testOr(1, null, 3, false);
+ testOr(1, null, null, true);
+ testOr(1, null, null, false);
+ testOr(null, 2, 3, true);
+ testOr(null, 2, 3, false);
+ testOr(null, 2, null, true);
+ testOr(null, 2, null, false);
+ testOr(null, null, 3, true);
+ testOr(null, null, 3, false);
+ testOr(null, null, null, true);
+ testOr(null, null, null, false);
+}
diff --git a/tests/language/nnbd/flow_analysis/local_boolean_null_test.dart b/tests/language/nnbd/flow_analysis/local_boolean_null_test.dart
new file mode 100644
index 0000000..d995051
--- /dev/null
+++ b/tests/language/nnbd/flow_analysis/local_boolean_null_test.dart
@@ -0,0 +1,27 @@
+// 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 '../../static_type_helper.dart';
+
+// This test checks that a local variable whose value is `null` cannot be used
+// in place of a literal `null` in flow analysis.
+
+test(int? x) {
+ if (x == null) {
+ x.expectStaticType<Exactly<int?>>();
+ } else {
+ x.expectStaticType<Exactly<int>>();
+ }
+ int? y = null;
+ if (x == y) {
+ x.expectStaticType<Exactly<int?>>();
+ } else {
+ x.expectStaticType<Exactly<int?>>();
+ }
+}
+
+main() {
+ test(0);
+ test(null);
+}
diff --git a/tests/language/nnbd/flow_analysis/local_boolean_promoted_on_assignment_test.dart b/tests/language/nnbd/flow_analysis/local_boolean_promoted_on_assignment_test.dart
new file mode 100644
index 0000000..e291ff8
--- /dev/null
+++ b/tests/language/nnbd/flow_analysis/local_boolean_promoted_on_assignment_test.dart
@@ -0,0 +1,49 @@
+// 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 '../../static_type_helper.dart';
+
+// This test checks that local variables can be used to perform type promotion
+// even in the case where the assignment ot (or initialization of) the local
+// variable promotes it.
+
+test(int? x) {
+ {
+ bool? b = null; // Makes `bool` a type of interest for `b`
+ b = x != null; // Promotes `b` to `bool`
+ b.expectStaticType<Exactly<bool>>();
+ if (b) {
+ x.expectStaticType<Exactly<int>>();
+ } else {
+ x.expectStaticType<Exactly<int?>>();
+ }
+ }
+ {
+ Object b = Object();
+ if (b is! bool) {
+ // Makes `bool` a type of interest for `b`
+ b = x != null; // Promotes `b` to `bool`
+ b.expectStaticType<Exactly<bool>>();
+ if (b) {
+ x.expectStaticType<Exactly<int>>();
+ } else {
+ x.expectStaticType<Exactly<int?>>();
+ }
+ }
+ }
+ {
+ bool? b = x != null; // Promotes `b` to `bool`
+ b.expectStaticType<Exactly<bool>>();
+ if (b) {
+ x.expectStaticType<Exactly<int>>();
+ } else {
+ x.expectStaticType<Exactly<int?>>();
+ }
+ }
+}
+
+main() {
+ test(null);
+ test(0);
+}
diff --git a/tests/language/nnbd/flow_analysis/local_boolean_promoted_test.dart b/tests/language/nnbd/flow_analysis/local_boolean_promoted_test.dart
new file mode 100644
index 0000000..681bcb7
--- /dev/null
+++ b/tests/language/nnbd/flow_analysis/local_boolean_promoted_test.dart
@@ -0,0 +1,20 @@
+// 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 '../../static_type_helper.dart';
+
+// This test checks that local variables can be used to perform type promotion
+// even in the case where the local variable is itself promoted.
+
+test(int? x) {
+ Object b = x != null;
+ if (b is bool && b) {
+ x.expectStaticType<Exactly<int>>();
+ }
+}
+
+main() {
+ test(null);
+ test(0);
+}
diff --git a/tests/language/nnbd/flow_analysis/local_boolean_test.dart b/tests/language/nnbd/flow_analysis/local_boolean_test.dart
new file mode 100644
index 0000000..0e8450d
--- /dev/null
+++ b/tests/language/nnbd/flow_analysis/local_boolean_test.dart
@@ -0,0 +1,814 @@
+// 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 '../../static_type_helper.dart';
+
+// This test checks whether a local boolean variable can be used to perform type
+// promotion, for various ways of declaring and assigning to it.
+//
+// For the boolean, we test all combinations of:
+// - type `bool`, `Object`, `Object?`, or `dynamic`
+// - late or non-late
+// - final or non-final
+// - assigned at initialization time or later
+// For the promoted variable, we test all combinations of:
+// - parameter, unmodified from its initial value
+// - parameter, assigned later
+// - local variable, assigned at initialization
+// - local variable, assigned later
+
+parameterUnmodified(int? x) {
+ {
+ late final bool b = x != null;
+ // We don't promote based on the initializers of late locals because we
+ // don't know when they execute.
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ late final bool b;
+ b = x != null;
+ // We do promote based on assignments to late locals because we do know when
+ // they execute.
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ {
+ late bool b = x != null;
+ // We don't promote based on the initializers of late locals because we
+ // don't know when they execute.
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ late bool b;
+ b = x != null;
+ // We do promote based on assignments to late locals because we do know when
+ // they execute.
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ {
+ final bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ {
+ final bool b;
+ b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ {
+ bool b;
+ b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ {
+ late final Object b = x != null;
+ // We don't promote based on the initializers of late locals because we
+ // don't know when they execute.
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ late final Object b;
+ b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ late Object b = x != null;
+ // We don't promote based on the initializers of late locals because we
+ // don't know when they execute.
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ late Object b;
+ b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ final Object b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ final Object b;
+ b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ Object b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ Object b;
+ b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ late final Object? b = x != null;
+ // We don't promote based on the initializers of late locals because we
+ // don't know when they execute.
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ late final Object? b;
+ b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ late Object? b = x != null;
+ // We don't promote based on the initializers of late locals because we
+ // don't know when they execute.
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ late Object? b;
+ b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ final Object? b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ final Object? b;
+ b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ Object? b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ Object? b;
+ b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ late final dynamic b = x != null;
+ // We don't promote based on the initializers of late locals because we
+ // don't know when they execute.
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ late final dynamic b;
+ b = x != null;
+ // We do promote based on assignments to late locals because we do know when
+ // they execute.
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ {
+ late dynamic b = x != null;
+ // We don't promote based on the initializers of late locals because we
+ // don't know when they execute.
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ late dynamic b;
+ b = x != null;
+ // We do promote based on assignments to late locals because we do know when
+ // they execute.
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ {
+ final dynamic b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ {
+ final dynamic b;
+ b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ {
+ dynamic b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ {
+ dynamic b;
+ b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+}
+
+parameterModifiedLater(int? x, int? y) {
+ x = y;
+ {
+ late final bool b = x != null;
+ // We don't promote based on the initializers of late locals because we
+ // don't know when they execute.
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ late final bool b;
+ b = x != null;
+ // We do promote based on assignments to late locals because we do know when
+ // they execute.
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ {
+ late bool b = x != null;
+ // We don't promote based on the initializers of late locals because we
+ // don't know when they execute.
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ late bool b;
+ b = x != null;
+ // We do promote based on assignments to late locals because we do know when
+ // they execute.
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ {
+ final bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ {
+ final bool b;
+ b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ {
+ bool b;
+ b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ {
+ late final Object b = x != null;
+ // We don't promote based on the initializers of late locals because we
+ // don't know when they execute.
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ late final Object b;
+ b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ late Object b = x != null;
+ // We don't promote based on the initializers of late locals because we
+ // don't know when they execute.
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ late Object b;
+ b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ final Object b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ final Object b;
+ b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ Object b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ Object b;
+ b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ late final Object? b = x != null;
+ // We don't promote based on the initializers of late locals because we
+ // don't know when they execute.
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ late final Object? b;
+ b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ late Object? b = x != null;
+ // We don't promote based on the initializers of late locals because we
+ // don't know when they execute.
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ late Object? b;
+ b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ final Object? b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ final Object? b;
+ b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ Object? b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ Object? b;
+ b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ late final dynamic b = x != null;
+ // We don't promote based on the initializers of late locals because we
+ // don't know when they execute.
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ late final dynamic b;
+ b = x != null;
+ // We do promote based on assignments to late locals because we do know when
+ // they execute.
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ {
+ late dynamic b = x != null;
+ // We don't promote based on the initializers of late locals because we
+ // don't know when they execute.
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ late dynamic b;
+ b = x != null;
+ // We do promote based on assignments to late locals because we do know when
+ // they execute.
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ {
+ final dynamic b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ {
+ final dynamic b;
+ b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ {
+ dynamic b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ {
+ dynamic b;
+ b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+}
+
+localVariableInitialized(int? y) {
+ int? x = y;
+ {
+ late final bool b = x != null;
+ // We don't promote based on the initializers of late locals because we
+ // don't know when they execute.
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ late final bool b;
+ b = x != null;
+ // We do promote based on assignments to late locals because we do know when
+ // they execute.
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ {
+ late bool b = x != null;
+ // We don't promote based on the initializers of late locals because we
+ // don't know when they execute.
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ late bool b;
+ b = x != null;
+ // We do promote based on assignments to late locals because we do know when
+ // they execute.
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ {
+ final bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ {
+ final bool b;
+ b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ {
+ bool b;
+ b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ {
+ late final Object b = x != null;
+ // We don't promote based on the initializers of late locals because we
+ // don't know when they execute.
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ late final Object b;
+ b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ late Object b = x != null;
+ // We don't promote based on the initializers of late locals because we
+ // don't know when they execute.
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ late Object b;
+ b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ final Object b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ final Object b;
+ b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ Object b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ Object b;
+ b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ late final Object? b = x != null;
+ // We don't promote based on the initializers of late locals because we
+ // don't know when they execute.
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ late final Object? b;
+ b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ late Object? b = x != null;
+ // We don't promote based on the initializers of late locals because we
+ // don't know when they execute.
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ late Object? b;
+ b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ final Object? b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ final Object? b;
+ b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ Object? b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ Object? b;
+ b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ late final dynamic b = x != null;
+ // We don't promote based on the initializers of late locals because we
+ // don't know when they execute.
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ late final dynamic b;
+ b = x != null;
+ // We do promote based on assignments to late locals because we do know when
+ // they execute.
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ {
+ late dynamic b = x != null;
+ // We don't promote based on the initializers of late locals because we
+ // don't know when they execute.
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ late dynamic b;
+ b = x != null;
+ // We do promote based on assignments to late locals because we do know when
+ // they execute.
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ {
+ final dynamic b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ {
+ final dynamic b;
+ b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ {
+ dynamic b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ {
+ dynamic b;
+ b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+}
+
+localVariableModifiedLater(int? y) {
+ int? x;
+ x = y;
+ {
+ late final bool b = x != null;
+ // We don't promote based on the initializers of late locals because we
+ // don't know when they execute.
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ late final bool b;
+ b = x != null;
+ // We do promote based on assignments to late locals because we do know when
+ // they execute.
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ {
+ late bool b = x != null;
+ // We don't promote based on the initializers of late locals because we
+ // don't know when they execute.
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ late bool b;
+ b = x != null;
+ // We do promote based on assignments to late locals because we do know when
+ // they execute.
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ {
+ final bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ {
+ final bool b;
+ b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ {
+ bool b;
+ b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ {
+ late final Object b = x != null;
+ // We don't promote based on the initializers of late locals because we
+ // don't know when they execute.
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ late final Object b;
+ b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ late Object b = x != null;
+ // We don't promote based on the initializers of late locals because we
+ // don't know when they execute.
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ late Object b;
+ b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ final Object b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ final Object b;
+ b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ Object b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ Object b;
+ b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ late final Object? b = x != null;
+ // We don't promote based on the initializers of late locals because we
+ // don't know when they execute.
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ late final Object? b;
+ b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ late Object? b = x != null;
+ // We don't promote based on the initializers of late locals because we
+ // don't know when they execute.
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ late Object? b;
+ b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ final Object? b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ final Object? b;
+ b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ Object? b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ Object? b;
+ b = x != null;
+ // We don't currently recognize that `b as bool` has the same value as `b`,
+ // so we don't promote. TODO(paulberry): should we?
+ if (b as bool) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ late final dynamic b = x != null;
+ // We don't promote based on the initializers of late locals because we
+ // don't know when they execute.
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ late final dynamic b;
+ b = x != null;
+ // We do promote based on assignments to late locals because we do know when
+ // they execute.
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ {
+ late dynamic b = x != null;
+ // We don't promote based on the initializers of late locals because we
+ // don't know when they execute.
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+ {
+ late dynamic b;
+ b = x != null;
+ // We do promote based on assignments to late locals because we do know when
+ // they execute.
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ {
+ final dynamic b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ {
+ final dynamic b;
+ b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ {
+ dynamic b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ {
+ dynamic b;
+ b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+}
+
+main() {
+ parameterUnmodified(null);
+ parameterUnmodified(0);
+ parameterModifiedLater(null, null);
+ parameterModifiedLater(null, 0);
+ localVariableInitialized(null);
+ localVariableInitialized(0);
+ localVariableModifiedLater(null);
+ localVariableModifiedLater(0);
+}
diff --git a/tests/language/nnbd/flow_analysis/local_boolean_try_finally_test.dart b/tests/language/nnbd/flow_analysis/local_boolean_try_finally_test.dart
new file mode 100644
index 0000000..96a4fa1
--- /dev/null
+++ b/tests/language/nnbd/flow_analysis/local_boolean_try_finally_test.dart
@@ -0,0 +1,58 @@
+// 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 '../../static_type_helper.dart';
+
+// This test checks that a local boolean condition variable can be used for
+// promotion in various corner case scenarios involving try/finally statements.
+
+test(int? x, bool b2) {
+ {
+ bool b = b2;
+ try {
+ b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ } finally {
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ {
+ bool b;
+ try {
+ b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ } finally {
+ // Note: we can't do `if (b)` here because `b` is not definitely assigned.
+ }
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ {
+ bool b = b2;
+ try {
+ if (b) x.expectStaticType<Exactly<int?>>();
+ } finally {
+ b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ {
+ bool b;
+ try {
+ // Note: we can't do `if (b)` here because `b` is not definitely assigned.
+ } finally {
+ b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+ if (b) x.expectStaticType<Exactly<int>>();
+ }
+}
+
+main() {
+ test(null, false);
+ test(null, true);
+ test(0, false);
+ test(0, true);
+}
diff --git a/tests/language/nnbd/flow_analysis/local_boolean_undefeated_by_assignment_test.dart b/tests/language/nnbd/flow_analysis/local_boolean_undefeated_by_assignment_test.dart
new file mode 100644
index 0000000..2ee8380
--- /dev/null
+++ b/tests/language/nnbd/flow_analysis/local_boolean_undefeated_by_assignment_test.dart
@@ -0,0 +1,566 @@
+// 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 '../../static_type_helper.dart';
+
+// This test checks various scenarios in which the use of a local variable for
+// type promotion is not defeated by an assignment to the local variable itself
+// or an assignment to the variable that would be promoted, due to the fact that
+// there is no control flow path from the assignment to the use.
+
+lateInitializer_noAssignments(int? x) {
+ bool b = x != null;
+ late final y = b ? x.expectStaticType<Exactly<int>>() : 3;
+}
+
+afterConditionalThen_toConditionalVar(int? x, bool b2) {
+ try {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ b2
+ ? [b = true, if (b) x.expectStaticType<Exactly<int?>>(), throw 'foo']
+ : null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ } on String {}
+}
+
+afterConditionalThen_toPromotedVar(int? x, bool b2, int? y) {
+ try {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ b2
+ ? [x = y, if (b) x.expectStaticType<Exactly<int?>>(), throw 'foo']
+ : null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ } on String {}
+}
+
+afterConditionalElse_toConditionalVar(int? x, bool b2) {
+ try {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ b2
+ ? null
+ : [b = true, if (b) x.expectStaticType<Exactly<int?>>(), throw 'foo'];
+ if (b) x.expectStaticType<Exactly<int>>();
+ } on String {}
+}
+
+afterConditionalElse_toPromotedVar(int? x, bool b2, int? y) {
+ try {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ b2
+ ? null
+ : [x = y, if (b) x.expectStaticType<Exactly<int?>>(), throw 'foo'];
+ if (b) x.expectStaticType<Exactly<int>>();
+ } on String {}
+}
+
+afterIfStatementThen_toConditionalVar(int? x, bool b2) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ if (b2) {
+ b = true;
+ if (b) x.expectStaticType<Exactly<int?>>();
+ return;
+ }
+ if (b) x.expectStaticType<Exactly<int>>();
+}
+
+afterIfStatementThen_toPromotedVar(int? x, bool b2, int? y) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ if (b2) {
+ x = y;
+ if (b) x.expectStaticType<Exactly<int?>>();
+ return;
+ }
+ if (b) x.expectStaticType<Exactly<int>>();
+}
+
+afterIfStatementElse_toConditionalVar(int? x, bool b2) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ if (b2) {
+ } else {
+ b = true;
+ if (b) x.expectStaticType<Exactly<int?>>();
+ return;
+ }
+ if (b) x.expectStaticType<Exactly<int>>();
+}
+
+afterIfStatementElse_toPromotedVar(int? x, bool b2, int? y) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ if (b2) {
+ } else {
+ x = y;
+ if (b) x.expectStaticType<Exactly<int?>>();
+ return;
+ }
+ if (b) x.expectStaticType<Exactly<int>>();
+}
+
+afterIfListThen_toConditionalVar(int? x, bool b2) {
+ try {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ [
+ if (b2)
+ [b = true, if (b) x.expectStaticType<Exactly<int?>>(), throw 'foo']
+ ];
+ if (b) x.expectStaticType<Exactly<int>>();
+ } on String {}
+}
+
+afterIfListThen_toPromotedVar(int? x, bool b2, int? y) {
+ try {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ [
+ if (b2) [x = y, if (b) x.expectStaticType<Exactly<int?>>(), throw 'foo']
+ ];
+ if (b) x.expectStaticType<Exactly<int>>();
+ } on String {}
+}
+
+afterIfListElse_toConditionalVar(int? x, bool b2) {
+ try {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ [
+ if (b2)
+ null
+ else
+ [b = true, if (b) x.expectStaticType<Exactly<int?>>(), throw 'foo']
+ ];
+ if (b) x.expectStaticType<Exactly<int>>();
+ } on String {}
+}
+
+afterIfListElse_toPromotedVar(int? x, bool b2, int? y) {
+ try {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ [
+ if (b2)
+ null
+ else
+ [x = y, if (b) x.expectStaticType<Exactly<int?>>(), throw 'foo']
+ ];
+ if (b) x.expectStaticType<Exactly<int>>();
+ } on String {}
+}
+
+afterIfSetThen_toConditionalVar(int? x, bool b2) {
+ try {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ ({
+ if (b2)
+ [b = true, if (b) x.expectStaticType<Exactly<int?>>(), throw 'foo']
+ });
+ if (b) x.expectStaticType<Exactly<int>>();
+ } on String {}
+}
+
+afterIfSetThen_toPromotedVar(int? x, bool b2, int? y) {
+ try {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ ({
+ if (b2) [x = y, if (b) x.expectStaticType<Exactly<int?>>(), throw 'foo']
+ });
+ if (b) x.expectStaticType<Exactly<int>>();
+ } on String {}
+}
+
+afterIfSetElse_toConditionalVar(int? x, bool b2) {
+ try {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ ({
+ if (b2)
+ null
+ else
+ [b = true, if (b) x.expectStaticType<Exactly<int?>>(), throw 'foo']
+ });
+ if (b) x.expectStaticType<Exactly<int>>();
+ } on String {}
+}
+
+afterIfSetElse_toPromotedVar(int? x, bool b2, int? y) {
+ try {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ ({
+ if (b2)
+ null
+ else
+ [x = y, if (b) x.expectStaticType<Exactly<int?>>(), throw 'foo']
+ });
+ if (b) x.expectStaticType<Exactly<int>>();
+ } on String {}
+}
+
+afterIfMapKeyThen_toConditionalVar(int? x, bool b2) {
+ try {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ ({
+ if (b2)
+ [b = true, if (b) x.expectStaticType<Exactly<int?>>(), throw 'foo']:
+ null
+ });
+ if (b) x.expectStaticType<Exactly<int>>();
+ } on String {}
+}
+
+afterIfMapKeyThen_toPromotedVar(int? x, bool b2, int? y) {
+ try {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ ({
+ if (b2)
+ [x = y, if (b) x.expectStaticType<Exactly<int?>>(), throw 'foo']: null
+ });
+ if (b) x.expectStaticType<Exactly<int>>();
+ } on String {}
+}
+
+afterIfMapKeyElse_toConditionalVar(int? x, bool b2) {
+ try {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ ({
+ if (b2)
+ null: null
+ else
+ [b = true, if (b) x.expectStaticType<Exactly<int?>>(), throw 'foo']:
+ null
+ });
+ if (b) x.expectStaticType<Exactly<int>>();
+ } on String {}
+}
+
+afterIfMapKeyElse_toPromotedVar(int? x, bool b2, int? y) {
+ try {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ ({
+ if (b2)
+ null: null
+ else
+ [x = y, if (b) x.expectStaticType<Exactly<int?>>(), throw 'foo']: null
+ });
+ if (b) x.expectStaticType<Exactly<int>>();
+ } on String {}
+}
+
+afterIfMapValueThen_toConditionalVar(int? x, bool b2) {
+ try {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ ({
+ if (b2)
+ null: [
+ b = true,
+ if (b) x.expectStaticType<Exactly<int?>>(),
+ throw 'foo'
+ ]
+ });
+ if (b) x.expectStaticType<Exactly<int>>();
+ } on String {}
+}
+
+afterIfMapValueThen_toPromotedVar(int? x, bool b2, int? y) {
+ try {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ ({
+ if (b2)
+ null: [x = y, if (b) x.expectStaticType<Exactly<int?>>(), throw 'foo']
+ });
+ if (b) x.expectStaticType<Exactly<int>>();
+ } on String {}
+}
+
+afterIfMapValueElse_toConditionalVar(int? x, bool b2) {
+ try {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ ({
+ if (b2)
+ null: null
+ else
+ null: [
+ b = true,
+ if (b) x.expectStaticType<Exactly<int?>>(),
+ throw 'foo'
+ ]
+ });
+ if (b) x.expectStaticType<Exactly<int>>();
+ } on String {}
+}
+
+afterIfMapValueElse_toPromotedVar(int? x, bool b2, int? y) {
+ try {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ ({
+ if (b2)
+ null: null
+ else
+ null: [x = y, if (b) x.expectStaticType<Exactly<int?>>(), throw 'foo']
+ });
+ if (b) x.expectStaticType<Exactly<int>>();
+ } on String {}
+}
+
+afterSwitch_toConditionalVar(int? x, int i) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ switch (i) {
+ case 0:
+ b = true;
+ if (b) x.expectStaticType<Exactly<int?>>();
+ return;
+ case 1:
+ break;
+ }
+ if (b) x.expectStaticType<Exactly<int>>();
+}
+
+afterSwitch_toPromotedVar(int? x, int i, int? y) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ switch (i) {
+ case 0:
+ x = y;
+ if (b) x.expectStaticType<Exactly<int?>>();
+ return;
+ case 1:
+ break;
+ }
+ if (b) x.expectStaticType<Exactly<int>>();
+}
+
+afterTryCatchTry_toConditionalVar(int? x, bool b2) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ try {
+ if (b2) {
+ b = true;
+ if (b) x.expectStaticType<Exactly<int?>>();
+ return;
+ }
+ } catch (_) {
+ if (b) x.expectStaticType<Exactly<int?>>();
+ return;
+ }
+ if (b) x.expectStaticType<Exactly<int>>();
+}
+
+afterTryCatchTry_toPromotedVar(int? x, bool b2, int? y) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ try {
+ if (b2) {
+ x = y;
+ if (b) x.expectStaticType<Exactly<int?>>();
+ return;
+ }
+ } catch (_) {
+ if (b) x.expectStaticType<Exactly<int?>>();
+ return;
+ }
+ if (b) x.expectStaticType<Exactly<int>>();
+}
+
+afterTryCatchCatch_toConditionalVar(int? x) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ try {} catch (_) {
+ b = true;
+ if (b) x.expectStaticType<Exactly<int?>>();
+ return;
+ }
+ if (b) x.expectStaticType<Exactly<int>>();
+}
+
+afterTryCatchCatch_toPromotedVar(int? x, int? y) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ try {} catch (_) {
+ x = y;
+ if (b) x.expectStaticType<Exactly<int?>>();
+ return;
+ }
+ if (b) x.expectStaticType<Exactly<int>>();
+}
+
+afterTryFinallyTry_toConditionalVar(int? x, bool b2) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ try {
+ if (b2) {
+ b = true;
+ if (b) x.expectStaticType<Exactly<int?>>();
+ return;
+ }
+ } finally {
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+ if (b) x.expectStaticType<Exactly<int>>();
+}
+
+afterTryFinallyTry_toPromotedVar(int? x, bool b2, int? y) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ try {
+ if (b2) {
+ x = y;
+ if (b) x.expectStaticType<Exactly<int?>>();
+ return;
+ }
+ } finally {
+ if (b) x.expectStaticType<Exactly<int?>>();
+ }
+ if (b) x.expectStaticType<Exactly<int>>();
+}
+
+afterTryFinallyFinally_toConditionalVar(int? x, bool b2) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ try {} finally {
+ if (b2) {
+ b = true;
+ if (b) x.expectStaticType<Exactly<int?>>();
+ return;
+ }
+ }
+ if (b) x.expectStaticType<Exactly<int>>();
+}
+
+afterTryFinallyFinally_toPromotedVar(int? x, bool b2, int? y) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ try {} finally {
+ if (b2) {
+ x = y;
+ if (b) x.expectStaticType<Exactly<int?>>();
+ return;
+ }
+ }
+ if (b) x.expectStaticType<Exactly<int>>();
+}
+
+switchLaterUnlabeled_toConditionalVar(int? x, int i) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ switch (i) {
+ case 0:
+ // Promotion is preserved because the case clause is unlabeled, so there's
+ // no path from the assignment back to here.
+ if (b) x.expectStaticType<Exactly<int>>();
+ break;
+ case 1:
+ b = true;
+ break;
+ }
+}
+
+switchLaterUnlabeled_toPromotedVar(int? x, int i, int? y) {
+ bool b = x != null;
+ if (b) x.expectStaticType<Exactly<int>>();
+ switch (i) {
+ case 0:
+ // Promotion is preserved because the case clause is unlabeled, so there's
+ // no path from the assignment back to here.
+ if (b) x.expectStaticType<Exactly<int>>();
+ break;
+ case 1:
+ x = y;
+ break;
+ }
+}
+
+main() {
+ lateInitializer_noAssignments(0);
+ lateInitializer_noAssignments(null);
+ afterConditionalThen_toConditionalVar(0, true);
+ afterConditionalThen_toConditionalVar(null, true);
+ afterConditionalThen_toPromotedVar(0, true, null);
+ afterConditionalThen_toPromotedVar(null, true, null);
+ afterConditionalElse_toConditionalVar(0, false);
+ afterConditionalElse_toConditionalVar(null, false);
+ afterConditionalElse_toPromotedVar(0, false, null);
+ afterConditionalElse_toPromotedVar(null, false, null);
+ afterIfStatementThen_toConditionalVar(0, true);
+ afterIfStatementThen_toConditionalVar(null, true);
+ afterIfStatementThen_toPromotedVar(0, true, null);
+ afterIfStatementThen_toPromotedVar(null, true, null);
+ afterIfStatementElse_toConditionalVar(0, false);
+ afterIfStatementElse_toConditionalVar(null, false);
+ afterIfStatementElse_toPromotedVar(0, false, null);
+ afterIfStatementElse_toPromotedVar(null, false, null);
+ afterIfListThen_toConditionalVar(0, true);
+ afterIfListThen_toConditionalVar(null, true);
+ afterIfListThen_toPromotedVar(0, true, null);
+ afterIfListThen_toPromotedVar(null, true, null);
+ afterIfListElse_toConditionalVar(0, false);
+ afterIfListElse_toConditionalVar(null, false);
+ afterIfListElse_toPromotedVar(0, false, null);
+ afterIfListElse_toPromotedVar(null, false, null);
+ afterIfSetThen_toConditionalVar(0, true);
+ afterIfSetThen_toConditionalVar(null, true);
+ afterIfSetThen_toPromotedVar(0, true, null);
+ afterIfSetThen_toPromotedVar(null, true, null);
+ afterIfSetElse_toConditionalVar(0, false);
+ afterIfSetElse_toConditionalVar(null, false);
+ afterIfSetElse_toPromotedVar(0, false, null);
+ afterIfSetElse_toPromotedVar(null, false, null);
+ afterIfMapKeyThen_toConditionalVar(0, true);
+ afterIfMapKeyThen_toConditionalVar(null, true);
+ afterIfMapKeyThen_toPromotedVar(0, true, null);
+ afterIfMapKeyThen_toPromotedVar(null, true, null);
+ afterIfMapKeyElse_toConditionalVar(0, false);
+ afterIfMapKeyElse_toConditionalVar(null, false);
+ afterIfMapKeyElse_toPromotedVar(0, false, null);
+ afterIfMapKeyElse_toPromotedVar(null, false, null);
+ afterIfMapValueThen_toConditionalVar(0, true);
+ afterIfMapValueThen_toConditionalVar(null, true);
+ afterIfMapValueThen_toPromotedVar(0, true, null);
+ afterIfMapValueThen_toPromotedVar(null, true, null);
+ afterIfMapValueElse_toConditionalVar(0, false);
+ afterIfMapValueElse_toConditionalVar(null, false);
+ afterIfMapValueElse_toPromotedVar(0, false, null);
+ afterIfMapValueElse_toPromotedVar(null, false, null);
+ afterSwitch_toConditionalVar(0, 1);
+ afterSwitch_toConditionalVar(null, 1);
+ afterSwitch_toPromotedVar(0, 1, null);
+ afterSwitch_toPromotedVar(null, 1, null);
+ afterTryCatchTry_toConditionalVar(0, false);
+ afterTryCatchTry_toConditionalVar(null, false);
+ afterTryCatchTry_toPromotedVar(0, false, null);
+ afterTryCatchTry_toPromotedVar(null, false, null);
+ afterTryCatchCatch_toConditionalVar(0);
+ afterTryCatchCatch_toConditionalVar(null);
+ afterTryCatchCatch_toPromotedVar(0, null);
+ afterTryCatchCatch_toPromotedVar(null, null);
+ afterTryFinallyTry_toConditionalVar(0, false);
+ afterTryFinallyTry_toConditionalVar(null, false);
+ afterTryFinallyTry_toPromotedVar(0, false, null);
+ afterTryFinallyTry_toPromotedVar(null, false, null);
+ afterTryFinallyFinally_toConditionalVar(0, false);
+ afterTryFinallyFinally_toConditionalVar(null, false);
+ afterTryFinallyFinally_toPromotedVar(0, false, null);
+ afterTryFinallyFinally_toPromotedVar(null, false, null);
+ switchLaterUnlabeled_toConditionalVar(0, 0);
+ switchLaterUnlabeled_toConditionalVar(null, 0);
+ switchLaterUnlabeled_toPromotedVar(0, 0, null);
+ switchLaterUnlabeled_toPromotedVar(null, 0, null);
+}
diff --git a/tests/lib/js/native_as_js_classes_static_test/default_library_namespace_test.dart b/tests/lib/js/native_as_js_classes_static_test/default_library_namespace_test.dart
deleted file mode 100644
index d230129..0000000
--- a/tests/lib/js/native_as_js_classes_static_test/default_library_namespace_test.dart
+++ /dev/null
@@ -1,75 +0,0 @@
-// 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.
-
-// Test errors with a library with the default namespace.
-
-@JS()
-library default_library_namespace_test;
-
-import 'package:js/js.dart';
-
-// Test same class name as a native class.
-@JS()
-class HTMLDocument {}
-// ^
-// [web] JS interop class 'HTMLDocument' conflicts with natively supported class 'HtmlDocument' in 'dart:html'.
-
-// Test same annotation name as a native class.
-@JS('HTMLDocument')
-class HtmlDocument {}
-// ^
-// [web] JS interop class 'HtmlDocument' conflicts with natively supported class 'HtmlDocument' in 'dart:html'.
-
-// Test annotation name with 'self' and 'window' prefixes.
-@JS('self.Window')
-class WindowWithSelf {}
-// ^
-// [web] JS interop class 'WindowWithSelf' conflicts with natively supported class 'Window' in 'dart:html'.
-
-@JS('window.Window')
-class WindowWithWindow {}
-// ^
-// [web] JS interop class 'WindowWithWindow' conflicts with natively supported class 'Window' in 'dart:html'.
-
-@JS('self.window.self.window.self.Window')
-class WindowWithMultipleSelfsAndWindows {}
-// ^
-// [web] JS interop class 'WindowWithMultipleSelfsAndWindows' conflicts with natively supported class 'Window' in 'dart:html'.
-
-// Test annotation with native class name but with a prefix that isn't 'self' or
-// 'window'.
-@JS('foo.Window')
-class WindowWithDifferentPrefix {}
-
-// Test same class name as a native class with multiple annotation names.
-// dart:html.Window uses both "Window" and "DOMWindow".
-@JS()
-class DOMWindow {}
-// ^
-// [web] JS interop class 'DOMWindow' conflicts with natively supported class 'Window' in 'dart:html'.
-
-// Test same annotation name as a native class with multiple annotation names
-// dart:html.Window uses both "Window" and "DOMWindow".
-@JS('DOMWindow')
-class DomWindow {}
-// ^
-// [web] JS interop class 'DomWindow' conflicts with natively supported class 'Window' in 'dart:html'.
-
-// Test different annotation name but with same class name as a @Native class.
-@JS('Foo')
-class Window {}
-
-// Dart classes don't have to worry about conflicts.
-class Element {}
-
-// Anonymous classes don't have to worry about conflicts either.
-@JS()
-@anonymous
-class HTMLElement {}
-
-@JS('HTMLElement')
-@anonymous
-class HtmlElement {}
-
-void main() {}
diff --git a/tests/lib/js/native_as_js_classes_static_test/global_library_namespace_test.dart b/tests/lib/js/native_as_js_classes_static_test/global_library_namespace_test.dart
deleted file mode 100644
index fb55aa6..0000000
--- a/tests/lib/js/native_as_js_classes_static_test/global_library_namespace_test.dart
+++ /dev/null
@@ -1,63 +0,0 @@
-// 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.
-
-// Test errors with a library with a global namespace.
-
-@JS('window')
-library global_library_namespace_test;
-
-import 'package:js/js.dart';
-
-@JS()
-class HTMLDocument {}
-// ^
-// [web] JS interop class 'HTMLDocument' conflicts with natively supported class 'HtmlDocument' in 'dart:html'.
-
-@JS('HTMLDocument')
-class HtmlDocument {}
-// ^
-// [web] JS interop class 'HtmlDocument' conflicts with natively supported class 'HtmlDocument' in 'dart:html'.
-
-@JS('self.Window')
-class WindowWithSelf {}
-// ^
-// [web] JS interop class 'WindowWithSelf' conflicts with natively supported class 'Window' in 'dart:html'.
-
-@JS('window.Window')
-class WindowWithWindow {}
-// ^
-// [web] JS interop class 'WindowWithWindow' conflicts with natively supported class 'Window' in 'dart:html'.
-
-@JS('self.window.self.window.self.Window')
-class WindowWithMultipleSelfsAndWindows {}
-// ^
-// [web] JS interop class 'WindowWithMultipleSelfsAndWindows' conflicts with natively supported class 'Window' in 'dart:html'.
-
-@JS('foo.Window')
-class WindowWithDifferentPrefix {}
-
-@JS()
-class DOMWindow {}
-// ^
-// [web] JS interop class 'DOMWindow' conflicts with natively supported class 'Window' in 'dart:html'.
-
-@JS('DOMWindow')
-class DomWindow {}
-// ^
-// [web] JS interop class 'DomWindow' conflicts with natively supported class 'Window' in 'dart:html'.
-
-@JS('Foo')
-class Window {}
-
-class Element {}
-
-@JS()
-@anonymous
-class HTMLElement {}
-
-@JS('HTMLElement')
-@anonymous
-class HtmlElement {}
-
-void main() {}
diff --git a/tests/lib/js/native_as_js_classes_static_test/local_library_namespace_test.dart b/tests/lib/js/native_as_js_classes_static_test/local_library_namespace_test.dart
deleted file mode 100644
index e529bfa..0000000
--- a/tests/lib/js/native_as_js_classes_static_test/local_library_namespace_test.dart
+++ /dev/null
@@ -1,50 +0,0 @@
-// 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.
-
-// Test errors with a library with a non-default or non-global namespace.
-// Note that none of the following should be errors in this case.
-
-@JS('foo')
-library global_library_namespace_test;
-
-import 'package:js/js.dart';
-
-@JS()
-class HTMLDocument {}
-
-@JS('HTMLDocument')
-class HtmlDocument {}
-
-@JS('self.Window')
-class WindowWithSelf {}
-
-@JS('window.Window')
-class WindowWithWindow {}
-
-@JS('self.window.self.window.self.Window')
-class WindowWithMultipleSelfsAndWindows {}
-
-@JS('foo.Window')
-class WindowWithDifferentPrefix {}
-
-@JS()
-class DOMWindow {}
-
-@JS('DOMWindow')
-class DomWindow {}
-
-@JS('Foo')
-class Window {}
-
-class Element {}
-
-@JS()
-@anonymous
-class HTMLElement {}
-
-@JS('HTMLElement')
-@anonymous
-class HtmlElement {}
-
-void main() {}
diff --git a/tools/VERSION b/tools/VERSION
index 823332b..aca474e 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 12
PATCH 0
-PRERELEASE 207
+PRERELEASE 208
PRERELEASE_PATCH 0
\ No newline at end of file