@Override public TypeBinding resolveType(BlockScope scope) { boolean expressionIsCast; if ((expressionIsCast = this.expression instanceof CastExpression) == true) { this.expression.bits |= DisableUnnecessaryCastCheck; // will check later on } TypeBinding expressionType = this.expression.resolveType(scope); if (expressionType == null) { this.constant = Constant.NotAConstant; return null; } int expressionTypeID = expressionType.id; // autoboxing support boolean use15specifics = scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5; if (use15specifics) { if (!expressionType.isBaseType()) { expressionTypeID = scope.environment().computeBoxingType(expressionType).id; } } if (expressionTypeID > 15) { this.constant = Constant.NotAConstant; scope.problemReporter().invalidOperator(this, expressionType); return null; } int tableId; switch ((this.bits & OperatorMASK) >> OperatorSHIFT) { case NOT: tableId = AND_AND; break; case TWIDDLE: tableId = LEFT_SHIFT; break; default: tableId = MINUS; } // + and - cases // the code is an int // (cast) left Op (cast) rigth --> result // 0000 0000 0000 0000 0000 // <<16 <<12 <<8 <<4 <<0 int operatorSignature = OperatorSignatures[tableId][(expressionTypeID << 4) + expressionTypeID]; this.expression.computeConversion( scope, TypeBinding.wellKnownType(scope, (operatorSignature >>> 16) & 0x0000F), expressionType); this.bits |= operatorSignature & 0xF; switch (operatorSignature & 0xF) { // only switch on possible result type..... 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; default: // error........ this.constant = Constant.NotAConstant; if (expressionTypeID != T_undefined) { scope.problemReporter().invalidOperator(this, expressionType); } return null; } // compute the constant when valid if (this.expression.constant != Constant.NotAConstant) { this.constant = Constant.computeConstantOperation( this.expression.constant, expressionTypeID, (this.bits & OperatorMASK) >> OperatorSHIFT); } else { this.constant = Constant.NotAConstant; if (((this.bits & OperatorMASK) >> OperatorSHIFT) == NOT) { Constant cst = this.expression.optimizedBooleanConstant(); if (cst != Constant.NotAConstant) { this.optimizedBooleanConstant = BooleanConstant.fromValue(!cst.booleanValue()); } } } if (expressionIsCast) { // check need for operand cast CastExpression.checkNeedForArgumentCast( scope, tableId, operatorSignature, this.expression, expressionTypeID); } return this.resolvedType; }
/* * The APIs with an extra argument is used whenever there are two references to the same variable which * are optimized in one access: e.g "a = a + 1" optimized into "a++". */ public void generateCompoundAssignment( BlockScope currentScope, MethodBinding writeAccessor, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) { switch (this.bits & ASTNode.RestrictiveFlagMASK) { case Binding.FIELD: // assigning to a field break; case Binding.LOCAL: // assigning to a local variable (cannot assign to outer local) LocalVariableBinding localBinding = (LocalVariableBinding) this.binding; // using incr bytecode if possible Constant assignConstant; switch (localBinding.type.id) { case T_JavaLangString: return; case T_int: assignConstant = expression.constant; if (localBinding.resolvedPosition == -1) { if (valueRequired) { /* * restart code gen because we either: * - need the value * - the constant can have potential side-effect */ localBinding.useFlag = LocalVariableBinding.USED; throw new AbortMethod(null, null); } else if (assignConstant == Constant.NotAConstant) { // we only need to generate the value of the expression's constant if it is not a // constant expression expression.generateCode(currentScope, false); } return; } if ((assignConstant != Constant.NotAConstant) && (assignConstant.typeID() != TypeIds.T_float) // only for integral types && (assignConstant.typeID() != TypeIds.T_double)) { // TODO (philippe) is this test needed ? switch (operator) { case PLUS: int increment = assignConstant.intValue(); if (increment != (short) increment) break; // not representable as a 16-bits value return; case MINUS: increment = -assignConstant.intValue(); if (increment != (short) increment) break; // not representable as a 16-bits value return; } } // $FALL-THROUGH$ default: if (localBinding.resolvedPosition == -1) { assignConstant = expression.constant; if (valueRequired) { /* * restart code gen because we either: * - need the value * - the constant can have potential side-effect */ localBinding.useFlag = LocalVariableBinding.USED; throw new AbortMethod(null, null); } else if (assignConstant == Constant.NotAConstant) { // we only need to generate the value of the expression's constant if it is not a // constant expression expression.generateCode(currentScope, false); } return; } } } switch ((this.implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4) { case T_JavaLangString: case T_JavaLangObject: case T_undefined: // we enter here if the single name reference is a field of type java.lang.String or if the // type of the // operation is java.lang.Object // For example: o = o + ""; // where the compiled type of o is java.lang.Object. // no need for generic cast on previous #getfield since using Object string buffer methods. break; default: // promote the array reference to the suitable operation type // generate the increment value (will by itself be promoted to the operation value) if (expression != IntLiteral.One) { // prefix operation expression.generateCode(currentScope, true); } } // store the result back into the variable switch (this.bits & ASTNode.RestrictiveFlagMASK) { case Binding.FIELD: // assigning to a field FieldBinding codegenField = ((FieldBinding) this.binding).original(); fieldStore( currentScope, codegenField, writeAccessor, this.actualReceiverType, true /* implicit this*/, valueRequired); // no need for generic cast as value got dupped return; case Binding.LOCAL: // assigning to a local variable LocalVariableBinding localBinding = (LocalVariableBinding) this.binding; if (valueRequired) { switch (localBinding.type.id) { case TypeIds.T_long: case TypeIds.T_double: break; default: break; } } } }