1 11 package org.eclipse.jdt.internal.compiler.ast; 12 13 import org.eclipse.jdt.internal.compiler.ASTVisitor; 14 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; 15 import org.eclipse.jdt.internal.compiler.codegen.CodeStream; 16 import org.eclipse.jdt.internal.compiler.codegen.BranchLabel; 17 import org.eclipse.jdt.internal.compiler.flow.FlowContext; 18 import org.eclipse.jdt.internal.compiler.flow.FlowInfo; 19 import org.eclipse.jdt.internal.compiler.flow.LoopingFlowContext; 20 import org.eclipse.jdt.internal.compiler.flow.UnconditionalFlowInfo; 21 import org.eclipse.jdt.internal.compiler.impl.Constant; 22 import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding; 23 import org.eclipse.jdt.internal.compiler.lookup.Binding; 24 import org.eclipse.jdt.internal.compiler.lookup.BlockScope; 25 import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; 26 import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; 27 import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding; 28 import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; 29 import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; 30 31 public class ForeachStatement extends Statement { 32 33 public LocalDeclaration elementVariable; 34 public int elementVariableImplicitWidening = -1; 35 public Expression collection; 36 public Statement action; 37 38 private int kind; 40 private static final int ARRAY = 0; 42 private static final int RAW_ITERABLE = 1; 43 private static final int GENERIC_ITERABLE = 2; 44 45 private TypeBinding iteratorReceiverType; 46 private TypeBinding collectionElementType; 47 48 private BranchLabel breakLabel; 50 private BranchLabel continueLabel; 51 52 public BlockScope scope; 53 54 public LocalVariableBinding indexVariable; 56 public LocalVariableBinding collectionVariable; public LocalVariableBinding maxVariable; 58 private static final char[] SecretIndexVariableName = " index".toCharArray(); private static final char[] SecretCollectionVariableName = " collection".toCharArray(); private static final char[] SecretMaxVariableName = " max".toCharArray(); 63 int postCollectionInitStateIndex = -1; 64 int mergedInitStateIndex = -1; 65 66 public ForeachStatement( 67 LocalDeclaration elementVariable, 68 int start) { 69 70 this.elementVariable = elementVariable; 71 this.sourceStart = start; 72 this.kind = -1; 73 } 74 75 public FlowInfo analyseCode( 76 BlockScope currentScope, 77 FlowContext flowContext, 78 FlowInfo flowInfo) { 79 breakLabel = new BranchLabel(); 81 continueLabel = new BranchLabel(); 82 83 this.collection.checkNPE(currentScope, flowContext, flowInfo); 85 flowInfo = this.elementVariable.analyseCode(scope, flowContext, flowInfo); 86 FlowInfo condInfo = this.collection.analyseCode(scope, flowContext, flowInfo.copy()); 87 88 condInfo.markAsDefinitelyAssigned(this.elementVariable.binding); 90 91 this.postCollectionInitStateIndex = currentScope.methodScope().recordInitializationStates(condInfo); 92 93 LoopingFlowContext loopingContext = 95 new LoopingFlowContext(flowContext, flowInfo, this, breakLabel, 96 continueLabel, scope); 97 UnconditionalFlowInfo actionInfo = 98 condInfo.nullInfoLessUnconditionalCopy(); 99 actionInfo.markAsDefinitelyUnknown(this.elementVariable.binding); 100 FlowInfo exitBranch; 101 if (!(action == null || (action.isEmptyBlock() 102 && currentScope.compilerOptions().complianceLevel <= ClassFileConstants.JDK1_3))) { 103 104 if (!this.action.complainIfUnreachable(actionInfo, scope, false)) { 105 actionInfo = action. 106 analyseCode(scope, loopingContext, actionInfo). 107 unconditionalCopy(); 108 } 109 110 exitBranch = flowInfo.unconditionalCopy(). 112 addInitializationsFrom(condInfo.initsWhenFalse()); 113 if ((actionInfo.tagBits & loopingContext.initsOnContinue.tagBits & 115 FlowInfo.UNREACHABLE) != 0) { 116 continueLabel = null; 117 } else { 118 actionInfo = actionInfo.mergedWith(loopingContext.initsOnContinue); 119 loopingContext.complainOnDeferredFinalChecks(scope, actionInfo); 120 exitBranch.addPotentialInitializationsFrom(actionInfo); 121 } 122 } else { 123 exitBranch = condInfo.initsWhenFalse(); 124 } 125 126 final boolean hasEmptyAction = this.action == null 129 || this.action.isEmptyBlock() 130 || ((this.action.bits & IsUsefulEmptyStatement) != 0); 131 132 switch(this.kind) { 133 case ARRAY : 134 if (!hasEmptyAction 135 || this.elementVariable.binding.resolvedPosition != -1) { 136 this.collectionVariable.useFlag = LocalVariableBinding.USED; 137 if (this.continueLabel != null) { 138 this.indexVariable.useFlag = LocalVariableBinding.USED; 139 this.maxVariable.useFlag = LocalVariableBinding.USED; 140 } 141 } 142 break; 143 case RAW_ITERABLE : 144 case GENERIC_ITERABLE : 145 this.indexVariable.useFlag = LocalVariableBinding.USED; 146 break; 147 } 148 loopingContext.complainOnDeferredNullChecks(currentScope, actionInfo); 150 151 FlowInfo mergedInfo = FlowInfo.mergedOptimizedBranches( 152 (loopingContext.initsOnBreak.tagBits & 153 FlowInfo.UNREACHABLE) != 0 ? 154 loopingContext.initsOnBreak : 155 flowInfo.addInitializationsFrom(loopingContext.initsOnBreak), false, 157 exitBranch, 158 false, 159 true ); 160 mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo); 161 return mergedInfo; 162 } 163 164 170 public void generateCode(BlockScope currentScope, CodeStream codeStream) { 171 172 if ((bits & IsReachable) == 0) { 173 return; 174 } 175 int pc = codeStream.position; 176 final boolean hasEmptyAction = this.action == null 177 || this.action.isEmptyBlock() 178 || ((this.action.bits & IsUsefulEmptyStatement) != 0); 179 180 if (hasEmptyAction 181 && this.elementVariable.binding.resolvedPosition == -1 182 && this.kind == ARRAY) { 183 collection.generateCode(scope, codeStream, false); 184 codeStream.exitUserScope(scope); 185 if (mergedInitStateIndex != -1) { 186 codeStream.removeNotDefinitelyAssignedVariables(currentScope, mergedInitStateIndex); 187 codeStream.addDefinitelyAssignedVariables(currentScope, mergedInitStateIndex); 188 } 189 codeStream.recordPositionsFrom(pc, this.sourceStart); 190 return; 191 } 192 193 switch(this.kind) { 195 case ARRAY : 196 collection.generateCode(scope, codeStream, true); 197 codeStream.store(this.collectionVariable, true); 198 if (this.continueLabel != null) { 199 codeStream.arraylength(); 201 codeStream.store(this.maxVariable, false); 202 codeStream.iconst_0(); 203 codeStream.store(this.indexVariable, false); 204 } else { 205 } 207 break; 208 case RAW_ITERABLE : 209 case GENERIC_ITERABLE : 210 collection.generateCode(scope, codeStream, true); 211 MethodBinding iteratorMethodBinding = 213 new MethodBinding( 214 ClassFileConstants.AccPublic, 215 "iterator".toCharArray(), scope.getJavaUtilIterator(), 217 Binding.NO_PARAMETERS, 218 Binding.NO_EXCEPTIONS, 219 (ReferenceBinding) this.iteratorReceiverType.erasure()); 220 if (this.iteratorReceiverType.isInterface()) { 221 codeStream.invokeinterface(iteratorMethodBinding); 222 } else { 223 codeStream.invokevirtual(iteratorMethodBinding); 224 } 225 codeStream.store(this.indexVariable, false); 226 break; 227 } 228 BranchLabel actionLabel = new BranchLabel(codeStream); 230 actionLabel.tagBits |= BranchLabel.USED; 231 BranchLabel conditionLabel = new BranchLabel(codeStream); 232 conditionLabel.tagBits |= BranchLabel.USED; 233 breakLabel.initialize(codeStream); 234 if (this.continueLabel == null) { 235 conditionLabel.place(); 237 int conditionPC = codeStream.position; 238 switch(this.kind) { 239 case ARRAY : 240 codeStream.arraylength(); 243 codeStream.ifeq(breakLabel); 244 break; 245 case RAW_ITERABLE : 246 case GENERIC_ITERABLE : 247 codeStream.load(this.indexVariable); 248 codeStream.invokeJavaUtilIteratorHasNext(); 249 codeStream.ifeq(breakLabel); 250 break; 251 } 252 codeStream.recordPositionsFrom(conditionPC, this.elementVariable.sourceStart); 253 } else { 254 this.continueLabel.initialize(codeStream); 255 this.continueLabel.tagBits |= BranchLabel.USED; 256 codeStream.goto_(conditionLabel); 258 } 259 260 actionLabel.place(); 262 263 switch(this.kind) { 265 case ARRAY : 266 if (this.elementVariable.binding.resolvedPosition != -1) { 267 codeStream.load(this.collectionVariable); 268 if (this.continueLabel == null) { 269 codeStream.iconst_0(); } else { 271 codeStream.load(this.indexVariable); 272 } 273 codeStream.arrayAt(this.collectionElementType.id); 274 if (this.elementVariableImplicitWidening != -1) { 275 codeStream.generateImplicitConversion(this.elementVariableImplicitWidening); 276 } 277 codeStream.store(this.elementVariable.binding, false); 278 codeStream.addVisibleLocalVariable(this.elementVariable.binding); 279 if (this.postCollectionInitStateIndex != -1) { 280 codeStream.addDefinitelyAssignedVariables( 281 currentScope, 282 this.postCollectionInitStateIndex); 283 } 284 } 285 break; 286 case RAW_ITERABLE : 287 case GENERIC_ITERABLE : 288 codeStream.load(this.indexVariable); 289 codeStream.invokeJavaUtilIteratorNext(); 290 if (this.elementVariable.binding.type.id != T_JavaLangObject) { 291 if (this.elementVariableImplicitWidening != -1) { 292 codeStream.checkcast(this.collectionElementType); 293 codeStream.generateImplicitConversion(this.elementVariableImplicitWidening); 294 } else { 295 codeStream.checkcast(this.elementVariable.binding.type); 296 } 297 } 298 if (this.elementVariable.binding.resolvedPosition == -1) { 299 codeStream.pop(); 300 } else { 301 codeStream.store(this.elementVariable.binding, false); 302 codeStream.addVisibleLocalVariable(this.elementVariable.binding); 303 if (this.postCollectionInitStateIndex != -1) { 304 codeStream.addDefinitelyAssignedVariables( 305 currentScope, 306 this.postCollectionInitStateIndex); 307 } 308 } 309 break; 310 } 311 312 if (!hasEmptyAction) { 313 this.action.generateCode(scope, codeStream); 314 } 315 codeStream.removeVariable(this.elementVariable.binding); 316 if (this.postCollectionInitStateIndex != -1) { 317 codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.postCollectionInitStateIndex); 318 } 319 if (this.continueLabel != null) { 321 this.continueLabel.place(); 322 int continuationPC = codeStream.position; 323 switch(this.kind) { 325 case ARRAY : 326 if (!hasEmptyAction || this.elementVariable.binding.resolvedPosition >= 0) { 327 codeStream.iinc(this.indexVariable.resolvedPosition, 1); 328 } 329 conditionLabel.place(); 331 codeStream.load(this.indexVariable); 332 codeStream.load(this.maxVariable); 333 codeStream.if_icmplt(actionLabel); 334 break; 335 case RAW_ITERABLE : 336 case GENERIC_ITERABLE : 337 conditionLabel.place(); 339 codeStream.load(this.indexVariable); 340 codeStream.invokeJavaUtilIteratorHasNext(); 341 codeStream.ifne(actionLabel); 342 break; 343 } 344 codeStream.recordPositionsFrom(continuationPC, this.elementVariable.sourceStart); 345 } 346 codeStream.exitUserScope(scope); 347 if (mergedInitStateIndex != -1) { 348 codeStream.removeNotDefinitelyAssignedVariables(currentScope, mergedInitStateIndex); 349 codeStream.addDefinitelyAssignedVariables(currentScope, mergedInitStateIndex); 350 } 351 breakLabel.place(); 352 codeStream.recordPositionsFrom(pc, this.sourceStart); 353 } 354 355 public StringBuffer printStatement(int indent, StringBuffer output) { 356 357 printIndent(indent, output).append("for ("); this.elementVariable.printAsExpression(0, output); 359 output.append(" : "); this.collection.print(0, output).append(") "); if (this.action == null) { 363 output.append(';'); 364 } else { 365 output.append('\n'); 366 this.action.printStatement(indent + 1, output); 367 } 368 return output; 369 } 370 371 public void resolve(BlockScope upperScope) { 372 scope = new BlockScope(upperScope); 374 this.elementVariable.resolve(scope); TypeBinding elementType = this.elementVariable.type.resolvedType; 376 TypeBinding collectionType = this.collection == null ? null : this.collection.resolveType(scope); 377 378 if (elementType != null && collectionType != null) { 379 if (collectionType.isArrayType()) { this.kind = ARRAY; 381 this.collection.computeConversion(scope,collectionType, collectionType); 382 this.collectionElementType = ((ArrayBinding) collectionType).elementsType(); 383 if (!collectionElementType.isCompatibleWith(elementType) 384 && !scope.isBoxingCompatibleWith(collectionElementType, elementType)) { 385 scope.problemReporter().notCompatibleTypesErrorInForeach(collection, collectionElementType, elementType); 386 } 387 int compileTimeTypeID = collectionElementType.id; 389 if (elementType.isBaseType()) { 390 if (!collectionElementType.isBaseType()) { 391 compileTimeTypeID = scope.environment().computeBoxingType(collectionElementType).id; 392 this.elementVariableImplicitWidening = UNBOXING; 393 if (elementType.isBaseType()) { 394 this.elementVariableImplicitWidening |= (elementType.id << 4) + compileTimeTypeID; 395 scope.problemReporter().autoboxing(collection, collectionElementType, elementType); 396 } 397 } else { 398 this.elementVariableImplicitWidening = (elementType.id << 4) + compileTimeTypeID; 399 } 400 } else { 401 if (collectionElementType.isBaseType()) { 402 int boxedID = scope.environment().computeBoxingType(collectionElementType).id; 403 this.elementVariableImplicitWidening = BOXING | (compileTimeTypeID << 4) | compileTimeTypeID; compileTimeTypeID = boxedID; 405 scope.problemReporter().autoboxing(collection, collectionElementType, elementType); 406 } 407 } 408 } else if (collectionType instanceof ReferenceBinding) { 409 ReferenceBinding iterableType = ((ReferenceBinding)collectionType).findSuperTypeErasingTo(T_JavaLangIterable, false ); 410 checkIterable: { 411 if (iterableType == null) break checkIterable; 412 413 this.iteratorReceiverType = collectionType.erasure(); 414 if (((ReferenceBinding)iteratorReceiverType).findSuperTypeErasingTo(T_JavaLangIterable, false) == null) { 415 this.iteratorReceiverType = iterableType; this.collection.computeConversion(scope, iterableType, collectionType); 417 } else { 418 this.collection.computeConversion(scope, collectionType, collectionType); 419 } 420 421 TypeBinding[] arguments = null; 422 switch (iterableType.kind()) { 423 case Binding.RAW_TYPE : this.kind = RAW_ITERABLE; 425 this.collectionElementType = scope.getJavaLangObject(); 426 if (!collectionElementType.isCompatibleWith(elementType) 427 && !scope.isBoxingCompatibleWith(collectionElementType, elementType)) { 428 scope.problemReporter().notCompatibleTypesErrorInForeach(collection, collectionElementType, elementType); 429 } 430 break checkIterable; 432 433 case Binding.GENERIC_TYPE : arguments = iterableType.typeVariables(); 435 break; 436 437 case Binding.PARAMETERIZED_TYPE : arguments = ((ParameterizedTypeBinding)iterableType).arguments; 439 break; 440 441 default: 442 break checkIterable; 443 } 444 if (arguments.length != 1) break checkIterable; this.kind = GENERIC_ITERABLE; 447 448 this.collectionElementType = arguments[0]; 449 if (!collectionElementType.isCompatibleWith(elementType) 450 && !scope.isBoxingCompatibleWith(collectionElementType, elementType)) { 451 scope.problemReporter().notCompatibleTypesErrorInForeach(collection, collectionElementType, elementType); 452 } 453 int compileTimeTypeID = collectionElementType.id; 454 if (elementType.isBaseType()) { 456 if (!collectionElementType.isBaseType()) { 457 compileTimeTypeID = scope.environment().computeBoxingType(collectionElementType).id; 458 this.elementVariableImplicitWidening = UNBOXING; 459 if (elementType.isBaseType()) { 460 this.elementVariableImplicitWidening |= (elementType.id << 4) + compileTimeTypeID; 461 } 462 } else { 463 this.elementVariableImplicitWidening = (elementType.id << 4) + compileTimeTypeID; 464 } 465 } else { 466 if (collectionElementType.isBaseType()) { 467 int boxedID = scope.environment().computeBoxingType(collectionElementType).id; 468 this.elementVariableImplicitWidening = BOXING | (compileTimeTypeID << 4) | compileTimeTypeID; compileTimeTypeID = boxedID; 470 } 471 } 472 } 473 } 474 switch(this.kind) { 475 case ARRAY : 476 this.indexVariable = new LocalVariableBinding(SecretIndexVariableName, TypeBinding.INT, ClassFileConstants.AccDefault, false); 478 scope.addLocalVariable(this.indexVariable); 479 this.indexVariable.setConstant(Constant.NotAConstant); 481 this.maxVariable = new LocalVariableBinding(SecretMaxVariableName, TypeBinding.INT, ClassFileConstants.AccDefault, false); 483 scope.addLocalVariable(this.maxVariable); 484 this.maxVariable.setConstant(Constant.NotAConstant); this.collectionVariable = new LocalVariableBinding(SecretCollectionVariableName, collectionType, ClassFileConstants.AccDefault, false); 487 scope.addLocalVariable(this.collectionVariable); 488 this.collectionVariable.setConstant(Constant.NotAConstant); break; 490 case RAW_ITERABLE : 491 case GENERIC_ITERABLE : 492 this.indexVariable = new LocalVariableBinding(SecretIndexVariableName, scope.getJavaUtilIterator(), ClassFileConstants.AccDefault, false); 494 scope.addLocalVariable(this.indexVariable); 495 this.indexVariable.setConstant(Constant.NotAConstant); break; 497 default : 498 scope.problemReporter().invalidTypeForCollection(collection); 499 } 500 } 501 if (action != null) { 502 action.resolve(scope); 503 } 504 } 505 506 public void traverse( 507 ASTVisitor visitor, 508 BlockScope blockScope) { 509 510 if (visitor.visit(this, blockScope)) { 511 this.elementVariable.traverse(visitor, scope); 512 this.collection.traverse(visitor, scope); 513 if (action != null) { 514 action.traverse(visitor, scope); 515 } 516 } 517 visitor.endVisit(this, blockScope); 518 } 519 } 520 | Popular Tags |