Makefile fixup
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / ast / ForStatement.java
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
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
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          */
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(
225                                 currentScope,
226                                 preCondInitStateIndex);
227                 }
228
229                 // generate the condition
230                 conditionLabel.place();
231                 if ((condition != null) && (condition.constant == NotAConstant)) {
232                         condition.generateOptimizedBoolean(scope, codeStream, actionLabel, null, true);
233                 } else {
234                         if (continueLabel != null) {
235                                 codeStream.goto_(actionLabel);
236                         }
237                 }
238                 breakLabel.place();
239
240                 // May loose some local variable initializations : affecting the local variable attributes
241                 if (neededScope) {
242                         codeStream.exitUserScope(scope);
243                 }
244                 if (mergedInitStateIndex != -1) {
245                         codeStream.removeNotDefinitelyAssignedVariables(currentScope, mergedInitStateIndex);
246                         codeStream.addDefinitelyAssignedVariables(currentScope, mergedInitStateIndex);
247                 }
248                 codeStream.recordPositionsFrom(pc, this.sourceStart);
249         }
250
251         public StringBuffer printStatement(int tab, StringBuffer output) {
252
253                 printIndent(tab, output).append("for ("); //$NON-NLS-1$
254                 //inits
255                 if (initializations != null) {
256                         for (int i = 0; i < initializations.length; i++) {
257                                 //nice only with expressions
258                                 if (i > 0) output.append(", "); //$NON-NLS-1$
259                                 initializations[i].print(0, output);
260                         }
261                 }
262                 output.append("; "); //$NON-NLS-1$
263                 //cond
264                 if (condition != null) condition.printExpression(0, output);
265                 output.append("; "); //$NON-NLS-1$
266                 //updates
267                 if (increments != null) {
268                         for (int i = 0; i < increments.length; i++) {
269                                 if (i > 0) output.append(", "); //$NON-NLS-1$
270                                 increments[i].print(0, output);
271                         }
272                 }
273                 output.append(") "); //$NON-NLS-1$
274                 //block
275                 if (action == null)
276                         output.append(';');
277                 else {
278                         output.append('\n');
279                         action.printStatement(tab + 1, output); //$NON-NLS-1$
280                 }
281                 return output.append(';');
282         }
283
284         public void resolve(BlockScope upperScope) {
285
286                 // use the scope that will hold the init declarations
287                 scope = neededScope ? new BlockScope(upperScope) : upperScope;
288                 if (initializations != null)
289                         for (int i = 0, length = initializations.length; i < length; i++)
290                                 initializations[i].resolve(scope);
291                 if (condition != null) {
292                         TypeBinding type = condition.resolveTypeExpecting(scope, BooleanBinding);
293                         condition.implicitWidening(type, type);
294                 }
295                 if (increments != null)
296                         for (int i = 0, length = increments.length; i < length; i++)
297                                 increments[i].resolve(scope);
298                 if (action != null)
299                         action.resolve(scope);
300         }
301         
302         public void traverse(
303                 ASTVisitor visitor,
304                 BlockScope blockScope) {
305
306                 if (visitor.visit(this, blockScope)) {
307                         if (initializations != null) {
308                                 int initializationsLength = initializations.length;
309                                 for (int i = 0; i < initializationsLength; i++)
310                                         initializations[i].traverse(visitor, scope);
311                         }
312
313                         if (condition != null)
314                                 condition.traverse(visitor, scope);
315
316                         if (increments != null) {
317                                 int incrementsLength = increments.length;
318                                 for (int i = 0; i < incrementsLength; i++)
319                                         increments[i].traverse(visitor, scope);
320                         }
321
322                         if (action != null)
323                                 action.traverse(visitor, scope);
324                 }
325                 visitor.endVisit(this, blockScope);
326         }
327 }