added -J option to preserve unmodified files in preexisting jarfile
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / ast / DoStatement.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 DoStatement extends Statement {
20
21         public Expression condition;
22         public Statement action;
23
24         private Label breakLabel, continueLabel;
25
26         // for local variables table attributes
27         int mergedInitStateIndex = -1;
28
29         public DoStatement(Expression condition, Statement action, int s, int e) {
30
31                 this.sourceStart = s;
32                 this.sourceEnd = e;
33                 this.condition = condition;
34                 this.action = action;
35                 // remember useful empty statement
36                 if (action instanceof EmptyStatement) action.bits |= IsUsefulEmptyStatementMASK;
37         }
38
39         public FlowInfo analyseCode(
40                 BlockScope currentScope,
41                 FlowContext flowContext,
42                 FlowInfo flowInfo) {
43
44                 breakLabel = new Label();
45                 continueLabel = new Label();
46                 LoopingFlowContext loopingContext =
47                         new LoopingFlowContext(
48                                 flowContext,
49                                 this,
50                                 breakLabel,
51                                 continueLabel,
52                                 currentScope);
53
54                 Constant cst = condition.constant;
55                 boolean isConditionTrue = cst != NotAConstant && cst.booleanValue() == true;
56                 cst = condition.optimizedBooleanConstant();
57                 boolean isConditionOptimizedTrue = cst != NotAConstant && cst.booleanValue() == true;
58                 boolean isConditionOptimizedFalse = cst != NotAConstant && cst.booleanValue() == false;
59
60                 int previousMode = flowInfo.reachMode();
61                                 
62                 FlowInfo actionInfo = flowInfo.copy().unconditionalInits().discardNullRelatedInitializations();
63                 if ((action != null) && !action.isEmptyBlock()) {
64                         actionInfo = action.analyseCode(currentScope, loopingContext, actionInfo);
65
66                         // code generation can be optimized when no need to continue in the loop
67                         if (!actionInfo.isReachable() && !loopingContext.initsOnContinue.isReachable()) {
68                                 continueLabel = null;
69                         }
70                 }
71                 /* Reset reach mode, to address following scenario.
72                  *   final blank;
73                  *   do { if (true) break; else blank = 0; } while(false);
74                  *   blank = 1; // may be initialized already 
75                  */
76                 actionInfo.setReachMode(previousMode);
77                 
78                 actionInfo =
79                         condition.analyseCode(
80                                 currentScope,
81                                 loopingContext,
82                                 (action == null
83                                         ? actionInfo
84                                         : (actionInfo.mergedWith(loopingContext.initsOnContinue))));
85                 if (!isConditionOptimizedFalse && continueLabel != null) {
86                         loopingContext.complainOnDeferredChecks(currentScope, actionInfo);
87                 }
88
89                 // end of loop
90                 FlowInfo mergedInfo = FlowInfo.mergedOptimizedBranches(
91                                 loopingContext.initsOnBreak, 
92                                 isConditionOptimizedTrue, 
93                                 actionInfo.initsWhenFalse().addInitializationsFrom(flowInfo), // recover null inits from before condition analysis
94                                 false, // never consider opt false case for DO loop, since break can always occur (47776)
95                                 !isConditionTrue /*do{}while(true); unreachable(); */);
96                 mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo);
97                 return mergedInfo;
98         }
99
100         /**
101          * Do statement code generation
102          *
103          */
104         public void generateCode(BlockScope currentScope, CodeStream codeStream) {
105
106                 if ((bits & IsReachableMASK) == 0) {
107                         return;
108                 }
109                 int pc = codeStream.position;
110
111                 // labels management
112                 Label actionLabel = new Label(codeStream);
113                 actionLabel.place();
114                 breakLabel.initialize(codeStream);
115                 if (continueLabel != null) {
116                         continueLabel.initialize(codeStream);
117                 }
118
119                 // generate action
120                 if (action != null) {
121                         action.generateCode(currentScope, codeStream);
122                 }
123                 // generate condition
124                 if (continueLabel != null) {
125                         continueLabel.place();
126                         condition.generateOptimizedBoolean(
127                                 currentScope,
128                                 codeStream,
129                                 actionLabel,
130                                 null,
131                                 true);
132                 }
133                 breakLabel.place();
134
135                 // May loose some local variable initializations : affecting the local variable attributes
136                 if (mergedInitStateIndex != -1) {
137                         codeStream.removeNotDefinitelyAssignedVariables(currentScope, mergedInitStateIndex);
138                         codeStream.addDefinitelyAssignedVariables(currentScope, mergedInitStateIndex);
139                 }
140                 codeStream.recordPositionsFrom(pc, this.sourceStart);
141
142         }
143
144         public StringBuffer printStatement(int indent, StringBuffer output) {
145
146                 printIndent(indent, output).append("do"); //$NON-NLS-1$
147                 if (action == null)
148                         output.append(" ;\n"); //$NON-NLS-1$
149                 else {
150                         output.append('\n');
151                         action.printStatement(indent + 1, output).append('\n');
152                 }
153                 output.append("while ("); //$NON-NLS-1$
154                 return condition.printExpression(0, output).append(");"); //$NON-NLS-1$
155         }
156         public void resolve(BlockScope scope) {
157
158                 TypeBinding type = condition.resolveTypeExpecting(scope, BooleanBinding);
159                 condition.computeConversion(scope, type, type);
160                 if (action != null)
161                         action.resolve(scope);
162         }
163
164         public void traverse(ASTVisitor visitor, BlockScope scope) {
165
166                 if (visitor.visit(this, scope)) {
167                         if (action != null) {
168                                 action.traverse(visitor, scope);
169                         }
170                         condition.traverse(visitor, scope);
171                 }
172                 visitor.endVisit(this, scope);
173         }
174 }