A massive organize imports and formatting of the sources using default Eclipse code...
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / ast / ReturnStatement.java
1 /***********************************************************************************************************************************
2  * Copyright (c) 2000, 2003 IBM Corporation and others. All rights reserved. This program and the accompanying materials are made
3  * available under the terms of the Common Public License v1.0 which accompanies this distribution, and is available at
4  * http://www.eclipse.org/legal/cpl-v10.html
5  * 
6  * Contributors: IBM Corporation - initial API and implementation
7  **********************************************************************************************************************************/
8 package net.sourceforge.phpdt.internal.compiler.ast;
9
10 import net.sourceforge.phpdt.internal.compiler.ASTVisitor;
11 import net.sourceforge.phpdt.internal.compiler.flow.FlowContext;
12 import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
13 import net.sourceforge.phpdt.internal.compiler.flow.InitializationFlowContext;
14 import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
15 import net.sourceforge.phpdt.internal.compiler.lookup.LocalVariableBinding;
16 import net.sourceforge.phpdt.internal.compiler.lookup.MethodBinding;
17 import net.sourceforge.phpdt.internal.compiler.lookup.MethodScope;
18 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
19
20 public class ReturnStatement extends Statement {
21         public Expression expression;
22
23         public TypeBinding expressionType;
24
25         public boolean isSynchronized;
26
27         public ASTNode[] subroutines;
28
29         public LocalVariableBinding saveValueVariable;
30
31         public ReturnStatement(Expression expr, int s, int e) {
32                 sourceStart = s;
33                 sourceEnd = e;
34                 expression = expr;
35         }
36
37         public FlowInfo analyseCode(BlockScope currentScope,
38                         FlowContext flowContext, FlowInfo flowInfo) { // here requires to
39                                                                                                                         // generate a
40                 // sequence of finally blocks
41                 // invocations depending
42                 // corresponding
43                 // to each of the traversed try statements, so that execution will
44                 // terminate properly.
45
46                 // lookup the label, this should answer the returnContext
47
48                 if (expression != null) {
49                         flowInfo = expression.analyseCode(currentScope, flowContext,
50                                         flowInfo);
51                 }
52                 // compute the return sequence (running the finally blocks)
53                 FlowContext traversedContext = flowContext;
54                 int subIndex = 0, maxSub = 5;
55                 boolean saveValueNeeded = false;
56                 boolean hasValueToSave = expression != null
57                                 && expression.constant == NotAConstant;
58                 do {
59                         ASTNode sub;
60                         if ((sub = traversedContext.subRoutine()) != null) {
61                                 if (this.subroutines == null) {
62                                         this.subroutines = new ASTNode[maxSub];
63                                 }
64                                 if (subIndex == maxSub) {
65                                         System.arraycopy(this.subroutines, 0,
66                                                         (this.subroutines = new ASTNode[maxSub *= 2]), 0,
67                                                         subIndex); // grow
68                                 }
69                                 this.subroutines[subIndex++] = sub;
70                                 if (sub.cannotReturn()) {
71                                         saveValueNeeded = false;
72                                         break;
73                                 }
74                         }
75                         traversedContext.recordReturnFrom(flowInfo.unconditionalInits());
76
77                         ASTNode node = traversedContext.associatedNode;
78                         // if ((node = traversedContext.associatedNode) instanceof
79                         // SynchronizedStatement) {
80                         // isSynchronized = true;
81                         //
82                         // } else
83                         if (node instanceof TryStatement) {
84                                 TryStatement tryStatement = (TryStatement) node;
85                                 flowInfo.addInitializationsFrom(tryStatement.subRoutineInits); // collect
86                                                                                                                                                                 // inits
87                                 if (hasValueToSave) {
88                                         if (this.saveValueVariable == null) { // closest
89                                                                                                                         // subroutine secret
90                                                                                                                         // variable is used
91                                                 prepareSaveValueLocation(tryStatement);
92                                         }
93                                         saveValueNeeded = true;
94                                 }
95
96                         } else if (traversedContext instanceof InitializationFlowContext) {
97                                 currentScope.problemReporter().cannotReturnInInitializer(this);
98                                 return FlowInfo.DEAD_END;
99                         }
100                 } while ((traversedContext = traversedContext.parent) != null);
101
102                 // resize subroutines
103                 if ((subroutines != null) && (subIndex != maxSub)) {
104                         System.arraycopy(subroutines, 0,
105                                         (subroutines = new ASTNode[subIndex]), 0, subIndex);
106                 }
107
108                 // secret local variable for return value (note that this can only occur
109                 // in a real method)
110                 if (saveValueNeeded) {
111                         if (this.saveValueVariable != null) {
112                                 this.saveValueVariable.useFlag = LocalVariableBinding.USED;
113                         }
114                 } else {
115                         this.saveValueVariable = null;
116                         if ((!isSynchronized) && (expressionType == BooleanBinding)) {
117                                 this.expression.bits |= ValueForReturnMASK;
118                         }
119                 }
120                 return FlowInfo.DEAD_END;
121         }
122
123         /**
124          * Retrun statement code generation
125          * 
126          * generate the finallyInvocationSequence.
127          * 
128          * @param currentScope
129          *            net.sourceforge.phpdt.internal.compiler.lookup.BlockScope
130          * @param codeStream
131          *            net.sourceforge.phpdt.internal.compiler.codegen.CodeStream
132          */
133         // public void generateCode(BlockScope currentScope, CodeStream codeStream)
134         // {
135         // if ((bits & IsReachableMASK) == 0) {
136         // return;
137         // }
138         // int pc = codeStream.position;
139         // // generate the expression
140         // if ((expression != null) && (expression.constant == NotAConstant)) {
141         // expression.generateCode(currentScope, codeStream, needValue()); // no
142         // value needed if non-returning subroutine
143         // generateStoreSaveValueIfNecessary(codeStream);
144         // }
145         //      
146         // // generation of code responsible for invoking the finally blocks in
147         // sequence
148         // if (subroutines != null) {
149         // for (int i = 0, max = subroutines.length; i < max; i++) {
150         // ASTNode sub;
151         // if ((sub = subroutines[i]) instanceof SynchronizedStatement) {
152         // codeStream.load(((SynchronizedStatement) sub).synchroVariable);
153         // codeStream.monitorexit();
154         // } else {
155         // TryStatement trySub = (TryStatement) sub;
156         // if (trySub.subRoutineCannotReturn) {
157         // codeStream.goto_(trySub.subRoutineStartLabel);
158         // codeStream.recordPositionsFrom(pc, this.sourceStart);
159         // return;
160         // } else {
161         // codeStream.jsr(trySub.subRoutineStartLabel);
162         // }
163         // }
164         // }
165         // }
166         // if (saveValueVariable != null) codeStream.load(saveValueVariable);
167         //      
168         // if ((expression != null) && (expression.constant != NotAConstant)) {
169         // codeStream.generateConstant(expression.constant,
170         // expression.implicitConversion);
171         // generateStoreSaveValueIfNecessary(codeStream);
172         // }
173         // // output the suitable return bytecode or wrap the value inside a
174         // descriptor for doits
175         // this.generateReturnBytecode(codeStream);
176         //      
177         // codeStream.recordPositionsFrom(pc, this.sourceStart);
178         // }
179         /**
180          * Dump the suitable return bytecode for a return statement
181          * 
182          */
183         // public void generateReturnBytecode(CodeStream codeStream) {
184         //
185         // if (expression == null) {
186         // codeStream.return_();
187         // } else {
188         // switch (expression.implicitConversion >> 4) {
189         // case T_boolean :
190         // case T_int :
191         // codeStream.ireturn();
192         // break;
193         // case T_float :
194         // codeStream.freturn();
195         // break;
196         // case T_long :
197         // codeStream.lreturn();
198         // break;
199         // case T_double :
200         // codeStream.dreturn();
201         // break;
202         // default :
203         // codeStream.areturn();
204         // }
205         // }
206         // }
207         // public void generateStoreSaveValueIfNecessary(CodeStream codeStream){
208         // if (saveValueVariable != null) codeStream.store(saveValueVariable,
209         // false);
210         // }
211         public boolean needValue() {
212                 return (subroutines == null) || (saveValueVariable != null)
213                                 || isSynchronized;
214         }
215
216         public void prepareSaveValueLocation(TryStatement targetTryStatement) {
217
218                 this.saveValueVariable = targetTryStatement.secretReturnValue;
219         }
220
221         public void resolve(BlockScope scope) {
222                 MethodScope methodScope = scope.methodScope();
223                 MethodBinding methodBinding;
224                 TypeBinding methodType = (methodScope.referenceContext instanceof AbstractMethodDeclaration) ? ((methodBinding = ((AbstractMethodDeclaration) methodScope.referenceContext).binding) == null ? null
225                                 : methodBinding.returnType)
226                                 : VoidBinding;
227                 if (methodType == VoidBinding) {
228                         // the expression should be null
229                         if (expression == null)
230                                 return;
231                         if ((expressionType = expression.resolveType(scope)) != null)
232                                 scope.problemReporter().attemptToReturnNonVoidExpression(this,
233                                                 expressionType);
234                         return;
235                 }
236                 if (expression == null) {
237                         if (methodType != null)
238                                 scope.problemReporter().shouldReturn(methodType, this);
239                         return;
240                 }
241                 if ((expressionType = expression.resolveType(scope)) == null)
242                         return;
243
244                 if (methodType != null
245                                 && expression.isConstantValueOfTypeAssignableToType(
246                                                 expressionType, methodType)) {
247                         // dealing with constant
248                         expression.implicitWidening(methodType, expressionType);
249                         return;
250                 }
251                 if (expressionType == VoidBinding) {
252                         scope.problemReporter().attemptToReturnVoidValue(this);
253                         return;
254                 }
255                 if (methodType != null && expressionType.isCompatibleWith(methodType)) {
256                         expression.implicitWidening(methodType, expressionType);
257                         return;
258                 }
259                 if (methodType != null) {
260                         scope.problemReporter().typeMismatchErrorActualTypeExpectedType(
261                                         expression, expressionType, methodType);
262                 }
263         }
264
265         public StringBuffer printStatement(int tab, StringBuffer output) {
266
267                 printIndent(tab, output).append("return "); //$NON-NLS-1$
268                 if (expression != null)
269                         expression.printExpression(0, output);
270                 return output.append(';');
271         }
272
273         public String toString(int tab) {
274
275                 String s = tabString(tab);
276                 s = s + "return "; //$NON-NLS-1$
277                 if (expression != null)
278                         s = s + expression.toStringExpression();
279                 return s;
280         }
281
282         public void traverse(ASTVisitor visitor, BlockScope scope) {
283                 if (visitor.visit(this, scope)) {
284                         if (expression != null)
285                                 expression.traverse(visitor, scope);
286                 }
287                 visitor.endVisit(this, scope);
288         }
289 }