X-Git-Url: http://git.phpeclipse.com diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/CastExpression.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/CastExpression.java index 6b434d0..950716d 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/CastExpression.java +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/ast/CastExpression.java @@ -1,65 +1,313 @@ +/******************************************************************************* + * 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; -import java.util.List; -import java.util.ArrayList; +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; -/** - * This is a cast expression. - * @author Matthieu Casanova - */ 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(final ConstantIdentifier type, - final Expression expression, - final int sourceStart, - final 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(); - } - - /** - * Get the variables from outside (parameters, globals ...) - */ - public void getOutsideVariable(final List list) { - } - - /** - * get the modified variables. - */ - public void getModifiedVariable(final List list) { - expression.getModifiedVariable(list); - } - - /** - * Get the variables used. - */ - public void getUsedVariable(final List list) { - expression.getUsedVariable(list); - } + 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); + } }