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 e103ccc..ad9c88a 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,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 +}