Search in sources :

Example 1 with SwitchFlowContext

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

the class SwitchStatement method analyseCode.

@Override
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
    try {
        flowInfo = this.expression.analyseCode(currentScope, flowContext, flowInfo);
        if (isNullHostile()) {
            this.expression.checkNPE(currentScope, flowContext, flowInfo, 1);
        }
        SwitchFlowContext switchContext = new SwitchFlowContext(flowContext, this, (this.breakLabel = new BranchLabel()), true, true);
        switchContext.isExpression = this instanceof SwitchExpression;
        // analyse the block by considering specially the case/default statements (need to bind them
        // to the entry point)
        FlowInfo caseInits = FlowInfo.DEAD_END;
        // in case of statements before the first case
        this.preSwitchInitStateIndex = currentScope.methodScope().recordInitializationStates(flowInfo);
        int caseIndex = 0;
        if (this.statements != null) {
            int initialComplaintLevel = (flowInfo.reachMode() & FlowInfo.UNREACHABLE) != 0 ? Statement.COMPLAINED_FAKE_REACHABLE : Statement.NOT_COMPLAINED;
            int complaintLevel = initialComplaintLevel;
            int fallThroughState = CASE;
            for (int i = 0, max = this.statements.length; i < max; i++) {
                Statement statement = this.statements[i];
                if ((caseIndex < this.caseCount) && (statement == this.cases[caseIndex])) {
                    // statement is a case
                    // record entering in a switch case block
                    this.scope.enclosingCase = this.cases[caseIndex];
                    caseIndex++;
                    if (fallThroughState == FALLTHROUGH) {
                        if (((CaseStatement) statement).containsPatternVariable())
                            this.scope.problemReporter().IllegalFallThroughToPattern(this.scope.enclosingCase);
                        else if ((statement.bits & ASTNode.DocumentedFallthrough) == 0) {
                            // the case is not fall-through protected by a line comment
                            this.scope.problemReporter().possibleFallThroughCase(this.scope.enclosingCase);
                        }
                    }
                    caseInits = caseInits.mergedWith(flowInfo.unconditionalInits());
                    // reset complaint
                    complaintLevel = initialComplaintLevel;
                    fallThroughState = this.containsPatterns ? FALLTHROUGH : CASE;
                } else if (statement == this.defaultCase) {
                    // statement is the default case
                    // record entering in a switch case block
                    this.scope.enclosingCase = this.defaultCase;
                    if (fallThroughState == FALLTHROUGH && (statement.bits & ASTNode.DocumentedFallthrough) == 0) {
                        this.scope.problemReporter().possibleFallThroughCase(this.scope.enclosingCase);
                    }
                    caseInits = caseInits.mergedWith(flowInfo.unconditionalInits());
                    if ((this.switchBits & LabeledRules) != 0 && this.expression.resolvedType instanceof ReferenceBinding) {
                        if (this.expression instanceof NameReference) {
                            // default case does not apply to null => mark the variable being switched over as nonnull:
                            NameReference reference = (NameReference) this.expression;
                            if (reference.localVariableBinding() != null) {
                                caseInits.markAsDefinitelyNonNull(reference.localVariableBinding());
                            } else if (reference.lastFieldBinding() != null) {
                                if (this.scope.compilerOptions().enableSyntacticNullAnalysisForFields)
                                    // survive this case statement and into the next
                                    switchContext.recordNullCheckedFieldReference(reference, 2);
                            }
                        } else if (this.expression instanceof FieldReference) {
                            if (this.scope.compilerOptions().enableSyntacticNullAnalysisForFields)
                                // survive this case statement and into the next
                                switchContext.recordNullCheckedFieldReference((FieldReference) this.expression, 2);
                        }
                    }
                    // reset complaint
                    complaintLevel = initialComplaintLevel;
                    fallThroughState = this.containsPatterns ? FALLTHROUGH : CASE;
                } else {
                    if (!(this instanceof SwitchExpression) && currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK14 && statement instanceof YieldStatement && ((YieldStatement) statement).isImplicit) {
                        YieldStatement y = (YieldStatement) statement;
                        Expression e = ((YieldStatement) statement).expression;
                        /* JLS 13 14.11.2
									Switch labeled rules in switch statements differ from those in switch expressions (15.28).
									In switch statements they must be switch labeled statement expressions, ... */
                        if (!y.expression.statementExpression()) {
                            this.scope.problemReporter().invalidExpressionAsStatement(e);
                        }
                    }
                    // reset below if needed
                    fallThroughState = getFallThroughState(statement, currentScope);
                }
                if ((complaintLevel = statement.complainIfUnreachable(caseInits, this.scope, complaintLevel, true)) < Statement.COMPLAINED_UNREACHABLE) {
                    caseInits = statement.analyseCode(this.scope, switchContext, caseInits);
                    if (caseInits == FlowInfo.DEAD_END) {
                        fallThroughState = ESCAPING;
                    }
                    switchContext.expireNullCheckedFieldInfo();
                }
            }
            completeNormallyCheck(currentScope);
        }
        final TypeBinding resolvedTypeBinding = this.expression.resolvedType;
        if (resolvedTypeBinding.isEnum()) {
            final SourceTypeBinding sourceTypeBinding = currentScope.classScope().referenceContext.binding;
            this.synthetic = sourceTypeBinding.addSyntheticMethodForSwitchEnum(resolvedTypeBinding, this);
        }
        // if no default case, then record it may jump over the block directly to the end
        if (this.defaultCase == null && needToCheckFlowInAbsenceOfDefaultBranch()) {
            // only retain the potential initializations
            flowInfo.addPotentialInitializationsFrom(caseInits.mergedWith(switchContext.initsOnBreak));
            this.mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(flowInfo);
            return flowInfo;
        }
        // merge all branches inits
        FlowInfo mergedInfo = caseInits.mergedWith(switchContext.initsOnBreak);
        this.mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo);
        return mergedInfo;
    } finally {
        // no longer inside switch case block
        if (this.scope != null)
            this.scope.enclosingCase = null;
    }
}
Also used : BranchLabel(org.eclipse.jdt.internal.compiler.codegen.BranchLabel) SourceTypeBinding(org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding) TypeBinding(org.eclipse.jdt.internal.compiler.lookup.TypeBinding) ReferenceBinding(org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding) SwitchFlowContext(org.eclipse.jdt.internal.compiler.flow.SwitchFlowContext) FlowInfo(org.eclipse.jdt.internal.compiler.flow.FlowInfo) SourceTypeBinding(org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding)

Aggregations

BranchLabel (org.eclipse.jdt.internal.compiler.codegen.BranchLabel)1 FlowInfo (org.eclipse.jdt.internal.compiler.flow.FlowInfo)1 SwitchFlowContext (org.eclipse.jdt.internal.compiler.flow.SwitchFlowContext)1 ReferenceBinding (org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding)1 SourceTypeBinding (org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding)1 TypeBinding (org.eclipse.jdt.internal.compiler.lookup.TypeBinding)1