From d0af8a481c95d1088fdaddabd2110e6f10b125e7 Mon Sep 17 00:00:00 2001 From: Srikanth Sankaran <131454720+srikanth-sankaran@users.noreply.github.com> Date: Wed, 30 Oct 2024 09:05:24 +0530 Subject: [PATCH] Streamline error handling for Switch Expressions (#3199) * Deprecate unused IProblem constants, simplify messages, rename methods for readability, get rid of unused property strings, subsume unnecessarily distinct diagnostics, ensure error handling happens in appropriate places, remove dead code, simplify control flow ... --- .../eclipse/jdt/core/compiler/IProblem.java | 40 ++++++-- .../internal/compiler/ast/BreakStatement.java | 2 +- .../internal/compiler/ast/CaseStatement.java | 17 +++- .../compiler/ast/ContinueStatement.java | 2 +- .../internal/compiler/ast/MessageSend.java | 2 +- .../compiler/ast/ReturnStatement.java | 2 +- .../compiler/ast/SwitchExpression.java | 62 +++--------- .../compiler/ast/SwitchStatement.java | 27 +----- .../internal/compiler/ast/YieldStatement.java | 25 ++--- .../jdt/internal/compiler/parser/Parser.java | 4 +- .../compiler/problem/ProblemReporter.java | 94 ++----------------- .../compiler/problem/messages.properties | 24 ++--- .../SwitchExpressionsYieldTest.java | 47 ++++++++-- .../eclipse/jdt/core/dom/ASTConverter.java | 4 +- 14 files changed, 135 insertions(+), 217 deletions(-) diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/core/compiler/IProblem.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/core/compiler/IProblem.java index 55276ed108a..42d2fd9d5de 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/core/compiler/IProblem.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/core/compiler/IProblem.java @@ -2325,35 +2325,55 @@ public interface IProblem { int SwitchExpressionsYieldNoResultExpression = Internal + 1702; /** @since 3.21 */ int SwitchExpressionaYieldSwitchLabeledBlockCompletesNormally = Internal + 1703; - /** @since 3.21 */ + /** @since 3.21 + * @deprecated no longer issued - will be removed + */ int SwitchExpressionsYieldLastStatementCompletesNormally = Internal + 1704; - /** @since 3.21 */ + /** @since 3.21 + * @deprecated no longer issued - will be removed + */ int SwitchExpressionsYieldTrailingSwitchLabels = Internal + 1705; /** @since 3.21 */ int SwitchPreviewMixedCase = Syntax + 1706; /** @since 3.21 */ int SwitchExpressionsYieldMissingDefaultCase = Syntax + 1707; - /** @since 3.21 */ + /** @since 3.21 + * @deprecated no longer issued - will be removed + */ int SwitchExpressionsYieldMissingValue = Syntax + 1708; /** @since 3.21 */ int SwitchExpressionsYieldMissingEnumConstantCase = Syntax + 1709; - /** @since 3.21 */ + /** @since 3.21 + * @deprecated no longer issued - will be removed + */ int SwitchExpressionsYieldIllegalLastStatement = Internal + 1710; - /** @since 3.21 */ + /** @since 3.21 + * @deprecated no longer issued - will be removed + */ int SwitchExpressionsYieldBreakNotAllowed = Syntax + 1711; - /** @since 3.21 */ + /** @since 3.21 + * @deprecated no longer issued - will be removed + */ int SwitchExpressionsYieldUnqualifiedMethodWarning = Syntax + 1712; /** @since 3.21 */ int SwitchExpressionsYieldUnqualifiedMethodError = Syntax + 1713; /** @since 3.21 */ int SwitchExpressionsYieldOutsideSwitchExpression = Syntax + 1714; - /** @since 3.21 */ + /** @since 3.21 + * @deprecated no longer issued - will be removed + */ int SwitchExpressionsYieldRestrictedGeneralWarning = Internal + 1715; - /** @since 3.21 */ + /** @since 3.21 + * @deprecated no longer issued - will be removed + */ int SwitchExpressionsYieldIllegalStatement = Internal + 1716; - /** @since 3.21 */ + /** @since 3.21 + * @deprecated no longer issued - will be removed + */ int SwitchExpressionsYieldTypeDeclarationWarning = Internal + 1717; - /** @since 3.21 */ + /** @since 3.21 + * @deprecated no longer issued - will be removed + */ int SwitchExpressionsYieldTypeDeclarationError = Internal + 1718; /** @since 3.22 */ int MultiConstantCaseLabelsNotSupported = Syntax + 1719; diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/BreakStatement.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/BreakStatement.java index 9c3a03016a8..a157727a96e 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/BreakStatement.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/BreakStatement.java @@ -46,7 +46,7 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl } return flowInfo; // pretend it did not break since no actual target } else if (targetContext == FlowContext.NonLocalGotoThroughSwitchContext) { // JLS 13 14.15 - currentScope.problemReporter().switchExpressionsBreakOutOfSwitchExpression(this); + currentScope.problemReporter().breakOutOfSwitchExpression(this); return flowInfo; // pretend it did not break since no actual target } diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/CaseStatement.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/CaseStatement.java index 77cb7cc0f05..7188e517e84 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/CaseStatement.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/CaseStatement.java @@ -43,7 +43,7 @@ public class CaseStatement extends Statement { public BranchLabel targetLabel; public Expression[] constantExpressions; // case with multiple expressions - if you want a under-the-hood view, use peeledLabelExpressions() public BranchLabel[] targetLabels; // for multiple expressions - public boolean isExpr = false; + public boolean isSwitchRule = false; public SwitchStatement swich; // owning switch public int typeSwitchIndex; // for the first pattern among this.constantExpressions @@ -177,6 +177,16 @@ public String toString() { */ public ResolvedCase[] resolveCase(BlockScope scope, TypeBinding switchExpressionType, SwitchStatement switchStatement) { this.swich = switchStatement; + + if (this.isSwitchRule) + this.swich.switchBits |= SwitchStatement.LabeledRules; + else + this.swich.switchBits |= SwitchStatement.LabeledBlockStatementGroup; + + if ((this.swich.switchBits & (SwitchStatement.LabeledRules | SwitchStatement.LabeledBlockStatementGroup)) == (SwitchStatement.LabeledRules | SwitchStatement.LabeledBlockStatementGroup)) { + scope.problemReporter().arrowColonMixup(this); + } + scope.enclosingCase = this; // record entering in a switch case block if (this.constantExpressions == Expression.NO_EXPRESSIONS) { checkDuplicateDefault(scope, switchStatement, this); @@ -461,16 +471,15 @@ public void generateCode(BlockScope currentScope, CodeStream codeStream) { public StringBuilder printStatement(int tab, StringBuilder output) { printIndent(tab, output); if (this.constantExpressions == Expression.NO_EXPRESSIONS) { - output.append("default "); //$NON-NLS-1$ - output.append(this.isExpr ? "->" : ":"); //$NON-NLS-1$ //$NON-NLS-2$ + output.append("default"); //$NON-NLS-1$ } else { output.append("case "); //$NON-NLS-1$ for (int i = 0, l = this.constantExpressions.length; i < l; ++i) { this.constantExpressions[i].printExpression(0, output); if (i < l -1) output.append(','); } - output.append(this.isExpr ? " ->" : " :"); //$NON-NLS-1$ //$NON-NLS-2$ } + output.append(this.isSwitchRule ? " ->" : " :"); //$NON-NLS-1$ //$NON-NLS-2$ return output; } diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/ContinueStatement.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/ContinueStatement.java index deb1a05b16c..0caa1678c89 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/ContinueStatement.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/ContinueStatement.java @@ -46,7 +46,7 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl } return flowInfo; // pretend it did not continue since no actual target } else if (targetContext == FlowContext.NonLocalGotoThroughSwitchContext) { - currentScope.problemReporter().switchExpressionsContinueOutOfSwitchExpression(this); + currentScope.problemReporter().continueOutOfSwitchExpression(this); return flowInfo; // pretend it did not continue since no actual target } diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/MessageSend.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/MessageSend.java index 3b20f500409..7932215dd15 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/MessageSend.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/MessageSend.java @@ -312,7 +312,7 @@ private void yieldQualifiedCheck(BlockScope currentScope) { return; if (!CharOperation.equals(this.selector, TypeConstants.YIELD)) return; - currentScope.problemReporter().switchExpressionsYieldUnqualifiedMethodError(this); + currentScope.problemReporter().unqualifiedYieldMethod(this); } private void recordCallingClose(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Expression closeTarget) { if (closeTarget.isThis() || closeTarget.isSuper()) { diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java index c51f4c0dac1..722ede5980f 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java @@ -161,7 +161,7 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl currentScope.problemReporter().cannotReturnInInitializer(this); return FlowInfo.DEAD_END; } else if (traversedContext.associatedNode instanceof SwitchExpression) { - currentScope.problemReporter().switchExpressionsReturnWithinSwitchExpression(this); + currentScope.problemReporter().returnOutOfSwitchExpression(this); return FlowInfo.DEAD_END; } } while ((traversedContext = traversedContext.getLocalParent()) != null); diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/SwitchExpression.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/SwitchExpression.java index 87a4e74995a..0d89b5d91a8 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/SwitchExpression.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/SwitchExpression.java @@ -125,53 +125,11 @@ private void computeNullStatus(FlowInfo flowInfo, FlowContext flowContext) { this.nullStatus = status; } - @Override - protected void completeNormallyCheck(BlockScope blockScope) { - int sz = this.statements != null ? this.statements.length : 0; - if (sz == 0) return; - /* JLS 12 15.28.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. - */ - if ((this.switchBits & LabeledRules) != 0) { - for (Statement stmt : this.statements) { - if (!(stmt instanceof Block)) - continue; - if (stmt.canCompleteNormally()) - blockScope.problemReporter().switchExpressionLastStatementCompletesNormally(stmt); - } - return; - } - /* JLS 12 15.28.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) { - if (lastNonCaseStmt.canCompleteNormally()) - blockScope.problemReporter().switchExpressionLastStatementCompletesNormally(lastNonCaseStmt); - else if (lastNonCaseStmt instanceof ContinueStatement || lastNonCaseStmt instanceof ReturnStatement) { - blockScope.problemReporter().switchExpressionIllegalLastStatement(lastNonCaseStmt); - } - } - if (firstTrailingCaseStmt != null) { - blockScope.problemReporter().switchExpressionTrailingSwitchLabels(firstTrailingCaseStmt); - } - } @Override protected boolean needToCheckFlowInAbsenceOfDefaultBranch() { // JLS 12 16.1.8 return (this.switchBits & LabeledRules) == 0; } + @Override public Expression[] getPolyExpressions() { List polys = new ArrayList<>(); @@ -379,7 +337,7 @@ public TypeBinding resolveType(BlockScope upperScope) { resultExpressionsCount = this.resultExpressions.size(); if (resultExpressionsCount == 0) { - upperScope.problemReporter().switchExpressionNoResultExpressions(this); + upperScope.problemReporter().unyieldingSwitchExpression(this); return this.resolvedType = null; } @@ -397,7 +355,6 @@ public TypeBinding resolveType(BlockScope upperScope) { } return this.resolvedType = computeConversions(this.scope, this.expectedType) ? this.expectedType : null; } - // fall through } else { // re-resolving of poly expression: resultExpressionsCount = this.resultExpressions.size(); @@ -418,7 +375,6 @@ public TypeBinding resolveType(BlockScope upperScope) { if (yieldErrors) return this.resolvedType = null; this.resolvedType = computeConversions(this.scope, this.expectedType) ? this.expectedType : null; - // fall through } boolean uniformYield = true; @@ -541,7 +497,7 @@ public TypeBinding resolveType(BlockScope upperScope) { } return this.resolvedType = commonType.capture(this.scope, this.sourceStart, this.sourceEnd); } - this.scope.problemReporter().switchExpressionIncompatibleResultExpressions(this); + this.scope.problemReporter().incompatibleSwitchExpressionResults(this); return null; } finally { if (this.scope != null) this.scope.enclosingCase = null; // no longer inside switch case block @@ -569,6 +525,18 @@ private boolean areAllIntegerResultExpressionsConvertibleToTargetType(TypeBindin @Override public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { flowInfo = super.analyseCode(currentScope, flowContext, flowInfo); + // 15.28.1 + if ((this.switchBits & LabeledRules) != 0) { + for (Statement stmt : this.statements) { + if (stmt instanceof Block && stmt.canCompleteNormally()) + currentScope.problemReporter().switchExpressionBlockCompletesNormally(stmt); + } + } else { + Statement ultimateStmt = this.statements[this.statements.length - 1]; // length guaranteed > 0 + if (ultimateStmt.canCompleteNormally()) + currentScope.problemReporter().switchExpressionBlockCompletesNormally(ultimateStmt); + } + this.resultExpressionNullStatus = new ArrayList<>(0); final CompilerOptions compilerOptions = currentScope.compilerOptions(); if (compilerOptions.enableSyntacticNullAnalysisForFields) { diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java index 5adc2ec3154..a53c29c6bb4 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java @@ -105,6 +105,7 @@ public static record SingletonBootstrap(String id, char[] selector, char[] signa public final static int TotalPattern = ASTNode.Bit3; public final static int Exhaustive = ASTNode.Bit4; public final static int QualifiedEnum = ASTNode.Bit5; + public final static int LabeledBlockStatementGroup = ASTNode.Bit6; // for switch on strings private static final char[] SecretStringVariableName = " switchDispatchString".toCharArray(); //$NON-NLS-1$ @@ -402,9 +403,6 @@ protected int getFallThroughState(Statement stmt, BlockScope blockScope) { } return FALLTHROUGH; } - protected void completeNormallyCheck(BlockScope blockScope) { - // do nothing - } protected boolean needToCheckFlowInAbsenceOfDefaultBranch() { return !this.isExhaustive(); } @@ -493,7 +491,6 @@ else if ((statement.bits & ASTNode.DocumentedFallthrough) == 0) { // the case is } } } - completeNormallyCheck(currentScope); } final TypeBinding resolvedTypeBinding = this.expression.resolvedType; @@ -1266,7 +1263,6 @@ && defaultFound && isExhaustive()) { if (this.dispatchPatternCopy == null) { addSecretPatternSwitchVariables(upperScope); } - reportMixingCaseTypes(); complainIfNotExhaustiveSwitch(upperScope, expressionType, compilerOptions); @@ -1501,26 +1497,7 @@ protected boolean ignoreMissingDefaultCase(CompilerOptions compilerOptions) { public boolean isTrulyExpression() { return false; } - private void reportMixingCaseTypes() { - if (this.caseCount == 0) { - if (this.defaultCase != null && this.defaultCase.isExpr) - this.switchBits |= LabeledRules; - return; - } - if (this.cases[0] == null) - return; - boolean isExpr = this.cases[0].isExpr; - if (isExpr) this.switchBits |= LabeledRules; - for (int i = 1, l = this.caseCount; i < l; ++i) { - if (this.cases[i].isExpr != isExpr) { - this.scope.problemReporter().switchExpressionMixedCase(this.cases[i]); - return; - } - } - if (this.defaultCase != null && this.defaultCase.isExpr != isExpr) { - this.scope.problemReporter().switchExpressionMixedCase(this.defaultCase); - } - } + private void reportDuplicateCase(final Statement duplicate, final Statement original, int length) { diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/YieldStatement.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/YieldStatement.java index 6b94f33ffce..0172477734c 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/YieldStatement.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/YieldStatement.java @@ -207,27 +207,20 @@ public void resolve(BlockScope scope) { this.switchExpression = scope.enclosingSwitchExpression(); if (this.switchExpression != null) { this.switchExpression.resultExpressions.add(this.expression); - if (this.switchExpression.expressionContext == ASSIGNMENT_CONTEXT || this.switchExpression.expressionContext == INVOCATION_CONTEXT) { // poly switch expression + if (this.switchExpression.expressionContext == ASSIGNMENT_CONTEXT || this.switchExpression.expressionContext == INVOCATION_CONTEXT) { // When switch expression is poly ... this.expression.setExpressionContext(this.switchExpression.expressionContext); // result expressions feature in same context ... this.expression.setExpectedType(this.switchExpression.expectedType); // ... with the same target type } } } - if (this.switchExpression != null || this.isImplicit) { - if (this.switchExpression == null && this.isImplicit && !this.expression.statementExpression()) { - if (scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK14) { - /* JLS 13 14.11.2 - Switch labeled rules in switch statements differ from those in switch expressions (15.28). - In switch statements they must be switch labeled statement expressions, ... */ - scope.problemReporter().invalidExpressionAsStatement(this.expression); - return; - } - } - } else { - if (scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK14) { - scope.problemReporter().switchExpressionsYieldOutsideSwitchExpression(this); + if (this.isImplicit) { + if (this.switchExpression == null && !this.expression.statementExpression()) { + scope.problemReporter().invalidExpressionAsStatement(this.expression); + return; } + } else if (this.switchExpression == null) { + scope.problemReporter().yieldOutsideSwitchExpression(this); } TypeBinding type = this.expression.resolveType(scope); if (this.switchExpression != null && type != null) @@ -236,12 +229,10 @@ Switch labeled rules in switch statements differ from those in switch expression @Override public StringBuilder printStatement(int tab, StringBuilder output) { - if (!this.isImplicit) - printIndent(tab, output).append("yield"); //$NON-NLS-1$ if (this.isImplicit) { this.expression.print(tab, output); } else { - output.append(' '); + printIndent(tab, output).append("yield "); //$NON-NLS-1$ this.expression.printExpression(tab, output); } return output.append(';'); diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/Parser.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/Parser.java index dd17bdc6e42..d8b236d3972 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/Parser.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/Parser.java @@ -9470,7 +9470,7 @@ protected void consumeCaseLabelExpr() { if (!this.parsingJava14Plus) { problemReporter().arrowInCaseStatementsNotSupported(caseStatement); } - caseStatement.isExpr = true; + caseStatement.isSwitchRule = true; } protected void consumeDefaultLabelExpr() { // SwitchLabelDefaultExpr ::= 'default' '->' @@ -9479,7 +9479,7 @@ protected void consumeDefaultLabelExpr() { if (!this.parsingJava14Plus) { problemReporter().arrowInCaseStatementsNotSupported(defaultStatement); } - defaultStatement.isExpr = true; + defaultStatement.isSwitchRule = true; } protected void consumeSwitchExpression() { // SwitchExpression ::= 'switch' '(' Expression ')' OpenBlock SwitchExpressionBlock diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java index f76bd42c7f8..92b95029525 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java @@ -1669,9 +1669,6 @@ public int computeSeverity(int problemID){ switch (problemID) { case IProblem.VarargsConflict : - case IProblem.SwitchExpressionsYieldUnqualifiedMethodWarning: - case IProblem.SwitchExpressionsYieldRestrictedGeneralWarning: - case IProblem.SwitchExpressionsYieldTypeDeclarationWarning: case IProblem.StrictfpNotRequired: return ProblemSeverities.Warning; case IProblem.TypeCollidesWithPackage : @@ -11671,7 +11668,7 @@ public void moduleDoesNotReadOther(ImportReference importReference, ModuleBindin importReference.sourceStart, importReference.sourceEnd); } -public void switchExpressionIncompatibleResultExpressions(SwitchExpression expression) { +public void incompatibleSwitchExpressionResults(SwitchExpression expression) { TypeBinding type = expression.resultExpressions.get(0).resolvedType; this.handle( IProblem.SwitchExpressionsYieldIncompatibleResultExpressionTypes, @@ -11680,7 +11677,7 @@ public void switchExpressionIncompatibleResultExpressions(SwitchExpression expre expression.sourceStart, expression.sourceEnd); } -public void switchExpressionNoResultExpressions(SwitchExpression expression) { +public void unyieldingSwitchExpression(SwitchExpression expression) { this.handle( IProblem.SwitchExpressionsYieldNoResultExpression, NoArgument, @@ -11688,15 +11685,7 @@ public void switchExpressionNoResultExpressions(SwitchExpression expression) { expression.sourceStart, expression.sourceEnd); } -public void switchExpressionSwitchLabeledBlockCompletesNormally(Block block) { - this.handle( - IProblem.SwitchExpressionaYieldSwitchLabeledBlockCompletesNormally, - NoArgument, - NoArgument, - block.sourceEnd - 1, - block.sourceEnd); -} -public void switchExpressionLastStatementCompletesNormally(Statement stmt) { +public void switchExpressionBlockCompletesNormally(Statement stmt) { this.handle( IProblem.SwitchExpressionaYieldSwitchLabeledBlockCompletesNormally, NoArgument, @@ -11704,23 +11693,7 @@ public void switchExpressionLastStatementCompletesNormally(Statement stmt) { stmt.sourceEnd - 1, stmt.sourceEnd); } -public void switchExpressionIllegalLastStatement(Statement stmt) { - this.handle( - IProblem.SwitchExpressionsYieldIllegalLastStatement, - NoArgument, - NoArgument, - stmt.sourceStart, - stmt.sourceEnd); -} -public void switchExpressionTrailingSwitchLabels(Statement stmt) { - this.handle( - IProblem.SwitchExpressionsYieldTrailingSwitchLabels, - NoArgument, - NoArgument, - stmt.sourceStart, - stmt.sourceEnd); -} -public void switchExpressionMixedCase(ASTNode statement) { +public void arrowColonMixup(ASTNode statement) { this.handle( IProblem.SwitchPreviewMixedCase, NoArgument, @@ -11728,24 +11701,7 @@ public void switchExpressionMixedCase(ASTNode statement) { statement.sourceStart, statement.sourceEnd); } -// Is this redundant ?? See switchExpressionsBreakOutOfSwitchExpression -public void switchExpressionBreakNotAllowed(ASTNode statement) { - this.handle( - IProblem.SwitchExpressionsYieldBreakNotAllowed, - NoArgument, - NoArgument, - statement.sourceStart, - statement.sourceEnd); -} -public void switchExpressionsYieldUnqualifiedMethodWarning(ASTNode statement) { - this.handle( - IProblem.SwitchExpressionsYieldUnqualifiedMethodWarning, - NoArgument, - NoArgument, - statement.sourceStart, - statement.sourceEnd); -} -public void switchExpressionsYieldUnqualifiedMethodError(ASTNode statement) { +public void unqualifiedYieldMethod(ASTNode statement) { this.handle( IProblem.SwitchExpressionsYieldUnqualifiedMethodError, NoArgument, @@ -11753,7 +11709,7 @@ public void switchExpressionsYieldUnqualifiedMethodError(ASTNode statement) { statement.sourceStart, statement.sourceEnd); } -public void switchExpressionsYieldOutsideSwitchExpression(ASTNode statement) { +public void yieldOutsideSwitchExpression(ASTNode statement) { this.handle( IProblem.SwitchExpressionsYieldOutsideSwitchExpression, NoArgument, @@ -11761,38 +11717,6 @@ public void switchExpressionsYieldOutsideSwitchExpression(ASTNode statement) { statement.sourceStart, statement.sourceEnd); } -public void switchExpressionsYieldRestrictedGeneralWarning(ASTNode statement) { - this.handle( - IProblem.SwitchExpressionsYieldRestrictedGeneralWarning, - NoArgument, - NoArgument, - statement.sourceStart, - statement.sourceEnd); -} -public void switchExpressionsYieldIllegalStatement(ASTNode statement) { - this.handle( - IProblem.SwitchExpressionsYieldIllegalStatement, - NoArgument, - NoArgument, - statement.sourceStart, - statement.sourceEnd); -} -public void switchExpressionsYieldTypeDeclarationWarning(ASTNode statement) { - this.handle( - IProblem.SwitchExpressionsYieldTypeDeclarationWarning, - NoArgument, - NoArgument, - statement.sourceStart, - statement.sourceEnd); -} -public void switchExpressionsYieldTypeDeclarationError(ASTNode statement) { - this.handle( - IProblem.SwitchExpressionsYieldTypeDeclarationError, - NoArgument, - NoArgument, - statement.sourceStart, - statement.sourceEnd); -} public void multiConstantCaseLabelsNotSupported(ASTNode statement) { this.handle( IProblem.MultiConstantCaseLabelsNotSupported, @@ -11817,7 +11741,7 @@ public void switchExpressionsNotSupported(ASTNode statement) { statement.sourceStart, statement.sourceEnd); } -public void switchExpressionsBreakOutOfSwitchExpression(ASTNode statement) { +public void breakOutOfSwitchExpression(ASTNode statement) { this.handle( IProblem.SwitchExpressionsBreakOutOfSwitchExpression, NoArgument, @@ -11825,7 +11749,7 @@ public void switchExpressionsBreakOutOfSwitchExpression(ASTNode statement) { statement.sourceStart, statement.sourceEnd); } -public void switchExpressionsContinueOutOfSwitchExpression(ASTNode statement) { +public void continueOutOfSwitchExpression(ASTNode statement) { this.handle( IProblem.SwitchExpressionsContinueOutOfSwitchExpression, NoArgument, @@ -11833,7 +11757,7 @@ public void switchExpressionsContinueOutOfSwitchExpression(ASTNode statement) { statement.sourceStart, statement.sourceEnd); } -public void switchExpressionsReturnWithinSwitchExpression(ASTNode statement) { +public void returnOutOfSwitchExpression(ASTNode statement) { this.handle( IProblem.SwitchExpressionsReturnWithinSwitchExpression, NoArgument, diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/problem/messages.properties b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/problem/messages.properties index e1828361424..4eed8042326 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/problem/messages.properties +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/problem/messages.properties @@ -1033,27 +1033,29 @@ ###[obsolete] 1701 = A switch expression should have a non-empty switch block 1702 = A switch expression should have at least one result expression 1703 = A switch labeled block in a switch expression should not complete normally -1704 = The last statement of a switch block in a switch expression should not complete normally -1705 = Trailing switch labels are not allowed in a switch expression. -1706 = Mixing of different kinds of case statements '->' and ':' is not allowed within a switch +###[obsolete] 1704 = The last statement of a switch block in a switch expression should not complete normally +###[obsolete] 1705 = Trailing switch labels are not allowed in a switch expression. +1706 = Mixing of '->' and ':' case statement styles is not allowed within a switch 1707 = A switch expression should have a default case -1708 = yield of a switch expression should have a value +###[obsolete] 1708 = yield of a switch expression should have a value 1709 = A Switch expression should cover all possible values -1710 = 'continue' or 'return' cannot be the last statement in a Switch expression case body -1711 = break out of switch expression not allowed -1712 = yield may be disallowed in future - qualify method calls to avoid this message +###[obsolete] 1710 = 'continue' or 'return' cannot be the last statement in a Switch expression case body +###[obsolete] 1711 = break out of switch expression not allowed +###[obsolete] 1712 = yield may be disallowed in future - qualify method calls to avoid this message 1713 = restricted identifier yield not allowed here - method calls need to be qualified 1714 = yield outside of switch expression -1715 = yield is a restricted keyword and may be disallowed in future -1716 = yield statement is illegal here -1717 = yield may be a restricted identifier in future and may be disallowed as a type name -1718 = yield is a restricted identifier and cannot be used as type name +###[obsolete] 1715 = yield is a restricted keyword and may be disallowed in future +###[obsolete] 1716 = yield statement is illegal here +###[obsolete] 1717 = yield may be a restricted identifier in future and may be disallowed as a type name +###[obsolete] 1718 = yield is a restricted identifier and cannot be used as type name 1719 = Multi-constant case labels supported from Java 14 onwards only 1720 = Arrow in case statement supported from Java 14 onwards only 1721 = Switch Expressions are supported from Java 14 onwards only 1722 = Breaking out of switch expressions not permitted 1723 = Continue out of switch expressions not permitted 1724 = Return within switch expressions not permitted + + # Java 15 Preview - begin # Records 1730 = Illegal modifier for the record {0}; only public, private, protected, static, final and strictfp are permitted 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 94eebc7c376..a2f376fcb39 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 @@ -2145,11 +2145,6 @@ public void testBug544073_076() { " continue;\n" + " ^^^^^^^^^\n" + "Continue out of switch expressions not permitted\n" + - "----------\n" + - "2. ERROR in X.java (at line 11)\n" + - " continue;\n" + - " ^^^^^^^^^\n" + - "'continue' or 'return' cannot be the last statement in a Switch expression case body\n" + "----------\n"); } public void testBug544073_077() { @@ -2182,11 +2177,6 @@ public void testBug544073_077() { " return 2;\n" + " ^^^^^^^^^\n" + "Return within switch expressions not permitted\n" + - "----------\n" + - "2. ERROR in X.java (at line 11)\n" + - " return 2;\n" + - " ^^^^^^^^^\n" + - "'continue' or 'return' cannot be the last statement in a Switch expression case body\n" + "----------\n"); } public void testBug544073_078() { @@ -3338,6 +3328,11 @@ public void testBug552764_001() { " default -> 3;\n" + " ^^^^^^^\n" + "Arrow in case statement supported from Java 14 onwards only\n" + + "----------\n" + + "2. ERROR in X.java (at line 4)\n" + + " default -> 3;\n" + + " ^\n" + + "Invalid expression as statement\n" + "----------\n"; this.runNegativeTest( testFiles, @@ -8060,4 +8055,36 @@ static void foo(Class c, int v) { "class [LX;\n42"); } + // test mixing of -> and : in the same switch + public void testMixingCaseStyles() { + if (this.complianceLevel < ClassFileConstants.JDK14) + return; + this.runNegativeTest( + new String[] { + "X.java", + """ + public class X { + public static void main(String[] args) { + int i = switch(args.length) { + case 2: yield 2; + default -> 1; + case 1 : yield 2; + }; + } + } + """ + }, + "----------\n" + + "1. ERROR in X.java (at line 5)\n" + + " default -> 1;\n" + + " ^^^^^^^\n" + + "Mixing of '->' and ':' case statement styles is not allowed within a switch\n" + + "----------\n" + + "2. ERROR in X.java (at line 6)\n" + + " case 1 : yield 2;\n" + + " ^^^^^^\n" + + "Mixing of '->' and ':' case statement styles is not allowed within a switch\n" + + "----------\n"); + } + } diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTConverter.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTConverter.java index 3676a045096..f000a77a8c0 100644 --- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTConverter.java +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTConverter.java @@ -1459,10 +1459,10 @@ public SwitchCase convert(org.eclipse.jdt.internal.compiler.ast.CaseStatement st } } if (this.ast.apiLevel >= AST.JLS14_INTERNAL) { - switchCase.setSwitchLabeledRule(statement.isExpr); + switchCase.setSwitchLabeledRule(statement.isSwitchRule); } switchCase.setSourceRange(statement.sourceStart, statement.sourceEnd - statement.sourceStart + 1); - if (statement.isExpr) { + if (statement.isSwitchRule) { retrieveArrowPosition(switchCase); } else { retrieveColonPosition(switchCase);