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.classfmt.ClassFileConstants;
15 import org.eclipse.jdt.internal.compiler.codegen.*;
16 import org.eclipse.jdt.internal.compiler.flow.*;
17 import org.eclipse.jdt.internal.compiler.impl.Constant;
18 import org.eclipse.jdt.internal.compiler.lookup.*;
19 
20 public class ForStatement extends Statement {
21 
22 	public Statement[] initializations;
23 	public Expression condition;
24 	public Statement[] increments;
25 	public Statement action;
26 
27 	//when there is no local declaration, there is no need of a new scope
28 	//scope is positionned either to a new scope, or to the "upper"scope (see resolveType)
29 	public boolean neededScope;
30 	public BlockScope scope;
31 
32 	private Label breakLabel, continueLabel;
33 
34 	// for local variables table attributes
35 	int preCondInitStateIndex = -1;
36 	int condIfTrueInitStateIndex = -1;
37 	int mergedInitStateIndex = -1;
38 
ForStatement( Statement[] initializations, Expression condition, Statement[] increments, Statement action, boolean neededScope, int s, int e)39 	public ForStatement(
40 		Statement[] initializations,
41 		Expression condition,
42 		Statement[] increments,
43 		Statement action,
44 		boolean neededScope,
45 		int s,
46 		int e) {
47 
48 		this.sourceStart = s;
49 		this.sourceEnd = e;
50 		this.initializations = initializations;
51 		this.condition = condition;
52 		this.increments = increments;
53 		this.action = action;
54 		// remember useful empty statement
55 		if (action instanceof EmptyStatement) action.bits |= IsUsefulEmptyStatementMASK;
56 		this.neededScope = neededScope;
57 	}
58 
analyseCode( BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo)59 	public FlowInfo analyseCode(
60 		BlockScope currentScope,
61 		FlowContext flowContext,
62 		FlowInfo flowInfo) {
63 
64 		breakLabel = new Label();
65 		continueLabel = new Label();
66 
67 		// process the initializations
68 		if (initializations != null) {
69 			for (int i = 0, count = initializations.length; i < count; i++) {
70 				flowInfo = initializations[i].analyseCode(scope, flowContext, flowInfo);
71 			}
72 		}
73 		preCondInitStateIndex =
74 			currentScope.methodScope().recordInitializationStates(flowInfo);
75 
76 		Constant cst = this.condition == null ? null : this.condition.constant;
77 		boolean isConditionTrue = cst == null || (cst != NotAConstant && cst.booleanValue() == true);
78 		boolean isConditionFalse = cst != null && (cst != NotAConstant && cst.booleanValue() == false);
79 
80 		cst = this.condition == null ? null : this.condition.optimizedBooleanConstant();
81 		boolean isConditionOptimizedTrue = cst == null ||  (cst != NotAConstant && cst.booleanValue() == true);
82 		boolean isConditionOptimizedFalse = cst != null && (cst != NotAConstant && cst.booleanValue() == false);
83 
84 		// process the condition
85 		LoopingFlowContext condLoopContext = null;
86 		if (condition != null) {
87 			if (!isConditionTrue) {
88 				flowInfo =
89 					condition.analyseCode(
90 						scope,
91 						(condLoopContext =
92 							new LoopingFlowContext(flowContext, this, null, null, scope)),
93 						flowInfo);
94 			}
95 		}
96 
97 		// process the action
98 		LoopingFlowContext loopingContext;
99 		FlowInfo actionInfo;
100 		if (action == null
101 			|| (action.isEmptyBlock() && currentScope.environment().options.complianceLevel <= ClassFileConstants.JDK1_3)) {
102 			if (condLoopContext != null)
103 				condLoopContext.complainOnFinalAssignmentsInLoop(scope, flowInfo);
104 			if (isConditionTrue) {
105 				return FlowInfo.DEAD_END;
106 			} else {
107 				if (isConditionFalse){
108 					continueLabel = null; // for(;false;p());
109 				}
110 				actionInfo = flowInfo.initsWhenTrue().copy();
111 				loopingContext =
112 					new LoopingFlowContext(flowContext, this, breakLabel, continueLabel, scope);
113 			}
114 		} else {
115 			loopingContext =
116 				new LoopingFlowContext(flowContext, this, breakLabel, continueLabel, scope);
117 			FlowInfo initsWhenTrue = flowInfo.initsWhenTrue();
118 			condIfTrueInitStateIndex =
119 				currentScope.methodScope().recordInitializationStates(initsWhenTrue);
120 
121 				if (isConditionFalse) {
122 					actionInfo = FlowInfo.DEAD_END;
123 				} else {
124 					actionInfo = initsWhenTrue.copy();
125 					if (isConditionOptimizedFalse){
126 						actionInfo.setReachMode(FlowInfo.UNREACHABLE);
127 					}
128 				}
129 			if (!this.action.complainIfUnreachable(actionInfo, scope, false)) {
130 				actionInfo = action.analyseCode(scope, loopingContext, actionInfo);
131 			}
132 
133 			// code generation can be optimized when no need to continue in the loop
134 			if (!actionInfo.isReachable() && !loopingContext.initsOnContinue.isReachable()) {
135 				continueLabel = null;
136 			} else {
137 				if (condLoopContext != null)
138 					condLoopContext.complainOnFinalAssignmentsInLoop(scope, flowInfo);
139 				actionInfo = actionInfo.mergedWith(loopingContext.initsOnContinue.unconditionalInits());
140 				loopingContext.complainOnFinalAssignmentsInLoop(scope, actionInfo);
141 			}
142 		}
143 		// for increments
144 		if ((continueLabel != null) && (increments != null)) {
145 			LoopingFlowContext loopContext =
146 				new LoopingFlowContext(flowContext, this, null, null, scope);
147 			for (int i = 0, count = increments.length; i < count; i++) {
148 				actionInfo = increments[i].analyseCode(scope, loopContext, actionInfo);
149 			}
150 			loopContext.complainOnFinalAssignmentsInLoop(scope, actionInfo);
151 		}
152 
153 		//end of loop
154 		FlowInfo mergedInfo = FlowInfo.mergedOptimizedBranches(
155 				loopingContext.initsOnBreak,
156 				isConditionOptimizedTrue,
157 				flowInfo.initsWhenFalse(),
158 				isConditionOptimizedFalse,
159 				!isConditionTrue /*for(;;){}while(true); unreachable(); */);
160 		mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo);
161 		return mergedInfo;
162 	}
163 
164 	/**
165 	 * For statement code generation
166 	 *
167 	 * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
168 	 * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
169 	 */
generateCode(BlockScope currentScope, CodeStream codeStream)170 	public void generateCode(BlockScope currentScope, CodeStream codeStream) {
171 
172 		if ((bits & IsReachableMASK) == 0) {
173 			return;
174 		}
175 		int pc = codeStream.position;
176 
177 		// generate the initializations
178 		if (initializations != null) {
179 			for (int i = 0, max = initializations.length; i < max; i++) {
180 				initializations[i].generateCode(scope, codeStream);
181 			}
182 		}
183 
184 		// label management
185 		Label actionLabel = new Label(codeStream);
186 		Label conditionLabel = new Label(codeStream);
187 		breakLabel.initialize(codeStream);
188 		if (continueLabel != null) {
189 			continueLabel.initialize(codeStream);
190 		}
191 		// jump over the actionBlock
192 		if ((condition != null)
193 			&& (condition.constant == NotAConstant)
194 			&& !((action == null || action.isEmptyBlock()) && (increments == null))) {
195 			int jumpPC = codeStream.position;
196 			codeStream.goto_(conditionLabel);
197 			codeStream.recordPositionsFrom(jumpPC, condition.sourceStart);
198 		}
199 		// generate the loop action
200 		actionLabel.place();
201 		if (action != null) {
202 			// Required to fix 1PR0XVS: LFRE:WINNT - Compiler: variable table for method appears incorrect
203 			if (condIfTrueInitStateIndex != -1) {
204 				// insert all locals initialized inside the condition into the action generated prior to the condition
205 				codeStream.addDefinitelyAssignedVariables(
206 					currentScope,
207 					condIfTrueInitStateIndex);
208 			}
209 			action.generateCode(scope, codeStream);
210 		}
211 		// continuation point
212 		if (continueLabel != null) {
213 			continueLabel.place();
214 			// generate the increments for next iteration
215 			if (increments != null) {
216 				for (int i = 0, max = increments.length; i < max; i++) {
217 					increments[i].generateCode(scope, codeStream);
218 				}
219 			}
220 		}
221 
222 		// May loose some local variable initializations : affecting the local variable attributes
223 		if (preCondInitStateIndex != -1) {
224 			codeStream.removeNotDefinitelyAssignedVariables(currentScope, preCondInitStateIndex);
225 		}
226 
227 		// generate the condition
228 		conditionLabel.place();
229 		if ((condition != null) && (condition.constant == NotAConstant)) {
230 			condition.generateOptimizedBoolean(scope, codeStream, actionLabel, null, true);
231 		} else {
232 			if (continueLabel != null) {
233 				codeStream.goto_(actionLabel);
234 			}
235 		}
236 		breakLabel.place();
237 
238 		// May loose some local variable initializations : affecting the local variable attributes
239 		if (neededScope) {
240 			codeStream.exitUserScope(scope);
241 		}
242 		if (mergedInitStateIndex != -1) {
243 			codeStream.removeNotDefinitelyAssignedVariables(currentScope, mergedInitStateIndex);
244 			codeStream.addDefinitelyAssignedVariables(currentScope, mergedInitStateIndex);
245 		}
246 		codeStream.recordPositionsFrom(pc, this.sourceStart);
247 	}
248 
printStatement(int tab, StringBuffer output)249 	public StringBuffer printStatement(int tab, StringBuffer output) {
250 
251 		printIndent(tab, output).append("for ("); //$NON-NLS-1$
252 		//inits
253 		if (initializations != null) {
254 			for (int i = 0; i < initializations.length; i++) {
255 				//nice only with expressions
256 				if (i > 0) output.append(", "); //$NON-NLS-1$
257 				initializations[i].print(0, output);
258 			}
259 		}
260 		output.append("; "); //$NON-NLS-1$
261 		//cond
262 		if (condition != null) condition.printExpression(0, output);
263 		output.append("; "); //$NON-NLS-1$
264 		//updates
265 		if (increments != null) {
266 			for (int i = 0; i < increments.length; i++) {
267 				if (i > 0) output.append(", "); //$NON-NLS-1$
268 				increments[i].print(0, output);
269 			}
270 		}
271 		output.append(") "); //$NON-NLS-1$
272 		//block
273 		if (action == null)
274 			output.append(';');
275 		else {
276 			output.append('\n');
277 			action.printStatement(tab + 1, output); //$NON-NLS-1$
278 		}
279 		return output.append(';');
280 	}
281 
resolve(BlockScope upperScope)282 	public void resolve(BlockScope upperScope) {
283 
284 		// use the scope that will hold the init declarations
285 		scope = neededScope ? new BlockScope(upperScope) : upperScope;
286 		if (initializations != null)
287 			for (int i = 0, length = initializations.length; i < length; i++)
288 				initializations[i].resolve(scope);
289 		if (condition != null) {
290 			TypeBinding type = condition.resolveTypeExpecting(scope, BooleanBinding);
291 			condition.computeConversion(scope, type, type);
292 		}
293 		if (increments != null)
294 			for (int i = 0, length = increments.length; i < length; i++)
295 				increments[i].resolve(scope);
296 		if (action != null)
297 			action.resolve(scope);
298 	}
299 
traverse( ASTVisitor visitor, BlockScope blockScope)300 	public void traverse(
301 		ASTVisitor visitor,
302 		BlockScope blockScope) {
303 
304 		if (visitor.visit(this, blockScope)) {
305 			if (initializations != null) {
306 				int initializationsLength = initializations.length;
307 				for (int i = 0; i < initializationsLength; i++)
308 					initializations[i].traverse(visitor, scope);
309 			}
310 
311 			if (condition != null)
312 				condition.traverse(visitor, scope);
313 
314 			if (increments != null) {
315 				int incrementsLength = increments.length;
316 				for (int i = 0; i < incrementsLength; i++)
317 					increments[i].traverse(visitor, scope);
318 			}
319 
320 			if (action != null)
321 				action.traverse(visitor, scope);
322 		}
323 		visitor.endVisit(this, blockScope);
324 	}
325 }
326