1 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) { 36 38 if (this.expression != null) { 39 flowInfo = this.expression.analyseCode(currentScope, flowContext, flowInfo); 40 } 41 this.initStateIndex = 42 currentScope.methodScope().recordInitializationStates(flowInfo); 43 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); } 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); if (hasValueToSave) { 76 if (this.saveValueVariable == null){ 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 if ((this.subroutines != null) && (subCount != this.subroutines.length)) { 90 System.arraycopy(this.subroutines, 0, (this.subroutines = new SubRoutineStatement[subCount]), 0, subCount); 91 } 92 93 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 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 if ((this.expression != null) && (this.expression.constant == Constant.NotAConstant) && !(this.expression instanceof NullLiteral)) { 123 alreadyGeneratedExpression = true; 124 this.expression.generateCode(currentScope, codeStream, needValue()); generateStoreSaveValueIfNecessary(codeStream); 126 } 127 128 if (this.subroutines != null) { 130 Object reusableJSRTarget = this.expression == null ? (Object )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 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 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 printStatement(int tab, StringBuffer output){ 187 printIndent(tab, output).append("return "); 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 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); 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) 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() && scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5 && !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 |