X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=repo%2Forg.ibex.tool%2Fsrc%2Forg%2Feclipse%2Fjdt%2Finternal%2Fcompiler%2Fast%2FCastExpression.java;fp=repo%2Forg.ibex.tool%2Fsrc%2Forg%2Feclipse%2Fjdt%2Finternal%2Fcompiler%2Fast%2FCastExpression.java;h=ecfe767b9e1b17c427efe70f8de11b5414d92865;hb=6f0cd02d46e011bd5599e1b7fefc6159cb811135;hp=0000000000000000000000000000000000000000;hpb=622d0e5a4b1b35b6918a516a79a0cc22272a919e;p=org.ibex.tool.git diff --git a/repo/org.ibex.tool/src/org/eclipse/jdt/internal/compiler/ast/CastExpression.java b/repo/org.ibex.tool/src/org/eclipse/jdt/internal/compiler/ast/CastExpression.java new file mode 100644 index 0000000..ecfe767 --- /dev/null +++ b/repo/org.ibex.tool/src/org/eclipse/jdt/internal/compiler/ast/CastExpression.java @@ -0,0 +1,512 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 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 + * Nick Teryaev - fix for bug (https://bugs.eclipse.org/bugs/show_bug.cgi?id=40752) + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.impl.*; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.lookup.*; +import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities; + +public class CastExpression extends Expression { + + public Expression expression; + public Expression type; + + //expression.implicitConversion holds the cast for baseType casting + public CastExpression(Expression expression, Expression type) { + this.expression = expression; + this.type = type; + + //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(); + } + + /** + * Returns false if the cast is unnecessary + */ + public final boolean checkCastTypesCompatibility( + 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. + + if (castType == null || expressionType == null) return true; + + // 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 false; + } + boolean necessary = false; + if (expressionType.isCompatibleWith(castType) + || (necessary = 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 necessary; + + } + } + scope.problemReporter().typeCastError(this, castType, expressionType); + return true; + } + + //-----------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 false; //null is compatible with every thing + } + if (expressionType.isBaseType()) { + scope.problemReporter().typeCastError(this, castType, expressionType); + return true; + } + + if (expressionType.isArrayType()) { + if (castType == expressionType) return false; // 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) { + this.bits |= NeedRuntimeCheckCastMASK; + } else { + scope.problemReporter().typeCastError(this, castType, expressionType); + } + return true; + } + // recursively on the elements... + return checkCastTypesCompatibility( + scope, + ((ArrayBinding) castType).elementsType(scope), + exprElementType); + } else if ( + castType.isClass()) { + //------(castType.isClass) expressionType.isArray --------------- + if (castType.id == T_Object) { + return false; + } + } else { //------- (castType.isInterface) expressionType.isArray ----------- + if (castType.id == T_JavaLangCloneable || castType.id == T_JavaIoSerializable) { + this.bits |= NeedRuntimeCheckCastMASK; + return true; + } + } + scope.problemReporter().typeCastError(this, castType, expressionType); + return true; + } + + if (expressionType.isClass()) { + if (castType.isArrayType()) { + // ---- (castType.isArray) expressionType.isClass ------- + if (expressionType.id == T_Object) { // potential runtime error + this.bits |= NeedRuntimeCheckCastMASK; + return true; + } + } 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 false; + } + if (castType.isCompatibleWith(expressionType)) { + // potential runtime error + this.bits |= NeedRuntimeCheckCastMASK; + return true; + } + } else { // ----- (castType.isInterface) expressionType.isClass ------- + if (expressionType.isCompatibleWith(castType)) + return false; + if (!((ReferenceBinding) expressionType).isFinal()) { + // a subclass may implement the interface ==> no check at compile time + this.bits |= NeedRuntimeCheckCastMASK; + return true; + } + // no subclass for expressionType, thus compile-time check is valid + } + scope.problemReporter().typeCastError(this, castType, expressionType); + return true; + } + + // if (expressionType.isInterface()) { cannot be anything else + if (castType.isArrayType()) { + // ----- (castType.isArray) expressionType.isInterface ------ + if (expressionType.id == T_JavaLangCloneable + || expressionType.id == T_JavaIoSerializable) {// potential runtime error + this.bits |= NeedRuntimeCheckCastMASK; + } else { + scope.problemReporter().typeCastError(this, castType, expressionType); + } + return true; + } else if (castType.isClass()) { // ----- (castType.isClass) expressionType.isInterface -------- + if (castType.id == T_Object) { // no runtime error + return false; + } + 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 true; + } + } + } else { // ----- (castType.isInterface) expressionType.isInterface ------- + if (expressionType.isCompatibleWith(castType)) { + return false; + } + if (!castType.isCompatibleWith(expressionType)) { + 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) + && (CharOperation.equals(castTypeMethods[i].selector, expressionTypeMethods[j].selector)) + && castTypeMethods[i].areParametersEqual(expressionTypeMethods[j])) { + scope.problemReporter().typeCastError(this, castType, expressionType); + } + } + } + } + this.bits |= NeedRuntimeCheckCastMASK; + return true; + } + + /** + * Casting an enclosing instance will considered as useful if removing it would actually bind to a different type + */ + public static void checkNeedForEnclosingInstanceCast(BlockScope scope, Expression enclosingInstance, TypeBinding enclosingInstanceType, TypeBinding memberType) { + + if (scope.environment().options.getSeverity(CompilerOptions.UnnecessaryTypeCheck) == ProblemSeverities.Ignore) return; + + TypeBinding castedExpressionType = ((CastExpression)enclosingInstance).expression.resolvedType; + if (castedExpressionType == null) return; // cannot do better + // obvious identity cast + if (castedExpressionType == enclosingInstanceType) { + scope.problemReporter().unnecessaryCast((CastExpression)enclosingInstance); + } else if (castedExpressionType == NullBinding){ + return; // tolerate null enclosing instance cast + } else { + TypeBinding alternateEnclosingInstanceType = castedExpressionType; + if (castedExpressionType.isBaseType() || castedExpressionType.isArrayType()) return; // error case + if (memberType == scope.getMemberType(memberType.sourceName(), (ReferenceBinding) alternateEnclosingInstanceType)) { + scope.problemReporter().unnecessaryCast((CastExpression)enclosingInstance); + } + } + } + + /** + * Only complain for identity cast, since other type of casts may be useful: e.g. ~((~(long) 0) << 32) is different from: ~((~0) << 32) + */ + public static void checkNeedForArgumentCast(BlockScope scope, int operator, int operatorSignature, Expression expression, int expressionTypeId) { + + if (scope.environment().options.getSeverity(CompilerOptions.UnnecessaryTypeCheck) == ProblemSeverities.Ignore) return; + + // check need for left operand cast + int alternateLeftTypeId = expressionTypeId; + if ((expression.bits & UnnecessaryCastMask) == 0 && expression.resolvedType.isBaseType()) { + // narrowing conversion on base type may change value, thus necessary + return; + } else { + TypeBinding alternateLeftType = ((CastExpression)expression).expression.resolvedType; + if (alternateLeftType == null) return; // cannot do better + if ((alternateLeftTypeId = alternateLeftType.id) == expressionTypeId) { // obvious identity cast + scope.problemReporter().unnecessaryCast((CastExpression)expression); + return; + } else if (alternateLeftTypeId == T_null) { + alternateLeftTypeId = expressionTypeId; // tolerate null argument cast + return; + } + } +/* tolerate widening cast in unary expressions, as may be used when combined in binary expressions (41680) + int alternateOperatorSignature = OperatorExpression.OperatorSignatures[operator][(alternateLeftTypeId << 4) + alternateLeftTypeId]; + // (cast) left Op (cast) right --> result + // 1111 0000 1111 0000 1111 + // <<16 <<12 <<8 <<4 <<0 + final int CompareMASK = (0xF<<16) + (0xF<<8) + 0xF; // mask hiding compile-time types + if ((operatorSignature & CompareMASK) == (alternateOperatorSignature & CompareMASK)) { // same promotions and result + scope.problemReporter().unnecessaryCastForArgument((CastExpression)expression, TypeBinding.wellKnownType(scope, expression.implicitConversion >> 4)); + } +*/ + } + + /** + * Cast expressions will considered as useful if removing them all would actually bind to a different method + * (no fine grain analysis on per casted argument basis, simply separate widening cast from narrowing ones) + */ + public static void checkNeedForArgumentCasts(BlockScope scope, Expression receiver, TypeBinding receiverType, MethodBinding binding, Expression[] arguments, TypeBinding[] argumentTypes, final InvocationSite invocationSite) { + + if (scope.environment().options.getSeverity(CompilerOptions.UnnecessaryTypeCheck) == ProblemSeverities.Ignore) return; + + int length = argumentTypes.length; + + // iterate over arguments, and retrieve original argument types (before cast) + TypeBinding[] rawArgumentTypes = argumentTypes; + for (int i = 0; i < length; i++) { + Expression argument = arguments[i]; + if (argument instanceof CastExpression) { + // narrowing conversion on base type may change value, thus necessary + if ((argument.bits & UnnecessaryCastMask) == 0 && argument.resolvedType.isBaseType()) { + continue; + } + TypeBinding castedExpressionType = ((CastExpression)argument).expression.resolvedType; + if (castedExpressionType == null) return; // cannot do better + // obvious identity cast + if (castedExpressionType == argumentTypes[i]) { + scope.problemReporter().unnecessaryCast((CastExpression)argument); + } else if (castedExpressionType == NullBinding){ + continue; // tolerate null argument cast + } else { + if (rawArgumentTypes == argumentTypes) { + System.arraycopy(rawArgumentTypes, 0, rawArgumentTypes = new TypeBinding[length], 0, length); + } + // retain original argument type + rawArgumentTypes[i] = castedExpressionType; + } + } + } + // perform alternate lookup with original types + if (rawArgumentTypes != argumentTypes) { + checkAlternateBinding(scope, receiver, receiverType, binding, arguments, argumentTypes, rawArgumentTypes, invocationSite); + } + } + + /** + * Check binary operator casted arguments + */ + public static void checkNeedForArgumentCasts(BlockScope scope, int operator, int operatorSignature, Expression left, int leftTypeId, boolean leftIsCast, Expression right, int rightTypeId, boolean rightIsCast) { + + if (scope.environment().options.getSeverity(CompilerOptions.UnnecessaryTypeCheck) == ProblemSeverities.Ignore) return; + + // check need for left operand cast + int alternateLeftTypeId = leftTypeId; + if (leftIsCast) { + if ((left.bits & UnnecessaryCastMask) == 0 && left.resolvedType.isBaseType()) { + // narrowing conversion on base type may change value, thus necessary + leftIsCast = false; + } else { + TypeBinding alternateLeftType = ((CastExpression)left).expression.resolvedType; + if (alternateLeftType == null) return; // cannot do better + if ((alternateLeftTypeId = alternateLeftType.id) == leftTypeId) { // obvious identity cast + scope.problemReporter().unnecessaryCast((CastExpression)left); + leftIsCast = false; + } else if (alternateLeftTypeId == T_null) { + alternateLeftTypeId = leftTypeId; // tolerate null argument cast + leftIsCast = false; + } + } + } + // check need for right operand cast + int alternateRightTypeId = rightTypeId; + if (rightIsCast) { + if ((right.bits & UnnecessaryCastMask) == 0 && right.resolvedType.isBaseType()) { + // narrowing conversion on base type may change value, thus necessary + rightIsCast = false; + } else { + TypeBinding alternateRightType = ((CastExpression)right).expression.resolvedType; + if (alternateRightType == null) return; // cannot do better + if ((alternateRightTypeId = alternateRightType.id) == rightTypeId) { // obvious identity cast + scope.problemReporter().unnecessaryCast((CastExpression)right); + rightIsCast = false; + } else if (alternateRightTypeId == T_null) { + alternateRightTypeId = rightTypeId; // tolerate null argument cast + rightIsCast = false; + } + } + } + if (leftIsCast || rightIsCast) { + if (alternateLeftTypeId > 15 || alternateRightTypeId > 15) { // must convert String + Object || Object + String + if (alternateLeftTypeId == T_String) { + alternateRightTypeId = T_Object; + } else if (alternateRightTypeId == T_String) { + alternateLeftTypeId = T_Object; + } else { + return; // invalid operator + } + } + int alternateOperatorSignature = OperatorExpression.OperatorSignatures[operator][(alternateLeftTypeId << 4) + alternateRightTypeId]; + // (cast) left Op (cast) right --> result + // 1111 0000 1111 0000 1111 + // <<16 <<12 <<8 <<4 <<0 + final int CompareMASK = (0xF<<16) + (0xF<<8) + 0xF; // mask hiding compile-time types + if ((operatorSignature & CompareMASK) == (alternateOperatorSignature & CompareMASK)) { // same promotions and result + if (leftIsCast) scope.problemReporter().unnecessaryCastForArgument((CastExpression)left, TypeBinding.wellKnownType(scope, left.implicitConversion >> 4)); + if (rightIsCast) scope.problemReporter().unnecessaryCastForArgument((CastExpression)right, TypeBinding.wellKnownType(scope, right.implicitConversion >> 4)); + } + } + } + + private static void checkAlternateBinding(BlockScope scope, Expression receiver, TypeBinding receiverType, MethodBinding binding, Expression[] arguments, TypeBinding[] originalArgumentTypes, TypeBinding[] alternateArgumentTypes, final InvocationSite invocationSite) { + + InvocationSite fakeInvocationSite = new InvocationSite(){ + public boolean isSuperAccess(){ return invocationSite.isSuperAccess(); } + public boolean isTypeAccess() { return invocationSite.isTypeAccess(); } + public void setActualReceiverType(ReferenceBinding actualReceiverType) { /* ignore */} + public void setDepth(int depth) { /* ignore */} + public void setFieldIndex(int depth){ /* ignore */} + public int sourceStart() { return 0; } + public int sourceEnd() { return 0; } + }; + MethodBinding bindingIfNoCast; + if (binding.isConstructor()) { + bindingIfNoCast = scope.getConstructor((ReferenceBinding)receiverType, alternateArgumentTypes, fakeInvocationSite); + } else { + bindingIfNoCast = receiver.isImplicitThis() + ? scope.getImplicitMethod(binding.selector, alternateArgumentTypes, fakeInvocationSite) + : scope.getMethod(receiverType, binding.selector, alternateArgumentTypes, fakeInvocationSite); + } + if (bindingIfNoCast == binding) { + for (int i = 0, length = originalArgumentTypes.length; i < length; i++) { + if (originalArgumentTypes[i] != alternateArgumentTypes[i]) { + scope.problemReporter().unnecessaryCastForArgument((CastExpression)arguments[i], binding.parameters[i]); + } + } + } + } + /** + * 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 + */ + public void generateCode( + BlockScope currentScope, + CodeStream codeStream, + boolean valueRequired) { + + int pc = codeStream.position; + boolean needRuntimeCheckcast = (this.bits & NeedRuntimeCheckCastMASK) != 0; + 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) + && ((type.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT) == 0) { // no extra parenthesis around type: ((A))exp + + this.resolvedType = type.resolveType(scope); + TypeBinding expressionType = expression.resolveType(scope); + if (this.resolvedType != null && expressionType != null) { + boolean necessary = checkCastTypesCompatibility(scope, this.resolvedType, expressionType); + if (!necessary && this.expression.resolvedType != null) { // cannot do better if expression is not bound + this.bits |= UnnecessaryCastMask; + if ((this.bits & IgnoreNeedForCastCheckMASK) == 0) { + scope.problemReporter().unnecessaryCast(this); + } + } + } + return this.resolvedType; + } else { // expression as a cast !!!!!!!! + TypeBinding expressionType = expression.resolveType(scope); + if (expressionType == null) return null; + scope.problemReporter().invalidTypeReference(type); + return null; + } + } + + public void traverse( + ASTVisitor visitor, + BlockScope blockScope) { + + if (visitor.visit(this, blockScope)) { + type.traverse(visitor, blockScope); + expression.traverse(visitor, blockScope); + } + visitor.endVisit(this, blockScope); + } +}