Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java')
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java327
1 files changed, 268 insertions, 59 deletions
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 15dbd6bfda..a694b0a101 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
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2017 IBM Corporation and others.
+ * Copyright (c) 2000, 2019 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -43,7 +43,7 @@ import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
@SuppressWarnings("rawtypes")
-public class SwitchStatement extends Statement {
+public class SwitchStatement extends Expression {
public Expression expression;
public Statement[] statements;
@@ -55,12 +55,16 @@ public class SwitchStatement extends Statement {
public int blockStart;
public int caseCount;
int[] constants;
+ int[] constMapping;
String[] stringConstants;
+ public boolean switchLabeledRules = false; // true if case ->, false if case :
+ public int nConstants;
// fallthrough
public final static int CASE = 0;
public final static int FALLTHROUGH = 1;
public final static int ESCAPING = 2;
+ public final static int BREAKING = 3;
// for switch on strings
private static final char[] SecretStringVariableName = " switchDispatchString".toCharArray(); //$NON-NLS-1$
@@ -76,6 +80,38 @@ public class SwitchStatement extends Statement {
int duplicateCaseStatementsCounter = 0;
private LocalVariableBinding dispatchStringCopy = null;
+ protected int getFallThroughState(Statement stmt, BlockScope blockScope) {
+ if (this.switchLabeledRules) {
+ if ((stmt instanceof Expression && ((Expression) stmt).isTrulyExpression()) || stmt instanceof ThrowStatement)
+ return BREAKING;
+
+ if (stmt instanceof Block) {
+ Block block = (Block) stmt;
+ if (block.doesNotCompleteNormally()) {
+ return BREAKING;
+ }
+ // else add an implicit break
+ BreakStatement breakStatement = new BreakStatement(null, block.sourceEnd -1, block.sourceEnd);
+ breakStatement.isImplicit = true;
+
+ int l = block.statements == null ? 0 : block.statements.length;
+ if (l == 0) {
+ block.statements = new Statement[] {breakStatement};
+ block.scope = this.scope; // (upper scope) see Block.resolve() for similar
+ } else {
+ Statement[] newArray = new Statement[l + 1];
+ System.arraycopy(block.statements, 0, newArray, 0, l);
+ newArray[l] = breakStatement;
+ block.statements = newArray;
+ }
+ return BREAKING;
+ }
+ }
+ return FALLTHROUGH;
+ }
+ protected void completeNormallyCheck(BlockScope blockScope) {
+ // do nothing
+ }
@Override
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
try {
@@ -120,7 +156,7 @@ public class SwitchStatement extends Statement {
complaintLevel = initialComplaintLevel; // reset complaint
fallThroughState = CASE;
} else {
- fallThroughState = FALLTHROUGH; // reset below if needed
+ fallThroughState = getFallThroughState(statement, currentScope); // reset below if needed
}
if ((complaintLevel = statement.complainIfUnreachable(caseInits, this.scope, complaintLevel, true)) < Statement.COMPLAINED_UNREACHABLE) {
caseInits = statement.analyseCode(this.scope, switchContext, caseInits);
@@ -130,6 +166,7 @@ public class SwitchStatement extends Statement {
switchContext.expireNullCheckedFieldInfo();
}
}
+ completeNormallyCheck(currentScope);
}
final TypeBinding resolvedTypeBinding = this.expression.resolvedType;
@@ -199,33 +236,77 @@ public class SwitchStatement extends Statement {
"case " + this.hashCode + ":(" + this.string + ")\n"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
}
-
+ /*
+ * With multi constant case statements, the number of case statements (hence branch labels)
+ * and number of constants (hence hashcode labels) could be different. For e.g:
+
+ switch(s) {
+ case "FB", "c":
+ System.out.println("A/C");
+ break;
+ case "Ea":
+ System.out.println("B");
+ break;
+
+ With the above code, we will have
+ 2 branch labels for FB and c
+ 3 stringCases for FB, c and Ea
+ 2 hashCodeCaseLabels one for FB, Ea and one for c
+
+ Should produce something like this:
+ lookupswitch { // 2
+ 99: 32
+ 2236: 44
+ default: 87
+
+ "FB" and "Ea" producing the same hashcode values, but still belonging in different case statements.
+ First, produce the two branch labels pertaining to the case statements
+ And the three string cases and use the this.constMapping to get the correct branch label.
+ */
final boolean hasCases = this.caseCount != 0;
-
- StringSwitchCase [] stringCases = new StringSwitchCase[this.caseCount]; // may have to shrink later if multiple strings hash to same code.
- BranchLabel[] sourceCaseLabels = new BranchLabel[this.caseCount];
- CaseLabel [] hashCodeCaseLabels = new CaseLabel[this.caseCount];
- this.constants = new int[this.caseCount]; // hashCode() values.
- for (int i = 0, max = this.caseCount; i < max; i++) {
- this.cases[i].targetLabel = (sourceCaseLabels[i] = new BranchLabel(codeStream)); // A branch label, not a case label.
- sourceCaseLabels[i].tagBits |= BranchLabel.USED;
- stringCases[i] = new StringSwitchCase(this.stringConstants[i].hashCode(), this.stringConstants[i], sourceCaseLabels[i]);
+ int constSize = hasCases ? this.stringConstants.length : 0;
+ BranchLabel[] sourceCaseLabels;
+ if (currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK12) {
+ for (int i = 0, max = this.caseCount; i < max; i++) {
+ int l = this.cases[i].constantExpressions.length;
+ this.cases[i].targetLabels = new BranchLabel[l];
+ }
+ sourceCaseLabels = new BranchLabel[this.nConstants];
+ int j = 0;
+ for (int i = 0, max = this.caseCount; i < max; i++) {
+ CaseStatement stmt = this.cases[i];
+ for (int k = 0, l = stmt.constantExpressions.length; k < l; ++k) {
+ stmt.targetLabels[k] = (sourceCaseLabels[j] = new BranchLabel(codeStream));
+ sourceCaseLabels[j++].tagBits |= BranchLabel.USED;
+ }
+ }
+ } else {
+ sourceCaseLabels = new BranchLabel[this.caseCount];
+ for (int i = 0, max = this.caseCount; i < max; i++) {
+ this.cases[i].targetLabel = (sourceCaseLabels[i] = new BranchLabel(codeStream)); // A branch label, not a case label.
+ sourceCaseLabels[i].tagBits |= BranchLabel.USED;
+ }
+ }
+ StringSwitchCase [] stringCases = new StringSwitchCase[constSize]; // may have to shrink later if multiple strings hash to same code.
+ CaseLabel [] hashCodeCaseLabels = new CaseLabel[constSize];
+ this.constants = new int[constSize]; // hashCode() values.
+ for (int i = 0; i < constSize; i++) {
+ stringCases[i] = new StringSwitchCase(this.stringConstants[i].hashCode(), this.stringConstants[i], sourceCaseLabels[this.constMapping[i]]);
hashCodeCaseLabels[i] = new CaseLabel(codeStream);
hashCodeCaseLabels[i].tagBits |= BranchLabel.USED;
-
}
Arrays.sort(stringCases);
int uniqHashCount = 0;
int lastHashCode = 0;
- for (int i = 0, length = this.caseCount; i < length; ++i) {
+ for (int i = 0, length = constSize; i < length; ++i) {
int hashCode = stringCases[i].hashCode;
if (i == 0 || hashCode != lastHashCode) {
lastHashCode = this.constants[uniqHashCount++] = hashCode;
}
}
- if (uniqHashCount != this.caseCount) { // multiple keys hashed to the same value.
+ if (uniqHashCount != constSize) { // multiple keys hashed to the same value.
System.arraycopy(this.constants, 0, this.constants = new int[uniqHashCount], 0, uniqHashCount);
System.arraycopy(hashCodeCaseLabels, 0, hashCodeCaseLabels = new CaseLabel[uniqHashCount], 0, uniqHashCount);
}
@@ -252,7 +333,7 @@ public class SwitchStatement extends Statement {
codeStream.invokeStringHashCode();
if (hasCases) {
codeStream.lookupswitch(defaultCaseLabel, this.constants, sortedIndexes, hashCodeCaseLabels);
- for (int i = 0, j = 0, max = this.caseCount; i < max; i++) {
+ for (int i = 0, j = 0, max = constSize; i < max; i++) {
int hashCode = stringCases[i].hashCode;
if (i == 0 || hashCode != lastHashCode) {
lastHashCode = hashCode;
@@ -291,7 +372,7 @@ public class SwitchStatement extends Statement {
}
}
}
- statement.generateCode(this.scope, codeStream);
+ statementGenerateCode(currentScope, codeStream, statement);
}
}
@@ -312,6 +393,13 @@ public class SwitchStatement extends Statement {
defaultCaseLabel.place();
defaultBranchLabel.place();
}
+ if (this.expectedType() != null) {
+ TypeBinding expectedType = this.expectedType().erasure();
+ boolean optimizedGoto = codeStream.lastAbruptCompletion == -1;
+ // if the last bytecode was an optimized goto (value is already on the stack) or an enum switch without default case, then we need to adjust the
+ // stack depth to reflect the fact that there is an value on the stack (return type of the switch expression)
+ codeStream.recordExpressionType(expectedType, optimizedGoto ? 0 : 1, optimizedGoto);
+ }
codeStream.recordPositionsFrom(pc, this.sourceStart);
} finally {
if (this.scope != null) this.scope.enclosingCase = null; // no longer inside switch case block
@@ -339,11 +427,32 @@ public class SwitchStatement extends Statement {
// prepare the labels and constants
this.breakLabel.initialize(codeStream);
- CaseLabel[] caseLabels = new CaseLabel[this.caseCount];
- for (int i = 0, max = this.caseCount; i < max; i++) {
- this.cases[i].targetLabel = (caseLabels[i] = new CaseLabel(codeStream));
- caseLabels[i].tagBits |= BranchLabel.USED;
+ int constantCount = this.constants == null ? 0 : this.constants.length;
+ int nCaseLabels = 0;
+ CaseLabel[] caseLabels;
+ if (currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK12) {
+ for (int i = 0, max = this.caseCount; i < max; i++) {
+ int l = this.cases[i].constantExpressions.length;
+ nCaseLabels += l;
+ this.cases[i].targetLabels = new BranchLabel[l];
+ }
+ caseLabels = new CaseLabel[nCaseLabels];
+ int j = 0;
+ for (int i = 0, max = this.caseCount; i < max; i++) {
+ CaseStatement stmt = this.cases[i];
+ for (int k = 0, l = stmt.constantExpressions.length; k < l; ++k) {
+ stmt.targetLabels[k] = (caseLabels[j] = new CaseLabel(codeStream));
+ caseLabels[j++].tagBits |= BranchLabel.USED;
+ }
+ }
+ } else {
+ caseLabels = new CaseLabel[this.caseCount];
+ for (int i = 0, max = this.caseCount; i < max; i++) {
+ this.cases[i].targetLabel = (caseLabels[i] = new CaseLabel(codeStream));
+ caseLabels[i].tagBits |= BranchLabel.USED;
+ }
}
+
CaseLabel defaultLabel = new CaseLabel(codeStream);
final boolean hasCases = this.caseCount != 0;
if (hasCases) defaultLabel.tagBits |= BranchLabel.USED;
@@ -351,19 +460,20 @@ public class SwitchStatement extends Statement {
this.defaultCase.targetLabel = defaultLabel;
}
- final TypeBinding resolvedType = this.expression.resolvedType;
+ final TypeBinding resolvedType1 = this.expression.resolvedType;
boolean valueRequired = false;
- if (resolvedType.isEnum()) {
+ if (resolvedType1.isEnum()) {
// go through the translation table
codeStream.invoke(Opcodes.OPC_invokestatic, this.synthetic, null /* default declaringClass */);
this.expression.generateCode(currentScope, codeStream, true);
// get enum constant ordinal()
- codeStream.invokeEnumOrdinal(resolvedType.constantPoolName());
+ codeStream.invokeEnumOrdinal(resolvedType1.constantPoolName());
codeStream.iaload();
if (!hasCases) {
// we can get rid of the generated ordinal value
codeStream.pop();
}
+ valueRequired = hasCases;
} else {
valueRequired = this.expression.constant == Constant.NotAConstant || hasCases;
// generate expression
@@ -371,18 +481,18 @@ public class SwitchStatement extends Statement {
}
// generate the appropriate switch table/lookup bytecode
if (hasCases) {
- int[] sortedIndexes = new int[this.caseCount];
+ int[] sortedIndexes = new int[constantCount];
// we sort the keys to be able to generate the code for tableswitch or lookupswitch
- for (int i = 0; i < this.caseCount; i++) {
+ for (int i = 0; i < constantCount; i++) {
sortedIndexes[i] = i;
}
int[] localKeysCopy;
- System.arraycopy(this.constants, 0, (localKeysCopy = new int[this.caseCount]), 0, this.caseCount);
- CodeStream.sort(localKeysCopy, 0, this.caseCount - 1, sortedIndexes);
+ System.arraycopy(this.constants, 0, (localKeysCopy = new int[constantCount]), 0, constantCount);
+ CodeStream.sort(localKeysCopy, 0, constantCount - 1, sortedIndexes);
- int max = localKeysCopy[this.caseCount - 1];
+ int max = localKeysCopy[constantCount - 1];
int min = localKeysCopy[0];
- if ((long) (this.caseCount * 2.5) > ((long) max - (long) min)) {
+ if ((long) (constantCount * 2.5) > ((long) max - (long) min)) {
// work-around 1.3 VM bug, if max>0x7FFF0000, must use lookup bytecode
// see http://dev.eclipse.org/bugs/show_bug.cgi?id=21557
@@ -396,6 +506,7 @@ public class SwitchStatement extends Statement {
max,
this.constants,
sortedIndexes,
+ this.constMapping,
caseLabels);
}
} else {
@@ -411,7 +522,7 @@ public class SwitchStatement extends Statement {
if (this.statements != null) {
for (int i = 0, maxCases = this.statements.length; i < maxCases; i++) {
Statement statement = this.statements[i];
- if ((caseIndex < this.caseCount) && (statement == this.cases[caseIndex])) { // statements[i] is a case
+ if ((caseIndex < constantCount) && (statement == this.cases[caseIndex])) { // statements[i] is a case
this.scope.enclosingCase = this.cases[caseIndex]; // record entering in a switch case block
if (this.preSwitchInitStateIndex != -1) {
codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.preSwitchInitStateIndex);
@@ -425,8 +536,29 @@ public class SwitchStatement extends Statement {
}
}
}
- statement.generateCode(this.scope, codeStream);
+ statementGenerateCode(currentScope, codeStream, statement);
+ }
+ }
+ boolean enumInSwitchExpression = resolvedType1.isEnum() && this instanceof SwitchExpression;
+ boolean isEnumSwitchWithoutDefaultCase = this.defaultCase == null && enumInSwitchExpression;
+ if (isEnumSwitchWithoutDefaultCase) {
+ // we want to force an line number entry to get an end position after the switch statement
+ if (this.preSwitchInitStateIndex != -1) {
+ codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.preSwitchInitStateIndex);
}
+ defaultLabel.place();
+ /* a default case is not needed for enum if all enum values are used in the switch expression
+ * we need to handle the default case to throw an error (IncompatibleClassChangeError) in order
+ * to make the stack map consistent. All cases will return a value on the stack except the missing default
+ * case.
+ * There is no returned value for the default case so we handle it with an exception thrown. An
+ * IllegalClassChangeError seems legitimate as this would mean the enum type has been recompiled with more
+ * enum constants and the class that is using the switch on the enum has not been recompiled
+ */
+ codeStream.newJavaLangIncompatibleClassChangeError();
+ codeStream.dup();
+ codeStream.invokeJavaLangIncompatibleClassChangeErrorDefaultConstructor();
+ codeStream.athrow();
}
// May loose some local variable initializations : affecting the local variable attributes
if (this.mergedInitStateIndex != -1) {
@@ -438,18 +570,35 @@ public class SwitchStatement extends Statement {
}
// place the trailing labels (for break and default case)
this.breakLabel.place();
- if (this.defaultCase == null) {
+ if (this.defaultCase == null && !enumInSwitchExpression) {
// we want to force an line number entry to get an end position after the switch statement
codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd, true);
defaultLabel.place();
}
+ if (this instanceof SwitchExpression) {
+ TypeBinding switchResolveType = this.resolvedType;
+ if (this.expectedType() != null) {
+ switchResolveType = this.expectedType().erasure();
+ }
+ boolean optimizedGoto = codeStream.lastAbruptCompletion == -1;
+ // if the last bytecode was an optimized goto (value is already on the stack) or an enum switch without default case, then we need to adjust the
+ // stack depth to reflect the fact that there is an value on the stack (return type of the switch expression)
+ codeStream.recordExpressionType(switchResolveType, optimizedGoto ? 0 : 1, optimizedGoto || isEnumSwitchWithoutDefaultCase);
+ }
codeStream.recordPositionsFrom(pc, this.sourceStart);
} finally {
if (this.scope != null) this.scope.enclosingCase = null; // no longer inside switch case block
}
}
+ protected void statementGenerateCode(BlockScope currentScope, CodeStream codeStream, Statement statement) {
+ statement.generateCode(this.scope, codeStream);
+ }
@Override
+ public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
+ generateCode(currentScope, codeStream); // redirecting to statement part
+ }
+ @Override
public StringBuffer printStatement(int indent, StringBuffer output) {
printIndent(indent, output).append("switch ("); //$NON-NLS-1$
@@ -468,6 +617,19 @@ public class SwitchStatement extends Statement {
return printIndent(indent, output).append('}');
}
+ private int getNConstants() {
+ int n = 0;
+ for (int i = 0, l = this.statements.length; i < l; ++i) {
+ final Statement statement = this.statements[i];
+ if (!(statement instanceof CaseStatement)) {
+ continue;
+ }
+ CaseStatement caseStmt = (CaseStatement) statement;
+ n += caseStmt.constantExpressions != null ? caseStmt.constantExpressions.length :
+ caseStmt.constantExpression != null ? 1 : 0;
+ }
+ return n;
+ }
@Override
public void resolve(BlockScope upperScope) {
try {
@@ -517,34 +679,49 @@ public class SwitchStatement extends Statement {
int length;
// collection of cases is too big but we will only iterate until caseCount
this.cases = new CaseStatement[length = this.statements.length];
+ this.nConstants = getNConstants();
if (!isStringSwitch) {
- this.constants = new int[length];
+ this.constants = new int[this.nConstants];
+ this.constMapping = new int[this.nConstants];
} else {
- this.stringConstants = new String[length];
+ this.stringConstants = new String[this.nConstants];
+ this.constMapping = new int[this.nConstants];
}
int counter = 0;
for (int i = 0; i < length; i++) {
- Constant constant;
+ Constant[] constantsList;
final Statement statement = this.statements[i];
- if ((constant = statement.resolveCase(this.scope, expressionType, this)) != Constant.NotAConstant) {
- if (!isStringSwitch) {
- int key = constant.intValue();
- //----check for duplicate case statement------------
- for (int j = 0; j < counter; j++) {
- if (this.constants[j] == key) {
- reportDuplicateCase((CaseStatement) statement, this.cases[j], length);
+ if (!(statement instanceof CaseStatement)) {
+ statement.resolve(this.scope);
+ continue;
+ }
+ if ((constantsList = statement.resolveCase(this.scope, expressionType, this)) != Constant.NotAConstantList) {
+ for (Constant con : constantsList) {
+ if (con == Constant.NotAConstant)
+ continue;
+ if (!isStringSwitch) {
+ int key = con.intValue();
+ //----check for duplicate case statement------------
+ for (int j = 0; j < counter; j++) {
+ if (this.constants[j] == key) {
+ reportDuplicateCase((CaseStatement) statement, this.cases[j], length);
+ }
}
- }
- this.constants[counter++] = key;
- } else {
- String key = constant.stringValue();
- //----check for duplicate case statement------------
- for (int j = 0; j < counter; j++) {
- if (this.stringConstants[j].equals(key)) {
- reportDuplicateCase((CaseStatement) statement, this.cases[j], length);
+ this.constants[counter] = key;
+ this.constMapping[counter] = counter;
+ counter++;
+ } else {
+ String key = con.stringValue();
+ //----check for duplicate case statement------------
+ for (int j = 0; j < counter; j++) {
+ if (this.stringConstants[j].equals(key)) {
+ reportDuplicateCase((CaseStatement) statement, this.cases[j], length);
+ }
}
+ this.stringConstants[counter] = key;
+ this.constMapping[counter] = counter;
+ counter++;
}
- this.stringConstants[counter++] = key;
}
}
}
@@ -554,15 +731,17 @@ public class SwitchStatement extends Statement {
} else {
System.arraycopy(this.stringConstants, 0, this.stringConstants = new String[counter], 0, counter);
}
+ System.arraycopy(this.constMapping, 0, this.constMapping = new int[counter], 0, counter);
}
} else {
if ((this.bits & UndocumentedEmptyBlock) != 0) {
upperScope.problemReporter().undocumentedEmptyBlock(this.blockStart, this.sourceEnd);
}
}
+ 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;
}
@@ -574,21 +753,21 @@ public class SwitchStatement extends Statement {
if (isEnumSwitch && compilerOptions.complianceLevel >= ClassFileConstants.JDK1_5) {
if (this.defaultCase == null || compilerOptions.reportMissingEnumCaseDespiteDefault) {
int constantCount = this.constants == null ? 0 : this.constants.length; // could be null if no case statement
- if (constantCount == this.caseCount
- && this.caseCount != ((ReferenceBinding)expressionType).enumConstantCount()) {
+ if (constantCount >= this.caseCount
+ && constantCount != ((ReferenceBinding)expressionType).enumConstantCount()) {
FieldBinding[] enumFields = ((ReferenceBinding)expressionType.erasure()).fields();
for (int i = 0, max = enumFields.length; i <max; i++) {
FieldBinding enumConstant = enumFields[i];
if ((enumConstant.modifiers & ClassFileConstants.AccEnum) == 0) continue;
findConstant : {
- for (int j = 0; j < this.caseCount; j++) {
+ for (int j = 0; j < constantCount; j++) {
if ((enumConstant.id + 1) == this.constants[j]) // zero should not be returned see bug 141810
break findConstant;
}
// enum constant did not get referenced from switch
boolean suppress = (this.defaultCase != null && (this.defaultCase.bits & DocumentedCasesOmitted) != 0);
if (!suppress) {
- upperScope.problemReporter().missingEnumConstantCase(this, enumConstant);
+ reportMissingEnumConstantCase(upperScope, enumConstant);
}
}
}
@@ -599,7 +778,32 @@ public class SwitchStatement extends Statement {
if (this.scope != null) this.scope.enclosingCase = null; // no longer inside switch case block
}
}
-
+ protected void reportMissingEnumConstantCase(BlockScope upperScope, FieldBinding enumConstant) {
+ upperScope.problemReporter().missingEnumConstantCase(this, enumConstant);
+ }
+ protected boolean ignoreMissingDefaultCase(CompilerOptions compilerOptions, boolean isEnumSwitch) {
+ return compilerOptions.getSeverity(CompilerOptions.MissingDefaultCase) == ProblemSeverities.Ignore;
+ }
+ @Override
+ public boolean isTrulyExpression() {
+ return false;
+ }
+ private void reportMixingCaseTypes() {
+ if (this.caseCount == 0) {
+ this.switchLabeledRules = this.defaultCase != null ? this.defaultCase.isExpr : this.switchLabeledRules;
+ return;
+ }
+ 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().switchExpressionMixedCase(this.cases[i]);
+ return;
+ }
+ }
+ if (this.defaultCase != null && this.defaultCase.isExpr != isExpr) {
+ this.scope.problemReporter().switchExpressionMixedCase(this.defaultCase);
+ }
+ }
private void reportDuplicateCase(final CaseStatement duplicate, final CaseStatement original, int length) {
if (this.duplicateCaseStatements == null) {
this.scope.problemReporter().duplicateCase(original);
@@ -675,4 +879,9 @@ public class SwitchStatement extends Statement {
}
return false;
}
+
+ @Override
+ public StringBuffer printExpression(int indent, StringBuffer output) {
+ return printStatement(indent, output);
+ }
}

Back to the top