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 {