1 /*******************************************************************************
2 * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v0.5
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v05.html
9 * IBM Corporation - initial API and implementation
10 ******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.ast;
13 import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor;
14 import net.sourceforge.phpdt.internal.compiler.impl.*;
15 import net.sourceforge.phpdt.internal.compiler.codegen.*;
16 import net.sourceforge.phpdt.internal.compiler.flow.*;
17 import net.sourceforge.phpdt.internal.compiler.lookup.*;
19 public class CastExpression extends Expression {
21 public Expression expression;
22 public Expression type;
23 public boolean needRuntimeCheckcast;
24 public TypeBinding castTb;
26 //expression.implicitConversion holds the cast for baseType casting
27 public CastExpression(Expression e, Expression t) {
31 //due to the fact an expression may start with ( and that a cast also start with (
32 //the field is an expression....it can be a TypeReference OR a NameReference Or
33 //an expression <--this last one is invalid.......
37 //if (type instanceof TypeReference )
38 // flag = IsTypeReference ;
40 // if (type instanceof NameReference)
41 // flag = IsNameReference ;
43 // flag = IsExpression ;
47 public FlowInfo analyseCode(
48 BlockScope currentScope,
49 FlowContext flowContext,
53 .analyseCode(currentScope, flowContext, flowInfo)
54 .unconditionalInits();
57 public final void areTypesCastCompatible(
60 TypeBinding expressionTb) {
62 // see specifications p.68
63 // handle errors and process constant when needed
65 // if either one of the type is null ==>
66 // some error has been already reported some where ==>
67 // we then do not report an obvious-cascade-error.
69 needRuntimeCheckcast = false;
70 if (castTb == null || expressionTb == null)
72 if (castTb.isBaseType()) {
73 if (expressionTb.isBaseType()) {
74 if (expressionTb == castTb) {
75 constant = expression.constant; //use the same constant
78 if (scope.areTypesCompatible(expressionTb, castTb)
79 || BaseTypeBinding.isNarrowing(castTb.id, expressionTb.id)) {
80 expression.implicitConversion = (castTb.id << 4) + expressionTb.id;
81 if (expression.constant != Constant.NotAConstant)
82 constant = expression.constant.castTo(expression.implicitConversion);
86 scope.problemReporter().typeCastError(this, castTb, expressionTb);
90 //-----------cast to something which is NOT a base type--------------------------
91 if (expressionTb == NullBinding)
92 return; //null is compatible with every thing
94 if (expressionTb.isBaseType()) {
95 scope.problemReporter().typeCastError(this, castTb, expressionTb);
99 if (expressionTb.isArrayType()) {
100 if (castTb.isArrayType()) {
101 //------- (castTb.isArray) expressionTb.isArray -----------
102 TypeBinding expressionEltTb = ((ArrayBinding) expressionTb).elementsType(scope);
103 if (expressionEltTb.isBaseType()) {
104 // <---stop the recursion-------
105 if (((ArrayBinding) castTb).elementsType(scope) == expressionEltTb)
106 needRuntimeCheckcast = true;
108 scope.problemReporter().typeCastError(this, castTb, expressionTb);
111 // recursively on the elements...
112 areTypesCastCompatible(
114 ((ArrayBinding) castTb).elementsType(scope),
119 //------(castTb.isClass) expressionTb.isArray ---------------
120 if (scope.isJavaLangObject(castTb))
122 } else { //------- (castTb.isInterface) expressionTb.isArray -----------
123 if (scope.isJavaLangCloneable(castTb) || scope.isJavaIoSerializable(castTb)) {
124 needRuntimeCheckcast = true;
128 scope.problemReporter().typeCastError(this, castTb, expressionTb);
132 if (expressionTb.isClass()) {
133 if (castTb.isArrayType()) {
134 // ---- (castTb.isArray) expressionTb.isClass -------
135 if (scope.isJavaLangObject(expressionTb)) { // potential runtime error
136 needRuntimeCheckcast = true;
140 castTb.isClass()) { // ----- (castTb.isClass) expressionTb.isClass ------
141 if (scope.areTypesCompatible(expressionTb, castTb)) // no runtime error
143 if (scope.areTypesCompatible(castTb, expressionTb)) {
144 // potential runtime error
145 needRuntimeCheckcast = true;
148 } else { // ----- (castTb.isInterface) expressionTb.isClass -------
149 if (((ReferenceBinding) expressionTb).isFinal()) {
150 // no subclass for expressionTb, thus compile-time check is valid
151 if (scope.areTypesCompatible(expressionTb, castTb))
153 } else { // a subclass may implement the interface ==> no check at compile time
154 needRuntimeCheckcast = true;
158 scope.problemReporter().typeCastError(this, castTb, expressionTb);
162 // if (expressionTb.isInterface()) { cannot be anything else
163 if (castTb.isArrayType()) {
164 // ----- (castTb.isArray) expressionTb.isInterface ------
165 if (scope.isJavaLangCloneable(expressionTb)
166 || scope.isJavaIoSerializable(expressionTb)) // potential runtime error
167 needRuntimeCheckcast = true;
169 scope.problemReporter().typeCastError(this, castTb, expressionTb);
172 castTb.isClass()) { // ----- (castTb.isClass) expressionTb.isInterface --------
173 if (scope.isJavaLangObject(castTb)) // no runtime error
175 if (((ReferenceBinding) castTb).isFinal()) {
176 // no subclass for castTb, thus compile-time check is valid
177 if (!scope.areTypesCompatible(castTb, expressionTb)) {
178 // potential runtime error
179 scope.problemReporter().typeCastError(this, castTb, expressionTb);
183 } else { // ----- (castTb.isInterface) expressionTb.isInterface -------
184 if (castTb != expressionTb
185 && (Scope.compareTypes(castTb, expressionTb) == NotRelated)) {
186 MethodBinding[] castTbMethods = ((ReferenceBinding) castTb).methods();
187 MethodBinding[] expressionTbMethods =
188 ((ReferenceBinding) expressionTb).methods();
189 int exprMethodsLength = expressionTbMethods.length;
190 for (int i = 0, castMethodsLength = castTbMethods.length;
191 i < castMethodsLength;
193 for (int j = 0; j < exprMethodsLength; j++)
194 if (castTbMethods[i].returnType != expressionTbMethods[j].returnType)
195 if (castTbMethods[i].selector == expressionTbMethods[j].selector)
196 if (castTbMethods[i].areParametersEqual(expressionTbMethods[j]))
197 scope.problemReporter().typeCastError(this, castTb, expressionTb);
200 needRuntimeCheckcast = true;
205 * Cast expression code generation
207 * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
208 * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
209 * @param valueRequired boolean
211 public void generateCode(
212 BlockScope currentScope,
213 CodeStream codeStream,
214 boolean valueRequired) {
216 int pc = codeStream.position;
217 if (constant != NotAConstant) {
219 || needRuntimeCheckcast) { // Added for: 1F1W9IG: IVJCOM:WINNT - Compiler omits casting check
220 codeStream.generateConstant(constant, implicitConversion);
221 if (needRuntimeCheckcast) {
222 codeStream.checkcast(castTb);
227 codeStream.recordPositionsFrom(pc, this.sourceStart);
230 expression.generateCode(
233 valueRequired || needRuntimeCheckcast);
234 if (needRuntimeCheckcast) {
235 codeStream.checkcast(castTb);
240 codeStream.generateImplicitConversion(implicitConversion);
242 codeStream.recordPositionsFrom(pc, this.sourceStart);
245 public TypeBinding resolveType(BlockScope scope) {
246 // compute a new constant if the cast is effective
248 // due to the fact an expression may start with ( and that a cast can also start with (
249 // the field is an expression....it can be a TypeReference OR a NameReference Or
250 // any kind of Expression <-- this last one is invalid.......
252 constant = Constant.NotAConstant;
253 implicitConversion = T_undefined;
254 TypeBinding expressionTb = expression.resolveType(scope);
255 if (expressionTb == null)
258 if ((type instanceof TypeReference) || (type instanceof NameReference)) {
259 if ((castTb = type.resolveType(scope)) == null)
261 areTypesCastCompatible(scope, castTb, expressionTb);
263 } else { // expression as a cast !!!!!!!!
264 scope.problemReporter().invalidTypeReference(type);
269 public String toStringExpression() {
271 return "(" + type.toString(0) + ") " + //$NON-NLS-2$ //$NON-NLS-1$
272 expression.toStringExpression();
275 public void traverse(
276 IAbstractSyntaxTreeVisitor visitor,
277 BlockScope blockScope) {
279 if (visitor.visit(this, blockScope)) {
280 type.traverse(visitor, blockScope);
281 expression.traverse(visitor, blockScope);
283 visitor.endVisit(this, blockScope);