Migration: support assignments to fields and setters.
Change-Id: I4dbf43878f5cbf0a16a041e0975880c3d844fa13
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/105041
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
diff --git a/pkg/analysis_server/lib/src/nullability/graph_builder.dart b/pkg/analysis_server/lib/src/nullability/graph_builder.dart
index ef7aa27..f467a40 100644
--- a/pkg/analysis_server/lib/src/nullability/graph_builder.dart
+++ b/pkg/analysis_server/lib/src/nullability/graph_builder.dart
@@ -114,13 +114,17 @@
baseElement.isSynthetic &&
!baseElement.variable.isSynthetic) {
var variable = baseElement.variable;
+ var decoratedElementType =
+ _variables.decoratedElementType(variable, create: true);
if (baseElement.isGetter) {
decoratedBaseType = DecoratedType(
baseElement.type, NullabilityNode.never,
- returnType:
- _variables.decoratedElementType(variable, create: true));
+ returnType: decoratedElementType);
} else {
- throw UnimplementedError('TODO(paulberry)');
+ assert(baseElement.isSetter);
+ decoratedBaseType = DecoratedType(
+ baseElement.type, NullabilityNode.never,
+ positionalParameters: [decoratedElementType]);
}
} else {
decoratedBaseType =
@@ -575,7 +579,11 @@
}
var calleeType = getOrComputeElementType(callee, targetType: targetType);
// TODO(paulberry): substitute if necessary
- return calleeType.returnType;
+ if (propertyName.inSetterContext()) {
+ return calleeType.positionalParameters[0];
+ } else {
+ return calleeType.returnType;
+ }
}
/// Double checks that [type] is sufficiently simple for this naive prototype
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 b325134..daa4bed 100644
--- a/pkg/analysis_server/test/src/nullability/migration_visitor_test.dart
+++ b/pkg/analysis_server/test/src/nullability/migration_visitor_test.dart
@@ -108,6 +108,33 @@
assertEdge(decoratedTypeAnnotation('int i').node, never, hard: true);
}
+ test_assignmentExpression_field() async {
+ await analyze('''
+class C {
+ int x = 0;
+}
+void f(C c, int i) {
+ c.x = i;
+}
+''');
+ assertEdge(decoratedTypeAnnotation('int i').node,
+ decoratedTypeAnnotation('int x').node,
+ hard: true);
+ }
+
+ test_assignmentExpression_field_target_check() async {
+ await analyze('''
+class C {
+ int x = 0;
+}
+void f(C c, int i) {
+ c.x = i;
+}
+''');
+ assertNullCheck(
+ checkExpression('c.x'), decoratedTypeAnnotation('C c').node);
+ }
+
test_assignmentExpression_indexExpression_index() async {
await analyze('''
class C {
@@ -183,6 +210,33 @@
hard: false);
}
+ test_assignmentExpression_setter() async {
+ await analyze('''
+class C {
+ void set s(int value) {}
+}
+void f(C c, int i) {
+ c.s = i;
+}
+''');
+ assertEdge(decoratedTypeAnnotation('int i').node,
+ decoratedTypeAnnotation('int value').node,
+ hard: true);
+ }
+
+ test_assignmentExpression_setter_target_check() async {
+ await analyze('''
+class C {
+ void set s(int value) {}
+}
+void f(C c, int i) {
+ c.s = i;
+}
+''');
+ assertNullCheck(
+ checkExpression('c.s'), decoratedTypeAnnotation('C c').node);
+ }
+
test_binaryExpression_add_left_check() async {
await analyze('''
int f(int i, int j) => i + j;
diff --git a/pkg/analysis_server/test/src/nullability/provisional_api_test.dart b/pkg/analysis_server/test/src/nullability/provisional_api_test.dart
index 07caad0..99c27ce37 100644
--- a/pkg/analysis_server/test/src/nullability/provisional_api_test.dart
+++ b/pkg/analysis_server/test/src/nullability/provisional_api_test.dart
@@ -224,7 +224,27 @@
await _checkSingleFileChanges(content, expected);
}
- test_data_flow_assignment() async {
+ test_data_flow_assignment_field() async {
+ var content = '''
+class C {
+ int x = 0;
+}
+void f(C c) {
+ c.x = null;
+}
+''';
+ var expected = '''
+class C {
+ int? x = 0;
+}
+void f(C c) {
+ c.x = null;
+}
+''';
+ await _checkSingleFileChanges(content, expected);
+ }
+
+ test_data_flow_assignment_local() async {
var content = '''
void main() {
int i = 0;
@@ -240,6 +260,26 @@
await _checkSingleFileChanges(content, expected);
}
+ test_data_flow_assignment_setter() async {
+ var content = '''
+class C {
+ void set s(int value) {}
+}
+void f(C c) {
+ c.s = null;
+}
+''';
+ var expected = '''
+class C {
+ void set s(int? value) {}
+}
+void f(C c) {
+ c.s = null;
+}
+''';
+ await _checkSingleFileChanges(content, expected);
+ }
+
test_data_flow_field_read() async {
var content = '''
class C {