diff options
author | Stephan Herrmann | 2019-12-25 21:52:01 +0000 |
---|---|---|
committer | Stephan Herrmann | 2019-12-25 22:18:45 +0000 |
commit | 956124562eb3b9e814a13212d1ed4c2577a40178 (patch) | |
tree | 09352b5d50a8a38d189029e410ff7a2c4a1b01ee | |
parent | abfd074d566b02cad792fdd003f292c2ebd53ad0 (diff) | |
download | eclipse.jdt.core-956124562eb3b9e814a13212d1ed4c2577a40178.tar.gz eclipse.jdt.core-956124562eb3b9e814a13212d1ed4c2577a40178.tar.xz eclipse.jdt.core-956124562eb3b9e814a13212d1ed4c2577a40178.zip |
Bug 552521 - [resource] warning against '<unassigned Closeable value>'
is weakened to "potential" inside "if"
Change-Id: I79f6397e6a1e022a90c6272008d6cd667f25599f
3 files changed, 174 insertions, 2 deletions
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 232019db46..e044f14439 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 @@ -5849,4 +5849,160 @@ public void testBug463320_comment19() { }, options); } +public void testBug552521() { + if (this.complianceLevel < ClassFileConstants.JDK1_7) return; // uses try-with-resources + + Map options = getCompilerOptions(); + options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR); + options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.WARNING); + runLeakTest( + new String[] { + "EclipseBug552521getChannel.java", + "import java.io.File;\n" + + "import java.io.FileInputStream;\n" + + "import java.io.FileOutputStream;\n" + + "import java.nio.channels.FileChannel;\n" + + "\n" + + "public class EclipseBug552521getChannel {\n" + + "\n" + + " @SuppressWarnings(\"unused\")\n" + + " public void copyFile(final File srcFile, final File dstFile) throws Exception {\n" + + " /*\n" + + " * TODO Eclipse Setting: Window/Preferences/Java/Compiler/Errors-Warnings/\n" + + " * Resource not managed via try-with-resource = Ignore (default)\n" + + " */\n" + + " try (\n" + + " final FileInputStream srcStream = new FileInputStream (srcFile);\n" + + " final FileChannel srcChannel = srcStream.getChannel();\n" + + " final FileChannel dstChannel = new FileOutputStream(dstFile) .getChannel();\n" + // line 17 + " // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TODO Warning ok\n" + + " )\n" + + " {\n" + + " srcChannel.transferTo(0, srcChannel.size(), dstChannel);\n" + + " }\n" + + "\n" + + " if (srcFile.isFile()) { // \"if\" (resolved at runtime) -> Warning suppressed\n" + + " try (\n" + + " final FileInputStream srcStream = new FileInputStream (srcFile);\n" + + " final FileChannel srcChannel = srcStream.getChannel();\n" + + " final FileChannel dstChannel = new FileOutputStream(dstFile) .getChannel();\n" + // line 28 + " // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ FIXME Warning missing!\n" + + " )\n" + + " {\n" + + " srcChannel.transferTo(0, srcChannel.size(), dstChannel);\n" + + " }\n" + + " } else { // \"else\" (resolved at runtime) -> Warning suppressed\n" + + " try (\n" + + " final FileInputStream srcStream = new FileInputStream (srcFile);\n" + + " final FileChannel srcChannel = srcStream.getChannel();\n" + + " final FileChannel dstChannel = new FileOutputStream(dstFile) .getChannel();\n" + // line 38 + " // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ FIXME Warning missing!\n" + + " )\n" + + " {\n" + + " srcChannel.transferTo(0, srcChannel.size(), dstChannel);\n" + + " }\n" + + " }\n" + + "\n" + + " if (true) { // Dummy \"if\" (= constant true) -> Warning\n" + + " try (\n" + + " final FileInputStream srcStream = new FileInputStream (srcFile);\n" + + " final FileChannel srcChannel = srcStream.getChannel();\n" + + " final FileChannel dstChannel = new FileOutputStream(dstFile) .getChannel();\n" + // line 50 + " // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TODO Warning ok\n" + + " )\n" + + " {\n" + + " srcChannel.transferTo(0, srcChannel.size(), dstChannel);\n" + + " }\n" + + " } else { // Dummy \"else\" (= constant false) -> Warning suppressed\n" + + " try (\n" + + " final FileInputStream srcStream = new FileInputStream (srcFile);\n" + + " final FileChannel srcChannel = srcStream.getChannel();\n" + + " final FileChannel dstChannel = new FileOutputStream(dstFile) .getChannel();\n" + // line 60 + " // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ FIXME Warning missing!\n" + + " )\n" + + " {\n" + + " srcChannel.transferTo(0, srcChannel.size(), dstChannel);\n" + + " }\n" + + " }\n" + + "\n" + + " if (false) { // Dummy \"if\" (= constant false) -> Warning suppressed\n" + + " try (\n" + + " final FileInputStream srcStream = new FileInputStream (srcFile);\n" + + " final FileChannel srcChannel = srcStream.getChannel();\n" + + " final FileChannel dstChannel = new FileOutputStream(dstFile) .getChannel();\n" + // line 72 + " // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ FIXME Warning missing!\n" + + " )\n" + + " {\n" + + " srcChannel.transferTo(0, srcChannel.size(), dstChannel);\n" + + " }\n" + + " } else { // Dummy \"else\" (= constant true) -> Warning\n" + + " try (\n" + + " final FileInputStream srcStream = new FileInputStream (srcFile);\n" + + " final FileChannel srcChannel = srcStream.getChannel();\n" + + " final FileChannel dstChannel = new FileOutputStream(dstFile) .getChannel();\n" + // line 82 + " // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TODO Warning ok\n" + + " )\n" + + " {\n" + + " srcChannel.transferTo(0, srcChannel.size(), dstChannel);\n" + + " }\n" + + " }\n" + + " /*\n" + + " * Following test-case differs from all the above as follows:\n" + + " * FileInputStream is unassigned, instead of FileOutputStream\n" + + " */\n" + + " try (\n" + + " final FileChannel srcChannel = new FileInputStream (srcFile) .getChannel();\n" + // line 94 + " // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TODO Warning ok\n" + + " final FileOutputStream dstStream = new FileOutputStream(srcFile);\n" + + " final FileChannel dstChannel = dstStream.getChannel();\n" + + " )\n" + + " {\n" + + " srcChannel.transferTo(0, srcChannel.size(), dstChannel);\n" + + " }\n" + + " }\n" + + "}\n" + }, + "----------\n" + + "1. ERROR in EclipseBug552521getChannel.java (at line 17)\n" + + " final FileChannel dstChannel = new FileOutputStream(dstFile) .getChannel();\n" + + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + + "Resource leak: \'<unassigned Closeable value>\' is never closed\n" + + "----------\n" + + "2. ERROR in EclipseBug552521getChannel.java (at line 28)\n" + + " final FileChannel dstChannel = new FileOutputStream(dstFile) .getChannel();\n" + + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + + "Resource leak: \'<unassigned Closeable value>\' is never closed\n" + + "----------\n" + + "3. ERROR in EclipseBug552521getChannel.java (at line 38)\n" + + " final FileChannel dstChannel = new FileOutputStream(dstFile) .getChannel();\n" + + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + + "Resource leak: \'<unassigned Closeable value>\' is never closed\n" + + "----------\n" + + "4. ERROR in EclipseBug552521getChannel.java (at line 50)\n" + + " final FileChannel dstChannel = new FileOutputStream(dstFile) .getChannel();\n" + + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + + "Resource leak: \'<unassigned Closeable value>\' is never closed\n" + + "----------\n" + + "5. ERROR in EclipseBug552521getChannel.java (at line 60)\n" + + " final FileChannel dstChannel = new FileOutputStream(dstFile) .getChannel();\n" + + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + + "Resource leak: \'<unassigned Closeable value>\' is never closed\n" + + "----------\n" + + "6. ERROR in EclipseBug552521getChannel.java (at line 72)\n" + + " final FileChannel dstChannel = new FileOutputStream(dstFile) .getChannel();\n" + + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + + "Resource leak: \'<unassigned Closeable value>\' is never closed\n" + + "----------\n" + + "7. ERROR in EclipseBug552521getChannel.java (at line 82)\n" + + " final FileChannel dstChannel = new FileOutputStream(dstFile) .getChannel();\n" + + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + + "Resource leak: \'<unassigned Closeable value>\' is never closed\n" + + "----------\n" + + "8. ERROR in EclipseBug552521getChannel.java (at line 94)\n" + + " final FileChannel srcChannel = new FileInputStream (srcFile) .getChannel();\n" + + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + + "Resource leak: \'<unassigned Closeable value>\' is never closed\n" + + "----------\n", + options); +} } 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 1ffed5baae..9bb4aa893e 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 @@ -790,8 +790,13 @@ public class FakedTrackingVariable extends LocalDeclaration { if ((status & FlowInfo.POTENTIALLY_NULL) != 0) return FlowInfo.POTENTIALLY_NULL; // non-null + doubt = pot null return FlowInfo.NON_NULL; - } else if ((status & FlowInfo.POTENTIALLY_NULL) != 0) + } else if ((status & FlowInfo.POTENTIALLY_NULL) != 0) { return FlowInfo.POTENTIALLY_NULL; + } else if (status == FlowInfo.UNKNOWN) { + // if unassigned resource (not having an originalBinding) is not withdrawn it is unclosed: + if (this.originalBinding == null) + return FlowInfo.NULL; + } return status; } 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 bf4ea57df6..a21beb4742 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 @@ -1167,8 +1167,19 @@ public void correlateTrackingVarsIfElse(FlowInfo thenFlowInfo, FlowInfo elseFlow int trackVarCount = this.trackingVariables.size(); for (int i=0; i<trackVarCount; i++) { FakedTrackingVariable trackingVar = (FakedTrackingVariable) this.trackingVariables.get(i); - if (trackingVar.originalBinding == null) + if (trackingVar.originalBinding == null) { + // avoid problem weakened to 'potential' if unassigned resource exists only in one branch: + boolean hasNullInfoInThen = thenFlowInfo.hasNullInfoFor(trackingVar.binding); + boolean hasNullInfoInElse = elseFlowInfo.hasNullInfoFor(trackingVar.binding); + if (hasNullInfoInThen && !hasNullInfoInElse) { + int nullStatus = thenFlowInfo.nullStatus(trackingVar.binding); + elseFlowInfo.markNullStatus(trackingVar.binding, nullStatus); + } else if (!hasNullInfoInThen && hasNullInfoInElse) { + int nullStatus = elseFlowInfo.nullStatus(trackingVar.binding); + thenFlowInfo.markNullStatus(trackingVar.binding, nullStatus); + } continue; + } if ( thenFlowInfo.isDefinitelyNonNull(trackingVar.binding) // closed in then branch && elseFlowInfo.isDefinitelyNull(trackingVar.originalBinding)) // null in else branch { |