removed Makefile; lifted repo/org.ibex.tool/src/ to src/
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / ast / InstanceOfExpression.java
diff --git a/src/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java b/src/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java
new file mode 100644 (file)
index 0000000..feacdaf
--- /dev/null
@@ -0,0 +1,223 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.ast;
+
+import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.ASTVisitor;
+import org.eclipse.jdt.internal.compiler.codegen.*;
+import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.lookup.*;
+
+public class InstanceOfExpression extends OperatorExpression {
+
+       public Expression expression;
+       public TypeReference type;
+
+       public InstanceOfExpression(
+               Expression expression,
+               TypeReference type,
+               int operator) {
+
+               this.expression = expression;
+               this.type = type;
+               this.bits |= operator << OperatorSHIFT;
+               this.sourceStart = expression.sourceStart;
+               this.sourceEnd = type.sourceEnd;
+       }
+
+       public FlowInfo analyseCode(
+               BlockScope currentScope,
+               FlowContext flowContext,
+               FlowInfo flowInfo) {
+
+               return expression
+                       .analyseCode(currentScope, flowContext, flowInfo)
+                       .unconditionalInits();
+       }
+       /**
+        * Returns false if the instanceof unnecessary
+        */
+       public final boolean checkCastTypesCompatibility(
+               BlockScope scope,
+               TypeBinding castType,
+               TypeBinding expressionType) {
+       
+               //A more complete version of this method is provided on
+               //CastExpression (it deals with constant and need runtime checkcast)
+
+               if (castType == expressionType) return false;
+               
+               //by grammatical construction, the base type check is not necessary
+
+               if (castType == null || expressionType == null) return true;
+       
+               //-----------cast to something which is NOT a base type--------------------------       
+               if (expressionType == NullBinding) {
+                       //      if (castType.isArrayType()){ // 26903 - need checkcast when casting null to array type
+                       //              needRuntimeCheckcast = true;
+                       //      }
+                       return false; //null is compatible with every thing
+               }
+               if (expressionType.isBaseType()) {
+                       scope.problemReporter().notCompatibleTypesError(this, expressionType, castType);
+                       return true;
+               }
+       
+               if (expressionType.isArrayType()) {
+                       if (castType == expressionType) return false; // identity conversion
+       
+                       if (castType.isArrayType()) {
+                               //------- (castType.isArray) expressionType.isArray -----------
+                               TypeBinding exprElementType = ((ArrayBinding) expressionType).elementsType(scope);
+                               if (exprElementType.isBaseType()) {
+                                       // <---stop the recursion------- 
+                                       if (((ArrayBinding) castType).elementsType(scope) != exprElementType)
+                                               scope.problemReporter().notCompatibleTypesError(this, expressionType, castType);
+                                       return true;
+                               }
+                               // recursively on the elements...
+                               return checkCastTypesCompatibility(
+                                       scope,
+                                       ((ArrayBinding) castType).elementsType(scope),
+                                       exprElementType);
+                       } else if (
+                               castType.isClass()) {
+                               //------(castType.isClass) expressionType.isArray ---------------       
+                               if (castType.id == T_Object) {
+                                       return false;
+                               }
+                       } else { //------- (castType.isInterface) expressionType.isArray -----------
+                               if (castType.id == T_JavaLangCloneable || castType.id == T_JavaIoSerializable) {
+                                       return true;
+                               }
+                       }
+                       scope.problemReporter().notCompatibleTypesError(this, expressionType, castType);
+                       return true;
+               }
+       
+               if (expressionType.isClass()) {
+                       if (castType.isArrayType()) {
+                               // ---- (castType.isArray) expressionType.isClass -------
+                               if (expressionType.id == T_Object) { // potential runtime error
+                                       return true;
+                               }
+                       } else if (castType.isClass()) { // ----- (castType.isClass) expressionType.isClass ------
+                               if (expressionType.isCompatibleWith(castType)){ // no runtime error
+                                       return false;
+                               }
+                               if (castType.isCompatibleWith(expressionType)) {
+                                       // potential runtime  error
+                                       return true;
+                               }
+                       } else { // ----- (castType.isInterface) expressionType.isClass -------  
+                               if (expressionType.isCompatibleWith(castType)) 
+                                       return false;
+                               if (!((ReferenceBinding) expressionType).isFinal()) {
+                                   // a subclass may implement the interface ==> no check at compile time
+                                       return true;
+                               }
+                               // no subclass for expressionType, thus compile-time check is valid
+                       }
+                       scope.problemReporter().notCompatibleTypesError(this, expressionType, castType);
+                       return true;
+               }
+       
+               //      if (expressionType.isInterface()) { cannot be anything else
+               if (castType.isArrayType()) {
+                       // ----- (castType.isArray) expressionType.isInterface ------
+                       if (!(expressionType.id == T_JavaLangCloneable
+                                       || expressionType.id == T_JavaIoSerializable)) {// potential runtime error
+                               scope.problemReporter().notCompatibleTypesError(this, expressionType, castType);
+                       }
+                       return true;
+               } else if (castType.isClass()) { // ----- (castType.isClass) expressionType.isInterface --------
+                       if (castType.id == T_Object) { // no runtime error
+                               return false;
+                       }
+                       if (((ReferenceBinding) castType).isFinal()) {
+                               // no subclass for castType, thus compile-time check is valid
+                               if (!castType.isCompatibleWith(expressionType)) {
+                                       // potential runtime error
+                                       scope.problemReporter().notCompatibleTypesError(this, expressionType, castType);
+                                       return true;
+                               }
+                       }
+               } else { // ----- (castType.isInterface) expressionType.isInterface -------
+                       if (expressionType.isCompatibleWith(castType)) { 
+                               return false;
+                       }
+                       if (!castType.isCompatibleWith(expressionType)) {
+                               MethodBinding[] castTypeMethods = ((ReferenceBinding) castType).methods();
+                               MethodBinding[] expressionTypeMethods =
+                                       ((ReferenceBinding) expressionType).methods();
+                               int exprMethodsLength = expressionTypeMethods.length;
+                               for (int i = 0, castMethodsLength = castTypeMethods.length; i < castMethodsLength; i++)
+                                       for (int j = 0; j < exprMethodsLength; j++) {
+                                               if ((castTypeMethods[i].returnType != expressionTypeMethods[j].returnType)
+                                                               && CharOperation.equals(castTypeMethods[i].selector, expressionTypeMethods[j].selector)
+                                                               && castTypeMethods[i].areParametersEqual(expressionTypeMethods[j])) {
+                                                       scope.problemReporter().notCompatibleTypesError(this, expressionType, castType);
+                                               }
+                                       }
+                       }
+               }
+               return true;
+       }
+       /**
+        * Code generation for instanceOfExpression
+        *
+        * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
+        * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
+        * @param valueRequired boolean
+       */
+       public void generateCode(
+               BlockScope currentScope,
+               CodeStream codeStream,
+               boolean valueRequired) {
+
+               int pc = codeStream.position;
+               expression.generateCode(currentScope, codeStream, true);
+               codeStream.instance_of(type.resolvedType);
+               if (!valueRequired)
+                       codeStream.pop();
+               codeStream.recordPositionsFrom(pc, this.sourceStart);
+       }
+
+       public StringBuffer printExpressionNoParenthesis(int indent, StringBuffer output) {
+
+               expression.printExpression(indent, output).append(" instanceof "); //$NON-NLS-1$
+               return type.print(0, output);
+       }
+       
+       public TypeBinding resolveType(BlockScope scope) {
+
+               constant = NotAConstant;
+               TypeBinding expressionType = expression.resolveType(scope);
+               TypeBinding checkType = type.resolveType(scope);
+               if (expressionType == null || checkType == null)
+                       return null;
+
+               boolean necessary = checkCastTypesCompatibility(scope, checkType, expressionType);
+               if (!necessary) {
+                       scope.problemReporter().unnecessaryInstanceof(this, checkType);
+               }
+               return this.resolvedType = BooleanBinding;
+       }
+
+       public void traverse(ASTVisitor visitor, BlockScope scope) {
+
+               if (visitor.visit(this, scope)) {
+                       expression.traverse(visitor, scope);
+                       type.traverse(visitor, scope);
+               }
+               visitor.endVisit(this, scope);
+       }
+}