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