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 |