diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/FakedTrackingVariable.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/FakedTrackingVariable.java index a7314183121..9fb248d2c31 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/FakedTrackingVariable.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/FakedTrackingVariable.java @@ -499,7 +499,7 @@ public static void analyseCloseableAllocation(BlockScope scope, FlowInfo flowInf * Check if a message send acquires a closeable from its receiver, see: * Bug 463320 - [compiler][resource] potential "resource leak" problem disappears when local variable inlined */ - public static FlowInfo analyseCloseableAcquisition(BlockScope scope, FlowInfo flowInfo, MessageSend acquisition) { + public static FlowInfo analyseCloseableAcquisition(BlockScope scope, FlowInfo flowInfo, FlowContext flowContext, MessageSend acquisition) { if (isFluentMethod(acquisition.binding)) { // share the existing close tracker of the receiver (if any): acquisition.closeTracker = findCloseTracker(scope, flowInfo, acquisition.receiver); @@ -542,7 +542,7 @@ public static FlowInfo analyseCloseableAcquisition(BlockScope scope, FlowInfo fl tracker.acquisition = acquisition; FlowInfo outsideInfo = flowInfo.copy(); outsideInfo.markAsDefinitelyNonNull(tracker.binding); - flowInfo.markAsDefinitelyNull(tracker.binding); + tracker.markNullStatus(flowInfo, flowContext, FlowInfo.NULL); return FlowInfo.conditional(outsideInfo, flowInfo); } } @@ -619,13 +619,13 @@ private static void handleRegularResource(BlockScope scope, FlowInfo flowInfo, F int finallyNullStatus = enclosingFinallyInfo.nullStatus(presetTracker.binding); enclosingFinallyInfo.markNullStatus(local.closeTracker.binding, finallyNullStatus); } - presetTracker.markUnknown(flowInfo, flowContext); // no longer relevant in this flow + presetTracker.markNullStatus(flowInfo, flowContext, FlowInfo.UNKNOWN); // no longer relevant in this flow } } } else { allocation.closeTracker = new FakedTrackingVariable(scope, allocation, flowInfo, FlowInfo.UNKNOWN); // no local available, closeable is unassigned } - flowInfo.markAsDefinitelyNull(allocation.closeTracker.binding); + allocation.closeTracker.markNullStatus(flowInfo, flowContext, FlowInfo.NULL); } /** Was this FTV created from the finally block of the current context? */ @@ -771,7 +771,7 @@ public static void handleResourceAssignment(BlockScope scope, FlowInfo upstreamI // re-assigning from a fresh value, mark as not-closed again: if ((previousTracker.globalClosingState & (SHARED_WITH_OUTSIDE|OWNED_BY_OUTSIDE|FOREACH_ELEMENT_VAR)) == 0 && flowInfo.hasNullInfoFor(previousTracker.binding)) // avoid spilling info into a branch that doesn't see the corresponding resource - flowInfo.markAsDefinitelyNull(previousTracker.binding); + previousTracker.markNullStatus(flowInfo, flowContext, FlowInfo.NULL); local.closeTracker = analyseCloseableExpression(scope, flowInfo, flowContext, useAnnotations, local, location, rhs, previousTracker); } } else { // 3. no re-use, create a fresh tracking variable: @@ -781,7 +781,7 @@ public static void handleResourceAssignment(BlockScope scope, FlowInfo upstreamI if (!useAnnotations) { // a fresh resource, mark as not-closed: if ((rhsTrackVar.globalClosingState & (SHARED_WITH_OUTSIDE|OWNED_BY_OUTSIDE|FOREACH_ELEMENT_VAR)) == 0) - flowInfo.markAsDefinitelyNull(rhsTrackVar.binding); + rhsTrackVar.markNullStatus(flowInfo, flowContext, FlowInfo.NULL); } // TODO(stephan): this might be useful, but I could not find a test case for it: // if (flowContext.initsOnFinally != null) @@ -843,7 +843,7 @@ public static void handleResourceFieldAssignment(BlockScope scope, FlowInfo flow } if (field != null) { if (!field.isStatic() && (field.tagBits & TagBits.AnnotationOwning) != 0) { - flowInfo.markAsDefinitelyNonNull(rhsTrackVar.binding); + rhsTrackVar.markNullStatus(flowInfo, flowContext, FlowInfo.NON_NULL); } else { rhsTrackVar.markAsShared(); } @@ -1186,10 +1186,10 @@ public void markClose(FlowInfo flowInfo, FlowContext flowContext) { }); } - private void markUnknown(FlowInfo flowInfo, FlowContext flowContext) { + public void markNullStatus(FlowInfo flowInfo, FlowContext flowContext, int status) { markAllConnected(current -> { - flowInfo.markAsDefinitelyUnknown(current.binding); - flowContext.markFinallyNullStatus(current.binding, FlowInfo.UNKNOWN); + flowInfo.markNullStatus(current.binding, status); + flowContext.markFinallyNullStatus(current.binding, status); }); } @@ -1245,7 +1245,7 @@ public static FlowInfo markPassedToOutside(BlockScope scope, Expression expressi ftv.globalClosingState |= flag; if (scope.methodScope() != ftv.methodScope) ftv.globalClosingState |= CLOSED_IN_NESTED_METHOD; - infoResourceIsClosed.markAsDefinitelyNonNull(ftv.binding); + ftv.markNullStatus(flowInfo, flowContext, FlowInfo.NON_NULL); }); if (owned) { return infoResourceIsClosed; // don't let downstream signal any problems on this flow diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/MessageSend.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/MessageSend.java index 3853f146da5..55e33065db8 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/MessageSend.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/MessageSend.java @@ -264,7 +264,7 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl } // after having analysed exceptions above start tracking newly allocated resource: if (analyseResources && FakedTrackingVariable.isAnyCloseable(this.resolvedType)) - flowInfo = FakedTrackingVariable.analyseCloseableAcquisition(currentScope, flowInfo, this); + flowInfo = FakedTrackingVariable.analyseCloseableAcquisition(currentScope, flowInfo, flowContext, this); manageSyntheticAccessIfNecessary(currentScope, flowInfo); // account for pot. exceptions thrown by method execution diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ResourceLeakAnnotatedTests.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ResourceLeakAnnotatedTests.java index 3845cc352a0..5586ff233e8 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ResourceLeakAnnotatedTests.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ResourceLeakAnnotatedTests.java @@ -1337,4 +1337,28 @@ static void test3(String name) throws Exception { """, null); } +public void testWrappingTwoResources() { + runLeakTestWithAnnotations( + new String[] { + "X.java", + """ + import java.io.*; + import org.eclipse.jdt.annotation.*; + public class X implements AutoCloseable { + private final @Owning DataInputStream fDataIn; + private final @Owning DataOutputStream fDataOut; + public X(@Owning InputStream in, @Owning OutputStream out) { + fDataIn = new DataInputStream(new BufferedInputStream(in)); + fDataOut = new DataOutputStream(new BufferedOutputStream(out)); + } + public void close() throws IOException { + fDataIn.close(); + fDataOut.close(); + } + } + """ + }, + "", + null); +} }