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 |