@@ -8,6 +8,7 @@ import 'package:analyzer/dart/element/type.dart';
88import 'package:analyzer/src/dart/element/type.dart' ;
99import 'package:analyzer/src/dart/element/type_provider.dart' ;
1010import 'package:analyzer/src/generated/resolver.dart' ;
11+ import 'package:analyzer/src/generated/source.dart' ;
1112import 'package:analyzer/src/generated/type_system.dart' ;
1213import 'package:nnbd_migration/src/decorated_class_hierarchy.dart' ;
1314import 'package:nnbd_migration/src/fix_builder.dart' ;
@@ -522,6 +523,16 @@ f() => 1.0;
522523 visitSubexpression (findNode.doubleLiteral ('1.0' ), 'double' );
523524 }
524525
526+ test_expressionStatement () async {
527+ await analyze ('''
528+ _f(int/*!*/ x, int/*?*/ y) {
529+ x = y;
530+ }
531+ ''' );
532+ visitStatement (findNode.statement ('x = y' ),
533+ nullChecked: {findNode.simple ('y;' )});
534+ }
535+
525536 test_integerLiteral () async {
526537 await analyze ('''
527538f() => 1;
@@ -649,6 +660,73 @@ f() => #foo;
649660 visitSubexpression (findNode.symbolLiteral ('#foo' ), 'Symbol' );
650661 }
651662
663+ test_typeName_dynamic () async {
664+ await analyze ('''
665+ void _f() {
666+ dynamic d = null;
667+ }
668+ ''' );
669+ visitTypeAnnotation (findNode.typeAnnotation ('dynamic' ), 'dynamic' );
670+ }
671+
672+ test_typeName_generic_nonNullable () async {
673+ await analyze ('''
674+ void _f() {
675+ List<int> i = [0];
676+ }
677+ ''' );
678+ visitTypeAnnotation (findNode.typeAnnotation ('List<int>' ), 'List<int>' );
679+ }
680+
681+ test_typeName_generic_nullable () async {
682+ await analyze ('''
683+ void _f() {
684+ List<int> i = null;
685+ }
686+ ''' );
687+ var listIntAnnotation = findNode.typeAnnotation ('List<int>' );
688+ visitTypeAnnotation (listIntAnnotation, 'List<int>?' ,
689+ nullable: {listIntAnnotation});
690+ }
691+
692+ test_typeName_generic_nullable_arg () async {
693+ await analyze ('''
694+ void _f() {
695+ List<int> i = [null];
696+ }
697+ ''' );
698+ visitTypeAnnotation (findNode.typeAnnotation ('List<int>' ), 'List<int?>' ,
699+ nullable: {findNode.typeAnnotation ('int' )});
700+ }
701+
702+ test_typeName_simple_nonNullable () async {
703+ await analyze ('''
704+ void _f() {
705+ int i = 0;
706+ }
707+ ''' );
708+ visitTypeAnnotation (findNode.typeAnnotation ('int' ), 'int' );
709+ }
710+
711+ test_typeName_simple_nullable () async {
712+ await analyze ('''
713+ void _f() {
714+ int i = null;
715+ }
716+ ''' );
717+ var intAnnotation = findNode.typeAnnotation ('int' );
718+ visitTypeAnnotation ((intAnnotation), 'int?' , nullable: {intAnnotation});
719+ }
720+
721+ test_typeName_void () async {
722+ await analyze ('''
723+ void _f() {
724+ void v;
725+ }
726+ ''' );
727+ visitTypeAnnotation (findNode.typeAnnotation ('void v' ), 'void' );
728+ }
729+
652730 test_use_of_dynamic () async {
653731 // Use of `dynamic` in a context requiring non-null is not explicitly null
654732 // checked.
@@ -658,6 +736,62 @@ bool _f(dynamic d, bool b) => d && b;
658736 visitSubexpression (findNode.binary ('&&' ), 'bool' );
659737 }
660738
739+ test_variableDeclaration_typed_initialized_nonNullable () async {
740+ await analyze ('''
741+ void _f() {
742+ int x = 0;
743+ }
744+ ''' );
745+ visitStatement (findNode.statement ('int x' ));
746+ }
747+
748+ test_variableDeclaration_typed_initialized_nullable () async {
749+ await analyze ('''
750+ void _f() {
751+ int x = null;
752+ }
753+ ''' );
754+ visitStatement (findNode.statement ('int x' ),
755+ nullable: {findNode.typeAnnotation ('int' )});
756+ }
757+
758+ test_variableDeclaration_typed_uninitialized () async {
759+ await analyze ('''
760+ void _f() {
761+ int x;
762+ }
763+ ''' );
764+ visitStatement (findNode.statement ('int x' ));
765+ }
766+
767+ test_variableDeclaration_untyped_initialized () async {
768+ await analyze ('''
769+ void _f() {
770+ var x = 0;
771+ }
772+ ''' );
773+ visitStatement (findNode.statement ('var x' ));
774+ }
775+
776+ test_variableDeclaration_untyped_uninitialized () async {
777+ await analyze ('''
778+ void _f() {
779+ var x;
780+ }
781+ ''' );
782+ visitStatement (findNode.statement ('var x' ));
783+ }
784+
785+ test_variableDeclaration_visit_initializer () async {
786+ await analyze ('''
787+ void _f(bool/*?*/ x, bool/*?*/ y) {
788+ bool z = x && y;
789+ }
790+ ''' );
791+ visitStatement (findNode.statement ('bool z' ),
792+ nullChecked: {findNode.simple ('x &&' ), findNode.simple ('y;' )});
793+ }
794+
661795 void visitAssignmentTarget (
662796 Expression node, String expectedReadType, String expectedWriteType,
663797 {Set <Expression > nullChecked = const < Expression > {},
@@ -672,21 +806,47 @@ bool _f(dynamic d, bool b) => d && b;
672806 expect (fixBuilder.problems, problems);
673807 }
674808
809+ void visitStatement (Statement node,
810+ {Set <Expression > nullChecked = const < Expression > {},
811+ Map <AstNode , Set <Problem >> problems = const < AstNode , Set <Problem >> {},
812+ Set <TypeAnnotation > nullable = const < TypeAnnotation > {}}) {
813+ _FixBuilder fixBuilder = _createFixBuilder (node);
814+ var type = node.accept (fixBuilder);
815+ expect (type, null );
816+ expect (fixBuilder.nullCheckedExpressions, nullChecked);
817+ expect (fixBuilder.problems, problems);
818+ expect (fixBuilder.nullable, nullable);
819+ }
820+
675821 void visitSubexpression (Expression node, String expectedType,
676822 {DartType contextType,
677823 Set <Expression > nullChecked = const < Expression > {},
678- Map <AstNode , Set <Problem >> problems = const < AstNode , Set <Problem >> {}}) {
824+ Map <AstNode , Set <Problem >> problems = const < AstNode , Set <Problem >> {},
825+ Set <TypeAnnotation > nullable = const < TypeAnnotation > {}}) {
679826 contextType ?? = dynamicType;
680827 _FixBuilder fixBuilder = _createFixBuilder (node);
681828 var type = fixBuilder.visitSubexpression (node, contextType);
682829 expect ((type as TypeImpl ).toString (withNullability: true ), expectedType);
683830 expect (fixBuilder.nullCheckedExpressions, nullChecked);
684831 expect (fixBuilder.problems, problems);
832+ expect (fixBuilder.nullable, nullable);
833+ }
834+
835+ void visitTypeAnnotation (TypeAnnotation node, String expectedType,
836+ {Set <Expression > nullChecked = const < Expression > {},
837+ Map <AstNode , Set <Problem >> problems = const < AstNode , Set <Problem >> {},
838+ Set <TypeAnnotation > nullable = const < TypeAnnotation > {}}) {
839+ _FixBuilder fixBuilder = _createFixBuilder (node);
840+ var type = node.accept (fixBuilder);
841+ expect ((type as TypeImpl ).toString (withNullability: true ), expectedType);
842+ expect (fixBuilder.nullCheckedExpressions, nullChecked);
843+ expect (fixBuilder.problems, problems);
844+ expect (fixBuilder.nullable, nullable);
685845 }
686846
687- _FixBuilder _createFixBuilder (Expression node) {
688- var fixBuilder = _FixBuilder (
689- decoratedClassHierarchy, typeProvider, typeSystem, variables);
847+ _FixBuilder _createFixBuilder (AstNode node) {
848+ var fixBuilder = _FixBuilder (testSource, decoratedClassHierarchy,
849+ typeProvider, typeSystem, variables);
690850 var body = node.thisOrAncestorOfType <FunctionBody >();
691851 var declaration = body.thisOrAncestorOfType <Declaration >();
692852 fixBuilder.createFlowAnalysis (declaration, null );
@@ -697,11 +857,20 @@ bool _f(dynamic d, bool b) => d && b;
697857class _FixBuilder extends FixBuilder {
698858 final Set <Expression > nullCheckedExpressions = {};
699859
860+ final Set <TypeAnnotation > nullable = {};
861+
700862 final Map <AstNode , Set <Problem >> problems = {};
701863
702- _FixBuilder (DecoratedClassHierarchy decoratedClassHierarchy,
864+ _FixBuilder (Source source, DecoratedClassHierarchy decoratedClassHierarchy,
703865 TypeProvider typeProvider, TypeSystem typeSystem, Variables variables)
704- : super (decoratedClassHierarchy, typeProvider, typeSystem, variables);
866+ : super (source, decoratedClassHierarchy, typeProvider, typeSystem,
867+ variables);
868+
869+ @override
870+ void addNullable (TypeAnnotation node) {
871+ var newlyAdded = nullable.add (node);
872+ expect (newlyAdded, true );
873+ }
705874
706875 @override
707876 void addNullCheck (Expression subexpression) {
0 commit comments