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 IfStatement(Expression condition, Statement thenStatement, int sourceStart, int sourceEnd)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 IfStatement(Expression condition, Statement thenStatement, Statement elseStatement, int sourceStart, int sourceEnd)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 analyseCode( BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo)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 */ generateCode(BlockScope currentScope, CodeStream codeStream)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(currentScope, thenInitStateIndex); 156 codeStream.addDefinitelyAssignedVariables(currentScope, thenInitStateIndex); 157 } 158 // generate then statement 159 this.thenStatement.generateCode(currentScope, codeStream); 160 // jump around the else statement 161 if (hasElsePart && !thenExit) { 162 this.thenStatement.branchChainTo(endifLabel); 163 int position = codeStream.position; 164 codeStream.goto_(endifLabel); 165 codeStream.updateLastRecordedEndPC(position); 166 //goto is tagged as part of the thenAction block 167 } 168 falseLabel.place(); 169 } else { 170 if (hasElsePart) { 171 // generate boolean condition 172 this.condition.generateOptimizedBoolean( 173 currentScope, 174 codeStream, 175 endifLabel, 176 null, 177 true); 178 } else { 179 // generate condition side-effects 180 this.condition.generateCode(currentScope, codeStream, false); 181 codeStream.recordPositionsFrom(pc, this.sourceStart); 182 } 183 } 184 // generate else statement 185 if (hasElsePart) { 186 // May loose some local variable initializations : affecting the local variable attributes 187 if (elseInitStateIndex != -1) { 188 codeStream.removeNotDefinitelyAssignedVariables( 189 currentScope, 190 elseInitStateIndex); 191 codeStream.addDefinitelyAssignedVariables(currentScope, elseInitStateIndex); 192 } 193 this.elseStatement.generateCode(currentScope, codeStream); 194 } 195 endifLabel.place(); 196 // May loose some local variable initializations : affecting the local variable attributes 197 if (mergedInitStateIndex != -1) { 198 codeStream.removeNotDefinitelyAssignedVariables( 199 currentScope, 200 mergedInitStateIndex); 201 } 202 codeStream.recordPositionsFrom(pc, this.sourceStart); 203 } 204 printStatement(int indent, StringBuffer output)205 public StringBuffer printStatement(int indent, StringBuffer output) { 206 207 printIndent(indent, output).append("if ("); //$NON-NLS-1$ 208 condition.printExpression(0, output).append(")\n"); //$NON-NLS-1$ 209 thenStatement.printStatement(indent + 2, output); 210 if (elseStatement != null) { 211 output.append('\n'); 212 printIndent(indent, output); 213 output.append("else\n"); //$NON-NLS-1$ 214 elseStatement.printStatement(indent + 2, output); 215 } 216 return output; 217 } 218 resolve(BlockScope scope)219 public void resolve(BlockScope scope) { 220 221 TypeBinding type = condition.resolveTypeExpecting(scope, BooleanBinding); 222 condition.computeConversion(scope, type, type); 223 if (thenStatement != null) 224 thenStatement.resolve(scope); 225 if (elseStatement != null) 226 elseStatement.resolve(scope); 227 } 228 traverse( ASTVisitor visitor, BlockScope blockScope)229 public void traverse( 230 ASTVisitor visitor, 231 BlockScope blockScope) { 232 233 if (visitor.visit(this, blockScope)) { 234 condition.traverse(visitor, blockScope); 235 if (thenStatement != null) 236 thenStatement.traverse(visitor, blockScope); 237 if (elseStatement != null) 238 elseStatement.traverse(visitor, blockScope); 239 } 240 visitor.endVisit(this, blockScope); 241 } 242 } 243