Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorManoj Palat2020-05-14 16:21:06 +0000
committerManoj Palat2020-05-14 18:24:02 +0000
commit28edbf1262165302ab535a12e4da10c870507c1d (patch)
tree7129beca28a665c515be493afeaacac6e42711fa
parent7764772c16a268ab0f81abb866119b541b2ffb60 (diff)
downloadeclipse.jdt.core-28edbf1262165302ab535a12e4da10c870507c1d.tar.gz
eclipse.jdt.core-28edbf1262165302ab535a12e4da10c870507c1d.tar.xz
eclipse.jdt.core-28edbf1262165302ab535a12e4da10c870507c1d.zip
Bug 563023 - [14] Switch Expression - Investigate the usage of
doesNotCompleteNormally() - Switch Statement in Switch Expression error Change-Id: I97a4b3cfbd45b90561f90fe604208aeb6297e6fe
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/LambdaShapeTests.java2
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchExpressionsYieldTest.java212
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Block.java13
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/BreakStatement.java7
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ContinueStatement.java11
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/DoStatement.java24
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForStatement.java19
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForeachStatement.java6
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IfStatement.java10
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LabeledStatement.java13
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java6
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java19
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchExpression.java6
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java51
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SynchronizedStatement.java11
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ThrowStatement.java6
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java30
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java16
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/YieldStatement.java6
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java2
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) {

Back to the top