001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.compiler.ast;
011:
012: import org.eclipse.jdt.internal.compiler.ASTVisitor;
013: import org.eclipse.jdt.internal.compiler.impl.*;
014: import org.eclipse.jdt.internal.compiler.codegen.*;
015: import org.eclipse.jdt.internal.compiler.flow.*;
016: import org.eclipse.jdt.internal.compiler.lookup.*;
017:
018: public class IfStatement extends Statement {
019:
020: //this class represents the case of only one statement in
021: //either else and/or then branches.
022:
023: public Expression condition;
024: public Statement thenStatement;
025: public Statement elseStatement;
026:
027: // for local variables table attributes
028: int thenInitStateIndex = -1;
029: int elseInitStateIndex = -1;
030: int mergedInitStateIndex = -1;
031:
032: public IfStatement(Expression condition, Statement thenStatement,
033: int sourceStart, int sourceEnd) {
034:
035: this .condition = condition;
036: this .thenStatement = thenStatement;
037: // remember useful empty statement
038: if (thenStatement instanceof EmptyStatement)
039: thenStatement.bits |= IsUsefulEmptyStatement;
040: this .sourceStart = sourceStart;
041: this .sourceEnd = sourceEnd;
042: }
043:
044: public IfStatement(Expression condition, Statement thenStatement,
045: Statement elseStatement, int sourceStart, int sourceEnd) {
046:
047: this .condition = condition;
048: this .thenStatement = thenStatement;
049: // remember useful empty statement
050: if (thenStatement instanceof EmptyStatement)
051: thenStatement.bits |= IsUsefulEmptyStatement;
052: this .elseStatement = elseStatement;
053: if (elseStatement instanceof IfStatement)
054: elseStatement.bits |= IsElseIfStatement;
055: if (elseStatement instanceof EmptyStatement)
056: elseStatement.bits |= IsUsefulEmptyStatement;
057: this .sourceStart = sourceStart;
058: this .sourceEnd = sourceEnd;
059: }
060:
061: public FlowInfo analyseCode(BlockScope currentScope,
062: FlowContext flowContext, FlowInfo flowInfo) {
063:
064: // process the condition
065: FlowInfo conditionFlowInfo = condition.analyseCode(
066: currentScope, flowContext, flowInfo);
067:
068: Constant cst = this .condition.optimizedBooleanConstant();
069: boolean isConditionOptimizedTrue = cst != Constant.NotAConstant
070: && cst.booleanValue() == true;
071: boolean isConditionOptimizedFalse = cst != Constant.NotAConstant
072: && cst.booleanValue() == false;
073:
074: // process the THEN part
075: FlowInfo thenFlowInfo = conditionFlowInfo.safeInitsWhenTrue();
076: if (isConditionOptimizedFalse) {
077: thenFlowInfo.setReachMode(FlowInfo.UNREACHABLE);
078: }
079: FlowInfo elseFlowInfo = conditionFlowInfo.initsWhenFalse();
080: if (isConditionOptimizedTrue) {
081: elseFlowInfo.setReachMode(FlowInfo.UNREACHABLE);
082: }
083: if (this .thenStatement != null) {
084: // Save info for code gen
085: thenInitStateIndex = currentScope.methodScope()
086: .recordInitializationStates(thenFlowInfo);
087: if (!thenStatement.complainIfUnreachable(thenFlowInfo,
088: currentScope, false)) {
089: thenFlowInfo = thenStatement.analyseCode(currentScope,
090: flowContext, thenFlowInfo);
091: }
092: }
093: // code gen: optimizing the jump around the ELSE part
094: if ((thenFlowInfo.tagBits & FlowInfo.UNREACHABLE) != 0) {
095: this .bits |= ASTNode.ThenExit;
096: }
097:
098: // process the ELSE part
099: if (this .elseStatement != null) {
100: // signal else clause unnecessarily nested, tolerate else-if code pattern
101: if (thenFlowInfo == FlowInfo.DEAD_END
102: && (this .bits & IsElseIfStatement) == 0 // else of an else-if
103: && !(this .elseStatement instanceof IfStatement)) {
104: currentScope.problemReporter().unnecessaryElse(
105: this .elseStatement);
106: }
107: // Save info for code gen
108: elseInitStateIndex = currentScope.methodScope()
109: .recordInitializationStates(elseFlowInfo);
110: if (!elseStatement.complainIfUnreachable(elseFlowInfo,
111: currentScope, false)) {
112: elseFlowInfo = elseStatement.analyseCode(currentScope,
113: flowContext, elseFlowInfo);
114: }
115: }
116:
117: // merge THEN & ELSE initializations
118: FlowInfo mergedInfo = FlowInfo
119: .mergedOptimizedBranches(thenFlowInfo,
120: isConditionOptimizedTrue, elseFlowInfo,
121: isConditionOptimizedFalse, true /*if(true){ return; } fake-reachable(); */);
122: mergedInitStateIndex = currentScope.methodScope()
123: .recordInitializationStates(mergedInfo);
124: return mergedInfo;
125: }
126:
127: /**
128: * If code generation
129: *
130: * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
131: * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
132: */
133: public void generateCode(BlockScope currentScope,
134: CodeStream codeStream) {
135:
136: if ((this .bits & IsReachable) == 0) {
137: return;
138: }
139: int pc = codeStream.position;
140: BranchLabel endifLabel = new BranchLabel(codeStream);
141:
142: // optimizing the then/else part code gen
143: Constant cst;
144: boolean hasThenPart = !(((cst = this .condition
145: .optimizedBooleanConstant()) != Constant.NotAConstant && cst
146: .booleanValue() == false)
147: || this .thenStatement == null || this .thenStatement
148: .isEmptyBlock());
149: boolean hasElsePart = !((cst != Constant.NotAConstant && cst
150: .booleanValue() == true)
151: || this .elseStatement == null || this .elseStatement
152: .isEmptyBlock());
153: if (hasThenPart) {
154: BranchLabel falseLabel = null;
155: // generate boolean condition
156: this .condition
157: .generateOptimizedBoolean(
158: currentScope,
159: codeStream,
160: null,
161: hasElsePart ? (falseLabel = new BranchLabel(
162: codeStream))
163: : endifLabel, true/*cst == Constant.NotAConstant*/);
164: // May loose some local variable initializations : affecting the local variable attributes
165: if (thenInitStateIndex != -1) {
166: codeStream.removeNotDefinitelyAssignedVariables(
167: currentScope, thenInitStateIndex);
168: codeStream.addDefinitelyAssignedVariables(currentScope,
169: thenInitStateIndex);
170: }
171: // generate then statement
172: this .thenStatement.generateCode(currentScope, codeStream);
173: // jump around the else statement
174: if (hasElsePart) {
175: if ((this .bits & ASTNode.ThenExit) == 0) {
176: this .thenStatement.branchChainTo(endifLabel);
177: int position = codeStream.position;
178: codeStream.goto_(endifLabel);
179: //goto is tagged as part of the thenAction block
180: codeStream
181: .updateLastRecordedEndPC(
182: (this .thenStatement instanceof Block) ? ((Block) this .thenStatement).scope
183: : currentScope, position);
184: // generate else statement
185: }
186: // May loose some local variable initializations : affecting the local variable attributes
187: if (elseInitStateIndex != -1) {
188: codeStream.removeNotDefinitelyAssignedVariables(
189: currentScope, elseInitStateIndex);
190: codeStream.addDefinitelyAssignedVariables(
191: currentScope, elseInitStateIndex);
192: }
193: if (falseLabel != null)
194: falseLabel.place();
195: this .elseStatement.generateCode(currentScope,
196: codeStream);
197: }
198: } else if (hasElsePart) {
199: // generate boolean condition
200: this .condition
201: .generateOptimizedBoolean(currentScope, codeStream,
202: endifLabel, null, true/*cst == Constant.NotAConstant*/);
203: // generate else statement
204: // May loose some local variable initializations : affecting the local variable attributes
205: if (elseInitStateIndex != -1) {
206: codeStream.removeNotDefinitelyAssignedVariables(
207: currentScope, elseInitStateIndex);
208: codeStream.addDefinitelyAssignedVariables(currentScope,
209: elseInitStateIndex);
210: }
211: this .elseStatement.generateCode(currentScope, codeStream);
212: } else {
213: // generate condition side-effects
214: this .condition
215: .generateCode(currentScope, codeStream, false);
216: codeStream.recordPositionsFrom(pc, this .sourceStart);
217: }
218: // May loose some local variable initializations : affecting the local variable attributes
219: if (mergedInitStateIndex != -1) {
220: codeStream.removeNotDefinitelyAssignedVariables(
221: currentScope, mergedInitStateIndex);
222: codeStream.addDefinitelyAssignedVariables(currentScope,
223: mergedInitStateIndex);
224: }
225: endifLabel.place();
226: codeStream.recordPositionsFrom(pc, this .sourceStart);
227: }
228:
229: public StringBuffer printStatement(int indent, StringBuffer output) {
230:
231: printIndent(indent, output).append("if ("); //$NON-NLS-1$
232: condition.printExpression(0, output).append(")\n"); //$NON-NLS-1$
233: thenStatement.printStatement(indent + 2, output);
234: if (elseStatement != null) {
235: output.append('\n');
236: printIndent(indent, output);
237: output.append("else\n"); //$NON-NLS-1$
238: elseStatement.printStatement(indent + 2, output);
239: }
240: return output;
241: }
242:
243: public void resolve(BlockScope scope) {
244:
245: TypeBinding type = condition.resolveTypeExpecting(scope,
246: TypeBinding.BOOLEAN);
247: condition.computeConversion(scope, type, type);
248: if (thenStatement != null)
249: thenStatement.resolve(scope);
250: if (elseStatement != null)
251: elseStatement.resolve(scope);
252: }
253:
254: public void traverse(ASTVisitor visitor, BlockScope blockScope) {
255:
256: if (visitor.visit(this, blockScope)) {
257: condition.traverse(visitor, blockScope);
258: if (thenStatement != null)
259: thenStatement.traverse(visitor, blockScope);
260: if (elseStatement != null)
261: elseStatement.traverse(visitor, blockScope);
262: }
263: visitor.endVisit(this, blockScope);
264: }
265: }
|