int initialComplaintLevel = (flowInfo.reachMode() & FlowInfo.UNREACHABLE) != 0 ? Statement.COMPLAINED_FAKE_REACHABLE : Statement.NOT_COMPLAINED;
// process the element variable and collection
this.collection.checkNPE(currentScope, flowContext, flowInfo);
flowInfo = this.elementVariable.analyseCode(this.scope, flowContext, flowInfo);
FlowInfo condInfo = this.collection.analyseCode(this.scope, flowContext, flowInfo.copy());
LocalVariableBinding elementVarBinding = this.elementVariable.binding;
// element variable will be assigned when iterating
condInfo.markAsDefinitelyAssigned(elementVarBinding);
this.postCollectionInitStateIndex = currentScope.methodScope().recordInitializationStates(condInfo);
// process the action
LoopingFlowContext loopingContext =
new LoopingFlowContext(flowContext, flowInfo, this, this.breakLabel,
this.continueLabel, this.scope);
UnconditionalFlowInfo actionInfo =
condInfo.nullInfoLessUnconditionalCopy();
actionInfo.markAsDefinitelyUnknown(elementVarBinding);
if (currentScope.compilerOptions().isAnnotationBasedNullAnalysisEnabled) {
// this currently produces an unavoidable warning against all @NonNull element vars:
int nullStatus = this.elementVariable.checkAssignmentAgainstNullAnnotation(currentScope, flowContext,
elementVarBinding, FlowInfo.UNKNOWN, this.collection, this.collectionElementType);
// TODO (stephan): once we have JSR 308 fetch nullStatus from the collection element type
// and feed the result into the above check (instead of FlowInfo.UNKNOWN)
if ((elementVarBinding.type.tagBits & TagBits.IsBaseType) == 0) {
actionInfo.markNullStatus(elementVarBinding, nullStatus);
}
}
FlowInfo exitBranch;
if (!(this.action == null || (this.action.isEmptyBlock()
&& currentScope.compilerOptions().complianceLevel <= ClassFileConstants.JDK1_3))) {
if (this.action.complainIfUnreachable(actionInfo, this.scope, initialComplaintLevel, true) < Statement.COMPLAINED_UNREACHABLE) {
actionInfo = this.action.analyseCode(this.scope, loopingContext, actionInfo).unconditionalCopy();
}
// code generation can be optimized when no need to continue in the loop
exitBranch = flowInfo.unconditionalCopy().
addInitializationsFrom(condInfo.initsWhenFalse());
// TODO (maxime) no need to test when false: can optimize (same for action being unreachable above)
if ((actionInfo.tagBits & loopingContext.initsOnContinue.tagBits &
FlowInfo.UNREACHABLE_OR_DEAD) != 0) {
this.continueLabel = null;
} else {
actionInfo = actionInfo.mergedWith(loopingContext.initsOnContinue);
loopingContext.complainOnDeferredFinalChecks(this.scope, actionInfo);
exitBranch.addPotentialInitializationsFrom(actionInfo);
}
} else {
exitBranch = condInfo.initsWhenFalse();
}
// we need the variable to iterate the collection even if the
// element variable is not used
final boolean hasEmptyAction = this.action == null
|| this.action.isEmptyBlock()
|| ((this.action.bits & IsUsefulEmptyStatement) != 0);
switch(this.kind) {
case ARRAY :
if (!hasEmptyAction
|| elementVarBinding.resolvedPosition != -1) {
this.collectionVariable.useFlag = LocalVariableBinding.USED;
if (this.continueLabel != null) {
this.indexVariable.useFlag = LocalVariableBinding.USED;
this.maxVariable.useFlag = LocalVariableBinding.USED;
}
}
break;
case RAW_ITERABLE :
case GENERIC_ITERABLE :
this.indexVariable.useFlag = LocalVariableBinding.USED;
break;
}
//end of loop
loopingContext.complainOnDeferredNullChecks(currentScope, actionInfo);
FlowInfo mergedInfo = FlowInfo.mergedOptimizedBranches(
(loopingContext.initsOnBreak.tagBits &
FlowInfo.UNREACHABLE) != 0 ?
loopingContext.initsOnBreak :
flowInfo.addInitializationsFrom(loopingContext.initsOnBreak), // recover upstream null info
false,
exitBranch,
false,
true /*for(;;){}while(true); unreachable(); */);
mergedInfo.resetAssignmentInfo(this.elementVariable.binding);
this.mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo);
return mergedInfo;
}