package org.eclipse.jdt.internal.compiler.ast;
import org.eclipse.jdt.internal.compiler.ASTVisitor;
import org.eclipse.jdt.internal.compiler.impl.*;
import org.eclipse.jdt.internal.compiler.codegen.*;
import org.eclipse.jdt.internal.compiler.flow.*;
import org.eclipse.jdt.internal.compiler.lookup.*;
public class IfStatement extends Statement {
public Expression condition;
public Statement thenStatement;
public Statement elseStatement;
int thenInitStateIndex = -1;
int elseInitStateIndex = -1;
int mergedInitStateIndex = -1;
public IfStatement(Expression condition, Statement thenStatement, int sourceStart, int sourceEnd) {
this.condition = condition;
this.thenStatement = thenStatement;
if (thenStatement instanceof EmptyStatement) thenStatement.bits |= IsUsefulEmptyStatement;
this.sourceStart = sourceStart;
this.sourceEnd = sourceEnd;
}
public IfStatement(Expression condition, Statement thenStatement, Statement elseStatement, int sourceStart, int sourceEnd) {
this.condition = condition;
this.thenStatement = thenStatement;
if (thenStatement instanceof EmptyStatement) thenStatement.bits |= IsUsefulEmptyStatement;
this.elseStatement = elseStatement;
if (elseStatement instanceof IfStatement) elseStatement.bits |= IsElseIfStatement;
if (elseStatement instanceof EmptyStatement) elseStatement.bits |= IsUsefulEmptyStatement;
this.sourceStart = sourceStart;
this.sourceEnd = sourceEnd;
}
@Override
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
FlowInfo conditionFlowInfo = this.condition.analyseCode(currentScope, flowContext, flowInfo);
int initialComplaintLevel = (flowInfo.reachMode() & FlowInfo.UNREACHABLE) != 0 ? Statement.COMPLAINED_FAKE_REACHABLE : Statement.NOT_COMPLAINED;
Constant cst = this.condition.optimizedBooleanConstant();
this.condition.checkNPEbyUnboxing(currentScope, flowContext, flowInfo);
boolean isConditionOptimizedTrue = cst != Constant.NotAConstant && cst.booleanValue() == true;
boolean isConditionOptimizedFalse = cst != Constant.NotAConstant && cst.booleanValue() == false;
flowContext.conditionalLevel++;
FlowInfo thenFlowInfo = conditionFlowInfo.safeInitsWhenTrue();
if (isConditionOptimizedFalse) {
thenFlowInfo.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD);
}
FlowInfo elseFlowInfo = conditionFlowInfo.initsWhenFalse().copy();
if (isConditionOptimizedTrue) {
elseFlowInfo.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD);
}
if (((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) &&
((thenFlowInfo.tagBits & FlowInfo.UNREACHABLE) != 0)) {
this.bits |= ASTNode.IsThenStatementUnreachable;
} else if (((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) &&
((elseFlowInfo.tagBits & FlowInfo.UNREACHABLE) != 0)) {
this.bits |= ASTNode.IsElseStatementUnreachable;
}
boolean reportDeadCodeForKnownPattern = !isKnowDeadCodePattern(this.condition) || currentScope.compilerOptions().reportDeadCodeInTrivialIfStatement;
if (this.thenStatement != null) {
this.thenInitStateIndex = currentScope.methodScope().recordInitializationStates(thenFlowInfo);
if (isConditionOptimizedFalse || ((this.bits & ASTNode.IsThenStatementUnreachable) != 0)) {
if (reportDeadCodeForKnownPattern) {
this.thenStatement.complainIfUnreachable(thenFlowInfo, currentScope, initialComplaintLevel, false);
} else {
this.bits &= ~ASTNode.IsThenStatementUnreachable;
}
}
thenFlowInfo = this.thenStatement.analyseCode(currentScope, flowContext, thenFlowInfo);
if (!(this.thenStatement instanceof Block))
flowContext.expireNullCheckedFieldInfo();
}
flowContext.expireNullCheckedFieldInfo();
if ((thenFlowInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) != 0) {
this.bits |= ASTNode.ThenExit;
}
if (this.elseStatement != null) {
if (thenFlowInfo == FlowInfo.DEAD_END
&& (this.bits & IsElseIfStatement) == 0
&& !(this.elseStatement instanceof IfStatement)) {
currentScope.problemReporter().unnecessaryElse(this.elseStatement);
}
this.elseInitStateIndex = currentScope.methodScope().recordInitializationStates(elseFlowInfo);
if (isConditionOptimizedTrue || ((this.bits & ASTNode.IsElseStatementUnreachable) != 0)) {
if (reportDeadCodeForKnownPattern) {
this.elseStatement.complainIfUnreachable(elseFlowInfo, currentScope, initialComplaintLevel, false);
} else {
this.bits &= ~ASTNode.IsElseStatementUnreachable;
}
}
elseFlowInfo = this.elseStatement.analyseCode(currentScope, flowContext, elseFlowInfo);
if (!(this.elseStatement instanceof Block))
flowContext.expireNullCheckedFieldInfo();
}
currentScope.correlateTrackingVarsIfElse(thenFlowInfo, elseFlowInfo);
FlowInfo mergedInfo = FlowInfo.mergedOptimizedBranchesIfElse(
thenFlowInfo,
isConditionOptimizedTrue,
elseFlowInfo,
isConditionOptimizedFalse,
true ,
flowInfo,
this,
reportDeadCodeForKnownPattern);
this.mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo);
flowContext.conditionalLevel--;
return mergedInfo;
}
@Override
public void generateCode(BlockScope currentScope, CodeStream codeStream) {
if ((this.bits & IsReachable) == 0) {
return;
}
int pc = codeStream.position;
BranchLabel endifLabel = new BranchLabel(codeStream);
Constant cst;
boolean hasThenPart =
!(((cst = this.condition.optimizedBooleanConstant()) != Constant.NotAConstant
&& cst.booleanValue() == false)
|| this.thenStatement == null
|| this.thenStatement.isEmptyBlock());
boolean hasElsePart =
!((cst != Constant.NotAConstant && cst.booleanValue() == true)
|| this.elseStatement == null
|| this.elseStatement.isEmptyBlock());
if (hasThenPart) {
BranchLabel falseLabel = null;
if (cst != Constant.NotAConstant && cst.booleanValue() == true) {
this.condition.generateCode(currentScope, codeStream, false);
} else {
this.condition.generateOptimizedBoolean(
currentScope,
codeStream,
null,
hasElsePart ? (falseLabel = new BranchLabel(codeStream)) : endifLabel,
true);
}
if (this.thenInitStateIndex != -1) {
codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.thenInitStateIndex);
codeStream.addDefinitelyAssignedVariables(currentScope, this.thenInitStateIndex);
}
this.thenStatement.generateCode(currentScope, codeStream);
if (hasElsePart) {
if ((this.bits & ASTNode.ThenExit) == 0) {
this.thenStatement.branchChainTo(endifLabel);
int position = codeStream.position;
codeStream.goto_(endifLabel);
codeStream.recordPositionsFrom(position, this.thenStatement.sourceEnd);
}
if (this.elseInitStateIndex != -1) {
codeStream.removeNotDefinitelyAssignedVariables(
currentScope,
this.elseInitStateIndex);
codeStream.addDefinitelyAssignedVariables(currentScope, this.elseInitStateIndex);
}
if (falseLabel != null) falseLabel.place();
this.elseStatement.generateCode(currentScope, codeStream);
}
} else if (hasElsePart) {
if (cst != Constant.NotAConstant && cst.booleanValue() == false) {
this.condition.generateCode(currentScope, codeStream, false);
} else {
this.condition.generateOptimizedBoolean(
currentScope,
codeStream,
endifLabel,
null,
true);
}
if (this.elseInitStateIndex != -1) {
codeStream.removeNotDefinitelyAssignedVariables(
currentScope,
this.elseInitStateIndex);
codeStream.addDefinitelyAssignedVariables(currentScope, this.elseInitStateIndex);
}
this.elseStatement.generateCode(currentScope, codeStream);
} else {
this.condition.generateCode(currentScope, codeStream, false);
codeStream.recordPositionsFrom(pc, this.sourceStart);
}
if (this.mergedInitStateIndex != -1) {
codeStream.removeNotDefinitelyAssignedVariables(
currentScope,
this.mergedInitStateIndex);
codeStream.addDefinitelyAssignedVariables(currentScope, this.mergedInitStateIndex);
}
endifLabel.place();
codeStream.recordPositionsFrom(pc, this.sourceStart);
}
@Override
public StringBuffer printStatement(int indent, StringBuffer output) {
printIndent(indent, output).append("if (");
this.condition.printExpression(0, output).append(")\n");
this.thenStatement.printStatement(indent + 2, output);
if (this.elseStatement != null) {
output.append('\n');
printIndent(indent, output);
output.append("else\n");
this.elseStatement.printStatement(indent + 2, output);
}
return output;
}
@Override
public void resolve(BlockScope scope) {
TypeBinding type = this.condition.resolveTypeExpecting(scope, TypeBinding.BOOLEAN);
this.condition.computeConversion(scope, type, type);
if (this.thenStatement != null)
this.thenStatement.resolve(scope);
if (this.elseStatement != null)
this.elseStatement.resolve(scope);
}
@Override
public void traverse(ASTVisitor visitor, BlockScope blockScope) {
if (visitor.visit(this, blockScope)) {
this.condition.traverse(visitor, blockScope);
if (this.thenStatement != null)
this.thenStatement.traverse(visitor, blockScope);
if (this.elseStatement != null)
this.elseStatement.traverse(visitor, blockScope);
}
visitor.endVisit(this, blockScope);
}
@Override
public boolean doesNotCompleteNormally() {
return this.thenStatement != null && this.thenStatement.doesNotCompleteNormally() && this.elseStatement != null && this.elseStatement.doesNotCompleteNormally();
}
@Override
public boolean completesByContinue() {
return this.thenStatement != null && this.thenStatement.completesByContinue() || this.elseStatement != null && this.elseStatement.completesByContinue();
}
}