1 /*******************************************************************************
2 * Copyright (c) 2000, 2004 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.jdt.internal.compiler.ast;
13 import org.eclipse.jdt.internal.compiler.ASTVisitor;
14 import org.eclipse.jdt.internal.compiler.impl.*;
15 import org.eclipse.jdt.internal.compiler.codegen.*;
16 import org.eclipse.jdt.internal.compiler.flow.*;
17 import org.eclipse.jdt.internal.compiler.lookup.*;
19 public class IfStatement extends Statement {
21 //this class represents the case of only one statement in
22 //either else and/or then branches.
24 public Expression condition;
25 public Statement thenStatement;
26 public Statement elseStatement;
30 // for local variables table attributes
31 int thenInitStateIndex = -1;
32 int elseInitStateIndex = -1;
33 int mergedInitStateIndex = -1;
35 public IfStatement(Expression condition, Statement thenStatement, int sourceStart, int sourceEnd) {
37 this.condition = condition;
38 this.thenStatement = thenStatement;
39 // remember useful empty statement
40 if (thenStatement instanceof EmptyStatement) thenStatement.bits |= IsUsefulEmptyStatementMASK;
41 this.sourceStart = sourceStart;
42 this.sourceEnd = sourceEnd;
45 public IfStatement(Expression condition, Statement thenStatement, Statement elseStatement, int sourceStart, int sourceEnd) {
47 this.condition = condition;
48 this.thenStatement = thenStatement;
49 // remember useful empty statement
50 if (thenStatement instanceof EmptyStatement) thenStatement.bits |= IsUsefulEmptyStatementMASK;
51 this.elseStatement = elseStatement;
52 if (elseStatement instanceof IfStatement) elseStatement.bits |= IsElseIfStatement;
53 this.sourceStart = sourceStart;
54 this.sourceEnd = sourceEnd;
57 public FlowInfo analyseCode(
58 BlockScope currentScope,
59 FlowContext flowContext,
62 // process the condition
63 flowInfo = condition.analyseCode(currentScope, flowContext, flowInfo);
65 Constant cst = this.condition.optimizedBooleanConstant();
66 boolean isConditionOptimizedTrue = cst != NotAConstant && cst.booleanValue() == true;
67 boolean isConditionOptimizedFalse = cst != NotAConstant && cst.booleanValue() == false;
69 // process the THEN part
70 FlowInfo thenFlowInfo = flowInfo.initsWhenTrue().copy();
71 if (isConditionOptimizedFalse) {
72 thenFlowInfo.setReachMode(FlowInfo.UNREACHABLE);
74 FlowInfo elseFlowInfo = flowInfo.initsWhenFalse().copy();
75 if (isConditionOptimizedTrue) {
76 elseFlowInfo.setReachMode(FlowInfo.UNREACHABLE);
78 this.condition.checkNullComparison(currentScope, flowContext, flowInfo, thenFlowInfo, elseFlowInfo);
79 if (this.thenStatement != null) {
80 // Save info for code gen
82 currentScope.methodScope().recordInitializationStates(thenFlowInfo);
83 if (!thenStatement.complainIfUnreachable(thenFlowInfo, currentScope, false)) {
85 thenStatement.analyseCode(currentScope, flowContext, thenFlowInfo);
88 // code gen: optimizing the jump around the ELSE part
89 this.thenExit = !thenFlowInfo.isReachable();
91 // process the ELSE part
92 if (this.elseStatement != null) {
93 // signal else clause unnecessarily nested, tolerate else-if code pattern
94 if (thenFlowInfo == FlowInfo.DEAD_END
95 && (this.bits & IsElseIfStatement) == 0 // else of an else-if
96 && !(this.elseStatement instanceof IfStatement)) {
97 currentScope.problemReporter().unnecessaryElse(this.elseStatement);
99 // Save info for code gen
101 currentScope.methodScope().recordInitializationStates(elseFlowInfo);
102 if (!elseStatement.complainIfUnreachable(elseFlowInfo, currentScope, false)) {
104 elseStatement.analyseCode(currentScope, flowContext, elseFlowInfo);
108 // merge THEN & ELSE initializations
109 FlowInfo mergedInfo = FlowInfo.mergedOptimizedBranches(
111 isConditionOptimizedTrue,
113 isConditionOptimizedFalse,
114 true /*if(true){ return; } fake-reachable(); */);
115 mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo);
122 * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
123 * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
125 public void generateCode(BlockScope currentScope, CodeStream codeStream) {
127 if ((this.bits & IsReachableMASK) == 0) {
130 int pc = codeStream.position;
131 Label endifLabel = new Label(codeStream);
133 // optimizing the then/else part code gen
135 boolean hasThenPart =
136 !(((cst = this.condition.optimizedBooleanConstant()) != NotAConstant
137 && cst.booleanValue() == false)
138 || this.thenStatement == null
139 || this.thenStatement.isEmptyBlock());
140 boolean hasElsePart =
141 !((cst != NotAConstant && cst.booleanValue() == true)
142 || this.elseStatement == null
143 || this.elseStatement.isEmptyBlock());
147 // generate boolean condition
148 this.condition.generateOptimizedBoolean(
152 (falseLabel = new Label(codeStream)),
154 // May loose some local variable initializations : affecting the local variable attributes
155 if (thenInitStateIndex != -1) {
156 codeStream.removeNotDefinitelyAssignedVariables(currentScope, thenInitStateIndex);
157 codeStream.addDefinitelyAssignedVariables(currentScope, thenInitStateIndex);
159 // generate then statement
160 this.thenStatement.generateCode(currentScope, codeStream);
161 // jump around the else statement
162 if (hasElsePart && !thenExit) {
163 this.thenStatement.branchChainTo(endifLabel);
164 int position = codeStream.position;
165 codeStream.goto_(endifLabel);
166 codeStream.updateLastRecordedEndPC(position);
167 //goto is tagged as part of the thenAction block
172 // generate boolean condition
173 this.condition.generateOptimizedBoolean(
180 // generate condition side-effects
181 this.condition.generateCode(currentScope, codeStream, false);
182 codeStream.recordPositionsFrom(pc, this.sourceStart);
185 // generate else statement
187 // May loose some local variable initializations : affecting the local variable attributes
188 if (elseInitStateIndex != -1) {
189 codeStream.removeNotDefinitelyAssignedVariables(
192 codeStream.addDefinitelyAssignedVariables(currentScope, elseInitStateIndex);
194 this.elseStatement.generateCode(currentScope, codeStream);
197 // May loose some local variable initializations : affecting the local variable attributes
198 if (mergedInitStateIndex != -1) {
199 codeStream.removeNotDefinitelyAssignedVariables(
201 mergedInitStateIndex);
203 codeStream.recordPositionsFrom(pc, this.sourceStart);
206 public StringBuffer printStatement(int indent, StringBuffer output) {
208 printIndent(indent, output).append("if ("); //$NON-NLS-1$
209 condition.printExpression(0, output).append(")\n"); //$NON-NLS-1$
210 thenStatement.printStatement(indent + 2, output);
211 if (elseStatement != null) {
213 printIndent(indent, output);
214 output.append("else\n"); //$NON-NLS-1$
215 elseStatement.printStatement(indent + 2, output);
220 public void resolve(BlockScope scope) {
222 TypeBinding type = condition.resolveTypeExpecting(scope, BooleanBinding);
223 condition.computeConversion(scope, type, type);
224 if (thenStatement != null)
225 thenStatement.resolve(scope);
226 if (elseStatement != null)
227 elseStatement.resolve(scope);
230 public void traverse(
232 BlockScope blockScope) {
234 if (visitor.visit(this, blockScope)) {
235 condition.traverse(visitor, blockScope);
236 if (thenStatement != null)
237 thenStatement.traverse(visitor, blockScope);
238 if (elseStatement != null)
239 elseStatement.traverse(visitor, blockScope);
241 visitor.endVisit(this, blockScope);