Bug 573935 -[compiler][internal] use multi label case expressions data
structure always
Change-Id: I4fd57271461a7d63bd381dc876de19c80a662a3b
Signed-off-by: Manoj Palat <manpalat@in.ibm.com>
Reviewed-on: https://git.eclipse.org/r/c/jdt/eclipse.jdt.core/+/181340
Tested-by: JDT Bot <jdt-bot@eclipse.org>
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java
index 7bf577c..71adafe 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java
@@ -6462,10 +6462,12 @@
char[][] alreadyUsedConstants = new char[switchStatement.caseCount][];
int alreadyUsedConstantCount = 0;
for (int i = 0; i < switchStatement.caseCount; i++) {
- Expression caseExpression = cases[i].constantExpression;
+ Expression[] caseExpressions = cases[i].constantExpressions;
+ Expression caseExpression = caseExpressions != null && caseExpressions.length > 0 ?
+ caseExpressions[0] : null;
if((caseExpression instanceof SingleNameReference)
&& (caseExpression.resolvedType != null && caseExpression.resolvedType.isEnum())) {
- alreadyUsedConstants[alreadyUsedConstantCount++] = ((SingleNameReference)cases[i].constantExpression).token;
+ alreadyUsedConstants[alreadyUsedConstantCount++] = ((SingleNameReference)caseExpression).token;
}
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CaseStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CaseStatement.java
index 9853097..8c504b2 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CaseStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CaseStatement.java
@@ -33,14 +33,17 @@
public class CaseStatement extends Statement {
- public Expression constantExpression;
public BranchLabel targetLabel;
public Expression[] constantExpressions; // case with multiple expressions
public BranchLabel[] targetLabels; // for multiple expressions
public boolean isExpr = false;
public CaseStatement(Expression constantExpression, int sourceEnd, int sourceStart) {
- this.constantExpression = constantExpression;
+ this(sourceEnd, sourceStart, constantExpression != null ? new Expression[] {constantExpression} : null);
+}
+
+public CaseStatement(int sourceEnd, int sourceStart, Expression[] constantExpressions) {
+ this.constantExpressions = constantExpressions;
this.sourceEnd = sourceEnd;
this.sourceStart = sourceStart;
}
@@ -50,14 +53,10 @@
BlockScope currentScope,
FlowContext flowContext,
FlowInfo flowInfo) {
- if (this.constantExpressions != null && this.constantExpressions.length > 1) {
+ if (this.constantExpressions != null) {
for (Expression e : this.constantExpressions) {
analyseConstantExpression(currentScope, flowContext, flowInfo, e);
}
- } else {
- if (this.constantExpression != null) {
- analyseConstantExpression(currentScope, flowContext, flowInfo, this.constantExpression);
- }
}
return flowInfo;
}
@@ -76,18 +75,14 @@
@Override
public StringBuffer printStatement(int tab, StringBuffer output) {
printIndent(tab, output);
- if (this.constantExpression == null) {
+ if (this.constantExpressions == null) {
output.append("default "); //$NON-NLS-1$
output.append(this.isExpr ? "->" : ":"); //$NON-NLS-1$ //$NON-NLS-2$
} else {
output.append("case "); //$NON-NLS-1$
- if (this.constantExpressions != null && this.constantExpressions.length > 0) {
- for (int i = 0, l = this.constantExpressions.length; i < l; ++i) {
- this.constantExpressions[i].printExpression(0, output);
- if (i < l -1) output.append(',');
- }
- } else {
- this.constantExpression.printExpression(0, output);
+ 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$
}
@@ -130,8 +125,9 @@
public Constant[] resolveCase(BlockScope scope, TypeBinding switchExpressionType, SwitchStatement switchStatement) {
// switchExpressionType maybe null in error case
scope.enclosingCase = this; // record entering in a switch case block
-
- if (this.constantExpression == null) {
+ Expression[] constExprs = this.constantExpressions;
+ Expression constExpr = constExprs != null && constExprs.length > 0 ? constExprs[0] : null;
+ if (constExpr == null) {
// remember the default case into the associated switch statement
if (switchStatement.defaultCase != null)
scope.problemReporter().duplicateDefaultCase(this);
@@ -142,33 +138,30 @@
}
// add into the collection of cases of the associated switch statement
switchStatement.cases[switchStatement.caseCount++] = this;
- if (switchExpressionType != null && switchExpressionType.isEnum() && (this.constantExpression instanceof SingleNameReference)) {
- ((SingleNameReference) this.constantExpression).setActualReceiverType((ReferenceBinding)switchExpressionType);
+ if (switchExpressionType != null && switchExpressionType.isEnum() && (constExpr instanceof SingleNameReference)) {
+ ((SingleNameReference) constExpr).setActualReceiverType((ReferenceBinding)switchExpressionType);
}
- TypeBinding caseType = this.constantExpression.resolveType(scope);
+ TypeBinding caseType = constExpr.resolveType(scope);
if (caseType == null || switchExpressionType == null) return Constant.NotAConstantList;
// tag constant name with enum type for privileged access to its members
- if (this.constantExpressions != null && this.constantExpressions.length > 1) {
- List<Constant> cases = new ArrayList<>();
- for (Expression e : this.constantExpressions) {
- if (e != this.constantExpression) {
- if (switchExpressionType.isEnum() && (e instanceof SingleNameReference)) {
- ((SingleNameReference) e).setActualReceiverType((ReferenceBinding)switchExpressionType);
- }
- e.resolveType(scope);
+ List<Constant> cases = new ArrayList<>();
+ for (Expression e : constExprs) {
+ if (e != constExpr) {
+ if (switchExpressionType.isEnum() && (e instanceof SingleNameReference)) {
+ ((SingleNameReference) e).setActualReceiverType((ReferenceBinding)switchExpressionType);
}
- Constant con = resolveConstantExpression(scope, caseType, switchExpressionType, switchStatement, e);
- if (con != Constant.NotAConstant) {
- cases.add(con);
- }
+ e.resolveType(scope);
}
- if (cases.size() > 0) {
- return cases.toArray(new Constant[cases.size()]);
+ Constant con = resolveConstantExpression(scope, caseType, switchExpressionType, switchStatement, e);
+ if (con != Constant.NotAConstant) {
+ cases.add(con);
}
- } else {
- return new Constant[] { resolveConstantExpression(scope, caseType, switchExpressionType, switchStatement, this.constantExpression) };
}
+ if (cases.size() > 0) {
+ return cases.toArray(new Constant[cases.size()]);
+ }
+
return Constant.NotAConstantList;
}
public Constant resolveConstantExpression(BlockScope scope,
@@ -202,19 +195,17 @@
// constantExpression.computeConversion(scope, caseType, switchExpressionType); - do not report boxing/unboxing conversion
return expression.constant;
}
- scope.problemReporter().typeMismatchError(caseType, switchExpressionType, this.constantExpression, switchStatement.expression);
+ scope.problemReporter().typeMismatchError(caseType, switchExpressionType, expression, switchStatement.expression);
return Constant.NotAConstant;
}
@Override
public void traverse(ASTVisitor visitor, BlockScope blockScope) {
if (visitor.visit(this, blockScope)) {
- if (this.constantExpressions != null && this.constantExpressions.length > 1) {
+ if (this.constantExpressions != null) {
for (Expression e : this.constantExpressions) {
e.traverse(visitor, blockScope);
}
- } else {
- if (this.constantExpression != null) this.constantExpression.traverse(visitor, blockScope);
}
}
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 ad6f8bb..c5e181e 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
@@ -20,6 +20,7 @@
package org.eclipse.jdt.internal.compiler.ast;
import java.util.Arrays;
+import java.util.function.Function;
import org.eclipse.jdt.internal.compiler.ASTVisitor;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
@@ -281,28 +282,7 @@
*/
final boolean hasCases = this.caseCount != 0;
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;
- }
- }
+ BranchLabel[] sourceCaseLabels = this.<BranchLabel>gatherLabels(codeStream, new BranchLabel[this.nConstants], BranchLabel::new);
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.
@@ -421,8 +401,20 @@
if (this.scope != null) this.scope.enclosingCase = null; // no longer inside switch case block
}
}
-
-
+ private <T extends BranchLabel>T[] gatherLabels(CodeStream codeStream, T[] caseLabels,
+ Function<CodeStream, T> newLabel)
+ {
+ for (int i = 0, j = 0, max = this.caseCount; i < max; i++) {
+ CaseStatement stmt = this.cases[i];
+ int l = stmt.constantExpressions.length;
+ stmt.targetLabels = new BranchLabel[l];
+ for (int k = 0; k < l; ++k) {
+ stmt.targetLabels[k] = (caseLabels[j] = newLabel.apply(codeStream));
+ caseLabels[j++].tagBits |= BranchLabel.USED;
+ }
+ }
+ return caseLabels;
+ }
/**
* Switch code generation
*
@@ -444,30 +436,7 @@
// prepare the labels and constants
this.breakLabel.initialize(codeStream);
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[] caseLabels = this.<CaseLabel>gatherLabels(codeStream, new CaseLabel[this.nConstants], CaseLabel::new);
CaseLabel defaultLabel = new CaseLabel(codeStream);
final boolean hasCases = this.caseCount != 0;
@@ -637,12 +606,10 @@
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;
+ if (statement instanceof CaseStatement) {
+ Expression[] exprs = ((CaseStatement) statement).constantExpressions;
+ n += exprs != null ? exprs.length : 0;
}
- CaseStatement caseStmt = (CaseStatement) statement;
- n += caseStmt.constantExpressions != null ? caseStmt.constantExpressions.length :
- caseStmt.constantExpression != null ? 1 : 0;
}
return n;
}
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 cf2678f..fe178b1 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
@@ -2278,13 +2278,12 @@
} else {
// TODO : ERROR
}
- CaseStatement caseStatement = new CaseStatement(constantExpressions[0], constantExpressions[length - 1].sourceEnd, this.intStack[this.intPtr--]);
+ CaseStatement caseStatement = new CaseStatement(constantExpressions[length - 1].sourceEnd, this.intStack[this.intPtr--], constantExpressions);
if (constantExpressions.length > 1) {
if (!this.parsingJava14Plus) {
problemReporter().multiConstantCaseLabelsNotSupported(caseStatement);
}
}
- caseStatement.constantExpressions = constantExpressions;
// Look for $fall-through$ tag in leading comment for case statement
if (hasLeadingTagComment(FALL_THROUGH_TAG, caseStatement.sourceStart)) {
caseStatement.bits |= ASTNode.DocumentedFallthrough;
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 58f5cc8..4257291 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
@@ -1414,7 +1414,9 @@
}
}
} else {
- org.eclipse.jdt.internal.compiler.ast.Expression constantExpression = statement.constantExpression;
+ org.eclipse.jdt.internal.compiler.ast.Expression[] constantExpressions = statement.constantExpressions;
+ org.eclipse.jdt.internal.compiler.ast.Expression constantExpression =
+ constantExpressions != null && constantExpressions.length > 0 ? constantExpressions[0] : null;
if (constantExpression == null) {
internalSetExpression(switchCase, null);
} else {