Download
Getting Started
Members
Projects
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
More
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
Toggle navigation
Bugzilla – Attachment 209234 Details for
Bug 358903
Filter practically unimportant resource leak warnings
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
Log In
[x]
|
Terms of Use
|
Copyright Agent
[patch]
Tests & fix v0.9.6
Bug_358903_v0.9.6.patch (text/plain), 96.79 KB, created by
Stephan Herrmann
on 2012-01-09 18:03:57 EST
(
hide
)
Description:
Tests & fix v0.9.6
Filename:
MIME Type:
Creator:
Stephan Herrmann
Created:
2012-01-09 18:03:57 EST
Size:
96.79 KB
patch
obsolete
>diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/TryWithResourcesStatementTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/TryWithResourcesStatementTest.java >index f21a57f..9660125 100644 >--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/TryWithResourcesStatementTest.java >+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/TryWithResourcesStatementTest.java >@@ -11,11 +11,21 @@ > * bug 358827 - [1.7] exception analysis for t-w-r spoils null analysis > * bug 349326 - [1.7] new warning for missing try-with-resources > * bug 359334 - Analysis for resource leak warnings does not consider exceptions as method exit points >+ * bug 358903 - Filter practically unimportant resource leak warnings >+ * bug 360908 - Avoid resource leak warning when the underlying/chained resource is closed explicitly >+ * bug 361073 - Avoid resource leak warning when the top level resource is closed explicitly >+ * bug 362331 - Resource leak not detected when closeable not assigned to variable >+ * bug 362332 - Only report potential leak when closeable not created in the local scope > *******************************************************************************/ > package org.eclipse.jdt.core.tests.compiler.regression; > >+import java.io.IOException; >+import java.net.URL; > import java.util.Map; > >+import org.eclipse.core.runtime.FileLocator; >+import org.eclipse.core.runtime.Path; >+import org.eclipse.core.runtime.Platform; > import org.eclipse.jdt.core.JavaCore; > import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; > >@@ -23,7 +33,7 @@ > public class TryWithResourcesStatementTest extends AbstractRegressionTest { > > static { >-// TESTS_NAMES = new String[] { "test056throw"}; >+// TESTS_NAMES = new String[] { "test061a"}; > // TESTS_NUMBERS = new int[] { 50 }; > // TESTS_RANGE = new int[] { 11, -1 }; > } >@@ -3713,11 +3723,12 @@ > options); > } > // Bug 349326 - [1.7] new warning for missing try-with-resources >+// Bug 362332 - Only report potential leak when closeable not created in the local scope > // one method returns an AutoCleasble, a second method uses this object without ever closing it. > public void test056e() { > Map options = getCompilerOptions(); > options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR); >- options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.WARNING); >+ options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR); > this.runNegativeTest( > new String[] { > "X.java", >@@ -3744,7 +3755,7 @@ > "1. ERROR in X.java (at line 11)\n" + > " FileReader reader = getReader(\"somefile\");\n" + > " ^^^^^^\n" + >- "Resource leak: 'reader' is never closed\n" + >+ "Potential resource leak: \'reader\' may not be closed\n" + > "----------\n", > null, > true, >@@ -3964,6 +3975,46 @@ > null, > true, > options); >+} >+// Bug 349326 - [1.7] new warning for missing try-with-resources >+// three AutoCloseables in different blocks of the same method - problems ignored >+public void test056i_ignore() { >+ Map options = getCompilerOptions(); >+ options.put(JavaCore.COMPILER_PB_UNCLOSED_CLOSEABLE, CompilerOptions.IGNORE); >+ options.put(JavaCore.COMPILER_PB_POTENTIALLY_UNCLOSED_CLOSEABLE, CompilerOptions.IGNORE); >+ options.put(JavaCore.COMPILER_PB_EXPLICITLY_CLOSED_AUTOCLOSEABLE, CompilerOptions.IGNORE); >+ this.runConformTest( >+ new String[] { >+ "X.java", >+ "import java.io.File;\n" + >+ "import java.io.FileReader;\n" + >+ "import java.io.IOException;\n" + >+ "public class X {\n" + >+ " void foo(boolean f1, boolean f2) throws IOException {\n" + >+ " File file = new File(\"somefile\");\n" + >+ " if (f1) {\n" + >+ " FileReader fileReader = new FileReader(file); // err: not closed\n" + >+ " char[] in = new char[50];\n" + >+ " fileReader.read(in);\n" + >+ " while (true) {\n" + >+ " FileReader loopReader = new FileReader(file); // don't warn, properly closed\n" + >+ " loopReader.close();" + >+ " break;\n" + >+ " }\n" + >+ " } else {\n" + >+ " FileReader fileReader = new FileReader(file); // warn: not closed on all paths\n" + >+ " if (f2)\n" + >+ " fileReader.close();\n" + >+ " }\n" + >+ " }\n" + >+ "}\n" >+ }, >+ "", >+ null, >+ true, >+ null, >+ options, >+ null); > } > // Bug 349326 - [1.7] new warning for missing try-with-resources > // three AutoCloseables in different blocks of the same method >@@ -4358,11 +4409,12 @@ > null/*requestor*/); > } > // Bug 349326 - [1.7] new warning for missing try-with-resources >+// Bug 362332 - Only report potential leak when closeable not created in the local scope > // a method uses an AutoCloseable without ever closing it, type from a type variable > public void test056p() { > Map options = getCompilerOptions(); > options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR); >- options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.WARNING); >+ options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR); > this.runNegativeTest( > new String[] { > "X.java", >@@ -4389,7 +4441,7 @@ > "1. ERROR in X.java (at line 8)\n" + > " T fileReader = newReader(file);\n" + > " ^^^^^^^^^^\n" + >- "Resource leak: 'fileReader' is never closed\n" + >+ "Potential resource leak: \'fileReader\' may not be closed\n" + > "----------\n", > null, > true, >@@ -4444,7 +4496,7 @@ > options); > } > // Bug 349326 - [1.7] new warning for missing try-with-resources >-// closed in dead code >+// properly closed, dead code in between > public void test056r() { > Map options = getCompilerOptions(); > options.put(JavaCore.COMPILER_PB_UNCLOSED_CLOSEABLE, CompilerOptions.ERROR); >@@ -5354,7 +5406,723 @@ > "X::~X\n" + > "true"); > } >- >+// Bug 358903 - Filter practically unimportant resource leak warnings >+// Bug 360908 - Avoid resource leak warning when the underlying/chained resource is closed explicitly >+// a resource wrapper is not closed but the underlying resource is >+public void test061a() { >+ Map options = getCompilerOptions(); >+ options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR); >+ options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR); >+ this.runConformTest( >+ new String[] { >+ "X.java", >+ "import java.io.File;\n" + >+ "import java.io.BufferedInputStream;\n" + >+ "import java.io.FileInputStream;\n" + >+ "import java.io.IOException;\n" + >+ "public class X {\n" + >+ " void foo() throws IOException {\n" + >+ " File file = new File(\"somefile\");\n" + >+ " FileInputStream fileStream = new FileInputStream(file);\n" + >+ " BufferedInputStream bis = new BufferedInputStream(fileStream);\n" + >+ " BufferedInputStream doubleWrap = new BufferedInputStream(bis);\n" + >+ " System.out.println(bis.available());\n" + >+ " fileStream.close();\n" + >+ " }\n" + >+ " void inline() throws IOException {\n" + >+ " File file = new File(\"somefile\");\n" + >+ " FileInputStream fileStream;\n" + >+ " BufferedInputStream bis = new BufferedInputStream(fileStream = new FileInputStream(file));\n" + >+ " System.out.println(bis.available());\n" + >+ " fileStream.close();\n" + >+ " }\n" + >+ " public static void main(String[] args) throws IOException {\n" + >+ " try {\n" + >+ " new X().foo();\n" + >+ " } catch (IOException ex) {" + >+ " System.out.println(\"Got IO Exception\");\n" + >+ " }\n" + >+ " }\n" + >+ "}\n" >+ }, >+ "Got IO Exception", >+ null, >+ true, >+ null, >+ options, >+ null); >+} >+// Bug 358903 - Filter practically unimportant resource leak warnings >+// a closeable without OS resource is not closed >+public void test061b() { >+ Map options = getCompilerOptions(); >+ options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR); >+ options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR); >+ this.runConformTest( >+ new String[] { >+ "X.java", >+ "import java.io.StringReader;\n" + >+ "import java.io.IOException;\n" + >+ "public class X {\n" + >+ " void foo() throws IOException {\n" + >+ " StringReader string = new StringReader(\"content\");\n" + >+ " System.out.println(string.read());\n" + >+ " }\n" + >+ " public static void main(String[] args) throws IOException {\n" + >+ " new X().foo();\n" + >+ " }\n" + >+ "}\n" >+ }, >+ "99", // character 'c' >+ null, >+ true, >+ null, >+ options, >+ null); >+} >+// Bug 358903 - Filter practically unimportant resource leak warnings >+// a resource wrapper is not closed but the underlying closeable is resource-free >+public void test061c() { >+ Map options = getCompilerOptions(); >+ options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR); >+ options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR); >+ this.runConformTest( >+ new String[] { >+ "X.java", >+ "import java.io.BufferedReader;\n" + >+ "import java.io.StringReader;\n" + >+ "import java.io.IOException;\n" + >+ "public class X {\n" + >+ " void foo() throws IOException {\n" + >+ " StringReader input = new StringReader(\"content\");\n" + >+ " BufferedReader br = new BufferedReader(input);\n" + >+ " BufferedReader doubleWrap = new BufferedReader(br);\n" + >+ " System.out.println(br.read());\n" + >+ " }\n" + >+ " void inline() throws IOException {\n" + >+ " BufferedReader br = new BufferedReader(new StringReader(\"content\"));\n" + >+ " System.out.println(br.read());\n" + >+ " }\n" + >+ " public static void main(String[] args) throws IOException {\n" + >+ " new X().foo();\n" + >+ " }\n" + >+ "}\n" >+ }, >+ "99", >+ null, >+ true, >+ null, >+ options, >+ null); >+} >+// Bug 358903 - Filter practically unimportant resource leak warnings >+// a resource wrapper is not closed neither is the underlying resource >+public void test061d() { >+ Map options = getCompilerOptions(); >+ options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR); >+ options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.WARNING); >+ this.runNegativeTest( >+ new String[] { >+ "X.java", >+ "import java.io.File;\n" + >+ "import java.io.BufferedInputStream;\n" + >+ "import java.io.FileInputStream;\n" + >+ "import java.io.IOException;\n" + >+ "public class X {\n" + >+ " void foo() throws IOException {\n" + >+ " File file = new File(\"somefile\");\n" + >+ " FileInputStream fileStream = new FileInputStream(file);\n" + >+ " BufferedInputStream bis = new BufferedInputStream(fileStream);\n" + >+ " BufferedInputStream doubleWrap = new BufferedInputStream(bis);\n" + >+ " System.out.println(bis.available());\n" + >+ " }\n" + >+ " void inline() throws IOException {\n" + >+ " File file = new File(\"somefile\");\n" + >+ " BufferedInputStream bis2 = new BufferedInputStream(new FileInputStream(file));\n" + >+ " System.out.println(bis2.available());\n" + >+ " }\n" + >+ " public static void main(String[] args) throws IOException {\n" + >+ " try {\n" + >+ " new X().foo();\n" + >+ " } catch (IOException ex) {" + >+ " System.out.println(\"Got IO Exception\");\n" + >+ " }\n" + >+ " }\n" + >+ "}\n" >+ }, >+ "----------\n" + >+ "1. ERROR in X.java (at line 10)\n" + >+ " BufferedInputStream doubleWrap = new BufferedInputStream(bis);\n" + >+ " ^^^^^^^^^^\n" + >+ "Resource leak: \'doubleWrap\' is never closed\n" + >+ "----------\n" + >+ "2. ERROR in X.java (at line 15)\n" + >+ " BufferedInputStream bis2 = new BufferedInputStream(new FileInputStream(file));\n" + >+ " ^^^^\n" + >+ "Resource leak: \'bis2\' is never closed\n" + >+ "----------\n", >+ null, >+ true, >+ options); >+} >+// Bug 358903 - Filter practically unimportant resource leak warnings >+// Bug 361073 - Avoid resource leak warning when the top level resource is closed explicitly >+// a resource wrapper is closed closing also the underlying resource >+public void test061e() { >+ Map options = getCompilerOptions(); >+ options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR); >+ options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR); >+ this.runConformTest( >+ new String[] { >+ "X.java", >+ "import java.io.File;\n" + >+ "import java.io.BufferedInputStream;\n" + >+ "import java.io.FileInputStream;\n" + >+ "import java.io.IOException;\n" + >+ "public class X {\n" + >+ " FileInputStream fis;" + >+ " void foo() throws IOException {\n" + >+ " File file = new File(\"somefile\");\n" + >+ " FileInputStream fileStream = new FileInputStream(file);\n" + >+ " BufferedInputStream bis = new BufferedInputStream(fileStream);\n" + >+ " BufferedInputStream doubleWrap = new BufferedInputStream(bis);\n" + >+ " System.out.println(bis.available());\n" + >+ " bis.close();\n" + >+ " }\n" + >+ " void inline() throws IOException {\n" + >+ " File file = new File(\"somefile\");\n" + >+ " BufferedInputStream bis2 = new BufferedInputStream(fis = new FileInputStream(file));\n" + // field assignment >+ " System.out.println(bis2.available());\n" + >+ " bis2.close();\n" + >+ " FileInputStream fileStream = null;\n" + >+ " BufferedInputStream bis3 = new BufferedInputStream(fileStream = new FileInputStream(file));\n" + >+ " System.out.println(bis3.available());\n" + >+ " bis3.close();\n" + >+ " }\n" + >+ " public static void main(String[] args) throws IOException {\n" + >+ " try {\n" + >+ " new X().foo();\n" + >+ " } catch (IOException ex) {" + >+ " System.out.println(\"Got IO Exception\");\n" + >+ " }\n" + >+ " }\n" + >+ "}\n" >+ }, >+ "Got IO Exception", >+ null, >+ true, >+ null, >+ options, >+ null); >+} >+// Bug 358903 - Filter practically unimportant resource leak warnings >+// Bug 361073 - Avoid resource leak warning when the top level resource is closed explicitly >+// a resource wrapper is closed closing also the underlying resource - original test case >+public void test061f() throws IOException { >+ Map options = getCompilerOptions(); >+ options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR); >+ options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR); >+ URL url = FileLocator.toFileURL(FileLocator.find(Platform.getBundle("org.eclipse.jdt.core.tests.compiler"), new Path("META-INF/MANIFEST.MF"), null)); >+ this.runConformTest( >+ new String[] { >+ "X.java", >+ "import java.io.InputStream;\n" + >+ "import java.io.InputStreamReader;\n" + >+ "import java.io.BufferedReader;\n" + >+ "import java.io.IOException;\n" + >+ "import java.net.URL;\n" + >+ "public class X {\n" + >+ " boolean loadURL(final URL url) throws IOException {\n" + >+ " InputStream stream = null;\n" + >+ " BufferedReader reader = null;\n" + >+ " try {\n" + >+ " stream = url.openStream();\n" + >+ " reader = new BufferedReader(new InputStreamReader(stream));\n" + >+ " System.out.println(reader.readLine());\n" + >+ " } finally {\n" + >+ " try {\n" + >+ " if (reader != null)\n" + >+ " reader.close();\n" + >+ " } catch (IOException x) {\n" + >+ " }\n" + >+ " }\n" + >+ " return false; // 'stream' may not be closed at this location\n" + >+ " }\n" + >+ " public static void main(String[] args) throws IOException {\n" + >+ " try {\n" + >+ " new X().loadURL(new URL(\""+url.toString()+"\"));\n" + >+ " } catch (IOException ex) {\n" + >+ " System.out.println(\"Got IO Exception\"+ex);\n" + >+ " }\n" + >+ " }\n" + >+ "}\n" >+ }, >+ "Manifest-Version: 1.0", >+ null, >+ true, >+ null, >+ options, >+ null); >+} >+// Bug 358903 - Filter practically unimportant resource leak warnings >+// Bug 360908 - Avoid resource leak warning when the underlying/chained resource is closed explicitly >+// Different points in a resource chain are closed >+public void test061g() { >+ Map options = getCompilerOptions(); >+ options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR); >+ options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR); >+ this.runNegativeTest( >+ new String[] { >+ "X.java", >+ "import java.io.File;\n" + >+ "import java.io.BufferedInputStream;\n" + >+ "import java.io.FileInputStream;\n" + >+ "import java.io.IOException;\n" + >+ "public class X {\n" + >+ " void closeMiddle() throws IOException {\n" + >+ " File file = new File(\"somefile\");\n" + >+ " FileInputStream fileStream = new FileInputStream(file);\n" + >+ " BufferedInputStream bis = new BufferedInputStream(fileStream);\n" + >+ " BufferedInputStream doubleWrap = new BufferedInputStream(bis);\n" + >+ " System.out.println(bis.available());\n" + >+ " bis.close();\n" + >+ " }\n" + >+ " void closeOuter() throws IOException {\n" + >+ " File file2 = new File(\"somefile\");\n" + >+ " FileInputStream fileStream2 = new FileInputStream(file2);\n" + >+ " BufferedInputStream bis2 = new BufferedInputStream(fileStream2);\n" + >+ " BufferedInputStream doubleWrap2 = new BufferedInputStream(bis2);\n" + >+ " System.out.println(bis2.available());\n" + >+ " doubleWrap2.close();\n" + >+ " }\n" + >+ " void neverClosed() throws IOException {\n" + >+ " File file3 = new File(\"somefile\");\n" + >+ " FileInputStream fileStream3 = new FileInputStream(file3);\n" + >+ " BufferedInputStream bis3 = new BufferedInputStream(fileStream3);\n" + >+ " BufferedInputStream doubleWrap3 = new BufferedInputStream(bis3);\n" + >+ " System.out.println(doubleWrap3.available());\n" + >+ " }\n" + >+ "}\n" >+ }, >+ "----------\n" + >+ "1. ERROR in X.java (at line 26)\n" + >+ " BufferedInputStream doubleWrap3 = new BufferedInputStream(bis3);\n" + >+ " ^^^^^^^^^^^\n" + >+ "Resource leak: \'doubleWrap3\' is never closed\n" + >+ "----------\n", >+ null, >+ true, >+ options); >+} >+// Bug 358903 - Filter practically unimportant resource leak warnings >+// Bug 360908 - Avoid resource leak warning when the underlying/chained resource is closed explicitly >+// Different points in a resource chain are potentially closed >+public void test061h() { >+ Map options = getCompilerOptions(); >+ options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR); >+ options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR); >+ this.runNegativeTest( >+ new String[] { >+ "X.java", >+ "import java.io.File;\n" + >+ "import java.io.BufferedInputStream;\n" + >+ "import java.io.FileInputStream;\n" + >+ "import java.io.IOException;\n" + >+ "public class X {\n" + >+ " void closeMiddle(boolean b) throws IOException {\n" + >+ " File file = new File(\"somefile\");\n" + >+ " FileInputStream fileStream = new FileInputStream(file);\n" + >+ " BufferedInputStream bis = new BufferedInputStream(fileStream);\n" + >+ " BufferedInputStream doubleWrap = new BufferedInputStream(bis);\n" + >+ " System.out.println(bis.available());\n" + >+ " if (b)\n" + >+ " bis.close();\n" + >+ " }\n" + >+ " void closeOuter(boolean b) throws IOException {\n" + >+ " File file2 = new File(\"somefile\");\n" + >+ " FileInputStream fileStream2 = new FileInputStream(file2);\n" + >+ " BufferedInputStream dummy;\n" + >+ " BufferedInputStream bis2 = (dummy = new BufferedInputStream(fileStream2));\n" + >+ " BufferedInputStream doubleWrap2 = new BufferedInputStream(bis2);\n" + >+ " System.out.println(bis2.available());\n" + >+ " if (b)\n" + >+ " doubleWrap2.close();\n" + >+ " }\n" + >+ " void potAndDef(boolean b) throws IOException {\n" + >+ " File file3 = new File(\"somefile\");\n" + >+ " FileInputStream fileStream3 = new FileInputStream(file3);\n" + >+ " BufferedInputStream bis3 = new BufferedInputStream(fileStream3);\n" + >+ " BufferedInputStream doubleWrap3 = new BufferedInputStream(bis3);\n" + >+ " System.out.println(doubleWrap3.available());\n" + >+ " if (b) bis3.close();\n" + >+ " fileStream3.close();\n" + >+ " }\n" + >+ "}\n" >+ }, >+ "----------\n" + >+ "1. ERROR in X.java (at line 10)\n" + >+ " BufferedInputStream doubleWrap = new BufferedInputStream(bis);\n" + >+ " ^^^^^^^^^^\n" + >+ "Potential resource leak: \'doubleWrap\' may not be closed\n" + >+ "----------\n" + >+ "2. ERROR in X.java (at line 20)\n" + >+ " BufferedInputStream doubleWrap2 = new BufferedInputStream(bis2);\n" + >+ " ^^^^^^^^^^^\n" + >+ "Potential resource leak: \'doubleWrap2\' may not be closed\n" + >+ "----------\n", >+ null, >+ true, >+ options); >+} >+// Bug 358903 - Filter practically unimportant resource leak warnings >+// local var is re-used for two levels of wrappers >+public void test061i() { >+ Map options = getCompilerOptions(); >+ options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR); >+ options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR); >+ this.runNegativeTest( >+ new String[] { >+ "X.java", >+ "import java.io.File;\n" + >+ "import java.io.InputStream;\n" + >+ "import java.io.BufferedInputStream;\n" + >+ "import java.io.FileInputStream;\n" + >+ "import java.io.IOException;\n" + >+ "public class X {\n" + >+ " void closeMiddle() throws IOException {\n" + >+ " File file = new File(\"somefile\");\n" + >+ " InputStream stream = new FileInputStream(file);\n" + >+ " stream = new BufferedInputStream(stream);\n" + >+ " InputStream middle;\n" + >+ " stream = new BufferedInputStream(middle = stream);\n" + >+ " System.out.println(stream.available());\n" + >+ " middle.close();\n" + >+ " }\n" + >+ " void closeOuter() throws IOException {\n" + >+ " File file = new File(\"somefile\");\n" + >+ " InputStream stream2 = new FileInputStream(file);\n" + >+ " stream2 = new BufferedInputStream(stream2);\n" + >+ " stream2 = new BufferedInputStream(stream2);\n" + >+ " System.out.println(stream2.available());\n" + >+ " stream2.close();\n" + >+ " }\n" + >+ " void neverClosed() throws IOException {\n" + >+ " File file = new File(\"somefile\");\n" + >+ " InputStream stream3 = new FileInputStream(file);\n" + >+ " stream3 = new BufferedInputStream(stream3);\n" + >+ " stream3 = new BufferedInputStream(stream3);\n" + >+ " System.out.println(stream3.available());\n" + >+ " }\n" + >+ "}\n" >+ }, >+ "----------\n" + >+ "1. ERROR in X.java (at line 26)\n" + >+ " InputStream stream3 = new FileInputStream(file);\n" + >+ " ^^^^^^^\n" + >+ "Resource leak: \'stream3\' is never closed\n" + >+ "----------\n", >+ null, >+ true, >+ options); >+} >+// Bug 358903 - Filter practically unimportant resource leak warnings >+// self-wrapping a method argument (caused NPE UnconditionalFlowInfo.markAsDefinitelyNull(..)). >+public void test061j() { >+ Map options = getCompilerOptions(); >+ options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR); >+ options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR); >+ this.runConformTest( >+ new String[] { >+ "X.java", >+ "import java.io.InputStream;\n" + >+ "import java.io.BufferedInputStream;\n" + >+ "import java.io.IOException;\n" + >+ "public class X {\n" + >+ " void foo(InputStream stream) throws IOException {\n" + >+ " stream = new BufferedInputStream(stream);\n" + >+ " System.out.println(stream.available());\n" + >+ " stream.close();\n" + >+ " }\n" + >+ " void boo(InputStream stream2) throws IOException {\n" + >+ " stream2 = new BufferedInputStream(stream2);\n" + >+ " System.out.println(stream2.available());\n" + >+ " }\n" + >+ "}\n" >+ }, >+ "", >+ null, >+ true, >+ null, >+ options, >+ null); >+} >+// Bug 358903 - Filter practically unimportant resource leak warnings >+// a wrapper is created in a return statement >+public void test061k() throws IOException { >+ Map options = getCompilerOptions(); >+ options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR); >+ options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR); >+ this.runConformTest( >+ new String[] { >+ "X.java", >+ "import java.io.File;\n" + >+ "import java.io.FileInputStream;\n" + >+ "import java.io.BufferedInputStream;\n" + >+ "import java.io.IOException;\n" + >+ "public class X {\n" + >+ " BufferedInputStream getReader(File file) throws IOException {\n" + >+ " FileInputStream stream = new FileInputStream(file);\n" + >+ " return new BufferedInputStream(stream);\n" + >+ " }\n" + >+ "}\n" >+ }, >+ "", >+ null, >+ true, >+ null, >+ options, >+ null); >+} >+// Bug 358903 - Filter practically unimportant resource leak warnings >+// a closeable is assigned to a field >+public void test061l() throws IOException { >+ Map options = getCompilerOptions(); >+ options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR); >+ options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR); >+ this.runConformTest( >+ new String[] { >+ "X.java", >+ "import java.io.File;\n" + >+ "import java.io.FileInputStream;\n" + >+ "import java.io.BufferedInputStream;\n" + >+ "import java.io.IOException;\n" + >+ "public class X {\n" + >+ " BufferedInputStream stream;\n" + >+ " void foo(File file) throws IOException {\n" + >+ " FileInputStream s = new FileInputStream(file);\n" + >+ " stream = new BufferedInputStream(s);\n" + >+ " }\n" + >+ "}\n" >+ }, >+ "", >+ null, >+ true, >+ null, >+ options, >+ null); >+} >+// Bug 362331 - Resource leak not detected when closeable not assigned to variable >+// a resource is never assigned >+public void test062a() throws IOException { >+ Map options = getCompilerOptions(); >+ options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR); >+ options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR); >+ this.runNegativeTest( >+ new String[] { >+ "X.java", >+ "import java.io.File;\n" + >+ "import java.io.FileOutputStream;\n" + >+ "import java.io.IOException;\n" + >+ "public class X {\n" + >+ " void foo() throws IOException {\n" + >+ " new FileOutputStream(new File(\"C:\\temp\\foo.txt\")).write(1);\n" + >+ " }\n" + >+ "}\n" >+ }, >+ "----------\n" + >+ "1. ERROR in X.java (at line 6)\n" + >+ " new FileOutputStream(new File(\"C:\\temp\\foo.txt\")).write(1);\n" + >+ " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + >+ "Resource leak: \'<unassigned Closeable value>\' is never closed\n" + >+ "----------\n", >+ null, >+ true, >+ options); >+} >+// Bug 362331 - Resource leak not detected when closeable not assigned to variable >+// a freshly allocated resource is immediately closed >+public void test062b() throws IOException { >+ Map options = getCompilerOptions(); >+ options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR); >+ options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR); >+ this.runConformTest( >+ new String[] { >+ "X.java", >+ "import java.io.File;\n" + >+ "import java.io.FileOutputStream;\n" + >+ "import java.io.IOException;\n" + >+ "public class X {\n" + >+ " void foo() throws IOException {\n" + >+ " new FileOutputStream(new File(\"C:\\temp\\foo.txt\")).close();\n" + >+ " }\n" + >+ "}\n" >+ }, >+ "", >+ null, >+ true, >+ null, >+ options, >+ null); >+} >+// Bug 362331 - Resource leak not detected when closeable not assigned to variable >+// a resource is directly passed to another method >+public void test062c() throws IOException { >+ Map options = getCompilerOptions(); >+ options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR); >+ options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR); >+ this.runConformTest( >+ new String[] { >+ "X.java", >+ "import java.io.File;\n" + >+ "import java.io.FileOutputStream;\n" + >+ "import java.io.IOException;\n" + >+ "public class X {\n" + >+ " void foo() throws IOException {\n" + >+ " writeIt(new FileOutputStream(new File(\"C:\\temp\\foo.txt\")));\n" + >+ " }\n" + >+ " void writeIt(FileOutputStream fos) throws IOException {\n" + >+ " fos.write(1);\n" + >+ " fos.close();\n" + >+ " }\n" + >+ "}\n" >+ }, >+ "", >+ null, >+ true, >+ null, >+ options, >+ null); >+} >+// Bug 362331 - Resource leak not detected when closeable not assigned to variable >+// a resource is not used >+public void test062d() throws IOException { >+ Map options = getCompilerOptions(); >+ options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR); >+ options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR); >+ this.runNegativeTest( >+ new String[] { >+ "X.java", >+ "import java.io.File;\n" + >+ "import java.io.FileOutputStream;\n" + >+ "import java.io.IOException;\n" + >+ "public class X {\n" + >+ " void foo() throws IOException {\n" + >+ " new FileOutputStream(new File(\"C:\\temp\\foo.txt\"));\n" + >+ " }\n" + >+ "}\n" >+ }, >+ "----------\n" + >+ "1. ERROR in X.java (at line 6)\n" + >+ " new FileOutputStream(new File(\"C:\\temp\\foo.txt\"));\n" + >+ " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + >+ "Resource leak: \'<unassigned Closeable value>\' is never closed\n" + >+ "----------\n", >+ null, >+ true, >+ options); >+} >+// Bug 362332 - Only report potential leak when closeable not created in the local scope >+// a wrapper is obtained from another method >+public void test063a() throws IOException { >+ Map options = getCompilerOptions(); >+ options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR); >+ options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR); >+ this.runNegativeTest( >+ new String[] { >+ "X.java", >+ "import java.io.File;\n" + >+ "import java.io.FileInputStream;\n" + >+ "import java.io.BufferedInputStream;\n" + >+ "import java.io.IOException;\n" + >+ "public class X {\n" + >+ " void read(File file) throws IOException {\n" + >+ " FileInputStream stream = new FileInputStream(file);\n" + >+ " BufferedInputStream bis = new BufferedInputStream(stream); // never since reassigned\n" + >+ " FileInputStream stream2 = new FileInputStream(file); // unsure since passed to method\n" + >+ " bis = getReader(stream2); // unsure since obtained from method\n" + >+ " bis.available();\n" + >+ " }\n" + >+ " BufferedInputStream getReader(FileInputStream stream) throws IOException {\n" + >+ " return new BufferedInputStream(stream);\n" + >+ " }\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", >+ null, >+ true, >+ options); >+} >+// Bug 362332 - Only report potential leak when closeable not created in the local scope >+// a wrapper is obtained from a field read >+public void test063b() throws IOException { >+ Map options = getCompilerOptions(); >+ options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR); >+ options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR); >+ this.runConformTest( >+ new String[] { >+ "X.java", >+ "import java.io.FileInputStream;\n" + >+ "import java.io.BufferedInputStream;\n" + >+ "import java.io.IOException;\n" + >+ "public class X {\n" + >+ " FileInputStream stream;\n" + >+ " void read() throws IOException {\n" + >+ " FileInputStream s = this.stream;\n" + >+ " BufferedInputStream bis = new BufferedInputStream(s); // don't complain since s is obtained from a field\n" + >+ " bis.available();\n" + >+ " }\n" + >+ "}\n" >+ }, >+ "", >+ null, >+ true, >+ null, >+ options, >+ null); >+} >+// Bug 362332 - Only report potential leak when closeable not created in the local scope >+// a wrapper is assigned to a field >+public void test063c() throws IOException { >+ Map options = getCompilerOptions(); >+ options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR); >+ options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR); >+ this.runConformTest( >+ new String[] { >+ "X.java", >+ "import java.io.FileInputStream;\n" + >+ "import java.io.BufferedInputStream;\n" + >+ "import java.io.IOException;\n" + >+ "public class X {\n" + >+ " BufferedInputStream stream;\n" + >+ " void read() throws IOException {\n" + >+ " FileInputStream s = new FileInputStream(\"somefile\");\n" + >+ " BufferedInputStream bis = new BufferedInputStream(s);\n" + >+ " this.stream = bis;\n" + >+ " }\n" + >+ "}\n" >+ }, >+ "", >+ null, >+ true, >+ null, >+ options, >+ null); >+} > public static Class testClass() { > return TryWithResourcesStatementTest.class; > } >diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java >index e811ea9..71217ce 100644 >--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java >+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright (c) 2000, 2011 IBM Corporation and others. >+ * Copyright (c) 2000, 2012 IBM Corporation and others. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -12,6 +12,7 @@ > * bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE > * bug 349326 - [1.7] new warning for missing try-with-resources > * bug 186342 - [compiler][null] Using annotations for null checking >+ * bug 358903 - Filter practically unimportant resource leak warnings > *******************************************************************************/ > package org.eclipse.jdt.internal.compiler.ast; > >@@ -37,6 +38,8 @@ > protected TypeBinding typeExpected; // for <> inference > public boolean inferredReturnType; > >+ public FakedTrackingVariable closeTracker; // when allocation a Closeable store a pre-liminary tracking variable here >+ > public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { > // check captured variables are initialized in current context (26134) > checkCapturedLocalInitializationIfNecessary((ReferenceBinding)this.binding.declaringClass.erasure(), currentScope, flowInfo); >@@ -44,18 +47,22 @@ > // process arguments > if (this.arguments != null) { > for (int i = 0, count = this.arguments.length; i < count; i++) { >- // if argument is an AutoCloseable insert info that it *may* be closed (by the target method, i.e.) >- flowInfo = FakedTrackingVariable.markPassedToOutside(currentScope, this.arguments[i], flowInfo); > flowInfo = > this.arguments[i] > .analyseCode(currentScope, flowContext, flowInfo) > .unconditionalInits(); >+ // if argument is an AutoCloseable insert info that it *may* be closed (by the target method, i.e.) >+ flowInfo = FakedTrackingVariable.markPassedToOutside(currentScope, this.arguments[i], flowInfo, this.resolvedType); > if ((this.arguments[i].implicitConversion & TypeIds.UNBOXING) != 0) { > this.arguments[i].checkNPE(currentScope, flowContext, flowInfo); > } > } > analyseArguments(currentScope, flowContext, flowInfo, this.binding, this.arguments); > } >+ >+ if (FakedTrackingVariable.isAutoCloseable(this.resolvedType)) >+ FakedTrackingVariable.analyseCloseableAllocation(currentScope, flowInfo, this); >+ > // record some dependency information for exception types > ReferenceBinding[] thrownExceptions; > if (((thrownExceptions = this.binding.thrownExceptions).length) != 0) { >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 970fc24..539a661 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 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright (c) 2000, 2011 IBM Corporation and others. >+ * Copyright (c) 2000, 2012 IBM Corporation and others. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -14,6 +14,7 @@ > * bug 335093 - [compiler][null] minimal hook for future null annotation support > * bug 349326 - [1.7] new warning for missing try-with-resources > * bug 186342 - [compiler][null] Using annotations for null checking >+ * bug 358903 - Filter practically unimportant resource leak warnings > *******************************************************************************/ > package org.eclipse.jdt.internal.compiler.ast; > >@@ -46,19 +47,27 @@ > if ((this.expression.implicitConversion & TypeIds.UNBOXING) != 0) { > this.expression.checkNPE(currentScope, flowContext, flowInfo); > } >+ >+ FlowInfo preInitInfo = null; >+ boolean shouldAnalyseResource = local != null >+ && flowInfo.reachMode() == FlowInfo.REACHABLE >+ && (FakedTrackingVariable.isAutoCloseable(this.expression.resolvedType) >+ || this.expression.resolvedType == TypeBinding.NULL); >+ if (shouldAnalyseResource) { >+ preInitInfo = flowInfo.unconditionalCopy(); >+ // analysis of resource leaks needs additional context while analyzing the RHS: >+ FakedTrackingVariable.preConnectTrackerAcrossAssignment(this, local, this.expression); >+ } >+ > flowInfo = ((Reference) this.lhs) > .analyseAssignment(currentScope, flowContext, flowInfo, this, false) > .unconditionalInits(); >- if (local != null) { >- LocalVariableBinding previousTrackerBinding = null; >- if (local.closeTracker != null) { >- // Assigning to a variable already holding an AutoCloseable, has it been closed before? >- previousTrackerBinding = local.closeTracker.binding; >- if (!flowInfo.isDefinitelyNull(local)) // only if previous value may be non-null >- local.closeTracker.recordErrorLocation(this, flowInfo.nullStatus(previousTrackerBinding)); >- } >- FakedTrackingVariable.handleResourceAssignment(flowInfo, this, this.expression, local, previousTrackerBinding); >- } >+ >+ if (shouldAnalyseResource) >+ FakedTrackingVariable.handleResourceAssignment(preInitInfo, flowInfo, this, this.expression, local); >+ else >+ FakedTrackingVariable.cleanUpAfterAssignment(currentScope, this.lhs.bits, this.expression); >+ > int nullStatus = this.expression.nullStatus(flowInfo); > if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) { > if (nullStatus == FlowInfo.NULL) { >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 ee13047..b35a67c 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 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright (c) 2011 GK Software AG and others. >+ * Copyright (c) 2011, 2012 GK Software AG and others. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -15,7 +15,6 @@ > import java.util.Map; > import java.util.Map.Entry; > >-import org.eclipse.jdt.core.compiler.CharOperation; > import org.eclipse.jdt.internal.compiler.codegen.CodeStream; > import org.eclipse.jdt.internal.compiler.flow.FlowContext; > import org.eclipse.jdt.internal.compiler.flow.FlowInfo; >@@ -48,20 +47,28 @@ > private static final int CLOSED_IN_NESTED_METHOD = 4; > // a location independent issue has been reported already against this resource: > private static final int REPORTED = 8; >- >+ // a resource is wrapped in another resource: >+ private static final int WRAPPED = 16; >+ >+ private static final int DOUBT_MASK = CLOSE_SEEN | PASSED_TO_OUTSIDE | CLOSED_IN_NESTED_METHOD | REPORTED; // not WRAPPED >+ > /** >- * Bitset of {@link #CLOSE_SEEN}, {@link #PASSED_TO_OUTSIDE}, {@link #CLOSED_IN_NESTED_METHOD} and {@link #REPORTED}. >+ * Bitset of {@link #CLOSE_SEEN}, {@link #PASSED_TO_OUTSIDE}, {@link #CLOSED_IN_NESTED_METHOD}, {@link #REPORTED} and {@link #WRAPPED}. > */ > private int globalClosingState = 0; > >+ public LocalVariableBinding originalBinding; // the real local being tracked, can be null for preliminary track vars for allocation expressions >+ >+ public FakedTrackingVariable innerTracker; // chained tracking variable of a chained (wrapped) resource >+ > MethodScope methodScope; // designates the method declaring this variable >- >- public LocalVariableBinding originalBinding; // the real local being tracked >- >- HashMap recordedLocations; // initially null, ASTNode -> Integer > >+ private HashMap recordedLocations; // initially null, ASTNode -> Integer > >- public FakedTrackingVariable(LocalVariableBinding original, Statement location) { >+ // temporary storage while analyzing "res = new Res();": >+ private ASTNode currentAssignment; // temporarily store the assignment as the location for error reporting >+ >+ public FakedTrackingVariable(LocalVariableBinding original, ASTNode location) { > super(original.name, location.sourceStart, location.sourceEnd); > this.type = new SingleTypeReference( > TypeConstants.OBJECT, >@@ -69,6 +76,17 @@ > this.methodScope = original.declaringScope.methodScope(); > this.originalBinding = original; > resolve(original.declaringScope); >+ } >+ >+ /* Create an unassigned tracking variable while analyzing an allocation expression: */ >+ private FakedTrackingVariable(BlockScope scope, ASTNode location) { >+ super("<unassigned Closeable value>".toCharArray(), location.sourceStart, location.sourceEnd); //$NON-NLS-1$ >+ 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) >@@ -88,8 +106,12 @@ > } > > /** >- * If expression resolves to a local variable binding of type AutoCloseable, >- * answer the variable that tracks closing of that local, creating it if needed. >+ * If expression resolves to a value of type AutoCloseable answer the variable that tracks closing of that local. >+ * Covers two cases: >+ * <ul> >+ * <li>value is a local variable reference, create tracking variable it if needed. >+ * <li>value is an allocation expression, return a preliminary tracking variable if set. >+ * </ul> > * @param expression > * @return a new {@link FakedTrackingVariable} or null. > */ >@@ -107,51 +129,258 @@ > Statement location = local.declaration; > return local.closeTracker = new FakedTrackingVariable(local, location); > } >- } >+ } else if (expression instanceof AllocationExpression) { >+ // return any preliminary tracking variable from analyseCloseableAllocation >+ return ((AllocationExpression) expression).closeTracker; >+ } > return null; > } > >- /** if 'invocationSite' is a call to close() that has a registered tracking variable, answer that variable's binding. */ >- public static LocalVariableBinding getTrackerForCloseCall(ASTNode invocationSite) { >- if (invocationSite instanceof MessageSend) { >- MessageSend send = (MessageSend) invocationSite; >- if (CharOperation.equals(TypeConstants.CLOSE, send.selector) && send.receiver instanceof SingleNameReference) { >- Binding receiverBinding = ((SingleNameReference)send.receiver).binding; >- if (receiverBinding instanceof LocalVariableBinding) { >- FakedTrackingVariable trackingVariable = ((LocalVariableBinding)receiverBinding).closeTracker; >- if (trackingVariable != null) >- return trackingVariable.binding; >- } >+ /** >+ * Before analyzing an assignment of this shape: <code>singleName = new Allocation()</code> >+ * connect any tracking variable of the LHS with the allocation on the RHS. >+ * Also the assignment is temporarily stored in the tracking variable in case we need to >+ * report errors because the assignment leaves the old LHS value unclosed. >+ * In this case the assignment should be used as the error location. >+ * >+ * @param location the assignment/local declaration being analyzed >+ * @param local the local variable being assigned to >+ * @param rhs the rhs of the assignment resp. the initialization of the local variable declaration. >+ */ >+ public static void preConnectTrackerAcrossAssignment(ASTNode location, LocalVariableBinding local, Expression rhs) { >+ FakedTrackingVariable closeTracker = null; >+ if (rhs instanceof AllocationExpression) { >+ closeTracker = local.closeTracker; >+ if (closeTracker == null) { >+ if (isAutoCloseable(rhs.resolvedType)) { >+ closeTracker = new FakedTrackingVariable(local, location); >+ } >+ } >+ if (closeTracker != null) { >+ closeTracker.currentAssignment = location; >+ ((AllocationExpression)rhs).closeTracker = closeTracker; > } > } >- return null; >+ } >+ >+ /** >+ * Compute/assign a tracking variable for a freshly allocated closeable value, using information from our white lists. >+ * See Bug 358903 - Filter practically unimportant resource leak warnings >+ */ >+ public static void analyseCloseableAllocation(BlockScope scope, FlowInfo flowInfo, AllocationExpression allocation) { >+ // client has checked that the resolvedType is an AutoCloseable, hence the following cast is safe: >+ if (((ReferenceBinding)allocation.resolvedType).hasTypeBit(TypeIds.BitResourceFreeCloseable)) { >+ // remove unnecessary attempts (closeable is not relevant) >+ if (allocation.closeTracker != null) { >+ scope.removeTrackingVar(allocation.closeTracker); >+ allocation.closeTracker = null; >+ } >+ } else if (((ReferenceBinding)allocation.resolvedType).hasTypeBit(TypeIds.BitWrapperCloseable)) { >+ if (allocation.arguments != null && allocation.arguments.length > 0) { >+ // find the wrapped resource represented by its tracking var: >+ FakedTrackingVariable innerTracker = analyseCloseableAllocationArgument(scope, flowInfo, allocation, allocation.arguments[0]); >+ if (innerTracker != null) { >+ if (innerTracker == allocation.closeTracker) >+ return; // self wrap (res = new Res(res)) -> neither change (here) nor remove (below) >+ if (allocation.closeTracker == null) { >+ allocation.closeTracker = new FakedTrackingVariable(scope, allocation); // no local available, closeable is unassigned >+ } >+ allocation.closeTracker.innerTracker = innerTracker; >+ innerTracker.globalClosingState |= WRAPPED; >+ flowInfo.markAsDefinitelyNull(allocation.closeTracker.binding); >+ return; // keep chaining wrapper >+ } >+ } >+ // remove unnecessary attempts (wrapper has no relevant inner) >+ if (allocation.closeTracker != null) { >+ scope.removeTrackingVar(allocation.closeTracker); >+ allocation.closeTracker = null; >+ } >+ } else { // regular resource >+ FakedTrackingVariable presetTracker = allocation.closeTracker; >+ if (presetTracker != null && presetTracker.originalBinding != null) { >+ int closeStatus = flowInfo.nullStatus(presetTracker.binding); >+ if (closeStatus != FlowInfo.NON_NULL >+ && !flowInfo.isDefinitelyNull(presetTracker.originalBinding) >+ && !(presetTracker.currentAssignment instanceof LocalDeclaration)) >+ allocation.closeTracker.recordErrorLocation(presetTracker.currentAssignment, closeStatus); >+ } else { >+ allocation.closeTracker = new FakedTrackingVariable(scope, allocation); // no local available, closeable is unassigned >+ } >+ flowInfo.markAsDefinitelyNull(allocation.closeTracker.binding); >+ } >+ } >+ >+ /** Find an existing tracking variable for the argument of an allocation for a resource wrapper. */ >+ public static FakedTrackingVariable analyseCloseableAllocationArgument(BlockScope scope, FlowInfo flowInfo, AllocationExpression allocation, Expression arg) >+ { >+ while (arg instanceof Assignment) { >+ Assignment assign = (Assignment)arg; >+ LocalVariableBinding innerLocal = assign.localVariableBinding(); >+ if (innerLocal != null) { >+ // nested assignment has already been processed >+ return innerLocal.closeTracker; >+ } else { >+ arg = assign.expression; // unwrap assignment and fall through >+ } >+ } >+ if (arg instanceof SingleNameReference) { >+ // is allocation arg a reference to an existing closeable? >+ LocalVariableBinding local = arg.localVariableBinding(); >+ if (local != null) { >+ return local.closeTracker; >+ } >+ } else if (arg instanceof AllocationExpression && arg.resolvedType instanceof ReferenceBinding) { >+ // nested allocation >+ return ((AllocationExpression)arg).closeTracker; >+ } >+ return null; // not a tracked expression > } > > /** > * 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. >+ * If so create or re-use a tracking variable, and wire and initialize everything. >+ * @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 >+ * @param rhs the right hand side of the assignment, this expression is to be analyzed. >+ * 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 flowInfo, Statement location, Expression rhs, LocalVariableBinding local, >- LocalVariableBinding previousTrackerBinding) >+ public static void handleResourceAssignment(FlowInfo upstreamInfo, FlowInfo flowInfo, ASTNode location, Expression rhs, LocalVariableBinding local) > { >- if (isAutoCloseable(rhs.resolvedType)) { >+ // does the LHS (local) already have a tracker, indicating we may leak a resource by the assignment? >+ FakedTrackingVariable previousTracker = null; >+ FakedTrackingVariable disconnectedTracker = null; >+ if (local.closeTracker != null) { >+ // assigning to a variable already holding an AutoCloseable, has it been closed before? >+ previousTracker = local.closeTracker; >+ int nullStatus = upstreamInfo.nullStatus(local); >+ if (nullStatus != FlowInfo.NULL && nullStatus != FlowInfo.UNKNOWN) // only if previous value may be relevant >+ disconnectedTracker = previousTracker; // report error below, unless we have a self-wrap assignment >+ } >+ >+ if (rhs.resolvedType != TypeBinding.NULL) { > // new value is AutoCloseable, start tracking, possibly re-using existing tracker var: >- > FakedTrackingVariable rhsTrackVar = getCloseTrackingVariable(rhs); >- if (rhsTrackVar != null) { // 1. share tracking variable with RHS? >- local.closeTracker = rhsTrackVar; >- // keep null-status unchanged across this assignment >- } else if (previousTrackerBinding != null) { // 2. re-use tracking variable from the LHS? >- // re-assigning from a fresh, mark as not-closed again: >- flowInfo.markAsDefinitelyNull(previousTrackerBinding); >+ if (rhsTrackVar != null) { // 1. if RHS has a tracking variable... >+ if (local.closeTracker == null) { >+ // null shouldn't occur but let's play safe >+ if (rhsTrackVar.originalBinding != null) >+ local.closeTracker = rhsTrackVar; // a.: let fresh LHS share it >+ } else { >+ if (rhsTrackVar == disconnectedTracker && rhs instanceof AllocationExpression) >+ return; // b.: self wrapper: res = new Wrap(res); -> done! >+ local.closeTracker = rhsTrackVar; // c.: conflicting LHS and RHS, proceed with recordErrorLocation below >+ } >+ // keep close-status of RHS unchanged across this assignment >+ } else if (previousTracker != null) { // 2. re-use tracking variable from the LHS? >+ // re-assigning from a fresh value, mark as not-closed again: >+ flowInfo.markAsDefinitelyNull(previousTracker.binding); >+ local.closeTracker = analyseCloseableExpression(flowInfo, local, location, rhs, previousTracker); > } else { // 3. no re-use, create a fresh tracking variable: >- local.closeTracker = new FakedTrackingVariable(local, location); >- // a fresh resource, mark as not-closed: >- flowInfo.markAsDefinitelyNull(local.closeTracker.binding); >+ rhsTrackVar = analyseCloseableExpression(flowInfo, local, location, rhs, null); >+ if (rhsTrackVar != null) { >+ local.closeTracker = rhsTrackVar; >+ // a fresh resource, mark as not-closed: >+ if ((rhsTrackVar.globalClosingState & PASSED_TO_OUTSIDE) == 0) >+ flowInfo.markAsDefinitelyNull(rhsTrackVar.binding); > // TODO(stephan): this might be useful, but I could not find a test case for it: >-// if (flowContext.initsOnFinally != null) >-// flowContext.initsOnFinally.markAsDefinitelyNonNull(trackerBinding); >+// if (flowContext.initsOnFinally != null) >+// flowContext.initsOnFinally.markAsDefinitelyNonNull(trackerBinding); >+ } > } >+ } >+ >+ if (disconnectedTracker != null) >+ disconnectedTracker.recordErrorLocation(location, upstreamInfo.nullStatus(disconnectedTracker.binding)); >+ } >+ /** >+ * Analyze structure of a closeable expression, matching (chained) resources against our white lists. >+ * @param flowInfo where to record close status >+ * @param local local variable to which the closeable is being assigned >+ * @param location where to flag errors/warnings against >+ * @param expression expression to be analyzed >+ * @param previousTracker when analyzing a re-assignment we may already have a tracking variable for local, >+ * which we should then re-use >+ * @return a tracking variable associated with local or null if no need to track >+ */ >+ private static FakedTrackingVariable analyseCloseableExpression(FlowInfo flowInfo, LocalVariableBinding local, >+ ASTNode location, Expression expression, FakedTrackingVariable previousTracker) >+ { >+ // unwrap uninteresting nodes: >+ while (true) { >+ if (expression instanceof Assignment) >+ expression = ((Assignment)expression).expression; >+ else if (expression instanceof CastExpression) >+ expression = ((CastExpression) expression).expression; >+ else >+ break; >+ } >+ >+ // analyze by node type: >+ if (expression instanceof AllocationExpression) { >+ // allocation expressions already have their tracking variables analyzed by analyseCloseableAllocation(..) >+ FakedTrackingVariable tracker = ((AllocationExpression) expression).closeTracker; >+ if (tracker != null && tracker.originalBinding == null) { >+ // tracker without original binding (unassigned closeable) shouldn't reach here but let's play safe >+ return null; >+ } >+ return tracker; >+ } else if (expression instanceof MessageSend >+ || expression instanceof ArrayReference) >+ { >+ // we *might* be responsible for the resource obtained >+ FakedTrackingVariable tracker = new FakedTrackingVariable(local, location); >+ tracker.globalClosingState |= PASSED_TO_OUTSIDE; >+ flowInfo.markPotentiallyNullBit(tracker.binding); >+ return tracker; >+ } else if (expression instanceof FieldReference >+ || expression instanceof QualifiedNameReference) >+ { >+ // responsibility for this resource probably lies at a higher level >+ FakedTrackingVariable tracker = new FakedTrackingVariable(local, location); >+ tracker.globalClosingState |= PASSED_TO_OUTSIDE; >+ flowInfo.markPotentiallyNonNullBit(tracker.binding); >+ return tracker; >+ } >+ >+ if (expression.resolvedType instanceof ReferenceBinding) { >+ ReferenceBinding resourceType = (ReferenceBinding) expression.resolvedType; >+ if (resourceType.hasTypeBit(TypeIds.BitResourceFreeCloseable)) { >+ // (a) resource-free closeable: -> null >+ return null; >+ } >+ } >+ if (local.closeTracker != null) >+ // (c): inner has already been analyzed: -> re-use track var >+ return local.closeTracker; >+ return new FakedTrackingVariable(local, location); >+ } >+ >+ public static void cleanUpAfterAssignment(BlockScope currentScope, int lhsBits, Expression expression) { >+ // remove all remaining track vars with no original binding >+ >+ // unwrap uninteresting nodes: >+ 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 { >+ // assignment passing a local into a field? >+ LocalVariableBinding local = expression.localVariableBinding(); >+ if (local != null && local.closeTracker != null && ((lhsBits & Binding.FIELD) != 0)) >+ currentScope.removeTrackingVar(local.closeTracker); > } > } > >@@ -159,6 +388,76 @@ > public static boolean isAutoCloseable(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; >+ // loop as to consider wrappers (per white list) encapsulating an inner resource. >+ while (currentTracker != null) { >+ LocalVariableBinding currentVar = currentTracker.binding; >+ int currentStatus = getNullStatusAggressively(currentVar, flowInfo); >+ if (locationScope != null) // only check at method exit points >+ currentStatus = mergeCloseStatus(locationScope, currentStatus, currentVar, currentScope); >+ if (currentStatus == FlowInfo.NON_NULL) { >+ status = currentStatus; >+ break; // closed -> stop searching >+ } else if (status == FlowInfo.NULL || status == FlowInfo.UNKNOWN) { >+ status = currentStatus; // improved although not yet safe -> keep searching for better >+ } >+ currentTracker = currentTracker.innerTracker; >+ } >+ return status; >+ } >+ >+ /** >+ * Get the null status looking even into unreachable flows >+ * @param local >+ * @param flowInfo >+ * @return one of the constants FlowInfo.{NULL,POTENTIALLY_NULL,POTENTIALLY_NON_NULL,NON_NULL}. >+ */ >+ private int getNullStatusAggressively(LocalVariableBinding local, FlowInfo flowInfo) { >+ int reachMode = flowInfo.reachMode(); >+ int status = 0; >+ try { >+ // unreachable flowInfo is too shy in reporting null-issues, temporarily forget reachability: >+ if (reachMode != FlowInfo.REACHABLE) >+ flowInfo.tagBits &= ~FlowInfo.UNREACHABLE; >+ status = flowInfo.nullStatus(local); >+ } finally { >+ // reset >+ flowInfo.tagBits |= reachMode; >+ } >+ // at this point some combinations are not useful so flatten to a single bit: >+ if ((status & FlowInfo.NULL) != 0) { >+ if ((status & (FlowInfo.NON_NULL | FlowInfo.POTENTIALLY_NON_NULL)) != 0) >+ return FlowInfo.POTENTIALLY_NULL; // null + doubt = pot null >+ return FlowInfo.NULL; >+ } else if ((status & FlowInfo.NON_NULL) != 0) { >+ 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) >+ return FlowInfo.POTENTIALLY_NULL; >+ return status; >+ } >+ >+ public int mergeCloseStatus(BlockScope currentScope, int status, LocalVariableBinding local, BlockScope outerScope) { >+ // get the most suitable null status representing whether resource 'binding' has been closed >+ // start at 'currentScope' and potentially travel out until 'outerScope' >+ // at each scope consult any recorded 'finallyInfo'. >+ 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) // neither is NON_NULL, but not both are NULL => call it POTENTIALLY_NULL >+ status = FlowInfo.POTENTIALLY_NULL; >+ } >+ if (currentScope != outerScope && currentScope.parent instanceof BlockScope) >+ return mergeCloseStatus(((BlockScope) currentScope.parent), status, local, outerScope); >+ } >+ return status; > } > > /** Mark that this resource is closed locally. */ >@@ -180,9 +479,18 @@ > * (as argument to a method/ctor call or as a return value from the current method), > * and thus should be considered as potentially closed. > */ >- public static FlowInfo markPassedToOutside(BlockScope scope, Expression expression, FlowInfo flowInfo) { >+ public static FlowInfo markPassedToOutside(BlockScope scope, Expression expression, FlowInfo flowInfo, TypeBinding allocatedType) { >+ if ((allocatedType instanceof ReferenceBinding) // only set when called from AllocationExpression >+ && ((ReferenceBinding) allocatedType).hasTypeBit(TypeIds.BitWrapperCloseable)) >+ return flowInfo; // allocation of wrapped closeables is analyzed specially >+ > FakedTrackingVariable trackVar = getCloseTrackingVariable(expression); > if (trackVar != null) { >+ if (trackVar.originalBinding == null) { >+ // an allocation that never was assigned to a local variable -> drop it completely as we're not responsible >+ scope.removeTrackingVar(trackVar); >+ return flowInfo; >+ } > trackVar.globalClosingState |= PASSED_TO_OUTSIDE; > if (scope.methodScope() != trackVar.methodScope) > trackVar.globalClosingState |= CLOSED_IN_NESTED_METHOD; >@@ -201,9 +509,14 @@ > } > > public boolean reportRecordedErrors(Scope scope) { >- if (this.globalClosingState == 0) { >- reportError(scope.problemReporter(), null, FlowInfo.NULL); >- return true; >+ FakedTrackingVariable current = this; >+ while ((current.globalClosingState & DOUBT_MASK) == 0) { >+ current = current.innerTracker; >+ if (current == null) { >+ // no relevant state found -> report: >+ reportError(scope.problemReporter(), null, FlowInfo.NULL); >+ return true; >+ } > } > boolean hasReported = false; > if (this.recordedLocations != null) { >@@ -218,6 +531,8 @@ > } > > public void reportError(ProblemReporter problemReporter, ASTNode location, int nullStatus) { >+ if ((this.globalClosingState & WRAPPED) != 0) >+ return; > if (nullStatus == FlowInfo.NULL) { > if ((this.globalClosingState & CLOSED_IN_NESTED_METHOD) != 0) > problemReporter.potentiallyUnclosedCloseable(this, location); >@@ -225,7 +540,7 @@ > problemReporter.unclosedCloseable(this, location); > } else if (nullStatus == FlowInfo.POTENTIALLY_NULL) { > problemReporter.potentiallyUnclosedCloseable(this, location); >- } >+ } > } > > public void reportExplicitClosing(ProblemReporter problemReporter) { >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 dac029c..3781553 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 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright (c) 2000, 2011 IBM Corporation and others. >+ * Copyright (c) 2000, 2012 IBM Corporation and others. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -13,6 +13,7 @@ > * bug 335093 - [compiler][null] minimal hook for future null annotation support > * bug 349326 - [1.7] new warning for missing try-with-resources > * bug 186342 - [compiler][null] Using annotations for null checking >+ * bug 358903 - Filter practically unimportant resource leak warnings > *******************************************************************************/ > package org.eclipse.jdt.internal.compiler.ast; > >@@ -74,11 +75,26 @@ > this.initialization.checkNPE(currentScope, flowContext, flowInfo); > } > >+ FlowInfo preInitInfo = null; >+ boolean shouldAnalyseResource = this.binding != null >+ && flowInfo.reachMode() == FlowInfo.REACHABLE >+ && FakedTrackingVariable.isAutoCloseable(this.initialization.resolvedType); >+ if (shouldAnalyseResource) { >+ preInitInfo = flowInfo.unconditionalCopy(); >+ // analysis of resource leaks needs additional context while analyzing the RHS: >+ FakedTrackingVariable.preConnectTrackerAcrossAssignment(this, this.binding, this.initialization); >+ } >+ > flowInfo = > this.initialization > .analyseCode(currentScope, flowContext, flowInfo) > .unconditionalInits(); >- FakedTrackingVariable.handleResourceAssignment(flowInfo, this, this.initialization, this.binding, null); >+ >+ if (shouldAnalyseResource) >+ FakedTrackingVariable.handleResourceAssignment(preInitInfo, flowInfo, this, this.initialization, this.binding); >+ else >+ FakedTrackingVariable.cleanUpAfterAssignment(currentScope, Binding.LOCAL, this.initialization); >+ > int nullStatus = this.initialization.nullStatus(flowInfo); > if (!flowInfo.isDefinitelyAssigned(this.binding)){// for local variable debug attributes > this.bits |= FirstAssignmentToLocal; >diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java >index 46d4540..4b311f9 100644 >--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java >+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright (c) 2000, 2011 IBM Corporation and others. >+ * Copyright (c) 2000, 2012 IBM Corporation and others. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -12,6 +12,7 @@ > * bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE > * bug 349326 - [1.7] new warning for missing try-with-resources > * bug 186342 - [compiler][null] Using annotations for null checking >+ * bug 358903 - Filter practically unimportant resource leak warnings > *******************************************************************************/ > package org.eclipse.jdt.internal.compiler.ast; > >@@ -96,9 +97,9 @@ > if ((this.arguments[i].implicitConversion & TypeIds.UNBOXING) != 0) { > this.arguments[i].checkNPE(currentScope, flowContext, flowInfo); > } >- // if argument is an AutoCloseable insert info that it *may* be closed (by the target method, i.e.) >- flowInfo = FakedTrackingVariable.markPassedToOutside(currentScope, this.arguments[i], flowInfo); > flowInfo = this.arguments[i].analyseCode(currentScope, flowContext, flowInfo).unconditionalInits(); >+ // if argument is an AutoCloseable insert info that it *may* be closed (by the target method, i.e.) >+ flowInfo = FakedTrackingVariable.markPassedToOutside(currentScope, this.arguments[i], flowInfo, null); > } > analyseArguments(currentScope, flowContext, flowInfo, this.binding, this.arguments); > } >diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java >index 3a2a0ed..0bd05f5 100644 >--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java >+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright (c) 2000, 2011 IBM Corporation and others. >+ * Copyright (c) 2000, 2012 IBM Corporation and others. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -11,6 +11,7 @@ > * bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE > * bug 349326 - [1.7] new warning for missing try-with-resources > * bug 186342 - [compiler][null] Using annotations for null checking >+ * bug 358903 - Filter practically unimportant resource leak warnings > *******************************************************************************/ > package org.eclipse.jdt.internal.compiler.ast; > >@@ -81,7 +82,7 @@ > if (this.arguments != null) { > for (int i = 0, count = this.arguments.length; i < count; i++) { > // if argument is an AutoCloseable insert info that it *may* be closed (by the target method, i.e.) >- flowInfo = FakedTrackingVariable.markPassedToOutside(currentScope, this.arguments[i], flowInfo); >+ flowInfo = FakedTrackingVariable.markPassedToOutside(currentScope, this.arguments[i], flowInfo, null); > flowInfo = this.arguments[i].analyseCode(currentScope, flowContext, flowInfo); > if ((this.arguments[i].implicitConversion & TypeIds.UNBOXING) != 0) { > this.arguments[i].checkNPE(currentScope, flowContext, flowInfo); >diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java >index d625d5b..41385c1 100644 >--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java >+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright (c) 2000, 2011 IBM Corporation and others. >+ * Copyright (c) 2000, 2012 IBM Corporation and others. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java >index 9fae009..0534970 100644 >--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java >+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java >@@ -12,6 +12,7 @@ > * bug 358827 - [1.7] exception analysis for t-w-r spoils null analysis > * bug 349326 - [1.7] new warning for missing try-with-resources > * bug 359334 - Analysis for resource leak warnings does not consider exceptions as method exit points >+ * bug 358903 - Filter practically unimportant resource leak warnings > *******************************************************************************/ > package org.eclipse.jdt.internal.compiler.ast; > >@@ -134,7 +135,7 @@ > if (resourceBinding.closeTracker != null) { > // this was false alarm, we don't need to track the resource > this.tryBlock.scope.removeTrackingVar(resourceBinding.closeTracker); >- resourceBinding.closeTracker = null; >+ // keep the tracking variable in the resourceBinding in order to prevent creating a new one while analyzing the try block > } > TypeBinding type = resourceBinding.type; > if (type != null && type.isValidBinding()) { >@@ -276,7 +277,7 @@ > if (resourceBinding.closeTracker != null) { > // this was false alarm, we don't need to track the resource > this.tryBlock.scope.removeTrackingVar(resourceBinding.closeTracker); >- resourceBinding.closeTracker = null; >+ // keep the tracking variable in the resourceBinding in order to prevent creating a new one while analyzing the try block > } > TypeBinding type = resourceBinding.type; > if (type != null && type.isValidBinding()) { >diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java >index 9294726..de17c07 100644 >--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java >+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright (c) 2000, 2011 IBM Corporation and others. >+ * Copyright (c) 2000, 2012 IBM Corporation and others. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -11,6 +11,7 @@ > * bug 349326 - [1.7] new warning for missing try-with-resources > * bug 186342 - [compiler][null] Using annotations for null checking > * bug 364890 - BinaryTypeBinding should use char constants from Util >+ * bug 358903 - Filter practically unimportant resource leak warnings > *******************************************************************************/ > package org.eclipse.jdt.internal.compiler.lookup; > >@@ -1275,7 +1276,9 @@ > this.environment.mayTolerateMissingType = wasToleratingMissingTypeProcessingAnnotations; > } > } >- this.typeBits |= this.superclass.typeBits; >+ this.typeBits |= (this.superclass.typeBits & TypeIds.InheritableBits); >+ if ((this.typeBits & (TypeIds.BitAutoCloseable|TypeIds.BitCloseable)) != 0) // avoid the side-effects of hasTypeBit()! >+ this.typeBits |= applyCloseableWhitelists(); > return this.superclass; > } > // NOTE: superInterfaces of binary types are resolved when needed >@@ -1298,7 +1301,7 @@ > this.environment.mayTolerateMissingType = wasToleratingMissingTypeProcessingAnnotations; > } > } >- this.typeBits |= this.superInterfaces[i].typeBits; >+ this.typeBits |= (this.superInterfaces[i].typeBits & TypeIds.InheritableBits); > } > this.tagBits &= ~TagBits.HasUnresolvedSuperinterfaces; > return this.superInterfaces; >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 c93c9d9..1890315 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 >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright (c) 2000, 2011 IBM Corporation and others. >+ * Copyright (c) 2000, 2012 IBM Corporation and others. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -10,6 +10,7 @@ > * Stephan Herrmann - Contributions for > * bug 349326 - [1.7] new warning for missing try-with-resources > * bug 359334 - Analysis for resource leak warnings does not consider exceptions as method exit points >+ * bug 358903 - Filter practically unimportant resource leak warnings > *******************************************************************************/ > package org.eclipse.jdt.internal.compiler.lookup; > >@@ -981,6 +982,10 @@ > } > /** When are no longer interested in this tracking variable - remove it. */ > public void removeTrackingVar(FakedTrackingVariable trackingVariable) { >+ if (trackingVariable.innerTracker != null) { >+ removeTrackingVar(trackingVariable.innerTracker); >+ trackingVariable.innerTracker = null; >+ } > if (this.trackingVariables != null) > if (this.trackingVariables.remove(trackingVariable)) > return; >@@ -1003,10 +1008,10 @@ > FakedTrackingVariable trackingVar = (FakedTrackingVariable) this.trackingVariables.get(i); > if (location != null && trackingVar.originalBinding != null && flowInfo.isDefinitelyNull(trackingVar.originalBinding)) > continue; // reporting against a specific location, resource is null at this flow, don't complain >- int status = getNullStatusAggressively(trackingVar.binding, flowInfo); >- // try to improve info if a close() inside finally was observed: >- if (locationScope != null) // only check at method exit points >- status = locationScope.mergeCloseStatus(status, trackingVar.binding, this); >+ >+ // compute the most specific null status for this resource, >+ int status = trackingVar.findMostSpecificStatus(flowInfo, this, locationScope); >+ > if (status == FlowInfo.NULL) { > // definitely unclosed: highest priority > reportResourceLeak(trackingVar, location, status); >@@ -1033,24 +1038,6 @@ > this.locals[i].closeTracker = null; > this.trackingVariables = null; > } >-} >- >-private int mergeCloseStatus(int status, LocalVariableBinding binding, BlockScope outerScope) { >- // get the most suitable null status representing whether resource 'binding' has been closed >- // start at this scope and potentially travel out until 'outerScope' >- // at each scope consult any recorded 'finallyInfo'. >- if (status != FlowInfo.NON_NULL) { >- if (this.finallyInfo != null) { >- int finallyStatus = this.finallyInfo.nullStatus(binding); >- if (finallyStatus == FlowInfo.NON_NULL) >- return finallyStatus; >- if (finallyStatus != FlowInfo.NULL) // neither is NON_NULL, but not both are NULL => call it POTENTIALLY_NULL >- status = FlowInfo.POTENTIALLY_NULL; >- } >- if (this != outerScope && this.parent instanceof BlockScope) >- return ((BlockScope) this.parent).mergeCloseStatus(status, binding, outerScope); >- } >- return status; > } > > private void reportResourceLeak(FakedTrackingVariable trackingVar, ASTNode location, int nullStatus) { >@@ -1083,6 +1070,8 @@ > if (this.trackingVariables != null) { > for (int i=0; i<this.trackingVariables.size(); i++) { > FakedTrackingVariable trackingVar = (FakedTrackingVariable) this.trackingVariables.get(i); >+ if (trackingVar.originalBinding == null) >+ continue; > if ( thenFlowInfo.isDefinitelyNonNull(trackingVar.binding) // closed in then branch > && elseFlowInfo.isDefinitelyNull(trackingVar.originalBinding)) // null in else branch > { >@@ -1097,37 +1086,5 @@ > } > if (this.parent instanceof BlockScope) > ((BlockScope) this.parent).correlateTrackingVarsIfElse(thenFlowInfo, elseFlowInfo); >-} >- >-/** >- * Get the null status looking even into unreachable flows >- * @param local >- * @param flowInfo >- * @return one of the constants FlowInfo.{NULL,POTENTIALLY_NULL,POTENTIALLY_NON_NULL,NON_NULL}. >- */ >-private int getNullStatusAggressively(LocalVariableBinding local, FlowInfo flowInfo) { >- int reachMode = flowInfo.reachMode(); >- int status = 0; >- try { >- // unreachable flowInfo is too shy in reporting null-issues, temporarily forget reachability: >- if (reachMode != FlowInfo.REACHABLE) >- flowInfo.tagBits &= ~FlowInfo.UNREACHABLE; >- status = flowInfo.nullStatus(local); >- } finally { >- // reset >- flowInfo.tagBits |= reachMode; >- } >- // at this point some combinations are not useful so flatten to a single bit: >- if ((status & FlowInfo.NULL) != 0) { >- if ((status & (FlowInfo.NON_NULL | FlowInfo.POTENTIALLY_NON_NULL)) != 0) >- return FlowInfo.POTENTIALLY_NULL; // null + doubt = pot null >- return FlowInfo.NULL; >- } else if ((status & FlowInfo.NON_NULL) != 0) { >- 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) >- return FlowInfo.POTENTIALLY_NULL; >- return status; > } > } >diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java >index 3eb3cca..8778c6b 100644 >--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java >+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright (c) 2000, 2011 IBM Corporation and others. >+ * Copyright (c) 2000, 2012 IBM Corporation and others. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -12,6 +12,7 @@ > * Bug 300576 - NPE Computing type hierarchy when compliance doesn't match libraries > * Bug 354536 - compiling package-info.java still depends on the order of compilation units > * Bug 349326 - [1.7] new warning for missing try-with-resources >+ * Bug 358903 - Filter practically unimportant resource leak warnings > *******************************************************************************/ > package org.eclipse.jdt.internal.compiler.lookup; > >@@ -909,7 +910,10 @@ > } else { > // only want to reach here when no errors are reported > sourceType.superclass = superclass; >- sourceType.typeBits |= superclass.typeBits; >+ sourceType.typeBits |= (superclass.typeBits & TypeIds.InheritableBits); >+ // further analysis against white lists for the unlikely case we are compiling java.io.*: >+ if ((sourceType.typeBits & (TypeIds.BitAutoCloseable|TypeIds.BitCloseable)) != 0) >+ sourceType.typeBits |= sourceType.applyCloseableWhitelists(); > return true; > } > } >@@ -1025,7 +1029,7 @@ > noProblems &= superInterfaceRef.resolvedType.isValidBinding(); > } > // only want to reach here when no errors are reported >- sourceType.typeBits |= superInterface.typeBits; >+ sourceType.typeBits |= (superInterface.typeBits & TypeIds.InheritableBits); > interfaceBindings[count++] = superInterface; > } > // hold onto all correctly resolved superinterfaces >diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java >index 75de854..0d82f6c 100644 >--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java >+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright (c) 2000, 2011 IBM Corporation and others. >+ * Copyright (c) 2000, 2012 IBM Corporation and others. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -10,6 +10,7 @@ > * Stephan Herrmann - Contributions for > * bug 349326 - [1.7] new warning for missing try-with-resources > * bug 186342 - [compiler][null] Using annotations for null checking >+ * bug 358903 - Filter practically unimportant resource leak warnings > *******************************************************************************/ > package org.eclipse.jdt.internal.compiler.lookup; > >@@ -1469,4 +1470,50 @@ > public FieldBinding[] unResolvedFields() { > return Binding.NO_FIELDS; > } >+ >+/* >+ * If a type - known to be a Closeable - is mentioned in one of our white lists >+ * answer the typeBit for the white list (BitWrapperCloseable or BitResourceFreeCloseable). >+ */ >+protected int applyCloseableWhitelists() { >+ switch (this.compoundName.length) { >+ case 3: >+ if (CharOperation.equals(TypeConstants.JAVA, this.compoundName[0])) { >+ if (CharOperation.equals(TypeConstants.IO, this.compoundName[1])) { >+ char[] simpleName = this.compoundName[2]; >+ int l = TypeConstants.JAVA_IO_WRAPPER_CLOSEABLES.length; >+ for (int i = 0; i < l; i++) { >+ if (CharOperation.equals(simpleName, TypeConstants.JAVA_IO_WRAPPER_CLOSEABLES[i])) >+ return TypeIds.BitWrapperCloseable; >+ } >+ l = TypeConstants.JAVA_IO_RESOURCE_FREE_CLOSEABLES.length; >+ for (int i = 0; i < l; i++) { >+ if (CharOperation.equals(simpleName, TypeConstants.JAVA_IO_RESOURCE_FREE_CLOSEABLES[i])) >+ return TypeIds.BitResourceFreeCloseable; >+ } >+ } >+ } >+ break; >+ case 4: >+ if (CharOperation.equals(TypeConstants.JAVA, this.compoundName[0])) { >+ if (CharOperation.equals(TypeConstants.UTIL, this.compoundName[1])) { >+ if (CharOperation.equals(TypeConstants.ZIP, this.compoundName[2])) { >+ char[] simpleName = this.compoundName[3]; >+ int l = TypeConstants.JAVA_UTIL_ZIP_WRAPPER_CLOSEABLES.length; >+ for (int i = 0; i < l; i++) { >+ if (CharOperation.equals(simpleName, TypeConstants.JAVA_UTIL_ZIP_WRAPPER_CLOSEABLES[i])) >+ return TypeIds.BitWrapperCloseable; >+ } >+ } >+ } >+ } >+ break; >+ } >+ int l = TypeConstants.OTHER_WRAPPER_CLOSEABLES.length; >+ for (int i = 0; i < l; i++) { >+ if (CharOperation.equals(this.compoundName, TypeConstants.OTHER_WRAPPER_CLOSEABLES[i])) >+ return TypeIds.BitWrapperCloseable; >+ } >+ return 0; >+} > } >diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java >index 0bbef47..679d04b 100644 >--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java >+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright (c) 2000, 2011 IBM Corporation and others. >+ * Copyright (c) 2000, 2012 IBM Corporation and others. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -7,7 +7,9 @@ > * > * Contributors: > * IBM Corporation - initial API and implementation >- * Stephan Herrmann - Contribution for bug 349326 - [1.7] new warning for missing try-with-resources >+ * Stephan Herrmann - Contributions for >+ * bug 349326 - [1.7] new warning for missing try-with-resources >+ * bug 358903 - Filter practically unimportant resource leak warnings > *******************************************************************************/ > package org.eclipse.jdt.internal.compiler.lookup; > >@@ -19,6 +21,7 @@ > char[] LANG = "lang".toCharArray(); //$NON-NLS-1$ > char[] IO = "io".toCharArray(); //$NON-NLS-1$ > char[] UTIL = "util".toCharArray(); //$NON-NLS-1$ >+ char[] ZIP = "zip".toCharArray(); //$NON-NLS-1$ > char[] ANNOTATION = "annotation".toCharArray(); //$NON-NLS-1$ > char[] REFLECT = "reflect".toCharArray(); //$NON-NLS-1$ > char[] LENGTH = "length".toCharArray(); //$NON-NLS-1$ >@@ -154,6 +157,59 @@ > }; > char[][] JAVA_LANG_AUTOCLOSEABLE = {JAVA, LANG, "AutoCloseable".toCharArray()}; //$NON-NLS-1$ > char[] CLOSE = "close".toCharArray(); //$NON-NLS-1$ >+ // white lists of closeables: >+ char[][] JAVA_IO_WRAPPER_CLOSEABLES = new char[][] { >+ "BufferedInputStream".toCharArray(), //$NON-NLS-1$ >+ "BufferedOutputStream".toCharArray(), //$NON-NLS-1$ >+ "BufferedReader".toCharArray(), //$NON-NLS-1$ >+ "BufferedWriter".toCharArray(), //$NON-NLS-1$ >+ "InputStreamReader".toCharArray(), //$NON-NLS-1$ >+ "PrintWriter".toCharArray(), //$NON-NLS-1$ >+ "LineNumberReader".toCharArray(), //$NON-NLS-1$ >+ "DataInputStream".toCharArray(), //$NON-NLS-1$ >+ "DataOutputStream".toCharArray(), //$NON-NLS-1$ >+ "ObjectInputStream".toCharArray(), //$NON-NLS-1$ >+ "ObjectOutputStream".toCharArray(), //$NON-NLS-1$ >+ "FilterInputStream".toCharArray(), //$NON-NLS-1$ >+ "FilterOutputStream".toCharArray(), //$NON-NLS-1$ >+ "DataInputStream".toCharArray(), //$NON-NLS-1$ >+ "DataOutputStream".toCharArray(), //$NON-NLS-1$ >+ "PushbackInputStream".toCharArray(), //$NON-NLS-1$ >+ "SequenceInputStream".toCharArray(), //$NON-NLS-1$ >+ "PrintStream".toCharArray(), //$NON-NLS-1$ >+ "PushbackReader".toCharArray(), //$NON-NLS-1$ >+ "OutputStreamWriter".toCharArray(), //$NON-NLS-1$ >+ }; >+ char[][] JAVA_UTIL_ZIP_WRAPPER_CLOSEABLES = new char[][] { >+ "GZIPInputStream".toCharArray(), //$NON-NLS-1$ >+ "InflaterInputStream".toCharArray(), //$NON-NLS-1$ >+ "DeflaterInputStream".toCharArray(), //$NON-NLS-1$ >+ "CheckedInputStream".toCharArray(), //$NON-NLS-1$ >+ "ZipInputStream".toCharArray(), //$NON-NLS-1$ >+ "JarInputStream".toCharArray(), //$NON-NLS-1$ >+ "GZIPOutputStream".toCharArray(), //$NON-NLS-1$ >+ "InflaterOutputStream".toCharArray(), //$NON-NLS-1$ >+ "DeflaterOutputStream".toCharArray(), //$NON-NLS-1$ >+ "CheckedOutputStream".toCharArray(), //$NON-NLS-1$ >+ "ZipOutputStream".toCharArray(), //$NON-NLS-1$ >+ "JarOutputStream".toCharArray(), //$NON-NLS-1$ >+ }; >+ char[][][] OTHER_WRAPPER_CLOSEABLES = new char[][][] { >+ {JAVA, "security".toCharArray(), "DigestInputStream".toCharArray()}, //$NON-NLS-1$ //$NON-NLS-2$ >+ {JAVA, "security".toCharArray(), "DigestOutputStream".toCharArray()}, //$NON-NLS-1$ //$NON-NLS-2$ >+ {JAVA, "beans".toCharArray(), "XMLEncoder".toCharArray()}, //$NON-NLS-1$ //$NON-NLS-2$ >+ {JAVA, "beans".toCharArray(), "XMLDecoder".toCharArray()}, //$NON-NLS-1$ //$NON-NLS-2$ >+ {JAVAX, "sound".toCharArray(), "sampled".toCharArray(), "AudioInputStream".toCharArray()}, //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ >+ }; >+ char[][] JAVA_IO_RESOURCE_FREE_CLOSEABLES = new char[][] { >+ "StringReader".toCharArray(), //$NON-NLS-1$ >+ "StringWriter".toCharArray(), //$NON-NLS-1$ >+ "ByteArrayInputStream".toCharArray(), //$NON-NLS-1$ >+ "ByteArrayOutputStream".toCharArray(), //$NON-NLS-1$ >+ "CharArrayReader".toCharArray(), //$NON-NLS-1$ >+ "CharArrayWriter".toCharArray(), //$NON-NLS-1$ >+ "StringBufferInputStream".toCharArray(), //$NON-NLS-1$ >+ }; > > // Constraints for generic type argument inference > int CONSTRAINT_EQUAL = 0; // Actual = Formal >diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java >index 7fff434..1e4514b 100644 >--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java >+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright (c) 2000, 2011 IBM Corporation and others. >+ * Copyright (c) 2000, 2012 IBM Corporation and others. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -11,6 +11,7 @@ > * bug 349326 - [1.7] new warning for missing try-with-resources > * bug 359362 - FUP of bug 349326: Resource leak on non-Closeable resource > * bug 186342 - [compiler][null] Using annotations for null checking >+ * bug 358903 - Filter practically unimportant resource leak warnings > *******************************************************************************/ > package org.eclipse.jdt.internal.compiler.lookup; > >@@ -207,4 +208,19 @@ > * @see ReferenceBinding#hasTypeBit(int) > */ > final int BitCloseable = 2; >+ /** >+ * Bit for members of a white list: >+ * Subtypes of Closeable that wrap another resource without directly holding any OS resources. >+ */ >+ final int BitWrapperCloseable = 4; >+ /** >+ * Bit for members of a white list: >+ * Subtypes of Closeable that do not hold an OS resource that needs to be released. >+ */ >+ final int BitResourceFreeCloseable = 8; >+ >+ /** >+ * Set of type bits that should be inherited by any sub types. >+ */ >+ final int InheritableBits = BitAutoCloseable | BitCloseable; > } >diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeVariableBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeVariableBinding.java >index 995f30e..91a7065 100644 >--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeVariableBinding.java >+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeVariableBinding.java >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright (c) 2000, 2011 IBM Corporation and others. >+ * Copyright (c) 2000, 2012 IBM Corporation and others. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -11,6 +11,7 @@ > * bug 282152 - [1.5][compiler] Generics code rejected by Eclipse but accepted by javac > * bug 349326 - [1.7] new warning for missing try-with-resources > * bug 359362 - FUP of bug 349326: Resource leak on non-Closeable resource >+ * bug 358903 - Filter practically unimportant resource leak warnings > *******************************************************************************/ > package org.eclipse.jdt.internal.compiler.lookup; > >@@ -316,11 +317,11 @@ > // initialize from bounds > this.typeBits = 0; > if (this.superclass != null && this.superclass.hasTypeBit(~TypeIds.BitUninitialized)) >- this.typeBits |= this.superclass.typeBits; >+ this.typeBits |= (this.superclass.typeBits & TypeIds.InheritableBits); > if (this.superInterfaces != null) > for (int i = 0, l = this.superInterfaces.length; i < l; i++) > if (this.superInterfaces[i].hasTypeBit(~TypeIds.BitUninitialized)) >- this.typeBits |= this.superInterfaces[i].typeBits; >+ this.typeBits |= (this.superInterfaces[i].typeBits & TypeIds.InheritableBits); > } > return (this.typeBits & bit) != 0; > } >diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/WildcardBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/WildcardBinding.java >index 01f369e..93dffe1 100644 >--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/WildcardBinding.java >+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/WildcardBinding.java >@@ -1,5 +1,5 @@ > /******************************************************************************* >- * Copyright (c) 2005, 2011 IBM Corporation and others. >+ * Copyright (c) 2005, 2012 IBM Corporation and others. > * All rights reserved. This program and the accompanying materials > * are made available under the terms of the Eclipse Public License v1.0 > * which accompanies this distribution, and is available at >@@ -10,6 +10,7 @@ > * Stephan Herrmann - Contribution for > * bug 349326 - [1.7] new warning for missing try-with-resources > * bug 359362 - FUP of bug 349326: Resource leak on non-Closeable resource >+ * bug 358903 - Filter practically unimportant resource leak warnings > *******************************************************************************/ > package org.eclipse.jdt.internal.compiler.lookup; > >@@ -429,11 +430,11 @@ > // initialize from upper bounds > this.typeBits = 0; > if (this.superclass != null && this.superclass.hasTypeBit(~TypeIds.BitUninitialized)) >- this.typeBits |= this.superclass.typeBits; >+ this.typeBits |= (this.superclass.typeBits & TypeIds.InheritableBits); > if (this.superInterfaces != null) > for (int i = 0, l = this.superInterfaces.length; i < l; i++) > if (this.superInterfaces[i].hasTypeBit(~TypeIds.BitUninitialized)) >- this.typeBits |= this.superInterfaces[i].typeBits; >+ this.typeBits |= (this.superInterfaces[i].typeBits & TypeIds.InheritableBits); > } > return (this.typeBits & bit) != 0; > }
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 358903
:
208899
|
209082
|
209107
|
209169
|
209179
|
209232
|
209234
|
209276
|
209373
|
209374
|
209384
|
209409
|
209457
|
209460
|
209464
|
209472
|
209482