removed Makefile; lifted repo/org.ibex.tool/src/ to src/
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / ast / IfStatement.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.impl.*;
15 import org.eclipse.jdt.internal.compiler.codegen.*;
16 import org.eclipse.jdt.internal.compiler.flow.*;
17 import org.eclipse.jdt.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(Expression condition, Statement thenStatement,       int sourceStart, int sourceEnd) {
36
37                 this.condition = condition;
38                 this.thenStatement = thenStatement;
39                 // remember useful empty statement
40                 if (thenStatement instanceof EmptyStatement) thenStatement.bits |= IsUsefulEmptyStatementMASK;
41                 this.sourceStart = sourceStart;
42                 this.sourceEnd = sourceEnd;
43         }
44
45         public IfStatement(Expression condition, Statement thenStatement, Statement elseStatement, int sourceStart, int sourceEnd) {
46
47                 this.condition = condition;
48                 this.thenStatement = thenStatement;
49                 // remember useful empty statement
50                 if (thenStatement instanceof EmptyStatement) thenStatement.bits |= IsUsefulEmptyStatementMASK;
51                 this.elseStatement = elseStatement;
52                 if (elseStatement instanceof IfStatement) elseStatement.bits |= IsElseIfStatement;
53                 this.sourceStart = sourceStart;
54                 this.sourceEnd = sourceEnd;
55         }
56
57         public FlowInfo analyseCode(
58                 BlockScope currentScope,
59                 FlowContext flowContext,
60                 FlowInfo flowInfo) {
61
62                 // process the condition
63                 flowInfo = condition.analyseCode(currentScope, flowContext, flowInfo);
64
65                 Constant cst = this.condition.optimizedBooleanConstant();
66                 boolean isConditionOptimizedTrue = cst != NotAConstant && cst.booleanValue() == true;
67                 boolean isConditionOptimizedFalse = cst != NotAConstant && cst.booleanValue() == false;
68                 
69                 // process the THEN part
70                 FlowInfo thenFlowInfo = flowInfo.initsWhenTrue().copy();
71                 if (isConditionOptimizedFalse) {
72                         thenFlowInfo.setReachMode(FlowInfo.UNREACHABLE); 
73                 }
74                 if (this.thenStatement != null) {
75                         // Save info for code gen
76                         thenInitStateIndex =
77                                 currentScope.methodScope().recordInitializationStates(thenFlowInfo);
78                         if (!thenStatement.complainIfUnreachable(thenFlowInfo, currentScope, false)) {
79                                 thenFlowInfo =
80                                         thenStatement.analyseCode(currentScope, flowContext, thenFlowInfo);
81                         }
82                 }
83                 // code gen: optimizing the jump around the ELSE part
84                 this.thenExit =  !thenFlowInfo.isReachable();
85
86                 // process the ELSE part
87                 FlowInfo elseFlowInfo = flowInfo.initsWhenFalse().copy();
88                 if (isConditionOptimizedTrue) {
89                         elseFlowInfo.setReachMode(FlowInfo.UNREACHABLE); 
90                 }
91                 if (this.elseStatement != null) {
92                     // signal else clause unnecessarily nested, tolerate else-if code pattern
93                     if (thenFlowInfo == FlowInfo.DEAD_END 
94                             && (this.bits & IsElseIfStatement) == 0     // else of an else-if
95                             && !(this.elseStatement instanceof IfStatement)) {
96                         currentScope.problemReporter().unnecessaryElse(this.elseStatement);
97                     }
98                         // Save info for code gen
99                         elseInitStateIndex =
100                                 currentScope.methodScope().recordInitializationStates(elseFlowInfo);
101                         if (!elseStatement.complainIfUnreachable(elseFlowInfo, currentScope, false)) {
102                                 elseFlowInfo =
103                                         elseStatement.analyseCode(currentScope, flowContext, elseFlowInfo);
104                         }
105                 }
106
107                 // merge THEN & ELSE initializations
108                 FlowInfo mergedInfo = FlowInfo.mergedOptimizedBranches(
109                                 thenFlowInfo, 
110                                 isConditionOptimizedTrue, 
111                                 elseFlowInfo, 
112                                 isConditionOptimizedFalse,
113                                 true /*if(true){ return; }  fake-reachable(); */);
114                 mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo);
115                 return mergedInfo;
116         }
117
118         /**
119          * If code generation
120          *
121          * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
122          * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
123          */
124         public void generateCode(BlockScope currentScope, CodeStream codeStream) {
125
126                 if ((this.bits & IsReachableMASK) == 0) {
127                         return;
128                 }
129                 int pc = codeStream.position;
130                 Label endifLabel = new Label(codeStream);
131
132                 // optimizing the then/else part code gen
133                 Constant cst;
134                 boolean hasThenPart = 
135                         !(((cst = this.condition.optimizedBooleanConstant()) != NotAConstant
136                                         && cst.booleanValue() == false)
137                                 || this.thenStatement == null
138                                 || this.thenStatement.isEmptyBlock());
139                 boolean hasElsePart =
140                         !((cst != NotAConstant && cst.booleanValue() == true)
141                                 || this.elseStatement == null
142                                 || this.elseStatement.isEmptyBlock());
143
144                 if (hasThenPart) {
145                         Label falseLabel;
146                         // generate boolean condition
147                         this.condition.generateOptimizedBoolean(
148                                 currentScope,
149                                 codeStream,
150                                 null,
151                                 (falseLabel = new Label(codeStream)),
152                                 true);
153                         // May loose some local variable initializations : affecting the local variable attributes
154                         if (thenInitStateIndex != -1) {
155                                 codeStream.removeNotDefinitelyAssignedVariables(
156                                         currentScope,
157                                         thenInitStateIndex);
158                                 codeStream.addDefinitelyAssignedVariables(currentScope, thenInitStateIndex);
159                         }
160                         // generate then statement
161                         this.thenStatement.generateCode(currentScope, codeStream);
162                         // jump around the else statement
163                         if (hasElsePart && !thenExit) {
164                                 this.thenStatement.branchChainTo(endifLabel);
165                                 int position = codeStream.position;
166                                 codeStream.goto_(endifLabel);
167                                 codeStream.updateLastRecordedEndPC(position);
168                                 //goto is tagged as part of the thenAction block
169                         }
170                         falseLabel.place();
171                 } else {
172                         if (hasElsePart) {
173                                 // generate boolean condition
174                                 this.condition.generateOptimizedBoolean(
175                                         currentScope,
176                                         codeStream,
177                                         endifLabel,
178                                         null,
179                                         true);
180                         } else {
181                                 // generate condition side-effects
182                                 this.condition.generateCode(currentScope, codeStream, false);
183                                 codeStream.recordPositionsFrom(pc, this.sourceStart);
184                         }
185                 }
186                 // generate else statement
187                 if (hasElsePart) {
188                         // May loose some local variable initializations : affecting the local variable attributes
189                         if (elseInitStateIndex != -1) {
190                                 codeStream.removeNotDefinitelyAssignedVariables(
191                                         currentScope,
192                                         elseInitStateIndex);
193                                 codeStream.addDefinitelyAssignedVariables(currentScope, elseInitStateIndex);
194                         }
195                         this.elseStatement.generateCode(currentScope, codeStream);
196                 }
197                 endifLabel.place();
198                 // May loose some local variable initializations : affecting the local variable attributes
199                 if (mergedInitStateIndex != -1) {
200                         codeStream.removeNotDefinitelyAssignedVariables(
201                                 currentScope,
202                                 mergedInitStateIndex);
203                 }
204                 codeStream.recordPositionsFrom(pc, this.sourceStart);
205         }
206
207         public StringBuffer printStatement(int indent, StringBuffer output) {
208
209                 printIndent(indent, output).append("if ("); //$NON-NLS-1$
210                 condition.printExpression(0, output).append(")\n");     //$NON-NLS-1$ 
211                 thenStatement.printStatement(indent + 2, output);
212                 if (elseStatement != null) {
213                         output.append('\n');
214                         printIndent(indent, output);
215                         output.append("else\n"); //$NON-NLS-1$
216                         elseStatement.printStatement(indent + 2, output);
217                 }
218                 return output;
219         }
220
221         public void resolve(BlockScope scope) {
222
223                 TypeBinding type = condition.resolveTypeExpecting(scope, BooleanBinding);
224                 condition.implicitWidening(type, type);
225                 if (thenStatement != null)
226                         thenStatement.resolve(scope);
227                 if (elseStatement != null)
228                         elseStatement.resolve(scope);
229         }
230
231         public void traverse(
232                 ASTVisitor visitor,
233                 BlockScope blockScope) {
234
235                 if (visitor.visit(this, blockScope)) {
236                         condition.traverse(visitor, blockScope);
237                         if (thenStatement != null)
238                                 thenStatement.traverse(visitor, blockScope);
239                         if (elseStatement != null)
240                                 elseStatement.traverse(visitor, blockScope);
241                 }
242                 visitor.endVisit(this, blockScope);
243         }
244 }