Search in sources :

Example 1 with BranchLabel

use of org.eclipse.jdt.internal.compiler.codegen.BranchLabel in project bazel-jdt-java-toolchain by salesforce.

the class Clinit method generateCode.

/**
 * Bytecode generation for a <clinit> method
 *
 * @param classScope org.eclipse.jdt.internal.compiler.lookup.ClassScope
 * @param classFile org.eclipse.jdt.internal.compiler.codegen.ClassFile
 */
private void generateCode(ClassScope classScope, ClassFile classFile, int clinitOffset) {
    ConstantPool constantPool = classFile.constantPool;
    int constantPoolOffset = constantPool.currentOffset;
    int constantPoolIndex = constantPool.currentIndex;
    classFile.generateMethodInfoHeaderForClinit();
    int codeAttributeOffset = classFile.contentsOffset;
    classFile.generateCodeAttributeHeader();
    CodeStream codeStream = classFile.codeStream;
    resolve(classScope);
    codeStream.reset(this, classFile);
    TypeDeclaration declaringType = classScope.referenceContext;
    // initialize local positions - including initializer scope.
    MethodScope staticInitializerScope = declaringType.staticInitializerScope;
    staticInitializerScope.computeLocalVariablePositions(0, codeStream);
    // This has to be done before any other initialization
    if (this.assertionSyntheticFieldBinding != null) {
        // generate code related to the activation of assertion for this class
        codeStream.generateClassLiteralAccessForType(classScope, classScope.outerMostClassScope().enclosingSourceType(), this.classLiteralSyntheticField);
        codeStream.invokeJavaLangClassDesiredAssertionStatus();
        BranchLabel falseLabel = new BranchLabel(codeStream);
        codeStream.ifne(falseLabel);
        codeStream.iconst_1();
        BranchLabel jumpLabel = new BranchLabel(codeStream);
        codeStream.decrStackSize(1);
        codeStream.goto_(jumpLabel);
        falseLabel.place();
        codeStream.iconst_0();
        jumpLabel.place();
        codeStream.fieldAccess(Opcodes.OPC_putstatic, this.assertionSyntheticFieldBinding, null);
    }
    boolean isJava9 = classScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK9;
    // generate static fields/initializers/enum constants
    final FieldDeclaration[] fieldDeclarations = declaringType.fields;
    int sourcePosition = -1;
    int remainingFieldCount = 0;
    if (TypeDeclaration.kind(declaringType.modifiers) == TypeDeclaration.ENUM_DECL) {
        int enumCount = declaringType.enumConstantsCounter;
        if (!isJava9 && enumCount > ENUM_CONSTANTS_THRESHOLD) {
            // generate synthetic methods to initialize all the enum constants
            int begin = -1;
            int count = 0;
            if (fieldDeclarations != null) {
                int max = fieldDeclarations.length;
                for (int i = 0; i < max; i++) {
                    FieldDeclaration fieldDecl = fieldDeclarations[i];
                    if (fieldDecl.isStatic()) {
                        if (fieldDecl.getKind() == AbstractVariableDeclaration.ENUM_CONSTANT) {
                            if (begin == -1) {
                                begin = i;
                            }
                            count++;
                            if (count > ENUM_CONSTANTS_THRESHOLD) {
                                SyntheticMethodBinding syntheticMethod = declaringType.binding.addSyntheticMethodForEnumInitialization(begin, i);
                                codeStream.invoke(Opcodes.OPC_invokestatic, syntheticMethod, null);
                                begin = i;
                                count = 1;
                            }
                        } else {
                            remainingFieldCount++;
                        }
                    }
                }
                if (count != 0) {
                    // add last synthetic method
                    SyntheticMethodBinding syntheticMethod = declaringType.binding.addSyntheticMethodForEnumInitialization(begin, max);
                    codeStream.invoke(Opcodes.OPC_invokestatic, syntheticMethod, null);
                }
            }
        } else if (fieldDeclarations != null) {
            for (int i = 0, max = fieldDeclarations.length; i < max; i++) {
                FieldDeclaration fieldDecl = fieldDeclarations[i];
                if (fieldDecl.isStatic()) {
                    if (fieldDecl.getKind() == AbstractVariableDeclaration.ENUM_CONSTANT) {
                        fieldDecl.generateCode(staticInitializerScope, codeStream);
                    } else {
                        remainingFieldCount++;
                    }
                }
            }
        }
        // enum need to initialize $VALUES synthetic cache of enum constants
        // $VALUES := new <EnumType>[<enumCount>]
        codeStream.generateInlinedValue(enumCount);
        codeStream.anewarray(declaringType.binding);
        if (enumCount > 0) {
            if (fieldDeclarations != null) {
                for (int i = 0, max = fieldDeclarations.length; i < max; i++) {
                    FieldDeclaration fieldDecl = fieldDeclarations[i];
                    // $VALUES[i] = <enum-constant-i>
                    if (fieldDecl.getKind() == AbstractVariableDeclaration.ENUM_CONSTANT) {
                        codeStream.dup();
                        codeStream.generateInlinedValue(fieldDecl.binding.id);
                        codeStream.fieldAccess(Opcodes.OPC_getstatic, fieldDecl.binding, null);
                        codeStream.aastore();
                    }
                }
            }
        }
        codeStream.fieldAccess(Opcodes.OPC_putstatic, declaringType.enumValuesSyntheticfield, null);
        if (remainingFieldCount != 0) {
            // if fields that are not enum constants need to be generated (static initializer/static field)
            for (int i = 0, max = fieldDeclarations.length; i < max && remainingFieldCount >= 0; i++) {
                FieldDeclaration fieldDecl = fieldDeclarations[i];
                switch(fieldDecl.getKind()) {
                    case AbstractVariableDeclaration.ENUM_CONSTANT:
                        break;
                    case AbstractVariableDeclaration.INITIALIZER:
                        if (!fieldDecl.isStatic()) {
                            break;
                        }
                        remainingFieldCount--;
                        sourcePosition = ((Initializer) fieldDecl).block.sourceEnd;
                        fieldDecl.generateCode(staticInitializerScope, codeStream);
                        break;
                    case AbstractVariableDeclaration.FIELD:
                        if (!fieldDecl.binding.isStatic()) {
                            break;
                        }
                        remainingFieldCount--;
                        sourcePosition = fieldDecl.declarationEnd;
                        fieldDecl.generateCode(staticInitializerScope, codeStream);
                        break;
                }
            }
        }
    } else {
        if (fieldDeclarations != null) {
            for (int i = 0, max = fieldDeclarations.length; i < max; i++) {
                FieldDeclaration fieldDecl = fieldDeclarations[i];
                switch(fieldDecl.getKind()) {
                    case AbstractVariableDeclaration.INITIALIZER:
                        if (!fieldDecl.isStatic())
                            break;
                        sourcePosition = ((Initializer) fieldDecl).block.sourceEnd;
                        fieldDecl.generateCode(staticInitializerScope, codeStream);
                        break;
                    case AbstractVariableDeclaration.FIELD:
                        if (!fieldDecl.binding.isStatic())
                            break;
                        sourcePosition = fieldDecl.declarationEnd;
                        fieldDecl.generateCode(staticInitializerScope, codeStream);
                        break;
                }
            }
        }
        if (isJava9) {
            declaringType.binding.generateSyntheticFinalFieldInitialization(codeStream);
        }
    }
    if (codeStream.position == 0) {
        // do not need to output a Clinit if no bytecodes
        // so we reset the offset inside the byte array contents.
        classFile.contentsOffset = clinitOffset;
        // like we don't addd a method we need to undo the increment on the method count
        classFile.methodCount--;
        // reset the constant pool to its state before the clinit
        constantPool.resetForClinit(constantPoolIndex, constantPoolOffset);
    } else {
        if ((this.bits & ASTNode.NeedFreeReturn) != 0) {
            int before = codeStream.position;
            codeStream.return_();
            if (sourcePosition != -1) {
                // expand the last initializer variables to include the trailing return
                codeStream.recordPositionsFrom(before, sourcePosition);
            }
        }
        // Record the end of the clinit: point to the declaration of the class
        codeStream.recordPositionsFrom(0, declaringType.sourceStart);
        classFile.completeCodeAttributeForClinit(codeAttributeOffset, classScope);
    }
}
Also used : CodeStream(org.eclipse.jdt.internal.compiler.codegen.CodeStream) BranchLabel(org.eclipse.jdt.internal.compiler.codegen.BranchLabel) ConstantPool(org.eclipse.jdt.internal.compiler.codegen.ConstantPool) SyntheticMethodBinding(org.eclipse.jdt.internal.compiler.lookup.SyntheticMethodBinding) MethodScope(org.eclipse.jdt.internal.compiler.lookup.MethodScope)

Example 2 with BranchLabel

use of org.eclipse.jdt.internal.compiler.codegen.BranchLabel in project bazel-jdt-java-toolchain by salesforce.

the class GuardedPattern method generateCode.

@Override
public void generateCode(BlockScope currentScope, CodeStream codeStream) {
    this.primaryPattern.generateCode(currentScope, codeStream);
    Constant cst = this.condition.optimizedBooleanConstant();
    this.thenTarget = new BranchLabel(codeStream);
    this.condition.generateOptimizedBoolean(currentScope, codeStream, this.thenTarget, null, cst == Constant.NotAConstant);
}
Also used : BranchLabel(org.eclipse.jdt.internal.compiler.codegen.BranchLabel) Constant(org.eclipse.jdt.internal.compiler.impl.Constant)

Example 3 with BranchLabel

use of org.eclipse.jdt.internal.compiler.codegen.BranchLabel in project bazel-jdt-java-toolchain by salesforce.

the class ForStatement method generateCode.

/**
 * For statement code generation
 *
 * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
 * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
 */
@Override
public void generateCode(BlockScope currentScope, CodeStream codeStream) {
    if ((this.bits & IsReachable) == 0) {
        return;
    }
    int pc = codeStream.position;
    // generate the initializations
    if (this.initializations != null) {
        for (int i = 0, max = this.initializations.length; i < max; i++) {
            this.initializations[i].generateCode(this.scope, codeStream);
        }
    }
    if (containsPatternVariable()) {
        this.condition.addPatternVariables(currentScope, codeStream);
    }
    Constant cst = this.condition == null ? null : this.condition.optimizedBooleanConstant();
    boolean isConditionOptimizedFalse = cst != null && (cst != Constant.NotAConstant && cst.booleanValue() == false);
    if (isConditionOptimizedFalse) {
        this.condition.generateCode(this.scope, codeStream, false);
        // May loose some local variable initializations : affecting the local variable attributes
        if ((this.bits & ASTNode.NeededScope) != 0) {
            codeStream.exitUserScope(this.scope);
        }
        if (this.mergedInitStateIndex != -1) {
            codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.mergedInitStateIndex);
            codeStream.addDefinitelyAssignedVariables(currentScope, this.mergedInitStateIndex);
        }
        codeStream.recordPositionsFrom(pc, this.sourceStart);
        return;
    }
    // label management
    BranchLabel actionLabel = new BranchLabel(codeStream);
    actionLabel.tagBits |= BranchLabel.USED;
    BranchLabel conditionLabel = new BranchLabel(codeStream);
    this.breakLabel.initialize(codeStream);
    if (this.continueLabel == null) {
        conditionLabel.place();
        if ((this.condition != null) && (this.condition.constant == Constant.NotAConstant)) {
            this.condition.generateOptimizedBoolean(this.scope, codeStream, null, this.breakLabel, true);
        }
    } else {
        this.continueLabel.initialize(codeStream);
        // jump over the actionBlock
        if ((this.condition != null) && (this.condition.constant == Constant.NotAConstant) && !((this.action == null || this.action.isEmptyBlock()) && (this.increments == null))) {
            conditionLabel.tagBits |= BranchLabel.USED;
            int jumpPC = codeStream.position;
            codeStream.goto_(conditionLabel);
            codeStream.recordPositionsFrom(jumpPC, this.condition.sourceStart);
        }
    }
    // generate the loop action
    if (this.action != null) {
        // Required to fix 1PR0XVS: LFRE:WINNT - Compiler: variable table for method appears incorrect
        if (this.condIfTrueInitStateIndex != -1) {
            // insert all locals initialized inside the condition into the action generated prior to the condition
            codeStream.addDefinitelyAssignedVariables(currentScope, this.condIfTrueInitStateIndex);
        }
        actionLabel.place();
        this.action.generateCode(this.scope, codeStream);
    } else {
        actionLabel.place();
    }
    if (this.preIncrementsInitStateIndex != -1) {
        codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.preIncrementsInitStateIndex);
        codeStream.addDefinitelyAssignedVariables(currentScope, this.preIncrementsInitStateIndex);
    }
    // continuation point
    if (this.continueLabel != null) {
        this.continueLabel.place();
        // generate the increments for next iteration
        if (this.increments != null) {
            for (int i = 0, max = this.increments.length; i < max; i++) {
                this.increments[i].generateCode(this.scope, codeStream);
            }
        }
        // This is causing PatternMatching14Test.test039() to fail
        if (this.preCondInitStateIndex != -1) {
            codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.preCondInitStateIndex);
        }
        // generate the condition
        conditionLabel.place();
        if ((this.condition != null) && (this.condition.constant == Constant.NotAConstant)) {
            this.condition.generateOptimizedBoolean(this.scope, codeStream, actionLabel, null, true);
        } else {
            codeStream.goto_(actionLabel);
        }
    } else {
        // May loose some local variable initializations : affecting the local variable attributes
        if (this.preCondInitStateIndex != -1) {
            codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.preCondInitStateIndex);
        }
    }
    // May loose some local variable initializations : affecting the local variable attributes
    if ((this.bits & ASTNode.NeededScope) != 0) {
        codeStream.exitUserScope(this.scope);
    }
    if (this.mergedInitStateIndex != -1) {
        codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.mergedInitStateIndex);
        codeStream.addDefinitelyAssignedVariables(currentScope, this.mergedInitStateIndex);
    }
    this.breakLabel.place();
    codeStream.recordPositionsFrom(pc, this.sourceStart);
}
Also used : BranchLabel(org.eclipse.jdt.internal.compiler.codegen.BranchLabel) Constant(org.eclipse.jdt.internal.compiler.impl.Constant)

Example 4 with BranchLabel

use of org.eclipse.jdt.internal.compiler.codegen.BranchLabel in project bazel-jdt-java-toolchain by salesforce.

the class ForStatement method analyseCode.

@Override
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
    this.breakLabel = new BranchLabel();
    this.continueLabel = new BranchLabel();
    int initialComplaintLevel = (flowInfo.reachMode() & FlowInfo.UNREACHABLE) != 0 ? Statement.COMPLAINED_FAKE_REACHABLE : Statement.NOT_COMPLAINED;
    // process the initializations
    if (this.initializations != null) {
        for (int i = 0, count = this.initializations.length; i < count; i++) {
            flowInfo = this.initializations[i].analyseCode(this.scope, flowContext, flowInfo);
        }
    }
    this.preCondInitStateIndex = currentScope.methodScope().recordInitializationStates(flowInfo);
    Constant cst = this.condition == null ? null : this.condition.constant;
    boolean isConditionTrue = cst == null || (cst != Constant.NotAConstant && cst.booleanValue() == true);
    boolean isConditionFalse = cst != null && (cst != Constant.NotAConstant && cst.booleanValue() == false);
    cst = this.condition == null ? null : this.condition.optimizedBooleanConstant();
    boolean isConditionOptimizedTrue = cst == null || (cst != Constant.NotAConstant && cst.booleanValue() == true);
    boolean isConditionOptimizedFalse = cst != null && (cst != Constant.NotAConstant && cst.booleanValue() == false);
    // process the condition
    LoopingFlowContext condLoopContext = null;
    FlowInfo condInfo = flowInfo.nullInfoLessUnconditionalCopy();
    if (this.condition != null) {
        if (!isConditionTrue) {
            condInfo = this.condition.analyseCode(this.scope, (condLoopContext = new LoopingFlowContext(flowContext, flowInfo, this, null, null, this.scope, true)), condInfo);
            this.condition.checkNPEbyUnboxing(currentScope, flowContext, flowInfo);
        }
    }
    // process the action
    LoopingFlowContext loopingContext;
    UnconditionalFlowInfo actionInfo;
    if (this.action == null || (this.action.isEmptyBlock() && currentScope.compilerOptions().complianceLevel <= ClassFileConstants.JDK1_3)) {
        if (condLoopContext != null)
            condLoopContext.complainOnDeferredFinalChecks(this.scope, condInfo);
        if (isConditionTrue) {
            if (condLoopContext != null) {
                condLoopContext.complainOnDeferredNullChecks(currentScope, condInfo);
            }
            return FlowInfo.DEAD_END;
        } else {
            if (isConditionFalse) {
                // for(;false;p());
                this.continueLabel = null;
            }
            actionInfo = condInfo.initsWhenTrue().unconditionalCopy();
            loopingContext = new LoopingFlowContext(flowContext, flowInfo, this, this.breakLabel, this.continueLabel, this.scope, false);
        // there is no action guarded by a preTest, so we use preTest=false
        // to avoid pointless burdens of updating FlowContext.conditionalLevel
        }
    } else {
        loopingContext = new LoopingFlowContext(flowContext, flowInfo, this, this.breakLabel, this.continueLabel, this.scope, true);
        FlowInfo initsWhenTrue = condInfo.initsWhenTrue();
        this.condIfTrueInitStateIndex = currentScope.methodScope().recordInitializationStates(initsWhenTrue);
        if (isConditionFalse) {
            actionInfo = FlowInfo.DEAD_END;
        } else {
            actionInfo = initsWhenTrue.unconditionalCopy();
            if (isConditionOptimizedFalse) {
                actionInfo.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD);
            }
        }
        if (this.action.complainIfUnreachable(actionInfo, this.scope, initialComplaintLevel, true) < Statement.COMPLAINED_UNREACHABLE) {
            if (this.condition != null)
                this.condition.updateFlowOnBooleanResult(actionInfo, true);
            actionInfo = this.action.analyseCode(this.scope, loopingContext, actionInfo).unconditionalInits();
        }
        // code generation can be optimized when no need to continue in the loop
        if ((actionInfo.tagBits & loopingContext.initsOnContinue.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) != 0) {
            this.continueLabel = null;
        } else {
            if (condLoopContext != null) {
                condLoopContext.complainOnDeferredFinalChecks(this.scope, condInfo);
            }
            actionInfo = actionInfo.mergedWith(loopingContext.initsOnContinue);
            loopingContext.complainOnDeferredFinalChecks(this.scope, actionInfo);
        }
    }
    // for increments
    FlowInfo exitBranch = flowInfo.copy();
    // recover null inits from before condition analysis
    LoopingFlowContext incrementContext = null;
    if (this.continueLabel != null) {
        if (this.increments != null) {
            incrementContext = new LoopingFlowContext(flowContext, flowInfo, this, null, null, this.scope, true);
            FlowInfo incrementInfo = actionInfo;
            this.preIncrementsInitStateIndex = currentScope.methodScope().recordInitializationStates(incrementInfo);
            for (int i = 0, count = this.increments.length; i < count; i++) {
                incrementInfo = this.increments[i].analyseCode(this.scope, incrementContext, incrementInfo);
            }
            incrementContext.complainOnDeferredFinalChecks(this.scope, actionInfo = incrementInfo.unconditionalInits());
        }
        exitBranch.addPotentialInitializationsFrom(actionInfo).addInitializationsFrom(condInfo.initsWhenFalse());
    } else {
        exitBranch.addInitializationsFrom(condInfo.initsWhenFalse());
        if (this.increments != null) {
            if (initialComplaintLevel == Statement.NOT_COMPLAINED) {
                currentScope.problemReporter().fakeReachable(this.increments[0]);
            }
        }
    }
    // nulls checks
    if (condLoopContext != null) {
        condLoopContext.complainOnDeferredNullChecks(currentScope, actionInfo);
    }
    loopingContext.complainOnDeferredNullChecks(currentScope, actionInfo);
    if (incrementContext != null) {
        incrementContext.complainOnDeferredNullChecks(currentScope, actionInfo);
    }
    if (loopingContext.hasEscapingExceptions()) {
        // https://bugs.eclipse.org/bugs/show_bug.cgi?id=321926
        FlowInfo loopbackFlowInfo = flowInfo.copy();
        if (this.continueLabel != null) {
            // we do get to the bottom
            // loopback | (loopback + action):
            loopbackFlowInfo = loopbackFlowInfo.mergedWith(loopbackFlowInfo.unconditionalCopy().addNullInfoFrom(actionInfo).unconditionalInits());
        }
        loopingContext.simulateThrowAfterLoopBack(loopbackFlowInfo);
    }
    // end of loop
    FlowInfo mergedInfo = FlowInfo.mergedOptimizedBranches((loopingContext.initsOnBreak.tagBits & FlowInfo.UNREACHABLE) != 0 ? loopingContext.initsOnBreak : // recover upstream null info
    flowInfo.addInitializationsFrom(loopingContext.initsOnBreak), isConditionOptimizedTrue, exitBranch, isConditionOptimizedFalse, !isConditionTrue);
    // https://bugs.eclipse.org/bugs/show_bug.cgi?id=359495
    if (this.initializations != null) {
        for (int i = 0; i < this.initializations.length; i++) {
            Statement init = this.initializations[i];
            if (init instanceof LocalDeclaration) {
                LocalVariableBinding binding = ((LocalDeclaration) init).binding;
                mergedInfo.resetAssignmentInfo(binding);
            }
        }
    }
    this.mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo);
    this.scope.checkUnclosedCloseables(mergedInfo, loopingContext, null, null);
    if (this.condition != null)
        this.condition.updateFlowOnBooleanResult(mergedInfo, false);
    return mergedInfo;
}
Also used : UnconditionalFlowInfo(org.eclipse.jdt.internal.compiler.flow.UnconditionalFlowInfo) FlowInfo(org.eclipse.jdt.internal.compiler.flow.FlowInfo) BranchLabel(org.eclipse.jdt.internal.compiler.codegen.BranchLabel) Constant(org.eclipse.jdt.internal.compiler.impl.Constant) LoopingFlowContext(org.eclipse.jdt.internal.compiler.flow.LoopingFlowContext) UnconditionalFlowInfo(org.eclipse.jdt.internal.compiler.flow.UnconditionalFlowInfo) LocalVariableBinding(org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding)

Example 5 with BranchLabel

use of org.eclipse.jdt.internal.compiler.codegen.BranchLabel in project bazel-jdt-java-toolchain by salesforce.

the class ForeachStatement method analyseCode.

@Override
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
    // initialize break and continue labels
    this.breakLabel = new BranchLabel();
    this.continueLabel = new BranchLabel();
    int initialComplaintLevel = (flowInfo.reachMode() & FlowInfo.UNREACHABLE) != 0 ? Statement.COMPLAINED_FAKE_REACHABLE : Statement.NOT_COMPLAINED;
    // process the element variable and collection
    flowInfo = this.elementVariable.analyseCode(this.scope, flowContext, flowInfo);
    FlowInfo condInfo = this.collection.analyseCode(this.scope, flowContext, flowInfo.copy());
    this.collection.checkNPE(currentScope, flowContext, condInfo.copy(), 1);
    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, true);
    UnconditionalFlowInfo actionInfo = condInfo.nullInfoLessUnconditionalCopy();
    actionInfo.markAsDefinitelyUnknown(elementVarBinding);
    if (currentScope.compilerOptions().isAnnotationBasedNullAnalysisEnabled) {
        int elementNullStatus = NullAnnotationMatching.nullStatusFromExpressionType(this.collectionElementType);
        int nullStatus = // have no useful flowinfo for element var
        NullAnnotationMatching.checkAssignment(// have no useful flowinfo for element var
        currentScope, // have no useful flowinfo for element var
        flowContext, // have no useful flowinfo for element var
        elementVarBinding, // have no useful flowinfo for element var
        null, elementNullStatus, this.collection, this.collectionElementType);
        if ((this.kind == GENERIC_ITERABLE || this.kind == RAW_ITERABLE) && !currentScope.compilerOptions().usesNullTypeAnnotations()) {
            // respect declaration annotation on Iterator.next():
            ReferenceBinding iterator = currentScope.getJavaUtilIterator();
            if (iterator != null) {
                MethodBinding next = iterator.getExactMethod(TypeConstants.NEXT, Binding.NO_TYPES, currentScope.compilationUnitScope);
                if (next != null && ((next.tagBits & TagBits.AnnotationNullMASK) != 0)) {
                    nullStatus = FlowInfo.tagBitsToNullStatus(next.tagBits);
                }
            }
        }
        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();
            FakedTrackingVariable.markForeachElementVar(this.elementVariable);
            // action.analyseCode() missed the following check due to identical scopes of ForeachStatement and action:
            // previously action did not see nullinfo from condInfo
            FlowInfo actionNullInfo = condInfo.copy().addNullInfoFrom(actionInfo);
            this.scope.checkUnclosedCloseables(actionNullInfo, loopingContext, null, null);
        }
        // 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();
        if (this.action instanceof Block && !this.action.isEmptyBlock()) {
            this.scope.checkUnclosedCloseables(actionInfo, loopingContext, null, null);
        }
    }
    // 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);
    if (loopingContext.hasEscapingExceptions()) {
        // https://bugs.eclipse.org/bugs/show_bug.cgi?id=321926
        FlowInfo loopbackFlowInfo = flowInfo.copy();
        if (this.continueLabel != null) {
            // we do get to the bottom
            // loopback | (loopback + action):
            loopbackFlowInfo = loopbackFlowInfo.mergedWith(loopbackFlowInfo.unconditionalCopy().addNullInfoFrom(actionInfo).unconditionalInits());
        }
        loopingContext.simulateThrowAfterLoopBack(loopbackFlowInfo);
    }
    FlowInfo mergedInfo = FlowInfo.mergedOptimizedBranches((loopingContext.initsOnBreak.tagBits & FlowInfo.UNREACHABLE) != 0 ? loopingContext.initsOnBreak : // recover upstream null info
    flowInfo.addInitializationsFrom(loopingContext.initsOnBreak), false, exitBranch, false, true);
    mergedInfo.resetAssignmentInfo(this.elementVariable.binding);
    this.mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo);
    return mergedInfo;
}
Also used : FlowInfo(org.eclipse.jdt.internal.compiler.flow.FlowInfo) UnconditionalFlowInfo(org.eclipse.jdt.internal.compiler.flow.UnconditionalFlowInfo) BranchLabel(org.eclipse.jdt.internal.compiler.codegen.BranchLabel) MethodBinding(org.eclipse.jdt.internal.compiler.lookup.MethodBinding) ReferenceBinding(org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding) ProblemReferenceBinding(org.eclipse.jdt.internal.compiler.lookup.ProblemReferenceBinding) LoopingFlowContext(org.eclipse.jdt.internal.compiler.flow.LoopingFlowContext) UnconditionalFlowInfo(org.eclipse.jdt.internal.compiler.flow.UnconditionalFlowInfo) LocalVariableBinding(org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding)

Aggregations

BranchLabel (org.eclipse.jdt.internal.compiler.codegen.BranchLabel)9 FlowInfo (org.eclipse.jdt.internal.compiler.flow.FlowInfo)3 Constant (org.eclipse.jdt.internal.compiler.impl.Constant)3 LoopingFlowContext (org.eclipse.jdt.internal.compiler.flow.LoopingFlowContext)2 UnconditionalFlowInfo (org.eclipse.jdt.internal.compiler.flow.UnconditionalFlowInfo)2 LocalVariableBinding (org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding)2 ReferenceBinding (org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding)2 SourceTypeBinding (org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding)2 TypeBinding (org.eclipse.jdt.internal.compiler.lookup.TypeBinding)2 CaseLabel (org.eclipse.jdt.internal.compiler.codegen.CaseLabel)1 CodeStream (org.eclipse.jdt.internal.compiler.codegen.CodeStream)1 ConstantPool (org.eclipse.jdt.internal.compiler.codegen.ConstantPool)1 SwitchFlowContext (org.eclipse.jdt.internal.compiler.flow.SwitchFlowContext)1 MethodBinding (org.eclipse.jdt.internal.compiler.lookup.MethodBinding)1 MethodScope (org.eclipse.jdt.internal.compiler.lookup.MethodScope)1 ProblemReferenceBinding (org.eclipse.jdt.internal.compiler.lookup.ProblemReferenceBinding)1 SyntheticMethodBinding (org.eclipse.jdt.internal.compiler.lookup.SyntheticMethodBinding)1