Add migration tool support for bare "return;" statements
Change-Id: I10e2adeaf3c682ccac011b307c43052178b0974a
Reviewed-on: https://dart-review.googlesource.com/c/93040
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Dan Rubel <danrubel@google.com>
diff --git a/pkg/analysis_server/lib/src/nullability/constraint_gatherer.dart b/pkg/analysis_server/lib/src/nullability/constraint_gatherer.dart
index e1e0f34..12f4ca5 100644
--- a/pkg/analysis_server/lib/src/nullability/constraint_gatherer.dart
+++ b/pkg/analysis_server/lib/src/nullability/constraint_gatherer.dart
@@ -49,6 +49,9 @@
/// For convenience, a [DecoratedType] representing non-nullable `Type`.
final DecoratedType _nonNullableTypeType;
+ /// For convenience, a [DecoratedType] representing `Null`.
+ final DecoratedType _nullType;
+
/// The [DecoratedType] of the innermost function or method being visited, or
/// `null` if the visitor is not inside any function or method.
///
@@ -72,7 +75,9 @@
this._constraints, this._source, this._permissive, this.assumptions)
: _notNullType = DecoratedType(typeProvider.objectType, null),
_nonNullableBoolType = DecoratedType(typeProvider.boolType, null),
- _nonNullableTypeType = DecoratedType(typeProvider.typeType, null);
+ _nonNullableTypeType = DecoratedType(typeProvider.typeType, null),
+ _nullType =
+ DecoratedType(typeProvider.nullType, ConstraintVariable.always);
/// Gets the decorated type of [element] from [_variables], performing any
/// necessary substitutions.
@@ -324,7 +329,7 @@
@override
DecoratedType visitNullLiteral(NullLiteral node) {
- return DecoratedType(node.staticType, ConstraintVariable.always);
+ return _nullType;
}
@override
@@ -334,9 +339,11 @@
@override
DecoratedType visitReturnStatement(ReturnStatement node) {
- // TODO(paulberry): handle implicit return
- assert(node.expression != null); // TODO(paulberry)
- _handleAssignment(_currentFunctionType.returnType, node.expression);
+ if (node.expression == null) {
+ _checkAssignment(_currentFunctionType.returnType, _nullType, null);
+ } else {
+ _handleAssignment(_currentFunctionType.returnType, node.expression);
+ }
return null;
}
@@ -444,6 +451,7 @@
/// call sites.
bool _isSimple(DecoratedType type) {
if (type.type.isBottom) return true;
+ if (type.type.isVoid) return true;
if (type.type is! InterfaceType) return false;
if ((type.type as InterfaceType).typeParameters.isNotEmpty) return false;
return true;
diff --git a/pkg/analysis_server/test/src/nullability/migration_visitor_test.dart b/pkg/analysis_server/test/src/nullability/migration_visitor_test.dart
index 12c9333..e64f358 100644
--- a/pkg/analysis_server/test/src/nullability/migration_visitor_test.dart
+++ b/pkg/analysis_server/test/src/nullability/migration_visitor_test.dart
@@ -552,6 +552,18 @@
[ConstraintVariable.always], decoratedTypeAnnotation('int').nullable);
}
+ test_return_implicit_null() async {
+ verifyNoTestUnitErrors = false;
+ await analyze('''
+int f() {
+ return;
+}
+''');
+
+ assertConstraint(
+ [ConstraintVariable.always], decoratedTypeAnnotation('int').nullable);
+ }
+
test_return_null() async {
await analyze('''
int f() {