| 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 362 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 373 | 373 |
| 374 @override | 374 @override |
| 375 void visitForStatement(ForStatement node) { | 375 void visitForStatement(ForStatement node) { |
| 376 if (node.condition != null) { | 376 if (node.condition != null) { |
| 377 checkBoolean(node.condition); | 377 checkBoolean(node.condition); |
| 378 } | 378 } |
| 379 node.visitChildren(this); | 379 node.visitChildren(this); |
| 380 } | 380 } |
| 381 | 381 |
| 382 @override | 382 @override |
| 383 void visitFunctionExpression(FunctionExpression node) { |
| 384 _checkForUnsafeBlockClosureInference(node); |
| 385 super.visitFunctionExpression(node); |
| 386 } |
| 387 |
| 388 @override |
| 383 void visitFunctionExpressionInvocation(FunctionExpressionInvocation node) { | 389 void visitFunctionExpressionInvocation(FunctionExpressionInvocation node) { |
| 384 checkFunctionApplication(node, node.function, node.argumentList); | 390 checkFunctionApplication(node, node.function, node.argumentList); |
| 385 node.visitChildren(this); | 391 node.visitChildren(this); |
| 386 } | 392 } |
| 387 | 393 |
| 388 @override | 394 @override |
| 389 void visitIfStatement(IfStatement node) { | 395 void visitIfStatement(IfStatement node) { |
| 390 checkBoolean(node.condition); | 396 checkBoolean(node.condition); |
| 391 node.visitChildren(this); | 397 node.visitChildren(this); |
| 392 } | 398 } |
| (...skipping 313 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 706 } | 712 } |
| 707 | 713 |
| 708 void _checkFieldAccess(AstNode node, AstNode target, SimpleIdentifier field) { | 714 void _checkFieldAccess(AstNode node, AstNode target, SimpleIdentifier field) { |
| 709 if ((_isDynamicTarget(target) || field.staticElement == null) && | 715 if ((_isDynamicTarget(target) || field.staticElement == null) && |
| 710 !_isObjectProperty(target, field)) { | 716 !_isObjectProperty(target, field)) { |
| 711 _recordDynamicInvoke(node, target); | 717 _recordDynamicInvoke(node, target); |
| 712 } | 718 } |
| 713 node.visitChildren(this); | 719 node.visitChildren(this); |
| 714 } | 720 } |
| 715 | 721 |
| 722 /** |
| 723 * Check if the closure [node] is unsafe due to dartbug.com/26947. If so, |
| 724 * issue a warning. |
| 725 * |
| 726 * TODO(paulberry): eliminate this once dartbug.com/26947 is fixed. |
| 727 */ |
| 728 void _checkForUnsafeBlockClosureInference(FunctionExpression node) { |
| 729 if (node.body is! BlockFunctionBody) { |
| 730 return; |
| 731 } |
| 732 if (node.element.returnType.isDynamic) { |
| 733 return; |
| 734 } |
| 735 // Find the enclosing variable declaration whose inferred type might depend |
| 736 // on the inferred return type of the block closure (if any). |
| 737 AstNode prevAncestor = node; |
| 738 AstNode ancestor = node.parent; |
| 739 while (ancestor != null && ancestor is! VariableDeclaration) { |
| 740 if (ancestor is BlockFunctionBody) { |
| 741 // node is inside another block function body; if that block |
| 742 // function body is unsafe, we've already warned about it. |
| 743 return; |
| 744 } |
| 745 if (ancestor is InstanceCreationExpression) { |
| 746 // node appears inside an instance creation expression; we may be safe |
| 747 // if the type of the instance creation expression requires no |
| 748 // inference. |
| 749 TypeName typeName = ancestor.constructorName.type; |
| 750 if (typeName.typeArguments != null) { |
| 751 // Type arguments were explicitly specified. We are safe. |
| 752 return; |
| 753 } |
| 754 DartType type = typeName.type; |
| 755 if (!(type is ParameterizedType && type.typeParameters.isNotEmpty)) { |
| 756 // Type is not generic. We are safe. |
| 757 return; |
| 758 } |
| 759 } |
| 760 if (ancestor is MethodInvocation) { |
| 761 // node appears inside a method or function invocation; we may be safe |
| 762 // if the type of the method or function requires no inference. |
| 763 if (ancestor.typeArguments != null) { |
| 764 // Type arguments were explicitly specified. We are safe. |
| 765 return; |
| 766 } |
| 767 Element methodElement = ancestor.methodName.staticElement; |
| 768 if (!(methodElement is ExecutableElement && |
| 769 methodElement.typeParameters.isNotEmpty)) { |
| 770 // Method is not generic. We are safe. |
| 771 return; |
| 772 } |
| 773 } |
| 774 if (ancestor is FunctionExpressionInvocation && |
| 775 !identical(prevAncestor, ancestor.function)) { |
| 776 // node appears inside an argument to a function expression invocation; |
| 777 // we may be safe if the type of the function expression requires no |
| 778 // inference. |
| 779 if (ancestor.typeArguments != null) { |
| 780 // Type arguments were explicitly specified. We are safe. |
| 781 return; |
| 782 } |
| 783 DartType type = ancestor.function.staticType; |
| 784 if (!(type is FunctionTypeImpl && type.typeFormals.isNotEmpty)) { |
| 785 // Type is not generic or has had its type parameters instantiated. |
| 786 // We are safe. |
| 787 return; |
| 788 } |
| 789 } |
| 790 if ((ancestor is ListLiteral && ancestor.typeArguments != null) || |
| 791 (ancestor is MapLiteral && ancestor.typeArguments != null)) { |
| 792 // node appears inside a list or map literal with an explicit type. We |
| 793 // are safe because no type inference is required. |
| 794 return; |
| 795 } |
| 796 prevAncestor = ancestor; |
| 797 ancestor = ancestor.parent; |
| 798 } |
| 799 if (ancestor == null) { |
| 800 // node is not inside a variable declaration, so it is safe. |
| 801 return; |
| 802 } |
| 803 VariableDeclaration decl = ancestor; |
| 804 VariableElement declElement = decl.element; |
| 805 if (!declElement.hasImplicitType) { |
| 806 // Variable declaration has an explicit type, so it's safe. |
| 807 return; |
| 808 } |
| 809 if (declElement.type.isDynamic) { |
| 810 // No type was successfully inferred for this variable, so it's safe. |
| 811 return; |
| 812 } |
| 813 if (declElement.enclosingElement is ExecutableElement) { |
| 814 // Variable declaration is inside a function or method, so it's safe. |
| 815 return; |
| 816 } |
| 817 _recordMessage(node, StrongModeCode.UNSAFE_BLOCK_CLOSURE_INFERENCE, |
| 818 [declElement.name]); |
| 819 } |
| 820 |
| 716 void _checkReturnOrYield(Expression expression, AstNode node, | 821 void _checkReturnOrYield(Expression expression, AstNode node, |
| 717 {bool yieldStar: false}) { | 822 {bool yieldStar: false}) { |
| 718 FunctionBody body = node.getAncestor((n) => n is FunctionBody); | 823 FunctionBody body = node.getAncestor((n) => n is FunctionBody); |
| 719 var type = _getExpectedReturnType(body, yieldStar: yieldStar); | 824 var type = _getExpectedReturnType(body, yieldStar: yieldStar); |
| 720 if (type == null) { | 825 if (type == null) { |
| 721 // We have a type mismatch: the async/async*/sync* modifier does | 826 // We have a type mismatch: the async/async*/sync* modifier does |
| 722 // not match the return or yield type. We should have already gotten an | 827 // not match the return or yield type. We should have already gotten an |
| 723 // analyzer error in this case. | 828 // analyzer error in this case. |
| 724 return; | 829 return; |
| 725 } | 830 } |
| (...skipping 644 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1370 var visited = new Set<InterfaceType>(); | 1475 var visited = new Set<InterfaceType>(); |
| 1371 do { | 1476 do { |
| 1372 visited.add(current); | 1477 visited.add(current); |
| 1373 current.mixins.reversed.forEach( | 1478 current.mixins.reversed.forEach( |
| 1374 (m) => _checkIndividualOverridesFromClass(node, m, seen, true)); | 1479 (m) => _checkIndividualOverridesFromClass(node, m, seen, true)); |
| 1375 _checkIndividualOverridesFromClass(node, current.superclass, seen, true); | 1480 _checkIndividualOverridesFromClass(node, current.superclass, seen, true); |
| 1376 current = current.superclass; | 1481 current = current.superclass; |
| 1377 } while (!current.isObject && !visited.contains(current)); | 1482 } while (!current.isObject && !visited.contains(current)); |
| 1378 } | 1483 } |
| 1379 } | 1484 } |
| OLD | NEW |