OLD | NEW |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 // TODO(jmesserly): this was ported from package:dev_compiler, and needs to be | 5 // TODO(jmesserly): this was ported from package:dev_compiler, and needs to be |
6 // refactored to fit into analyzer. | 6 // refactored to fit into analyzer. |
7 library analyzer.src.task.strong.checker; | 7 library analyzer.src.task.strong.checker; |
8 | 8 |
9 import 'package:analyzer/analyzer.dart'; | 9 import 'package:analyzer/analyzer.dart'; |
10 import 'package:analyzer/dart/ast/ast.dart'; | 10 import 'package:analyzer/dart/ast/ast.dart'; |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
156 if (expectedType == null) expectedType = DynamicTypeImpl.instance; | 156 if (expectedType == null) expectedType = DynamicTypeImpl.instance; |
157 checkArgument(arg, expectedType); | 157 checkArgument(arg, expectedType); |
158 } | 158 } |
159 } | 159 } |
160 | 160 |
161 void checkAssignment(Expression expr, DartType type) { | 161 void checkAssignment(Expression expr, DartType type) { |
162 if (expr is ParenthesizedExpression) { | 162 if (expr is ParenthesizedExpression) { |
163 checkAssignment(expr.expression, type); | 163 checkAssignment(expr.expression, type); |
164 } else { | 164 } else { |
165 _checkDowncast(expr, type); | 165 _checkDowncast(expr, type); |
| 166 _checkNonNullAssignment(expr, type); |
166 } | 167 } |
167 } | 168 } |
168 | 169 |
169 /// Analyzer checks boolean conversions, but we need to check too, because | 170 /// Analyzer checks boolean conversions, but we need to check too, because |
170 /// it uses the default assignability rules that allow `dynamic` and `Object` | 171 /// it uses the default assignability rules that allow `dynamic` and `Object` |
171 /// to be assigned to bool with no message. | 172 /// to be assigned to bool with no message. |
172 void checkBoolean(Expression expr) => | 173 void checkBoolean(Expression expr) => |
173 checkAssignment(expr, typeProvider.boolType); | 174 checkAssignment(expr, typeProvider.boolType); |
174 | 175 |
175 void checkFunctionApplication( | 176 void checkFunctionApplication( |
(...skipping 430 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
606 } | 607 } |
607 | 608 |
608 @override | 609 @override |
609 void visitVariableDeclarationList(VariableDeclarationList node) { | 610 void visitVariableDeclarationList(VariableDeclarationList node) { |
610 TypeName type = node.type; | 611 TypeName type = node.type; |
611 if (type == null) { | 612 if (type == null) { |
612 // No checks are needed when the type is var. Although internally the | 613 // No checks are needed when the type is var. Although internally the |
613 // typing rules may have inferred a more precise type for the variable | 614 // typing rules may have inferred a more precise type for the variable |
614 // based on the initializer. | 615 // based on the initializer. |
615 } else { | 616 } else { |
616 var dartType = getType(type); | |
617 for (VariableDeclaration variable in node.variables) { | 617 for (VariableDeclaration variable in node.variables) { |
618 var initializer = variable.initializer; | 618 var initializer = variable.initializer; |
619 if (initializer != null) { | 619 if (initializer != null) { |
620 checkAssignment(initializer, dartType); | 620 checkAssignment(initializer, type.type); |
621 } | 621 } |
622 } | 622 } |
623 } | 623 } |
624 node.visitChildren(this); | 624 node.visitChildren(this); |
625 } | 625 } |
626 | 626 |
627 @override | 627 @override |
628 void visitWhileStatement(WhileStatement node) { | 628 void visitWhileStatement(WhileStatement node) { |
629 checkBoolean(node.condition); | 629 checkBoolean(node.condition); |
630 node.visitChildren(this); | 630 node.visitChildren(this); |
(...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
832 return; | 832 return; |
833 } | 833 } |
834 if (declElement.enclosingElement is ExecutableElement) { | 834 if (declElement.enclosingElement is ExecutableElement) { |
835 // Variable declaration is inside a function or method, so it's safe. | 835 // Variable declaration is inside a function or method, so it's safe. |
836 return; | 836 return; |
837 } | 837 } |
838 _recordMessage(node, StrongModeCode.UNSAFE_BLOCK_CLOSURE_INFERENCE, | 838 _recordMessage(node, StrongModeCode.UNSAFE_BLOCK_CLOSURE_INFERENCE, |
839 [declElement.name]); | 839 [declElement.name]); |
840 } | 840 } |
841 | 841 |
| 842 void _checkNonNullAssignment(Expression expression, DartType type) { |
| 843 var exprType = expression.staticType; |
| 844 if (rules.isNonNullableType(type) && !rules.isNonNullableType(exprType)) { |
| 845 _recordMessage(expression, StaticTypeWarningCode.INVALID_ASSIGNMENT, |
| 846 [exprType, type]); |
| 847 } |
| 848 } |
| 849 |
842 void _checkReturnOrYield(Expression expression, AstNode node, | 850 void _checkReturnOrYield(Expression expression, AstNode node, |
843 {bool yieldStar: false}) { | 851 {bool yieldStar: false}) { |
844 FunctionBody body = node.getAncestor((n) => n is FunctionBody); | 852 FunctionBody body = node.getAncestor((n) => n is FunctionBody); |
845 var type = _getExpectedReturnType(body, yieldStar: yieldStar); | 853 var type = _getExpectedReturnType(body, yieldStar: yieldStar); |
846 if (type == null) { | 854 if (type == null) { |
847 // We have a type mismatch: the async/async*/sync* modifier does | 855 // We have a type mismatch: the async/async*/sync* modifier does |
848 // not match the return or yield type. We should have already gotten an | 856 // not match the return or yield type. We should have already gotten an |
849 // analyzer error in this case. | 857 // analyzer error in this case. |
850 return; | 858 return; |
851 } | 859 } |
(...skipping 629 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1481 var visited = new Set<InterfaceType>(); | 1489 var visited = new Set<InterfaceType>(); |
1482 do { | 1490 do { |
1483 visited.add(current); | 1491 visited.add(current); |
1484 current.mixins.reversed.forEach( | 1492 current.mixins.reversed.forEach( |
1485 (m) => _checkIndividualOverridesFromClass(node, m, seen, true)); | 1493 (m) => _checkIndividualOverridesFromClass(node, m, seen, true)); |
1486 _checkIndividualOverridesFromClass(node, current.superclass, seen, true); | 1494 _checkIndividualOverridesFromClass(node, current.superclass, seen, true); |
1487 current = current.superclass; | 1495 current = current.superclass; |
1488 } while (!current.isObject && !visited.contains(current)); | 1496 } while (!current.isObject && !visited.contains(current)); |
1489 } | 1497 } |
1490 } | 1498 } |
OLD | NEW |