1) Moved net.sourceforge.phpeclipse.ui\src\net\sourceforge\phpdt back to net.sourcefo...
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / ast / CastExpression.java
index e103ccc..ad9c88a 100644 (file)
@@ -1,17 +1,16 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v0.5 
+ * are made available under the terms of the Common Public License v1.0
  * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v05.html
+ * http://www.eclipse.org/legal/cpl-v10.html
  * 
  * Contributors:
  *     IBM Corporation - initial API and implementation
- ******************************************************************************/
+ *******************************************************************************/
 package net.sourceforge.phpdt.internal.compiler.ast;
 
-import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor;
-import net.sourceforge.phpdt.internal.compiler.codegen.CodeStream;
+import net.sourceforge.phpdt.internal.compiler.ASTVisitor;
 import net.sourceforge.phpdt.internal.compiler.flow.FlowContext;
 import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
 import net.sourceforge.phpdt.internal.compiler.impl.Constant;
@@ -26,47 +25,45 @@ import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
 public class CastExpression extends Expression {
 
        public Expression expression;
+
        public Expression type;
+
        public boolean needRuntimeCheckcast;
-       public TypeBinding castTb;
 
-       //expression.implicitConversion holds the cast for baseType casting 
+       // expression.implicitConversion holds the cast for baseType casting
        public CastExpression(Expression e, Expression t) {
                expression = e;
                type = t;
 
-               //due to the fact an expression may start with ( and that a cast also start with (
-               //the field is an expression....it can be a TypeReference OR a NameReference Or
-               //an expression <--this last one is invalid.......
+               // due to the fact an expression may start with ( and that a cast also
+               // start with (
+               // the field is an expression....it can be a TypeReference OR a
+               // NameReference Or
+               // an expression <--this last one is invalid.......
 
                // :-( .............
 
-               //if (type instanceof TypeReference )
-               //      flag = IsTypeReference ;
-               //else
-               //      if (type instanceof NameReference)
-               //              flag = IsNameReference ;
-               //      else
-               //              flag = IsExpression ;
+               // if (type instanceof TypeReference )
+               // flag = IsTypeReference ;
+               // else
+               // if (type instanceof NameReference)
+               // flag = IsNameReference ;
+               // else
+               // flag = IsExpression ;
 
        }
 
-       public FlowInfo analyseCode(
-               BlockScope currentScope,
-               FlowContext flowContext,
-               FlowInfo flowInfo) {
+       public FlowInfo analyseCode(BlockScope currentScope,
+                       FlowContext flowContext, FlowInfo flowInfo) {
 
-               return expression
-                       .analyseCode(currentScope, flowContext, flowInfo)
-                       .unconditionalInits();
+               return expression.analyseCode(currentScope, flowContext, flowInfo)
+                               .unconditionalInits();
        }
 
-       public final void areTypesCastCompatible(
-               BlockScope scope,
-               TypeBinding castTb,
-               TypeBinding expressionTb) {
+       public final void areTypesCastCompatible(BlockScope scope,
+                       TypeBinding castType, TypeBinding expressionType) {
 
-               // see specifications p.68
+               // see specifications 5.5
                // handle errors and process constant when needed
 
                // if either one of the type is null ==>
@@ -74,134 +71,176 @@ public class CastExpression extends Expression {
                // we then do not report an obvious-cascade-error.
 
                needRuntimeCheckcast = false;
-               if (castTb == null || expressionTb == null)
+               if (castType == null || expressionType == null)
                        return;
-               if (castTb.isBaseType()) {
-                       if (expressionTb.isBaseType()) {
-                               if (expressionTb == castTb) {
-                                       constant = expression.constant; //use the same constant
+
+               // identity conversion cannot be performed upfront, due to side-effects
+               // like constant propagation
+
+               if (castType.isBaseType()) {
+                       if (expressionType.isBaseType()) {
+                               if (expressionType == castType) {
+                                       expression.implicitWidening(castType, expressionType);
+                                       constant = expression.constant; // use the same constant
                                        return;
                                }
-                               if (BlockScope.areTypesCompatible(expressionTb, castTb)
-                                       || BaseTypeBinding.isNarrowing(castTb.id, expressionTb.id)) {
-                                       expression.implicitConversion = (castTb.id << 4) + expressionTb.id;
+                               if (expressionType.isCompatibleWith(castType)
+                                               || BaseTypeBinding.isNarrowing(castType.id,
+                                                               expressionType.id)) {
+                                       expression.implicitConversion = (castType.id << 4)
+                                                       + expressionType.id;
                                        if (expression.constant != Constant.NotAConstant)
-                                               constant = expression.constant.castTo(expression.implicitConversion);
+                                               constant = expression.constant
+                                                               .castTo(expression.implicitConversion);
                                        return;
                                }
                        }
-                       scope.problemReporter().typeCastError(this, castTb, expressionTb);
+                       scope.problemReporter().typeCastError(this, castType,
+                                       expressionType);
                        return;
                }
 
-               //-----------cast to something which is NOT a base type--------------------------       
-               if (expressionTb == NullBinding)
-                       return; //null is compatible with every thing
-
-               if (expressionTb.isBaseType()) {
-                       scope.problemReporter().typeCastError(this, castTb, expressionTb);
+               // -----------cast to something which is NOT a base
+               // type--------------------------
+               if (expressionType == NullBinding) {
+                       // if (castType.isArrayType()){ // 26903 - need checkcast when
+                       // casting null to array type
+                       // needRuntimeCheckcast = true;
+                       // }
+                       return; // null is compatible with every thing
+               }
+               if (expressionType.isBaseType()) {
+                       scope.problemReporter().typeCastError(this, castType,
+                                       expressionType);
                        return;
                }
 
-               if (expressionTb.isArrayType()) {
-                       if (castTb.isArrayType()) {
-                               //------- (castTb.isArray) expressionTb.isArray -----------
-                               TypeBinding expressionEltTb = ((ArrayBinding) expressionTb).elementsType(scope);
-                               if (expressionEltTb.isBaseType()) {
-                                       // <---stop the recursion------- 
-                                       if (((ArrayBinding) castTb).elementsType(scope) == expressionEltTb)
+               if (expressionType.isArrayType()) {
+                       if (castType == expressionType)
+                               return; // identity conversion
+
+                       if (castType.isArrayType()) {
+                               // ------- (castType.isArray) expressionType.isArray -----------
+                               TypeBinding exprElementType = ((ArrayBinding) expressionType)
+                                               .elementsType(scope);
+                               if (exprElementType.isBaseType()) {
+                                       // <---stop the recursion-------
+                                       if (((ArrayBinding) castType).elementsType(scope) == exprElementType)
                                                needRuntimeCheckcast = true;
                                        else
-                                               scope.problemReporter().typeCastError(this, castTb, expressionTb);
+                                               scope.problemReporter().typeCastError(this, castType,
+                                                               expressionType);
                                        return;
                                }
                                // recursively on the elements...
-                               areTypesCastCompatible(
-                                       scope,
-                                       ((ArrayBinding) castTb).elementsType(scope),
-                                       expressionEltTb);
+                               areTypesCastCompatible(scope, ((ArrayBinding) castType)
+                                               .elementsType(scope), exprElementType);
                                return;
-                       } else if (
-                               castTb.isClass()) {
-                               //------(castTb.isClass) expressionTb.isArray ---------------   
-                               if (scope.isJavaLangObject(castTb))
+                       } else if (castType.isClass()) {
+                               // ------(castType.isClass) expressionType.isArray
+                               // ---------------
+                               if (scope.isJavaLangObject(castType))
                                        return;
-                       } else { //------- (castTb.isInterface) expressionTb.isArray -----------
-                               if (scope.isJavaLangCloneable(castTb) || scope.isJavaIoSerializable(castTb)) {
+                       } else { // ------- (castType.isInterface) expressionType.isArray
+                                               // -----------
+                               if (scope.isJavaLangCloneable(castType)
+                                               || scope.isJavaIoSerializable(castType)) {
                                        needRuntimeCheckcast = true;
                                        return;
                                }
                        }
-                       scope.problemReporter().typeCastError(this, castTb, expressionTb);
+                       scope.problemReporter().typeCastError(this, castType,
+                                       expressionType);
                        return;
                }
 
-               if (expressionTb.isClass()) {
-                       if (castTb.isArrayType()) {
-                               // ---- (castTb.isArray) expressionTb.isClass -------
-                               if (scope.isJavaLangObject(expressionTb)) { // potential runtime error
+               if (expressionType.isClass()) {
+                       if (castType.isArrayType()) {
+                               // ---- (castType.isArray) expressionType.isClass -------
+                               if (scope.isJavaLangObject(expressionType)) { // potential
+                                                                                                                               // runtime error
                                        needRuntimeCheckcast = true;
                                        return;
                                }
-                       } else if (
-                               castTb.isClass()) { // ----- (castTb.isClass) expressionTb.isClass ------
-                               if (BlockScope.areTypesCompatible(expressionTb, castTb)) // no runtime error
+                       } else if (castType.isClass()) { // ----- (castType.isClass)
+                                                                                               // expressionType.isClass ------
+                               if (expressionType.isCompatibleWith(castType)) { // no
+                                                                                                                                       // runtime
+                                                                                                                                       // error
+                                       if (castType.id == T_String)
+                                               constant = expression.constant; // (String) cst is still
+                                                                                                               // a constant
                                        return;
-                               if (BlockScope.areTypesCompatible(castTb, expressionTb)) {
-                                       // potential runtime  error
+                               }
+                               if (castType.isCompatibleWith(expressionType)) {
+                                       // potential runtime error
                                        needRuntimeCheckcast = true;
                                        return;
                                }
-                       } else { // ----- (castTb.isInterface) expressionTb.isClass -------  
-                               if (((ReferenceBinding) expressionTb).isFinal()) {
-                                       // no subclass for expressionTb, thus compile-time check is valid
-                                       if (BlockScope.areTypesCompatible(expressionTb, castTb))
+                       } else { // ----- (castType.isInterface) expressionType.isClass
+                                               // -------
+                               if (((ReferenceBinding) expressionType).isFinal()) {
+                                       // no subclass for expressionType, thus compile-time check
+                                       // is valid
+                                       if (expressionType.isCompatibleWith(castType))
                                                return;
-                               } else { // a subclass may implement the interface ==> no check at compile time
+                               } else { // a subclass may implement the interface ==> no
+                                                       // check at compile time
                                        needRuntimeCheckcast = true;
                                        return;
                                }
                        }
-                       scope.problemReporter().typeCastError(this, castTb, expressionTb);
+                       scope.problemReporter().typeCastError(this, castType,
+                                       expressionType);
                        return;
                }
 
-               //      if (expressionTb.isInterface()) { cannot be anything else
-               if (castTb.isArrayType()) {
-                       // ----- (castTb.isArray) expressionTb.isInterface ------
-                       if (scope.isJavaLangCloneable(expressionTb)
-                               || scope.isJavaIoSerializable(expressionTb)) // potential runtime error
+               // if (expressionType.isInterface()) { cannot be anything else
+               if (castType.isArrayType()) {
+                       // ----- (castType.isArray) expressionType.isInterface ------
+                       if (scope.isJavaLangCloneable(expressionType)
+                                       || scope.isJavaIoSerializable(expressionType)) // potential
+                                                                                                                                       // runtime
+                                                                                                                                       // error
                                needRuntimeCheckcast = true;
                        else
-                               scope.problemReporter().typeCastError(this, castTb, expressionTb);
+                               scope.problemReporter().typeCastError(this, castType,
+                                               expressionType);
                        return;
-               } else if (
-                       castTb.isClass()) { // ----- (castTb.isClass) expressionTb.isInterface --------
-                       if (scope.isJavaLangObject(castTb)) // no runtime error
+               } else if (castType.isClass()) { // ----- (castType.isClass)
+                                                                                       // expressionType.isInterface
+                                                                                       // --------
+                       if (scope.isJavaLangObject(castType)) // no runtime error
                                return;
-                       if (((ReferenceBinding) castTb).isFinal()) {
-                               // no subclass for castTb, thus compile-time check is valid
-                               if (!BlockScope.areTypesCompatible(castTb, expressionTb)) {
+                       if (((ReferenceBinding) castType).isFinal()) {
+                               // no subclass for castType, thus compile-time check is valid
+                               if (!castType.isCompatibleWith(expressionType)) {
                                        // potential runtime error
-                                       scope.problemReporter().typeCastError(this, castTb, expressionTb);
+                                       scope.problemReporter().typeCastError(this, castType,
+                                                       expressionType);
                                        return;
                                }
                        }
-               } else { // ----- (castTb.isInterface) expressionTb.isInterface -------
-                       if (castTb != expressionTb
-                               && (Scope.compareTypes(castTb, expressionTb) == NotRelated)) {
-                               MethodBinding[] castTbMethods = ((ReferenceBinding) castTb).methods();
-                               MethodBinding[] expressionTbMethods =
-                                       ((ReferenceBinding) expressionTb).methods();
-                               int exprMethodsLength = expressionTbMethods.length;
-                               for (int i = 0, castMethodsLength = castTbMethods.length;
-                                       i < castMethodsLength;
-                                       i++)
-                                       for (int j = 0; j < exprMethodsLength; j++)
-                                               if (castTbMethods[i].returnType != expressionTbMethods[j].returnType)
-                                                       if (castTbMethods[i].selector == expressionTbMethods[j].selector)
-                                                               if (castTbMethods[i].areParametersEqual(expressionTbMethods[j]))
-                                                                       scope.problemReporter().typeCastError(this, castTb, expressionTb);
+               } else { // ----- (castType.isInterface) expressionType.isInterface
+                                       // -------
+                       if (castType == expressionType)
+                               return; // identity conversion
+                       if (Scope.compareTypes(castType, expressionType) == NotRelated) {
+                               MethodBinding[] castTypeMethods = ((ReferenceBinding) castType)
+                                               .methods();
+                               MethodBinding[] expressionTypeMethods = ((ReferenceBinding) expressionType)
+                                               .methods();
+                               int exprMethodsLength = expressionTypeMethods.length;
+                               for (int i = 0, castMethodsLength = castTypeMethods.length; i < castMethodsLength; i++)
+                                       for (int j = 0; j < exprMethodsLength; j++) {
+                                               if ((castTypeMethods[i].returnType != expressionTypeMethods[j].returnType)
+                                                               && (castTypeMethods[i].selector == expressionTypeMethods[j].selector)
+                                                               && castTypeMethods[i]
+                                                                               .areParametersEqual(expressionTypeMethods[j])) {
+                                                       scope.problemReporter().typeCastError(this,
+                                                                       castType, expressionType);
+                                               }
+                                       }
                        }
                }
                needRuntimeCheckcast = true;
@@ -210,64 +249,86 @@ public class CastExpression extends Expression {
 
        /**
         * Cast expression code generation
-        *
-        * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
-        * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
-        * @param valueRequired boolean
+        * 
+        * @param currentScope
+        *            net.sourceforge.phpdt.internal.compiler.lookup.BlockScope
+        * @param codeStream
+        *            net.sourceforge.phpdt.internal.compiler.codegen.CodeStream
+        * @param valueRequired
+        *            boolean
         */
-       public void generateCode(
-               BlockScope currentScope,
-               CodeStream codeStream,
-               boolean valueRequired) {
-
-               int pc = codeStream.position;
-               if (constant != NotAConstant) {
-                       if (valueRequired
-                               || needRuntimeCheckcast) { // Added for: 1F1W9IG: IVJCOM:WINNT - Compiler omits casting check
-                               codeStream.generateConstant(constant, implicitConversion);
-                               if (needRuntimeCheckcast) {
-                                       codeStream.checkcast(castTb);
-                                       if (!valueRequired)
-                                               codeStream.pop();
-                               }
-                       }
-                       codeStream.recordPositionsFrom(pc, this.sourceStart);
-                       return;
-               }
-               expression.generateCode(
-                       currentScope,
-                       codeStream,
-                       valueRequired || needRuntimeCheckcast);
-               if (needRuntimeCheckcast) {
-                       codeStream.checkcast(castTb);
-                       if (!valueRequired)
-                               codeStream.pop();
-               } else {
-                       if (valueRequired)
-                               codeStream.generateImplicitConversion(implicitConversion);
+       // public void generateCode(
+       // BlockScope currentScope,
+       // CodeStream codeStream,
+       // boolean valueRequired) {
+       //
+       // int pc = codeStream.position;
+       // if (constant != NotAConstant) {
+       // if (valueRequired
+       // || needRuntimeCheckcast) { // Added for: 1F1W9IG: IVJCOM:WINNT - Compiler
+       // omits casting check
+       // codeStream.generateConstant(constant, implicitConversion);
+       // if (needRuntimeCheckcast) {
+       // codeStream.checkcast(this.resolvedType);
+       // if (!valueRequired)
+       // codeStream.pop();
+       // }
+       // }
+       // codeStream.recordPositionsFrom(pc, this.sourceStart);
+       // return;
+       // }
+       // expression.generateCode(
+       // currentScope,
+       // codeStream,
+       // valueRequired || needRuntimeCheckcast);
+       // if (needRuntimeCheckcast) {
+       // codeStream.checkcast(this.resolvedType);
+       // if (!valueRequired)
+       // codeStream.pop();
+       // } else {
+       // if (valueRequired)
+       // codeStream.generateImplicitConversion(implicitConversion);
+       // }
+       // codeStream.recordPositionsFrom(pc, this.sourceStart);
+       // }
+       public Expression innermostCastedExpression() {
+               Expression current = this.expression;
+               while (current instanceof CastExpression) {
+                       current = ((CastExpression) current).expression;
                }
-               codeStream.recordPositionsFrom(pc, this.sourceStart);
+               return current;
+       }
+
+       public StringBuffer printExpression(int indent, StringBuffer output) {
+
+               output.append('(');
+               type.print(0, output).append(") "); //$NON-NLS-1$
+               return expression.printExpression(0, output);
        }
 
        public TypeBinding resolveType(BlockScope scope) {
                // compute a new constant if the cast is effective
 
-               // due to the fact an expression may start with ( and that a cast can also start with (
-               // the field is an expression....it can be a TypeReference OR a NameReference Or
+               // due to the fact an expression may start with ( and that a cast can
+               // also start with (
+               // the field is an expression....it can be a TypeReference OR a
+               // NameReference Or
                // any kind of Expression <-- this last one is invalid.......
 
                constant = Constant.NotAConstant;
                implicitConversion = T_undefined;
-               TypeBinding expressionTb = expression.resolveType(scope);
-               if (expressionTb == null)
-                       return null;
-
                if ((type instanceof TypeReference) || (type instanceof NameReference)) {
-                       if ((castTb = type.resolveType(scope)) == null)
+                       this.resolvedType = type.resolveType(scope);
+                       TypeBinding castedExpressionType = expression.resolveType(scope);
+                       if (this.resolvedType != null && castedExpressionType != null) {
+                               areTypesCastCompatible(scope, this.resolvedType,
+                                               castedExpressionType);
+                       }
+                       return this.resolvedType;
+               } else { // expression as a cast !!!!!!!!
+                       TypeBinding castedExpressionType = expression.resolveType(scope);
+                       if (castedExpressionType == null)
                                return null;
-                       areTypesCastCompatible(scope, castTb, expressionTb);
-                       return castTb;
-               } else { // expression as a cast !!!!!!!! 
                        scope.problemReporter().invalidTypeReference(type);
                        return null;
                }
@@ -276,12 +337,10 @@ public class CastExpression extends Expression {
        public String toStringExpression() {
 
                return "(" + type.toString(0) + ") " + //$NON-NLS-2$ //$NON-NLS-1$
-               expression.toStringExpression();
+                               expression.toStringExpression();
        }
 
-       public void traverse(
-               IAbstractSyntaxTreeVisitor visitor,
-               BlockScope blockScope) {
+       public void traverse(ASTVisitor visitor, BlockScope blockScope) {
 
                if (visitor.visit(this, blockScope)) {
                        type.traverse(visitor, blockScope);
@@ -289,4 +348,4 @@ public class CastExpression extends Expression {
                }
                visitor.endVisit(this, blockScope);
        }
-}
\ No newline at end of file
+}