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
7  *
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package org.eclipse.jdt.internal.compiler.ast;
12 
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.*;
18 
19 public class IfStatement extends Statement {
20 
21 	//this class represents the case of only one statement in
22 	//either else and/or then branches.
23 
24 	public Expression condition;
25 	public Statement thenStatement;
26 	public Statement elseStatement;
27 
28 	boolean thenExit;
29 
30 	// for local variables table attributes
31 	int thenInitStateIndex = -1;
32 	int elseInitStateIndex = -1;
33 	int mergedInitStateIndex = -1;
34 
IfStatement(Expression condition, Statement thenStatement, int sourceStart, int sourceEnd)35 	public IfStatement(Expression condition, Statement thenStatement, 	int sourceStart, int sourceEnd) {
36 
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;
43 	}
44 
IfStatement(Expression condition, Statement thenStatement, Statement elseStatement, int sourceStart, int sourceEnd)45 	public IfStatement(Expression condition, Statement thenStatement, Statement elseStatement, int sourceStart, int sourceEnd) {
46 
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;
55 	}
56 
analyseCode( BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo)57 	public FlowInfo analyseCode(
58 		BlockScope currentScope,
59 		FlowContext flowContext,
60 		FlowInfo flowInfo) {
61 
62 		// process the condition
63 		flowInfo = condition.analyseCode(currentScope, flowContext, flowInfo);
64 
65 		Constant cst = this.condition.optimizedBooleanConstant();
66 		boolean isConditionOptimizedTrue = cst != NotAConstant && cst.booleanValue() == true;
67 		boolean isConditionOptimizedFalse = cst != NotAConstant && cst.booleanValue() == false;
68 
69 		// process the THEN part
70 		FlowInfo thenFlowInfo = flowInfo.initsWhenTrue().copy();
71 		if (isConditionOptimizedFalse) {
72 			thenFlowInfo.setReachMode(FlowInfo.UNREACHABLE);
73 		}
74 		if (this.thenStatement != null) {
75 			// Save info for code gen
76 			thenInitStateIndex =
77 				currentScope.methodScope().recordInitializationStates(thenFlowInfo);
78 			if (!thenStatement.complainIfUnreachable(thenFlowInfo, currentScope, false)) {
79 				thenFlowInfo =
80 					thenStatement.analyseCode(currentScope, flowContext, thenFlowInfo);
81 			}
82 		}
83 		// code gen: optimizing the jump around the ELSE part
84 		this.thenExit =  !thenFlowInfo.isReachable();
85 
86 		// process the ELSE part
87 		FlowInfo elseFlowInfo = flowInfo.initsWhenFalse().copy();
88 		if (isConditionOptimizedTrue) {
89 			elseFlowInfo.setReachMode(FlowInfo.UNREACHABLE);
90 		}
91 		if (this.elseStatement != null) {
92 		    // signal else clause unnecessarily nested, tolerate else-if code pattern
93 		    if (thenFlowInfo == FlowInfo.DEAD_END
94 		            && (this.bits & IsElseIfStatement) == 0 	// else of an else-if
95 		            && !(this.elseStatement instanceof IfStatement)) {
96 		        currentScope.problemReporter().unnecessaryElse(this.elseStatement);
97 		    }
98 			// Save info for code gen
99 			elseInitStateIndex =
100 				currentScope.methodScope().recordInitializationStates(elseFlowInfo);
101 			if (!elseStatement.complainIfUnreachable(elseFlowInfo, currentScope, false)) {
102 				elseFlowInfo =
103 					elseStatement.analyseCode(currentScope, flowContext, elseFlowInfo);
104 			}
105 		}
106 
107 		// merge THEN & ELSE initializations
108 		FlowInfo mergedInfo = FlowInfo.mergedOptimizedBranches(
109 				thenFlowInfo,
110 				isConditionOptimizedTrue,
111 				elseFlowInfo,
112 				isConditionOptimizedFalse,
113 				true /*if(true){ return; }  fake-reachable(); */);
114 		mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo);
115 		return mergedInfo;
116 	}
117 
118 	/**
119 	 * If code generation
120 	 *
121 	 * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
122 	 * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
123 	 */
generateCode(BlockScope currentScope, CodeStream codeStream)124 	public void generateCode(BlockScope currentScope, CodeStream codeStream) {
125 
126 		if ((this.bits & IsReachableMASK) == 0) {
127 			return;
128 		}
129 		int pc = codeStream.position;
130 		Label endifLabel = new Label(codeStream);
131 
132 		// optimizing the then/else part code gen
133 		Constant cst;
134 		boolean hasThenPart =
135 			!(((cst = this.condition.optimizedBooleanConstant()) != NotAConstant
136 					&& cst.booleanValue() == false)
137 				|| this.thenStatement == null
138 				|| this.thenStatement.isEmptyBlock());
139 		boolean hasElsePart =
140 			!((cst != NotAConstant && cst.booleanValue() == true)
141 				|| this.elseStatement == null
142 				|| this.elseStatement.isEmptyBlock());
143 
144 		if (hasThenPart) {
145 			Label falseLabel;
146 			// generate boolean condition
147 			this.condition.generateOptimizedBoolean(
148 				currentScope,
149 				codeStream,
150 				null,
151 				(falseLabel = new Label(codeStream)),
152 				true);
153 			// May loose some local variable initializations : affecting the local variable attributes
154 			if (thenInitStateIndex != -1) {
155 				codeStream.removeNotDefinitelyAssignedVariables(currentScope, thenInitStateIndex);
156 				codeStream.addDefinitelyAssignedVariables(currentScope, thenInitStateIndex);
157 			}
158 			// generate then statement
159 			this.thenStatement.generateCode(currentScope, codeStream);
160 			// jump around the else statement
161 			if (hasElsePart && !thenExit) {
162 				this.thenStatement.branchChainTo(endifLabel);
163 				int position = codeStream.position;
164 				codeStream.goto_(endifLabel);
165 				codeStream.updateLastRecordedEndPC(position);
166 				//goto is tagged as part of the thenAction block
167 			}
168 			falseLabel.place();
169 		} else {
170 			if (hasElsePart) {
171 				// generate boolean condition
172 				this.condition.generateOptimizedBoolean(
173 					currentScope,
174 					codeStream,
175 					endifLabel,
176 					null,
177 					true);
178 			} else {
179 				// generate condition side-effects
180 				this.condition.generateCode(currentScope, codeStream, false);
181 				codeStream.recordPositionsFrom(pc, this.sourceStart);
182 			}
183 		}
184 		// generate else statement
185 		if (hasElsePart) {
186 			// May loose some local variable initializations : affecting the local variable attributes
187 			if (elseInitStateIndex != -1) {
188 				codeStream.removeNotDefinitelyAssignedVariables(
189 					currentScope,
190 					elseInitStateIndex);
191 				codeStream.addDefinitelyAssignedVariables(currentScope, elseInitStateIndex);
192 			}
193 			this.elseStatement.generateCode(currentScope, codeStream);
194 		}
195 		endifLabel.place();
196 		// May loose some local variable initializations : affecting the local variable attributes
197 		if (mergedInitStateIndex != -1) {
198 			codeStream.removeNotDefinitelyAssignedVariables(
199 				currentScope,
200 				mergedInitStateIndex);
201 		}
202 		codeStream.recordPositionsFrom(pc, this.sourceStart);
203 	}
204 
printStatement(int indent, StringBuffer output)205 	public StringBuffer printStatement(int indent, StringBuffer output) {
206 
207 		printIndent(indent, output).append("if ("); //$NON-NLS-1$
208 		condition.printExpression(0, output).append(")\n");	//$NON-NLS-1$
209 		thenStatement.printStatement(indent + 2, output);
210 		if (elseStatement != null) {
211 			output.append('\n');
212 			printIndent(indent, output);
213 			output.append("else\n"); //$NON-NLS-1$
214 			elseStatement.printStatement(indent + 2, output);
215 		}
216 		return output;
217 	}
218 
resolve(BlockScope scope)219 	public void resolve(BlockScope scope) {
220 
221 		TypeBinding type = condition.resolveTypeExpecting(scope, BooleanBinding);
222 		condition.computeConversion(scope, type, type);
223 		if (thenStatement != null)
224 			thenStatement.resolve(scope);
225 		if (elseStatement != null)
226 			elseStatement.resolve(scope);
227 	}
228 
traverse( ASTVisitor visitor, BlockScope blockScope)229 	public void traverse(
230 		ASTVisitor visitor,
231 		BlockScope blockScope) {
232 
233 		if (visitor.visit(this, blockScope)) {
234 			condition.traverse(visitor, blockScope);
235 			if (thenStatement != null)
236 				thenStatement.traverse(visitor, blockScope);
237 			if (elseStatement != null)
238 				elseStatement.traverse(visitor, blockScope);
239 		}
240 		visitor.endVisit(this, blockScope);
241 	}
242 }
243