org.eclipse.jdt.internal.compiler.ast.CaseStatement Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ecj Show documentation
Show all versions of ecj Show documentation
Eclipse Compiler for Java(TM)
/*******************************************************************************
* 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
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.ast;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jdt.internal.compiler.ASTVisitor;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.codegen.BranchLabel;
import org.eclipse.jdt.internal.compiler.codegen.CodeStream;
import org.eclipse.jdt.internal.compiler.flow.FlowContext;
import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
import org.eclipse.jdt.internal.compiler.impl.Constant;
import org.eclipse.jdt.internal.compiler.impl.IntConstant;
//import org.eclipse.jdt.internal.compiler.impl.IntConstant;
import org.eclipse.jdt.internal.compiler.lookup.Binding;
import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
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 = sourceEnd;
this.sourceStart = sourceStart;
}
@Override
public FlowInfo analyseCode(
BlockScope currentScope,
FlowContext flowContext,
FlowInfo flowInfo) {
if (this.constantExpressions != null && this.constantExpressions.length > 1) {
for (Expression e : this.constantExpressions) {
analyseConstantExpression(currentScope, flowContext, flowInfo, e);
}
} else {
if (this.constantExpression != null) {
analyseConstantExpression(currentScope, flowContext, flowInfo, this.constantExpression);
}
}
return flowInfo;
}
private void analyseConstantExpression(
BlockScope currentScope,
FlowContext flowContext,
FlowInfo flowInfo,
Expression e) {
if (e.constant == Constant.NotAConstant
&& !e.resolvedType.isEnum()) {
currentScope.problemReporter().caseExpressionMustBeConstant(e);
}
e.analyseCode(currentScope, flowContext, flowInfo);
}
@Override
public StringBuffer printStatement(int tab, StringBuffer output) {
printIndent(tab, output);
if (this.constantExpression == 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);
}
output.append(this.isExpr ? " ->" : " :"); //$NON-NLS-1$ //$NON-NLS-2$
}
return output;
}
/**
* Case code generation
*
*/
@Override
public void generateCode(BlockScope currentScope, CodeStream codeStream) {
if ((this.bits & ASTNode.IsReachable) == 0) {
return;
}
int pc = codeStream.position;
if (this.targetLabels != null) {
for (int i = 0, l = this.targetLabels.length; i < l; ++i) {
this.targetLabels[i].place();
}
} else {
this.targetLabel.place();
}
codeStream.recordPositionsFrom(pc, this.sourceStart);
}
/**
* No-op : should use resolveCase(...) instead.
*/
@Override
public void resolve(BlockScope scope) {
// no-op : should use resolveCase(...) instead.
}
/**
* Returns the constant intValue or ordinal for enum constants. If constant is NotAConstant, then answers Float.MIN_VALUE
* see org.eclipse.jdt.internal.compiler.ast.Statement#resolveCase(org.eclipse.jdt.internal.compiler.lookup.BlockScope, org.eclipse.jdt.internal.compiler.lookup.TypeBinding, org.eclipse.jdt.internal.compiler.ast.SwitchStatement)
*/
@Override
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) {
// remember the default case into the associated switch statement
if (switchStatement.defaultCase != null)
scope.problemReporter().duplicateDefaultCase(this);
// on error the last default will be the selected one ...
switchStatement.defaultCase = this;
return Constant.NotAConstantList;
}
// 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);
}
TypeBinding caseType = this.constantExpression.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 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);
}
Constant con = resolveConstantExpression(scope, caseType, switchExpressionType, switchStatement, e);
if (con != Constant.NotAConstant) {
cases.add(con);
}
}
if (cases.size() > 0) {
return cases.toArray(new Constant[cases.size()]);
}
} else {
return new Constant[] { resolveConstantExpression(scope, caseType, switchExpressionType, switchStatement, this.constantExpression) };
}
return Constant.NotAConstantList;
}
public Constant resolveConstantExpression(BlockScope scope,
TypeBinding caseType,
TypeBinding switchExpressionType,
SwitchStatement switchStatement,
Expression expression) {
if (expression.isConstantValueOfTypeAssignableToType(caseType, switchExpressionType)
|| caseType.isCompatibleWith(switchExpressionType)) {
if (caseType.isEnum()) {
if (((expression.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT) != 0) {
scope.problemReporter().enumConstantsCannotBeSurroundedByParenthesis(expression);
}
if (expression instanceof NameReference
&& (expression.bits & ASTNode.RestrictiveFlagMASK) == Binding.FIELD) {
NameReference reference = (NameReference) expression;
FieldBinding field = reference.fieldBinding();
if ((field.modifiers & ClassFileConstants.AccEnum) == 0) {
scope.problemReporter().enumSwitchCannotTargetField(reference, field);
} else if (reference instanceof QualifiedNameReference) {
scope.problemReporter().cannotUseQualifiedEnumConstantInCaseLabel(reference, field);
}
return IntConstant.fromValue(field.original().id + 1); // (ordinal value + 1) zero should not be returned see bug 141810
}
} else {
return expression.constant;
}
} else if (isBoxingCompatible(caseType, switchExpressionType, expression, scope)) {
// constantExpression.computeConversion(scope, caseType, switchExpressionType); - do not report boxing/unboxing conversion
return expression.constant;
}
scope.problemReporter().typeMismatchError(caseType, switchExpressionType, this.constantExpression, 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) {
for (Expression e : this.constantExpressions) {
e.traverse(visitor, blockScope);
}
} else {
if (this.constantExpression != null) this.constantExpression.traverse(visitor, blockScope);
}
}
visitor.endVisit(this, blockScope);
}
}