package org.eclipse.jdt.internal.compiler.ast;
import org.eclipse.jdt.internal.compiler.ASTVisitor;
import org.eclipse.jdt.internal.compiler.impl.*;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.codegen.*;
import org.eclipse.jdt.internal.compiler.flow.*;
import org.eclipse.jdt.internal.compiler.lookup.*;
public class BinaryExpression extends OperatorExpression {
public Expression left, right;
public Constant optimizedBooleanConstant;
public BinaryExpression(Expression left, Expression right, int operator) {
this.left = left;
this.right = right;
this.bits |= operator << ASTNode.OperatorSHIFT;
this.sourceStart = left.sourceStart;
this.sourceEnd = right.sourceEnd;
}
public BinaryExpression(BinaryExpression expression) {
this.left = expression.left;
this.right = expression.right;
this.bits = expression.bits;
this.sourceStart = expression.sourceStart;
this.sourceEnd = expression.sourceEnd;
}
@Override
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
try {
if (this.resolvedType.id == TypeIds.T_JavaLangString) {
return this.right.analyseCode(
currentScope, flowContext,
this.left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits())
.unconditionalInits();
} else {
flowInfo = this.left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits();
this.left.checkNPE(currentScope, flowContext, flowInfo);
if (((this.bits & OperatorMASK) >> OperatorSHIFT) != AND) {
flowContext.expireNullCheckedFieldInfo();
}
flowInfo = this.right.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits();
this.right.checkNPE(currentScope, flowContext, flowInfo);
if (((this.bits & OperatorMASK) >> OperatorSHIFT) != AND) {
flowContext.expireNullCheckedFieldInfo();
}
return flowInfo;
}
} finally {
flowContext.recordAbruptExit();
}
}
public void computeConstant(BlockScope scope, int leftId, int rightId) {
if ((this.left.constant != Constant.NotAConstant)
&& (this.right.constant != Constant.NotAConstant)) {
try {
this.constant =
Constant.computeConstantOperation(
this.left.constant,
leftId,
(this.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT,
this.right.constant,
rightId);
} catch (ArithmeticException e) {
this.constant = Constant.NotAConstant;
}
} else {
this.constant = Constant.NotAConstant;
this.optimizedBooleanConstant(
leftId,
(this.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT,
rightId);
}
}
@Override
public Constant optimizedBooleanConstant() {
return this.optimizedBooleanConstant == null ? this.constant : this.optimizedBooleanConstant;
}
@Override
public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
int pc = codeStream.position;
if (this.constant != Constant.NotAConstant) {
if (valueRequired)
codeStream.generateConstant(this.constant, this.implicitConversion);
codeStream.recordPositionsFrom(pc, this.sourceStart);
return;
}
switch ((this.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT) {
case PLUS :
switch (this.bits & ASTNode.ReturnTypeIDMASK) {
case T_JavaLangString :
codeStream.generateStringConcatenationAppend(currentScope, this.left, this.right);
if (!valueRequired)
codeStream.pop();
break;
case T_int :
this.left.generateCode(currentScope, codeStream, valueRequired);
this.right.generateCode(currentScope, codeStream, valueRequired);
if (valueRequired)
codeStream.iadd();
break;
case T_long :
this.left.generateCode(currentScope, codeStream, valueRequired);
this.right.generateCode(currentScope, codeStream, valueRequired);
if (valueRequired)
codeStream.ladd();
break;
case T_double :
this.left.generateCode(currentScope, codeStream, valueRequired);
this.right.generateCode(currentScope, codeStream, valueRequired);
if (valueRequired)
codeStream.dadd();
break;
case T_float :
this.left.generateCode(currentScope, codeStream, valueRequired);
this.right.generateCode(currentScope, codeStream, valueRequired);
if (valueRequired)
codeStream.fadd();
break;
}
break;
case MINUS :
switch (this.bits & ASTNode.ReturnTypeIDMASK) {
case T_int :
this.left.generateCode(currentScope, codeStream, valueRequired);
this.right.generateCode(currentScope, codeStream, valueRequired);
if (valueRequired)
codeStream.isub();
break;
case T_long :
this.left.generateCode(currentScope, codeStream, valueRequired);
this.right.generateCode(currentScope, codeStream, valueRequired);
if (valueRequired)
codeStream.lsub();
break;
case T_double :
this.left.generateCode(currentScope, codeStream, valueRequired);
this.right.generateCode(currentScope, codeStream, valueRequired);
if (valueRequired)
codeStream.dsub();
break;
case T_float :
this.left.generateCode(currentScope, codeStream, valueRequired);
this.right.generateCode(currentScope, codeStream, valueRequired);
if (valueRequired)
codeStream.fsub();
break;
}
break;
case MULTIPLY :
switch (this.bits & ASTNode.ReturnTypeIDMASK) {
case T_int :
this.left.generateCode(currentScope, codeStream, valueRequired);
this.right.generateCode(currentScope, codeStream, valueRequired);
if (valueRequired)
codeStream.imul();
break;
case T_long :
this.left.generateCode(currentScope, codeStream, valueRequired);
this.right.generateCode(currentScope, codeStream, valueRequired);
if (valueRequired)
codeStream.lmul();
break;
case T_double :
this.left.generateCode(currentScope, codeStream, valueRequired);
this.right.generateCode(currentScope, codeStream, valueRequired);
if (valueRequired)
codeStream.dmul();
break;
case T_float :
this.left.generateCode(currentScope, codeStream, valueRequired);
this.right.generateCode(currentScope, codeStream, valueRequired);
if (valueRequired)
codeStream.fmul();
break;
}
break;
case DIVIDE :
switch (this.bits & ASTNode.ReturnTypeIDMASK) {
case T_int :
this.left.generateCode(currentScope, codeStream, true);
this.right.generateCode(currentScope, codeStream, true);
codeStream.idiv();
if (!valueRequired)
codeStream.pop();
break;
case T_long :
this.left.generateCode(currentScope, codeStream, true);
this.right.generateCode(currentScope, codeStream, true);
codeStream.ldiv();
if (!valueRequired)
codeStream.pop2();
break;
case T_double :
this.left.generateCode(currentScope, codeStream, valueRequired);
this.right.generateCode(currentScope, codeStream, valueRequired);
if (valueRequired)
codeStream.ddiv();
break;
case T_float :
this.left.generateCode(currentScope, codeStream, valueRequired);
this.right.generateCode(currentScope, codeStream, valueRequired);
if (valueRequired)
codeStream.fdiv();
break;
}
break;
case REMAINDER :
switch (this.bits & ASTNode.ReturnTypeIDMASK) {
case T_int :
this.left.generateCode(currentScope, codeStream, true);
this.right.generateCode(currentScope, codeStream, true);
codeStream.irem();
if (!valueRequired)
codeStream.pop();
break;
case T_long :
this.left.generateCode(currentScope, codeStream, true);
this.right.generateCode(currentScope, codeStream, true);
codeStream.lrem();
if (!valueRequired)
codeStream.pop2();
break;
case T_double :
this.left.generateCode(currentScope, codeStream, valueRequired);
this.right.generateCode(currentScope, codeStream, valueRequired);
if (valueRequired)
codeStream.drem();
break;
case T_float :
this.left.generateCode(currentScope, codeStream, valueRequired);
this.right.generateCode(currentScope, codeStream, valueRequired);
if (valueRequired)
codeStream.frem();
break;
}
break;
case AND :
switch (this.bits & ASTNode.ReturnTypeIDMASK) {
case T_int :
if ((this.left.constant != Constant.NotAConstant)
&& (this.left.constant.typeID() == TypeIds.T_int)
&& (this.left.constant.intValue() == 0)) {
this.right.generateCode(currentScope, codeStream, false);
if (valueRequired)
codeStream.iconst_0();
} else {
if ((this.right.constant != Constant.NotAConstant)
&& (this.right.constant.typeID() == TypeIds.T_int)
&& (this.right.constant.intValue() == 0)) {
this.left.generateCode(currentScope, codeStream, false);
if (valueRequired)
codeStream.iconst_0();
} else {
this.left.generateCode(currentScope, codeStream, valueRequired);
this.right.generateCode(currentScope, codeStream, valueRequired);
if (valueRequired)
codeStream.iand();
}
}
break;
case T_long :
if ((this.left.constant != Constant.NotAConstant)
&& (this.left.constant.typeID() == TypeIds.T_long)
&& (this.left.constant.longValue() == 0L)) {
this.right.generateCode(currentScope, codeStream, false);
if (valueRequired)
codeStream.lconst_0();
} else {
if ((this.right.constant != Constant.NotAConstant)
&& (this.right.constant.typeID() == TypeIds.T_long)
&& (this.right.constant.longValue() == 0L)) {
this.left.generateCode(currentScope, codeStream, false);
if (valueRequired)
codeStream.lconst_0();
} else {
this.left.generateCode(currentScope, codeStream, valueRequired);
this.right.generateCode(currentScope, codeStream, valueRequired);
if (valueRequired)
codeStream.land();
}
}
break;
case T_boolean :
generateLogicalAnd(currentScope, codeStream, valueRequired);
break;
}
break;
case OR :
switch (this.bits & ASTNode.ReturnTypeIDMASK) {
case T_int :
if ((this.left.constant != Constant.NotAConstant)
&& (this.left.constant.typeID() == TypeIds.T_int)
&& (this.left.constant.intValue() == 0)) {
this.right.generateCode(currentScope, codeStream, valueRequired);
} else {
if ((this.right.constant != Constant.NotAConstant)
&& (this.right.constant.typeID() == TypeIds.T_int)
&& (this.right.constant.intValue() == 0)) {
this.left.generateCode(currentScope, codeStream, valueRequired);
} else {
this.left.generateCode(currentScope, codeStream, valueRequired);
this.right.generateCode(currentScope, codeStream, valueRequired);
if (valueRequired)
codeStream.ior();
}
}
break;
case T_long :
if ((this.left.constant != Constant.NotAConstant)
&& (this.left.constant.typeID() == TypeIds.T_long)
&& (this.left.constant.longValue() == 0L)) {
this.right.generateCode(currentScope, codeStream, valueRequired);
} else {
if ((this.right.constant != Constant.NotAConstant)
&& (this.right.constant.typeID() == TypeIds.T_long)
&& (this.right.constant.longValue() == 0L)) {
this.left.generateCode(currentScope, codeStream, valueRequired);
} else {
this.left.generateCode(currentScope, codeStream, valueRequired);
this.right.generateCode(currentScope, codeStream, valueRequired);
if (valueRequired)
codeStream.lor();
}
}
break;
case T_boolean :
generateLogicalOr(currentScope, codeStream, valueRequired);
break;
}
break;
case XOR :
switch (this.bits & ASTNode.ReturnTypeIDMASK) {
case T_int :
if ((this.left.constant != Constant.NotAConstant)
&& (this.left.constant.typeID() == TypeIds.T_int)
&& (this.left.constant.intValue() == 0)) {
this.right.generateCode(currentScope, codeStream, valueRequired);
} else {
if ((this.right.constant != Constant.NotAConstant)
&& (this.right.constant.typeID() == TypeIds.T_int)
&& (this.right.constant.intValue() == 0)) {
this.left.generateCode(currentScope, codeStream, valueRequired);
} else {
this.left.generateCode(currentScope, codeStream, valueRequired);
this.right.generateCode(currentScope, codeStream, valueRequired);
if (valueRequired)
codeStream.ixor();
}
}
break;
case T_long :
if ((this.left.constant != Constant.NotAConstant)
&& (this.left.constant.typeID() == TypeIds.T_long)
&& (this.left.constant.longValue() == 0L)) {
this.right.generateCode(currentScope, codeStream, valueRequired);
} else {
if ((this.right.constant != Constant.NotAConstant)
&& (this.right.constant.typeID() == TypeIds.T_long)
&& (this.right.constant.longValue() == 0L)) {
this.left.generateCode(currentScope, codeStream, valueRequired);
} else {
this.left.generateCode(currentScope, codeStream, valueRequired);
this.right.generateCode(currentScope, codeStream, valueRequired);
if (valueRequired)
codeStream.lxor();
}
}
break;
case T_boolean :
generateLogicalXor(currentScope, codeStream, valueRequired);
break;
}
break;
case LEFT_SHIFT :
switch (this.bits & ASTNode.ReturnTypeIDMASK) {
case T_int :
this.left.generateCode(currentScope, codeStream, valueRequired);
this.right.generateCode(currentScope, codeStream, valueRequired);
if (valueRequired)
codeStream.ishl();
break;
case T_long :
this.left.generateCode(currentScope, codeStream, valueRequired);
this.right.generateCode(currentScope, codeStream, valueRequired);
if (valueRequired)
codeStream.lshl();
}
break;
case RIGHT_SHIFT :
switch (this.bits & ASTNode.ReturnTypeIDMASK) {
case T_int :
this.left.generateCode(currentScope, codeStream, valueRequired);
this.right.generateCode(currentScope, codeStream, valueRequired);
if (valueRequired)
codeStream.ishr();
break;
case T_long :
this.left.generateCode(currentScope, codeStream, valueRequired);
this.right.generateCode(currentScope, codeStream, valueRequired);
if (valueRequired)
codeStream.lshr();
}
break;
case UNSIGNED_RIGHT_SHIFT :
switch (this.bits & ASTNode.ReturnTypeIDMASK) {
case T_int :
this.left.generateCode(currentScope, codeStream, valueRequired);
this.right.generateCode(currentScope, codeStream, valueRequired);
if (valueRequired)
codeStream.iushr();
break;
case T_long :
this.left.generateCode(currentScope, codeStream, valueRequired);
this.right.generateCode(currentScope, codeStream, valueRequired);
if (valueRequired)
codeStream.lushr();
}
break;
case GREATER :
BranchLabel falseLabel, endLabel;
generateOptimizedGreaterThan(
currentScope,
codeStream,
null,
(falseLabel = new BranchLabel(codeStream)),
valueRequired);
if (valueRequired) {
codeStream.iconst_1();
if ((this.bits & ASTNode.IsReturnedValue) != 0) {
codeStream.generateImplicitConversion(this.implicitConversion);
codeStream.generateReturnBytecode(this);
falseLabel.place();
codeStream.iconst_0();
} else {
codeStream.goto_(endLabel = new BranchLabel(codeStream));
codeStream.decrStackSize(1);
falseLabel.place();
codeStream.iconst_0();
endLabel.place();
}
}
break;
case GREATER_EQUAL :
generateOptimizedGreaterThanOrEqual(
currentScope,
codeStream,
null,
(falseLabel = new BranchLabel(codeStream)),
valueRequired);
if (valueRequired) {
codeStream.iconst_1();
if ((this.bits & ASTNode.IsReturnedValue) != 0) {
codeStream.generateImplicitConversion(this.implicitConversion);
codeStream.generateReturnBytecode(this);
falseLabel.place();
codeStream.iconst_0();
} else {
codeStream.goto_(endLabel = new BranchLabel(codeStream));
codeStream.decrStackSize(1);
falseLabel.place();
codeStream.iconst_0();
endLabel.place();
}
}
break;
case LESS :
generateOptimizedLessThan(
currentScope,
codeStream,
null,
(falseLabel = new BranchLabel(codeStream)),
valueRequired);
if (valueRequired) {
codeStream.iconst_1();
if ((this.bits & ASTNode.IsReturnedValue) != 0) {
codeStream.generateImplicitConversion(this.implicitConversion);
codeStream.generateReturnBytecode(this);
falseLabel.place();
codeStream.iconst_0();
} else {
codeStream.goto_(endLabel = new BranchLabel(codeStream));
codeStream.decrStackSize(1);
falseLabel.place();
codeStream.iconst_0();
endLabel.place();
}
}
break;
case LESS_EQUAL :
generateOptimizedLessThanOrEqual(
currentScope,
codeStream,
null,
(falseLabel = new BranchLabel(codeStream)),
valueRequired);
if (valueRequired) {
codeStream.iconst_1();
if ((this.bits & ASTNode.IsReturnedValue) != 0) {
codeStream.generateImplicitConversion(this.implicitConversion);
codeStream.generateReturnBytecode(this);
falseLabel.place();
codeStream.iconst_0();
} else {
codeStream.goto_(endLabel = new BranchLabel(codeStream));
codeStream.decrStackSize(1);
falseLabel.place();
codeStream.iconst_0();
endLabel.place();
}
}
}
if (valueRequired) {
codeStream.generateImplicitConversion(this.implicitConversion);
}
codeStream.recordPositionsFrom(pc, this.sourceStart);
}
@Override
public void generateOptimizedBoolean(BlockScope currentScope, CodeStream codeStream, BranchLabel trueLabel, BranchLabel falseLabel, boolean valueRequired) {
if ((this.constant != Constant.NotAConstant) && (this.constant.typeID() == TypeIds.T_boolean)) {
super.generateOptimizedBoolean(
currentScope,
codeStream,
trueLabel,
falseLabel,
valueRequired);
return;
}
switch ((this.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT) {
case LESS :
generateOptimizedLessThan(
currentScope,
codeStream,
trueLabel,
falseLabel,
valueRequired);
return;
case LESS_EQUAL :
generateOptimizedLessThanOrEqual(
currentScope,
codeStream,
trueLabel,
falseLabel,
valueRequired);
return;
case GREATER :
generateOptimizedGreaterThan(
currentScope,
codeStream,
trueLabel,
falseLabel,
valueRequired);
return;
case GREATER_EQUAL :
generateOptimizedGreaterThanOrEqual(
currentScope,
codeStream,
trueLabel,
falseLabel,
valueRequired);
return;
case AND :
generateOptimizedLogicalAnd(
currentScope,
codeStream,
trueLabel,
falseLabel,
valueRequired);
return;
case OR :
generateOptimizedLogicalOr(
currentScope,
codeStream,
trueLabel,
falseLabel,
valueRequired);
return;
case XOR :
generateOptimizedLogicalXor(
currentScope,
codeStream,
trueLabel,
falseLabel,
valueRequired);
return;
}
super.generateOptimizedBoolean(
currentScope,
codeStream,
trueLabel,
falseLabel,
valueRequired);
}
public void generateOptimizedGreaterThan(BlockScope currentScope, CodeStream codeStream, BranchLabel trueLabel, BranchLabel falseLabel, boolean valueRequired) {
int promotedTypeID = (this.left.implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4;
if (promotedTypeID == TypeIds.T_int) {
if ((this.left.constant != Constant.NotAConstant) && (this.left.constant.intValue() == 0)) {
this.right.generateCode(currentScope, codeStream, valueRequired);
if (valueRequired) {
if (falseLabel == null) {
if (trueLabel != null) {
codeStream.iflt(trueLabel);
}
} else {
if (trueLabel == null) {
codeStream.ifge(falseLabel);
} else {
}
}
}
codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd);
return;
}
if ((this.right.constant != Constant.NotAConstant) && (this.right.constant.intValue() == 0)) {
this.left.generateCode(currentScope, codeStream, valueRequired);
if (valueRequired) {
if (falseLabel == null) {
if (trueLabel != null) {
codeStream.ifgt(trueLabel);
}
} else {
if (trueLabel == null) {
codeStream.ifle(falseLabel);
} else {
}
}
}
codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd);
return;
}
}
this.left.generateCode(currentScope, codeStream, valueRequired);
this.right.generateCode(currentScope, codeStream, valueRequired);
if (valueRequired) {
if (falseLabel == null) {
if (trueLabel != null) {
switch (promotedTypeID) {
case T_int :
codeStream.if_icmpgt(trueLabel);
break;
case T_float :
codeStream.fcmpl();
codeStream.ifgt(trueLabel);
break;
case T_long :
codeStream.lcmp();
codeStream.ifgt(trueLabel);
break;
case T_double :
codeStream.dcmpl();
codeStream.ifgt(trueLabel);
}
codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd);
return;
}
} else {
if (trueLabel == null) {
switch (promotedTypeID) {
case T_int :
codeStream.if_icmple(falseLabel);
break;
case T_float :
codeStream.fcmpl();
codeStream.ifle(falseLabel);
break;
case T_long :
codeStream.lcmp();
codeStream.ifle(falseLabel);
break;
case T_double :
codeStream.dcmpl();
codeStream.ifle(falseLabel);
}
codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd);
return;
} else {
}
}
}
}
public void generateOptimizedGreaterThanOrEqual(BlockScope currentScope, CodeStream codeStream, BranchLabel trueLabel, BranchLabel falseLabel, boolean valueRequired) {
int promotedTypeID = (this.left.implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4;
if (promotedTypeID == TypeIds.T_int) {
if ((this.left.constant != Constant.NotAConstant) && (this.left.constant.intValue() == 0)) {
this.right.generateCode(currentScope, codeStream, valueRequired);
if (valueRequired) {
if (falseLabel == null) {
if (trueLabel != null) {
codeStream.ifle(trueLabel);
}
} else {
if (trueLabel == null) {
codeStream.ifgt(falseLabel);
} else {
}
}
}
codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd);
return;
}
if ((this.right.constant != Constant.NotAConstant) && (this.right.constant.intValue() == 0)) {
this.left.generateCode(currentScope, codeStream, valueRequired);
if (valueRequired) {
if (falseLabel == null) {
if (trueLabel != null) {
codeStream.ifge(trueLabel);
}
} else {
if (trueLabel == null) {
codeStream.iflt(falseLabel);
} else {
}
}
}
codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd);
return;
}
}
this.left.generateCode(currentScope, codeStream, valueRequired);
this.right.generateCode(currentScope, codeStream, valueRequired);
if (valueRequired) {
if (falseLabel == null) {
if (trueLabel != null) {
switch (promotedTypeID) {
case T_int :
codeStream.if_icmpge(trueLabel);
break;
case T_float :
codeStream.fcmpl();
codeStream.ifge(trueLabel);
break;
case T_long :
codeStream.lcmp();
codeStream.ifge(trueLabel);
break;
case T_double :
codeStream.dcmpl();
codeStream.ifge(trueLabel);
}
codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd);
return;
}
} else {
if (trueLabel == null) {
switch (promotedTypeID) {
case T_int :
codeStream.if_icmplt(falseLabel);
break;
case T_float :
codeStream.fcmpl();
codeStream.iflt(falseLabel);
break;
case T_long :
codeStream.lcmp();
codeStream.iflt(falseLabel);
break;
case T_double :
codeStream.dcmpl();
codeStream.iflt(falseLabel);
}
codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd);
return;
} else {
}
}
}
}
public void generateOptimizedLessThan(BlockScope currentScope, CodeStream codeStream, BranchLabel trueLabel, BranchLabel falseLabel, boolean valueRequired) {
int promotedTypeID = (this.left.implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4;
if (promotedTypeID == TypeIds.T_int) {
if ((this.left.constant != Constant.NotAConstant) && (this.left.constant.intValue() == 0)) {
this.right.generateCode(currentScope, codeStream, valueRequired);
if (valueRequired) {
if (falseLabel == null) {
if (trueLabel != null) {
codeStream.ifgt(trueLabel);
}
} else {
if (trueLabel == null) {
codeStream.ifle(falseLabel);
} else {
}
}
}
codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd);
return;
}
if ((this.right.constant != Constant.NotAConstant) && (this.right.constant.intValue() == 0)) {
this.left.generateCode(currentScope, codeStream, valueRequired);
if (valueRequired) {
if (falseLabel == null) {
if (trueLabel != null) {
codeStream.iflt(trueLabel);
}
} else {
if (trueLabel == null) {
codeStream.ifge(falseLabel);
} else {
}
}
}
codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd);
return;
}
}
this.left.generateCode(currentScope, codeStream, valueRequired);
this.right.generateCode(currentScope, codeStream, valueRequired);
if (valueRequired) {
if (falseLabel == null) {
if (trueLabel != null) {
switch (promotedTypeID) {
case T_int :
codeStream.if_icmplt(trueLabel);
break;
case T_float :
codeStream.fcmpg();
codeStream.iflt(trueLabel);
break;
case T_long :
codeStream.lcmp();
codeStream.iflt(trueLabel);
break;
case T_double :
codeStream.dcmpg();
codeStream.iflt(trueLabel);
}
codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd);
return;
}
} else {
if (trueLabel == null) {
switch (promotedTypeID) {
case T_int :
codeStream.if_icmpge(falseLabel);
break;
case T_float :
codeStream.fcmpg();
codeStream.ifge(falseLabel);
break;
case T_long :
codeStream.lcmp();
codeStream.ifge(falseLabel);
break;
case T_double :
codeStream.dcmpg();
codeStream.ifge(falseLabel);
}
codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd);
return;
} else {
}
}
}
}
public void generateOptimizedLessThanOrEqual(BlockScope currentScope, CodeStream codeStream, BranchLabel trueLabel, BranchLabel falseLabel, boolean valueRequired) {
int promotedTypeID = (this.left.implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4;
if (promotedTypeID == TypeIds.T_int) {
if ((this.left.constant != Constant.NotAConstant) && (this.left.constant.intValue() == 0)) {
this.right.generateCode(currentScope, codeStream, valueRequired);
if (valueRequired) {
if (falseLabel == null) {
if (trueLabel != null) {
codeStream.ifge(trueLabel);
}
} else {
if (trueLabel == null) {
codeStream.iflt(falseLabel);
} else {
}
}
}
codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd);
return;
}
if ((this.right.constant != Constant.NotAConstant) && (this.right.constant.intValue() == 0)) {
this.left.generateCode(currentScope, codeStream, valueRequired);
if (valueRequired) {
if (falseLabel == null) {
if (trueLabel != null) {
codeStream.ifle(trueLabel);
}
} else {
if (trueLabel == null) {
codeStream.ifgt(falseLabel);
} else {
}
}
}
codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd);
return;
}
}
this.left.generateCode(currentScope, codeStream, valueRequired);
this.right.generateCode(currentScope, codeStream, valueRequired);
if (valueRequired) {
if (falseLabel == null) {
if (trueLabel != null) {
switch (promotedTypeID) {
case T_int :
codeStream.if_icmple(trueLabel);
break;
case T_float :
codeStream.fcmpg();
codeStream.ifle(trueLabel);
break;
case T_long :
codeStream.lcmp();
codeStream.ifle(trueLabel);
break;
case T_double :
codeStream.dcmpg();
codeStream.ifle(trueLabel);
}
codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd);
return;
}
} else {
if (trueLabel == null) {
switch (promotedTypeID) {
case T_int :
codeStream.if_icmpgt(falseLabel);
break;
case T_float :
codeStream.fcmpg();
codeStream.ifgt(falseLabel);
break;
case T_long :
codeStream.lcmp();
codeStream.ifgt(falseLabel);
break;
case T_double :
codeStream.dcmpg();
codeStream.ifgt(falseLabel);
}
codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd);
return;
} else {
}
}
}
}
public void generateLogicalAnd(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
Constant condConst;
if ((this.left.implicitConversion & TypeIds.COMPILE_TYPE_MASK) == TypeIds.T_boolean) {
if ((condConst = this.left.optimizedBooleanConstant()) != Constant.NotAConstant) {
if (condConst.booleanValue() == true) {
this.left.generateCode(currentScope, codeStream, false);
this.right.generateCode(currentScope, codeStream, valueRequired);
} else {
this.left.generateCode(currentScope, codeStream, false);
this.right.generateCode(currentScope, codeStream, false);
if (valueRequired) {
codeStream.iconst_0();
}
codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd);
}
return;
}
if ((condConst = this.right.optimizedBooleanConstant()) != Constant.NotAConstant) {
if (condConst.booleanValue() == true) {
this.left.generateCode(currentScope, codeStream, valueRequired);
this.right.generateCode(currentScope, codeStream, false);
} else {
this.left.generateCode(currentScope, codeStream, false);
this.right.generateCode(currentScope, codeStream, false);
if (valueRequired) {
codeStream.iconst_0();
}
codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd);
}
return;
}
}
this.left.generateCode(currentScope, codeStream, valueRequired);
this.right.generateCode(currentScope, codeStream, valueRequired);
if (valueRequired) {
codeStream.iand();
}
codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd);
}
public void generateLogicalOr(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
Constant condConst;
if ((this.left.implicitConversion & TypeIds.COMPILE_TYPE_MASK) == TypeIds.T_boolean) {
if ((condConst = this.left.optimizedBooleanConstant()) != Constant.NotAConstant) {
if (condConst.booleanValue() == true) {
this.left.generateCode(currentScope, codeStream, false);
this.right.generateCode(currentScope, codeStream, false);
if (valueRequired) {
codeStream.iconst_1();
}
codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd);
} else {
this.left.generateCode(currentScope, codeStream, false);
this.right.generateCode(currentScope, codeStream, valueRequired);
}
return;
}
if ((condConst = this.right.optimizedBooleanConstant()) != Constant.NotAConstant) {
if (condConst.booleanValue() == true) {
this.left.generateCode(currentScope, codeStream, false);
this.right.generateCode(currentScope, codeStream, false);
if (valueRequired) {
codeStream.iconst_1();
}
codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd);
} else {
this.left.generateCode(currentScope, codeStream, valueRequired);
this.right.generateCode(currentScope, codeStream, false);
}
return;
}
}
this.left.generateCode(currentScope, codeStream, valueRequired);
this.right.generateCode(currentScope, codeStream, valueRequired);
if (valueRequired) {
codeStream.ior();
}
codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd);
}
public void generateLogicalXor(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
Constant condConst;
if ((this.left.implicitConversion & TypeIds.COMPILE_TYPE_MASK) == TypeIds.T_boolean) {
if ((condConst = this.left.optimizedBooleanConstant()) != Constant.NotAConstant) {
if (condConst.booleanValue() == true) {
this.left.generateCode(currentScope, codeStream, false);
if (valueRequired) {
codeStream.iconst_1();
}
this.right.generateCode(currentScope, codeStream, valueRequired);
if (valueRequired) {
codeStream.ixor();
codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd);
}
} else {
this.left.generateCode(currentScope, codeStream, false);
this.right.generateCode(currentScope, codeStream, valueRequired);
}
return;
}
if ((condConst = this.right.optimizedBooleanConstant()) != Constant.NotAConstant) {
if (condConst.booleanValue() == true) {
this.left.generateCode(currentScope, codeStream, valueRequired);
this.right.generateCode(currentScope, codeStream, false);
if (valueRequired) {
codeStream.iconst_1();
codeStream.ixor();
codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd);
}
} else {
this.left.generateCode(currentScope, codeStream, valueRequired);
this.right.generateCode(currentScope, codeStream, false);
}
return;
}
}
this.left.generateCode(currentScope, codeStream, valueRequired);
this.right.generateCode(currentScope, codeStream, valueRequired);
if (valueRequired) {
codeStream.ixor();
}
codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd);
}
public void generateOptimizedLogicalAnd(BlockScope currentScope, CodeStream codeStream, BranchLabel trueLabel, BranchLabel falseLabel, boolean valueRequired) {
Constant condConst;
if ((this.left.implicitConversion & TypeIds.COMPILE_TYPE_MASK) == TypeIds.T_boolean) {
if ((condConst = this.left.optimizedBooleanConstant()) != Constant.NotAConstant) {
if (condConst.booleanValue() == true) {
this.left.generateOptimizedBoolean(
currentScope,
codeStream,
trueLabel,
falseLabel,
false);
this.right.generateOptimizedBoolean(
currentScope,
codeStream,
trueLabel,
falseLabel,
valueRequired);
} else {
this.left.generateOptimizedBoolean(
currentScope,
codeStream,
trueLabel,
falseLabel,
false);
this.right.generateOptimizedBoolean(
currentScope,
codeStream,
trueLabel,
falseLabel,
false);
if (valueRequired) {
if (falseLabel != null) {
codeStream.goto_(falseLabel);
}
}
codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd);
}
return;
}
if ((condConst = this.right.optimizedBooleanConstant()) != Constant.NotAConstant) {
if (condConst.booleanValue() == true) {
this.left.generateOptimizedBoolean(
currentScope,
codeStream,
trueLabel,
falseLabel,
valueRequired);
this.right.generateOptimizedBoolean(
currentScope,
codeStream,
trueLabel,
falseLabel,
false);
} else {
BranchLabel internalTrueLabel = new BranchLabel(codeStream);
this.left.generateOptimizedBoolean(
currentScope,
codeStream,
internalTrueLabel,
falseLabel,
false);
internalTrueLabel.place();
this.right.generateOptimizedBoolean(
currentScope,
codeStream,
trueLabel,
falseLabel,
false);
if (valueRequired) {
if (falseLabel != null) {
codeStream.goto_(falseLabel);
}
}
codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd);
}
return;
}
}
this.left.generateCode(currentScope, codeStream, valueRequired);
this.right.generateCode(currentScope, codeStream, valueRequired);
if (valueRequired) {
codeStream.iand();
if (falseLabel == null) {
if (trueLabel != null) {
codeStream.ifne(trueLabel);
}
} else {
if (trueLabel == null) {
codeStream.ifeq(falseLabel);
} else {
}
}
}
codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd);
}
public void generateOptimizedLogicalOr(BlockScope currentScope, CodeStream codeStream, BranchLabel trueLabel, BranchLabel falseLabel, boolean valueRequired) {
Constant condConst;
if ((this.left.implicitConversion & TypeIds.COMPILE_TYPE_MASK) == TypeIds.T_boolean) {
if ((condConst = this.left.optimizedBooleanConstant()) != Constant.NotAConstant) {
if (condConst.booleanValue() == true) {
this.left.generateOptimizedBoolean(
currentScope,
codeStream,
trueLabel,
falseLabel,
false);
BranchLabel internalFalseLabel = new BranchLabel(codeStream);
this.right.generateOptimizedBoolean(
currentScope,
codeStream,
trueLabel,
internalFalseLabel,
false);
internalFalseLabel.place();
if (valueRequired) {
if (trueLabel != null) {
codeStream.goto_(trueLabel);
}
}
codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd);
} else {
this.left.generateOptimizedBoolean(
currentScope,
codeStream,
trueLabel,
falseLabel,
false);
this.right.generateOptimizedBoolean(
currentScope,
codeStream,
trueLabel,
falseLabel,
valueRequired);
}
return;
}
if ((condConst = this.right.optimizedBooleanConstant()) != Constant.NotAConstant) {
if (condConst.booleanValue() == true) {
BranchLabel internalFalseLabel = new BranchLabel(codeStream);
this.left.generateOptimizedBoolean(
currentScope,
codeStream,
trueLabel,
internalFalseLabel,
false);
internalFalseLabel.place();
this.right.generateOptimizedBoolean(
currentScope,
codeStream,
trueLabel,
falseLabel,
false);
if (valueRequired) {
if (trueLabel != null) {
codeStream.goto_(trueLabel);
}
}
codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd);
} else {
this.left.generateOptimizedBoolean(
currentScope,
codeStream,
trueLabel,
falseLabel,
valueRequired);
this.right.generateOptimizedBoolean(
currentScope,
codeStream,
trueLabel,
falseLabel,
false);
}
return;
}
}
this.left.generateCode(currentScope, codeStream, valueRequired);
this.right.generateCode(currentScope, codeStream, valueRequired);
if (valueRequired) {
codeStream.ior();
if (falseLabel == null) {
if (trueLabel != null) {
codeStream.ifne(trueLabel);
}
} else {
if (trueLabel == null) {
codeStream.ifeq(falseLabel);
} else {
}
}
}
codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd);
}
public void generateOptimizedLogicalXor(BlockScope currentScope, CodeStream codeStream, BranchLabel trueLabel, BranchLabel falseLabel, boolean valueRequired) {
Constant condConst;
if ((this.left.implicitConversion & TypeIds.COMPILE_TYPE_MASK) == TypeIds.T_boolean) {
if ((condConst = this.left.optimizedBooleanConstant()) != Constant.NotAConstant) {
if (condConst.booleanValue() == true) {
this.left.generateOptimizedBoolean(
currentScope,
codeStream,
trueLabel,
falseLabel,
false);
this.right.generateOptimizedBoolean(
currentScope,
codeStream,
falseLabel,
trueLabel,
valueRequired);
} else {
this.left.generateOptimizedBoolean(
currentScope,
codeStream,
trueLabel,
falseLabel,
false);
this.right.generateOptimizedBoolean(
currentScope,
codeStream,
trueLabel,
falseLabel,
valueRequired);
}
return;
}
if ((condConst = this.right.optimizedBooleanConstant()) != Constant.NotAConstant) {
if (condConst.booleanValue() == true) {
this.left.generateOptimizedBoolean(
currentScope,
codeStream,
falseLabel,
trueLabel,
valueRequired);
this.right.generateOptimizedBoolean(
currentScope,
codeStream,
trueLabel,
falseLabel,
false);
} else {
this.left.generateOptimizedBoolean(
currentScope,
codeStream,
trueLabel,
falseLabel,
valueRequired);
this.right.generateOptimizedBoolean(
currentScope,
codeStream,
trueLabel,
falseLabel,
false);
}
return;
}
}
this.left.generateCode(currentScope, codeStream, valueRequired);
this.right.generateCode(currentScope, codeStream, valueRequired);
if (valueRequired) {
codeStream.ixor();
if (falseLabel == null) {
if (trueLabel != null) {
codeStream.ifne(trueLabel);
}
} else {
if (trueLabel == null) {
codeStream.ifeq(falseLabel);
} else {
}
}
}
codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd);
}
@Override
public void generateOptimizedStringConcatenation(BlockScope blockScope, CodeStream codeStream, int typeID) {
if ((((this.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT) == OperatorIds.PLUS)
&& ((this.bits & ASTNode.ReturnTypeIDMASK) == TypeIds.T_JavaLangString)) {
if (this.constant != Constant.NotAConstant) {
codeStream.generateConstant(this.constant, this.implicitConversion);
codeStream.invokeStringConcatenationAppendForType(this.implicitConversion & TypeIds.COMPILE_TYPE_MASK);
} else {
int pc = codeStream.position;
this.left.generateOptimizedStringConcatenation(
blockScope,
codeStream,
this.left.implicitConversion & TypeIds.COMPILE_TYPE_MASK);
codeStream.recordPositionsFrom(pc, this.left.sourceStart);
pc = codeStream.position;
this.right.generateOptimizedStringConcatenation(
blockScope,
codeStream,
this.right.implicitConversion & TypeIds.COMPILE_TYPE_MASK);
codeStream.recordPositionsFrom(pc, this.right.sourceStart);
}
} else {
super.generateOptimizedStringConcatenation(blockScope, codeStream, typeID);
}
}
@Override
public void generateOptimizedStringConcatenationCreation(BlockScope blockScope, CodeStream codeStream, int typeID) {
if ((((this.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT) == OperatorIds.PLUS)
&& ((this.bits & ASTNode.ReturnTypeIDMASK) == TypeIds.T_JavaLangString)) {
if (this.constant != Constant.NotAConstant) {
codeStream.newStringContatenation();
codeStream.dup();
codeStream.ldc(this.constant.stringValue());
codeStream.invokeStringConcatenationStringConstructor();
} else {
int pc = codeStream.position;
this.left.generateOptimizedStringConcatenationCreation(
blockScope,
codeStream,
this.left.implicitConversion & TypeIds.COMPILE_TYPE_MASK);
codeStream.recordPositionsFrom(pc, this.left.sourceStart);
pc = codeStream.position;
this.right.generateOptimizedStringConcatenation(
blockScope,
codeStream,
this.right.implicitConversion & TypeIds.COMPILE_TYPE_MASK);
codeStream.recordPositionsFrom(pc, this.right.sourceStart);
}
} else {
super.generateOptimizedStringConcatenationCreation(blockScope, codeStream, typeID);
}
}
@Override
public boolean isCompactableOperation() {
return true;
}
void nonRecursiveResolveTypeUpwards(BlockScope scope) {
boolean leftIsCast, rightIsCast;
TypeBinding leftType = this.left.resolvedType;
if ((rightIsCast = this.right instanceof CastExpression) == true) {
this.right.bits |= ASTNode.DisableUnnecessaryCastCheck;
}
TypeBinding rightType = this.right.resolveType(scope);
if (leftType == null || rightType == null) {
this.constant = Constant.NotAConstant;
return;
}
int leftTypeID = leftType.id;
int rightTypeID = rightType.id;
boolean use15specifics = scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5;
if (use15specifics) {
if (!leftType.isBaseType() && rightTypeID != TypeIds.T_JavaLangString && rightTypeID != TypeIds.T_null) {
leftTypeID = scope.environment().computeBoxingType(leftType).id;
}
if (!rightType.isBaseType() && leftTypeID != TypeIds.T_JavaLangString && leftTypeID != TypeIds.T_null) {
rightTypeID = scope.environment().computeBoxingType(rightType).id;
}
}
if (leftTypeID > 15
|| rightTypeID > 15) {
if (leftTypeID == TypeIds.T_JavaLangString) {
rightTypeID = TypeIds.T_JavaLangObject;
} else if (rightTypeID == TypeIds.T_JavaLangString) {
leftTypeID = TypeIds.T_JavaLangObject;
} else {
this.constant = Constant.NotAConstant;
scope.problemReporter().invalidOperator(this, leftType, rightType);
return;
}
}
if (((this.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT) == OperatorIds.PLUS) {
if (leftTypeID == TypeIds.T_JavaLangString) {
this.left.computeConversion(scope, leftType, leftType);
if (rightType.isArrayType() && TypeBinding.equalsEquals(((ArrayBinding) rightType).elementsType(), TypeBinding.CHAR)) {
scope.problemReporter().signalNoImplicitStringConversionForCharArrayExpression(this.right);
}
}
if (rightTypeID == TypeIds.T_JavaLangString) {
this.right.computeConversion(scope, rightType, rightType);
if (leftType.isArrayType() && TypeBinding.equalsEquals(((ArrayBinding) leftType).elementsType(), TypeBinding.CHAR)) {
scope.problemReporter().signalNoImplicitStringConversionForCharArrayExpression(this.left);
}
}
}
int operator = (this.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT;
int operatorSignature = OperatorExpression.OperatorSignatures[operator][(leftTypeID << 4) + rightTypeID];
this.left.computeConversion(scope, TypeBinding.wellKnownType(scope, (operatorSignature >>> 16) & 0x0000F), leftType);
this.right.computeConversion(scope, TypeBinding.wellKnownType(scope, (operatorSignature >>> 8) & 0x0000F), rightType);
this.bits |= operatorSignature & 0xF;
switch (operatorSignature & 0xF) {
case T_boolean :
this.resolvedType = TypeBinding.BOOLEAN;
break;
case T_byte :
this.resolvedType = TypeBinding.BYTE;
break;
case T_char :
this.resolvedType = TypeBinding.CHAR;
break;
case T_double :
this.resolvedType = TypeBinding.DOUBLE;
break;
case T_float :
this.resolvedType = TypeBinding.FLOAT;
break;
case T_int :
this.resolvedType = TypeBinding.INT;
break;
case T_long :
this.resolvedType = TypeBinding.LONG;
break;
case T_JavaLangString :
this.resolvedType = scope.getJavaLangString();
break;
default :
this.constant = Constant.NotAConstant;
scope.problemReporter().invalidOperator(this, leftType, rightType);
return;
}
if ((leftIsCast = (this.left instanceof CastExpression)) == true ||
rightIsCast) {
CastExpression.checkNeedForArgumentCasts(scope, operator, operatorSignature, this.left, leftTypeID, leftIsCast, this.right, rightTypeID, rightIsCast);
}
computeConstant(scope, leftTypeID, rightTypeID);
}
public void optimizedBooleanConstant(int leftId, int operator, int rightId) {
switch (operator) {
case AND :
if ((leftId != TypeIds.T_boolean) || (rightId != TypeIds.T_boolean))
return;
case AND_AND :
Constant cst;
if ((cst = this.left.optimizedBooleanConstant()) != Constant.NotAConstant) {
if (cst.booleanValue() == false) {
this.optimizedBooleanConstant = cst;
return;
} else {
if ((cst = this.right.optimizedBooleanConstant()) != Constant.NotAConstant) {
this.optimizedBooleanConstant = cst;
}
return;
}
}
if ((cst = this.right.optimizedBooleanConstant()) != Constant.NotAConstant) {
if (cst.booleanValue() == false) {
this.optimizedBooleanConstant = cst;
}
}
return;
case OR :
if ((leftId != TypeIds.T_boolean) || (rightId != TypeIds.T_boolean))
return;
case OR_OR :
if ((cst = this.left.optimizedBooleanConstant()) != Constant.NotAConstant) {
if (cst.booleanValue() == true) {
this.optimizedBooleanConstant = cst;
return;
} else {
if ((cst = this.right.optimizedBooleanConstant()) != Constant.NotAConstant) {
this.optimizedBooleanConstant = cst;
}
return;
}
}
if ((cst = this.right.optimizedBooleanConstant()) != Constant.NotAConstant) {
if (cst.booleanValue() == true) {
this.optimizedBooleanConstant = cst;
}
}
}
}
@Override
public StringBuffer printExpressionNoParenthesis(int indent, StringBuffer output) {
this.left.printExpression(indent, output).append(' ').append(operatorToString()).append(' ');
return this.right.printExpression(0, output);
}
@Override
public TypeBinding resolveType(BlockScope scope) {
boolean leftIsCast, rightIsCast;
if ((leftIsCast = this.left instanceof CastExpression) == true) this.left.bits |= ASTNode.DisableUnnecessaryCastCheck;
TypeBinding leftType = this.left.resolveType(scope);
if ((rightIsCast = this.right instanceof CastExpression) == true) this.right.bits |= ASTNode.DisableUnnecessaryCastCheck;
TypeBinding rightType = this.right.resolveType(scope);
if (leftType == null || rightType == null) {
this.constant = Constant.NotAConstant;
return null;
}
int leftTypeID = leftType.id;
int rightTypeID = rightType.id;
boolean use15specifics = scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5;
if (use15specifics) {
if (!leftType.isBaseType() && rightTypeID != TypeIds.T_JavaLangString && rightTypeID != TypeIds.T_null) {
leftTypeID = scope.environment().computeBoxingType(leftType).id;
}
if (!rightType.isBaseType() && leftTypeID != TypeIds.T_JavaLangString && leftTypeID != TypeIds.T_null) {
rightTypeID = scope.environment().computeBoxingType(rightType).id;
}
}
if (leftTypeID > 15
|| rightTypeID > 15) {
if (leftTypeID == TypeIds.T_JavaLangString) {
rightTypeID = TypeIds.T_JavaLangObject;
} else if (rightTypeID == TypeIds.T_JavaLangString) {
leftTypeID = TypeIds.T_JavaLangObject;
} else {
this.constant = Constant.NotAConstant;
scope.problemReporter().invalidOperator(this, leftType, rightType);
return null;
}
}
if (((this.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT) == OperatorIds.PLUS) {
if (leftTypeID == TypeIds.T_JavaLangString) {
this.left.computeConversion(scope, leftType, leftType);
if (rightType.isArrayType() && TypeBinding.equalsEquals(((ArrayBinding) rightType).elementsType(), TypeBinding.CHAR)) {
scope.problemReporter().signalNoImplicitStringConversionForCharArrayExpression(this.right);
}
}
if (rightTypeID == TypeIds.T_JavaLangString) {
this.right.computeConversion(scope, rightType, rightType);
if (leftType.isArrayType() && TypeBinding.equalsEquals(((ArrayBinding) leftType).elementsType(), TypeBinding.CHAR)) {
scope.problemReporter().signalNoImplicitStringConversionForCharArrayExpression(this.left);
}
}
}
int operator = (this.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT;
int operatorSignature = OperatorExpression.OperatorSignatures[operator][(leftTypeID << 4) + rightTypeID];
this.left.computeConversion(scope, TypeBinding.wellKnownType(scope, (operatorSignature >>> 16) & 0x0000F), leftType);
this.right.computeConversion(scope, TypeBinding.wellKnownType(scope, (operatorSignature >>> 8) & 0x0000F), rightType);
this.bits |= operatorSignature & 0xF;
switch (operatorSignature & 0xF) {
case T_boolean :
this.resolvedType = TypeBinding.BOOLEAN;
break;
case T_byte :
this.resolvedType = TypeBinding.BYTE;
break;
case T_char :
this.resolvedType = TypeBinding.CHAR;
break;
case T_double :
this.resolvedType = TypeBinding.DOUBLE;
break;
case T_float :
this.resolvedType = TypeBinding.FLOAT;
break;
case T_int :
this.resolvedType = TypeBinding.INT;
break;
case T_long :
this.resolvedType = TypeBinding.LONG;
break;
case T_JavaLangString :
this.resolvedType = scope.getJavaLangString();
break;
default :
this.constant = Constant.NotAConstant;
scope.problemReporter().invalidOperator(this, leftType, rightType);
return null;
}
if (leftIsCast || rightIsCast) {
CastExpression.checkNeedForArgumentCasts(scope, operator, operatorSignature, this.left, leftTypeID, leftIsCast, this.right, rightTypeID, rightIsCast);
}
computeConstant(scope, leftTypeID, rightTypeID);
return this.resolvedType;
}
@Override
public void traverse(ASTVisitor visitor, BlockScope scope) {
if (visitor.visit(this, scope)) {
this.left.traverse(visitor, scope);
this.right.traverse(visitor, scope);
}
visitor.endVisit(this, scope);
}
}