removed Makefile; lifted repo/org.ibex.tool/src/ to src/
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / ast / ReturnStatement.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.codegen.*;
15 import org.eclipse.jdt.internal.compiler.flow.*;
16 import org.eclipse.jdt.internal.compiler.lookup.*;
17
18 public class ReturnStatement extends Statement {
19                 
20         public Expression expression;
21         public TypeBinding expressionType;
22         public boolean isSynchronized;
23         public SubRoutineStatement[] subroutines;
24         public boolean isAnySubRoutineEscaping = false;
25         public LocalVariableBinding saveValueVariable;
26         
27         public ReturnStatement(Expression expr, int s, int e ) {
28                 sourceStart = s;
29                 sourceEnd = e;
30                 expression = expr ;
31         }
32         public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {      // here requires to generate a sequence of finally blocks invocations depending corresponding
33                 // to each of the traversed try statements, so that execution will terminate properly.
34         
35                 // lookup the label, this should answer the returnContext
36         
37                 if (expression != null) {
38                         flowInfo = expression.analyseCode(currentScope, flowContext, flowInfo);
39                 }
40                 // compute the return sequence (running the finally blocks)
41                 FlowContext traversedContext = flowContext;
42                 int subIndex = 0, maxSub = 5;
43                 boolean saveValueNeeded = false;
44                 boolean hasValueToSave = expression != null && expression.constant == NotAConstant;
45                 do {
46                         SubRoutineStatement sub;
47                         if ((sub = traversedContext.subRoutine()) != null) {
48                                 if (this.subroutines == null){
49                                         this.subroutines = new SubRoutineStatement[maxSub];
50                                 }
51                                 if (subIndex == maxSub) {
52                                         System.arraycopy(this.subroutines, 0, (this.subroutines = new SubRoutineStatement[maxSub *= 2]), 0, subIndex); // grow
53                                 }
54                                 this.subroutines[subIndex++] = sub;
55                                 if (sub.isSubRoutineEscaping()) {
56                                         saveValueNeeded = false;
57                                         isAnySubRoutineEscaping = true;
58                                         break;
59                                 }
60                         }
61                         traversedContext.recordReturnFrom(flowInfo.unconditionalInits());
62         
63                         ASTNode node;
64                         if ((node = traversedContext.associatedNode) instanceof SynchronizedStatement) {
65                                 isSynchronized = true;
66         
67                         } else if (node instanceof TryStatement) {
68                                 TryStatement tryStatement = (TryStatement) node;
69                                 flowInfo.addInitializationsFrom(tryStatement.subRoutineInits); // collect inits
70                                 if (hasValueToSave) {
71                                         if (this.saveValueVariable == null){ // closest subroutine secret variable is used
72                                                 prepareSaveValueLocation(tryStatement);
73                                         }
74                                         saveValueNeeded = true;
75                                 }
76         
77                         } else if (traversedContext instanceof InitializationFlowContext) {
78                                         currentScope.problemReporter().cannotReturnInInitializer(this);
79                                         return FlowInfo.DEAD_END;
80                         }
81                 } while ((traversedContext = traversedContext.parent) != null);
82                 
83                 // resize subroutines
84                 if ((subroutines != null) && (subIndex != maxSub)) {
85                         System.arraycopy(subroutines, 0, (subroutines = new SubRoutineStatement[subIndex]), 0, subIndex);
86                 }
87         
88                 // secret local variable for return value (note that this can only occur in a real method)
89                 if (saveValueNeeded) {
90                         if (this.saveValueVariable != null) {
91                                 this.saveValueVariable.useFlag = LocalVariableBinding.USED;
92                         }
93                 } else {
94                         this.saveValueVariable = null;
95                         if ((!isSynchronized) && (expressionType == BooleanBinding)) {
96                                 this.expression.bits |= ValueForReturnMASK;
97                         }
98                 }
99                 return FlowInfo.DEAD_END;
100         }
101          
102         /**
103          * Retrun statement code generation
104          *
105          *   generate the finallyInvocationSequence.
106          *
107          * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
108          * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
109          */
110         public void generateCode(BlockScope currentScope, CodeStream codeStream) {
111                 if ((bits & IsReachableMASK) == 0) {
112                         return;
113                 }
114                 int pc = codeStream.position;
115                 // generate the expression
116                 if ((expression != null) && (expression.constant == NotAConstant)) {
117                         expression.generateCode(currentScope, codeStream, needValue()); // no value needed if non-returning subroutine
118                         generateStoreSaveValueIfNecessary(codeStream);
119                 }
120                 
121                 // generation of code responsible for invoking the finally blocks in sequence
122                 if (subroutines != null) {
123                         for (int i = 0, max = subroutines.length; i < max; i++) {
124                                 SubRoutineStatement sub = subroutines[i];
125                                 sub.generateSubRoutineInvocation(currentScope, codeStream);
126                                 if (sub.isSubRoutineEscaping()) {
127                                                 codeStream.recordPositionsFrom(pc, this.sourceStart);
128                                                 SubRoutineStatement.reenterExceptionHandlers(subroutines, i, codeStream);
129                                                 return;
130                                 }
131                                 sub.exitAnyExceptionHandler();
132                         }
133                 }
134                 if (saveValueVariable != null) codeStream.load(saveValueVariable);
135                 
136                 if ((expression != null) && (expression.constant != NotAConstant)) {
137                         codeStream.generateConstant(expression.constant, expression.implicitConversion);
138                         generateStoreSaveValueIfNecessary(codeStream);          
139                 }
140                 // output the suitable return bytecode or wrap the value inside a descriptor for doits
141                 this.generateReturnBytecode(codeStream);
142                 codeStream.recordPositionsFrom(pc, this.sourceStart);
143                 SubRoutineStatement.reenterExceptionHandlers(subroutines, -1, codeStream);
144         }
145         /**
146          * Dump the suitable return bytecode for a return statement
147          *
148          */
149         public void generateReturnBytecode(CodeStream codeStream) {
150         
151                 if (expression == null) {
152                         codeStream.return_();
153                 } else {
154                         switch (expression.implicitConversion >> 4) {
155                                 case T_boolean :
156                                 case T_int :
157                                         codeStream.ireturn();
158                                         break;
159                                 case T_float :
160                                         codeStream.freturn();
161                                         break;
162                                 case T_long :
163                                         codeStream.lreturn();
164                                         break;
165                                 case T_double :
166                                         codeStream.dreturn();
167                                         break;
168                                 default :
169                                         codeStream.areturn();
170                         }
171                 }
172         }
173         public void generateStoreSaveValueIfNecessary(CodeStream codeStream){
174                 if (saveValueVariable != null) codeStream.store(saveValueVariable, false);
175         }
176         public boolean needValue(){
177                 return (subroutines == null) || (saveValueVariable != null) || isSynchronized;
178         }
179         public void prepareSaveValueLocation(TryStatement targetTryStatement){
180                         
181                 this.saveValueVariable = targetTryStatement.secretReturnValue;
182         }
183         public StringBuffer printStatement(int tab, StringBuffer output){
184         
185                 printIndent(tab, output).append("return "); //$NON-NLS-1$
186                 if (expression != null )
187                         expression.printExpression(0, output) ;
188                 return output.append(';');
189         }
190         public void resolve(BlockScope scope) {
191                 MethodScope methodScope = scope.methodScope();
192                 MethodBinding methodBinding;
193                 TypeBinding methodType =
194                         (methodScope.referenceContext instanceof AbstractMethodDeclaration)
195                                 ? ((methodBinding = ((AbstractMethodDeclaration) methodScope.referenceContext).binding) == null 
196                                         ? null 
197                                         : methodBinding.returnType)
198                                 : VoidBinding;
199                 if (methodType == VoidBinding) {
200                         // the expression should be null
201                         if (expression == null)
202                                 return;
203                         if ((expressionType = expression.resolveType(scope)) != null)
204                                 scope.problemReporter().attemptToReturnNonVoidExpression(this, expressionType);
205                         return;
206                 }
207                 if (expression == null) {
208                         if (methodType != null) scope.problemReporter().shouldReturn(methodType, this);
209                         return;
210                 }
211                 if ((expressionType = expression.resolveType(scope)) == null)
212                         return;
213         
214                 if (methodType != null && expression.isConstantValueOfTypeAssignableToType(expressionType, methodType)) {
215                         // dealing with constant
216                         expression.implicitWidening(methodType, expressionType);
217                         return;
218                 }
219                 if (expressionType == VoidBinding) {
220                         scope.problemReporter().attemptToReturnVoidValue(this);
221                         return;
222                 }
223                 if (methodType != null && expressionType.isCompatibleWith(methodType)) {
224                         expression.implicitWidening(methodType, expressionType);
225                         return;
226                 }
227                 if (methodType != null){
228                         scope.problemReporter().typeMismatchErrorActualTypeExpectedType(expression, expressionType, methodType);
229                 }
230         }
231         public void traverse(ASTVisitor visitor, BlockScope scope) {
232                 if (visitor.visit(this, scope)) {
233                         if (expression != null)
234                                 expression.traverse(visitor, scope);
235                 }
236                 visitor.endVisit(this, scope);
237         }
238 }