misc changes
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / ast / IfStatement.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v0.5 
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v05.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  ******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.ast;
12
13 import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor;
14 import net.sourceforge.phpdt.internal.compiler.impl.*;
15 import net.sourceforge.phpdt.internal.compiler.codegen.*;
16 import net.sourceforge.phpdt.internal.compiler.flow.*;
17 import net.sourceforge.phpdt.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
35         public IfStatement(
36                 Expression condition,
37                 Statement thenStatement,
38                 int s,
39                 int e) {
40
41                 this.condition = condition;
42                 this.thenStatement = thenStatement;
43                 sourceStart = s;
44                 sourceEnd = e;
45         }
46
47         public IfStatement(
48                 Expression condition,
49                 Statement thenStatement,
50                 Statement elseStatement,
51                 int s,
52                 int e) {
53
54                 this.condition = condition;
55                 this.thenStatement = thenStatement;
56                 this.elseStatement = elseStatement;
57                 sourceEnd = e;
58                 sourceStart = s;
59         }
60
61         public FlowInfo analyseCode(
62                 BlockScope currentScope,
63                 FlowContext flowContext,
64                 FlowInfo flowInfo) {
65
66                 FlowInfo thenFlowInfo, elseFlowInfo;
67
68                 // process the condition
69                 flowInfo = condition.analyseCode(currentScope, flowContext, flowInfo);
70
71                 // process the THEN part
72                 if (thenStatement == null) {
73                         thenFlowInfo = flowInfo.initsWhenTrue();
74                 } else {
75                         Constant cst;
76                         thenFlowInfo =
77                                 ((((cst = condition.constant) != NotAConstant)
78                                         && (cst.booleanValue() == false))
79                                         || (((cst = condition.conditionalConstant()) != NotAConstant)
80                                                 && (cst.booleanValue() == false)))
81                                         ? (flowInfo.initsWhenTrue().copy().markAsFakeReachable(true))
82                                         : flowInfo.initsWhenTrue().copy();
83                         // Save info for code gen
84                         thenInitStateIndex =
85                                 currentScope.methodScope().recordInitializationStates(thenFlowInfo);
86                         if (!thenFlowInfo.complainIfUnreachable(thenStatement, currentScope)) {
87                                 thenFlowInfo =
88                                         thenStatement.analyseCode(currentScope, flowContext, thenFlowInfo);
89                         }
90                 };
91                 // optimizing the jump around the ELSE part
92                 thenExit = (thenFlowInfo == FlowInfo.DeadEnd) || thenFlowInfo.isFakeReachable();
93
94                 // process the ELSE part
95                 if (elseStatement == null) {
96                         elseFlowInfo = flowInfo.initsWhenFalse();
97                 } else {
98                         Constant cst;
99                         elseFlowInfo =
100                                 ((((cst = condition.constant) != NotAConstant) && (cst.booleanValue() == true))
101                                         || (((cst = condition.conditionalConstant()) != NotAConstant)
102                                                 && (cst.booleanValue() == true)))
103                                         ? (flowInfo.initsWhenFalse().copy().markAsFakeReachable(true))
104                                         : flowInfo.initsWhenFalse().copy();
105                         // Save info for code gen
106                         elseInitStateIndex =
107                                 currentScope.methodScope().recordInitializationStates(elseFlowInfo);
108                         if (!elseFlowInfo.complainIfUnreachable(elseStatement, currentScope)) {
109                                 elseFlowInfo =
110                                         elseStatement.analyseCode(currentScope, flowContext, elseFlowInfo);
111                         }
112                 }
113
114                 // merge THEN & ELSE initializations
115                 FlowInfo mergedInfo;
116                 if ((condition.constant != NotAConstant)
117                         && (condition.constant.booleanValue() == true)) {
118                         // IF (TRUE)
119                         if (thenExit) {
120                                 mergedInfo = elseFlowInfo.markAsFakeReachable(true);
121                                 mergedInitStateIndex =
122                                         currentScope.methodScope().recordInitializationStates(mergedInfo);
123                                 return mergedInfo;
124                         } else {
125                                 mergedInitStateIndex =
126                                         currentScope.methodScope().recordInitializationStates(thenFlowInfo);
127                                 return thenFlowInfo;
128                         }
129                 } else {
130                         // IF (FALSE)
131                         if ((condition.constant != NotAConstant)
132                                 && (condition.constant.booleanValue() == false)) {
133                                 if (elseFlowInfo.isDeadEnd()) {
134                                         mergedInfo = thenFlowInfo.markAsFakeReachable(true);
135                                         mergedInitStateIndex =
136                                                 currentScope.methodScope().recordInitializationStates(mergedInfo);
137                                         return mergedInfo;
138                                 } else {
139                                         mergedInitStateIndex =
140                                                 currentScope.methodScope().recordInitializationStates(elseFlowInfo);
141                                         return elseFlowInfo;
142                                 }
143                         }
144                 }
145                 mergedInfo = thenFlowInfo.mergedWith(elseFlowInfo.unconditionalInits());
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 ((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, condCst;
167                 boolean hasThenPart =
168                         !((((cst = condition.constant) != NotAConstant)
169                                 && (cst.booleanValue() == false))
170                                 || (thenStatement == null)
171                                 || (thenStatement.isEmptyBlock())
172                                 || (((condCst = condition.conditionalConstant()) != NotAConstant)
173                                         && (condCst.booleanValue() == false)));
174                 boolean hasElsePart =
175                         !(((cst != NotAConstant) && (cst.booleanValue() == true))
176                                 || (elseStatement == null)
177                                 || (elseStatement.isEmptyBlock())
178                                 || (((condCst = condition.conditionalConstant()) != NotAConstant)
179                                         && (condCst.booleanValue() == true)));
180
181                 if (hasThenPart) {
182                         Label falseLabel;
183                         // generate boolean condition
184                         condition.generateOptimizedBoolean(
185                                 currentScope,
186                                 codeStream,
187                                 null,
188                                 (falseLabel = new Label(codeStream)),
189                                 true);
190                         // May loose some local variable initializations : affecting the local variable attributes
191                         if (thenInitStateIndex != -1) {
192                                 codeStream.removeNotDefinitelyAssignedVariables(
193                                         currentScope,
194                                         thenInitStateIndex);
195                                 codeStream.addDefinitelyAssignedVariables(currentScope, thenInitStateIndex);
196                         }
197                         // generate then statement
198                         thenStatement.generateCode(currentScope, codeStream);
199                         // jump around the else statement
200                         if (hasElsePart && !thenExit) {
201                                 thenStatement.branchChainTo(endifLabel);
202                                 int position = codeStream.position;
203                                 codeStream.goto_(endifLabel);
204                                 codeStream.updateLastRecordedEndPC(position);
205                                 //goto is tagged as part of the thenAction block
206                         }
207                         falseLabel.place();
208                 } else {
209                         if (hasElsePart) {
210                                 // generate boolean condition
211                                 condition.generateOptimizedBoolean(
212                                         currentScope,
213                                         codeStream,
214                                         endifLabel,
215                                         null,
216                                         true);
217                         } else {
218                                 // generate condition side-effects
219                                 condition.generateCode(currentScope, codeStream, false);
220                                 codeStream.recordPositionsFrom(pc, this.sourceStart);
221                         }
222                 }
223                 // generate else statement
224                 if (hasElsePart) {
225                         // May loose some local variable initializations : affecting the local variable attributes
226                         if (elseInitStateIndex != -1) {
227                                 codeStream.removeNotDefinitelyAssignedVariables(
228                                         currentScope,
229                                         elseInitStateIndex);
230                                 codeStream.addDefinitelyAssignedVariables(currentScope, elseInitStateIndex);
231                         }
232                         elseStatement.generateCode(currentScope, codeStream);
233                 }
234                 endifLabel.place();
235                 // May loose some local variable initializations : affecting the local variable attributes
236                 if (mergedInitStateIndex != -1) {
237                         codeStream.removeNotDefinitelyAssignedVariables(
238                                 currentScope,
239                                 mergedInitStateIndex);
240                 }
241                 codeStream.recordPositionsFrom(pc, this.sourceStart);
242         }
243
244         public void resolve(BlockScope scope) {
245
246                 TypeBinding type = condition.resolveTypeExpecting(scope, BooleanBinding);
247                 condition.implicitWidening(type, type);
248                 if (thenStatement != null)
249                         thenStatement.resolve(scope);
250                 if (elseStatement != null)
251                         elseStatement.resolve(scope);
252         }
253
254         public String toString(int tab) {
255
256                 String inFront, s = tabString(tab);
257                 inFront = s;
258                 s = s + "if (" + condition.toStringExpression() + ") \n";       //$NON-NLS-1$ //$NON-NLS-2$
259                 s = s + thenStatement.toString(tab + 2) + ";"; //$NON-NLS-1$
260                 if (elseStatement != null)
261                         s = s + "\n" + inFront + "else\n" + elseStatement.toString(tab + 2) + ";"; //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-3$
262                 return s;
263         }
264
265         public void traverse(
266                 IAbstractSyntaxTreeVisitor visitor,
267                 BlockScope blockScope) {
268
269                 if (visitor.visit(this, blockScope)) {
270                         condition.traverse(visitor, blockScope);
271                         if (thenStatement != null)
272                                 thenStatement.traverse(visitor, blockScope);
273                         if (elseStatement != null)
274                                 elseStatement.traverse(visitor, blockScope);
275                 }
276                 visitor.endVisit(this, blockScope);
277         }
278 }