<s> package org . eclipse . jdt . internal . compiler . flow ; import java . util . ArrayList ; import org . eclipse . jdt . core . compiler . CharOperation ; import org . eclipse . jdt . internal . compiler . ast . ASTNode ; import org . eclipse . jdt . internal . compiler . ast . AbstractMethodDeclaration ; import org . eclipse . jdt . internal . compiler . ast . Expression ; import org . eclipse . jdt . internal . compiler . ast . FakedTrackingVariable ; import org . eclipse . jdt . internal . compiler . ast . LabeledStatement ; import org . eclipse . jdt . internal . compiler . ast . Reference ; import org . eclipse . jdt . internal . compiler . ast . SingleNameReference ; import org . eclipse . jdt . internal . compiler . ast . SubRoutineStatement ; import org . eclipse . jdt . internal . compiler . ast . ThrowStatement ; import org . eclipse . jdt . internal . compiler . ast . TryStatement ; import org . eclipse . jdt . internal . compiler . ast . TypeDeclaration ; import org . eclipse . jdt . internal . compiler . classfmt . ClassFileConstants ; import org . eclipse . jdt . internal . compiler . codegen . BranchLabel ; import org . eclipse . jdt . internal . compiler . lookup . Binding ; import org . eclipse . jdt . internal . compiler . lookup . BlockScope ; import org . eclipse . jdt . internal . compiler . lookup . CatchParameterBinding ; import org . eclipse . jdt . internal . compiler . lookup . LocalVariableBinding ; import org . eclipse . jdt . internal . compiler . lookup . ReferenceBinding ; import org . eclipse . jdt . internal . compiler . lookup . Scope ; import org . eclipse . jdt . internal . compiler . lookup . TypeBinding ; import org . eclipse . jdt . internal . compiler . lookup . TypeConstants ; import org . eclipse . jdt . internal . compiler . lookup . TypeIds ; import org . eclipse . jdt . internal . compiler . lookup . VariableBinding ; public class FlowContext implements TypeConstants { public final static FlowContext NotContinuableContext = new FlowContext ( null , null ) ; public ASTNode associatedNode ; public FlowContext parent ; public NullInfoRegistry initsOnFinally ; public int tagBits ; public TypeBinding [ ] [ ] providedExpectedTypes = null ; public static final int DEFER_NULL_DIAGNOSTIC = 0x1 ; public static final int PREEMPT_NULL_DIAGNOSTIC = 0x2 ; public static final int HIDE_NULL_COMPARISON_WARNING = 0x1000 ; public static final int HIDE_NULL_COMPARISON_WARNING_MASK = 0xF000 ; public static final int CAN_ONLY_NULL_NON_NULL = 0x0000 ; public static final int CAN_ONLY_NULL = 0x0001 ; public static final int CAN_ONLY_NON_NULL = 0x0002 ; public static final int MAY_NULL = 0x0003 ; public final static int ASSIGN_TO_NONNULL = 0x0080 ; public static final int EXIT_RESOURCE = 0x0800 ; public static final int CHECK_MASK = 0x00FF ; public static final int IN_COMPARISON_NULL = 0x0100 ; public static final int IN_COMPARISON_NON_NULL = 0x0200 ; public static final int IN_ASSIGNMENT = 0x0300 ; public static final int IN_INSTANCEOF = 0x0400 ; public static final int CONTEXT_MASK = ~ CHECK_MASK & ~ HIDE_NULL_COMPARISON_WARNING_MASK ; public FlowContext ( FlowContext parent , ASTNode associatedNode ) { this . parent = parent ; this . associatedNode = associatedNode ; if ( parent != null ) { if ( ( parent . tagBits & ( FlowContext . DEFER_NULL_DIAGNOSTIC | FlowContext . PREEMPT_NULL_DIAGNOSTIC ) ) != 0 ) { this . tagBits |= FlowContext . DEFER_NULL_DIAGNOSTIC ; } this . initsOnFinally = parent . initsOnFinally ; } } public BranchLabel breakLabel ( ) { return null ; } public void checkExceptionHandlers ( TypeBinding raisedException , ASTNode location , FlowInfo flowInfo , BlockScope scope ) { checkExceptionHandlers ( raisedException , location , flowInfo , scope , false ) ; } public void checkExceptionHandlers ( TypeBinding raisedException , ASTNode location , FlowInfo flowInfo , BlockScope scope , boolean isExceptionOnAutoClose ) { FlowContext traversedContext = this ; ArrayList abruptlyExitedLoops = null ; if ( scope . compilerOptions ( ) . sourceLevel >= ClassFileConstants . JDK1_7 && location instanceof ThrowStatement ) { Expression throwExpression = ( ( ThrowStatement ) location ) . exception ; LocalVariableBinding throwArgBinding = throwExpression . localVariableBinding ( ) ; if ( throwExpression instanceof SingleNameReference && throwArgBinding instanceof CatchParameterBinding && throwArgBinding . isEffectivelyFinal ( ) ) { CatchParameterBinding parameter = ( CatchParameterBinding ) throwArgBinding ; checkExceptionHandlers ( parameter . getPreciseTypes ( ) , location , flowInfo , scope ) ; return ; } } while ( traversedContext != null ) { SubRoutineStatement sub ; if ( ( ( sub = traversedContext . subroutine ( ) ) != null ) && sub . isSubRoutineEscaping ( ) ) { return ; } if ( traversedContext instanceof ExceptionHandlingFlowContext ) { ExceptionHandlingFlowContext exceptionContext = ( ExceptionHandlingFlowContext ) traversedContext ; ReferenceBinding [ ] caughtExceptions ; if ( ( caughtExceptions = exceptionContext . handledExceptions ) != Binding . NO_EXCEPTIONS ) { boolean definitelyCaught = false ; for ( int caughtIndex = 0 , caughtCount = caughtExceptions . length ; caughtIndex < caughtCount ; caughtIndex ++ ) { ReferenceBinding caughtException = caughtExceptions [ caughtIndex ] ; int state = caughtException == null ? Scope . EQUAL_OR_MORE_SPECIFIC : Scope . compareTypes ( raisedException , caughtException ) ; if ( abruptlyExitedLoops != null && caughtException != null && state != Scope . NOT_RELATED ) { for ( int i = 0 , abruptlyExitedLoopsCount = abruptlyExitedLoops . size ( ) ; i < abruptlyExitedLoopsCount ; i ++ ) { LoopingFlowContext loop = ( LoopingFlowContext ) abruptlyExitedLoops . get ( i ) ; loop . recordCatchContextOfEscapingException ( exceptionContext , caughtException ) ; } } switch ( state ) { case Scope . EQUAL_OR_MORE_SPECIFIC : exceptionContext . recordHandlingException ( caughtException , flowInfo . unconditionalInits ( ) , raisedException , raisedException , location , definitelyCaught ) ; definitelyCaught = true ; break ; case Scope . MORE_GENERIC : exceptionContext . recordHandlingException ( caughtException , flowInfo . unconditionalInits ( ) , raisedException , caughtException , location , false ) ; } } if ( definitelyCaught ) return ; } if ( exceptionContext . isMethodContext ) { if ( raisedException . isUncheckedException ( false ) ) return ; if ( exceptionContext . associatedNode instanceof AbstractMethodDeclaration ) { AbstractMethodDeclaration method = ( AbstractMethodDeclaration ) exceptionContext . associatedNode ; if ( method . isConstructor ( ) && method . binding . declaringClass . isAnonymousType ( ) ) { exceptionContext . mergeUnhandledException ( raisedException ) ; return ; } } break ; } } else if ( traversedContext instanceof LoopingFlowContext ) { if ( abruptlyExitedLoops == null ) { abruptlyExitedLoops = new ArrayList ( 5 ) ; } abruptlyExitedLoops . add ( traversedContext ) ; } traversedContext . recordReturnFrom ( flowInfo . unconditionalInits ( ) ) ; if ( ! isExceptionOnAutoClose ) { if ( traversedContext instanceof InsideSubRoutineFlowContext ) { ASTNode node = traversedContext . associatedNode ; if ( node instanceof TryStatement ) { TryStatement tryStatement = ( TryStatement ) node ; flowInfo . addInitializationsFrom ( tryStatement . subRoutineInits ) ; } } } traversedContext = traversedContext . getLocalParent ( ) ; } if ( isExceptionOnAutoClose ) { scope . problemReporter ( ) . unhandledExceptionFromAutoClose ( raisedException , location ) ; } else { scope . problemReporter ( ) . unhandledException ( raisedException , location ) ; } } public void checkExceptionHandlers ( TypeBinding [ ] raisedExceptions , ASTNode location , FlowInfo flowInfo , BlockScope scope ) { int remainingCount ; int raisedCount ; if ( ( raisedExceptions == null ) || ( ( raisedCount = raisedExceptions . length ) == 0 ) ) return ; remainingCount = raisedCount ; System . arraycopy ( raisedExceptions , 0 , ( raisedExceptions = new TypeBinding [ raisedCount ] ) , 0 , raisedCount ) ; FlowContext traversedContext = this ; ArrayList abruptlyExitedLoops = null ; while ( traversedContext != null ) { SubRoutineStatement sub ; if ( ( ( sub = traversedContext . subroutine ( ) ) != null ) && sub . isSubRoutineEscaping ( ) ) { return ; } if ( traversedContext instanceof ExceptionHandlingFlowContext ) { ExceptionHandlingFlowContext exceptionContext = ( ExceptionHandlingFlowContext ) traversedContext ; ReferenceBinding [ ] caughtExceptions ; if ( ( caughtExceptions = exceptionContext . handledExceptions ) != Binding . NO_EXCEPTIONS ) { int caughtCount = caughtExceptions . length ; boolean [ ] locallyCaught = new boolean [ raisedCount ] ; for ( int caughtIndex = 0 ; caughtIndex < caughtCount ; caughtIndex ++ ) { ReferenceBinding caughtException = caughtExceptions [ caughtIndex ] ; for ( int raisedIndex = 0 ; raisedIndex < raisedCount ; raisedIndex ++ ) { TypeBinding raisedException ; if ( ( raisedException = raisedExceptions [ raisedIndex ] ) != null ) { int state = caughtException == null ? Scope . EQUAL_OR_MORE_SPECIFIC : Scope . compareTypes ( raisedException , caughtException ) ; if ( abruptlyExitedLoops != null && caughtException != null && state != Scope . NOT_RELATED ) { for ( int i = 0 , abruptlyExitedLoopsCount = abruptlyExitedLoops . size ( ) ; i < abruptlyExitedLoopsCount ; i ++ ) { LoopingFlowContext loop = ( LoopingFlowContext ) abruptlyExitedLoops . get ( i ) ; loop . recordCatchContextOfEscapingException ( exceptionContext , caughtException ) ; } } switch ( state ) { case Scope . EQUAL_OR_MORE_SPECIFIC : exceptionContext . recordHandlingException ( caughtException , flowInfo . unconditionalInits ( ) , raisedException , raisedException , location , locallyCaught [ raisedIndex ] ) ; if ( ! locallyCaught [ raisedIndex ] ) { locallyCaught [ raisedIndex ] = true ; remainingCount -- ; } break ; case Scope . MORE_GENERIC : exceptionContext . recordHandlingException ( caughtException , flowInfo . unconditionalInits ( ) , raisedException , caughtException , location , false ) ; } } } } for ( int i = 0 ; i < raisedCount ; i ++ ) { if ( locallyCaught [ i ] ) { raisedExceptions [ i ] = null ; } } } if ( exceptionContext . isMethodContext ) { for ( int i = 0 ; i < raisedCount ; i ++ ) { TypeBinding raisedException ; if ( ( raisedException = raisedExceptions [ i ] ) != null ) { if ( raisedException . isUncheckedException ( false ) ) { remainingCount -- ; raisedExceptions [ i ] = null ; } } } if ( exceptionContext . associatedNode instanceof AbstractMethodDeclaration ) { AbstractMethodDeclaration method = ( AbstractMethodDeclaration ) exceptionContext . associatedNode ; if ( method . isConstructor ( ) && method . binding . declaringClass . isAnonymousType ( ) ) { for ( int i = 0 ; i < raisedCount ; i ++ ) { TypeBinding raisedException ; if ( ( raisedException = raisedExceptions [ i ] ) != null ) { exceptionContext . mergeUnhandledException ( raisedException ) ; } } return ; } } break ; } } else if ( traversedContext instanceof LoopingFlowContext ) { if ( abruptlyExitedLoops == null ) { abruptlyExitedLoops = new ArrayList ( 5 ) ; } abruptlyExitedLoops . add ( traversedContext ) ; } if ( remainingCount == 0 ) return ; traversedContext . recordReturnFrom ( flowInfo . unconditionalInits ( ) ) ; if ( traversedContext instanceof InsideSubRoutineFlowContext ) { ASTNode node = traversedContext . associatedNode ; if ( node instanceof TryStatement ) { TryStatement tryStatement = ( TryStatement ) node ; flowInfo . addInitializationsFrom ( tryStatement . subRoutineInits ) ; } } traversedContext = traversedContext . getLocalParent ( ) ; } nextReport : for ( int i = 0 ; i < raisedCount ; i ++ ) { TypeBinding exception ; if ( ( exception = raisedExceptions [ i ] ) != null ) { for ( int j = 0 ; j < i ; j ++ ) { if ( raisedExceptions [ j ] == exception ) continue nextReport ; } scope . problemReporter ( ) . unhandledException ( exception , location ) ; } } } public BranchLabel continueLabel ( ) { return null ; } public FlowInfo getInitsForFinalBlankInitializationCheck ( TypeBinding declaringType , FlowInfo flowInfo ) { FlowContext current = this ; FlowInfo inits = flowInfo ; do { if ( current instanceof InitializationFlowContext ) { InitializationFlowContext initializationContext = ( InitializationFlowContext ) current ; if ( ( ( TypeDeclaration ) initializationContext . associatedNode ) . binding == declaringType ) { return inits ; } inits = initializationContext . initsBeforeContext ; current = initializationContext . initializationParent ; } else if ( current instanceof ExceptionHandlingFlowContext ) { ExceptionHandlingFlowContext exceptionContext = ( ExceptionHandlingFlowContext ) current ; current = exceptionContext . initializationParent == null ? exceptionContext . getLocalParent ( ) : exceptionContext . initializationParent ; } else { current = current . getLocalParent ( ) ; } } while ( current != null ) ; return null ; } public FlowContext getTargetContextForBreakLabel ( char [ ] labelName ) { FlowContext current = this , lastNonReturningSubRoutine = null ; while ( current != null ) { if ( current . isNonReturningContext ( ) ) { lastNonReturningSubRoutine = current ; } char [ ] currentLabelName ; if ( ( ( currentLabelName = current . labelName ( ) ) != null ) && CharOperation . equals ( currentLabelName , labelName ) ) { ( ( LabeledStatement ) current . associatedNode ) . bits |= ASTNode . LabelUsed ; if ( lastNonReturningSubRoutine == null ) return current ; return lastNonReturningSubRoutine ; } current = current . getLocalParent ( ) ; } return null ; } public FlowContext getTargetContextForContinueLabel ( char [ ] labelName ) { FlowContext current = this ; FlowContext lastContinuable = null ; FlowContext lastNonReturningSubRoutine = null ; while ( current != null ) { if ( current . isNonReturningContext ( ) ) { lastNonReturningSubRoutine = current ; } else { if ( current . isContinuable ( ) ) { lastContinuable = current ; } } char [ ] currentLabelName ; if ( ( currentLabelName = current . labelName ( ) ) != null && CharOperation . equals ( currentLabelName , labelName ) ) { ( ( LabeledStatement ) current . associatedNode ) . bits |= ASTNode . LabelUsed ; if ( ( lastContinuable != null ) && ( current . associatedNode . concreteStatement ( ) == lastContinuable . associatedNode ) ) { if ( lastNonReturningSubRoutine == null ) return lastContinuable ; return lastNonReturningSubRoutine ; } return FlowContext . NotContinuableContext ; } current = current . getLocalParent ( ) ; } return null ; } public FlowContext getTargetContextForDefaultBreak ( ) { FlowContext current = this , lastNonReturningSubRoutine = null ; while ( current != null ) { if ( current . isNonReturningContext ( ) ) { lastNonReturningSubRoutine = current ; } if ( current . isBreakable ( ) && current . labelName ( ) == null ) { if ( lastNonReturningSubRoutine == null ) return current ; return lastNonReturningSubRoutine ; } current = current . getLocalParent ( ) ; } return null ; } public FlowContext getTargetContextForDefaultContinue ( ) { FlowContext current = this , lastNonReturningSubRoutine = null ; while ( current != null ) { if ( current . isNonReturningContext ( ) ) { lastNonReturningSubRoutine = current ; } if ( current . isContinuable ( ) ) { if ( lastNonReturningSubRoutine == null ) return current ; return lastNonReturningSubRoutine ; } current = current . getLocalParent ( ) ; } return null ; } public FlowContext getLocalParent ( ) { if ( this . associatedNode instanceof AbstractMethodDeclaration || this . associatedNode instanceof TypeDeclaration ) return null ; return this . parent ; } public String individualToString ( ) { return "Flow context" ; } public FlowInfo initsOnBreak ( ) { return FlowInfo . DEAD_END ; } public UnconditionalFlowInfo initsOnReturn ( ) { return FlowInfo . DEAD_END ; } public boolean isBreakable ( ) { return false ; } public boolean isContinuable ( ) { return false ; } public boolean isNonReturningContext ( ) { return false ; } public boolean isSubRoutine ( ) { return false ; } public char [ ] labelName ( ) { return null ; } public void recordBreakFrom ( FlowInfo flowInfo ) { } public void recordBreakTo ( FlowContext targetContext ) { } public void recordContinueFrom ( FlowContext innerFlowContext , FlowInfo flowInfo ) { } public boolean recordExitAgainstResource ( BlockScope scope , FlowInfo flowInfo , FakedTrackingVariable trackingVar , ASTNode reference ) { return false ; } protected void recordProvidedExpectedTypes ( TypeBinding providedType , TypeBinding expectedType , int nullCount ) { if ( nullCount == 0 ) { this . providedExpectedTypes = new TypeBinding [ 5 ] [ ] ; } else if ( this . providedExpectedTypes == null ) { int size = 5 ; while ( size <= nullCount ) size *= 2 ; this . providedExpectedTypes = new TypeBinding [ size ] [ ] ; } else if ( nullCount >= this . providedExpectedTypes . length ) { int oldLen = this . providedExpectedTypes . length ; System . arraycopy ( this . providedExpectedTypes , 0 , this . providedExpectedTypes = new TypeBinding [ nullCount * 2 ] [ ] , 0 , oldLen ) ; } this . providedExpectedTypes [ nullCount ] = new TypeBinding [ ] { providedType , expectedType } ; } protected boolean recordFinalAssignment ( VariableBinding variable , Reference finalReference ) { return true ; } protected void recordNullReference ( LocalVariableBinding local , ASTNode location , int status ) { } public void recordReturnFrom ( UnconditionalFlowInfo flowInfo ) { } public void recordSettingFinal ( VariableBinding variable , Reference finalReference , FlowInfo flowInfo ) { if ( ( flowInfo . tagBits & FlowInfo . UNREACHABLE_OR_DEAD ) == 0 ) { FlowContext context = this ; while ( context != null ) { if ( ! context . recordFinalAssignment ( variable , finalReference ) ) { break ; } context = context . getLocalParent ( ) ; } } } public void recordUsingNullReference ( Scope scope , LocalVariableBinding local , ASTNode location , int checkType , FlowInfo flowInfo ) { if ( ( flowInfo . tagBits & FlowInfo . UNREACHABLE ) != 0 || flowInfo . isDefinitelyUnknown ( local ) ) { return ; } checkType |= ( this . tagBits & FlowContext . HIDE_NULL_COMPARISON_WARNING ) ; int checkTypeWithoutHideNullWarning = checkType & ~ FlowContext . HIDE_NULL_COMPARISON_WARNING_MASK ; switch ( checkTypeWithoutHideNullWarning ) { case CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NULL : case CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL : if ( flowInfo . isDefinitelyNonNull ( local ) ) { if ( checkTypeWithoutHideNullWarning == ( CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL ) ) { if ( ( checkType & HIDE_NULL_COMPARISON_WARNING ) == 0 ) { scope . problemReporter ( ) . localVariableRedundantCheckOnNonNull ( local , location ) ; } flowInfo . initsWhenFalse ( ) . setReachMode ( FlowInfo . UNREACHABLE_BY_NULLANALYSIS ) ; } else { scope . problemReporter ( ) . localVariableNonNullComparedToNull ( local , location ) ; flowInfo . initsWhenTrue ( ) . setReachMode ( FlowInfo . UNREACHABLE_BY_NULLANALYSIS ) ; } return ; } else if ( flowInfo . cannotBeDefinitelyNullOrNonNull ( local ) ) { return ; } case CAN_ONLY_NULL | IN_COMPARISON_NULL : case CAN_ONLY_NULL | IN_COMPARISON_NON_NULL : case CAN_ONLY_NULL | IN_ASSIGNMENT : case CAN_ONLY_NULL | IN_INSTANCEOF : Expression reference = ( Expression ) location ; if ( flowInfo . isDefinitelyNull ( local ) ) { switch ( checkTypeWithoutHideNullWarning & CONTEXT_MASK ) { case FlowContext . IN_COMPARISON_NULL : if ( ( ( checkTypeWithoutHideNullWarning & CHECK_MASK ) == CAN_ONLY_NULL ) && ( reference . implicitConversion & TypeIds . UNBOXING ) != 0 ) { scope . problemReporter ( ) . localVariableNullReference ( local , reference ) ; return ; } if ( ( checkType & HIDE_NULL_COMPARISON_WARNING ) == 0 ) { scope . problemReporter ( ) . localVariableRedundantCheckOnNull ( local , reference ) ; } flowInfo . initsWhenFalse ( ) . setReachMode ( FlowInfo . UNREACHABLE_BY_NULLANALYSIS ) ; return ; case FlowContext . IN_COMPARISON_NON_NULL : if ( ( ( checkTypeWithoutHideNullWarning & CHECK_MASK ) == CAN_ONLY_NULL ) && ( reference . implicitConversion & TypeIds . UNBOXING ) != 0 ) { scope . problemReporter ( ) . localVariableNullReference ( local , reference ) ; return ; } scope . problemReporter ( ) . localVariableNullComparedToNonNull ( local , reference ) ; flowInfo . initsWhenTrue ( ) . setReachMode ( FlowInfo . UNREACHABLE_BY_NULLANALYSIS ) ; return ; case FlowContext . IN_ASSIGNMENT : scope . problemReporter ( ) . localVariableRedundantNullAssignment ( local , reference ) ; return ; case FlowContext . IN_INSTANCEOF : scope . problemReporter ( ) . localVariableNullInstanceof ( local , reference ) ; return ; } } else if ( flowInfo . isPotentiallyNull ( local ) ) { switch ( checkTypeWithoutHideNullWarning & CONTEXT_MASK ) { case FlowContext . IN_COMPARISON_NULL : if ( ( ( checkTypeWithoutHideNullWarning & CHECK_MASK ) == CAN_ONLY_NULL ) && ( reference . implicitConversion & TypeIds . UNBOXING ) != 0 ) { scope . problemReporter ( ) . localVariablePotentialNullReference ( local , reference ) ; return ; } break ; case FlowContext . IN_COMPARISON_NON_NULL : if ( ( ( checkTypeWithoutHideNullWarning & CHECK_MASK ) == CAN_ONLY_NULL ) && ( reference . implicitConversion & TypeIds . UNBOXING ) != 0 ) { scope . problemReporter ( ) . localVariablePotentialNullReference ( local , reference ) ; return ; } break ; } } else if ( flowInfo . cannotBeDefinitelyNullOrNonNull ( local ) ) { return ; } break ; case MAY_NULL : if ( flowInfo . isDefinitelyNull ( local ) ) { scope . problemReporter ( ) . localVariableNullReference ( local , location ) ; return ; } if ( flowInfo . isPotentiallyNull ( local ) ) { scope . problemReporter ( ) . localVariablePotentialNullReference ( local , location ) ; return ; } break ; default : } if ( this . parent != null ) { this . parent . recordUsingNullReference ( scope , local , location , checkType , flowInfo ) ; } } void removeFinalAssignmentIfAny ( Reference reference ) { } public SubRoutineStatement subroutine ( ) { return null ; } public String toString ( ) { StringBuffer buffer = new StringBuffer ( ) ; FlowContext current = this ; int parentsCount = 0 ; while ( ( current = current . parent ) != null ) { parentsCount ++ ; } FlowContext [ ] parents = new FlowContext [ parentsCount + 1 ] ; current = this ; int index = parentsCount ; while ( index >= 0 ) { parents [ index -- ] = current ; current = current . parent ; } for ( int i = 0 ; i < parentsCount ; i ++ ) { for ( int j = 0 ; j < i ; j ++ ) buffer . append ( '\t' ) ; buffer . append ( parents [ i ] . individualToString ( ) ) . append ( '\n' ) ; } buffer . append ( '*' ) ; for ( int j = 0 ; j < parentsCount + 1 ; j ++ ) buffer . append ( '\t' ) ; buffer . append ( individualToString ( ) ) . append ( '\n' ) ; return buffer . toString ( ) ; } public void recordNullityMismatch ( BlockScope currentScope , Expression expression , TypeBinding providedType , TypeBinding expectedType , int nullStatus ) { if ( providedType == null ) { return ; } if ( expression . localVariableBinding ( ) != null ) { FlowContext currentContext = this ; while ( currentContext != null ) { int isInsideAssert = 0x0 ; if ( ( this . tagBits & FlowContext . HIDE_NULL_COMPARISON_WARNING ) != 0 ) { isInsideAssert = FlowContext . HIDE_NULL_COMPARISON_WARNING ; } if ( currentContext . internalRecordNullityMismatch ( expression , providedType , nullStatus , expectedType , ASSIGN_TO_NONNULL | isInsideAssert ) ) return ; currentContext = currentContext . parent ; } } char [ ] [ ] annotationName = currentScope . environment ( ) . getNonNullAnnotationName ( ) ; currentScope . problemReporter ( ) . nullityMismatch ( expression , providedType , expectedType , nullStatus , annotationName ) ; } protected boolean internalRecordNullityMismatch ( Expression expression , TypeBinding providedType , int nullStatus , TypeBinding expectedType , int checkType ) { return false ; } } </s>