package org.eclipse.jdt.internal.compiler.ast; | |
/* | |
* (c) Copyright IBM Corp. 2000, 2001. | |
* All Rights Reserved. | |
*/ | |
import org.eclipse.jdt.internal.compiler.IAbstractSyntaxTreeVisitor; | |
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 { | |
//this class represents the case of only one statement in | |
//either else and/or then branches. | |
public Expression condition; | |
public Statement thenStatement; | |
public Statement elseStatement; | |
boolean thenExit; | |
// for local variables table attributes | |
int thenInitStateIndex = -1; | |
int elseInitStateIndex = -1; | |
int mergedInitStateIndex = -1; | |
public IfStatement(Expression condition, Statement thenStatement,int s,int e) { | |
this.condition = condition; | |
this.thenStatement = thenStatement; | |
sourceStart = s; | |
sourceEnd = e; | |
} | |
public IfStatement(Expression condition, Statement thenStatement, Statement elseStatement, int s, int e) { | |
this.condition = condition; | |
this.thenStatement = thenStatement; | |
this.elseStatement = elseStatement; | |
sourceEnd =e; | |
sourceStart=s; | |
} | |
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { | |
FlowInfo thenFlowInfo, elseFlowInfo; | |
// process the condition | |
flowInfo = condition.analyseCode(currentScope, flowContext, flowInfo); | |
// process the THEN part | |
if (thenStatement == null) { | |
thenFlowInfo = flowInfo.initsWhenTrue(); | |
} else { | |
Constant cst; | |
thenFlowInfo = | |
((((cst = condition.constant) != NotAConstant) && (cst.booleanValue() == false)) | |
|| (((cst = condition.conditionalConstant()) != NotAConstant) && (cst.booleanValue() == false))) | |
? (flowInfo.initsWhenTrue().copy().markAsFakeReachable(true)) | |
: flowInfo.initsWhenTrue().copy(); | |
// Save info for code gen | |
thenInitStateIndex = currentScope.methodScope().recordInitializationStates(thenFlowInfo); | |
if (!thenFlowInfo.complainIfUnreachable(thenStatement, currentScope)) { | |
thenFlowInfo = thenStatement.analyseCode(currentScope, flowContext, thenFlowInfo); | |
} | |
}; | |
// optimizing the jump around the ELSE part | |
thenExit = (thenFlowInfo == FlowInfo.DeadEnd) || thenFlowInfo.isFakeReachable(); | |
// process the ELSE part | |
if (elseStatement == null) { | |
elseFlowInfo = flowInfo.initsWhenFalse(); | |
} else { | |
Constant cst; | |
elseFlowInfo = | |
((((cst = condition.constant) != NotAConstant) && (cst.booleanValue() == true)) | |
|| (((cst = condition.conditionalConstant()) != NotAConstant) && (cst.booleanValue() == true))) | |
? (flowInfo.initsWhenFalse().copy().markAsFakeReachable(true)) | |
: flowInfo.initsWhenFalse().copy(); | |
// Save info for code gen | |
elseInitStateIndex = currentScope.methodScope().recordInitializationStates(elseFlowInfo); | |
if (!elseFlowInfo.complainIfUnreachable(elseStatement, currentScope)) { | |
elseFlowInfo = elseStatement.analyseCode(currentScope, flowContext, elseFlowInfo); | |
} | |
} | |
// merge THEN & ELSE initializations | |
FlowInfo mergedInfo; | |
if ((condition.constant != NotAConstant) && (condition.constant.booleanValue() == true)) { | |
if (thenExit) { | |
mergedInfo = elseFlowInfo.markAsFakeReachable(true); | |
mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo); | |
return mergedInfo; | |
} else { | |
mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(thenFlowInfo); | |
return thenFlowInfo; | |
} | |
} else { | |
if ((condition.constant != NotAConstant) && (condition.constant.booleanValue() == false)) { | |
if (elseFlowInfo.isDeadEnd()) { | |
mergedInfo = thenFlowInfo.markAsFakeReachable(true); | |
mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo); | |
return mergedInfo; | |
} else { | |
mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(elseFlowInfo); | |
return elseFlowInfo; | |
} | |
} | |
} | |
mergedInfo = thenFlowInfo.mergedWith(elseFlowInfo.unconditionalInits()); | |
mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo); | |
return mergedInfo; | |
} | |
/** | |
* If code generation | |
* | |
* @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope | |
* @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream | |
*/ | |
public void generateCode(BlockScope currentScope, CodeStream codeStream) { | |
if ((bits & IsReachableMASK) == 0) { | |
return; | |
} | |
int pc = codeStream.position, divergePC; | |
Label endifLabel = new Label(codeStream); | |
// optimizing the then/else part code gen | |
Constant cst, condCst; | |
boolean hasThenPart = !((((cst = condition.constant) != NotAConstant) && (cst.booleanValue() == false)) | |
|| (thenStatement == null) | |
|| (thenStatement.isEmptyBlock()) | |
|| (((condCst = condition.conditionalConstant()) != NotAConstant) && (condCst.booleanValue() == false))); | |
boolean hasElsePart = !(((cst != NotAConstant) && (cst.booleanValue() == true)) | |
|| (elseStatement == null) | |
|| (elseStatement.isEmptyBlock()) | |
|| (((condCst = condition.conditionalConstant()) != NotAConstant) && (condCst.booleanValue() == true))); | |
if (hasThenPart) { | |
Label falseLabel; | |
// generate boolean condition | |
condition.generateOptimizedBoolean(currentScope, codeStream, null, (falseLabel = new Label(codeStream)), true); | |
// May loose some local variable initializations : affecting the local variable attributes | |
if (thenInitStateIndex != -1) { | |
codeStream.removeNotDefinitelyAssignedVariables(currentScope, thenInitStateIndex); | |
codeStream.addDefinitelyAssignedVariables(currentScope, thenInitStateIndex); | |
} | |
// generate then statement | |
thenStatement.generateCode(currentScope, codeStream); | |
// jump around the else statement | |
if (hasElsePart && !thenExit) { | |
int position = codeStream.position; | |
codeStream.goto_(endifLabel); | |
codeStream.updateLastRecordedEndPC(position); //goto is tagged as part of the thenAction block | |
} | |
falseLabel.place(); | |
} else { | |
if (hasElsePart) { | |
// generate boolean condition | |
condition.generateOptimizedBoolean(currentScope, codeStream, endifLabel, null, true); | |
} else { | |
// generate condition side-effects | |
condition.generateCode(currentScope, codeStream, false); | |
codeStream.recordPositionsFrom(pc, this); | |
} | |
} | |
// generate else statement | |
if (hasElsePart){ | |
// May loose some local variable initializations : affecting the local variable attributes | |
if (elseInitStateIndex != -1){ | |
codeStream.removeNotDefinitelyAssignedVariables(currentScope, elseInitStateIndex); | |
codeStream.addDefinitelyAssignedVariables(currentScope, elseInitStateIndex); | |
} | |
elseStatement.generateCode(currentScope, codeStream); | |
} | |
endifLabel.place(); | |
// May loose some local variable initializations : affecting the local variable attributes | |
if (mergedInitStateIndex != -1) { | |
codeStream.removeNotDefinitelyAssignedVariables(currentScope, mergedInitStateIndex); | |
} | |
codeStream.recordPositionsFrom(pc, this); | |
} | |
public void resolve(BlockScope scope) { | |
TypeBinding type = condition.resolveTypeExpecting(scope, BooleanBinding); | |
condition.implicitWidening(type, type); | |
if (thenStatement != null) | |
thenStatement.resolve(scope); | |
if (elseStatement != null) | |
elseStatement.resolve(scope); | |
} | |
public String toString(int tab){ | |
/*slow code */ | |
String inFront , s = tabString(tab) ; | |
inFront = s ; | |
s = s + "if ("/*nonNLS*/+ condition.toStringExpression()+") \n"/*nonNLS*/; | |
s = s + thenStatement.toString(tab+2) + ";"/*nonNLS*/ ; | |
if (elseStatement != null) | |
s = s + "\n"/*nonNLS*/ + inFront + "else\n"/*nonNLS*/ + elseStatement.toString(tab+2) + ";"/*nonNLS*/; | |
return s ;} | |
public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope blockScope) { | |
if (visitor.visit(this, blockScope)) { | |
condition.traverse(visitor, blockScope); | |
if (thenStatement != null) | |
thenStatement.traverse(visitor, blockScope); | |
if (elseStatement != null) | |
elseStatement.traverse(visitor, blockScope); | |
} | |
visitor.endVisit(this, blockScope); | |
} | |
} |