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.phpdt.internal.compiler.ast;
13 import net.sourceforge.phpdt.internal.compiler.ASTVisitor;
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;
29 public Expression type;
31 public boolean needRuntimeCheckcast;
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
40 // the field is an expression....it can be a TypeReference OR a
42 // an expression <--this last one is invalid.......
46 // if (type instanceof TypeReference )
47 // flag = IsTypeReference ;
49 // if (type instanceof NameReference)
50 // flag = IsNameReference ;
52 // flag = IsExpression ;
56 public FlowInfo analyseCode(BlockScope currentScope,
57 FlowContext flowContext, FlowInfo flowInfo) {
59 return expression.analyseCode(currentScope, flowContext, flowInfo)
60 .unconditionalInits();
63 public final void areTypesCastCompatible(BlockScope scope,
64 TypeBinding castType, TypeBinding expressionType) {
66 // see specifications 5.5
67 // handle errors and process constant when needed
69 // if either one of the type is null ==>
70 // some error has been already reported some where ==>
71 // we then do not report an obvious-cascade-error.
73 needRuntimeCheckcast = false;
74 if (castType == null || expressionType == null)
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,
90 expression.implicitConversion = (castType.id << 4)
92 if (expression.constant != Constant.NotAConstant)
93 constant = expression.constant
94 .castTo(expression.implicitConversion);
98 scope.problemReporter().typeCastError(this, castType,
103 // -----------cast to something which is NOT a base
104 // type--------------------------
105 if (expressionType == NullBinding) {
106 // if (castType.isArrayType()){ // 26903 - need checkcast when
107 // casting null to array type
108 // needRuntimeCheckcast = true;
110 return; // null is compatible with every thing
112 if (expressionType.isBaseType()) {
113 scope.problemReporter().typeCastError(this, castType,
118 if (expressionType.isArrayType()) {
119 if (castType == expressionType)
120 return; // identity conversion
122 if (castType.isArrayType()) {
123 // ------- (castType.isArray) expressionType.isArray -----------
124 TypeBinding exprElementType = ((ArrayBinding) expressionType)
125 .elementsType(scope);
126 if (exprElementType.isBaseType()) {
127 // <---stop the recursion-------
128 if (((ArrayBinding) castType).elementsType(scope) == exprElementType)
129 needRuntimeCheckcast = true;
131 scope.problemReporter().typeCastError(this, castType,
135 // recursively on the elements...
136 areTypesCastCompatible(scope, ((ArrayBinding) castType)
137 .elementsType(scope), exprElementType);
139 } else if (castType.isClass()) {
140 // ------(castType.isClass) expressionType.isArray
142 if (scope.isJavaLangObject(castType))
144 } else { // ------- (castType.isInterface) expressionType.isArray
146 if (scope.isJavaLangCloneable(castType)
147 || scope.isJavaIoSerializable(castType)) {
148 needRuntimeCheckcast = true;
152 scope.problemReporter().typeCastError(this, castType,
157 if (expressionType.isClass()) {
158 if (castType.isArrayType()) {
159 // ---- (castType.isArray) expressionType.isClass -------
160 if (scope.isJavaLangObject(expressionType)) { // potential
162 needRuntimeCheckcast = true;
165 } else if (castType.isClass()) { // ----- (castType.isClass)
166 // expressionType.isClass ------
167 if (expressionType.isCompatibleWith(castType)) { // no
170 if (castType.id == T_String)
171 constant = expression.constant; // (String) cst is still
175 if (castType.isCompatibleWith(expressionType)) {
176 // potential runtime error
177 needRuntimeCheckcast = true;
180 } else { // ----- (castType.isInterface) expressionType.isClass
182 if (((ReferenceBinding) expressionType).isFinal()) {
183 // no subclass for expressionType, thus compile-time check
185 if (expressionType.isCompatibleWith(castType))
187 } else { // a subclass may implement the interface ==> no
188 // check at compile time
189 needRuntimeCheckcast = true;
193 scope.problemReporter().typeCastError(this, castType,
198 // if (expressionType.isInterface()) { cannot be anything else
199 if (castType.isArrayType()) {
200 // ----- (castType.isArray) expressionType.isInterface ------
201 if (scope.isJavaLangCloneable(expressionType)
202 || scope.isJavaIoSerializable(expressionType)) // potential
205 needRuntimeCheckcast = true;
207 scope.problemReporter().typeCastError(this, castType,
210 } else if (castType.isClass()) { // ----- (castType.isClass)
211 // expressionType.isInterface
213 if (scope.isJavaLangObject(castType)) // no runtime error
215 if (((ReferenceBinding) castType).isFinal()) {
216 // no subclass for castType, thus compile-time check is valid
217 if (!castType.isCompatibleWith(expressionType)) {
218 // potential runtime error
219 scope.problemReporter().typeCastError(this, castType,
224 } else { // ----- (castType.isInterface) expressionType.isInterface
226 if (castType == expressionType)
227 return; // identity conversion
228 if (Scope.compareTypes(castType, expressionType) == NotRelated) {
229 MethodBinding[] castTypeMethods = ((ReferenceBinding) castType)
231 MethodBinding[] expressionTypeMethods = ((ReferenceBinding) expressionType)
233 int exprMethodsLength = expressionTypeMethods.length;
234 for (int i = 0, castMethodsLength = castTypeMethods.length; i < castMethodsLength; i++)
235 for (int j = 0; j < exprMethodsLength; j++) {
236 if ((castTypeMethods[i].returnType != expressionTypeMethods[j].returnType)
237 && (castTypeMethods[i].selector == expressionTypeMethods[j].selector)
238 && castTypeMethods[i]
239 .areParametersEqual(expressionTypeMethods[j])) {
240 scope.problemReporter().typeCastError(this,
241 castType, expressionType);
246 needRuntimeCheckcast = true;
251 * Cast expression code generation
253 * @param currentScope
254 * net.sourceforge.phpdt.internal.compiler.lookup.BlockScope
256 * net.sourceforge.phpdt.internal.compiler.codegen.CodeStream
257 * @param valueRequired
260 // public void generateCode(
261 // BlockScope currentScope,
262 // CodeStream codeStream,
263 // boolean valueRequired) {
265 // int pc = codeStream.position;
266 // if (constant != NotAConstant) {
268 // || needRuntimeCheckcast) { // Added for: 1F1W9IG: IVJCOM:WINNT - Compiler
269 // omits casting check
270 // codeStream.generateConstant(constant, implicitConversion);
271 // if (needRuntimeCheckcast) {
272 // codeStream.checkcast(this.resolvedType);
273 // if (!valueRequired)
277 // codeStream.recordPositionsFrom(pc, this.sourceStart);
280 // expression.generateCode(
283 // valueRequired || needRuntimeCheckcast);
284 // if (needRuntimeCheckcast) {
285 // codeStream.checkcast(this.resolvedType);
286 // if (!valueRequired)
289 // if (valueRequired)
290 // codeStream.generateImplicitConversion(implicitConversion);
292 // codeStream.recordPositionsFrom(pc, this.sourceStart);
294 public Expression innermostCastedExpression() {
295 Expression current = this.expression;
296 while (current instanceof CastExpression) {
297 current = ((CastExpression) current).expression;
302 public StringBuffer printExpression(int indent, StringBuffer output) {
305 type.print(0, output).append(") "); //$NON-NLS-1$
306 return expression.printExpression(0, output);
309 public TypeBinding resolveType(BlockScope scope) {
310 // compute a new constant if the cast is effective
312 // due to the fact an expression may start with ( and that a cast can
314 // the field is an expression....it can be a TypeReference OR a
316 // any kind of Expression <-- this last one is invalid.......
318 constant = Constant.NotAConstant;
319 implicitConversion = T_undefined;
320 if ((type instanceof TypeReference) || (type instanceof NameReference)) {
321 this.resolvedType = type.resolveType(scope);
322 TypeBinding castedExpressionType = expression.resolveType(scope);
323 if (this.resolvedType != null && castedExpressionType != null) {
324 areTypesCastCompatible(scope, this.resolvedType,
325 castedExpressionType);
327 return this.resolvedType;
328 } else { // expression as a cast !!!!!!!!
329 TypeBinding castedExpressionType = expression.resolveType(scope);
330 if (castedExpressionType == null)
332 scope.problemReporter().invalidTypeReference(type);
337 public String toStringExpression() {
339 return "(" + type.toString(0) + ") " + //$NON-NLS-2$ //$NON-NLS-1$
340 expression.toStringExpression();
343 public void traverse(ASTVisitor visitor, BlockScope blockScope) {
345 if (visitor.visit(this, blockScope)) {
346 type.traverse(visitor, blockScope);
347 expression.traverse(visitor, blockScope);
349 visitor.endVisit(this, blockScope);