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.codegen.CodeStream;
15 import net.sourceforge.phpdt.internal.compiler.flow.FlowContext;
16 import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
17 import net.sourceforge.phpdt.internal.compiler.impl.Constant;
18 import net.sourceforge.phpdt.internal.compiler.lookup.ArrayBinding;
19 import net.sourceforge.phpdt.internal.compiler.lookup.BaseTypeBinding;
20 import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
21 import net.sourceforge.phpdt.internal.compiler.lookup.MethodBinding;
22 import net.sourceforge.phpdt.internal.compiler.lookup.ReferenceBinding;
23 import net.sourceforge.phpdt.internal.compiler.lookup.Scope;
24 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
26 public class CastExpression extends Expression {
28 public Expression expression;
29 public Expression type;
30 public boolean needRuntimeCheckcast;
31 public TypeBinding castTb;
33 //expression.implicitConversion holds the cast for baseType casting
34 public CastExpression(Expression e, Expression t) {
38 //due to the fact an expression may start with ( and that a cast also start with (
39 //the field is an expression....it can be a TypeReference OR a NameReference Or
40 //an expression <--this last one is invalid.......
44 //if (type instanceof TypeReference )
45 // flag = IsTypeReference ;
47 // if (type instanceof NameReference)
48 // flag = IsNameReference ;
50 // flag = IsExpression ;
54 public FlowInfo analyseCode(
55 BlockScope currentScope,
56 FlowContext flowContext,
60 .analyseCode(currentScope, flowContext, flowInfo)
61 .unconditionalInits();
64 public final void areTypesCastCompatible(
67 TypeBinding expressionTb) {
69 // see specifications p.68
70 // handle errors and process constant when needed
72 // if either one of the type is null ==>
73 // some error has been already reported some where ==>
74 // we then do not report an obvious-cascade-error.
76 needRuntimeCheckcast = false;
77 if (castTb == null || expressionTb == null)
79 if (castTb.isBaseType()) {
80 if (expressionTb.isBaseType()) {
81 if (expressionTb == castTb) {
82 constant = expression.constant; //use the same constant
85 if (BlockScope.areTypesCompatible(expressionTb, castTb)
86 || BaseTypeBinding.isNarrowing(castTb.id, expressionTb.id)) {
87 expression.implicitConversion = (castTb.id << 4) + expressionTb.id;
88 if (expression.constant != Constant.NotAConstant)
89 constant = expression.constant.castTo(expression.implicitConversion);
93 scope.problemReporter().typeCastError(this, castTb, expressionTb);
97 //-----------cast to something which is NOT a base type--------------------------
98 if (expressionTb == NullBinding)
99 return; //null is compatible with every thing
101 if (expressionTb.isBaseType()) {
102 scope.problemReporter().typeCastError(this, castTb, expressionTb);
106 if (expressionTb.isArrayType()) {
107 if (castTb.isArrayType()) {
108 //------- (castTb.isArray) expressionTb.isArray -----------
109 TypeBinding expressionEltTb = ((ArrayBinding) expressionTb).elementsType(scope);
110 if (expressionEltTb.isBaseType()) {
111 // <---stop the recursion-------
112 if (((ArrayBinding) castTb).elementsType(scope) == expressionEltTb)
113 needRuntimeCheckcast = true;
115 scope.problemReporter().typeCastError(this, castTb, expressionTb);
118 // recursively on the elements...
119 areTypesCastCompatible(
121 ((ArrayBinding) castTb).elementsType(scope),
126 //------(castTb.isClass) expressionTb.isArray ---------------
127 if (scope.isJavaLangObject(castTb))
129 } else { //------- (castTb.isInterface) expressionTb.isArray -----------
130 if (scope.isJavaLangCloneable(castTb) || scope.isJavaIoSerializable(castTb)) {
131 needRuntimeCheckcast = true;
135 scope.problemReporter().typeCastError(this, castTb, expressionTb);
139 if (expressionTb.isClass()) {
140 if (castTb.isArrayType()) {
141 // ---- (castTb.isArray) expressionTb.isClass -------
142 if (scope.isJavaLangObject(expressionTb)) { // potential runtime error
143 needRuntimeCheckcast = true;
147 castTb.isClass()) { // ----- (castTb.isClass) expressionTb.isClass ------
148 if (BlockScope.areTypesCompatible(expressionTb, castTb)) // no runtime error
150 if (BlockScope.areTypesCompatible(castTb, expressionTb)) {
151 // potential runtime error
152 needRuntimeCheckcast = true;
155 } else { // ----- (castTb.isInterface) expressionTb.isClass -------
156 if (((ReferenceBinding) expressionTb).isFinal()) {
157 // no subclass for expressionTb, thus compile-time check is valid
158 if (BlockScope.areTypesCompatible(expressionTb, castTb))
160 } else { // a subclass may implement the interface ==> no check at compile time
161 needRuntimeCheckcast = true;
165 scope.problemReporter().typeCastError(this, castTb, expressionTb);
169 // if (expressionTb.isInterface()) { cannot be anything else
170 if (castTb.isArrayType()) {
171 // ----- (castTb.isArray) expressionTb.isInterface ------
172 if (scope.isJavaLangCloneable(expressionTb)
173 || scope.isJavaIoSerializable(expressionTb)) // potential runtime error
174 needRuntimeCheckcast = true;
176 scope.problemReporter().typeCastError(this, castTb, expressionTb);
179 castTb.isClass()) { // ----- (castTb.isClass) expressionTb.isInterface --------
180 if (scope.isJavaLangObject(castTb)) // no runtime error
182 if (((ReferenceBinding) castTb).isFinal()) {
183 // no subclass for castTb, thus compile-time check is valid
184 if (!BlockScope.areTypesCompatible(castTb, expressionTb)) {
185 // potential runtime error
186 scope.problemReporter().typeCastError(this, castTb, expressionTb);
190 } else { // ----- (castTb.isInterface) expressionTb.isInterface -------
191 if (castTb != expressionTb
192 && (Scope.compareTypes(castTb, expressionTb) == NotRelated)) {
193 MethodBinding[] castTbMethods = ((ReferenceBinding) castTb).methods();
194 MethodBinding[] expressionTbMethods =
195 ((ReferenceBinding) expressionTb).methods();
196 int exprMethodsLength = expressionTbMethods.length;
197 for (int i = 0, castMethodsLength = castTbMethods.length;
198 i < castMethodsLength;
200 for (int j = 0; j < exprMethodsLength; j++)
201 if (castTbMethods[i].returnType != expressionTbMethods[j].returnType)
202 if (castTbMethods[i].selector == expressionTbMethods[j].selector)
203 if (castTbMethods[i].areParametersEqual(expressionTbMethods[j]))
204 scope.problemReporter().typeCastError(this, castTb, expressionTb);
207 needRuntimeCheckcast = true;
212 * Cast expression code generation
214 * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
215 * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
216 * @param valueRequired boolean
218 public void generateCode(
219 BlockScope currentScope,
220 CodeStream codeStream,
221 boolean valueRequired) {
223 int pc = codeStream.position;
224 if (constant != NotAConstant) {
226 || needRuntimeCheckcast) { // Added for: 1F1W9IG: IVJCOM:WINNT - Compiler omits casting check
227 codeStream.generateConstant(constant, implicitConversion);
228 if (needRuntimeCheckcast) {
229 codeStream.checkcast(castTb);
234 codeStream.recordPositionsFrom(pc, this.sourceStart);
237 expression.generateCode(
240 valueRequired || needRuntimeCheckcast);
241 if (needRuntimeCheckcast) {
242 codeStream.checkcast(castTb);
247 codeStream.generateImplicitConversion(implicitConversion);
249 codeStream.recordPositionsFrom(pc, this.sourceStart);
252 public TypeBinding resolveType(BlockScope scope) {
253 // compute a new constant if the cast is effective
255 // due to the fact an expression may start with ( and that a cast can also start with (
256 // the field is an expression....it can be a TypeReference OR a NameReference Or
257 // any kind of Expression <-- this last one is invalid.......
259 constant = Constant.NotAConstant;
260 implicitConversion = T_undefined;
261 TypeBinding expressionTb = expression.resolveType(scope);
262 if (expressionTb == null)
265 if ((type instanceof TypeReference) || (type instanceof NameReference)) {
266 if ((castTb = type.resolveType(scope)) == null)
268 areTypesCastCompatible(scope, castTb, expressionTb);
270 } else { // expression as a cast !!!!!!!!
271 scope.problemReporter().invalidTypeReference(type);
276 public String toStringExpression() {
278 return "(" + type.toString(0) + ") " + //$NON-NLS-2$ //$NON-NLS-1$
279 expression.toStringExpression();
282 public void traverse(
283 IAbstractSyntaxTreeVisitor visitor,
284 BlockScope blockScope) {
286 if (visitor.visit(this, blockScope)) {
287 type.traverse(visitor, blockScope);
288 expression.traverse(visitor, blockScope);
290 visitor.endVisit(this, blockScope);