diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ResourceLeakTests.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ResourceLeakTests.java index 1dfb83c..d0786ca 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ResourceLeakTests.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ResourceLeakTests.java @@ -2702,21 +2702,21 @@ public void test063a() throws IOException { " }\n" + "}\n" }, - "----------\n" + - "1. ERROR in X.java (at line 8)\n" + - " BufferedInputStream bis = new BufferedInputStream(stream); // never since reassigned\n" + - " ^^^\n" + - "Resource leak: \'bis\' is never closed\n" + - "----------\n" + - "2. ERROR in X.java (at line 9)\n" + - " FileInputStream stream2 = new FileInputStream(file); // unsure since passed to method\n" + - " ^^^^^^^\n" + - "Potential resource leak: \'stream2\' may not be closed\n" + - "----------\n" + - "3. ERROR in X.java (at line 10)\n" + - " bis = getReader(stream2); // unsure since obtained from method\n" + - " ^^^^^^^^^^^^^^^^^^^^^^^^\n" + - "Potential resource leak: \'bis\' may not be closed\n" + + "----------\n" + + "1. ERROR in X.java (at line 7)\n" + + " FileInputStream stream = new FileInputStream(file);\n" + + " ^^^^^^\n" + + "Resource leak: \'stream\' is never closed\n" + + "----------\n" + + "2. ERROR in X.java (at line 9)\n" + + " FileInputStream stream2 = new FileInputStream(file); // unsure since passed to method\n" + + " ^^^^^^^\n" + + "Potential resource leak: \'stream2\' may not be closed\n" + + "----------\n" + + "3. ERROR in X.java (at line 10)\n" + + " bis = getReader(stream2); // unsure since obtained from method\n" + + " ^^^^^^^^^^^^^^^^^^^^^^^^\n" + + "Potential resource leak: \'bis\' may not be closed\n" + "----------\n", null, true, diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java index e328f12..ea1af7b 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java @@ -64,7 +64,7 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl .unconditionalInits(); if (shouldAnalyseResource) - FakedTrackingVariable.handleResourceAssignment(preInitInfo, flowInfo, this, this.expression, local); + FakedTrackingVariable.handleResourceAssignment(currentScope, preInitInfo, flowInfo, this, this.expression, local); else FakedTrackingVariable.cleanUpAfterAssignment(currentScope, this.lhs.bits, this.expression); diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FakedTrackingVariable.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FakedTrackingVariable.java index 0d2cbe9..b39419e 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FakedTrackingVariable.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FakedTrackingVariable.java @@ -284,6 +284,7 @@ public class FakedTrackingVariable extends LocalDeclaration { /** * Check if the rhs of an assignment or local declaration is an (Auto)Closeable. * If so create or re-use a tracking variable, and wire and initialize everything. + * @param scope scope containing the assignment * @param upstreamInfo info without analysis of the rhs, use this to determine the status of a resource being disconnected * @param flowInfo info with analysis of the rhs, use this for recording resource status because this will be passed downstream * @param location where to report warnigs/errors against @@ -291,7 +292,7 @@ public class FakedTrackingVariable extends LocalDeclaration { * The caller has already checked that the rhs is either of a closeable type or null. * @param local the local variable into which the rhs is being assigned */ - public static void handleResourceAssignment(FlowInfo upstreamInfo, FlowInfo flowInfo, ASTNode location, Expression rhs, LocalVariableBinding local) + public static void handleResourceAssignment(BlockScope scope, FlowInfo upstreamInfo, FlowInfo flowInfo, ASTNode location, Expression rhs, LocalVariableBinding local) { // does the LHS (local) already have a tracker, indicating we may leak a resource by the assignment? FakedTrackingVariable previousTracker = null; @@ -338,9 +339,14 @@ public class FakedTrackingVariable extends LocalDeclaration { } if (disconnectedTracker != null) { - int upstreamStatus = upstreamInfo.nullStatus(disconnectedTracker.binding); - if (upstreamStatus != FlowInfo.NON_NULL) - disconnectedTracker.recordErrorLocation(location, upstreamStatus); + 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); + } } } /** diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java index 239ef15..91808db 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java @@ -91,7 +91,7 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl .unconditionalInits(); if (shouldAnalyseResource) - FakedTrackingVariable.handleResourceAssignment(preInitInfo, flowInfo, this, this.initialization, this.binding); + FakedTrackingVariable.handleResourceAssignment(currentScope, preInitInfo, flowInfo, this, this.initialization, this.binding); else FakedTrackingVariable.cleanUpAfterAssignment(currentScope, Binding.LOCAL, this.initialization); diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java index 24ad91f..30c8198 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java @@ -993,6 +993,10 @@ public void removeTrackingVar(FakedTrackingVariable trackingVariable) { if (this.parent instanceof BlockScope) ((BlockScope)this.parent).removeTrackingVar(trackingVariable); } +/** Unregister a wrapper resource without affecting its inner. */ +public void pruneWrapperTrackingVar(FakedTrackingVariable trackingVariable) { + this.trackingVariables.remove(trackingVariable); +} /** * At the end of a block check the closing-status of all tracked closeables that are declared in this block. * Also invoked when entering unreachable code.