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
7  *
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.ast;
12 
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.lookup.ArrayBinding;
17 import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
18 import net.sourceforge.phpdt.internal.compiler.lookup.MethodBinding;
19 import net.sourceforge.phpdt.internal.compiler.lookup.ReferenceBinding;
20 import net.sourceforge.phpdt.internal.compiler.lookup.Scope;
21 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
22 
23 public class InstanceOfExpression extends OperatorExpression {
24 
25 	public Expression expression;
26 
27 	public TypeReference type;
28 
InstanceOfExpression(Expression expression, TypeReference type, int operator)29 	public InstanceOfExpression(Expression expression, TypeReference type,
30 			int operator) {
31 
32 		this.expression = expression;
33 		this.type = type;
34 		this.bits |= operator << OperatorSHIFT;
35 		this.sourceStart = expression.sourceStart;
36 		this.sourceEnd = type.sourceEnd;
37 	}
38 
analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo)39 	public FlowInfo analyseCode(BlockScope currentScope,
40 			FlowContext flowContext, FlowInfo flowInfo) {
41 
42 		return expression.analyseCode(currentScope, flowContext, flowInfo)
43 				.unconditionalInits();
44 	}
45 
areTypesCastCompatible(BlockScope scope, TypeBinding castType, TypeBinding expressionType)46 	public final boolean areTypesCastCompatible(BlockScope scope,
47 			TypeBinding castType, TypeBinding expressionType) {
48 
49 		// see specifications p.68
50 		// A more cpmplete version of this method is provided on
51 		// CastExpression (it deals with constant and need runtime checkcast)
52 
53 		if (castType == expressionType)
54 			return true;
55 
56 		// by grammatical construction, the first test is ALWAYS false
57 		// if (castTb.isBaseType())
58 		// { if (expressionTb.isBaseType())
59 		// { if
60 		// (expression.isConstantValueOfTypeAssignableToType(expressionTb,castTb))
61 		// { return true;}
62 		// else
63 		// { if (expressionTb==castTb)
64 		// { return true;}
65 		// else
66 		// { if (scope.areTypesCompatible(expressionTb,castTb))
67 		// { return true; }
68 		//
69 		// if (BaseTypeBinding.isNarrowing(castTb.id,expressionTb.id))
70 		// { return true;}
71 		// return false;}}}
72 		// else
73 		// { return false; }}
74 		// else
75 		{ // -------------checkcast to something which is NOT a
76 			// basetype----------------------------------
77 
78 			// null is compatible with every thing ....
79 			if (NullBinding == expressionType) {
80 				return true;
81 			}
82 			if (expressionType.isArrayType()) {
83 				if (castType.isArrayType()) {
84 					// ------- (castTb.isArray) expressionTb.isArray -----------
85 					TypeBinding expressionEltTb = ((ArrayBinding) expressionType)
86 							.elementsType(scope);
87 					if (expressionEltTb.isBaseType())
88 						// <---stop the recursion-------
89 						return ((ArrayBinding) castType).elementsType(scope) == expressionEltTb;
90 					// recursivly on the elts...
91 					return areTypesCastCompatible(scope,
92 							((ArrayBinding) castType).elementsType(scope),
93 							expressionEltTb);
94 				}
95 				if (castType.isClass()) {
96 					// ------(castTb.isClass) expressionTb.isArray
97 					// ---------------
98 					if (scope.isJavaLangObject(castType))
99 						return true;
100 					return false;
101 				}
102 				if (castType.isInterface()) {
103 					// ------- (castTb.isInterface) expressionTb.isArray
104 					// -----------
105 					if (scope.isJavaLangCloneable(castType)
106 							|| scope.isJavaIoSerializable(castType)) {
107 						return true;
108 					}
109 					return false;
110 				}
111 
112 				return false;
113 			}
114 			if (expressionType.isBaseType()) {
115 				return false;
116 			}
117 			if (expressionType.isClass()) {
118 				if (castType.isArrayType()) {
119 					// ---- (castTb.isArray) expressionTb.isClass -------
120 					if (scope.isJavaLangObject(expressionType)) {
121 						return true;
122 					} else {
123 						return false;
124 					}
125 				}
126 				if (castType.isClass()) { // ----- (castTb.isClass)
127 											// expressionTb.isClass ------
128 					if (expressionType.isCompatibleWith(castType))
129 						return true;
130 					else {
131 						if (castType.isCompatibleWith(expressionType)) {
132 							return true;
133 						}
134 						return false;
135 					}
136 				}
137 				if (castType.isInterface()) {
138 					// ----- (castTb.isInterface) expressionTb.isClass -------
139 					if (((ReferenceBinding) expressionType).isFinal()) {
140 						// no subclass for expressionTb, thus compile-time check
141 						// is valid
142 						if (expressionType.isCompatibleWith(castType))
143 							return true;
144 						return false;
145 					} else {
146 						return true;
147 					}
148 				}
149 
150 				return false;
151 			}
152 			if (expressionType.isInterface()) {
153 				if (castType.isArrayType()) {
154 					// ----- (castTb.isArray) expressionTb.isInterface ------
155 					if (scope.isJavaLangCloneable(expressionType)
156 							|| scope.isJavaIoSerializable(expressionType))
157 					// potential runtime error
158 					{
159 						return true;
160 					}
161 					return false;
162 				}
163 				if (castType.isClass()) {
164 					// ----- (castTb.isClass) expressionTb.isInterface --------
165 					if (scope.isJavaLangObject(castType))
166 						return true;
167 					if (((ReferenceBinding) castType).isFinal()) {
168 						// no subclass for castTb, thus compile-time check is
169 						// valid
170 						if (castType.isCompatibleWith(expressionType)) {
171 							return true;
172 						}
173 						return false;
174 					}
175 					return true;
176 				}
177 				if (castType.isInterface()) {
178 					// ----- (castTb.isInterface) expressionTb.isInterface
179 					// -------
180 					if ((Scope.compareTypes(castType, expressionType) == NotRelated)) {
181 						MethodBinding[] castTbMethods = ((ReferenceBinding) castType)
182 								.methods();
183 						int castTbMethodsLength = castTbMethods.length;
184 						MethodBinding[] expressionTbMethods = ((ReferenceBinding) expressionType)
185 								.methods();
186 						int expressionTbMethodsLength = expressionTbMethods.length;
187 						for (int i = 0; i < castTbMethodsLength; i++) {
188 							for (int j = 0; j < expressionTbMethodsLength; j++) {
189 								if (castTbMethods[i].selector == expressionTbMethods[j].selector) {
190 									if (castTbMethods[i].returnType != expressionTbMethods[j].returnType) {
191 										if (castTbMethods[i]
192 												.areParametersEqual(expressionTbMethods[j])) {
193 											return false;
194 										}
195 									}
196 								}
197 							}
198 						}
199 					}
200 					return true;
201 				}
202 
203 				return false;
204 			}
205 
206 			return false;
207 		}
208 	}
209 
210 	/**
211 	 * Code generation for instanceOfExpression
212 	 *
213 	 * @param currentScope
214 	 *            net.sourceforge.phpdt.internal.compiler.lookup.BlockScope
215 	 * @param codeStream
216 	 *            net.sourceforge.phpdt.internal.compiler.codegen.CodeStream
217 	 * @param valueRequired
218 	 *            boolean
219 	 */
220 	// public void generateCode(
221 	// BlockScope currentScope,
222 	// CodeStream codeStream,
223 	// boolean valueRequired) {
224 	//
225 	// int pc = codeStream.position;
226 	// expression.generateCode(currentScope, codeStream, true);
227 	// codeStream.instance_of(type.resolvedType);
228 	// if (!valueRequired)
229 	// codeStream.pop();
230 	// codeStream.recordPositionsFrom(pc, this.sourceStart);
231 	// }
resolveType(BlockScope scope)232 	public TypeBinding resolveType(BlockScope scope) {
233 
234 		constant = NotAConstant;
235 		TypeBinding expressionType = expression.resolveType(scope);
236 		TypeBinding checkType = type.resolveType(scope);
237 		if (expressionType == null || checkType == null)
238 			return null;
239 
240 		if (!areTypesCastCompatible(scope, checkType, expressionType)) {
241 			scope.problemReporter().notCompatibleTypesError(this,
242 					expressionType, checkType);
243 			return null;
244 		}
245 		this.resolvedType = BooleanBinding;
246 		return BooleanBinding;
247 	}
248 
printExpressionNoParenthesis(int indent, StringBuffer output)249 	public StringBuffer printExpressionNoParenthesis(int indent,
250 			StringBuffer output) {
251 
252 		expression.printExpression(indent, output).append(" instanceof "); //$NON-NLS-1$
253 		return type.print(0, output);
254 	}
255 
toStringExpressionNoParenthesis()256 	public String toStringExpressionNoParenthesis() {
257 
258 		return expression.toStringExpression() + " instanceof " + //$NON-NLS-1$
259 				type.toString(0);
260 	}
261 
traverse(ASTVisitor visitor, BlockScope scope)262 	public void traverse(ASTVisitor visitor, BlockScope scope) {
263 
264 		if (visitor.visit(this, scope)) {
265 			expression.traverse(visitor, scope);
266 			type.traverse(visitor, scope);
267 		}
268 		visitor.endVisit(this, scope);
269 	}
270 }
271