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
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.jdt.internal.compiler.ast;
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.*;
19 public class InstanceOfExpression extends OperatorExpression {
21 public Expression expression;
22 public TypeReference type;
24 public InstanceOfExpression(
25 Expression expression,
29 this.expression = expression;
31 this.bits |= operator << OperatorSHIFT;
32 this.sourceStart = expression.sourceStart;
33 this.sourceEnd = type.sourceEnd;
36 public FlowInfo analyseCode(
37 BlockScope currentScope,
38 FlowContext flowContext,
42 .analyseCode(currentScope, flowContext, flowInfo)
43 .unconditionalInits();
46 * Returns false if the instanceof unnecessary
48 public final boolean checkCastTypesCompatibility(
51 TypeBinding expressionType) {
53 //A more complete version of this method is provided on
54 //CastExpression (it deals with constant and need runtime checkcast)
56 if (castType == expressionType) return false;
58 //by grammatical construction, the base type check is not necessary
60 if (castType == null || expressionType == null) return true;
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;
67 return false; //null is compatible with every thing
69 if (expressionType.isBaseType()) {
70 scope.problemReporter().notCompatibleTypesError(this, expressionType, castType);
74 if (expressionType.isArrayType()) {
75 if (castType == expressionType) return false; // identity conversion
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);
86 // recursively on the elements...
87 return checkCastTypesCompatibility(
89 ((ArrayBinding) castType).elementsType(scope),
93 //------(castType.isClass) expressionType.isArray ---------------
94 if (castType.id == T_Object) {
97 } else { //------- (castType.isInterface) expressionType.isArray -----------
98 if (castType.id == T_JavaLangCloneable || castType.id == T_JavaIoSerializable) {
102 scope.problemReporter().notCompatibleTypesError(this, expressionType, castType);
106 if (expressionType.isClass()) {
107 if (castType.isArrayType()) {
108 // ---- (castType.isArray) expressionType.isClass -------
109 if (expressionType.id == T_Object) { // potential runtime error
112 } else if (castType.isClass()) { // ----- (castType.isClass) expressionType.isClass ------
113 if (expressionType.isCompatibleWith(castType)){ // no runtime error
116 if (castType.isCompatibleWith(expressionType)) {
117 // potential runtime error
120 } else { // ----- (castType.isInterface) expressionType.isClass -------
121 if (expressionType.isCompatibleWith(castType))
123 if (!((ReferenceBinding) expressionType).isFinal()) {
124 // a subclass may implement the interface ==> no check at compile time
127 // no subclass for expressionType, thus compile-time check is valid
129 scope.problemReporter().notCompatibleTypesError(this, expressionType, castType);
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);
141 } else if (castType.isClass()) { // ----- (castType.isClass) expressionType.isInterface --------
142 if (castType.id == T_Object) { // no runtime error
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);
153 } else { // ----- (castType.isInterface) expressionType.isInterface -------
154 if (expressionType.isCompatibleWith(castType)) {
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);
175 * Code generation for instanceOfExpression
177 * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
178 * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
179 * @param valueRequired boolean
181 public void generateCode(
182 BlockScope currentScope,
183 CodeStream codeStream,
184 boolean valueRequired) {
186 int pc = codeStream.position;
187 expression.generateCode(currentScope, codeStream, true);
188 codeStream.instance_of(type.resolvedType);
191 codeStream.recordPositionsFrom(pc, this.sourceStart);
194 public StringBuffer printExpressionNoParenthesis(int indent, StringBuffer output) {
196 expression.printExpression(indent, output).append(" instanceof "); //$NON-NLS-1$
197 return type.print(0, output);
200 public TypeBinding resolveType(BlockScope scope) {
202 constant = NotAConstant;
203 TypeBinding expressionType = expression.resolveType(scope);
204 TypeBinding checkType = type.resolveType(scope);
205 if (expressionType == null || checkType == null)
208 boolean necessary = checkCastTypesCompatibility(scope, checkType, expressionType);
210 scope.problemReporter().unnecessaryInstanceof(this, checkType);
212 return this.resolvedType = BooleanBinding;
215 public void traverse(ASTVisitor visitor, BlockScope scope) {
217 if (visitor.visit(this, scope)) {
218 expression.traverse(visitor, scope);
219 type.traverse(visitor, scope);
221 visitor.endVisit(this, scope);