diff options
author | Manoj Palat | 2020-05-14 16:21:06 +0000 |
---|---|---|
committer | Manoj Palat | 2020-05-14 18:24:02 +0000 |
commit | 28edbf1262165302ab535a12e4da10c870507c1d (patch) | |
tree | 7129beca28a665c515be493afeaacac6e42711fa | |
parent | 7764772c16a268ab0f81abb866119b541b2ffb60 (diff) | |
download | eclipse.jdt.core-28edbf1262165302ab535a12e4da10c870507c1d.tar.gz eclipse.jdt.core-28edbf1262165302ab535a12e4da10c870507c1d.tar.xz eclipse.jdt.core-28edbf1262165302ab535a12e4da10c870507c1d.zip |
doesNotCompleteNormally() - Switch Statement in Switch Expression error
Change-Id: I97a4b3cfbd45b90561f90fe604208aeb6297e6fe
20 files changed, 464 insertions, 6 deletions
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaShapeTests.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaShapeTests.java index c892bd5e23..97c50dfff0 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaShapeTests.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaShapeTests.java @@ -18,7 +18,7 @@ import junit.framework.Test; @SuppressWarnings({ "rawtypes" }) public class LambdaShapeTests extends AbstractRegressionTest { static { -// TESTS_NAMES = new String[] { "testWhileThis"}; +// TESTS_NAMES = new String[] { "test016"}; // TESTS_NUMBERS = new int[] { 50 }; // TESTS_RANGE = new int[] { 11, -1 }; } diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchExpressionsYieldTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchExpressionsYieldTest.java index 4b46ebc746..0cb6f7e8fc 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchExpressionsYieldTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchExpressionsYieldTest.java @@ -4872,6 +4872,218 @@ public class SwitchExpressionsYieldTest extends AbstractRegressionTest { "Return within switch expressions not permitted\n" + "----------\n"); } + public void testBug563023_001() { + runConformTest( + new String[] { + "X.java", + "public class X { \n"+ + " static public int foo(int a, int b){\n"+ + " int t = switch (a) {\n"+ + " default -> {\n"+ + " switch (b) {\n"+ + " default -> {\n"+ + " yield 0;\n"+ + " }\n"+ + " } \n"+ + " }\n"+ + " };\n"+ + " return t;\n"+ + " }\n"+ + " public static void main(String[] args) {\n"+ + " System.out.println(X.foo(0, 0));\n"+ + " }\n"+ + "}\n" + }, + "0"); + } + public void testBug563023_002() { + this.runNegativeTest( + new String[] { + "X.java", + "public class X { \n"+ + " static public int foo(int a, int b){\n"+ + " int t = switch (a) {\n"+ + " default -> {\n"+ + " switch (b) {\n"+ + " case 0 -> {\n"+ + " break;\n"+ + " }\n"+ + " default -> {\n"+ + " yield 0;\n"+ + " }\n"+ + " } \n"+ + " }\n"+ + " };\n"+ + " return t;\n"+ + " }\n"+ + " public static void main(String[] args) {\n"+ + " System.out.println(X.foo(0, 0));\n"+ + " }\n"+ + "}\n" + }, + "----------\n" + + "1. ERROR in X.java (at line 13)\n" + + " }\n" + + " ^^\n" + + "A switch labeled block in a switch expression should not complete normally\n" + + "----------\n"); +} + public void testBug563023_003() { + this.runNegativeTest( + new String[] { + "X.java", + "public class X { \n"+ + " static public int foo(int a, int b){\n"+ + " int t = switch (a) {\n"+ + " default -> {\n"+ + " switch (b) {\n"+ + " case 0 -> {\n"+ + " yield 0;\n"+ + " }\n"+ + " } \n"+ + " }\n"+ + " };\n"+ + " return t;\n"+ + " }\n"+ + " public static void main(String[] args) {\n"+ + " System.out.println(X.foo(0, 0));\n"+ + " }\n"+ + "}\n" + }, + "----------\n" + + "1. ERROR in X.java (at line 10)\n" + + " }\n" + + " ^^\n" + + "A switch labeled block in a switch expression should not complete normally\n" + + "----------\n"); +} + public void testBug563023_004() { + this.runNegativeTest( + new String[] { + "X.java", + "public class X { \n"+ + " static public int foo(int a, int b){\n"+ + " int t = switch (a) {\n"+ + " default -> {\n"+ + " switch (b) {\n"+ + " case 0 -> {\n"+ + " break;\n"+ + " }\n"+ + " default -> yield 0;\n"+ + " } \n"+ + " }\n"+ + " };\n"+ + " return t;\n"+ + " }\n"+ + " public static void main(String[] args) {\n"+ + " System.out.println(X.foo(0, 0));\n"+ + " }\n"+ + "}\n" + }, + "----------\n" + + "1. ERROR in X.java (at line 9)\n" + + " default -> yield 0;\n" + + " ^\n" + + "Syntax error on token \"0\", delete this token\n" + + "----------\n"); +} + public void testBug563023_005() { + this.runNegativeTest( + new String[] { + "X.java", + "public class X { \n"+ + " static public int foo(int a, int b){\n"+ + " int t = switch (a) {\n"+ + " default -> {\n"+ + " switch (b) {\n"+ + " case 0 -> {\n"+ + " break;\n"+ + " }\n"+ + " default ->{ yield 0;}\n"+ + " } \n"+ + " }\n"+ + " };\n"+ + " return t;\n"+ + " }\n"+ + " public static void main(String[] args) {\n"+ + " System.out.println(X.foo(0, 0));\n"+ + " }\n"+ + "}\n" + }, + "----------\n" + + "1. ERROR in X.java (at line 11)\n" + + " }\n" + + " ^^\n" + + "A switch labeled block in a switch expression should not complete normally\n" + + "----------\n"); +} + public void testBug563023_006() { + runConformTest( + new String[] { + "X.java", + "public class X { \n"+ + " static public int foo(MyEnum a, MyEnum b){\n"+ + " int t = switch (a) {\n"+ + " default -> {\n"+ + " switch (b) {\n"+ + " case ONE -> { \n"+ + " yield 0;\n"+ + " }\n"+ + " default -> {yield 1;}\n"+ + " } \n"+ + " }\n"+ + " };\n"+ + " return t;\n"+ + " }\n"+ + " public static void main(String[] args) {\n"+ + " System.out.println(X.foo(MyEnum.ONE, MyEnum.TWO));\n"+ + " }\n"+ + "} \n"+ + "enum MyEnum {\n"+ + " ONE,\n"+ + " TWO\n"+ + "}\n" + }, + "1"); + } + public void testBug563023_007() { + this.runNegativeTest( + new String[] { + "X.java", + "public class X { \n"+ + " static public int foo(MyEnum a, MyEnum b){\n"+ + " int t = switch (a) {\n"+ + " default -> {\n"+ + " switch (b) {\n"+ + " case ONE -> { \n"+ + " yield 0;\n"+ + " }\n"+ + " } \n"+ + " }\n"+ + " };\n"+ + " return t;\n"+ + " }\n"+ + " public static void main(String[] args) {\n"+ + " System.out.println(X.foo(MyEnum.ONE, MyEnum.TWO));\n"+ + " }\n"+ + "} \n"+ + "enum MyEnum {\n"+ + " ONE,\n"+ + " TWO\n"+ + "}\n" + }, + "----------\n" + + "1. WARNING in X.java (at line 5)\n" + + " switch (b) {\n" + + " ^\n" + + "The enum constant TWO needs a corresponding case label in this enum switch on MyEnum\n" + + "----------\n" + + "2. ERROR in X.java (at line 10)\n" + + " }\n" + + " ^^\n" + + "A switch labeled block in a switch expression should not complete normally\n" + + "----------\n"); +} public void testBug563147_001() { runConformTest( new String[] { diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Block.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Block.java index 70ee4f9eda..fc8e826f85 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Block.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Block.java @@ -179,4 +179,17 @@ public boolean completesByContinue() { int length = this.statements == null ? 0 : this.statements.length; return length > 0 && this.statements[length - 1].completesByContinue(); } + +@Override +public boolean canCompleteNormally() { + int length = this.statements == null ? 0 : this.statements.length; + return length == 0 || this.statements[length - 1].canCompleteNormally(); +} + +@Override +public boolean continueCompletes() { + int length = this.statements == null ? 0 : this.statements.length; + return length > 0 && this.statements[length - 1].continueCompletes(); +} + } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/BreakStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/BreakStatement.java index 7085ee8421..84467d87fb 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/BreakStatement.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/BreakStatement.java @@ -111,6 +111,13 @@ public void traverse(ASTVisitor visitor, BlockScope blockscope) { public boolean doesNotCompleteNormally() { return true; } + +@Override +public boolean canCompleteNormally() { + return false; +} + + @Override protected boolean doNotReportUnreachable() { return this.isSynthetic; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ContinueStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ContinueStatement.java index 7161c6e91f..b1237e8b4e 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ContinueStatement.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ContinueStatement.java @@ -109,8 +109,19 @@ public void traverse(ASTVisitor visitor, BlockScope blockScope) { public boolean doesNotCompleteNormally() { return true; } + @Override public boolean completesByContinue() { return true; } + +@Override +public boolean canCompleteNormally() { + return false; +} + +@Override +public boolean continueCompletes() { + return true; +} } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/DoStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/DoStatement.java index 548bedd3c8..3c13922f01 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/DoStatement.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/DoStatement.java @@ -262,4 +262,28 @@ public boolean doesNotCompleteNormally() { public boolean completesByContinue() { return this.action.continuesAtOuterLabel(); } + +@Override +public boolean canCompleteNormally() { + Constant cst = this.condition.constant; + boolean isConditionTrue = cst == null || cst != Constant.NotAConstant && cst.booleanValue() == true; + cst = this.condition.optimizedBooleanConstant(); + boolean isConditionOptimizedTrue = cst == null ? true : cst != Constant.NotAConstant && cst.booleanValue() == true; + + if (!(isConditionTrue || isConditionOptimizedTrue)) { + if (this.action == null || this.action.canCompleteNormally()) + return true; + if (this.action != null && this.action.continueCompletes()) + return true; + } + if (this.action != null && this.action.breaksOut(null)) + return true; + + return false; +} +@Override +public boolean continueCompletes() { + return this.action.continuesAtOuterLabel(); +} + } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForStatement.java index db8a6621c6..fc83729691 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForStatement.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForStatement.java @@ -471,4 +471,23 @@ public class ForStatement extends Statement { public boolean completesByContinue() { return this.action.continuesAtOuterLabel(); } + @Override + public boolean canCompleteNormally() { + Constant cst = this.condition == null ? null : this.condition.constant; + boolean isConditionTrue = cst == null || cst != Constant.NotAConstant && cst.booleanValue() == true; + cst = this.condition == null ? null : this.condition.optimizedBooleanConstant(); + boolean isConditionOptimizedTrue = cst == null ? true : cst != Constant.NotAConstant && cst.booleanValue() == true; + + if (!(isConditionTrue || isConditionOptimizedTrue)) + return true; + if (this.action != null && this.action.breaksOut(null)) + return true; + return false; + } + + @Override + public boolean continueCompletes() { + return this.action.continuesAtOuterLabel(); + } + } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForeachStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForeachStatement.java index 99d4f63731..72a538a359 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForeachStatement.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForeachStatement.java @@ -677,4 +677,10 @@ public class ForeachStatement extends Statement { public boolean doesNotCompleteNormally() { return false; // may not be entered at all. } + + @Override + public boolean canCompleteNormally() { + return true; + } + } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IfStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IfStatement.java index bcb2b53a71..1cb95e1394 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IfStatement.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IfStatement.java @@ -306,4 +306,14 @@ public boolean doesNotCompleteNormally() { public boolean completesByContinue() { return this.thenStatement != null && this.thenStatement.completesByContinue() || this.elseStatement != null && this.elseStatement.completesByContinue(); } +@Override +public boolean canCompleteNormally() { + return ((this.thenStatement == null || this.thenStatement.canCompleteNormally()) || + (this.elseStatement == null || this.elseStatement.canCompleteNormally())); +} +@Override +public boolean continueCompletes() { + return this.thenStatement != null && this.thenStatement.continueCompletes() || + this.elseStatement != null && this.elseStatement.continueCompletes(); +} } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LabeledStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LabeledStatement.java index b252fc8af1..fa0b95186d 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LabeledStatement.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LabeledStatement.java @@ -161,4 +161,17 @@ public class LabeledStatement extends Statement { public boolean completesByContinue() { return this.statement instanceof ContinueStatement; // NOT this.statement.continuesAtOuterLabel } + + @Override + public boolean canCompleteNormally() { + if (this.statement.canCompleteNormally()) + return true; + return this.statement.breaksOut(this.label); + } + + @Override + public boolean continueCompletes() { + return this.statement instanceof ContinueStatement; // NOT this.statement.continuesAtOuterLabel + } + } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java index a856cfdf5a..91c2cf20cc 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java @@ -184,6 +184,12 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl public boolean doesNotCompleteNormally() { return true; } + +@Override +public boolean canCompleteNormally() { + return false; +} + /** * Retrun statement code generation * diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java index 86e2b43cce..fac3135ca3 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java @@ -90,7 +90,7 @@ public abstract FlowInfo analyseCode(BlockScope currentScope, FlowContext flowCo For blocks, we don't perform intra-reachability analysis. We assume the lambda body is free of intrinsic control flow errors (if such errors exist they will not be flagged by this analysis, but are guaranteed to surface later on.) - @see Block#doesNotCompleteNormally + @see Block#doesNotCompleteNormally() */ public boolean doesNotCompleteNormally() { return false; @@ -104,6 +104,23 @@ public boolean completesByContinue() { return false; } +/** + * Switch Expression analysis: *Assuming* this is reachable, analyze if this completes normally + * i.e control flow can reach the textually next statement, as per JLS 14 Sec 14.22 + * For blocks, we don't perform intra-reachability analysis. + * Note: delinking this from a similar (opposite) {@link #doesNotCompleteNormally()} since that was + * coded for a specific purpose of Lambda Shape Analysis. + */ +public boolean canCompleteNormally() { + return true; +} +/** + * The equivalent function of completesByContinue - implements both the rules concerning continue with + * and without a label. + */ +public boolean continueCompletes() { + return false; +} public static final int NOT_COMPLAINED = 0; public static final int COMPLAINED_FAKE_REACHABLE = 1; public static final int COMPLAINED_UNREACHABLE = 2; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchExpression.java index 6d10ca950e..e0c96327b4 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchExpression.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchExpression.java @@ -102,7 +102,7 @@ public class SwitchExpression extends SwitchStatement implements IPolyExpression if (this.switchLabeledRules // do this check for every block if '->' (Switch Labeled Rules) && stmt instanceof Block) { Block block = (Block) stmt; - if (block.doesNotCompleteNormally()) { + if (!block.canCompleteNormally()) { return BREAKING; } } @@ -150,7 +150,7 @@ public class SwitchExpression extends SwitchStatement implements IPolyExpression for (Statement stmt : this.statements) { if (!(stmt instanceof Block)) continue; - if (!stmt.doesNotCompleteNormally()) + if (stmt.canCompleteNormally()) blockScope.problemReporter().switchExpressionLastStatementCompletesNormally(stmt); } return; @@ -172,7 +172,7 @@ public class SwitchExpression extends SwitchStatement implements IPolyExpression } } if (lastNonCaseStmt != null) { - if (!lastNonCaseStmt.doesNotCompleteNormally()) + if (lastNonCaseStmt.canCompleteNormally()) blockScope.problemReporter().switchExpressionLastStatementCompletesNormally(lastNonCaseStmt); else if (lastNonCaseStmt instanceof ContinueStatement || lastNonCaseStmt instanceof ReturnStatement) { blockScope.problemReporter().switchExpressionIllegalLastStatement(lastNonCaseStmt); diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java index 0c4745215b..ad6f8bb65e 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java @@ -84,6 +84,8 @@ public class SwitchStatement extends Expression { if (this.switchLabeledRules) { if ((stmt instanceof Expression && ((Expression) stmt).isTrulyExpression()) || stmt instanceof ThrowStatement) return BREAKING; + if (!stmt.canCompleteNormally()) + return BREAKING; if (stmt instanceof Block) { Block block = (Block) stmt; @@ -903,6 +905,55 @@ public class SwitchStatement extends Expression { } @Override + public boolean canCompleteNormally() { + if (this.statements == null || this.statements.length == 0) + return true; + if (!this.switchLabeledRules) { // switch labeled statement group + if (this.statements[this.statements.length - 1].canCompleteNormally()) + return true; // last statement as well as last switch label after blocks if exists. + if (this.defaultCase == null) + return true; + for (int i = 0, length = this.statements.length; i < length; i++) { + if (this.statements[i].breaksOut(null)) + return true; + } + } else { + // switch block consists of switch rules + for (Statement stmt : this.statements) { + if (stmt instanceof CaseStatement) + continue; // skip case + if (this.defaultCase == null) + return true; + if (stmt instanceof Expression) + return true; + if (stmt.canCompleteNormally()) + return true; + if (stmt instanceof YieldStatement && ((YieldStatement) stmt).isImplicit) // note: artificially introduced + return true; + if (stmt instanceof Block) { + Block block = (Block) stmt; + if (block.canCompleteNormally()) + return true; + if (block.breaksOut(null)) + return true; + } + } + } + return false; + } + + @Override + public boolean continueCompletes() { + if (this.statements == null || this.statements.length == 0) + return false; + for (int i = 0, length = this.statements.length; i < length; i++) { + if (this.statements[i].continueCompletes()) + return true; + } + return false; + } + + @Override public StringBuffer printExpression(int indent, StringBuffer output) { return printStatement(indent, output); } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SynchronizedStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SynchronizedStatement.java index cbc5e91707..dbede23432 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SynchronizedStatement.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SynchronizedStatement.java @@ -234,7 +234,18 @@ public boolean doesNotCompleteNormally() { return this.block.doesNotCompleteNormally(); } @Override + public boolean completesByContinue() { return this.block.completesByContinue(); } + +@Override +public boolean canCompleteNormally() { + return this.block.canCompleteNormally(); +} + +@Override +public boolean continueCompletes() { + return this.block.continueCompletes(); +} } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ThrowStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ThrowStatement.java index a744229e5d..bc41e37119 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ThrowStatement.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ThrowStatement.java @@ -99,4 +99,10 @@ public void traverse(ASTVisitor visitor, BlockScope blockScope) { public boolean doesNotCompleteNormally() { return true; } + +@Override +public boolean canCompleteNormally() { + return false; +} + } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java index d5fe5dc9b5..1bd8198bc1 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java @@ -1352,4 +1352,34 @@ public boolean completesByContinue() { } return this.finallyBlock != null && this.finallyBlock.completesByContinue(); } +@Override +public boolean canCompleteNormally() { + if (this.tryBlock.canCompleteNormally()) { + return (this.finallyBlock != null) ? this.finallyBlock.canCompleteNormally() : true; + } + if (this.catchBlocks != null) { + for (int i = 0; i < this.catchBlocks.length; i++) { + if (this.catchBlocks[i].canCompleteNormally()) { + return (this.finallyBlock != null) ? this.finallyBlock.canCompleteNormally() : true; + } + } + } + return false; +} +@Override +public boolean continueCompletes() { + if (this.tryBlock.continueCompletes()) { + return (this.finallyBlock == null) ? true : + this.finallyBlock.canCompleteNormally() || this.finallyBlock.continueCompletes(); + } + if (this.catchBlocks != null) { + for (int i = 0; i < this.catchBlocks.length; i++) { + if (this.catchBlocks[i].continueCompletes()) { + return (this.finallyBlock == null) ? true : + this.finallyBlock.canCompleteNormally() || this.finallyBlock.continueCompletes(); + } + } + } + return this.finallyBlock != null && this.finallyBlock.continueCompletes(); +} } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java index 3db9b23d37..3863cde89f 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java @@ -319,4 +319,20 @@ public class WhileStatement extends Statement { public boolean completesByContinue() { return this.action.continuesAtOuterLabel(); } + + @Override + public boolean canCompleteNormally() { + Constant cst = this.condition.constant; + boolean isConditionTrue = cst == null || cst != Constant.NotAConstant && cst.booleanValue() == true; + cst = this.condition.optimizedBooleanConstant(); + boolean isConditionOptimizedTrue = cst == null ? true : cst != Constant.NotAConstant && cst.booleanValue() == true; + if (!(isConditionTrue || isConditionOptimizedTrue)) + return true; + return this.action != null && this.action.breaksOut(null); + } + + @Override + public boolean continueCompletes() { + return this.action.continuesAtOuterLabel(); + } } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/YieldStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/YieldStatement.java index 87b8c8687b..84a9106bc7 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/YieldStatement.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/YieldStatement.java @@ -224,4 +224,10 @@ public void traverse(ASTVisitor visitor, BlockScope blockscope) { public boolean doesNotCompleteNormally() { return true; } + +@Override +public boolean canCompleteNormally() { + return false; +} + } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java index 39363daa08..ccc537b3ba 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java @@ -9875,7 +9875,7 @@ protected void consumeDefaultLabelExpr() { } @Override public boolean visit(SwitchStatement stmt, BlockScope blockScope) { - return false; + return true; } @Override public boolean visit(TypeDeclaration stmt, BlockScope blockScope) { |