1 /*******************************************************************************
2 * Copyright (c) 2000, 2003 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package net.sourceforge.phpeclipse.internal.compiler.ast;
13 import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor;
14 import net.sourceforge.phpdt.internal.compiler.flow.FlowContext;
15 import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
16 import net.sourceforge.phpdt.internal.compiler.impl.Constant;
17 import net.sourceforge.phpdt.internal.compiler.lookup.ArrayBinding;
18 import net.sourceforge.phpdt.internal.compiler.lookup.BaseTypeBinding;
19 import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
20 import net.sourceforge.phpdt.internal.compiler.lookup.MethodBinding;
21 import net.sourceforge.phpdt.internal.compiler.lookup.ReferenceBinding;
22 import net.sourceforge.phpdt.internal.compiler.lookup.Scope;
23 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
25 public class CastExpression extends Expression {
27 public Expression expression;
28 public Expression type;
29 public boolean needRuntimeCheckcast;
31 //expression.implicitConversion holds the cast for baseType casting
32 public CastExpression(Expression e, Expression t) {
36 //due to the fact an expression may start with ( and that a cast also start with (
37 //the field is an expression....it can be a TypeReference OR a NameReference Or
38 //an expression <--this last one is invalid.......
42 //if (type instanceof TypeReference )
43 // flag = IsTypeReference ;
45 // if (type instanceof NameReference)
46 // flag = IsNameReference ;
48 // flag = IsExpression ;
52 public FlowInfo analyseCode(
53 BlockScope currentScope,
54 FlowContext flowContext,
58 .analyseCode(currentScope, flowContext, flowInfo)
59 .unconditionalInits();
62 public final void areTypesCastCompatible(
65 TypeBinding expressionType) {
67 // see specifications 5.5
68 // handle errors and process constant when needed
70 // if either one of the type is null ==>
71 // some error has been already reported some where ==>
72 // we then do not report an obvious-cascade-error.
74 needRuntimeCheckcast = false;
75 if (castType == null || expressionType == null) return;
77 // identity conversion cannot be performed upfront, due to side-effects
78 // like constant propagation
80 if (castType.isBaseType()) {
81 if (expressionType.isBaseType()) {
82 if (expressionType == castType) {
83 expression.implicitWidening(castType, expressionType);
84 constant = expression.constant; //use the same constant
87 if (expressionType.isCompatibleWith(castType)
88 || BaseTypeBinding.isNarrowing(castType.id, expressionType.id)) {
89 expression.implicitConversion = (castType.id << 4) + expressionType.id;
90 if (expression.constant != Constant.NotAConstant)
91 constant = expression.constant.castTo(expression.implicitConversion);
95 scope.problemReporter().typeCastError(this, castType, expressionType);
99 //-----------cast to something which is NOT a base type--------------------------
100 if (expressionType == NullBinding) {
101 // if (castType.isArrayType()){ // 26903 - need checkcast when casting null to array type
102 // needRuntimeCheckcast = true;
104 return; //null is compatible with every thing
106 if (expressionType.isBaseType()) {
107 scope.problemReporter().typeCastError(this, castType, expressionType);
111 if (expressionType.isArrayType()) {
112 if (castType == expressionType) return; // identity conversion
114 if (castType.isArrayType()) {
115 //------- (castType.isArray) expressionType.isArray -----------
116 TypeBinding exprElementType = ((ArrayBinding) expressionType).elementsType(scope);
117 if (exprElementType.isBaseType()) {
118 // <---stop the recursion-------
119 if (((ArrayBinding) castType).elementsType(scope) == exprElementType)
120 needRuntimeCheckcast = true;
122 scope.problemReporter().typeCastError(this, castType, expressionType);
125 // recursively on the elements...
126 areTypesCastCompatible(
128 ((ArrayBinding) castType).elementsType(scope),
132 castType.isClass()) {
133 //------(castType.isClass) expressionType.isArray ---------------
134 if (scope.isJavaLangObject(castType))
136 } else { //------- (castType.isInterface) expressionType.isArray -----------
137 if (scope.isJavaLangCloneable(castType) || scope.isJavaIoSerializable(castType)) {
138 needRuntimeCheckcast = true;
142 scope.problemReporter().typeCastError(this, castType, expressionType);
146 if (expressionType.isClass()) {
147 if (castType.isArrayType()) {
148 // ---- (castType.isArray) expressionType.isClass -------
149 if (scope.isJavaLangObject(expressionType)) { // potential runtime error
150 needRuntimeCheckcast = true;
153 } else if (castType.isClass()) { // ----- (castType.isClass) expressionType.isClass ------
154 if (expressionType.isCompatibleWith(castType)){ // no runtime error
155 if (castType.id == T_String) constant = expression.constant; // (String) cst is still a constant
158 if (castType.isCompatibleWith(expressionType)) {
159 // potential runtime error
160 needRuntimeCheckcast = true;
163 } else { // ----- (castType.isInterface) expressionType.isClass -------
164 if (((ReferenceBinding) expressionType).isFinal()) {
165 // no subclass for expressionType, thus compile-time check is valid
166 if (expressionType.isCompatibleWith(castType))
168 } else { // a subclass may implement the interface ==> no check at compile time
169 needRuntimeCheckcast = true;
173 scope.problemReporter().typeCastError(this, castType, expressionType);
177 // if (expressionType.isInterface()) { cannot be anything else
178 if (castType.isArrayType()) {
179 // ----- (castType.isArray) expressionType.isInterface ------
180 if (scope.isJavaLangCloneable(expressionType)
181 || scope.isJavaIoSerializable(expressionType)) // potential runtime error
182 needRuntimeCheckcast = true;
184 scope.problemReporter().typeCastError(this, castType, expressionType);
186 } else if (castType.isClass()) { // ----- (castType.isClass) expressionType.isInterface --------
187 if (scope.isJavaLangObject(castType)) // no runtime error
189 if (((ReferenceBinding) castType).isFinal()) {
190 // no subclass for castType, thus compile-time check is valid
191 if (!castType.isCompatibleWith(expressionType)) {
192 // potential runtime error
193 scope.problemReporter().typeCastError(this, castType, expressionType);
197 } else { // ----- (castType.isInterface) expressionType.isInterface -------
198 if (castType == expressionType) return; // identity conversion
199 if (Scope.compareTypes(castType, expressionType) == NotRelated) {
200 MethodBinding[] castTypeMethods = ((ReferenceBinding) castType).methods();
201 MethodBinding[] expressionTypeMethods =
202 ((ReferenceBinding) expressionType).methods();
203 int exprMethodsLength = expressionTypeMethods.length;
204 for (int i = 0, castMethodsLength = castTypeMethods.length; i < castMethodsLength; i++)
205 for (int j = 0; j < exprMethodsLength; j++) {
206 if ((castTypeMethods[i].returnType != expressionTypeMethods[j].returnType)
207 && (castTypeMethods[i].selector == expressionTypeMethods[j].selector)
208 && castTypeMethods[i].areParametersEqual(expressionTypeMethods[j])) {
209 scope.problemReporter().typeCastError(this, castType, expressionType);
214 needRuntimeCheckcast = true;
219 * Cast expression code generation
221 * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
222 * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
223 * @param valueRequired boolean
225 // public void generateCode(
226 // BlockScope currentScope,
227 // CodeStream codeStream,
228 // boolean valueRequired) {
230 // int pc = codeStream.position;
231 // if (constant != NotAConstant) {
233 // || needRuntimeCheckcast) { // Added for: 1F1W9IG: IVJCOM:WINNT - Compiler omits casting check
234 // codeStream.generateConstant(constant, implicitConversion);
235 // if (needRuntimeCheckcast) {
236 // codeStream.checkcast(this.resolvedType);
237 // if (!valueRequired)
241 // codeStream.recordPositionsFrom(pc, this.sourceStart);
244 // expression.generateCode(
247 // valueRequired || needRuntimeCheckcast);
248 // if (needRuntimeCheckcast) {
249 // codeStream.checkcast(this.resolvedType);
250 // if (!valueRequired)
253 // if (valueRequired)
254 // codeStream.generateImplicitConversion(implicitConversion);
256 // codeStream.recordPositionsFrom(pc, this.sourceStart);
259 public Expression innermostCastedExpression(){
260 Expression current = this.expression;
261 while (current instanceof CastExpression) {
262 current = ((CastExpression) current).expression;
267 public TypeBinding resolveType(BlockScope scope) {
268 // compute a new constant if the cast is effective
270 // due to the fact an expression may start with ( and that a cast can also start with (
271 // the field is an expression....it can be a TypeReference OR a NameReference Or
272 // any kind of Expression <-- this last one is invalid.......
274 constant = Constant.NotAConstant;
275 implicitConversion = T_undefined;
276 if ((type instanceof TypeReference) || (type instanceof NameReference)) {
277 this.resolvedType = type.resolveType(scope);
278 TypeBinding castedExpressionType = expression.resolveType(scope);
279 if (this.resolvedType != null && castedExpressionType != null) {
280 areTypesCastCompatible(scope, this.resolvedType, castedExpressionType);
282 return this.resolvedType;
283 } else { // expression as a cast !!!!!!!!
284 TypeBinding castedExpressionType = expression.resolveType(scope);
285 if (castedExpressionType == null) return null;
286 scope.problemReporter().invalidTypeReference(type);
291 public String toStringExpression() {
293 return "(" + type.toString(0) + ") " + //$NON-NLS-2$ //$NON-NLS-1$
294 expression.toStringExpression();
297 public void traverse(
298 IAbstractSyntaxTreeVisitor visitor,
299 BlockScope blockScope) {
301 if (visitor.visit(this, blockScope)) {
302 type.traverse(visitor, blockScope);
303 expression.traverse(visitor, blockScope);
305 visitor.endVisit(this, blockScope);