<s> package org . eclipse . jdt . internal . compiler . ast ; import org . eclipse . jdt . internal . compiler . ASTVisitor ; import org . eclipse . jdt . internal . compiler . codegen . * ; import org . eclipse . jdt . internal . compiler . flow . * ; import org . eclipse . jdt . internal . compiler . impl . Constant ; import org . eclipse . jdt . internal . compiler . lookup . * ; public class ReturnStatement extends Statement { public Expression expression ; public SubRoutineStatement [ ] subroutines ; public LocalVariableBinding saveValueVariable ; public int initStateIndex = - 1 ; public ReturnStatement ( Expression expression , int sourceStart , int sourceEnd ) { this . sourceStart = sourceStart ; this . sourceEnd = sourceEnd ; this . expression = expression ; } public FlowInfo analyseCode ( BlockScope currentScope , FlowContext flowContext , FlowInfo flowInfo ) { if ( this . expression != null ) { flowInfo = this . expression . analyseCode ( currentScope , flowContext , flowInfo ) ; } this . initStateIndex = currentScope . methodScope ( ) . recordInitializationStates ( flowInfo ) ; FlowContext traversedContext = flowContext ; int subCount = 0 ; boolean saveValueNeeded = false ; boolean hasValueToSave = needValueStore ( ) ; do { SubRoutineStatement sub ; if ( ( sub = traversedContext . subroutine ( ) ) != null ) { if ( this . subroutines == null ) { this . subroutines = new SubRoutineStatement [ 5 ] ; } if ( subCount == this . subroutines . length ) { System . arraycopy ( this . subroutines , 0 , ( this . subroutines = new SubRoutineStatement [ subCount * 2 ] ) , 0 , subCount ) ; } this . subroutines [ subCount ++ ] = sub ; if ( sub . isSubRoutineEscaping ( ) ) { saveValueNeeded = false ; this . bits |= ASTNode . IsAnySubRoutineEscaping ; break ; } } traversedContext . recordReturnFrom ( flowInfo . unconditionalInits ( ) ) ; if ( traversedContext instanceof InsideSubRoutineFlowContext ) { ASTNode node = traversedContext . associatedNode ; if ( node instanceof SynchronizedStatement ) { this . bits |= ASTNode . IsSynchronized ; } else if ( node instanceof TryStatement ) { TryStatement tryStatement = ( TryStatement ) node ; flowInfo . addInitializationsFrom ( tryStatement . subRoutineInits ) ; if ( hasValueToSave ) { if ( this . saveValueVariable == null ) { prepareSaveValueLocation ( tryStatement ) ; } saveValueNeeded = true ; this . initStateIndex = currentScope . methodScope ( ) . recordInitializationStates ( flowInfo ) ; } } } else if ( traversedContext instanceof InitializationFlowContext ) { currentScope . problemReporter ( ) . cannotReturnInInitializer ( this ) ; return FlowInfo . DEAD_END ; } } while ( ( traversedContext = traversedContext . parent ) != null ) ; if ( ( this . subroutines != null ) && ( subCount != this . subroutines . length ) ) { System . arraycopy ( this . subroutines , 0 , ( this . subroutines = new SubRoutineStatement [ subCount ] ) , 0 , subCount ) ; } if ( saveValueNeeded ) { if ( this . saveValueVariable != null ) { this . saveValueVariable . useFlag = LocalVariableBinding . USED ; } } else { this . saveValueVariable = null ; if ( ( ( this . bits & ASTNode . IsSynchronized ) == 0 ) && this . expression != null && this . expression . resolvedType == TypeBinding . BOOLEAN ) { this . expression . bits |= ASTNode . IsReturnedValue ; } } return FlowInfo . DEAD_END ; } public void generateCode ( BlockScope currentScope , CodeStream codeStream ) { if ( ( this . bits & ASTNode . IsReachable ) == 0 ) { return ; } int pc = codeStream . position ; boolean alreadyGeneratedExpression = false ; if ( needValueStore ( ) ) { alreadyGeneratedExpression = true ; this . expression . generateCode ( currentScope , codeStream , needValue ( ) ) ; generateStoreSaveValueIfNecessary ( codeStream ) ; } if ( this . subroutines != null ) { Object reusableJSRTarget = this . expression == null ? ( Object ) TypeBinding . VOID : this . expression . reusableJSRTarget ( ) ; for ( int i = 0 , max = this . subroutines . length ; i < max ; i ++ ) { SubRoutineStatement sub = this . subroutines [ i ] ; boolean didEscape = sub . generateSubRoutineInvocation ( currentScope , codeStream , reusableJSRTarget , this . initStateIndex , this . saveValueVariable ) ; if ( didEscape ) { codeStream . recordPositionsFrom ( pc , this . sourceStart ) ; SubRoutineStatement . reenterAllExceptionHandlers ( this . subroutines , i , codeStream ) ; return ; } } } if ( this . saveValueVariable != null ) { codeStream . addVariable ( this . saveValueVariable ) ; codeStream . load ( this . saveValueVariable ) ; } if ( this . expression != null && ! alreadyGeneratedExpression ) { this . expression . generateCode ( currentScope , codeStream , true ) ; generateStoreSaveValueIfNecessary ( codeStream ) ; } generateReturnBytecode ( codeStream ) ; if ( this . saveValueVariable != null ) { codeStream . removeVariable ( this . saveValueVariable ) ; } if ( this . initStateIndex != - 1 ) { codeStream . removeNotDefinitelyAssignedVariables ( currentScope , this . initStateIndex ) ; codeStream . addDefinitelyAssignedVariables ( currentScope , this . initStateIndex ) ; } codeStream . recordPositionsFrom ( pc , this . sourceStart ) ; SubRoutineStatement . reenterAllExceptionHandlers ( this . subroutines , - 1 , codeStream ) ; } public void generateReturnBytecode ( CodeStream codeStream ) { codeStream . generateReturnBytecode ( this . expression ) ; } public void generateStoreSaveValueIfNecessary ( CodeStream codeStream ) { if ( this . saveValueVariable != null ) { codeStream . store ( this . saveValueVariable , false ) ; } } private boolean needValueStore ( ) { return this . expression != null && ( this . expression . constant == Constant . NotAConstant || ( this . expression . implicitConversion & TypeIds . BOXING ) != 0 ) && ! ( this . expression instanceof NullLiteral ) ; } public boolean needValue ( ) { return this . saveValueVariable != null || ( this . bits & ASTNode . IsSynchronized ) != 0 || ( ( this . bits & ASTNode . IsAnySubRoutineEscaping ) == 0 ) ; } public void prepareSaveValueLocation ( TryStatement targetTryStatement ) { this . saveValueVariable = targetTryStatement . secretReturnValue ; } public StringBuffer printStatement ( int tab , StringBuffer output ) { printIndent ( tab , output ) . append ( "return " ) ; if ( this . expression != null ) this . expression . printExpression ( 0 , output ) ; return output . append ( ';' ) ; } public void resolve ( BlockScope scope ) { MethodScope methodScope = scope . methodScope ( ) ; MethodBinding methodBinding ; TypeBinding methodType = ( methodScope . referenceContext instanceof AbstractMethodDeclaration ) ? ( ( methodBinding = ( ( AbstractMethodDeclaration ) methodScope . referenceContext ) . binding ) == null ? null : methodBinding . returnType ) : TypeBinding . VOID ; TypeBinding expressionType ; if ( methodType == TypeBinding . VOID ) { if ( this . expression == null ) return ; if ( ( expressionType = this . expression . resolveType ( scope ) ) != null ) scope . problemReporter ( ) . attemptToReturnNonVoidExpression ( this , expressionType ) ; return ; } if ( this . expression == null ) { if ( methodType != null ) scope . problemReporter ( ) . shouldReturn ( methodType , this ) ; return ; } this . expression . setExpectedType ( methodType ) ; if ( ( expressionType = this . expression . resolveType ( scope ) ) == null ) return ; if ( expressionType == TypeBinding . VOID ) { scope . problemReporter ( ) . attemptToReturnVoidValue ( this ) ; return ; } if ( methodType == null ) return ; if ( methodType != expressionType ) scope . compilationUnitScope ( ) . recordTypeConversion ( methodType , expressionType ) ; if ( this . expression . isConstantValueOfTypeAssignableToType ( expressionType , methodType ) || expressionType . isCompatibleWith ( methodType ) ) { this . expression . computeConversion ( scope , methodType , expressionType ) ; if ( expressionType . needsUncheckedConversion ( methodType ) ) { scope . problemReporter ( ) . unsafeTypeConversion ( this . expression , expressionType , methodType ) ; } if ( this . expression instanceof CastExpression && ( this . expression . bits & ( ASTNode . UnnecessaryCast | ASTNode . DisableUnnecessaryCastCheck ) ) == 0 ) { CastExpression . checkNeedForAssignedCast ( scope , methodType , ( CastExpression ) this . expression ) ; } return ; } else if ( isBoxingCompatible ( expressionType , methodType , this . expression , scope ) ) { this . expression . computeConversion ( scope , methodType , expressionType ) ; if ( this . expression instanceof CastExpression && ( this . expression . bits & ( ASTNode . UnnecessaryCast | ASTNode . DisableUnnecessaryCastCheck ) ) == 0 ) { CastExpression . checkNeedForAssignedCast ( scope , methodType , ( CastExpression ) this . expression ) ; } return ; } if ( ( methodType . tagBits & TagBits . HasMissingType ) == 0 ) { scope . problemReporter ( ) . typeMismatchError ( expressionType , methodType , this . expression , null ) ; } } public void traverse ( ASTVisitor visitor , BlockScope scope ) { if ( visitor . visit ( this , scope ) ) { if ( this . expression != null ) this . expression . traverse ( visitor , scope ) ; } visitor . endVisit ( this , scope ) ; } } </s>