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