Chromium Code Reviews| 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 VariableDeclaration decl = null; | |
| 738 AstNode ancestor = node.parent; | |
| 739 while (ancestor != null) { | |
| 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 VariableDeclaration) { | |
|
Leaf
2016/07/22 23:34:41
Might be a bit clearer just to make this part of t
Paul Berry
2016/07/23 16:18:18
Done.
| |
| 746 decl = ancestor; | |
| 747 break; | |
| 748 } | |
| 749 if (ancestor is InstanceCreationExpression) { | |
|
Leaf
2016/07/22 23:34:41
Presumably this same logic could be applied to Lis
Paul Berry
2016/07/23 16:18:18
Done. PTAL.
| |
| 750 // node appears inside an instance creation expression; we may be safe | |
| 751 // if the type of the instance creation expression requires no | |
| 752 // inference. | |
| 753 TypeName typeName = ancestor.constructorName.type; | |
| 754 DartType type = typeName.type; | |
| 755 if (typeName.typeArguments != null) { | |
| 756 // Type arguments were explicitly specified. We are safe. | |
| 757 return; | |
| 758 } | |
| 759 if (!(type is ParameterizedType && type.typeParameters.isNotEmpty)) { | |
| 760 // Type is not generic. We are safe. | |
| 761 return; | |
| 762 } | |
| 763 } | |
| 764 ancestor = ancestor.parent; | |
| 765 } | |
| 766 if (decl == null) { | |
| 767 // node is not inside a variable declaration, so it is safe. | |
| 768 return; | |
| 769 } | |
| 770 VariableElement declElement = decl.element; | |
| 771 if (!declElement.hasImplicitType) { | |
| 772 // Variable declaration has an explicit type, so it's safe. | |
| 773 return; | |
| 774 } | |
| 775 if (declElement.type.isDynamic) { | |
| 776 // No type was successfully inferred for this variable, so it's safe. | |
| 777 return; | |
| 778 } | |
| 779 if (declElement.enclosingElement is ExecutableElement) { | |
| 780 // Variable declaration is inside a function or method, so it's safe. | |
| 781 return; | |
| 782 } | |
| 783 _recordMessage(node, StrongModeCode.UNSAFE_BLOCK_CLOSURE_INFERENCE, | |
| 784 [declElement.name]); | |
| 785 } | |
| 786 | |
| 716 void _checkReturnOrYield(Expression expression, AstNode node, | 787 void _checkReturnOrYield(Expression expression, AstNode node, |
| 717 {bool yieldStar: false}) { | 788 {bool yieldStar: false}) { |
| 718 FunctionBody body = node.getAncestor((n) => n is FunctionBody); | 789 FunctionBody body = node.getAncestor((n) => n is FunctionBody); |
| 719 var type = _getExpectedReturnType(body, yieldStar: yieldStar); | 790 var type = _getExpectedReturnType(body, yieldStar: yieldStar); |
| 720 if (type == null) { | 791 if (type == null) { |
| 721 // We have a type mismatch: the async/async*/sync* modifier does | 792 // 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 | 793 // not match the return or yield type. We should have already gotten an |
| 723 // analyzer error in this case. | 794 // analyzer error in this case. |
| 724 return; | 795 return; |
| 725 } | 796 } |
| (...skipping 644 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1370 var visited = new Set<InterfaceType>(); | 1441 var visited = new Set<InterfaceType>(); |
| 1371 do { | 1442 do { |
| 1372 visited.add(current); | 1443 visited.add(current); |
| 1373 current.mixins.reversed.forEach( | 1444 current.mixins.reversed.forEach( |
| 1374 (m) => _checkIndividualOverridesFromClass(node, m, seen, true)); | 1445 (m) => _checkIndividualOverridesFromClass(node, m, seen, true)); |
| 1375 _checkIndividualOverridesFromClass(node, current.superclass, seen, true); | 1446 _checkIndividualOverridesFromClass(node, current.superclass, seen, true); |
| 1376 current = current.superclass; | 1447 current = current.superclass; |
| 1377 } while (!current.isObject && !visited.contains(current)); | 1448 } while (!current.isObject && !visited.contains(current)); |
| 1378 } | 1449 } |
| 1379 } | 1450 } |
| OLD | NEW |