Index: pkg/analyzer/lib/src/generated/resolver.dart |
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart |
index 7dbf6e42c99492dbe9054a776fd77d0869c52b5e..f1fb45e006db2ecb53a565d47a312a0f6fdb6b50 100644 |
--- a/pkg/analyzer/lib/src/generated/resolver.dart |
+++ b/pkg/analyzer/lib/src/generated/resolver.dart |
@@ -3470,6 +3470,11 @@ class ExitDetector extends GeneralizingAstVisitor<bool> { |
*/ |
bool _enclosingBlockContainsBreak = false; |
+ /** |
+ * Add node when a labelled `break` is encountered. |
+ */ |
+ Set<AstNode> _enclosingBlockBreaksLabel = new Set<AstNode>(); |
+ |
@override |
bool visitArgumentList(ArgumentList node) => |
_visitExpressions(node.arguments); |
@@ -3545,6 +3550,9 @@ class ExitDetector extends GeneralizingAstVisitor<bool> { |
@override |
bool visitBreakStatement(BreakStatement node) { |
_enclosingBlockContainsBreak = true; |
+ if (node.label != null) { |
+ _enclosingBlockBreaksLabel.add(node.target); |
+ } |
return false; |
} |
@@ -3634,13 +3642,13 @@ class ExitDetector extends GeneralizingAstVisitor<bool> { |
if (_visitExpressions(node.updaters)) { |
return true; |
} |
+ bool blockReturns = _nodeExits(node.body); |
// TODO(jwren) Do we want to take all constant expressions into account? |
// If for(; true; ) (or for(;;)), and the body doesn't return or the body |
// doesn't have a break, then return true. |
bool implicitOrExplictTrue = conditionExpression == null || |
(conditionExpression is BooleanLiteral && conditionExpression.value); |
if (implicitOrExplictTrue) { |
- bool blockReturns = _nodeExits(node.body); |
if (blockReturns || !_enclosingBlockContainsBreak) { |
return true; |
} |
@@ -3680,18 +3688,18 @@ class ExitDetector extends GeneralizingAstVisitor<bool> { |
// TODO(jwren) Do we want to take all constant expressions into account? |
if (conditionExpression is BooleanLiteral) { |
if (conditionExpression.value) { |
- // if(true) ... |
+ // if (true) ... |
return _nodeExits(thenStatement); |
} else if (elseStatement != null) { |
// if (false) ... |
return _nodeExits(elseStatement); |
} |
} |
- if (thenStatement == null || elseStatement == null) { |
- return false; |
- } |
bool thenExits = _nodeExits(thenStatement); |
bool elseExits = _nodeExits(elseStatement); |
+ if (thenStatement == null || elseStatement == null) { |
+ return false; |
+ } |
return thenExits && elseExits; |
} |
@@ -3718,8 +3726,16 @@ class ExitDetector extends GeneralizingAstVisitor<bool> { |
bool visitLabel(Label node) => false; |
@override |
- bool visitLabeledStatement(LabeledStatement node) => |
- node.statement.accept(this); |
+ bool visitLabeledStatement(LabeledStatement node) { |
+ try { |
+ bool statementExits = _nodeExits(node.statement); |
+ bool neverBrokeFromLabel = |
+ !_enclosingBlockBreaksLabel.contains(node.statement); |
+ return statementExits && neverBrokeFromLabel; |
+ } finally { |
+ _enclosingBlockBreaksLabel.remove(node.statement); |
+ } |
+ } |
@override |
bool visitLiteral(Literal node) => false; |
@@ -3873,11 +3889,11 @@ class ExitDetector extends GeneralizingAstVisitor<bool> { |
if (conditionExpression.accept(this)) { |
return true; |
} |
+ bool blockReturns = node.body.accept(this); |
// TODO(jwren) Do we want to take all constant expressions into account? |
if (conditionExpression is BooleanLiteral) { |
// If while(true), and the body doesn't return or the body doesn't have |
// a break, then return true. |
- bool blockReturns = node.body.accept(this); |
if (conditionExpression.value && |
(blockReturns || !_enclosingBlockContainsBreak)) { |
return true; |
@@ -3912,7 +3928,7 @@ class ExitDetector extends GeneralizingAstVisitor<bool> { |
} |
bool _visitStatements(NodeList<Statement> statements) { |
- for (int i = statements.length - 1; i >= 0; i--) { |
+ for (int i = 0; i < statements.length; i++) { |
if (statements[i].accept(this)) { |
return true; |
} |