0001: /*******************************************************************************
0002: * Copyright (c) 2000, 2007 IBM Corporation and others.
0003: * All rights reserved. This program and the accompanying materials
0004: * are made available under the terms of the Eclipse Public License v1.0
0005: * which accompanies this distribution, and is available at
0006: * http://www.eclipse.org/legal/epl-v10.html
0007: *
0008: * Contributors:
0009: * IBM Corporation - initial API and implementation
0010: *******************************************************************************/package org.eclipse.jdt.internal.compiler.ast;
0011:
0012: import java.util.ArrayList;
0013:
0014: import org.eclipse.jdt.core.compiler.CharOperation;
0015: import org.eclipse.jdt.internal.compiler.ASTVisitor;
0016: import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
0017: import org.eclipse.jdt.internal.compiler.codegen.BranchLabel;
0018: import org.eclipse.jdt.internal.compiler.codegen.CodeStream;
0019: import org.eclipse.jdt.internal.compiler.flow.FlowContext;
0020: import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
0021: import org.eclipse.jdt.internal.compiler.impl.Constant;
0022: import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
0023: import org.eclipse.jdt.internal.compiler.lookup.BaseTypeBinding;
0024: import org.eclipse.jdt.internal.compiler.lookup.Binding;
0025: import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
0026: import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
0027: import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
0028: import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
0029: import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
0030: import org.eclipse.jdt.internal.compiler.lookup.Scope;
0031: import org.eclipse.jdt.internal.compiler.lookup.TagBits;
0032: import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
0033: import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
0034: import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
0035: import org.eclipse.jdt.internal.compiler.lookup.WildcardBinding;
0036: import org.eclipse.jdt.internal.compiler.problem.ShouldNotImplement;
0037: import org.eclipse.jdt.internal.compiler.util.Messages;
0038:
0039: public abstract class Expression extends Statement {
0040:
0041: public Constant constant;
0042:
0043: public int statementEnd = -1;
0044:
0045: //Some expression may not be used - from a java semantic point
0046: //of view only - as statements. Other may. In order to avoid the creation
0047: //of wrappers around expression in order to tune them as expression
0048: //Expression is a subclass of Statement. See the message isValidJavaStatement()
0049:
0050: public int implicitConversion;
0051: public TypeBinding resolvedType;
0052:
0053: public static final boolean isConstantValueRepresentable(
0054: Constant constant, int constantTypeID, int targetTypeID) {
0055: //true if there is no loss of precision while casting.
0056: // constantTypeID == constant.typeID
0057: if (targetTypeID == constantTypeID)
0058: return true;
0059: switch (targetTypeID) {
0060: case T_char:
0061: switch (constantTypeID) {
0062: case T_char:
0063: return true;
0064: case T_double:
0065: return constant.doubleValue() == constant.charValue();
0066: case T_float:
0067: return constant.floatValue() == constant.charValue();
0068: case T_int:
0069: return constant.intValue() == constant.charValue();
0070: case T_short:
0071: return constant.shortValue() == constant.charValue();
0072: case T_byte:
0073: return constant.byteValue() == constant.charValue();
0074: case T_long:
0075: return constant.longValue() == constant.charValue();
0076: default:
0077: return false;//boolean
0078: }
0079:
0080: case T_float:
0081: switch (constantTypeID) {
0082: case T_char:
0083: return constant.charValue() == constant.floatValue();
0084: case T_double:
0085: return constant.doubleValue() == constant.floatValue();
0086: case T_float:
0087: return true;
0088: case T_int:
0089: return constant.intValue() == constant.floatValue();
0090: case T_short:
0091: return constant.shortValue() == constant.floatValue();
0092: case T_byte:
0093: return constant.byteValue() == constant.floatValue();
0094: case T_long:
0095: return constant.longValue() == constant.floatValue();
0096: default:
0097: return false;//boolean
0098: }
0099:
0100: case T_double:
0101: switch (constantTypeID) {
0102: case T_char:
0103: return constant.charValue() == constant.doubleValue();
0104: case T_double:
0105: return true;
0106: case T_float:
0107: return constant.floatValue() == constant.doubleValue();
0108: case T_int:
0109: return constant.intValue() == constant.doubleValue();
0110: case T_short:
0111: return constant.shortValue() == constant.doubleValue();
0112: case T_byte:
0113: return constant.byteValue() == constant.doubleValue();
0114: case T_long:
0115: return constant.longValue() == constant.doubleValue();
0116: default:
0117: return false; //boolean
0118: }
0119:
0120: case T_byte:
0121: switch (constantTypeID) {
0122: case T_char:
0123: return constant.charValue() == constant.byteValue();
0124: case T_double:
0125: return constant.doubleValue() == constant.byteValue();
0126: case T_float:
0127: return constant.floatValue() == constant.byteValue();
0128: case T_int:
0129: return constant.intValue() == constant.byteValue();
0130: case T_short:
0131: return constant.shortValue() == constant.byteValue();
0132: case T_byte:
0133: return true;
0134: case T_long:
0135: return constant.longValue() == constant.byteValue();
0136: default:
0137: return false; //boolean
0138: }
0139:
0140: case T_short:
0141: switch (constantTypeID) {
0142: case T_char:
0143: return constant.charValue() == constant.shortValue();
0144: case T_double:
0145: return constant.doubleValue() == constant.shortValue();
0146: case T_float:
0147: return constant.floatValue() == constant.shortValue();
0148: case T_int:
0149: return constant.intValue() == constant.shortValue();
0150: case T_short:
0151: return true;
0152: case T_byte:
0153: return constant.byteValue() == constant.shortValue();
0154: case T_long:
0155: return constant.longValue() == constant.shortValue();
0156: default:
0157: return false; //boolean
0158: }
0159:
0160: case T_int:
0161: switch (constantTypeID) {
0162: case T_char:
0163: return constant.charValue() == constant.intValue();
0164: case T_double:
0165: return constant.doubleValue() == constant.intValue();
0166: case T_float:
0167: return constant.floatValue() == constant.intValue();
0168: case T_int:
0169: return true;
0170: case T_short:
0171: return constant.shortValue() == constant.intValue();
0172: case T_byte:
0173: return constant.byteValue() == constant.intValue();
0174: case T_long:
0175: return constant.longValue() == constant.intValue();
0176: default:
0177: return false; //boolean
0178: }
0179:
0180: case T_long:
0181: switch (constantTypeID) {
0182: case T_char:
0183: return constant.charValue() == constant.longValue();
0184: case T_double:
0185: return constant.doubleValue() == constant.longValue();
0186: case T_float:
0187: return constant.floatValue() == constant.longValue();
0188: case T_int:
0189: return constant.intValue() == constant.longValue();
0190: case T_short:
0191: return constant.shortValue() == constant.longValue();
0192: case T_byte:
0193: return constant.byteValue() == constant.longValue();
0194: case T_long:
0195: return true;
0196: default:
0197: return false; //boolean
0198: }
0199:
0200: default:
0201: return false; //boolean
0202: }
0203: }
0204:
0205: public Expression() {
0206: super ();
0207: }
0208:
0209: public FlowInfo analyseCode(BlockScope currentScope,
0210: FlowContext flowContext, FlowInfo flowInfo) {
0211: return flowInfo;
0212: }
0213:
0214: /**
0215: * More sophisticated for of the flow analysis used for analyzing expressions, and be able to optimize out
0216: * portions of expressions where no actual value is required.
0217: *
0218: * @param currentScope
0219: * @param flowContext
0220: * @param flowInfo
0221: * @param valueRequired
0222: * @return The state of initialization after the analysis of the current expression
0223: */
0224: public FlowInfo analyseCode(BlockScope currentScope,
0225: FlowContext flowContext, FlowInfo flowInfo,
0226: boolean valueRequired) {
0227:
0228: return analyseCode(currentScope, flowContext, flowInfo);
0229: }
0230:
0231: /**
0232: * Returns false if cast is not legal.
0233: */
0234: public final boolean checkCastTypesCompatibility(Scope scope,
0235: TypeBinding castType, TypeBinding expressionType,
0236: Expression expression) {
0237:
0238: // see specifications 5.5
0239: // handle errors and process constant when needed
0240:
0241: // if either one of the type is null ==>
0242: // some error has been already reported some where ==>
0243: // we then do not report an obvious-cascade-error.
0244:
0245: if (castType == null || expressionType == null)
0246: return true;
0247:
0248: // identity conversion cannot be performed upfront, due to side-effects
0249: // like constant propagation
0250: boolean use15specifics = scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5;
0251: if (castType.isBaseType()) {
0252: if (expressionType.isBaseType()) {
0253: if (expressionType == castType) {
0254: if (expression != null) {
0255: this .constant = expression.constant; //use the same constant
0256: }
0257: tagAsUnnecessaryCast(scope, castType);
0258: return true;
0259: }
0260: boolean necessary = false;
0261: if (expressionType.isCompatibleWith(castType)
0262: || (necessary = BaseTypeBinding.isNarrowing(
0263: castType.id, expressionType.id))) {
0264: if (expression != null) {
0265: expression.implicitConversion = (castType.id << 4)
0266: + expressionType.id;
0267: if (expression.constant != Constant.NotAConstant) {
0268: this .constant = expression.constant
0269: .castTo(expression.implicitConversion);
0270: }
0271: }
0272: if (!necessary)
0273: tagAsUnnecessaryCast(scope, castType);
0274: return true;
0275:
0276: }
0277: } else if (use15specifics
0278: && scope.environment().computeBoxingType(
0279: expressionType).isCompatibleWith(castType)) { // unboxing - only widening match is allowed
0280: tagAsUnnecessaryCast(scope, castType);
0281: return true;
0282: }
0283: return false;
0284: } else if (use15specifics
0285: && expressionType.isBaseType()
0286: && scope.environment()
0287: .computeBoxingType(expressionType)
0288: .isCompatibleWith(castType)) { // boxing - only widening match is allowed
0289: tagAsUnnecessaryCast(scope, castType);
0290: return true;
0291: }
0292:
0293: switch (expressionType.kind()) {
0294: case Binding.BASE_TYPE:
0295: //-----------cast to something which is NOT a base type--------------------------
0296: if (expressionType == TypeBinding.NULL) {
0297: tagAsUnnecessaryCast(scope, castType);
0298: return true; //null is compatible with every thing
0299: }
0300: return false;
0301:
0302: case Binding.ARRAY_TYPE:
0303: if (castType == expressionType) {
0304: tagAsUnnecessaryCast(scope, castType);
0305: return true; // identity conversion
0306: }
0307: switch (castType.kind()) {
0308: case Binding.ARRAY_TYPE:
0309: // ( ARRAY ) ARRAY
0310: TypeBinding castElementType = ((ArrayBinding) castType)
0311: .elementsType();
0312: TypeBinding exprElementType = ((ArrayBinding) expressionType)
0313: .elementsType();
0314: if (exprElementType.isBaseType()
0315: || castElementType.isBaseType()) {
0316: if (castElementType == exprElementType) {
0317: tagAsNeedCheckCast();
0318: return true;
0319: }
0320: return false;
0321: }
0322: // recurse on array type elements
0323: return checkCastTypesCompatibility(scope,
0324: castElementType, exprElementType, expression);
0325:
0326: case Binding.TYPE_PARAMETER:
0327: // ( TYPE_PARAMETER ) ARRAY
0328: TypeBinding match = expressionType
0329: .findSuperTypeWithSameErasure(castType);
0330: if (match == null) {
0331: checkUnsafeCast(scope, castType, expressionType,
0332: null /*no match*/, true);
0333: }
0334: // recurse on the type variable upper bound
0335: return checkCastTypesCompatibility(scope,
0336: ((TypeVariableBinding) castType).upperBound(),
0337: expressionType, expression);
0338:
0339: default:
0340: // ( CLASS/INTERFACE ) ARRAY
0341: switch (castType.id) {
0342: case T_JavaLangCloneable:
0343: case T_JavaIoSerializable:
0344: tagAsNeedCheckCast();
0345: return true;
0346: case T_JavaLangObject:
0347: tagAsUnnecessaryCast(scope, castType);
0348: return true;
0349: default:
0350: return false;
0351: }
0352: }
0353:
0354: case Binding.TYPE_PARAMETER:
0355: TypeBinding match = expressionType
0356: .findSuperTypeWithSameErasure(castType);
0357: if (match != null) {
0358: return checkUnsafeCast(scope, castType, expressionType,
0359: match, false);
0360: }
0361: // recursively on the type variable upper bound
0362: return checkCastTypesCompatibility(
0363: scope,
0364: castType,
0365: ((TypeVariableBinding) expressionType).upperBound(),
0366: expression);
0367:
0368: case Binding.WILDCARD_TYPE: // intersection type
0369: match = expressionType
0370: .findSuperTypeWithSameErasure(castType);
0371: if (match != null) {
0372: return checkUnsafeCast(scope, castType, expressionType,
0373: match, false);
0374: }
0375: // recursively on the type variable upper bound
0376: return checkCastTypesCompatibility(scope, castType,
0377: ((WildcardBinding) expressionType).bound,
0378: expression);
0379:
0380: default:
0381: if (expressionType.isInterface()) {
0382: switch (castType.kind()) {
0383: case Binding.ARRAY_TYPE:
0384: // ( ARRAY ) INTERFACE
0385: switch (expressionType.id) {
0386: case T_JavaLangCloneable:
0387: case T_JavaIoSerializable:
0388: tagAsNeedCheckCast();
0389: return true;
0390: default:
0391: return false;
0392: }
0393:
0394: case Binding.TYPE_PARAMETER:
0395: // ( INTERFACE ) TYPE_PARAMETER
0396: match = expressionType
0397: .findSuperTypeWithSameErasure(castType);
0398: if (match == null) {
0399: checkUnsafeCast(scope, castType,
0400: expressionType, null /*no match*/,
0401: true);
0402: }
0403: // recurse on the type variable upper bound
0404: return checkCastTypesCompatibility(scope,
0405: ((TypeVariableBinding) castType)
0406: .upperBound(), expressionType,
0407: expression);
0408:
0409: default:
0410: if (castType.isInterface()) {
0411: // ( INTERFACE ) INTERFACE
0412: ReferenceBinding interfaceType = (ReferenceBinding) expressionType;
0413: match = interfaceType
0414: .findSuperTypeWithSameErasure(castType);
0415: if (match != null) {
0416: return checkUnsafeCast(scope, castType,
0417: interfaceType, match, false);
0418: }
0419: tagAsNeedCheckCast();
0420: match = castType
0421: .findSuperTypeWithSameErasure(interfaceType);
0422: if (match != null) {
0423: return checkUnsafeCast(scope, castType,
0424: interfaceType, match, true);
0425: }
0426: if (use15specifics) {
0427: checkUnsafeCast(scope, castType,
0428: expressionType, null /*no match*/,
0429: true);
0430: // ensure there is no collision between both interfaces: i.e. I1 extends List<String>, I2 extends List<Object>
0431: if (interfaceType
0432: .hasIncompatibleSuperType((ReferenceBinding) castType))
0433: return false;
0434: } else {
0435: // pre1.5 semantics - no covariance allowed (even if 1.5 compliant, but 1.4 source)
0436: MethodBinding[] castTypeMethods = getAllInheritedMethods((ReferenceBinding) castType);
0437: MethodBinding[] expressionTypeMethods = getAllInheritedMethods((ReferenceBinding) expressionType);
0438: int exprMethodsLength = expressionTypeMethods.length;
0439: for (int i = 0, castMethodsLength = castTypeMethods.length; i < castMethodsLength; i++) {
0440: for (int j = 0; j < exprMethodsLength; j++) {
0441: if ((castTypeMethods[i].returnType != expressionTypeMethods[j].returnType)
0442: && (CharOperation
0443: .equals(
0444: castTypeMethods[i].selector,
0445: expressionTypeMethods[j].selector))
0446: && castTypeMethods[i]
0447: .areParametersEqual(expressionTypeMethods[j])) {
0448: return false;
0449:
0450: }
0451: }
0452: }
0453: }
0454: return true;
0455: } else {
0456: // ( CLASS ) INTERFACE
0457: if (castType.id == TypeIds.T_JavaLangObject) { // no runtime error
0458: tagAsUnnecessaryCast(scope, castType);
0459: return true;
0460: }
0461: // can only be a downcast
0462: tagAsNeedCheckCast();
0463: match = castType
0464: .findSuperTypeWithSameErasure(expressionType);
0465: if (match != null) {
0466: return checkUnsafeCast(scope, castType,
0467: expressionType, match, true);
0468: }
0469: if (((ReferenceBinding) castType).isFinal()) {
0470: // no subclass for castType, thus compile-time check is invalid
0471: return false;
0472: }
0473: if (use15specifics) {
0474: checkUnsafeCast(scope, castType,
0475: expressionType, null /*no match*/,
0476: true);
0477: // ensure there is no collision between both interfaces: i.e. I1 extends List<String>, I2 extends List<Object>
0478: if (((ReferenceBinding) castType)
0479: .hasIncompatibleSuperType((ReferenceBinding) expressionType)) {
0480: return false;
0481: }
0482: }
0483: return true;
0484: }
0485: }
0486: } else {
0487: switch (castType.kind()) {
0488: case Binding.ARRAY_TYPE:
0489: // ( ARRAY ) CLASS
0490: if (expressionType.id == TypeIds.T_JavaLangObject) { // potential runtime error
0491: if (use15specifics)
0492: checkUnsafeCast(scope, castType,
0493: expressionType, expressionType,
0494: true);
0495: tagAsNeedCheckCast();
0496: return true;
0497: }
0498: return false;
0499:
0500: case Binding.TYPE_PARAMETER:
0501: // ( TYPE_PARAMETER ) CLASS
0502: match = expressionType
0503: .findSuperTypeWithSameErasure(castType);
0504: if (match == null) {
0505: checkUnsafeCast(scope, castType,
0506: expressionType, match, true);
0507: }
0508: // recurse on the type variable upper bound
0509: return checkCastTypesCompatibility(scope,
0510: ((TypeVariableBinding) castType)
0511: .upperBound(), expressionType,
0512: expression);
0513:
0514: default:
0515: if (castType.isInterface()) {
0516: // ( INTERFACE ) CLASS
0517: ReferenceBinding refExprType = (ReferenceBinding) expressionType;
0518: match = refExprType
0519: .findSuperTypeWithSameErasure(castType);
0520: if (match != null) {
0521: return checkUnsafeCast(scope, castType,
0522: expressionType, match, false);
0523: }
0524: // unless final a subclass may implement the interface ==> no check at compile time
0525: if (refExprType.isFinal()) {
0526: return false;
0527: }
0528: tagAsNeedCheckCast();
0529: match = castType
0530: .findSuperTypeWithSameErasure(expressionType);
0531: if (match != null) {
0532: return checkUnsafeCast(scope, castType,
0533: expressionType, match, true);
0534: }
0535: if (use15specifics) {
0536: checkUnsafeCast(scope, castType,
0537: expressionType, null /*no match*/,
0538: true);
0539: // ensure there is no collision between both interfaces: i.e. I1 extends List<String>, I2 extends List<Object>
0540: if (refExprType
0541: .hasIncompatibleSuperType((ReferenceBinding) castType))
0542: return false;
0543: }
0544: return true;
0545: } else {
0546: // ( CLASS ) CLASS
0547: match = expressionType
0548: .findSuperTypeWithSameErasure(castType);
0549: if (match != null) {
0550: if (expression != null
0551: && castType.id == TypeIds.T_JavaLangString)
0552: this .constant = expression.constant; // (String) cst is still a constant
0553: return checkUnsafeCast(scope, castType,
0554: expressionType, match, false);
0555: }
0556: match = castType
0557: .findSuperTypeWithSameErasure(expressionType);
0558: if (match != null) {
0559: tagAsNeedCheckCast();
0560: return checkUnsafeCast(scope, castType,
0561: expressionType, match, true);
0562: }
0563: return false;
0564: }
0565: }
0566: }
0567: }
0568: }
0569:
0570: /**
0571: * Check the local variable of this expression, if any, against potential NPEs
0572: * given a flow context and an upstream flow info. If so, report the risk to
0573: * the context. Marks the local as checked, which affects the flow info.
0574: * @param scope the scope of the analysis
0575: * @param flowContext the current flow context
0576: * @param flowInfo the upstream flow info; caveat: may get modified
0577: */
0578: public void checkNPE(BlockScope scope, FlowContext flowContext,
0579: FlowInfo flowInfo) {
0580: LocalVariableBinding local = this .localVariableBinding();
0581: if (local != null
0582: && (local.type.tagBits & TagBits.IsBaseType) == 0) {
0583: if ((this .bits & ASTNode.IsNonNull) == 0) {
0584: flowContext.recordUsingNullReference(scope, local,
0585: this , FlowContext.MAY_NULL, flowInfo);
0586: }
0587: flowInfo.markAsComparedEqualToNonNull(local);
0588: // from thereon it is set
0589: if (flowContext.initsOnFinally != null) {
0590: flowContext.initsOnFinally
0591: .markAsComparedEqualToNonNull(local);
0592: }
0593: }
0594: }
0595:
0596: public boolean checkUnsafeCast(Scope scope, TypeBinding castType,
0597: TypeBinding expressionType, TypeBinding match,
0598: boolean isNarrowing) {
0599: if (match == castType) {
0600: if (!isNarrowing)
0601: tagAsUnnecessaryCast(scope, castType);
0602: return true;
0603: }
0604: if (match != null
0605: && (castType.isBoundParameterizedType() || expressionType
0606: .isBoundParameterizedType())) {
0607:
0608: if (match.isProvablyDistinctFrom(
0609: isNarrowing ? expressionType : castType, 0)) {
0610: return false;
0611: }
0612: }
0613: if (!isNarrowing)
0614: tagAsUnnecessaryCast(scope, castType);
0615: return true;
0616: }
0617:
0618: /**
0619: * Base types need that the widening is explicitly done by the compiler using some bytecode like i2f.
0620: * Also check unsafe type operations.
0621: */
0622: public void computeConversion(Scope scope, TypeBinding runtimeType,
0623: TypeBinding compileTimeType) {
0624:
0625: if (runtimeType == null || compileTimeType == null)
0626: return;
0627: if (this .implicitConversion != 0)
0628: return; // already set independantly
0629:
0630: // it is possible for a Byte to be unboxed to a byte & then converted to an int
0631: // but it is not possible for a byte to become Byte & then assigned to an Integer,
0632: // or to become an int before boxed into an Integer
0633: if (runtimeType != TypeBinding.NULL && runtimeType.isBaseType()) {
0634: if (!compileTimeType.isBaseType()) {
0635: TypeBinding unboxedType = scope.environment()
0636: .computeBoxingType(compileTimeType);
0637: this .implicitConversion = TypeIds.UNBOXING;
0638: scope.problemReporter().autoboxing(this ,
0639: compileTimeType, runtimeType);
0640: compileTimeType = unboxedType;
0641: }
0642: } else if (compileTimeType != TypeBinding.NULL
0643: && compileTimeType.isBaseType()) {
0644: TypeBinding boxedType = scope.environment()
0645: .computeBoxingType(runtimeType);
0646: if (boxedType == runtimeType) // Object o = 12;
0647: boxedType = compileTimeType;
0648: this .implicitConversion = TypeIds.BOXING
0649: | (boxedType.id << 4) + compileTimeType.id;
0650: scope.problemReporter().autoboxing(this , compileTimeType,
0651: scope.environment().computeBoxingType(boxedType));
0652: return;
0653: } else if (this .constant != Constant.NotAConstant
0654: && this .constant.typeID() != TypeIds.T_JavaLangString) {
0655: this .implicitConversion = TypeIds.BOXING;
0656: return;
0657: }
0658: int compileTimeTypeID, runtimeTypeID;
0659: if ((compileTimeTypeID = compileTimeType.id) == TypeIds.NoId) { // e.g. ? extends String ==> String (103227)
0660: compileTimeTypeID = compileTimeType.erasure().id == TypeIds.T_JavaLangString ? TypeIds.T_JavaLangString
0661: : TypeIds.T_JavaLangObject;
0662: }
0663: switch (runtimeTypeID = runtimeType.id) {
0664: case T_byte:
0665: case T_short:
0666: case T_char:
0667: this .implicitConversion |= (TypeIds.T_int << 4)
0668: + compileTimeTypeID;
0669: break;
0670: case T_JavaLangString:
0671: case T_float:
0672: case T_boolean:
0673: case T_double:
0674: case T_int: //implicitConversion may result in i2i which will result in NO code gen
0675: case T_long:
0676: this .implicitConversion |= (runtimeTypeID << 4)
0677: + compileTimeTypeID;
0678: break;
0679: default: // regular object ref
0680: // if (compileTimeType.isRawType() && runtimeTimeType.isBoundParameterizedType()) {
0681: // scope.problemReporter().unsafeRawExpression(this, compileTimeType, runtimeTimeType);
0682: // }
0683: }
0684: }
0685:
0686: /**
0687: * Expression statements are plain expressions, however they generate like
0688: * normal expressions with no value required.
0689: *
0690: * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
0691: * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
0692: */
0693: public void generateCode(BlockScope currentScope,
0694: CodeStream codeStream) {
0695:
0696: if ((this .bits & ASTNode.IsReachable) == 0) {
0697: return;
0698: }
0699: generateCode(currentScope, codeStream, false);
0700: }
0701:
0702: /**
0703: * Every expression is responsible for generating its implicit conversion when necessary.
0704: *
0705: * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
0706: * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
0707: * @param valueRequired boolean
0708: */
0709: public void generateCode(BlockScope currentScope,
0710: CodeStream codeStream, boolean valueRequired) {
0711:
0712: if (this .constant != Constant.NotAConstant) {
0713: // generate a constant expression
0714: int pc = codeStream.position;
0715: codeStream.generateConstant(this .constant,
0716: this .implicitConversion);
0717: codeStream.recordPositionsFrom(pc, this .sourceStart);
0718: } else {
0719: // actual non-constant code generation
0720: throw new ShouldNotImplement(Messages.ast_missingCode);
0721: }
0722: }
0723:
0724: /**
0725: * Default generation of a boolean value
0726: * @param currentScope
0727: * @param codeStream
0728: * @param trueLabel
0729: * @param falseLabel
0730: * @param valueRequired
0731: */
0732: public void generateOptimizedBoolean(BlockScope currentScope,
0733: CodeStream codeStream, BranchLabel trueLabel,
0734: BranchLabel falseLabel, boolean valueRequired) {
0735:
0736: // a label valued to nil means: by default we fall through the case...
0737: // both nil means we leave the value on the stack
0738:
0739: Constant cst = this .optimizedBooleanConstant();
0740: generateCode(currentScope, codeStream, valueRequired
0741: && cst == Constant.NotAConstant);
0742: if ((cst != Constant.NotAConstant)
0743: && (cst.typeID() == TypeIds.T_boolean)) {
0744: int pc = codeStream.position;
0745: if (cst.booleanValue() == true) {
0746: // constant == true
0747: if (valueRequired) {
0748: if (falseLabel == null) {
0749: // implicit falling through the FALSE case
0750: if (trueLabel != null) {
0751: codeStream.goto_(trueLabel);
0752: }
0753: }
0754: }
0755: } else {
0756: if (valueRequired) {
0757: if (falseLabel != null) {
0758: // implicit falling through the TRUE case
0759: if (trueLabel == null) {
0760: codeStream.goto_(falseLabel);
0761: }
0762: }
0763: }
0764: }
0765: codeStream.recordPositionsFrom(pc, this .sourceStart);
0766: return;
0767: }
0768: // branching
0769: int position = codeStream.position;
0770: if (valueRequired) {
0771: if (falseLabel == null) {
0772: if (trueLabel != null) {
0773: // Implicit falling through the FALSE case
0774: codeStream.ifne(trueLabel);
0775: }
0776: } else {
0777: if (trueLabel == null) {
0778: // Implicit falling through the TRUE case
0779: codeStream.ifeq(falseLabel);
0780: } else {
0781: // No implicit fall through TRUE/FALSE --> should never occur
0782: }
0783: }
0784: }
0785: // reposition the endPC
0786: codeStream.updateLastRecordedEndPC(currentScope, position);
0787: }
0788:
0789: /* Optimized (java) code generation for string concatenations that involve StringBuffer
0790: * creation: going through this path means that there is no need for a new StringBuffer
0791: * creation, further operands should rather be only appended to the current one.
0792: * By default: no optimization.
0793: */
0794: public void generateOptimizedStringConcatenation(
0795: BlockScope blockScope, CodeStream codeStream, int typeID) {
0796:
0797: if (typeID == TypeIds.T_JavaLangString
0798: && this .constant != Constant.NotAConstant
0799: && this .constant.stringValue().length() == 0) {
0800: return; // optimize str + ""
0801: }
0802: generateCode(blockScope, codeStream, true);
0803: codeStream.invokeStringConcatenationAppendForType(typeID);
0804: }
0805:
0806: /* Optimized (java) code generation for string concatenations that involve StringBuffer
0807: * creation: going through this path means that there is no need for a new StringBuffer
0808: * creation, further operands should rather be only appended to the current one.
0809: */
0810: public void generateOptimizedStringConcatenationCreation(
0811: BlockScope blockScope, CodeStream codeStream, int typeID) {
0812:
0813: codeStream.newStringContatenation();
0814: codeStream.dup();
0815: switch (typeID) {
0816: case T_JavaLangObject:
0817: case T_undefined:
0818: // in the case the runtime value of valueOf(Object) returns null, we have to use append(Object) instead of directly valueOf(Object)
0819: // append(Object) returns append(valueOf(Object)), which means that the null case is handled by the next case.
0820: codeStream.invokeStringConcatenationDefaultConstructor();
0821: generateCode(blockScope, codeStream, true);
0822: codeStream
0823: .invokeStringConcatenationAppendForType(TypeIds.T_JavaLangObject);
0824: return;
0825: case T_JavaLangString:
0826: case T_null:
0827: if (this .constant != Constant.NotAConstant) {
0828: String stringValue = this .constant.stringValue();
0829: if (stringValue.length() == 0) { // optimize ""+<str>
0830: codeStream
0831: .invokeStringConcatenationDefaultConstructor();
0832: return;
0833: }
0834: codeStream.ldc(stringValue);
0835: } else {
0836: // null case is not a constant
0837: generateCode(blockScope, codeStream, true);
0838: codeStream
0839: .invokeStringValueOf(TypeIds.T_JavaLangObject);
0840: }
0841: break;
0842: default:
0843: generateCode(blockScope, codeStream, true);
0844: codeStream.invokeStringValueOf(typeID);
0845: }
0846: codeStream.invokeStringConcatenationStringConstructor();
0847: }
0848:
0849: private MethodBinding[] getAllInheritedMethods(
0850: ReferenceBinding binding) {
0851: ArrayList collector = new ArrayList();
0852: getAllInheritedMethods0(binding, collector);
0853: return (MethodBinding[]) collector
0854: .toArray(new MethodBinding[collector.size()]);
0855: }
0856:
0857: private void getAllInheritedMethods0(ReferenceBinding binding,
0858: ArrayList collector) {
0859: if (!binding.isInterface())
0860: return;
0861: MethodBinding[] methodBindings = binding.methods();
0862: for (int i = 0, max = methodBindings.length; i < max; i++) {
0863: collector.add(methodBindings[i]);
0864: }
0865: ReferenceBinding[] super Interfaces = binding.super Interfaces();
0866: for (int i = 0, max = super Interfaces.length; i < max; i++) {
0867: getAllInheritedMethods0(super Interfaces[i], collector);
0868: }
0869: }
0870:
0871: public boolean isCompactableOperation() {
0872:
0873: return false;
0874: }
0875:
0876: //Return true if the conversion is done AUTOMATICALLY by the vm
0877: //while the javaVM is an int based-machine, thus for example pushing
0878: //a byte onto the stack , will automatically create an int on the stack
0879: //(this request some work d be done by the VM on signed numbers)
0880: public boolean isConstantValueOfTypeAssignableToType(
0881: TypeBinding constantType, TypeBinding targetType) {
0882:
0883: if (this .constant == Constant.NotAConstant)
0884: return false;
0885: if (constantType == targetType)
0886: return true;
0887: if (constantType.isBaseType() && targetType.isBaseType()) {
0888: //No free assignment conversion from anything but to integral ones.
0889: if ((constantType == TypeBinding.INT || BaseTypeBinding
0890: .isWidening(TypeIds.T_int, constantType.id))
0891: && (BaseTypeBinding.isNarrowing(targetType.id,
0892: TypeIds.T_int))) {
0893: //use current explicit conversion in order to get some new value to compare with current one
0894: return isConstantValueRepresentable(this .constant,
0895: constantType.id, targetType.id);
0896: }
0897: }
0898: return false;
0899: }
0900:
0901: public boolean isTypeReference() {
0902: return false;
0903: }
0904:
0905: /**
0906: * Returns the local variable referenced by this node. Can be a direct reference (SingleNameReference)
0907: * or thru a cast expression etc...
0908: */
0909: public LocalVariableBinding localVariableBinding() {
0910: return null;
0911: }
0912:
0913: /**
0914: * Mark this expression as being non null, per a specific tag in the
0915: * source code.
0916: */
0917: // this is no more called for now, waiting for inter procedural null reference analysis
0918: public void markAsNonNull() {
0919: this .bits |= ASTNode.IsNonNull;
0920: }
0921:
0922: public int nullStatus(FlowInfo flowInfo) {
0923:
0924: if (/* (this.bits & IsNonNull) != 0 || */
0925: this .constant != null && this .constant != Constant.NotAConstant)
0926: return FlowInfo.NON_NULL; // constant expression cannot be null
0927:
0928: LocalVariableBinding local = localVariableBinding();
0929: if (local != null) {
0930: if (flowInfo.isDefinitelyNull(local))
0931: return FlowInfo.NULL;
0932: if (flowInfo.isDefinitelyNonNull(local))
0933: return FlowInfo.NON_NULL;
0934: return FlowInfo.UNKNOWN;
0935: }
0936: return FlowInfo.NON_NULL;
0937: }
0938:
0939: /**
0940: * Constant usable for bytecode pattern optimizations, but cannot be inlined
0941: * since it is not strictly equivalent to the definition of constant expressions.
0942: * In particular, some side-effects may be required to occur (only the end value
0943: * is known).
0944: * @return Constant known to be of boolean type
0945: */
0946: public Constant optimizedBooleanConstant() {
0947: return this .constant;
0948: }
0949:
0950: /**
0951: * Returns the type of the expression after required implicit conversions. When expression type gets promoted
0952: * or inserted a generic cast, the converted type will differ from the resolved type (surface side-effects from
0953: * #computeConversion(...)).
0954: * @return the type after implicit conversion
0955: */
0956: public TypeBinding postConversionType(Scope scope) {
0957: TypeBinding convertedType = this .resolvedType;
0958: int runtimeType = (this .implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4;
0959: switch (runtimeType) {
0960: case T_boolean:
0961: convertedType = TypeBinding.BOOLEAN;
0962: break;
0963: case T_byte:
0964: convertedType = TypeBinding.BYTE;
0965: break;
0966: case T_short:
0967: convertedType = TypeBinding.SHORT;
0968: break;
0969: case T_char:
0970: convertedType = TypeBinding.CHAR;
0971: break;
0972: case T_int:
0973: convertedType = TypeBinding.INT;
0974: break;
0975: case T_float:
0976: convertedType = TypeBinding.FLOAT;
0977: break;
0978: case T_long:
0979: convertedType = TypeBinding.LONG;
0980: break;
0981: case T_double:
0982: convertedType = TypeBinding.DOUBLE;
0983: break;
0984: default:
0985: }
0986: if ((this .implicitConversion & TypeIds.BOXING) != 0) {
0987: convertedType = scope.environment().computeBoxingType(
0988: convertedType);
0989: }
0990: return convertedType;
0991: }
0992:
0993: public StringBuffer print(int indent, StringBuffer output) {
0994: printIndent(indent, output);
0995: return printExpression(indent, output);
0996: }
0997:
0998: public abstract StringBuffer printExpression(int indent,
0999: StringBuffer output);
1000:
1001: public StringBuffer printStatement(int indent, StringBuffer output) {
1002: return print(indent, output).append(";"); //$NON-NLS-1$
1003: }
1004:
1005: public void resolve(BlockScope scope) {
1006: // drops the returning expression's type whatever the type is.
1007:
1008: this .resolveType(scope);
1009: return;
1010: }
1011:
1012: /**
1013: * Resolve the type of this expression in the context of a blockScope
1014: *
1015: * @param scope
1016: * @return
1017: * Return the actual type of this expression after resolution
1018: */
1019: public TypeBinding resolveType(BlockScope scope) {
1020: // by default... subclasses should implement a better TB if required.
1021: return null;
1022: }
1023:
1024: /**
1025: * Resolve the type of this expression in the context of a classScope
1026: *
1027: * @param scope
1028: * @return
1029: * Return the actual type of this expression after resolution
1030: */
1031: public TypeBinding resolveType(ClassScope scope) {
1032: // by default... subclasses should implement a better TB if required.
1033: return null;
1034: }
1035:
1036: public TypeBinding resolveTypeExpecting(BlockScope scope,
1037: TypeBinding expectedType) {
1038:
1039: this .setExpectedType(expectedType); // needed in case of generic method invocation
1040: TypeBinding expressionType = this .resolveType(scope);
1041: if (expressionType == null)
1042: return null;
1043: if (expressionType == expectedType)
1044: return expressionType;
1045:
1046: if (!expressionType.isCompatibleWith(expectedType)) {
1047: if (scope.isBoxingCompatibleWith(expressionType,
1048: expectedType)) {
1049: this .computeConversion(scope, expectedType,
1050: expressionType);
1051: } else {
1052: scope.problemReporter().typeMismatchError(
1053: expressionType, expectedType, this );
1054: return null;
1055: }
1056: }
1057: return expressionType;
1058: }
1059:
1060: /**
1061: * Returns an object which can be used to identify identical JSR sequence targets
1062: * (see TryStatement subroutine codegen)
1063: * or <code>null</null> if not reusable
1064: */
1065: public Object reusableJSRTarget() {
1066: if (this .constant != Constant.NotAConstant)
1067: return this .constant;
1068: return null;
1069: }
1070:
1071: /**
1072: * Record the type expectation before this expression is typechecked.
1073: * e.g. String s = foo();, foo() will be tagged as being expected of type String
1074: * Used to trigger proper inference of generic method invocations.
1075: *
1076: * @param expectedType
1077: * The type denoting an expectation in the context of an assignment conversion
1078: */
1079: public void setExpectedType(TypeBinding expectedType) {
1080: // do nothing by default
1081: }
1082:
1083: public void tagAsNeedCheckCast() {
1084: // do nothing by default
1085: }
1086:
1087: /**
1088: * Record the fact a cast expression got detected as being unnecessary.
1089: *
1090: * @param scope
1091: * @param castType
1092: */
1093: public void tagAsUnnecessaryCast(Scope scope, TypeBinding castType) {
1094: // do nothing by default
1095: }
1096:
1097: public Expression toTypeReference() {
1098: //by default undefined
1099:
1100: //this method is meanly used by the parser in order to transform
1101: //an expression that is used as a type reference in a cast ....
1102: //--appreciate the fact that castExpression and ExpressionWithParenthesis
1103: //--starts with the same pattern.....
1104:
1105: return this ;
1106: }
1107:
1108: /**
1109: * Traverse an expression in the context of a blockScope
1110: * @param visitor
1111: * @param scope
1112: */
1113: public void traverse(ASTVisitor visitor, BlockScope scope) {
1114: // nothing to do
1115: }
1116:
1117: /**
1118: * Traverse an expression in the context of a classScope
1119: * @param visitor
1120: * @param scope
1121: */
1122: public void traverse(ASTVisitor visitor, ClassScope scope) {
1123: // nothing to do
1124: }
1125: }
|