removed Makefile; lifted repo/org.ibex.tool/src/ to src/
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / ast / InstanceOfExpression.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2004 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 org.eclipse.jdt.internal.compiler.ast;
12
13 import org.eclipse.jdt.core.compiler.CharOperation;
14 import org.eclipse.jdt.internal.compiler.ASTVisitor;
15 import org.eclipse.jdt.internal.compiler.codegen.*;
16 import org.eclipse.jdt.internal.compiler.flow.*;
17 import org.eclipse.jdt.internal.compiler.lookup.*;
18
19 public class InstanceOfExpression extends OperatorExpression {
20
21         public Expression expression;
22         public TypeReference type;
23
24         public InstanceOfExpression(
25                 Expression expression,
26                 TypeReference type,
27                 int operator) {
28
29                 this.expression = expression;
30                 this.type = type;
31                 this.bits |= operator << OperatorSHIFT;
32                 this.sourceStart = expression.sourceStart;
33                 this.sourceEnd = type.sourceEnd;
34         }
35
36         public FlowInfo analyseCode(
37                 BlockScope currentScope,
38                 FlowContext flowContext,
39                 FlowInfo flowInfo) {
40
41                 return expression
42                         .analyseCode(currentScope, flowContext, flowInfo)
43                         .unconditionalInits();
44         }
45         /**
46          * Returns false if the instanceof unnecessary
47          */
48         public final boolean checkCastTypesCompatibility(
49                 BlockScope scope,
50                 TypeBinding castType,
51                 TypeBinding expressionType) {
52         
53                 //A more complete version of this method is provided on
54                 //CastExpression (it deals with constant and need runtime checkcast)
55
56                 if (castType == expressionType) return false;
57                 
58                 //by grammatical construction, the base type check is not necessary
59
60                 if (castType == null || expressionType == null) return true;
61         
62                 //-----------cast to something which is NOT a base type--------------------------       
63                 if (expressionType == NullBinding) {
64                         //      if (castType.isArrayType()){ // 26903 - need checkcast when casting null to array type
65                         //              needRuntimeCheckcast = true;
66                         //      }
67                         return false; //null is compatible with every thing
68                 }
69                 if (expressionType.isBaseType()) {
70                         scope.problemReporter().notCompatibleTypesError(this, expressionType, castType);
71                         return true;
72                 }
73         
74                 if (expressionType.isArrayType()) {
75                         if (castType == expressionType) return false; // identity conversion
76         
77                         if (castType.isArrayType()) {
78                                 //------- (castType.isArray) expressionType.isArray -----------
79                                 TypeBinding exprElementType = ((ArrayBinding) expressionType).elementsType(scope);
80                                 if (exprElementType.isBaseType()) {
81                                         // <---stop the recursion------- 
82                                         if (((ArrayBinding) castType).elementsType(scope) != exprElementType)
83                                                 scope.problemReporter().notCompatibleTypesError(this, expressionType, castType);
84                                         return true;
85                                 }
86                                 // recursively on the elements...
87                                 return checkCastTypesCompatibility(
88                                         scope,
89                                         ((ArrayBinding) castType).elementsType(scope),
90                                         exprElementType);
91                         } else if (
92                                 castType.isClass()) {
93                                 //------(castType.isClass) expressionType.isArray ---------------       
94                                 if (castType.id == T_Object) {
95                                         return false;
96                                 }
97                         } else { //------- (castType.isInterface) expressionType.isArray -----------
98                                 if (castType.id == T_JavaLangCloneable || castType.id == T_JavaIoSerializable) {
99                                         return true;
100                                 }
101                         }
102                         scope.problemReporter().notCompatibleTypesError(this, expressionType, castType);
103                         return true;
104                 }
105         
106                 if (expressionType.isClass()) {
107                         if (castType.isArrayType()) {
108                                 // ---- (castType.isArray) expressionType.isClass -------
109                                 if (expressionType.id == T_Object) { // potential runtime error
110                                         return true;
111                                 }
112                         } else if (castType.isClass()) { // ----- (castType.isClass) expressionType.isClass ------
113                                 if (expressionType.isCompatibleWith(castType)){ // no runtime error
114                                         return false;
115                                 }
116                                 if (castType.isCompatibleWith(expressionType)) {
117                                         // potential runtime  error
118                                         return true;
119                                 }
120                         } else { // ----- (castType.isInterface) expressionType.isClass -------  
121                                 if (expressionType.isCompatibleWith(castType)) 
122                                         return false;
123                                 if (!((ReferenceBinding) expressionType).isFinal()) {
124                                     // a subclass may implement the interface ==> no check at compile time
125                                         return true;
126                                 }
127                                 // no subclass for expressionType, thus compile-time check is valid
128                         }
129                         scope.problemReporter().notCompatibleTypesError(this, expressionType, castType);
130                         return true;
131                 }
132         
133                 //      if (expressionType.isInterface()) { cannot be anything else
134                 if (castType.isArrayType()) {
135                         // ----- (castType.isArray) expressionType.isInterface ------
136                         if (!(expressionType.id == T_JavaLangCloneable
137                                         || expressionType.id == T_JavaIoSerializable)) {// potential runtime error
138                                 scope.problemReporter().notCompatibleTypesError(this, expressionType, castType);
139                         }
140                         return true;
141                 } else if (castType.isClass()) { // ----- (castType.isClass) expressionType.isInterface --------
142                         if (castType.id == T_Object) { // no runtime error
143                                 return false;
144                         }
145                         if (((ReferenceBinding) castType).isFinal()) {
146                                 // no subclass for castType, thus compile-time check is valid
147                                 if (!castType.isCompatibleWith(expressionType)) {
148                                         // potential runtime error
149                                         scope.problemReporter().notCompatibleTypesError(this, expressionType, castType);
150                                         return true;
151                                 }
152                         }
153                 } else { // ----- (castType.isInterface) expressionType.isInterface -------
154                         if (expressionType.isCompatibleWith(castType)) { 
155                                 return false;
156                         }
157                         if (!castType.isCompatibleWith(expressionType)) {
158                                 MethodBinding[] castTypeMethods = ((ReferenceBinding) castType).methods();
159                                 MethodBinding[] expressionTypeMethods =
160                                         ((ReferenceBinding) expressionType).methods();
161                                 int exprMethodsLength = expressionTypeMethods.length;
162                                 for (int i = 0, castMethodsLength = castTypeMethods.length; i < castMethodsLength; i++)
163                                         for (int j = 0; j < exprMethodsLength; j++) {
164                                                 if ((castTypeMethods[i].returnType != expressionTypeMethods[j].returnType)
165                                                                 && CharOperation.equals(castTypeMethods[i].selector, expressionTypeMethods[j].selector)
166                                                                 && castTypeMethods[i].areParametersEqual(expressionTypeMethods[j])) {
167                                                         scope.problemReporter().notCompatibleTypesError(this, expressionType, castType);
168                                                 }
169                                         }
170                         }
171                 }
172                 return true;
173         }
174         /**
175          * Code generation for instanceOfExpression
176          *
177          * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
178          * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
179          * @param valueRequired boolean
180         */
181         public void generateCode(
182                 BlockScope currentScope,
183                 CodeStream codeStream,
184                 boolean valueRequired) {
185
186                 int pc = codeStream.position;
187                 expression.generateCode(currentScope, codeStream, true);
188                 codeStream.instance_of(type.resolvedType);
189                 if (!valueRequired)
190                         codeStream.pop();
191                 codeStream.recordPositionsFrom(pc, this.sourceStart);
192         }
193
194         public StringBuffer printExpressionNoParenthesis(int indent, StringBuffer output) {
195
196                 expression.printExpression(indent, output).append(" instanceof "); //$NON-NLS-1$
197                 return type.print(0, output);
198         }
199         
200         public TypeBinding resolveType(BlockScope scope) {
201
202                 constant = NotAConstant;
203                 TypeBinding expressionType = expression.resolveType(scope);
204                 TypeBinding checkType = type.resolveType(scope);
205                 if (expressionType == null || checkType == null)
206                         return null;
207
208                 boolean necessary = checkCastTypesCompatibility(scope, checkType, expressionType);
209                 if (!necessary) {
210                         scope.problemReporter().unnecessaryInstanceof(this, checkType);
211                 }
212                 return this.resolvedType = BooleanBinding;
213         }
214
215         public void traverse(ASTVisitor visitor, BlockScope scope) {
216
217                 if (visitor.visit(this, scope)) {
218                         expression.traverse(visitor, scope);
219                         type.traverse(visitor, scope);
220                 }
221                 visitor.endVisit(this, scope);
222         }
223 }