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