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 9c7da62..ad9c88a 100644 (file)
+/*******************************************************************************
+ * 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 v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
 package net.sourceforge.phpdt.internal.compiler.ast;
 
-/**
- * This is a cast expression.
- * @author Matthieu Casanova
- */
+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;
+import net.sourceforge.phpdt.internal.compiler.lookup.ArrayBinding;
+import net.sourceforge.phpdt.internal.compiler.lookup.BaseTypeBinding;
+import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
+import net.sourceforge.phpdt.internal.compiler.lookup.MethodBinding;
+import net.sourceforge.phpdt.internal.compiler.lookup.ReferenceBinding;
+import net.sourceforge.phpdt.internal.compiler.lookup.Scope;
+import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
+
 public class CastExpression extends Expression {
 
-  /** The type in which we cast the expression. */
-  public ConstantIdentifier type;
-
-  /** The expression to be casted. */
-  public Expression expression;
-
-  /**
-   * Create a cast expression.
-   * @param type the type
-   * @param expression the expression
-   * @param sourceStart starting offset
-   * @param sourceEnd ending offset
-   */
-  public CastExpression(ConstantIdentifier type,
-                        Expression expression,
-                        int sourceStart,
-                        int sourceEnd) {
-    super(sourceStart, sourceEnd);
-    this.type = type;
-    this.expression = expression;
-  }
-
-  /**
-   * Return the expression as String.
-   * @return the expression
-   */
-  public String toStringExpression() {
-    final StringBuffer buff = new StringBuffer("(");
-    buff.append(type.toStringExpression());
-    buff.append(") ");
-    buff.append(expression.toStringExpression());
-    return buff.toString();
-  }
+       public Expression expression;
+
+       public Expression type;
+
+       public boolean needRuntimeCheckcast;
+
+       // 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.......
+
+               // :-( .............
+
+               // 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) {
+
+               return expression.analyseCode(currentScope, flowContext, flowInfo)
+                               .unconditionalInits();
+       }
+
+       public final void areTypesCastCompatible(BlockScope scope,
+                       TypeBinding castType, TypeBinding expressionType) {
+
+               // see specifications 5.5
+               // handle errors and process constant when needed
+
+               // if either one of the type is null ==>
+               // some error has been already reported some where ==>
+               // we then do not report an obvious-cascade-error.
+
+               needRuntimeCheckcast = false;
+               if (castType == null || expressionType == null)
+                       return;
+
+               // 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 (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);
+                                       return;
+                               }
+                       }
+                       scope.problemReporter().typeCastError(this, castType,
+                                       expressionType);
+                       return;
+               }
+
+               // -----------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 (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, castType,
+                                                               expressionType);
+                                       return;
+                               }
+                               // recursively on the elements...
+                               areTypesCastCompatible(scope, ((ArrayBinding) castType)
+                                               .elementsType(scope), exprElementType);
+                               return;
+                       } else if (castType.isClass()) {
+                               // ------(castType.isClass) expressionType.isArray
+                               // ---------------
+                               if (scope.isJavaLangObject(castType))
+                                       return;
+                       } else { // ------- (castType.isInterface) expressionType.isArray
+                                               // -----------
+                               if (scope.isJavaLangCloneable(castType)
+                                               || scope.isJavaIoSerializable(castType)) {
+                                       needRuntimeCheckcast = true;
+                                       return;
+                               }
+                       }
+                       scope.problemReporter().typeCastError(this, castType,
+                                       expressionType);
+                       return;
+               }
+
+               if (expressionType.isClass()) {
+                       if (castType.isArrayType()) {
+                               // ---- (castType.isArray) expressionType.isClass -------
+                               if (scope.isJavaLangObject(expressionType)) { // potential
+                                                                                                                               // runtime error
+                                       needRuntimeCheckcast = true;
+                                       return;
+                               }
+                       } 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 (castType.isCompatibleWith(expressionType)) {
+                                       // potential runtime error
+                                       needRuntimeCheckcast = true;
+                                       return;
+                               }
+                       } 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
+                                       needRuntimeCheckcast = true;
+                                       return;
+                               }
+                       }
+                       scope.problemReporter().typeCastError(this, castType,
+                                       expressionType);
+                       return;
+               }
+
+               // 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, castType,
+                                               expressionType);
+                       return;
+               } else if (castType.isClass()) { // ----- (castType.isClass)
+                                                                                       // expressionType.isInterface
+                                                                                       // --------
+                       if (scope.isJavaLangObject(castType)) // no runtime error
+                               return;
+                       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, castType,
+                                                       expressionType);
+                                       return;
+                               }
+                       }
+               } 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;
+               return;
+       }
+
+       /**
+        * Cast expression code generation
+        * 
+        * @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(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;
+               }
+               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
+               // any kind of Expression <-- this last one is invalid.......
+
+               constant = Constant.NotAConstant;
+               implicitConversion = T_undefined;
+               if ((type instanceof TypeReference) || (type instanceof NameReference)) {
+                       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;
+                       scope.problemReporter().invalidTypeReference(type);
+                       return null;
+               }
+       }
+
+       public String toStringExpression() {
+
+               return "(" + type.toString(0) + ") " + //$NON-NLS-2$ //$NON-NLS-1$
+                               expression.toStringExpression();
+       }
+
+       public void traverse(ASTVisitor visitor, BlockScope blockScope) {
+
+               if (visitor.visit(this, blockScope)) {
+                       type.traverse(visitor, blockScope);
+                       expression.traverse(visitor, blockScope);
+               }
+               visitor.endVisit(this, blockScope);
+       }
 }