| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 library analyzer.src.generated.resolver; | 5 library analyzer.src.generated.resolver; |
| 6 | 6 |
| 7 import 'dart:collection'; | 7 import 'dart:collection'; |
| 8 | 8 |
| 9 import 'package:analyzer/dart/ast/ast.dart'; | 9 import 'package:analyzer/dart/ast/ast.dart'; |
| 10 import 'package:analyzer/dart/ast/token.dart'; | 10 import 'package:analyzer/dart/ast/token.dart'; |
| (...skipping 3452 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3463 * to terminate by executing a `return` statement, `throw` expression, `rethrow` | 3463 * to terminate by executing a `return` statement, `throw` expression, `rethrow` |
| 3464 * expression, or simple infinite loop such as `while(true)`. | 3464 * expression, or simple infinite loop such as `while(true)`. |
| 3465 */ | 3465 */ |
| 3466 class ExitDetector extends GeneralizingAstVisitor<bool> { | 3466 class ExitDetector extends GeneralizingAstVisitor<bool> { |
| 3467 /** | 3467 /** |
| 3468 * Set to `true` when a `break` is encountered, and reset to `false` when a | 3468 * Set to `true` when a `break` is encountered, and reset to `false` when a |
| 3469 * `do`, `while`, `for` or `switch` block is entered. | 3469 * `do`, `while`, `for` or `switch` block is entered. |
| 3470 */ | 3470 */ |
| 3471 bool _enclosingBlockContainsBreak = false; | 3471 bool _enclosingBlockContainsBreak = false; |
| 3472 | 3472 |
| 3473 /** |
| 3474 * Add node when a labelled `break` is encountered. |
| 3475 */ |
| 3476 Set<AstNode> _enclosingBlockBreaksLabel = new Set<AstNode>(); |
| 3477 |
| 3473 @override | 3478 @override |
| 3474 bool visitArgumentList(ArgumentList node) => | 3479 bool visitArgumentList(ArgumentList node) => |
| 3475 _visitExpressions(node.arguments); | 3480 _visitExpressions(node.arguments); |
| 3476 | 3481 |
| 3477 @override | 3482 @override |
| 3478 bool visitAsExpression(AsExpression node) => _nodeExits(node.expression); | 3483 bool visitAsExpression(AsExpression node) => _nodeExits(node.expression); |
| 3479 | 3484 |
| 3480 @override | 3485 @override |
| 3481 bool visitAssertStatement(AssertStatement node) => false; | 3486 bool visitAssertStatement(AssertStatement node) => false; |
| 3482 | 3487 |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3538 | 3543 |
| 3539 @override | 3544 @override |
| 3540 bool visitBlock(Block node) => _visitStatements(node.statements); | 3545 bool visitBlock(Block node) => _visitStatements(node.statements); |
| 3541 | 3546 |
| 3542 @override | 3547 @override |
| 3543 bool visitBlockFunctionBody(BlockFunctionBody node) => _nodeExits(node.block); | 3548 bool visitBlockFunctionBody(BlockFunctionBody node) => _nodeExits(node.block); |
| 3544 | 3549 |
| 3545 @override | 3550 @override |
| 3546 bool visitBreakStatement(BreakStatement node) { | 3551 bool visitBreakStatement(BreakStatement node) { |
| 3547 _enclosingBlockContainsBreak = true; | 3552 _enclosingBlockContainsBreak = true; |
| 3553 if (node.label != null) { |
| 3554 _enclosingBlockBreaksLabel.add(node.target); |
| 3555 } |
| 3548 return false; | 3556 return false; |
| 3549 } | 3557 } |
| 3550 | 3558 |
| 3551 @override | 3559 @override |
| 3552 bool visitCascadeExpression(CascadeExpression node) => | 3560 bool visitCascadeExpression(CascadeExpression node) => |
| 3553 _nodeExits(node.target) || _visitExpressions(node.cascadeSections); | 3561 _nodeExits(node.target) || _visitExpressions(node.cascadeSections); |
| 3554 | 3562 |
| 3555 @override | 3563 @override |
| 3556 bool visitConditionalExpression(ConditionalExpression node) { | 3564 bool visitConditionalExpression(ConditionalExpression node) { |
| 3557 Expression conditionExpression = node.condition; | 3565 Expression conditionExpression = node.condition; |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3627 if (node.initialization != null && _nodeExits(node.initialization)) { | 3635 if (node.initialization != null && _nodeExits(node.initialization)) { |
| 3628 return true; | 3636 return true; |
| 3629 } | 3637 } |
| 3630 Expression conditionExpression = node.condition; | 3638 Expression conditionExpression = node.condition; |
| 3631 if (conditionExpression != null && _nodeExits(conditionExpression)) { | 3639 if (conditionExpression != null && _nodeExits(conditionExpression)) { |
| 3632 return true; | 3640 return true; |
| 3633 } | 3641 } |
| 3634 if (_visitExpressions(node.updaters)) { | 3642 if (_visitExpressions(node.updaters)) { |
| 3635 return true; | 3643 return true; |
| 3636 } | 3644 } |
| 3645 bool blockReturns = _nodeExits(node.body); |
| 3637 // TODO(jwren) Do we want to take all constant expressions into account? | 3646 // TODO(jwren) Do we want to take all constant expressions into account? |
| 3638 // If for(; true; ) (or for(;;)), and the body doesn't return or the body | 3647 // If for(; true; ) (or for(;;)), and the body doesn't return or the body |
| 3639 // doesn't have a break, then return true. | 3648 // doesn't have a break, then return true. |
| 3640 bool implicitOrExplictTrue = conditionExpression == null || | 3649 bool implicitOrExplictTrue = conditionExpression == null || |
| 3641 (conditionExpression is BooleanLiteral && conditionExpression.value); | 3650 (conditionExpression is BooleanLiteral && conditionExpression.value); |
| 3642 if (implicitOrExplictTrue) { | 3651 if (implicitOrExplictTrue) { |
| 3643 bool blockReturns = _nodeExits(node.body); | |
| 3644 if (blockReturns || !_enclosingBlockContainsBreak) { | 3652 if (blockReturns || !_enclosingBlockContainsBreak) { |
| 3645 return true; | 3653 return true; |
| 3646 } | 3654 } |
| 3647 } | 3655 } |
| 3648 return false; | 3656 return false; |
| 3649 } finally { | 3657 } finally { |
| 3650 _enclosingBlockContainsBreak = outerBreakValue; | 3658 _enclosingBlockContainsBreak = outerBreakValue; |
| 3651 } | 3659 } |
| 3652 } | 3660 } |
| 3653 | 3661 |
| (...skipping 19 matching lines...) Expand all Loading... |
| 3673 bool visitIfStatement(IfStatement node) { | 3681 bool visitIfStatement(IfStatement node) { |
| 3674 Expression conditionExpression = node.condition; | 3682 Expression conditionExpression = node.condition; |
| 3675 Statement thenStatement = node.thenStatement; | 3683 Statement thenStatement = node.thenStatement; |
| 3676 Statement elseStatement = node.elseStatement; | 3684 Statement elseStatement = node.elseStatement; |
| 3677 if (_nodeExits(conditionExpression)) { | 3685 if (_nodeExits(conditionExpression)) { |
| 3678 return true; | 3686 return true; |
| 3679 } | 3687 } |
| 3680 // TODO(jwren) Do we want to take all constant expressions into account? | 3688 // TODO(jwren) Do we want to take all constant expressions into account? |
| 3681 if (conditionExpression is BooleanLiteral) { | 3689 if (conditionExpression is BooleanLiteral) { |
| 3682 if (conditionExpression.value) { | 3690 if (conditionExpression.value) { |
| 3683 // if(true) ... | 3691 // if (true) ... |
| 3684 return _nodeExits(thenStatement); | 3692 return _nodeExits(thenStatement); |
| 3685 } else if (elseStatement != null) { | 3693 } else if (elseStatement != null) { |
| 3686 // if (false) ... | 3694 // if (false) ... |
| 3687 return _nodeExits(elseStatement); | 3695 return _nodeExits(elseStatement); |
| 3688 } | 3696 } |
| 3689 } | 3697 } |
| 3698 bool thenExits = _nodeExits(thenStatement); |
| 3699 bool elseExits = _nodeExits(elseStatement); |
| 3690 if (thenStatement == null || elseStatement == null) { | 3700 if (thenStatement == null || elseStatement == null) { |
| 3691 return false; | 3701 return false; |
| 3692 } | 3702 } |
| 3693 bool thenExits = _nodeExits(thenStatement); | |
| 3694 bool elseExits = _nodeExits(elseStatement); | |
| 3695 return thenExits && elseExits; | 3703 return thenExits && elseExits; |
| 3696 } | 3704 } |
| 3697 | 3705 |
| 3698 @override | 3706 @override |
| 3699 bool visitIndexExpression(IndexExpression node) { | 3707 bool visitIndexExpression(IndexExpression node) { |
| 3700 Expression target = node.realTarget; | 3708 Expression target = node.realTarget; |
| 3701 if (_nodeExits(target)) { | 3709 if (_nodeExits(target)) { |
| 3702 return true; | 3710 return true; |
| 3703 } | 3711 } |
| 3704 if (_nodeExits(node.index)) { | 3712 if (_nodeExits(node.index)) { |
| 3705 return true; | 3713 return true; |
| 3706 } | 3714 } |
| 3707 return false; | 3715 return false; |
| 3708 } | 3716 } |
| 3709 | 3717 |
| 3710 @override | 3718 @override |
| 3711 bool visitInstanceCreationExpression(InstanceCreationExpression node) => | 3719 bool visitInstanceCreationExpression(InstanceCreationExpression node) => |
| 3712 _nodeExits(node.argumentList); | 3720 _nodeExits(node.argumentList); |
| 3713 | 3721 |
| 3714 @override | 3722 @override |
| 3715 bool visitIsExpression(IsExpression node) => node.expression.accept(this); | 3723 bool visitIsExpression(IsExpression node) => node.expression.accept(this); |
| 3716 | 3724 |
| 3717 @override | 3725 @override |
| 3718 bool visitLabel(Label node) => false; | 3726 bool visitLabel(Label node) => false; |
| 3719 | 3727 |
| 3720 @override | 3728 @override |
| 3721 bool visitLabeledStatement(LabeledStatement node) => | 3729 bool visitLabeledStatement(LabeledStatement node) { |
| 3722 node.statement.accept(this); | 3730 try { |
| 3731 bool statementExits = _nodeExits(node.statement); |
| 3732 bool neverBrokeFromLabel = |
| 3733 !_enclosingBlockBreaksLabel.contains(node.statement); |
| 3734 return statementExits && neverBrokeFromLabel; |
| 3735 } finally { |
| 3736 _enclosingBlockBreaksLabel.remove(node.statement); |
| 3737 } |
| 3738 } |
| 3723 | 3739 |
| 3724 @override | 3740 @override |
| 3725 bool visitLiteral(Literal node) => false; | 3741 bool visitLiteral(Literal node) => false; |
| 3726 | 3742 |
| 3727 @override | 3743 @override |
| 3728 bool visitMethodInvocation(MethodInvocation node) { | 3744 bool visitMethodInvocation(MethodInvocation node) { |
| 3729 Expression target = node.realTarget; | 3745 Expression target = node.realTarget; |
| 3730 if (target != null) { | 3746 if (target != null) { |
| 3731 if (target.accept(this)) { | 3747 if (target.accept(this)) { |
| 3732 return true; | 3748 return true; |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3866 | 3882 |
| 3867 @override | 3883 @override |
| 3868 bool visitWhileStatement(WhileStatement node) { | 3884 bool visitWhileStatement(WhileStatement node) { |
| 3869 bool outerBreakValue = _enclosingBlockContainsBreak; | 3885 bool outerBreakValue = _enclosingBlockContainsBreak; |
| 3870 _enclosingBlockContainsBreak = false; | 3886 _enclosingBlockContainsBreak = false; |
| 3871 try { | 3887 try { |
| 3872 Expression conditionExpression = node.condition; | 3888 Expression conditionExpression = node.condition; |
| 3873 if (conditionExpression.accept(this)) { | 3889 if (conditionExpression.accept(this)) { |
| 3874 return true; | 3890 return true; |
| 3875 } | 3891 } |
| 3892 bool blockReturns = node.body.accept(this); |
| 3876 // TODO(jwren) Do we want to take all constant expressions into account? | 3893 // TODO(jwren) Do we want to take all constant expressions into account? |
| 3877 if (conditionExpression is BooleanLiteral) { | 3894 if (conditionExpression is BooleanLiteral) { |
| 3878 // If while(true), and the body doesn't return or the body doesn't have | 3895 // If while(true), and the body doesn't return or the body doesn't have |
| 3879 // a break, then return true. | 3896 // a break, then return true. |
| 3880 bool blockReturns = node.body.accept(this); | |
| 3881 if (conditionExpression.value && | 3897 if (conditionExpression.value && |
| 3882 (blockReturns || !_enclosingBlockContainsBreak)) { | 3898 (blockReturns || !_enclosingBlockContainsBreak)) { |
| 3883 return true; | 3899 return true; |
| 3884 } | 3900 } |
| 3885 } | 3901 } |
| 3886 return false; | 3902 return false; |
| 3887 } finally { | 3903 } finally { |
| 3888 _enclosingBlockContainsBreak = outerBreakValue; | 3904 _enclosingBlockContainsBreak = outerBreakValue; |
| 3889 } | 3905 } |
| 3890 } | 3906 } |
| (...skipping 14 matching lines...) Expand all Loading... |
| 3905 bool _visitExpressions(NodeList<Expression> expressions) { | 3921 bool _visitExpressions(NodeList<Expression> expressions) { |
| 3906 for (int i = expressions.length - 1; i >= 0; i--) { | 3922 for (int i = expressions.length - 1; i >= 0; i--) { |
| 3907 if (expressions[i].accept(this)) { | 3923 if (expressions[i].accept(this)) { |
| 3908 return true; | 3924 return true; |
| 3909 } | 3925 } |
| 3910 } | 3926 } |
| 3911 return false; | 3927 return false; |
| 3912 } | 3928 } |
| 3913 | 3929 |
| 3914 bool _visitStatements(NodeList<Statement> statements) { | 3930 bool _visitStatements(NodeList<Statement> statements) { |
| 3915 for (int i = statements.length - 1; i >= 0; i--) { | 3931 for (int i = 0; i < statements.length; i++) { |
| 3916 if (statements[i].accept(this)) { | 3932 if (statements[i].accept(this)) { |
| 3917 return true; | 3933 return true; |
| 3918 } | 3934 } |
| 3919 } | 3935 } |
| 3920 return false; | 3936 return false; |
| 3921 } | 3937 } |
| 3922 | 3938 |
| 3923 bool _visitVariableDeclarations( | 3939 bool _visitVariableDeclarations( |
| 3924 NodeList<VariableDeclaration> variableDeclarations) { | 3940 NodeList<VariableDeclaration> variableDeclarations) { |
| 3925 for (int i = variableDeclarations.length - 1; i >= 0; i--) { | 3941 for (int i = variableDeclarations.length - 1; i >= 0; i--) { |
| (...skipping 7055 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10981 return null; | 10997 return null; |
| 10982 } | 10998 } |
| 10983 if (identical(node.staticElement, variable)) { | 10999 if (identical(node.staticElement, variable)) { |
| 10984 if (node.inSetterContext()) { | 11000 if (node.inSetterContext()) { |
| 10985 result = true; | 11001 result = true; |
| 10986 } | 11002 } |
| 10987 } | 11003 } |
| 10988 return null; | 11004 return null; |
| 10989 } | 11005 } |
| 10990 } | 11006 } |
| OLD | NEW |