Skip to content

Commit 15a3df3

Browse files
stereotype441commit-bot@chromium.org
authored andcommitted
Migration: add support for cascade expressions.
Change-Id: Iae52bef6a18c9536db3187102566423bc2f1dba8 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/105325 Reviewed-by: Brian Wilkerson <[email protected]> Reviewed-by: Konstantin Shcheglov <[email protected]> Commit-Queue: Paul Berry <[email protected]>
1 parent da66902 commit 15a3df3

File tree

3 files changed

+299
-23
lines changed

3 files changed

+299
-23
lines changed

pkg/analysis_server/lib/src/nullability/graph_builder.dart

Lines changed: 40 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,13 @@ class GraphBuilder extends GeneralizingAstVisitor<DecoratedType> {
212212
return DecoratedType(node.staticType, NullabilityNode.never);
213213
}
214214

215+
@override
216+
DecoratedType visitCascadeExpression(CascadeExpression node) {
217+
var type = node.target.accept(this);
218+
node.cascadeSections.accept(this);
219+
return type;
220+
}
221+
215222
@override
216223
DecoratedType visitClassDeclaration(ClassDeclaration node) {
217224
node.members.accept(this);
@@ -313,8 +320,9 @@ class GraphBuilder extends GeneralizingAstVisitor<DecoratedType> {
313320
@override
314321
DecoratedType visitIndexExpression(IndexExpression node) {
315322
DecoratedType targetType;
316-
if (node.target != null) {
317-
targetType = _handleAssignment(_notNullType, node.target);
323+
var target = node.realTarget;
324+
if (target != null) {
325+
targetType = _handleAssignment(_notNullType, target);
318326
}
319327
var callee = node.staticElement;
320328
if (callee == null) {
@@ -353,12 +361,17 @@ class GraphBuilder extends GeneralizingAstVisitor<DecoratedType> {
353361
@override
354362
DecoratedType visitMethodInvocation(MethodInvocation node) {
355363
DecoratedType targetType;
356-
if (node.target != null) {
357-
if (node.operator.type != TokenType.PERIOD) {
358-
throw new UnimplementedError('TODO(paulberry)');
364+
var target = node.realTarget;
365+
if (target != null) {
366+
switch (node.operator.type) {
367+
case TokenType.PERIOD:
368+
case TokenType.PERIOD_PERIOD:
369+
_checkNonObjectMember(node.methodName.name); // TODO(paulberry)
370+
targetType = _handleAssignment(_notNullType, target);
371+
break;
372+
default:
373+
throw new UnimplementedError('TODO(paulberry)');
359374
}
360-
_checkNonObjectMember(node.methodName.name); // TODO(paulberry)
361-
targetType = _handleAssignment(_notNullType, node.target);
362375
}
363376
var callee = node.methodName.staticElement;
364377
if (callee == null) {
@@ -423,7 +436,8 @@ class GraphBuilder extends GeneralizingAstVisitor<DecoratedType> {
423436

424437
@override
425438
DecoratedType visitPropertyAccess(PropertyAccess node) {
426-
return _handlePropertyAccess(node.target, node.operator, node.propertyName);
439+
return _handlePropertyAccess(
440+
node.realTarget, node.operator, node.propertyName);
427441
}
428442

429443
@override
@@ -568,21 +582,24 @@ class GraphBuilder extends GeneralizingAstVisitor<DecoratedType> {
568582

569583
DecoratedType _handlePropertyAccess(
570584
Expression target, Token operator, SimpleIdentifier propertyName) {
571-
if (operator.type != TokenType.PERIOD) {
572-
throw new UnimplementedError('TODO(paulberry)');
573-
}
574-
_checkNonObjectMember(propertyName.name); // TODO(paulberry)
575-
var targetType = _handleAssignment(_notNullType, target);
576-
var callee = propertyName.staticElement;
577-
if (callee == null) {
578-
throw new UnimplementedError('TODO(paulberry)');
579-
}
580-
var calleeType = getOrComputeElementType(callee, targetType: targetType);
581-
// TODO(paulberry): substitute if necessary
582-
if (propertyName.inSetterContext()) {
583-
return calleeType.positionalParameters[0];
584-
} else {
585-
return calleeType.returnType;
585+
switch (operator.type) {
586+
case TokenType.PERIOD:
587+
case TokenType.PERIOD_PERIOD:
588+
_checkNonObjectMember(propertyName.name); // TODO(paulberry)
589+
var targetType = _handleAssignment(_notNullType, target);
590+
var callee = propertyName.staticElement;
591+
if (callee == null) {
592+
throw new UnimplementedError('TODO(paulberry)');
593+
}
594+
var calleeType =
595+
getOrComputeElementType(callee, targetType: targetType);
596+
// TODO(paulberry): substitute if necessary
597+
if (propertyName.inSetterContext()) {
598+
return calleeType.positionalParameters[0];
599+
}
600+
return calleeType.returnType;
601+
default:
602+
throw new UnimplementedError('TODO(paulberry)');
586603
}
587604
}
588605

pkg/analysis_server/test/src/nullability/migration_visitor_test.dart

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,20 @@ void f(C c, int i) {
122122
hard: true);
123123
}
124124

125+
test_assignmentExpression_field_cascaded() async {
126+
await analyze('''
127+
class C {
128+
int x = 0;
129+
}
130+
void f(C c, int i) {
131+
c..x = i;
132+
}
133+
''');
134+
assertEdge(decoratedTypeAnnotation('int i').node,
135+
decoratedTypeAnnotation('int x').node,
136+
hard: true);
137+
}
138+
125139
test_assignmentExpression_field_target_check() async {
126140
await analyze('''
127141
class C {
@@ -135,6 +149,19 @@ void f(C c, int i) {
135149
checkExpression('c.x'), decoratedTypeAnnotation('C c').node);
136150
}
137151

152+
test_assignmentExpression_field_target_check_cascaded() async {
153+
await analyze('''
154+
class C {
155+
int x = 0;
156+
}
157+
void f(C c, int i) {
158+
c..x = i;
159+
}
160+
''');
161+
assertNullCheck(
162+
checkExpression('c..x'), decoratedTypeAnnotation('C c').node);
163+
}
164+
138165
test_assignmentExpression_indexExpression_index() async {
139166
await analyze('''
140167
class C {
@@ -318,6 +345,18 @@ bool f() {
318345
assertNoUpstreamNullability(decoratedTypeAnnotation('bool').node);
319346
}
320347

348+
test_cascadeExpression() async {
349+
await analyze('''
350+
class C {
351+
int x = 0;
352+
}
353+
C f(C c, int i) => c..x = i;
354+
''');
355+
assertEdge(decoratedTypeAnnotation('C c').node,
356+
decoratedTypeAnnotation('C f').node,
357+
hard: false);
358+
}
359+
321360
test_conditionalExpression_condition_check() async {
322361
await analyze('''
323362
int f(bool b, int i, int j) {
@@ -680,6 +719,18 @@ int f(C c, int j) => c[j];
680719
hard: true);
681720
}
682721

722+
test_indexExpression_index_cascaded() async {
723+
await analyze('''
724+
class C {
725+
int operator[](int i) => 1;
726+
}
727+
C f(C c, int j) => c..[j];
728+
''');
729+
assertEdge(decoratedTypeAnnotation('int j').node,
730+
decoratedTypeAnnotation('int i').node,
731+
hard: true);
732+
}
733+
683734
test_indexExpression_return_type() async {
684735
await analyze('''
685736
class C {
@@ -702,6 +753,37 @@ int f(C c) => c[0];
702753
assertNullCheck(checkExpression('c['), decoratedTypeAnnotation('C c').node);
703754
}
704755

756+
test_indexExpression_target_check_cascaded() async {
757+
await analyze('''
758+
class C {
759+
int operator[](int i) => 1;
760+
}
761+
C f(C c) => c..[0];
762+
''');
763+
assertNullCheck(
764+
checkExpression('c..['), decoratedTypeAnnotation('C c').node);
765+
}
766+
767+
test_indexExpression_target_demonstrates_non_null_intent() async {
768+
await analyze('''
769+
class C {
770+
int operator[](int i) => 1;
771+
}
772+
int f(C c) => c[0];
773+
''');
774+
assertEdge(decoratedTypeAnnotation('C c').node, never, hard: true);
775+
}
776+
777+
test_indexExpression_target_demonstrates_non_null_intent_cascaded() async {
778+
await analyze('''
779+
class C {
780+
int operator[](int i) => 1;
781+
}
782+
C f(C c) => c..[0];
783+
''');
784+
assertEdge(decoratedTypeAnnotation('C c').node, never, hard: true);
785+
}
786+
705787
test_intLiteral() async {
706788
await analyze('''
707789
int f() {
@@ -809,6 +891,20 @@ void test(C c) {
809891
checkExpression('c.m'), decoratedTypeAnnotation('C c').node);
810892
}
811893

894+
test_methodInvocation_target_check_cascaded() async {
895+
await analyze('''
896+
class C {
897+
void m() {}
898+
}
899+
void test(C c) {
900+
c..m();
901+
}
902+
''');
903+
904+
assertNullCheck(
905+
checkExpression('c..m'), decoratedTypeAnnotation('C c').node);
906+
}
907+
812908
test_methodInvocation_target_demonstrates_non_null_intent() async {
813909
await analyze('''
814910
class C {
@@ -822,6 +918,19 @@ void test(C c) {
822918
assertEdge(decoratedTypeAnnotation('C c').node, never, hard: true);
823919
}
824920

921+
test_methodInvocation_target_demonstrates_non_null_intent_cascaded() async {
922+
await analyze('''
923+
class C {
924+
void m() {}
925+
}
926+
void test(C c) {
927+
c..m();
928+
}
929+
''');
930+
931+
assertEdge(decoratedTypeAnnotation('C c').node, never, hard: true);
932+
}
933+
825934
test_never() async {
826935
await analyze('');
827936

0 commit comments

Comments
 (0)