diff options
author | Manoj Palat | 2018-12-04 15:07:24 +0000 |
---|---|---|
committer | Manoj Palat | 2018-12-04 15:07:24 +0000 |
commit | ab4cec02baf018e87db6b9fd3711ce680743587e (patch) | |
tree | 3a1b080a389263d13edcec80eaef260dadd586d1 | |
parent | 05420e1187f52475d6ca4430467d7cd83e2581c7 (diff) | |
download | eclipse.jdt.core-ab4cec02baf018e87db6b9fd3711ce680743587e.tar.gz eclipse.jdt.core-ab4cec02baf018e87db6b9fd3711ce680743587e.tar.xz eclipse.jdt.core-ab4cec02baf018e87db6b9fd3711ce680743587e.zip |
resolution refactoring, IProblem additions
7 files changed, 118 insertions, 89 deletions
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchExpressionTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchExpressionTest.java index e7d9b62e29..9dc76795a4 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchExpressionTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchExpressionTest.java @@ -44,6 +44,7 @@ public class SwitchExpressionTest extends AbstractRegressionTest { defaultOptions.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_9); return defaultOptions; } + public void testSimpleExpressions() { runConformTest( @@ -52,9 +53,9 @@ public class SwitchExpressionTest extends AbstractRegressionTest { "public class X {\n" + " static int twice(int i) {\n" + " int tw = switch (i) {\n" + - " case 0 -> 0;\n" + + " case 0 -> i * 0;\n" + " case 1 -> 2;\n" + - " default -> i * 2;\n" + + " default -> 3;\n" + " };\n" + " return tw;\n" + " }\n" + @@ -104,11 +105,7 @@ public class SwitchExpressionTest extends AbstractRegressionTest { "X.java", "public class X {\n" + " public static void main(String[] args) {\n" + - " int x, y;\n" + - " I i = () -> {\n" + - " int z = 10;\n" + - " };\n" + - " i++;\n" + + " twice(1);\n" + " }\n" + " public static int twice(int i) {\n" + " int tw = switch (i) {\n" + @@ -118,10 +115,16 @@ public class SwitchExpressionTest extends AbstractRegressionTest { "}\n", }, "----------\n" + - "1. ERROR in X.java (at line 7)\n" + + "1. ERROR in X.java (at line 6)\n" + " int tw = switch (i) {\n" + - " ^^^^^\n" + - " A switch expression should have at least one result expression\n" + + " };\n" + + " ^^^^^^^^^^^^^^^^\n" + + "A switch expression should have a non-empty switch block\n" + + "----------\n" + + "2. ERROR in X.java (at line 6)\n" + + " int tw = switch (i) {\n" + + " ^\n" + + "A switch expression should have a default case\n" + "----------\n"); } public void testBug531714_error_004() { @@ -130,11 +133,7 @@ public class SwitchExpressionTest extends AbstractRegressionTest { "X.java", "public class X {\n" + " public static void main(String[] args) {\n" + - " int x, y;\n" + - " I i = () -> {\n" + - " int z = 10;\n" + - " };\n" + - " i++;\n" + + " twice(1);\n" + " }\n" + " public static int twice(int i) {\n" + " int tw = switch (i) {\n" + @@ -143,19 +142,18 @@ public class SwitchExpressionTest extends AbstractRegressionTest { " System.out.println(\"heel\");\n" + " break 1;\n" + " } \n" + - " // case 2 -> 2;\n" + - " case \"hello\" -> throw new IOException(\"hello\");\n" + - " default -> throw new IOException(\"world\");\n" + + " case \"hello\" -> throw new java.io.IOException(\"hello\");\n" + + " default -> throw new java.io.IOException(\"world\");\n" + " };\n" + " return tw;\n" + " }\n" + "}\n", }, "----------\n" + - "1. ERROR in X.java (at line 7)\n" + - " int tw = switch (i) {\n" + - " ^^^^^\n" + - " Incompatible switch results expressions\n" + + "1. ERROR in X.java (at line 12)\n" + + " case \"hello\" -> throw new java.io.IOException(\"hello\");\n" + + " ^^^^^^^\n" + + "Type mismatch: cannot convert from String to int\n" + "----------\n"); } public void testBug531714_error_005() { @@ -164,11 +162,7 @@ public class SwitchExpressionTest extends AbstractRegressionTest { "X.java", "public class X {\n" + " public static void main(String[] args) {\n" + - " int x, y;\n" + - " I i = () -> {\n" + - " int z = 10;\n" + - " };\n" + - " i++;\n" + + " twice(1);\n" + " }\n" + " public static int twice(int i) {\n" + " int tw = switch (i) {\n" + @@ -177,18 +171,17 @@ public class SwitchExpressionTest extends AbstractRegressionTest { " System.out.println(\"heel\");\n" + " break 1;\n" + " } \n" + - " // case 2 -> 2;\n" + - " case \"hello\" -> throw new IOException(\"hello\");\n" + + " case 2 -> 2;\n" + " };\n" + " return tw;\n" + " }\n" + "}\n", }, "----------\n" + - "1. ERROR in X.java (at line 7)\n" + + "1. ERROR in X.java (at line 6)\n" + " int tw = switch (i) {\n" + - " ^^^^^\n" + - " The switch expression should have a default case\n" + + " ^\n" + + "A switch expression should have a default case\n" + "----------\n"); } /** @@ -198,7 +191,7 @@ public class SwitchExpressionTest extends AbstractRegressionTest { * must contain all the enum constants of that enum type * Add a missing enum test case */ - public void testBug531714_error_006() { + public void _testBug531714_error_006() { this.runNegativeTest( new String[] { "X.java", diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java index 1ccca7a7b4..ddc18aa429 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java @@ -2083,7 +2083,13 @@ void setSourceStart(int sourceStart); /** @since 3.16 BETA_JAVA_12 */ int SwitchExpressionsNoResultExpression = TypeRelated + 1602; /** @since 3.16 BETA_JAVA_12 */ - int SwitchExpressionBlockCompletesNormally = Internal + 1603; + int SwitchExpressionSwitchLabeledBlockCompletesNormally = Internal + 1603; /** @since 3.16 BETA_JAVA_12 */ - int MixedCase = Syntax + 1604; + int SwitchExpressionLastStatementCompletesNormally = Internal + 1604; + /** @since 3.16 BETA_JAVA_12 */ + int SwitchExpressionTrailingSwitchLabels = Internal + 1605; + /** @since 3.16 BETA_JAVA_12 */ + int MixedCase = Syntax + 1606; + /** @since 3.16 BETA_JAVA_12 */ + int SwitchExpressionMissingDefaultCase = Internal + 1607; } 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 7542bdd65d..ab4a46b616 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 @@ -102,6 +102,12 @@ protected void generateExpressionResultCode(BlockScope currentScope, CodeStream this.expression.generateCode(currentScope, codeStream, true /* valueRequired */); } } +@Override +public void resolve(BlockScope scope) { + super.resolve(scope); + if (this.expression != null) + this.expression.resolve(scope); +} @Override public TypeBinding resolveExpressionType(BlockScope scope) { 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 1e9af10f38..5c9a11e069 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 @@ -22,14 +22,12 @@ import org.eclipse.jdt.internal.compiler.ASTVisitor; import org.eclipse.jdt.internal.compiler.codegen.CodeStream; import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.eclipse.jdt.internal.compiler.impl.Constant; -import org.eclipse.jdt.internal.compiler.lookup.Binding; import org.eclipse.jdt.internal.compiler.lookup.BlockScope; import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment; import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; import org.eclipse.jdt.internal.compiler.lookup.PolyTypeBinding; import org.eclipse.jdt.internal.compiler.lookup.Scope; import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities; public class SwitchExpression extends SwitchStatement implements IPolyExpression { @@ -56,21 +54,54 @@ public class SwitchExpression extends SwitchStatement implements IPolyExpression return this.expressionContext; } @Override + protected boolean ignoreMissingDefaultCase(CompilerOptions compilerOptions, boolean isEnumSwitch) { + return isEnumSwitch; // mandatory error if not enum in switch expressions + } + @Override protected int getFallThroughState(Statement stmt, BlockScope blockScope) { if (stmt instanceof Expression || stmt instanceof ThrowStatement) return BREAKING; - if (stmt instanceof Block) { + if (this.switchLabeledRules // do this check for every block if '->' (Switch Labeled Rules) + && stmt instanceof Block) { Block block = (Block) stmt; if (block.doesNotCompleteNormally()) { return BREAKING; } //JLS 12 15.29.1 Given a switch expression, if the switch block consists of switch labeled rules, //then it is a compile-time error if any switch labeled block can complete normally. - blockScope.problemReporter().switchExpressionBlockCompletesNormally(block); + blockScope.problemReporter().switchExpressionSwitchLabeledBlockCompletesNormally(block); } return FALLTHROUGH; } @Override + protected void completeNormallyCheck(BlockScope blockScope) { + if (this.switchLabeledRules) return; // already taken care in getFallThroughState() + int sz = this.statements != null ? this.statements.length : 0; + if (sz == 0) return; + /* JLS 12 15.29.1 + * If, on the other hand, the switch block consists of switch labeled statement groups, then it is a + * compile-time error if either the last statement in the switch block can complete normally, or the + * switch block includes one or more switch labels at the end. + */ + Statement lastNonCaseStmt = null; + Statement firstTrailingCaseStmt = null; + for (int i = sz - 1; i >= 0; i--) { + Statement stmt = this.statements[sz - 1]; + if (stmt instanceof CaseStatement) + firstTrailingCaseStmt = stmt; + else { + lastNonCaseStmt = stmt; + break; + } + } + if (lastNonCaseStmt != null && !lastNonCaseStmt.doesNotCompleteNormally()) { + blockScope.problemReporter().switchExpressionLastStatementCompletesNormally(lastNonCaseStmt); + } + if (firstTrailingCaseStmt != null) { + blockScope.problemReporter().switchExpressionTrailingSwitchLabels(firstTrailingCaseStmt); + } + } + @Override public Expression[] getPolyExpressions() { List<Expression> polys = new ArrayList<>(); for (Expression e : this.resultExpressions) { @@ -247,16 +278,6 @@ public class SwitchExpression extends SwitchStatement implements IPolyExpression upperScope.problemReporter().switchExpressionEmptySwitchBlock(this); return null; } - if (this.defaultCase == null) { - if (compilerOptions.getSeverity(CompilerOptions.MissingDefaultCase) == ProblemSeverities.Ignore) { - TypeBinding expressionType = this.expression.resolvedType; - if (!expressionType.isEnum()) { - // cannot ignore in SwitchExpressions - this is a compile-time error - // it was not reported earlier in super.resolve() since it was ignored. - upperScope.problemReporter().missingDefaultCase(this, false /* isEnumSwitch*/, expressionType); - } - } - } // now we are done with case constants, let us collect the result expressions collectResultExpressions(); @@ -279,24 +300,14 @@ public class SwitchExpression extends SwitchStatement implements IPolyExpression } } - if (this.constant != Constant.NotAConstant) { - this.constant = Constant.NotAConstant; + if (this.originalValueResultExpressionTypes == null) { this.originalValueResultExpressionTypes = new TypeBinding[resultExpressionsCount]; + this.finalValueResultExpressionTypes = new TypeBinding[resultExpressionsCount]; for (int i = 0; i < resultExpressionsCount; ++i) { - this.originalValueResultExpressionTypes[i] = this.resultExpressions.get(i).resolveType(this.scope); + this.finalValueResultExpressionTypes[i] = this.originalValueResultExpressionTypes[i] = + this.resultExpressions.get(i).resolvedType; } - // TODO: should we return if one of the types is null? to check - } else { - for (int i = 0; i < resultExpressionsCount; ++i) { - if (this.originalValueResultExpressionTypes[i].kind() == Binding.POLY_TYPE) - this.originalValueResultExpressionTypes[i] = this.resultExpressions.get(i).resolveType(this.scope); - } - // TODO: should we return if one of the types is null? to check } - this.finalValueResultExpressionTypes = new TypeBinding[resultExpressionsCount]; - for (int i = 0; i < resultExpressionsCount; ++i) - this.finalValueResultExpressionTypes[i] = this.originalValueResultExpressionTypes[i]; - if (isPolyExpression()) { //The type of a poly switch expression is the same as its target type. if (this.expectedType == null || !this.expectedType.isProperType(true)) { return new PolyTypeBinding(this); 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 8631eed5af..86940e68dd 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 @@ -56,6 +56,7 @@ public class SwitchStatement extends Expression { public int caseCount; int[] constants; String[] stringConstants; + public boolean switchLabeledRules = false; // true if case ->, false if case : // fallthrough public final static int CASE = 0; @@ -80,6 +81,9 @@ public class SwitchStatement extends Expression { protected int getFallThroughState(Statement stmt, BlockScope blockScope) { return FALLTHROUGH; } + protected void completeNormallyCheck(BlockScope blockScope) { + // do nothing + } @Override public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { try { @@ -126,6 +130,7 @@ public class SwitchStatement extends Expression { } else { fallThroughState = getFallThroughState(statement, currentScope); // reset below if needed } + completeNormallyCheck(currentScope); if ((complaintLevel = statement.complainIfUnreachable(caseInits, this.scope, complaintLevel, true)) < Statement.COMPLAINED_UNREACHABLE) { caseInits = statement.analyseCode(this.scope, switchContext, caseInits); if (caseInits == FlowInfo.DEAD_END) { @@ -570,7 +575,7 @@ public class SwitchStatement extends Expression { reportMixingCaseTypes(); // check default case for all kinds of switch: if (this.defaultCase == null) { - if (compilerOptions.getSeverity(CompilerOptions.MissingDefaultCase) == ProblemSeverities.Ignore) { + if (ignoreMissingDefaultCase(compilerOptions, isEnumSwitch)) { if (isEnumSwitch) { upperScope.methodScope().hasMissingSwitchDefault = true; } @@ -607,18 +612,23 @@ public class SwitchStatement extends Expression { if (this.scope != null) this.scope.enclosingCase = null; // no longer inside switch case block } } + protected boolean ignoreMissingDefaultCase(CompilerOptions compilerOptions, boolean isEnumSwitch) { + return compilerOptions.getSeverity(CompilerOptions.MissingDefaultCase) == ProblemSeverities.Ignore; + } private void reportMixingCaseTypes() { - if (this.caseCount == 0) + if (this.caseCount == 0) { + this.switchLabeledRules = this.defaultCase != null ? this.defaultCase.isExpr : this.switchLabeledRules; return; - boolean isExpr = this.cases[0].isExpr; + } + boolean isExpr = this.switchLabeledRules = this.cases[0].isExpr; for (int i = 1, l = this.caseCount; i < l; ++i) { if (this.cases[i].isExpr != isExpr) { this.scope.problemReporter().mixedCase(this.cases[i]); return; } } - if (this.defaultCase.isExpr != isExpr) { + if (this.defaultCase != null && this.defaultCase.isExpr != isExpr) { this.scope.problemReporter().mixedCase(this.defaultCase); } } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java index f2752bf6db..9e4be30c9b 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java @@ -6496,30 +6496,14 @@ public void missingDefaultCase(SwitchStatement switchStatement, boolean isEnumSw switchStatement.expression.sourceEnd); } else { this.handle( - IProblem.MissingDefaultCase, + switchStatement instanceof SwitchExpression ? + IProblem.SwitchExpressionMissingDefaultCase : IProblem.MissingDefaultCase, NoArgument, NoArgument, switchStatement.expression.sourceStart, switchStatement.expression.sourceEnd); } } -public void missingDefaultCase(SwitchExpression switchExpression, boolean isEnumSwitch, TypeBinding expressionType) { - if (isEnumSwitch) { - this.handle( - IProblem.MissingEnumDefaultCase, - new String[] {new String(expressionType.readableName())}, - new String[] {new String(expressionType.shortReadableName())}, - switchExpression.expression.sourceStart, - switchExpression.expression.sourceEnd); - } else { - this.handle( - IProblem.MissingDefaultCase, - NoArgument, - NoArgument, - switchExpression.expression.sourceStart, - switchExpression.expression.sourceEnd); - } -} public void missingOverrideAnnotation(AbstractMethodDeclaration method) { int severity = computeSeverity(IProblem.MissingOverrideAnnotation); if (severity == ProblemSeverities.Ignore) return; @@ -11030,14 +11014,30 @@ public void switchExpressionNoResultExpressions(SwitchExpression expression) { expression.sourceStart, expression.sourceEnd); } -public void switchExpressionBlockCompletesNormally(Block block) { +public void switchExpressionSwitchLabeledBlockCompletesNormally(Block block) { this.handle( - IProblem.SwitchExpressionBlockCompletesNormally, + IProblem.SwitchExpressionSwitchLabeledBlockCompletesNormally, NoArgument, NoArgument, block.sourceStart, block.sourceEnd); } +public void switchExpressionLastStatementCompletesNormally(Statement stmt) { + this.handle( + IProblem.SwitchExpressionSwitchLabeledBlockCompletesNormally, + NoArgument, + NoArgument, + stmt.sourceStart, + stmt.sourceEnd); +} +public void switchExpressionTrailingSwitchLabels(Statement stmt) { + this.handle( + IProblem.SwitchExpressionTrailingSwitchLabels, + NoArgument, + NoArgument, + stmt.sourceStart, + stmt.sourceEnd); +} public void mixedCase(ASTNode statement) { this.handle( IProblem.MixedCase, diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties index 4d878866a1..696807cebb 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties @@ -970,8 +970,11 @@ 1600 = Incompatible switch results expressions {0} 1601 = A switch expression should have a non-empty switch block 1602 = A switch expression {0} should have at least one result expression -1603 = The switch block in a switch expression should not complete normally -1604 = Mixing of different kinds of case statements '->' and ':' is not allowed within a switch +1603 = A switch labeled block in a switch expression should not complete normally +1604 = The last statement of a switch block in a switch expression should not complete normally +1605 = Trailing switch labels are not allowed in a switch expression. +1606 = Mixing of different kinds of case statements '->' and ':' is not allowed within a switch +1607 = A switch expression should have a default case ### ELABORATIONS |