fixed bug #1037094 (foreach)
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpeclipse / internal / compiler / ast / IfStatement.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2003 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 net.sourceforge.phpeclipse.internal.compiler.ast;
12
13 import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor;
14 import net.sourceforge.phpdt.internal.compiler.codegen.Label;
15 import net.sourceforge.phpdt.internal.compiler.flow.FlowContext;
16 import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
17 import net.sourceforge.phpdt.internal.compiler.impl.Constant;
18 import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
19 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
20
21 public class IfStatement extends Statement {
22         
23         //this class represents the case of only one statement in 
24         //either else and/or then branches.
25
26         public Expression condition;
27         public Statement thenStatement;
28         public Statement elseStatement;
29
30         boolean thenExit;
31
32         // for local variables table attributes
33         int thenInitStateIndex = -1;
34         int elseInitStateIndex = -1;
35         int mergedInitStateIndex = -1;
36
37         public IfStatement(
38                 Expression condition,
39                 Statement thenStatement,
40                 int s,
41                 int e) {
42
43                 this.condition = condition;
44                 this.thenStatement = thenStatement;
45                 sourceStart = s;
46                 sourceEnd = e;
47         }
48
49         public IfStatement(
50                 Expression condition,
51                 Statement thenStatement,
52                 Statement elseStatement,
53                 int s,
54                 int e) {
55
56                 this.condition = condition;
57                 this.thenStatement = thenStatement;
58                 this.elseStatement = elseStatement;
59                 sourceEnd = e;
60                 sourceStart = s;
61         }
62
63         public FlowInfo analyseCode(
64                 BlockScope currentScope,
65                 FlowContext flowContext,
66                 FlowInfo flowInfo) {
67
68                 // process the condition
69                 flowInfo = condition.analyseCode(currentScope, flowContext, flowInfo);
70
71                 Constant cst = this.condition.optimizedBooleanConstant();
72                 boolean isConditionOptimizedTrue = cst != NotAConstant && cst.booleanValue() == true;
73                 boolean isConditionOptimizedFalse = cst != NotAConstant && cst.booleanValue() == false;
74                 
75                 // process the THEN part
76                 FlowInfo thenFlowInfo = flowInfo.initsWhenTrue().copy();
77                 if (isConditionOptimizedFalse) {
78                         thenFlowInfo.setReachMode(FlowInfo.UNREACHABLE); 
79                 }
80                 if (this.thenStatement != null) {
81                         // Save info for code gen
82                         thenInitStateIndex =
83                                 currentScope.methodScope().recordInitializationStates(thenFlowInfo);
84                         if (!thenFlowInfo.complainIfUnreachable(thenStatement, currentScope, false)) {
85                                 thenFlowInfo =
86                                         thenStatement.analyseCode(currentScope, flowContext, thenFlowInfo);
87                         }
88                 };
89                 // optimizing the jump around the ELSE part
90                 this.thenExit = !thenFlowInfo.isReachable();
91
92                 // process the ELSE part
93                 FlowInfo elseFlowInfo = flowInfo.initsWhenFalse().copy();
94                 if (isConditionOptimizedTrue) {
95                         elseFlowInfo.setReachMode(FlowInfo.UNREACHABLE); 
96                 }
97                 if (this.elseStatement != null) {
98                         // Save info for code gen
99                         elseInitStateIndex =
100                                 currentScope.methodScope().recordInitializationStates(elseFlowInfo);
101                         if (!elseFlowInfo.complainIfUnreachable(elseStatement, currentScope, false)) {
102                                 elseFlowInfo =
103                                         elseStatement.analyseCode(currentScope, flowContext, elseFlowInfo);
104                         }
105                 }
106
107                 boolean elseExit = !elseFlowInfo.isReachable();
108                 
109                 // merge THEN & ELSE initializations
110                 FlowInfo mergedInfo;
111 //              if (isConditionOptimizedTrue){
112 //                      if (!this.thenExit) {
113 //                              mergedInfo = thenFlowInfo;
114 //                      } else {
115 //                              mergedInfo = elseFlowInfo.setReachMode(FlowInfo.UNREACHABLE);
116 //                      }
117 //
118 //              } else if (isConditionOptimizedFalse) {
119 //                      if (!elseExit) {
120 //                              mergedInfo = elseFlowInfo;
121 //                      } else {
122 //                              mergedInfo = thenFlowInfo.setReachMode(FlowInfo.UNREACHABLE);
123 //                      }
124 //
125 //              } else {
126 //                      mergedInfo = thenFlowInfo.mergedWith(elseFlowInfo.unconditionalInits());
127 //              }
128                 if (isConditionOptimizedTrue){
129                         if (!this.thenExit) {
130                                 mergedInfo = thenFlowInfo.addPotentialInitializationsFrom(elseFlowInfo);
131                         } else {
132                                 mergedInfo = elseFlowInfo.setReachMode(FlowInfo.UNREACHABLE);
133                         }
134
135                 } else if (isConditionOptimizedFalse) {
136                         if (!elseExit) {
137                                 mergedInfo = elseFlowInfo.addPotentialInitializationsFrom(thenFlowInfo);
138                         } else {
139                                 mergedInfo = thenFlowInfo.setReachMode(FlowInfo.UNREACHABLE);
140                         }
141
142                 } else {
143                         mergedInfo = thenFlowInfo.mergedWith(elseFlowInfo.unconditionalInits());
144                 }
145
146                 mergedInitStateIndex =
147                         currentScope.methodScope().recordInitializationStates(mergedInfo);
148                 return mergedInfo;
149         }
150
151         /**
152          * If code generation
153          *
154          * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
155          * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
156          */
157 //      public void generateCode(BlockScope currentScope, CodeStream codeStream) {
158 //
159 //              if ((this.bits & IsReachableMASK) == 0) {
160 //                      return;
161 //              }
162 //              int pc = codeStream.position;
163 //              Label endifLabel = new Label(codeStream);
164 //
165 //              // optimizing the then/else part code gen
166 //              Constant cst;
167 //              boolean hasThenPart = 
168 //                      !(((cst = this.condition.optimizedBooleanConstant()) != NotAConstant
169 //                                      && cst.booleanValue() == false)
170 //                              || this.thenStatement == null
171 //                              || this.thenStatement.isEmptyBlock());
172 //              boolean hasElsePart =
173 //                      !((cst != NotAConstant && cst.booleanValue() == true)
174 //                              || this.elseStatement == null
175 //                              || this.elseStatement.isEmptyBlock());
176 //
177 //              if (hasThenPart) {
178 //                      Label falseLabel;
179 //                      // generate boolean condition
180 //                      this.condition.generateOptimizedBoolean(
181 //                              currentScope,
182 //                              codeStream,
183 //                              null,
184 //                              (falseLabel = new Label(codeStream)),
185 //                              true);
186 //                      // May loose some local variable initializations : affecting the local variable attributes
187 //                      if (thenInitStateIndex != -1) {
188 //                              codeStream.removeNotDefinitelyAssignedVariables(
189 //                                      currentScope,
190 //                                      thenInitStateIndex);
191 //                              codeStream.addDefinitelyAssignedVariables(currentScope, thenInitStateIndex);
192 //                      }
193 //                      // generate then statement
194 //                      this.thenStatement.generateCode(currentScope, codeStream);
195 //                      // jump around the else statement
196 //                      if (hasElsePart && !thenExit) {
197 //                              this.thenStatement.branchChainTo(endifLabel);
198 //                              int position = codeStream.position;
199 //                              codeStream.goto_(endifLabel);
200 //                              codeStream.updateLastRecordedEndPC(position);
201 //                              //goto is tagged as part of the thenAction block
202 //                      }
203 //                      falseLabel.place();
204 //              } else {
205 //                      if (hasElsePart) {
206 //                              // generate boolean condition
207 //                              this.condition.generateOptimizedBoolean(
208 //                                      currentScope,
209 //                                      codeStream,
210 //                                      endifLabel,
211 //                                      null,
212 //                                      true);
213 //                      } else {
214 //                              // generate condition side-effects
215 //                              this.condition.generateCode(currentScope, codeStream, false);
216 //                              codeStream.recordPositionsFrom(pc, this.sourceStart);
217 //                      }
218 //              }
219 //              // generate else statement
220 //              if (hasElsePart) {
221 //                      // May loose some local variable initializations : affecting the local variable attributes
222 //                      if (elseInitStateIndex != -1) {
223 //                              codeStream.removeNotDefinitelyAssignedVariables(
224 //                                      currentScope,
225 //                                      elseInitStateIndex);
226 //                              codeStream.addDefinitelyAssignedVariables(currentScope, elseInitStateIndex);
227 //                      }
228 //                      this.elseStatement.generateCode(currentScope, codeStream);
229 //              }
230 //              endifLabel.place();
231 //              // May loose some local variable initializations : affecting the local variable attributes
232 //              if (mergedInitStateIndex != -1) {
233 //                      codeStream.removeNotDefinitelyAssignedVariables(
234 //                              currentScope,
235 //                              mergedInitStateIndex);
236 //              }
237 //              codeStream.recordPositionsFrom(pc, this.sourceStart);
238 //      }
239
240         public void resolve(BlockScope scope) {
241
242                 TypeBinding type = condition.resolveTypeExpecting(scope, BooleanBinding);
243                 condition.implicitWidening(type, type);
244                 if (thenStatement != null)
245                         thenStatement.resolve(scope);
246                 if (elseStatement != null)
247                         elseStatement.resolve(scope);
248         }
249
250         public String toString(int tab) {
251
252                 String inFront, s = tabString(tab);
253                 inFront = s;
254                 s = s + "if (" + condition.toStringExpression() + ") \n";       //$NON-NLS-1$ //$NON-NLS-2$
255                 s = s + thenStatement.toString(tab + 2) + ";"; //$NON-NLS-1$
256                 if (elseStatement != null)
257                         s = s + "\n" + inFront + "else\n" + elseStatement.toString(tab + 2) + ";"; //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-3$
258                 return s;
259         }
260
261         public void traverse(
262                 IAbstractSyntaxTreeVisitor visitor,
263                 BlockScope blockScope) {
264
265                 if (visitor.visit(this, blockScope)) {
266                         condition.traverse(visitor, blockScope);
267                         if (thenStatement != null)
268                                 thenStatement.traverse(visitor, blockScope);
269                         if (elseStatement != null)
270                                 elseStatement.traverse(visitor, blockScope);
271                 }
272                 visitor.endVisit(this, blockScope);
273         }
274 }