Applying pteague's patch (re #685)
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / ast / InstanceOfExpression.java
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
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
39         public FlowInfo analyseCode(BlockScope currentScope,
40                         FlowContext flowContext, FlowInfo flowInfo) {
41
42                 return expression.analyseCode(currentScope, flowContext, flowInfo)
43                                 .unconditionalInits();
44         }
45
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         // }
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
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
256         public String toStringExpressionNoParenthesis() {
257
258                 return expression.toStringExpression() + " instanceof " + //$NON-NLS-1$
259                                 type.toString(0);
260         }
261
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 }