KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > compiler > ast > ReturnStatement


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-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 ReturnStatement extends Statement {
21         
22     public Expression expression;
23     public SubRoutineStatement[] subroutines;
24     public LocalVariableBinding saveValueVariable;
25     public int initStateIndex = -1;
26     
27 public ReturnStatement(Expression expression, int sourceStart, int sourceEnd) {
28     this.sourceStart = sourceStart;
29     this.sourceEnd = sourceEnd;
30     this.expression = expression ;
31 }
32
33 public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { // here requires to generate a sequence of finally blocks invocations depending corresponding
34
// to each of the traversed try statements, so that execution will terminate properly.
35

36     // lookup the label, this should answer the returnContext
37

38     if (this.expression != null) {
39         flowInfo = this.expression.analyseCode(currentScope, flowContext, flowInfo);
40     }
41     this.initStateIndex =
42         currentScope.methodScope().recordInitializationStates(flowInfo);
43     // compute the return sequence (running the finally blocks)
44
FlowContext traversedContext = flowContext;
45     int subCount = 0;
46     boolean saveValueNeeded = false;
47     boolean hasValueToSave = this.expression != null
48                         && this.expression.constant == Constant.NotAConstant
49                         && !(this.expression instanceof NullLiteral);
50     do {
51         SubRoutineStatement sub;
52         if ((sub = traversedContext.subroutine()) != null) {
53             if (this.subroutines == null){
54                 this.subroutines = new SubRoutineStatement[5];
55             }
56             if (subCount == this.subroutines.length) {
57                 System.arraycopy(this.subroutines, 0, (this.subroutines = new SubRoutineStatement[subCount*2]), 0, subCount); // grow
58
}
59             this.subroutines[subCount++] = sub;
60             if (sub.isSubRoutineEscaping()) {
61                 saveValueNeeded = false;
62                 this.bits |= ASTNode.IsAnySubRoutineEscaping;
63                 break;
64             }
65         }
66         traversedContext.recordReturnFrom(flowInfo.unconditionalInits());
67
68         if (traversedContext instanceof InsideSubRoutineFlowContext) {
69             ASTNode node = traversedContext.associatedNode;
70             if (node instanceof SynchronizedStatement) {
71                 this.bits |= ASTNode.IsSynchronized;
72             } else if (node instanceof TryStatement) {
73                 TryStatement tryStatement = (TryStatement) node;
74                 flowInfo.addInitializationsFrom(tryStatement.subRoutineInits); // collect inits
75
if (hasValueToSave) {
76                     if (this.saveValueVariable == null){ // closest subroutine secret variable is used
77
prepareSaveValueLocation(tryStatement);
78                     }
79                     saveValueNeeded = true;
80                 }
81             }
82         } else if (traversedContext instanceof InitializationFlowContext) {
83                 currentScope.problemReporter().cannotReturnInInitializer(this);
84                 return FlowInfo.DEAD_END;
85         }
86     } while ((traversedContext = traversedContext.parent) != null);
87     
88     // resize subroutines
89
if ((this.subroutines != null) && (subCount != this.subroutines.length)) {
90         System.arraycopy(this.subroutines, 0, (this.subroutines = new SubRoutineStatement[subCount]), 0, subCount);
91     }
92
93     // secret local variable for return value (note that this can only occur in a real method)
94
if (saveValueNeeded) {
95         if (this.saveValueVariable != null) {
96             this.saveValueVariable.useFlag = LocalVariableBinding.USED;
97         }
98     } else {
99         this.saveValueVariable = null;
100         if (((this.bits & ASTNode.IsSynchronized) == 0) && this.expression != null && this.expression.resolvedType == TypeBinding.BOOLEAN) {
101             this.expression.bits |= ASTNode.IsReturnedValue;
102         }
103     }
104     return FlowInfo.DEAD_END;
105 }
106  
107 /**
108  * Retrun statement code generation
109  *
110  * generate the finallyInvocationSequence.
111  *
112  * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
113  * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
114  */

115 public void generateCode(BlockScope currentScope, CodeStream codeStream) {
116     if ((this.bits & ASTNode.IsReachable) == 0) {
117         return;
118     }
119     int pc = codeStream.position;
120     boolean alreadyGeneratedExpression = false;
121     // generate the expression
122
if ((this.expression != null) && (this.expression.constant == Constant.NotAConstant) && !(this.expression instanceof NullLiteral)) {
123         alreadyGeneratedExpression = true;
124         this.expression.generateCode(currentScope, codeStream, needValue()); // no value needed if non-returning subroutine
125
generateStoreSaveValueIfNecessary(codeStream);
126     }
127     
128     // generation of code responsible for invoking the finally blocks in sequence
129
if (this.subroutines != null) {
130         Object JavaDoc reusableJSRTarget = this.expression == null ? (Object JavaDoc)TypeBinding.VOID : this.expression.reusableJSRTarget();
131         for (int i = 0, max = this.subroutines.length; i < max; i++) {
132             SubRoutineStatement sub = this.subroutines[i];
133             boolean didEscape = sub.generateSubRoutineInvocation(currentScope, codeStream, reusableJSRTarget, this.initStateIndex, this.saveValueVariable);
134             if (didEscape) {
135                     codeStream.recordPositionsFrom(pc, this.sourceStart);
136                     SubRoutineStatement.reenterAllExceptionHandlers(this.subroutines, i, codeStream);
137                     return;
138             }
139         }
140     }
141     if (this.saveValueVariable != null) {
142         codeStream.addVariable(this.saveValueVariable);
143         codeStream.load(this.saveValueVariable);
144     }
145     if (this.expression != null && !alreadyGeneratedExpression) {
146         this.expression.generateCode(currentScope, codeStream, true);
147         generateStoreSaveValueIfNecessary(codeStream);
148     }
149     // output the suitable return bytecode or wrap the value inside a descriptor for doits
150
this.generateReturnBytecode(codeStream);
151     if (this.saveValueVariable != null) {
152         codeStream.removeVariable(this.saveValueVariable);
153     }
154     if (this.initStateIndex != -1) {
155         codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.initStateIndex);
156         codeStream.addDefinitelyAssignedVariables(currentScope, this.initStateIndex);
157     }
158     codeStream.recordPositionsFrom(pc, this.sourceStart);
159     SubRoutineStatement.reenterAllExceptionHandlers(this.subroutines, -1, codeStream);
160 }
161
162 /**
163  * Dump the suitable return bytecode for a return statement
164  *
165  */

166 public void generateReturnBytecode(CodeStream codeStream) {
167     codeStream.generateReturnBytecode(this.expression);
168 }
169
170 public void generateStoreSaveValueIfNecessary(CodeStream codeStream){
171     if (this.saveValueVariable != null) {
172         codeStream.store(this.saveValueVariable, false);
173     }
174 }
175
176 public boolean needValue() {
177     return this.saveValueVariable != null
178                     || (this.bits & ASTNode.IsSynchronized) != 0
179                     || ((this.bits & ASTNode.IsAnySubRoutineEscaping) == 0);
180 }
181
182 public void prepareSaveValueLocation(TryStatement targetTryStatement){
183     this.saveValueVariable = targetTryStatement.secretReturnValue;
184 }
185
186 public StringBuffer JavaDoc printStatement(int tab, StringBuffer JavaDoc output){
187     printIndent(tab, output).append("return "); //$NON-NLS-1$
188
if (this.expression != null )
189         this.expression.printExpression(0, output) ;
190     return output.append(';');
191 }
192
193 public void resolve(BlockScope scope) {
194     MethodScope methodScope = scope.methodScope();
195     MethodBinding methodBinding;
196     TypeBinding methodType =
197         (methodScope.referenceContext instanceof AbstractMethodDeclaration)
198             ? ((methodBinding = ((AbstractMethodDeclaration) methodScope.referenceContext).binding) == null
199                 ? null
200                 : methodBinding.returnType)
201             : TypeBinding.VOID;
202     TypeBinding expressionType;
203     if (methodType == TypeBinding.VOID) {
204         // the expression should be null
205
if (this.expression == null)
206             return;
207         if ((expressionType = this.expression.resolveType(scope)) != null)
208             scope.problemReporter().attemptToReturnNonVoidExpression(this, expressionType);
209         return;
210     }
211     if (this.expression == null) {
212         if (methodType != null) scope.problemReporter().shouldReturn(methodType, this);
213         return;
214     }
215     this.expression.setExpectedType(methodType); // needed in case of generic method invocation
216
if ((expressionType = this.expression.resolveType(scope)) == null) return;
217     if (expressionType == TypeBinding.VOID) {
218         scope.problemReporter().attemptToReturnVoidValue(this);
219         return;
220     }
221     if (methodType == null)
222         return;
223
224     if (methodType != expressionType) // must call before computeConversion() and typeMismatchError()
225
scope.compilationUnitScope().recordTypeConversion(methodType, expressionType);
226     if (this.expression.isConstantValueOfTypeAssignableToType(expressionType, methodType)
227             || expressionType.isCompatibleWith(methodType)) {
228
229         this.expression.computeConversion(scope, methodType, expressionType);
230         if (expressionType.needsUncheckedConversion(methodType)) {
231             scope.problemReporter().unsafeTypeConversion(this.expression, expressionType, methodType);
232         }
233         if (this.expression instanceof CastExpression
234                 && (this.expression.bits & (ASTNode.UnnecessaryCast|ASTNode.DisableUnnecessaryCastCheck)) == 0) {
235             CastExpression.checkNeedForAssignedCast(scope, methodType, (CastExpression) this.expression);
236         }
237         return;
238     } else if (scope.isBoxingCompatibleWith(expressionType, methodType)
239                         || (expressionType.isBaseType() // narrowing then boxing ?
240
&& scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5 // autoboxing
241
&& !methodType.isBaseType()
242                                 && this.expression.isConstantValueOfTypeAssignableToType(expressionType, scope.environment().computeBoxingType(methodType)))) {
243         this.expression.computeConversion(scope, methodType, expressionType);
244         if (this.expression instanceof CastExpression
245                 && (this.expression.bits & (ASTNode.UnnecessaryCast|ASTNode.DisableUnnecessaryCastCheck)) == 0) {
246             CastExpression.checkNeedForAssignedCast(scope, methodType, (CastExpression) this.expression);
247         } return;
248     }
249     scope.problemReporter().typeMismatchError(expressionType, methodType, this.expression);
250 }
251
252 public void traverse(ASTVisitor visitor, BlockScope scope) {
253     if (visitor.visit(this, scope)) {
254         if (this.expression != null)
255             this.expression.traverse(visitor, scope);
256     }
257     visitor.endVisit(this, scope);
258 }
259 }
260
Popular Tags