<s> package org . eclipse . jdt . internal . compiler . ast ; import java . util . HashMap ; import java . util . Iterator ; import java . util . Map ; import java . util . Map . Entry ; import java . util . Set ; import org . eclipse . jdt . internal . compiler . codegen . CodeStream ; import org . eclipse . jdt . internal . compiler . flow . FlowContext ; import org . eclipse . jdt . internal . compiler . flow . FlowInfo ; import org . eclipse . jdt . internal . compiler . impl . Constant ; import org . eclipse . jdt . internal . compiler . lookup . Binding ; import org . eclipse . jdt . internal . compiler . lookup . BlockScope ; import org . eclipse . jdt . internal . compiler . lookup . LocalVariableBinding ; import org . eclipse . jdt . internal . compiler . lookup . MethodScope ; 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 . problem . ProblemReporter ; public class FakedTrackingVariable extends LocalDeclaration { private static final int CLOSE_SEEN = 1 ; private static final int SHARED_WITH_OUTSIDE = 2 ; private static final int OWNED_BY_OUTSIDE = 4 ; private static final int CLOSED_IN_NESTED_METHOD = 8 ; private static final int REPORTED_EXPLICIT_CLOSE = 16 ; private static final int REPORTED_POTENTIAL_LEAK = 32 ; private static final int REPORTED_DEFINITIVE_LEAK = 64 ; public static boolean TEST_372319 = false ; private int globalClosingState = 0 ; public LocalVariableBinding originalBinding ; public FakedTrackingVariable innerTracker ; public FakedTrackingVariable outerTracker ; MethodScope methodScope ; private HashMap recordedLocations ; private ASTNode currentAssignment ; public FakedTrackingVariable ( LocalVariableBinding original , ASTNode location ) { super ( original . name , location . sourceStart , location . sourceEnd ) ; this . type = new SingleTypeReference ( TypeConstants . OBJECT , ( ( long ) this . sourceStart << 32 ) + this . sourceEnd ) ; this . methodScope = original . declaringScope . methodScope ( ) ; this . originalBinding = original ; resolve ( original . declaringScope ) ; } private FakedTrackingVariable ( BlockScope scope , ASTNode location ) { super ( "" . toCharArray ( ) , location . sourceStart , location . sourceEnd ) ; this . type = new SingleTypeReference ( TypeConstants . OBJECT , ( ( long ) this . sourceStart << 32 ) + this . sourceEnd ) ; this . methodScope = scope . methodScope ( ) ; this . originalBinding = null ; resolve ( scope ) ; } public void generateCode ( BlockScope currentScope , CodeStream codeStream ) { } public void resolve ( BlockScope scope ) { this . binding = new LocalVariableBinding ( this . name , scope . getJavaLangObject ( ) , 0 , false ) ; this . binding . closeTracker = this ; this . binding . declaringScope = scope ; this . binding . setConstant ( Constant . NotAConstant ) ; this . binding . useFlag = LocalVariableBinding . USED ; this . binding . id = scope . registerTrackingVariable ( this ) ; } public static FakedTrackingVariable getCloseTrackingVariable ( Expression expression ) { while ( true ) { if ( expression instanceof CastExpression ) expression = ( ( CastExpression ) expression ) . expression ; else if ( expression instanceof Assignment ) expression = ( ( Assignment ) expression ) . expression ; else break ; } if ( expression instanceof SingleNameReference ) { SingleNameReference name = ( SingleNameReference ) expression ; if ( name . binding instanceof LocalVariableBinding ) { LocalVariableBinding local = ( LocalVariableBinding ) name . binding ; if ( local . closeTracker != null ) return local . closeTracker ; if ( ! isAnyCloseable ( expression . resolvedType ) ) return null ; Statement location = local . declaration ; local . closeTracker = new FakedTrackingVariable ( local , location ) ; if ( local . isParameter ( ) ) { local . closeTracker . globalClosingState |= OWNED_BY_OUTSIDE ; } return local . closeTracker ; } } else if ( expression instanceof AllocationExpression ) { return ( ( AllocationExpression ) expression ) . closeTracker ; } return null ; } public static void preConnectTrackerAcrossAssignment ( ASTNode location , LocalVariableBinding local , Expression rhs ) { FakedTrackingVariable closeTracker = null ; if ( rhs instanceof AllocationExpression ) { closeTracker = local . closeTracker ; if ( closeTracker == null ) { if ( rhs . resolvedType != TypeBinding . NULL ) { closeTracker = new FakedTrackingVariable ( local , location ) ; if ( local . isParameter ( ) ) { closeTracker . globalClosingState |= OWNED_BY_OUTSIDE ; } } } if ( closeTracker != null ) { closeTracker . currentAssignment = location ; AllocationExpression allocation = ( AllocationExpression ) rhs ; allocation . closeTracker = closeTracker ; if ( allocation . arguments != null && allocation . arguments . length > 0 ) { preConnectTrackerAcrossAssignment ( location , local , allocation . arguments [ 0 ] ) ; } } } } public static void analyseCloseableAllocation ( BlockScope scope , FlowInfo flowInfo , AllocationExpression allocation ) { if ( ( ( ReferenceBinding ) allocation . resolvedType ) . hasTypeBit ( TypeIds . BitResourceFreeCloseable ) ) { if ( allocation . closeTracker != null ) { scope . removeTrackingVar ( allocation . closeTracker ) ; allocation . closeTracker = null ; } } else if ( ( ( ReferenceBinding ) allocation . resolvedType ) . hasTypeBit ( TypeIds . BitWrapperCloseable ) ) { boolean isWrapper = true ; if ( allocation . arguments != null && allocation . arguments . length > 0 ) { FakedTrackingVariable innerTracker = findCloseTracker ( scope , flowInfo , allocation . arguments [ 0 ] ) ; if ( innerTracker != null ) { FakedTrackingVariable currentInner = innerTracker ; do { if ( currentInner == allocation . closeTracker ) return ; currentInner = currentInner . innerTracker ; } while ( currentInner != null ) ; int newStatus = FlowInfo . NULL ; if ( allocation . closeTracker == null ) { allocation . closeTracker = new FakedTrackingVariable ( scope , allocation ) ; } else { if ( scope . finallyInfo != null ) { int finallyStatus = scope . finallyInfo . nullStatus ( allocation . closeTracker . binding ) ; if ( finallyStatus != FlowInfo . UNKNOWN ) newStatus = finallyStatus ; } } allocation . closeTracker . innerTracker = innerTracker ; innerTracker . outerTracker = allocation . closeTracker ; flowInfo . markNullStatus ( allocation . closeTracker . binding , newStatus ) ; if ( newStatus != FlowInfo . NULL ) { FakedTrackingVariable currentTracker = innerTracker ; while ( currentTracker != null ) { flowInfo . markNullStatus ( currentTracker . binding , newStatus ) ; currentTracker . globalClosingState |= allocation . closeTracker . globalClosingState ; currentTracker = currentTracker . innerTracker ; } } return ; } else { if ( ! isAnyCloseable ( allocation . arguments [ 0 ] . resolvedType ) ) { isWrapper = false ; } } } else { isWrapper = false ; } if ( isWrapper ) { if ( allocation . closeTracker != null ) { scope . removeTrackingVar ( allocation . closeTracker ) ; allocation . closeTracker = null ; } } else { handleRegularResource ( scope , flowInfo , allocation ) ; } } else { handleRegularResource ( scope , flowInfo , allocation ) ; } } private static void handleRegularResource ( BlockScope scope , FlowInfo flowInfo , AllocationExpression allocation ) { FakedTrackingVariable presetTracker = allocation . closeTracker ; if ( presetTracker != null && presetTracker . originalBinding != null ) { int closeStatus = flowInfo . nullStatus ( presetTracker . binding ) ; if ( closeStatus != FlowInfo . NON_NULL && closeStatus != FlowInfo . UNKNOWN && ! flowInfo . isDefinitelyNull ( presetTracker . originalBinding ) && ! ( presetTracker . currentAssignment instanceof LocalDeclaration ) ) allocation . closeTracker . recordErrorLocation ( presetTracker . currentAssignment , closeStatus ) ; } else { allocation . closeTracker = new FakedTrackingVariable ( scope , allocation ) ; } flowInfo . markAsDefinitelyNull ( allocation . closeTracker . binding ) ; } private static FakedTrackingVariable findCloseTracker ( BlockScope scope , FlowInfo flowInfo , Expression arg ) { while ( arg instanceof Assignment ) { Assignment assign = ( Assignment ) arg ; LocalVariableBinding innerLocal = assign . localVariableBinding ( ) ; if ( innerLocal != null ) { return innerLocal . closeTracker ; } else { arg = assign . expression ; } } if ( arg instanceof SingleNameReference ) { LocalVariableBinding local = arg . localVariableBinding ( ) ; if ( local != null ) { return local . closeTracker ; } } else if ( arg instanceof AllocationExpression ) { return ( ( AllocationExpression ) arg ) . closeTracker ; } return null ; } public static void handleResourceAssignment ( BlockScope scope , FlowInfo upstreamInfo , FlowInfo flowInfo , ASTNode location , Expression rhs , LocalVariableBinding local ) { FakedTrackingVariable previousTracker = null ; FakedTrackingVariable disconnectedTracker = null ; if ( local . closeTracker != null ) { previousTracker = local . closeTracker ; int nullStatus = upstreamInfo . nullStatus ( local ) ; if ( nullStatus != FlowInfo . NULL && nullStatus != FlowInfo . UNKNOWN ) disconnectedTracker = previousTracker ; } rhsAnalyis : if ( rhs . resolvedType != TypeBinding . NULL ) { FakedTrackingVariable rhsTrackVar = getCloseTrackingVariable ( rhs ) ; if ( rhsTrackVar != null ) { if ( local . closeTracker == null ) { if ( rhsTrackVar . originalBinding != null ) local . closeTracker = rhsTrackVar ; if ( rhsTrackVar . currentAssignment == location ) { rhsTrackVar . globalClosingState &= ~ ( SHARED_WITH_OUTSIDE | OWNED_BY_OUTSIDE ) ; } } else { if ( rhs instanceof AllocationExpression ) { if ( rhsTrackVar == disconnectedTracker ) return ; if ( local . closeTracker == rhsTrackVar && ( ( rhsTrackVar . globalClosingState & OWNED_BY_OUTSIDE ) != 0 ) ) { local . closeTracker = new FakedTrackingVariable ( local , location ) ; flowInfo . markAsDefinitelyNull ( local . closeTracker . binding ) ; break rhsAnalyis ; } } local . closeTracker = rhsTrackVar ; } } else if ( previousTracker != null ) { if ( ( previousTracker . globalClosingState & ( SHARED_WITH_OUTSIDE | OWNED_BY_OUTSIDE ) ) == 0 ) flowInfo . markAsDefinitelyNull ( previousTracker . binding ) ; local . closeTracker = analyseCloseableExpression ( flowInfo , local , location , rhs , previousTracker ) ; } else { rhsTrackVar = analyseCloseableExpression ( flowInfo , local , location , rhs , null ) ; if ( rhsTrackVar != null ) { local . closeTracker = rhsTrackVar ; if ( ( rhsTrackVar . globalClosingState & ( SHARED_WITH_OUTSIDE | OWNED_BY_OUTSIDE ) ) == 0 ) flowInfo . markAsDefinitelyNull ( rhsTrackVar . binding ) ; } } } if ( disconnectedTracker != null ) { if ( disconnectedTracker . innerTracker != null && disconnectedTracker . innerTracker . binding . declaringScope == scope ) { disconnectedTracker . innerTracker . outerTracker = null ; scope . pruneWrapperTrackingVar ( disconnectedTracker ) ; } else { int upstreamStatus = upstreamInfo . nullStatus ( disconnectedTracker . binding ) ; if ( upstreamStatus != FlowInfo . NON_NULL ) disconnectedTracker . recordErrorLocation ( location , upstreamStatus ) ; } } } private static FakedTrackingVariable analyseCloseableExpression ( FlowInfo flowInfo , LocalVariableBinding local , ASTNode location , Expression expression , FakedTrackingVariable previousTracker ) { while ( true ) { if ( expression instanceof Assignment ) expression = ( ( Assignment ) expression ) . expression ; else if ( expression instanceof CastExpression ) expression = ( ( CastExpression ) expression ) . expression ; else break ; } if ( expression instanceof AllocationExpression ) { FakedTrackingVariable tracker = ( ( AllocationExpression ) expression ) . closeTracker ; if ( tracker != null && tracker . originalBinding == null ) { return null ; } return tracker ; } else if ( expression instanceof MessageSend || expression instanceof ArrayReference ) { FakedTrackingVariable tracker = new FakedTrackingVariable ( local , location ) ; tracker . globalClosingState |= SHARED_WITH_OUTSIDE ; flowInfo . markPotentiallyNullBit ( tracker . binding ) ; return tracker ; } else if ( ( expression . bits & RestrictiveFlagMASK ) == Binding . FIELD || ( ( expression instanceof QualifiedNameReference ) && ( ( QualifiedNameReference ) expression ) . isFieldAccess ( ) ) ) { FakedTrackingVariable tracker = new FakedTrackingVariable ( local , location ) ; tracker . globalClosingState |= OWNED_BY_OUTSIDE ; return tracker ; } if ( expression . resolvedType instanceof ReferenceBinding ) { ReferenceBinding resourceType = ( ReferenceBinding ) expression . resolvedType ; if ( resourceType . hasTypeBit ( TypeIds . BitResourceFreeCloseable ) ) { return null ; } } if ( local . closeTracker != null ) return local . closeTracker ; FakedTrackingVariable newTracker = new FakedTrackingVariable ( local , location ) ; LocalVariableBinding rhsLocal = expression . localVariableBinding ( ) ; if ( rhsLocal != null && rhsLocal . isParameter ( ) ) { newTracker . globalClosingState |= OWNED_BY_OUTSIDE ; } return newTracker ; } public static void cleanUpAfterAssignment ( BlockScope currentScope , int lhsBits , Expression expression ) { while ( true ) { if ( expression instanceof Assignment ) expression = ( ( Assignment ) expression ) . expression ; else if ( expression instanceof CastExpression ) expression = ( ( CastExpression ) expression ) . expression ; else break ; } if ( expression instanceof AllocationExpression ) { FakedTrackingVariable tracker = ( ( AllocationExpression ) expression ) . closeTracker ; if ( tracker != null && tracker . originalBinding == null ) { currentScope . removeTrackingVar ( tracker ) ; ( ( AllocationExpression ) expression ) . closeTracker = null ; } } else { LocalVariableBinding local = expression . localVariableBinding ( ) ; if ( local != null && local . closeTracker != null && ( ( lhsBits & Binding . FIELD ) != 0 ) ) currentScope . removeTrackingVar ( local . closeTracker ) ; } } public static boolean isAnyCloseable ( TypeBinding typeBinding ) { return typeBinding instanceof ReferenceBinding && ( ( ReferenceBinding ) typeBinding ) . hasTypeBit ( TypeIds . BitAutoCloseable | TypeIds . BitCloseable ) ; } public int findMostSpecificStatus ( FlowInfo flowInfo , BlockScope currentScope , BlockScope locationScope ) { int status = FlowInfo . UNKNOWN ; FakedTrackingVariable currentTracker = this ; while ( currentTracker != null ) { LocalVariableBinding currentVar = currentTracker . binding ; int currentStatus = getNullStatusAggressively ( currentVar , flowInfo ) ; if ( locationScope != null ) currentStatus = mergeCloseStatus ( locationScope , currentStatus , currentVar , currentScope ) ; if ( currentStatus == FlowInfo . NON_NULL ) { status = currentStatus ; break ; } else if ( status == FlowInfo . NULL || status == FlowInfo . UNKNOWN ) { status = currentStatus ; } currentTracker = currentTracker . innerTracker ; } return status ; } private int getNullStatusAggressively ( LocalVariableBinding local , FlowInfo flowInfo ) { if ( flowInfo == FlowInfo . DEAD_END ) { return FlowInfo . UNKNOWN ; } int reachMode = flowInfo . reachMode ( ) ; int status = 0 ; try { if ( reachMode != FlowInfo . REACHABLE ) flowInfo . tagBits &= ~ FlowInfo . UNREACHABLE ; status = flowInfo . nullStatus ( local ) ; if ( TEST_372319 ) { try { Thread . sleep ( 5 ) ; } catch ( InterruptedException e ) { } } } finally { flowInfo . tagBits |= reachMode ; } if ( ( status & FlowInfo . NULL ) != 0 ) { if ( ( status & ( FlowInfo . NON_NULL | FlowInfo . POTENTIALLY_NON_NULL ) ) != 0 ) return FlowInfo . POTENTIALLY_NULL ; return FlowInfo . NULL ; } else if ( ( status & FlowInfo . NON_NULL ) != 0 ) { if ( ( status & FlowInfo . POTENTIALLY_NULL ) != 0 ) return FlowInfo . POTENTIALLY_NULL ; return FlowInfo . NON_NULL ; } else if ( ( status & FlowInfo . POTENTIALLY_NULL ) != 0 ) return FlowInfo . POTENTIALLY_NULL ; return status ; } public int mergeCloseStatus ( BlockScope currentScope , int status , LocalVariableBinding local , BlockScope outerScope ) { if ( status != FlowInfo . NON_NULL ) { if ( currentScope . finallyInfo != null ) { int finallyStatus = currentScope . finallyInfo . nullStatus ( local ) ; if ( finallyStatus == FlowInfo . NON_NULL ) return finallyStatus ; if ( finallyStatus != FlowInfo . NULL ) status = FlowInfo . POTENTIALLY_NULL ; } if ( currentScope != outerScope && currentScope . parent instanceof BlockScope ) return mergeCloseStatus ( ( ( BlockScope ) currentScope . parent ) , status , local , outerScope ) ; } return status ; } public void markClose ( FlowInfo flowInfo , FlowContext flowContext ) { FakedTrackingVariable current = this ; do { flowInfo . markAsDefinitelyNonNull ( current . binding ) ; current . globalClosingState |= CLOSE_SEEN ; if ( flowContext . initsOnFinally != null ) flowContext . initsOnFinally . markAsDefinitelyNonNull ( this . binding ) ; current = current . innerTracker ; } while ( current != null ) ; } public void markClosedInNestedMethod ( ) { this . globalClosingState |= CLOSED_IN_NESTED_METHOD ; } public static FlowInfo markPassedToOutside ( BlockScope scope , Expression expression , FlowInfo flowInfo , boolean owned ) { FakedTrackingVariable trackVar = getCloseTrackingVariable ( expression ) ; if ( trackVar != null ) { FlowInfo infoResourceIsClosed = owned ? flowInfo : flowInfo . copy ( ) ; int flag = owned ? OWNED_BY_OUTSIDE : SHARED_WITH_OUTSIDE ; do { trackVar . globalClosingState |= flag ; if ( scope . methodScope ( ) != trackVar . methodScope ) trackVar . globalClosingState |= CLOSED_IN_NESTED_METHOD ; infoResourceIsClosed . markAsDefinitelyNonNull ( trackVar . binding ) ; } while ( ( trackVar = trackVar . innerTracker ) != null ) ; if ( owned ) { return infoResourceIsClosed ; } else { return FlowInfo . conditional ( flowInfo , infoResourceIsClosed ) ; } } return flowInfo ; } public static FakedTrackingVariable pickVarForReporting ( Set varsOfScope , BlockScope scope , boolean atExit ) { if ( varsOfScope . isEmpty ( ) ) return null ; FakedTrackingVariable trackingVar = ( FakedTrackingVariable ) varsOfScope . iterator ( ) . next ( ) ; while ( trackingVar . outerTracker != null ) { if ( varsOfScope . contains ( trackingVar . outerTracker ) ) { trackingVar = trackingVar . outerTracker ; } else if ( atExit ) { break ; } else { BlockScope outerTrackerScope = trackingVar . outerTracker . binding . declaringScope ; if ( outerTrackerScope == scope ) { break ; } else { Scope currentScope = scope ; while ( ( currentScope = currentScope . parent ) instanceof BlockScope ) { if ( outerTrackerScope == currentScope ) { varsOfScope . remove ( trackingVar ) ; return pickVarForReporting ( varsOfScope , scope , atExit ) ; } } break ; } } } varsOfScope . remove ( trackingVar ) ; return trackingVar ; } public boolean hasDefinitelyNoResource ( FlowInfo flowInfo ) { if ( this . originalBinding == null ) return false ; if ( flowInfo . isDefinitelyNull ( this . originalBinding ) ) { return true ; } if ( ! ( flowInfo . isDefinitelyAssigned ( this . originalBinding ) || flowInfo . isPotentiallyAssigned ( this . originalBinding ) ) ) { return true ; } return false ; } public boolean isClosedInFinallyOfEnclosing ( BlockScope scope ) { BlockScope currentScope = scope ; while ( true ) { if ( currentScope . finallyInfo != null && currentScope . finallyInfo . isDefinitelyNonNull ( this . binding ) ) { return true ; } if ( ! ( currentScope . parent instanceof BlockScope ) ) { return false ; } currentScope = ( BlockScope ) currentScope . parent ; } } public boolean isResourceBeingReturned ( FakedTrackingVariable returnedResource ) { FakedTrackingVariable current = this ; do { if ( current == returnedResource ) { this . globalClosingState |= REPORTED_DEFINITIVE_LEAK ; return true ; } current = current . innerTracker ; } while ( current != null ) ; return false ; } public void recordErrorLocation ( ASTNode location , int nullStatus ) { if ( ( this . globalClosingState & OWNED_BY_OUTSIDE ) != 0 ) { return ; } if ( this . recordedLocations == null ) this . recordedLocations = new HashMap ( ) ; this . recordedLocations . put ( location , new Integer ( nullStatus ) ) ; } public boolean reportRecordedErrors ( Scope scope , int mergedStatus ) { FakedTrackingVariable current = this ; while ( current . globalClosingState == 0 ) { current = current . innerTracker ; if ( current == null ) { reportError ( scope . problemReporter ( ) , null , mergedStatus ) ; return true ; } } boolean hasReported = false ; if ( this . recordedLocations != null ) { Iterator locations = this . recordedLocations . entrySet ( ) . iterator ( ) ; int reportFlags = 0 ; while ( locations . hasNext ( ) ) { Map . Entry entry = ( Entry ) locations . next ( ) ; reportFlags |= reportError ( scope . problemReporter ( ) , ( ASTNode ) entry . getKey ( ) , ( ( Integer ) entry . getValue ( ) ) . intValue ( ) ) ; hasReported = true ; } if ( reportFlags != 0 ) { current = this ; do { current . globalClosingState |= reportFlags ; } while ( ( current = current . innerTracker ) != null ) ; } } return hasReported ; } public int reportError ( ProblemReporter problemReporter , ASTNode location , int nullStatus ) { if ( ( this . globalClosingState & OWNED_BY_OUTSIDE ) != 0 ) { return 0 ; } boolean isPotentialProblem = false ; if ( nullStatus == FlowInfo . NULL ) { if ( ( this . globalClosingState & CLOSED_IN_NESTED_METHOD ) != 0 ) isPotentialProblem = true ; } else if ( ( nullStatus & ( FlowInfo . POTENTIALLY_NULL | FlowInfo . POTENTIALLY_NON_NULL ) ) != 0 ) { isPotentialProblem = true ; } if ( isPotentialProblem ) { if ( ( this . globalClosingState & ( REPORTED_POTENTIAL_LEAK | REPORTED_DEFINITIVE_LEAK ) ) != 0 ) return 0 ; problemReporter . potentiallyUnclosedCloseable ( this , location ) ; } else { if ( ( this . globalClosingState & ( REPORTED_DEFINITIVE_LEAK ) ) != 0 ) return 0 ; problemReporter . unclosedCloseable ( this , location ) ; } int reportFlag = isPotentialProblem ? REPORTED_POTENTIAL_LEAK : REPORTED_DEFINITIVE_LEAK ; if ( location == null ) { FakedTrackingVariable current = this ; do { current . globalClosingState |= reportFlag ; } while ( ( current = current . innerTracker ) != null ) ; } return reportFlag ; } public void reportExplicitClosing ( ProblemReporter problemReporter ) { if ( ( this . globalClosingState & ( OWNED_BY_OUTSIDE | REPORTED_EXPLICIT_CLOSE ) ) == 0 ) { this . globalClosingState |= REPORTED_EXPLICIT_CLOSE ; problemReporter . explicitlyClosedAutoCloseable ( this ) ; } } public void resetReportingBits ( ) { FakedTrackingVariable current = this ; do { current . globalClosingState &= ~ ( REPORTED_POTENTIAL_LEAK | REPORTED_DEFINITIVE_LEAK ) ; current = current . innerTracker ; } while ( current != null ) ; } } </s>