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.classfmt.ClassFileConstants; 15 import org.eclipse.jdt.internal.compiler.codegen.*; 16 import org.eclipse.jdt.internal.compiler.flow.*; 17 import org.eclipse.jdt.internal.compiler.impl.Constant; 18 import org.eclipse.jdt.internal.compiler.lookup.*; 19 20 public class ForStatement extends Statement { 21 22 public Statement[] initializations; 23 public Expression condition; 24 public Statement[] increments; 25 public Statement action; 26 27 //when there is no local declaration, there is no need of a new scope 28 //scope is positionned either to a new scope, or to the "upper"scope (see resolveType) 29 public boolean neededScope; 30 public BlockScope scope; 31 32 private Label breakLabel, continueLabel; 33 34 // for local variables table attributes 35 int preCondInitStateIndex = -1; 36 int condIfTrueInitStateIndex = -1; 37 int mergedInitStateIndex = -1; 38 ForStatement( Statement[] initializations, Expression condition, Statement[] increments, Statement action, boolean neededScope, int s, int e)39 public ForStatement( 40 Statement[] initializations, 41 Expression condition, 42 Statement[] increments, 43 Statement action, 44 boolean neededScope, 45 int s, 46 int e) { 47 48 this.sourceStart = s; 49 this.sourceEnd = e; 50 this.initializations = initializations; 51 this.condition = condition; 52 this.increments = increments; 53 this.action = action; 54 // remember useful empty statement 55 if (action instanceof EmptyStatement) action.bits |= IsUsefulEmptyStatementMASK; 56 this.neededScope = neededScope; 57 } 58 analyseCode( BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo)59 public FlowInfo analyseCode( 60 BlockScope currentScope, 61 FlowContext flowContext, 62 FlowInfo flowInfo) { 63 64 breakLabel = new Label(); 65 continueLabel = new Label(); 66 67 // process the initializations 68 if (initializations != null) { 69 for (int i = 0, count = initializations.length; i < count; i++) { 70 flowInfo = initializations[i].analyseCode(scope, flowContext, flowInfo); 71 } 72 } 73 preCondInitStateIndex = 74 currentScope.methodScope().recordInitializationStates(flowInfo); 75 76 Constant cst = this.condition == null ? null : this.condition.constant; 77 boolean isConditionTrue = cst == null || (cst != NotAConstant && cst.booleanValue() == true); 78 boolean isConditionFalse = cst != null && (cst != NotAConstant && cst.booleanValue() == false); 79 80 cst = this.condition == null ? null : this.condition.optimizedBooleanConstant(); 81 boolean isConditionOptimizedTrue = cst == null || (cst != NotAConstant && cst.booleanValue() == true); 82 boolean isConditionOptimizedFalse = cst != null && (cst != NotAConstant && cst.booleanValue() == false); 83 84 // process the condition 85 LoopingFlowContext condLoopContext = null; 86 if (condition != null) { 87 if (!isConditionTrue) { 88 flowInfo = 89 condition.analyseCode( 90 scope, 91 (condLoopContext = 92 new LoopingFlowContext(flowContext, this, null, null, scope)), 93 flowInfo); 94 } 95 } 96 97 // process the action 98 LoopingFlowContext loopingContext; 99 FlowInfo actionInfo; 100 if (action == null 101 || (action.isEmptyBlock() && currentScope.environment().options.complianceLevel <= ClassFileConstants.JDK1_3)) { 102 if (condLoopContext != null) 103 condLoopContext.complainOnFinalAssignmentsInLoop(scope, flowInfo); 104 if (isConditionTrue) { 105 return FlowInfo.DEAD_END; 106 } else { 107 if (isConditionFalse){ 108 continueLabel = null; // for(;false;p()); 109 } 110 actionInfo = flowInfo.initsWhenTrue().copy(); 111 loopingContext = 112 new LoopingFlowContext(flowContext, this, breakLabel, continueLabel, scope); 113 } 114 } else { 115 loopingContext = 116 new LoopingFlowContext(flowContext, this, breakLabel, continueLabel, scope); 117 FlowInfo initsWhenTrue = flowInfo.initsWhenTrue(); 118 condIfTrueInitStateIndex = 119 currentScope.methodScope().recordInitializationStates(initsWhenTrue); 120 121 if (isConditionFalse) { 122 actionInfo = FlowInfo.DEAD_END; 123 } else { 124 actionInfo = initsWhenTrue.copy(); 125 if (isConditionOptimizedFalse){ 126 actionInfo.setReachMode(FlowInfo.UNREACHABLE); 127 } 128 } 129 if (!this.action.complainIfUnreachable(actionInfo, scope, false)) { 130 actionInfo = action.analyseCode(scope, loopingContext, actionInfo); 131 } 132 133 // code generation can be optimized when no need to continue in the loop 134 if (!actionInfo.isReachable() && !loopingContext.initsOnContinue.isReachable()) { 135 continueLabel = null; 136 } else { 137 if (condLoopContext != null) 138 condLoopContext.complainOnFinalAssignmentsInLoop(scope, flowInfo); 139 actionInfo = actionInfo.mergedWith(loopingContext.initsOnContinue.unconditionalInits()); 140 loopingContext.complainOnFinalAssignmentsInLoop(scope, actionInfo); 141 } 142 } 143 // for increments 144 if ((continueLabel != null) && (increments != null)) { 145 LoopingFlowContext loopContext = 146 new LoopingFlowContext(flowContext, this, null, null, scope); 147 for (int i = 0, count = increments.length; i < count; i++) { 148 actionInfo = increments[i].analyseCode(scope, loopContext, actionInfo); 149 } 150 loopContext.complainOnFinalAssignmentsInLoop(scope, actionInfo); 151 } 152 153 //end of loop 154 FlowInfo mergedInfo = FlowInfo.mergedOptimizedBranches( 155 loopingContext.initsOnBreak, 156 isConditionOptimizedTrue, 157 flowInfo.initsWhenFalse(), 158 isConditionOptimizedFalse, 159 !isConditionTrue /*for(;;){}while(true); unreachable(); */); 160 mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo); 161 return mergedInfo; 162 } 163 164 /** 165 * For statement code generation 166 * 167 * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope 168 * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream 169 */ generateCode(BlockScope currentScope, CodeStream codeStream)170 public void generateCode(BlockScope currentScope, CodeStream codeStream) { 171 172 if ((bits & IsReachableMASK) == 0) { 173 return; 174 } 175 int pc = codeStream.position; 176 177 // generate the initializations 178 if (initializations != null) { 179 for (int i = 0, max = initializations.length; i < max; i++) { 180 initializations[i].generateCode(scope, codeStream); 181 } 182 } 183 184 // label management 185 Label actionLabel = new Label(codeStream); 186 Label conditionLabel = new Label(codeStream); 187 breakLabel.initialize(codeStream); 188 if (continueLabel != null) { 189 continueLabel.initialize(codeStream); 190 } 191 // jump over the actionBlock 192 if ((condition != null) 193 && (condition.constant == NotAConstant) 194 && !((action == null || action.isEmptyBlock()) && (increments == null))) { 195 int jumpPC = codeStream.position; 196 codeStream.goto_(conditionLabel); 197 codeStream.recordPositionsFrom(jumpPC, condition.sourceStart); 198 } 199 // generate the loop action 200 actionLabel.place(); 201 if (action != null) { 202 // Required to fix 1PR0XVS: LFRE:WINNT - Compiler: variable table for method appears incorrect 203 if (condIfTrueInitStateIndex != -1) { 204 // insert all locals initialized inside the condition into the action generated prior to the condition 205 codeStream.addDefinitelyAssignedVariables( 206 currentScope, 207 condIfTrueInitStateIndex); 208 } 209 action.generateCode(scope, codeStream); 210 } 211 // continuation point 212 if (continueLabel != null) { 213 continueLabel.place(); 214 // generate the increments for next iteration 215 if (increments != null) { 216 for (int i = 0, max = increments.length; i < max; i++) { 217 increments[i].generateCode(scope, codeStream); 218 } 219 } 220 } 221 222 // May loose some local variable initializations : affecting the local variable attributes 223 if (preCondInitStateIndex != -1) { 224 codeStream.removeNotDefinitelyAssignedVariables(currentScope, preCondInitStateIndex); 225 } 226 227 // generate the condition 228 conditionLabel.place(); 229 if ((condition != null) && (condition.constant == NotAConstant)) { 230 condition.generateOptimizedBoolean(scope, codeStream, actionLabel, null, true); 231 } else { 232 if (continueLabel != null) { 233 codeStream.goto_(actionLabel); 234 } 235 } 236 breakLabel.place(); 237 238 // May loose some local variable initializations : affecting the local variable attributes 239 if (neededScope) { 240 codeStream.exitUserScope(scope); 241 } 242 if (mergedInitStateIndex != -1) { 243 codeStream.removeNotDefinitelyAssignedVariables(currentScope, mergedInitStateIndex); 244 codeStream.addDefinitelyAssignedVariables(currentScope, mergedInitStateIndex); 245 } 246 codeStream.recordPositionsFrom(pc, this.sourceStart); 247 } 248 printStatement(int tab, StringBuffer output)249 public StringBuffer printStatement(int tab, StringBuffer output) { 250 251 printIndent(tab, output).append("for ("); //$NON-NLS-1$ 252 //inits 253 if (initializations != null) { 254 for (int i = 0; i < initializations.length; i++) { 255 //nice only with expressions 256 if (i > 0) output.append(", "); //$NON-NLS-1$ 257 initializations[i].print(0, output); 258 } 259 } 260 output.append("; "); //$NON-NLS-1$ 261 //cond 262 if (condition != null) condition.printExpression(0, output); 263 output.append("; "); //$NON-NLS-1$ 264 //updates 265 if (increments != null) { 266 for (int i = 0; i < increments.length; i++) { 267 if (i > 0) output.append(", "); //$NON-NLS-1$ 268 increments[i].print(0, output); 269 } 270 } 271 output.append(") "); //$NON-NLS-1$ 272 //block 273 if (action == null) 274 output.append(';'); 275 else { 276 output.append('\n'); 277 action.printStatement(tab + 1, output); //$NON-NLS-1$ 278 } 279 return output.append(';'); 280 } 281 resolve(BlockScope upperScope)282 public void resolve(BlockScope upperScope) { 283 284 // use the scope that will hold the init declarations 285 scope = neededScope ? new BlockScope(upperScope) : upperScope; 286 if (initializations != null) 287 for (int i = 0, length = initializations.length; i < length; i++) 288 initializations[i].resolve(scope); 289 if (condition != null) { 290 TypeBinding type = condition.resolveTypeExpecting(scope, BooleanBinding); 291 condition.computeConversion(scope, type, type); 292 } 293 if (increments != null) 294 for (int i = 0, length = increments.length; i < length; i++) 295 increments[i].resolve(scope); 296 if (action != null) 297 action.resolve(scope); 298 } 299 traverse( ASTVisitor visitor, BlockScope blockScope)300 public void traverse( 301 ASTVisitor visitor, 302 BlockScope blockScope) { 303 304 if (visitor.visit(this, blockScope)) { 305 if (initializations != null) { 306 int initializationsLength = initializations.length; 307 for (int i = 0; i < initializationsLength; i++) 308 initializations[i].traverse(visitor, scope); 309 } 310 311 if (condition != null) 312 condition.traverse(visitor, scope); 313 314 if (increments != null) { 315 int incrementsLength = increments.length; 316 for (int i = 0; i < incrementsLength; i++) 317 increments[i].traverse(visitor, scope); 318 } 319 320 if (action != null) 321 action.traverse(visitor, scope); 322 } 323 visitor.endVisit(this, blockScope); 324 } 325 } 326