View | Details | Raw Unified | Return to bug 358903 | Differences between
and this patch

Collapse All | Expand All

(-)a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/TryWithResourcesStatementTest.java (-7 / +733 lines)
Lines 14-21 Link Here
14
 *******************************************************************************/
14
 *******************************************************************************/
15
package org.eclipse.jdt.core.tests.compiler.regression;
15
package org.eclipse.jdt.core.tests.compiler.regression;
16
16
17
import java.io.IOException;
18
import java.net.URL;
17
import java.util.Map;
19
import java.util.Map;
18
20
21
import org.eclipse.core.runtime.FileLocator;
22
import org.eclipse.core.runtime.Path;
23
import org.eclipse.core.runtime.Platform;
19
import org.eclipse.jdt.core.JavaCore;
24
import org.eclipse.jdt.core.JavaCore;
20
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
25
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
21
26
Lines 23-29 Link Here
23
public class TryWithResourcesStatementTest extends AbstractRegressionTest {
28
public class TryWithResourcesStatementTest extends AbstractRegressionTest {
24
29
25
static {
30
static {
26
//	TESTS_NAMES = new String[] { "test056throw"};
31
//	TESTS_NAMES = new String[] { "test063c"};
27
//	TESTS_NUMBERS = new int[] { 50 };
32
//	TESTS_NUMBERS = new int[] { 50 };
28
//	TESTS_RANGE = new int[] { 11, -1 };
33
//	TESTS_RANGE = new int[] { 11, -1 };
29
}
34
}
Lines 3713-3723 Link Here
3713
		options);
3718
		options);
3714
}
3719
}
3715
// Bug 349326 - [1.7] new warning for missing try-with-resources
3720
// Bug 349326 - [1.7] new warning for missing try-with-resources
3721
// Bug 362332 - Only report potential leak when closeable not created in the local scope
3716
// one method returns an AutoCleasble, a second method uses this object without ever closing it.
3722
// one method returns an AutoCleasble, a second method uses this object without ever closing it.
3717
public void test056e() {
3723
public void test056e() {
3718
	Map options = getCompilerOptions();
3724
	Map options = getCompilerOptions();
3719
	options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR);
3725
	options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR);
3720
	options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.WARNING);
3726
	options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR);
3721
	this.runNegativeTest(
3727
	this.runNegativeTest(
3722
		new String[] {
3728
		new String[] {
3723
			"X.java",
3729
			"X.java",
Lines 3744-3750 Link Here
3744
		"1. ERROR in X.java (at line 11)\n" + 
3750
		"1. ERROR in X.java (at line 11)\n" + 
3745
		"	FileReader reader = getReader(\"somefile\");\n" + 
3751
		"	FileReader reader = getReader(\"somefile\");\n" + 
3746
		"	           ^^^^^^\n" + 
3752
		"	           ^^^^^^\n" + 
3747
		"Resource leak: 'reader' is never closed\n" + 
3753
		"Potential resource leak: \'reader\' may not be closed\n" + 
3748
		"----------\n",
3754
		"----------\n",
3749
		null,
3755
		null,
3750
		true,
3756
		true,
Lines 4358-4368 Link Here
4358
		null/*requestor*/);
4364
		null/*requestor*/);
4359
}
4365
}
4360
// Bug 349326 - [1.7] new warning for missing try-with-resources
4366
// Bug 349326 - [1.7] new warning for missing try-with-resources
4367
// Bug 362332 - Only report potential leak when closeable not created in the local scope
4361
// a method uses an AutoCloseable without ever closing it, type from a type variable
4368
// a method uses an AutoCloseable without ever closing it, type from a type variable
4362
public void test056p() {
4369
public void test056p() {
4363
	Map options = getCompilerOptions();
4370
	Map options = getCompilerOptions();
4364
	options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR);
4371
	options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR);
4365
	options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.WARNING);
4372
	options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR);
4366
	this.runNegativeTest(
4373
	this.runNegativeTest(
4367
		new String[] {
4374
		new String[] {
4368
			"X.java",
4375
			"X.java",
Lines 4389-4395 Link Here
4389
		"1. ERROR in X.java (at line 8)\n" + 
4396
		"1. ERROR in X.java (at line 8)\n" + 
4390
		"	T fileReader = newReader(file);\n" + 
4397
		"	T fileReader = newReader(file);\n" + 
4391
		"	  ^^^^^^^^^^\n" + 
4398
		"	  ^^^^^^^^^^\n" + 
4392
		"Resource leak: 'fileReader' is never closed\n" +
4399
		"Potential resource leak: \'fileReader\' may not be closed\n" +
4393
		"----------\n",
4400
		"----------\n",
4394
		null,
4401
		null,
4395
		true,
4402
		true,
Lines 4444-4450 Link Here
4444
		options);
4451
		options);
4445
}
4452
}
4446
// Bug 349326 - [1.7] new warning for missing try-with-resources
4453
// Bug 349326 - [1.7] new warning for missing try-with-resources
4447
// closed in dead code
4454
// properly closed, dead code in between
4448
public void test056r() {
4455
public void test056r() {
4449
	Map options = getCompilerOptions();
4456
	Map options = getCompilerOptions();
4450
	options.put(JavaCore.COMPILER_PB_UNCLOSED_CLOSEABLE, CompilerOptions.ERROR);
4457
	options.put(JavaCore.COMPILER_PB_UNCLOSED_CLOSEABLE, CompilerOptions.ERROR);
Lines 5354-5360 Link Here
5354
		"X::~X\n" + 
5361
		"X::~X\n" + 
5355
		"true");
5362
		"true");
5356
}
5363
}
5357
5364
// Bug 358903 - Filter practically unimportant resource leak warnings
5365
// Bug 360908 - Avoid resource leak warning when the underlying/chained resource is closed explicitly
5366
// a resource wrapper is not closed but the underlying resource is
5367
public void test061a() {
5368
	Map options = getCompilerOptions();
5369
	options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR);
5370
	options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR);
5371
	this.runConformTest(
5372
		new String[] {
5373
			"X.java",
5374
			"import java.io.File;\n" +
5375
			"import java.io.BufferedInputStream;\n" +
5376
			"import java.io.FileInputStream;\n" +
5377
			"import java.io.IOException;\n" +
5378
			"public class X {\n" +
5379
			"    void foo() throws IOException {\n" +
5380
			"        File file = new File(\"somefile\");\n" +
5381
			"        FileInputStream fileStream  = new FileInputStream(file);\n" +
5382
			"        BufferedInputStream bis = new BufferedInputStream(fileStream);\n" +
5383
			"        BufferedInputStream doubleWrap = new BufferedInputStream(bis);\n" +
5384
			"        System.out.println(bis.available());\n" +
5385
			"        fileStream.close();\n" +
5386
			"    }\n" +
5387
			"    void inline() throws IOException {\n" +
5388
			"        File file = new File(\"somefile\");\n" +
5389
			"        FileInputStream fileStream;\n" +
5390
			"        BufferedInputStream bis = new BufferedInputStream(fileStream = new FileInputStream(file));\n" +
5391
			"        System.out.println(bis.available());\n" +
5392
			"        fileStream.close();\n" +
5393
			"    }\n" +
5394
			"    public static void main(String[] args) throws IOException {\n" +
5395
			"        try {\n" +
5396
			"            new X().foo();\n" +
5397
			"        } catch (IOException ex) {" +
5398
			"            System.out.println(\"Got IO Exception\");\n" +
5399
			"        }\n" +
5400
			"    }\n" +
5401
			"}\n"
5402
		},
5403
		"Got IO Exception",
5404
		null,
5405
		true,
5406
		null,
5407
		options,
5408
		null);
5409
}
5410
// Bug 358903 - Filter practically unimportant resource leak warnings
5411
// a closeable without OS resource is not closed
5412
public void test061b() {
5413
	Map options = getCompilerOptions();
5414
	options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR);
5415
	options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR);
5416
	this.runConformTest(
5417
		new String[] {
5418
			"X.java",
5419
			"import java.io.StringReader;\n" +
5420
			"import java.io.IOException;\n" +
5421
			"public class X {\n" +
5422
			"    void foo() throws IOException {\n" +
5423
			"        StringReader string  = new StringReader(\"content\");\n" +
5424
			"        System.out.println(string.read());\n" +
5425
			"    }\n" +
5426
			"    public static void main(String[] args) throws IOException {\n" +
5427
			"        new X().foo();\n" +
5428
			"    }\n" +
5429
			"}\n"
5430
		},
5431
		"99", // character 'c'
5432
		null,
5433
		true,
5434
		null,
5435
		options,
5436
		null);
5437
}
5438
// Bug 358903 - Filter practically unimportant resource leak warnings
5439
// a resource wrapper is not closed but the underlying closeable is resource-free
5440
public void test061c() {
5441
	Map options = getCompilerOptions();
5442
	options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR);
5443
	options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR);
5444
	this.runConformTest(
5445
		new String[] {
5446
			"X.java",
5447
			"import java.io.BufferedReader;\n" +
5448
			"import java.io.StringReader;\n" +
5449
			"import java.io.IOException;\n" +
5450
			"public class X {\n" +
5451
			"    void foo() throws IOException {\n" +
5452
			"        StringReader input = new StringReader(\"content\");\n" +
5453
			"        BufferedReader br = new BufferedReader(input);\n" +
5454
			"        BufferedReader doubleWrap = new BufferedReader(br);\n" +
5455
			"        System.out.println(br.read());\n" +
5456
			"    }\n" +
5457
			"    void inline() throws IOException {\n" +
5458
			"        BufferedReader br = new BufferedReader(new StringReader(\"content\"));\n" +
5459
			"        System.out.println(br.read());\n" +
5460
			"    }\n" +
5461
			"    public static void main(String[] args) throws IOException {\n" +
5462
			"        new X().foo();\n" +
5463
			"    }\n" +
5464
			"}\n"
5465
		},
5466
		"99",
5467
		null,
5468
		true,
5469
		null,
5470
		options,
5471
		null);
5472
}
5473
// Bug 358903 - Filter practically unimportant resource leak warnings
5474
// a resource wrapper is not closed neither is the underlying resource
5475
public void test061d() {
5476
	Map options = getCompilerOptions();
5477
	options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR);
5478
	options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.WARNING);
5479
	this.runNegativeTest(
5480
		new String[] {
5481
			"X.java",
5482
			"import java.io.File;\n" +
5483
			"import java.io.BufferedInputStream;\n" +
5484
			"import java.io.FileInputStream;\n" +
5485
			"import java.io.IOException;\n" +
5486
			"public class X {\n" +
5487
			"    void foo() throws IOException {\n" +
5488
			"        File file = new File(\"somefile\");\n" +
5489
			"        FileInputStream fileStream  = new FileInputStream(file);\n" +
5490
			"        BufferedInputStream bis = new BufferedInputStream(fileStream);\n" +
5491
			"        BufferedInputStream doubleWrap = new BufferedInputStream(bis);\n" +
5492
			"        System.out.println(bis.available());\n" +
5493
			"    }\n" +
5494
			"    void inline() throws IOException {\n" +
5495
			"        File file = new File(\"somefile\");\n" +
5496
			"        BufferedInputStream bis2 = new BufferedInputStream(new FileInputStream(file));\n" +
5497
			"        System.out.println(bis2.available());\n" +
5498
			"    }\n" +
5499
			"    public static void main(String[] args) throws IOException {\n" +
5500
			"        try {\n" +
5501
			"            new X().foo();\n" +
5502
			"        } catch (IOException ex) {" +
5503
			"            System.out.println(\"Got IO Exception\");\n" +
5504
			"        }\n" +
5505
			"    }\n" +
5506
			"}\n"
5507
		},
5508
		"----------\n" + 
5509
		"1. ERROR in X.java (at line 10)\n" + 
5510
		"	BufferedInputStream doubleWrap = new BufferedInputStream(bis);\n" + 
5511
		"	                    ^^^^^^^^^^\n" + 
5512
		"Resource leak: \'doubleWrap\' is never closed\n" + 
5513
		"----------\n" + 
5514
		"2. ERROR in X.java (at line 15)\n" + 
5515
		"	BufferedInputStream bis2 = new BufferedInputStream(new FileInputStream(file));\n" + 
5516
		"	                    ^^^^\n" + 
5517
		"Resource leak: \'bis2\' is never closed\n" + 
5518
		"----------\n",
5519
		null,
5520
		true,
5521
		options);
5522
}
5523
// Bug 358903 - Filter practically unimportant resource leak warnings
5524
// Bug 361073 - Avoid resource leak warning when the top level resource is closed explicitly
5525
// a resource wrapper is closed closing also the underlying resource
5526
public void test061e() {
5527
	Map options = getCompilerOptions();
5528
	options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR);
5529
	options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR);
5530
	this.runConformTest(
5531
		new String[] {
5532
			"X.java",
5533
			"import java.io.File;\n" +
5534
			"import java.io.BufferedInputStream;\n" +
5535
			"import java.io.FileInputStream;\n" +
5536
			"import java.io.IOException;\n" +
5537
			"public class X {\n" +
5538
			"    FileInputStream fis;" +
5539
			"    void foo() throws IOException {\n" +
5540
			"        File file = new File(\"somefile\");\n" +
5541
			"        FileInputStream fileStream  = new FileInputStream(file);\n" +
5542
			"        BufferedInputStream bis = new BufferedInputStream(fileStream);\n" +
5543
			"        BufferedInputStream doubleWrap = new BufferedInputStream(bis);\n" +
5544
			"        System.out.println(bis.available());\n" +
5545
			"        bis.close();\n" +
5546
			"    }\n" +
5547
			"    void inline() throws IOException {\n" +
5548
			"        File file = new File(\"somefile\");\n" +
5549
			"        BufferedInputStream bis2 = new BufferedInputStream(fis = new FileInputStream(file));\n" + // field assignment
5550
			"        System.out.println(bis2.available());\n" +
5551
			"        bis2.close();\n" +
5552
			"        FileInputStream fileStream  = null;\n" +
5553
			"        BufferedInputStream bis3 = new BufferedInputStream(fileStream = new FileInputStream(file));\n" +
5554
			"        System.out.println(bis3.available());\n" +
5555
			"        bis3.close();\n" +
5556
			"    }\n" +
5557
			"    public static void main(String[] args) throws IOException {\n" +
5558
			"        try {\n" +
5559
			"            new X().foo();\n" +
5560
			"        } catch (IOException ex) {" +
5561
			"            System.out.println(\"Got IO Exception\");\n" +
5562
			"        }\n" +
5563
			"    }\n" +
5564
			"}\n"
5565
		},
5566
		"Got IO Exception",
5567
		null,
5568
		true,
5569
		null,
5570
		options,
5571
		null);
5572
}
5573
// Bug 358903 - Filter practically unimportant resource leak warnings
5574
// Bug 361073 - Avoid resource leak warning when the top level resource is closed explicitly
5575
// a resource wrapper is closed closing also the underlying resource - original test case
5576
public void test061f() throws IOException {
5577
	Map options = getCompilerOptions();
5578
	options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR);
5579
	options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR);
5580
	URL url = FileLocator.toFileURL(FileLocator.find(Platform.getBundle("org.eclipse.jdt.core.tests.compiler"), new Path("META-INF/MANIFEST.MF"), null));
5581
	this.runConformTest(
5582
		new String[] {
5583
			"X.java",
5584
			"import java.io.InputStream;\n" +
5585
			"import java.io.InputStreamReader;\n" +
5586
			"import java.io.BufferedReader;\n" +
5587
			"import java.io.IOException;\n" +
5588
			"import java.net.URL;\n" +
5589
			"public class X {\n" +
5590
			"    boolean loadURL(final URL url) throws IOException {\n" + 
5591
			"        InputStream stream = null;\n" + 
5592
			"        BufferedReader reader = null;\n" + 
5593
			"        try {\n" + 
5594
			"            stream = url.openStream();\n" + 
5595
			"            reader = new BufferedReader(new InputStreamReader(stream));\n" + 
5596
			"            System.out.println(reader.readLine());\n" +
5597
			"        } finally {\n" + 
5598
			"            try {\n" + 
5599
			"                if (reader != null)\n" + 
5600
			"                    reader.close();\n" + 
5601
			"            } catch (IOException x) {\n" + 
5602
			"            }\n" + 
5603
			"        }\n" + 
5604
			"        return false; // 'stream' may not be closed at this location\n" + 
5605
			"    }\n" + 
5606
			"    public static void main(String[] args) throws IOException {\n" +
5607
			"        try {\n" +
5608
			"            new X().loadURL(new URL(\""+url.toString()+"\"));\n" +
5609
			"        } catch (IOException ex) {\n" +
5610
			"            System.out.println(\"Got IO Exception\"+ex);\n" +
5611
			"        }\n" +
5612
			"    }\n" +
5613
			"}\n"
5614
		},
5615
		"Manifest-Version: 1.0",
5616
		null,
5617
		true,
5618
		null,
5619
		options,
5620
		null);
5621
}
5622
// Bug 358903 - Filter practically unimportant resource leak warnings
5623
// Bug 360908 - Avoid resource leak warning when the underlying/chained resource is closed explicitly
5624
// Different points in a resource chain are closed
5625
public void test061g() {
5626
	Map options = getCompilerOptions();
5627
	options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR);
5628
	options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR);
5629
	this.runNegativeTest(
5630
		new String[] {
5631
			"X.java",
5632
			"import java.io.File;\n" +
5633
			"import java.io.BufferedInputStream;\n" +
5634
			"import java.io.FileInputStream;\n" +
5635
			"import java.io.IOException;\n" +
5636
			"public class X {\n" +
5637
			"    void closeMiddle() throws IOException {\n" +
5638
			"        File file = new File(\"somefile\");\n" +
5639
			"        FileInputStream fileStream  = new FileInputStream(file);\n" +
5640
			"        BufferedInputStream bis = new BufferedInputStream(fileStream);\n" +
5641
			"        BufferedInputStream doubleWrap = new BufferedInputStream(bis);\n" +
5642
			"        System.out.println(bis.available());\n" +
5643
			"        bis.close();\n" +
5644
			"    }\n" +
5645
			"    void closeOuter() throws IOException {\n" +
5646
			"        File file2 = new File(\"somefile\");\n" +
5647
			"        FileInputStream fileStream2  = new FileInputStream(file2);\n" +
5648
			"        BufferedInputStream bis2 = new BufferedInputStream(fileStream2);\n" +
5649
			"        BufferedInputStream doubleWrap2 = new BufferedInputStream(bis2);\n" +
5650
			"        System.out.println(bis2.available());\n" +
5651
			"        doubleWrap2.close();\n" +
5652
			"    }\n" +
5653
			"    void neverClosed() throws IOException {\n" +
5654
			"        File file3 = new File(\"somefile\");\n" +
5655
			"        FileInputStream fileStream3  = new FileInputStream(file3);\n" +
5656
			"        BufferedInputStream bis3 = new BufferedInputStream(fileStream3);\n" +
5657
			"        BufferedInputStream doubleWrap3 = new BufferedInputStream(bis3);\n" +
5658
			"        System.out.println(doubleWrap3.available());\n" +
5659
			"    }\n" +
5660
			"}\n"
5661
		},
5662
		"----------\n" + 
5663
		"1. ERROR in X.java (at line 26)\n" + 
5664
		"	BufferedInputStream doubleWrap3 = new BufferedInputStream(bis3);\n" + 
5665
		"	                    ^^^^^^^^^^^\n" + 
5666
		"Resource leak: \'doubleWrap3\' is never closed\n" + 
5667
		"----------\n",
5668
		null,
5669
		true,
5670
		options);
5671
}
5672
// Bug 358903 - Filter practically unimportant resource leak warnings
5673
// Bug 360908 - Avoid resource leak warning when the underlying/chained resource is closed explicitly
5674
// Different points in a resource chain are potentially closed
5675
public void test061h() {
5676
	Map options = getCompilerOptions();
5677
	options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR);
5678
	options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR);
5679
	this.runNegativeTest(
5680
		new String[] {
5681
			"X.java",
5682
			"import java.io.File;\n" +
5683
			"import java.io.BufferedInputStream;\n" +
5684
			"import java.io.FileInputStream;\n" +
5685
			"import java.io.IOException;\n" +
5686
			"public class X {\n" +
5687
			"    void closeMiddle(boolean b) throws IOException {\n" +
5688
			"        File file = new File(\"somefile\");\n" +
5689
			"        FileInputStream fileStream  = new FileInputStream(file);\n" +
5690
			"        BufferedInputStream bis = new BufferedInputStream(fileStream);\n" +
5691
			"        BufferedInputStream doubleWrap = new BufferedInputStream(bis);\n" +
5692
			"        System.out.println(bis.available());\n" +
5693
			"        if (b)\n" +
5694
			"            bis.close();\n" +
5695
			"    }\n" +
5696
			"    void closeOuter(boolean b) throws IOException {\n" +
5697
			"        File file2 = new File(\"somefile\");\n" +
5698
			"        FileInputStream fileStream2  = new FileInputStream(file2);\n" +
5699
			"        BufferedInputStream dummy;\n" +
5700
			"        BufferedInputStream bis2 = (dummy = new BufferedInputStream(fileStream2));\n" +
5701
			"        BufferedInputStream doubleWrap2 = new BufferedInputStream(bis2);\n" +
5702
			"        System.out.println(bis2.available());\n" +
5703
			"        if (b)\n" +
5704
			"            doubleWrap2.close();\n" +
5705
			"    }\n" +
5706
			"    void potAndDef(boolean b) throws IOException {\n" +
5707
			"        File file3 = new File(\"somefile\");\n" +
5708
			"        FileInputStream fileStream3  = new FileInputStream(file3);\n" +
5709
			"        BufferedInputStream bis3 = new BufferedInputStream(fileStream3);\n" +
5710
			"        BufferedInputStream doubleWrap3 = new BufferedInputStream(bis3);\n" +
5711
			"        System.out.println(doubleWrap3.available());\n" +
5712
			"        if (b) bis3.close();\n" +
5713
			"        fileStream3.close();\n" +
5714
			"    }\n" +
5715
			"}\n"
5716
		},
5717
		"----------\n" + 
5718
		"1. ERROR in X.java (at line 10)\n" + 
5719
		"	BufferedInputStream doubleWrap = new BufferedInputStream(bis);\n" + 
5720
		"	                    ^^^^^^^^^^\n" + 
5721
		"Potential resource leak: \'doubleWrap\' may not be closed\n" + 
5722
		"----------\n" + 
5723
		"2. ERROR in X.java (at line 20)\n" + 
5724
		"	BufferedInputStream doubleWrap2 = new BufferedInputStream(bis2);\n" + 
5725
		"	                    ^^^^^^^^^^^\n" + 
5726
		"Potential resource leak: \'doubleWrap2\' may not be closed\n" + 
5727
		"----------\n",
5728
		null,
5729
		true,
5730
		options);
5731
}
5732
// Bug 358903 - Filter practically unimportant resource leak warnings
5733
// local var is re-used for two levels of wrappers
5734
public void test061i() {
5735
	Map options = getCompilerOptions();
5736
	options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR);
5737
	options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR);
5738
	this.runNegativeTest(
5739
		new String[] {
5740
			"X.java",
5741
			"import java.io.File;\n" +
5742
			"import java.io.InputStream;\n" +
5743
			"import java.io.BufferedInputStream;\n" +
5744
			"import java.io.FileInputStream;\n" +
5745
			"import java.io.IOException;\n" +
5746
			"public class X {\n" +
5747
			"    void closeMiddle() throws IOException {\n" +
5748
			"        File file = new File(\"somefile\");\n" +
5749
			"        InputStream stream  = new FileInputStream(file);\n" +
5750
			"        stream = new BufferedInputStream(stream);\n" +
5751
			"        InputStream middle;\n" +
5752
			"        stream = new BufferedInputStream(middle = stream);\n" +
5753
			"        System.out.println(stream.available());\n" +
5754
			"        middle.close();\n" +
5755
			"    }\n" +
5756
			"    void closeOuter() throws IOException {\n" +
5757
			"        File file = new File(\"somefile\");\n" +
5758
			"        InputStream stream2  = new FileInputStream(file);\n" +
5759
			"        stream2 = new BufferedInputStream(stream2);\n" +
5760
			"        stream2 = new BufferedInputStream(stream2);\n" +
5761
			"        System.out.println(stream2.available());\n" +
5762
			"        stream2.close();\n" +
5763
			"    }\n" +
5764
			"    void neverClosed() throws IOException {\n" +
5765
			"        File file = new File(\"somefile\");\n" +
5766
			"        InputStream stream3  = new FileInputStream(file);\n" +
5767
			"        stream3 = new BufferedInputStream(stream3);\n" +
5768
			"        stream3 = new BufferedInputStream(stream3);\n" +
5769
			"        System.out.println(stream3.available());\n" +
5770
			"    }\n" +
5771
			"}\n"
5772
		},
5773
		"----------\n" + 
5774
		"1. ERROR in X.java (at line 26)\n" + 
5775
		"	InputStream stream3  = new FileInputStream(file);\n" + 
5776
		"	            ^^^^^^^\n" + 
5777
		"Resource leak: \'stream3\' is never closed\n" + 
5778
		"----------\n",
5779
		null,
5780
		true,
5781
		options);
5782
}
5783
// Bug 358903 - Filter practically unimportant resource leak warnings
5784
// self-wrapping a method argument (caused NPE UnconditionalFlowInfo.markAsDefinitelyNull(..)).
5785
public void test061j() {
5786
	Map options = getCompilerOptions();
5787
	options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR);
5788
	options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR);
5789
	this.runConformTest(
5790
		new String[] {
5791
			"X.java",
5792
			"import java.io.InputStream;\n" +
5793
			"import java.io.BufferedInputStream;\n" +
5794
			"import java.io.IOException;\n" +
5795
			"public class X {\n" +
5796
			"    void foo(InputStream stream) throws IOException {\n" +
5797
			"        stream = new BufferedInputStream(stream);\n" +
5798
			"        System.out.println(stream.available());\n" +
5799
			"        stream.close();\n" +
5800
			"    }\n" +
5801
			"    void boo(InputStream stream2) throws IOException {\n" +
5802
			"        stream2 = new BufferedInputStream(stream2);\n" +
5803
			"        System.out.println(stream2.available());\n" +
5804
			"    }\n" +
5805
			"}\n"
5806
		},
5807
		"",
5808
		null,
5809
		true,
5810
		null,
5811
		options,
5812
		null);
5813
}
5814
// Bug 358903 - Filter practically unimportant resource leak warnings
5815
// a wrapper is created in a return statement
5816
public void test061k() throws IOException {
5817
	Map options = getCompilerOptions();
5818
	options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR);
5819
	options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR);
5820
	this.runConformTest(
5821
		new String[] {
5822
			"X.java",
5823
			"import java.io.File;\n" +
5824
			"import java.io.FileInputStream;\n" +
5825
			"import java.io.BufferedInputStream;\n" +
5826
			"import java.io.IOException;\n" +
5827
			"public class X {\n" +
5828
			"    BufferedInputStream getReader(File file) throws IOException {\n" +
5829
			"        FileInputStream stream = new FileInputStream(file);\n" +
5830
			"        return new BufferedInputStream(stream);\n" +
5831
			"    }\n" +
5832
			"}\n"
5833
		},
5834
		"",
5835
		null,
5836
		true,
5837
		null,
5838
		options,
5839
		null);
5840
}
5841
// Bug 358903 - Filter practically unimportant resource leak warnings
5842
// a closeable is assigned to a field
5843
public void test061l() throws IOException {
5844
	Map options = getCompilerOptions();
5845
	options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR);
5846
	options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR);
5847
	this.runConformTest(
5848
		new String[] {
5849
			"X.java",
5850
			"import java.io.File;\n" +
5851
			"import java.io.FileInputStream;\n" +
5852
			"import java.io.BufferedInputStream;\n" +
5853
			"import java.io.IOException;\n" +
5854
			"public class X {\n" +
5855
			"    BufferedInputStream stream;\n" +
5856
			"    void foo(File file) throws IOException {\n" +
5857
			"        FileInputStream s = new FileInputStream(file);\n" +
5858
			"        stream = new BufferedInputStream(s);\n" +
5859
			"    }\n" +
5860
			"}\n"
5861
		},
5862
		"",
5863
		null,
5864
		true,
5865
		null,
5866
		options,
5867
		null);
5868
}
5869
// Bug 362331 - Resource leak not detected when closeable not assigned to variable
5870
// a resource is never assigned
5871
public void test062a() throws IOException {
5872
	Map options = getCompilerOptions();
5873
	options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR);
5874
	options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR);
5875
	this.runNegativeTest(
5876
		new String[] {
5877
			"X.java",
5878
			"import java.io.File;\n" +
5879
			"import java.io.FileOutputStream;\n" +
5880
			"import java.io.IOException;\n" +
5881
			"public class X {\n" +
5882
			"    void foo() throws IOException {\n" +
5883
			"        new FileOutputStream(new File(\"C:\\temp\\foo.txt\")).write(1);\n" + 
5884
			"    }\n" +
5885
			"}\n"
5886
		},
5887
		"----------\n" + 
5888
		"1. ERROR in X.java (at line 6)\n" + 
5889
		"	new FileOutputStream(new File(\"C:\\temp\\foo.txt\")).write(1);\n" + 
5890
		"	^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + 
5891
		"Resource leak: \'<unassigned Closeable value>\' is never closed\n" + 
5892
		"----------\n",
5893
		null,
5894
		true,
5895
		options);
5896
}
5897
// Bug 362331 - Resource leak not detected when closeable not assigned to variable
5898
// a freshly allocated resource is immediately closed
5899
public void test062b() throws IOException {
5900
	Map options = getCompilerOptions();
5901
	options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR);
5902
	options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR);
5903
	this.runConformTest(
5904
		new String[] {
5905
			"X.java",
5906
			"import java.io.File;\n" +
5907
			"import java.io.FileOutputStream;\n" +
5908
			"import java.io.IOException;\n" +
5909
			"public class X {\n" +
5910
			"    void foo() throws IOException {\n" +
5911
			"        new FileOutputStream(new File(\"C:\\temp\\foo.txt\")).close();\n" + 
5912
			"    }\n" +
5913
			"}\n"
5914
		},
5915
		"",
5916
		null,
5917
		true,
5918
		null,
5919
		options,
5920
		null);
5921
}
5922
// Bug 362331 - Resource leak not detected when closeable not assigned to variable
5923
// a resource is directly passed to another method
5924
public void test062c() throws IOException {
5925
	Map options = getCompilerOptions();
5926
	options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR);
5927
	options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR);
5928
	this.runConformTest(
5929
		new String[] {
5930
			"X.java",
5931
			"import java.io.File;\n" +
5932
			"import java.io.FileOutputStream;\n" +
5933
			"import java.io.IOException;\n" +
5934
			"public class X {\n" +
5935
			"    void foo() throws IOException {\n" +
5936
			"        writeIt(new FileOutputStream(new File(\"C:\\temp\\foo.txt\")));\n" + 
5937
			"    }\n" +
5938
			"    void writeIt(FileOutputStream fos) throws IOException {\n" +
5939
			"        fos.write(1);\n" +
5940
			"        fos.close();\n" +
5941
			"    }\n" +
5942
			"}\n"
5943
		},
5944
		"",
5945
		null,
5946
		true,
5947
		null,
5948
		options,
5949
		null);
5950
}
5951
// Bug 362331 - Resource leak not detected when closeable not assigned to variable
5952
// a resource is not used
5953
public void test062d() throws IOException {
5954
	Map options = getCompilerOptions();
5955
	options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR);
5956
	options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR);
5957
	this.runNegativeTest(
5958
		new String[] {
5959
			"X.java",
5960
			"import java.io.File;\n" +
5961
			"import java.io.FileOutputStream;\n" +
5962
			"import java.io.IOException;\n" +
5963
			"public class X {\n" +
5964
			"    void foo() throws IOException {\n" +
5965
			"        new FileOutputStream(new File(\"C:\\temp\\foo.txt\"));\n" + 
5966
			"    }\n" +
5967
			"}\n"
5968
		},
5969
		"----------\n" + 
5970
		"1. ERROR in X.java (at line 6)\n" + 
5971
		"	new FileOutputStream(new File(\"C:\\temp\\foo.txt\"));\n" + 
5972
		"	^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + 
5973
		"Resource leak: \'<unassigned Closeable value>\' is never closed\n" + 
5974
		"----------\n",
5975
		null,
5976
		true,
5977
		options);
5978
}
5979
// Bug 362332 - Only report potential leak when closeable not created in the local scope
5980
// a wrapper is obtained from another method
5981
public void test063a() throws IOException {
5982
	Map options = getCompilerOptions();
5983
	options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR);
5984
	options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR);
5985
	this.runNegativeTest(
5986
		new String[] {
5987
			"X.java",
5988
			"import java.io.File;\n" +
5989
			"import java.io.FileInputStream;\n" +
5990
			"import java.io.BufferedInputStream;\n" +
5991
			"import java.io.IOException;\n" +
5992
			"public class X {\n" +
5993
			"    void read(File file) throws IOException {\n" +
5994
			"        FileInputStream stream = new FileInputStream(file);\n" +
5995
			"        BufferedInputStream bis = new BufferedInputStream(stream); // never since reassigned\n" +
5996
			"        FileInputStream stream2 = new FileInputStream(file); // unsure since passed to method\n" +
5997
			"        bis = getReader(stream2); // unsure since obtained from method\n" +
5998
			"        bis.available();\n" +
5999
			"    }\n" +
6000
			"    BufferedInputStream getReader(FileInputStream stream) throws IOException {\n" +
6001
			"        return new BufferedInputStream(stream);\n" +
6002
			"    }\n" +
6003
			"}\n"
6004
		},
6005
		"----------\n" + 
6006
		"1. ERROR in X.java (at line 8)\n" + 
6007
		"	BufferedInputStream bis = new BufferedInputStream(stream); // never since reassigned\n" + 
6008
		"	                    ^^^\n" + 
6009
		"Resource leak: \'bis\' is never closed\n" + 
6010
		"----------\n" + 
6011
		"2. ERROR in X.java (at line 9)\n" + 
6012
		"	FileInputStream stream2 = new FileInputStream(file); // unsure since passed to method\n" + 
6013
		"	                ^^^^^^^\n" + 
6014
		"Potential resource leak: \'stream2\' may not be closed\n" + 
6015
		"----------\n" + 
6016
		"3. ERROR in X.java (at line 10)\n" + 
6017
		"	bis = getReader(stream2); // unsure since obtained from method\n" + 
6018
		"	^^^^^^^^^^^^^^^^^^^^^^^^\n" + 
6019
		"Potential resource leak: \'bis\' may not be closed\n" + 
6020
		"----------\n",
6021
		null,
6022
		true,
6023
		options);
6024
}
6025
// Bug 362332 - Only report potential leak when closeable not created in the local scope
6026
// a wrapper is obtained from a field read
6027
public void test063b() throws IOException {
6028
	Map options = getCompilerOptions();
6029
	options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR);
6030
	options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR);
6031
	this.runNegativeTest(
6032
		new String[] {
6033
			"X.java",
6034
			"import java.io.FileInputStream;\n" +
6035
			"import java.io.BufferedInputStream;\n" +
6036
			"import java.io.IOException;\n" +
6037
			"public class X {\n" +
6038
			"    FileInputStream stream;\n" +
6039
			"    void read() throws IOException {\n" +
6040
			"        FileInputStream s = this.stream;\n" +
6041
			"        BufferedInputStream bis = new BufferedInputStream(s); // unsure since s is obtained from a field\n" +
6042
			"        bis.available();\n" +
6043
			"    }\n" +
6044
			"}\n"
6045
		},
6046
		"----------\n" + 
6047
		"1. ERROR in X.java (at line 8)\n" + 
6048
		"	BufferedInputStream bis = new BufferedInputStream(s); // unsure since s is obtained from a field\n" + 
6049
		"	                    ^^^\n" + 
6050
		"Potential resource leak: \'bis\' may not be closed\n" + 
6051
		"----------\n",
6052
		null,
6053
		true,
6054
		options);
6055
}
6056
// Bug 362332 - Only report potential leak when closeable not created in the local scope
6057
// a wrapper is assigned to a field
6058
public void test063c() throws IOException {
6059
	Map options = getCompilerOptions();
6060
	options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR);
6061
	options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR);
6062
	this.runConformTest(
6063
		new String[] {
6064
			"X.java",
6065
			"import java.io.FileInputStream;\n" +
6066
			"import java.io.BufferedInputStream;\n" +
6067
			"import java.io.IOException;\n" +
6068
			"public class X {\n" +
6069
			"    BufferedInputStream stream;\n" +
6070
			"    void read() throws IOException {\n" +
6071
			"        FileInputStream s = new FileInputStream(\"somefile\");\n" +
6072
			"        BufferedInputStream bis = new BufferedInputStream(s);\n" +
6073
			"        this.stream = bis;\n" +
6074
			"    }\n" +
6075
			"}\n"
6076
		},
6077
		"",
6078
		null,
6079
		true,
6080
		null,
6081
		options,
6082
		null);
6083
}
5358
public static Class testClass() {
6084
public static Class testClass() {
5359
	return TryWithResourcesStatementTest.class;
6085
	return TryWithResourcesStatementTest.class;
5360
}
6086
}
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java (-3 / +9 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2011 IBM Corporation and others.
2
 * Copyright (c) 2000, 2012 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 37-42 Link Here
37
	protected TypeBinding typeExpected;	  // for <> inference
37
	protected TypeBinding typeExpected;	  // for <> inference
38
	public boolean inferredReturnType;
38
	public boolean inferredReturnType;
39
39
40
	public FakedTrackingVariable closeTracker;	// when allocation a Closeable store a pre-liminary tracking variable here
41
40
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
42
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
41
	// check captured variables are initialized in current context (26134)
43
	// check captured variables are initialized in current context (26134)
42
	checkCapturedLocalInitializationIfNecessary((ReferenceBinding)this.binding.declaringClass.erasure(), currentScope, flowInfo);
44
	checkCapturedLocalInitializationIfNecessary((ReferenceBinding)this.binding.declaringClass.erasure(), currentScope, flowInfo);
Lines 44-61 Link Here
44
	// process arguments
46
	// process arguments
45
	if (this.arguments != null) {
47
	if (this.arguments != null) {
46
		for (int i = 0, count = this.arguments.length; i < count; i++) {
48
		for (int i = 0, count = this.arguments.length; i < count; i++) {
47
			// if argument is an AutoCloseable insert info that it *may* be closed (by the target method, i.e.)
48
			flowInfo = FakedTrackingVariable.markPassedToOutside(currentScope, this.arguments[i], flowInfo);
49
			flowInfo =
49
			flowInfo =
50
				this.arguments[i]
50
				this.arguments[i]
51
					.analyseCode(currentScope, flowContext, flowInfo)
51
					.analyseCode(currentScope, flowContext, flowInfo)
52
					.unconditionalInits();
52
					.unconditionalInits();
53
			// if argument is an AutoCloseable insert info that it *may* be closed (by the target method, i.e.)
54
			flowInfo = FakedTrackingVariable.markPassedToOutside(currentScope, this.arguments[i], flowInfo, this.resolvedType);
53
			if ((this.arguments[i].implicitConversion & TypeIds.UNBOXING) != 0) {
55
			if ((this.arguments[i].implicitConversion & TypeIds.UNBOXING) != 0) {
54
				this.arguments[i].checkNPE(currentScope, flowContext, flowInfo);
56
				this.arguments[i].checkNPE(currentScope, flowContext, flowInfo);
55
			}
57
			}
56
		}
58
		}
57
		analyseArguments(currentScope, flowContext, flowInfo, this.binding, this.arguments);
59
		analyseArguments(currentScope, flowContext, flowInfo, this.binding, this.arguments);
58
	}
60
	}
61
62
	if (FakedTrackingVariable.isAutoCloseable(this.resolvedType))
63
		FakedTrackingVariable.analyseCloseableAllocation(currentScope, flowInfo, this);
64
59
	// record some dependency information for exception types
65
	// record some dependency information for exception types
60
	ReferenceBinding[] thrownExceptions;
66
	ReferenceBinding[] thrownExceptions;
61
	if (((thrownExceptions = this.binding.thrownExceptions).length) != 0) {
67
	if (((thrownExceptions = this.binding.thrownExceptions).length) != 0) {
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java (-11 / +19 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2011 IBM Corporation and others.
2
 * Copyright (c) 2000, 2012 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 46-64 Link Here
46
	if ((this.expression.implicitConversion & TypeIds.UNBOXING) != 0) {
46
	if ((this.expression.implicitConversion & TypeIds.UNBOXING) != 0) {
47
		this.expression.checkNPE(currentScope, flowContext, flowInfo);
47
		this.expression.checkNPE(currentScope, flowContext, flowInfo);
48
	}
48
	}
49
	
50
	FlowInfo preInitInfo = null;
51
	boolean shouldAnalyseResource = local != null 
52
			&& flowInfo.reachMode() == FlowInfo.REACHABLE 
53
			&& (FakedTrackingVariable.isAutoCloseable(this.expression.resolvedType)
54
					|| this.expression.resolvedType == TypeBinding.NULL);
55
	if (shouldAnalyseResource) {
56
		preInitInfo = flowInfo.unconditionalCopy();
57
		// analysis of resource leaks needs additional context while analyzing the RHS:
58
		FakedTrackingVariable.preConnectTrackerAcrossAssignment(this, local, this.expression);
59
	}
60
	
49
	flowInfo = ((Reference) this.lhs)
61
	flowInfo = ((Reference) this.lhs)
50
		.analyseAssignment(currentScope, flowContext, flowInfo, this, false)
62
		.analyseAssignment(currentScope, flowContext, flowInfo, this, false)
51
		.unconditionalInits();
63
		.unconditionalInits();
52
	if (local != null) {
64
53
		LocalVariableBinding previousTrackerBinding = null;
65
	if (shouldAnalyseResource)
54
		if (local.closeTracker != null) {
66
		FakedTrackingVariable.handleResourceAssignment(preInitInfo, flowInfo, this, this.expression, local);
55
			// Assigning to a variable already holding an AutoCloseable, has it been closed before?
67
	else
56
			previousTrackerBinding = local.closeTracker.binding;
68
		FakedTrackingVariable.cleanUpAfterAssignment(currentScope, this.lhs.bits, this.expression);
57
			if (!flowInfo.isDefinitelyNull(local)) // only if previous value may be non-null
69
58
				local.closeTracker.recordErrorLocation(this, flowInfo.nullStatus(previousTrackerBinding));
59
		}
60
		FakedTrackingVariable.handleResourceAssignment(flowInfo, this, this.expression, local, previousTrackerBinding);
61
	}
62
	int nullStatus = this.expression.nullStatus(flowInfo);
70
	int nullStatus = this.expression.nullStatus(flowInfo);
63
	if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) {
71
	if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) {
64
		if (nullStatus == FlowInfo.NULL) {
72
		if (nullStatus == FlowInfo.NULL) {
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FakedTrackingVariable.java (-42 / +347 lines)
Lines 15-21 Link Here
15
import java.util.Map;
15
import java.util.Map;
16
import java.util.Map.Entry;
16
import java.util.Map.Entry;
17
17
18
import org.eclipse.jdt.core.compiler.CharOperation;
19
import org.eclipse.jdt.internal.compiler.codegen.CodeStream;
18
import org.eclipse.jdt.internal.compiler.codegen.CodeStream;
20
import org.eclipse.jdt.internal.compiler.flow.FlowContext;
19
import org.eclipse.jdt.internal.compiler.flow.FlowContext;
21
import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
20
import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
Lines 48-67 Link Here
48
	private static final int CLOSED_IN_NESTED_METHOD = 4;
47
	private static final int CLOSED_IN_NESTED_METHOD = 4;
49
	// a location independent issue has been reported already against this resource:
48
	// a location independent issue has been reported already against this resource:
50
	private static final int REPORTED = 8;
49
	private static final int REPORTED = 8;
51
	
50
	// a resource is wrapped in another resource:
51
	private static final int WRAPPED = 16;
52
53
	private static final int DOUBT_MASK = CLOSE_SEEN | PASSED_TO_OUTSIDE | CLOSED_IN_NESTED_METHOD | REPORTED; // not WRAPPED
54
52
	/**
55
	/**
53
	 * Bitset of {@link #CLOSE_SEEN}, {@link #PASSED_TO_OUTSIDE}, {@link #CLOSED_IN_NESTED_METHOD} and {@link #REPORTED}.
56
	 * Bitset of {@link #CLOSE_SEEN}, {@link #PASSED_TO_OUTSIDE}, {@link #CLOSED_IN_NESTED_METHOD}, {@link #REPORTED} and {@link #WRAPPED}.
54
	 */
57
	 */
55
	private int globalClosingState = 0;
58
	private int globalClosingState = 0;
56
59
60
	public LocalVariableBinding originalBinding; // the real local being tracked, can be null for preliminary track vars for allocation expressions
61
	
62
	public FakedTrackingVariable innerTracker; // chained tracking variable of a chained (wrapped) resource
63
57
	MethodScope methodScope; // designates the method declaring this variable
64
	MethodScope methodScope; // designates the method declaring this variable
58
	
59
	public LocalVariableBinding originalBinding; // the real local being tracked
60
	
61
	HashMap recordedLocations; // initially null, ASTNode -> Integer 
62
65
66
	private HashMap recordedLocations; // initially null, ASTNode -> Integer
63
67
64
	public FakedTrackingVariable(LocalVariableBinding original, Statement location) {
68
	// temporary storage while analyzing "res = new Res();":
69
	private ASTNode currentAssignment; // temporarily store the assignment as the location for error reporting
70
71
	public FakedTrackingVariable(LocalVariableBinding original, ASTNode location) {
65
		super(original.name, location.sourceStart, location.sourceEnd);
72
		super(original.name, location.sourceStart, location.sourceEnd);
66
		this.type = new SingleTypeReference(
73
		this.type = new SingleTypeReference(
67
				TypeConstants.OBJECT,
74
				TypeConstants.OBJECT,
Lines 69-74 Link Here
69
		this.methodScope = original.declaringScope.methodScope();
76
		this.methodScope = original.declaringScope.methodScope();
70
		this.originalBinding = original;
77
		this.originalBinding = original;
71
		resolve(original.declaringScope);
78
		resolve(original.declaringScope);
79
	}
80
81
	/* Create an unassigned tracking variable while analyzing an allocation expression: */
82
	private FakedTrackingVariable(BlockScope scope, ASTNode location) {
83
		super("<unassigned Closeable value>".toCharArray(), location.sourceStart, location.sourceEnd); //$NON-NLS-1$
84
		this.type = new SingleTypeReference(
85
				TypeConstants.OBJECT,
86
				((long)this.sourceStart <<32)+this.sourceEnd);
87
		this.methodScope = scope.methodScope();
88
		this.originalBinding = null;
89
		resolve(scope);
72
	}
90
	}
73
	
91
	
74
	public void generateCode(BlockScope currentScope, CodeStream codeStream)
92
	public void generateCode(BlockScope currentScope, CodeStream codeStream)
Lines 88-95 Link Here
88
	}
106
	}
89
107
90
	/**
108
	/**
91
	 * If expression resolves to a local variable binding of type AutoCloseable,
109
	 * If expression resolves to a value of type AutoCloseable answer the variable that tracks closing of that local.
92
	 * answer the variable that tracks closing of that local, creating it if needed.
110
	 * Covers two cases:
111
	 * <ul>
112
	 * <li>value is a local variable reference, create tracking variable it if needed.
113
	 * <li>value is an allocation expression, return a preliminary tracking variable if set.
114
	 * </ul>
93
	 * @param expression
115
	 * @param expression
94
	 * @return a new {@link FakedTrackingVariable} or null.
116
	 * @return a new {@link FakedTrackingVariable} or null.
95
	 */
117
	 */
Lines 107-157 Link Here
107
				Statement location = local.declaration;
129
				Statement location = local.declaration;
108
				return local.closeTracker = new FakedTrackingVariable(local, location);
130
				return local.closeTracker = new FakedTrackingVariable(local, location);
109
			}
131
			}
110
		}
132
		} else if (expression instanceof AllocationExpression) {
133
			// return any preliminary tracking variable from analyseCloseableAllocation 
134
			return ((AllocationExpression) expression).closeTracker;
135
		}		
111
		return null;
136
		return null;
112
	}
137
	}
113
138
114
	/** if 'invocationSite' is a call to close() that has a registered tracking variable, answer that variable's binding. */
139
	/**
115
	public static LocalVariableBinding getTrackerForCloseCall(ASTNode invocationSite) {
140
	 * Before analyzing an assignment of this shape: <code>singleName = new Allocation()</code>
116
		if (invocationSite instanceof MessageSend) {
141
	 * connect any tracking variable of the LHS with the allocation on the RHS.
117
			MessageSend send = (MessageSend) invocationSite;
142
	 * Also the assignment is temporarily stored in the tracking variable in case we need to
118
			if (CharOperation.equals(TypeConstants.CLOSE, send.selector) && send.receiver instanceof SingleNameReference) {
143
	 * report errors because the assignment leaves the old LHS value unclosed.
119
				Binding receiverBinding = ((SingleNameReference)send.receiver).binding;
144
	 * In this case the assignment should be used as the error location.
120
				if (receiverBinding instanceof LocalVariableBinding) {
145
	 * 
121
					FakedTrackingVariable trackingVariable = ((LocalVariableBinding)receiverBinding).closeTracker;
146
	 * @param location the assignment/local declaration being analyzed
122
					if (trackingVariable != null)
147
	 * @param local the local variable being assigned to
123
						return trackingVariable.binding;
148
	 * @param rhs the rhs of the assignment resp. the initialization of the local variable declaration.
149
	 * @return a tracking variable with temporarily set 'currentAssignment' or null.
150
	 */
151
	public static FakedTrackingVariable preConnectTrackerAcrossAssignment(ASTNode location, LocalVariableBinding local, Expression rhs) {
152
		FakedTrackingVariable closeTracker = null;
153
		if (rhs instanceof AllocationExpression) {
154
			closeTracker = local.closeTracker;
155
			if (closeTracker == null) {
156
				if (isAutoCloseable(rhs.resolvedType)) {
157
					closeTracker = new FakedTrackingVariable(local, location);
158
				}					
159
			}
160
			if (closeTracker != null) {
161
				closeTracker.currentAssignment = location;
162
				((AllocationExpression)rhs).closeTracker = closeTracker;
163
			}
164
		}
165
		return closeTracker;
166
	}
167
168
	/** Compute/assign a tracking variable for a freshly allocated closeable value, using information from our white lists. */
169
	public static void analyseCloseableAllocation(BlockScope scope, FlowInfo flowInfo, AllocationExpression allocation) {
170
		if (((ReferenceBinding)allocation.resolvedType).hasTypeBit(TypeIds.BitResourceFreeCloseable)) {
171
			// remove unnecessary attempts (closeable is not relevant)
172
			if (allocation.closeTracker != null) {
173
				scope.removeTrackingVar(allocation.closeTracker);
174
				allocation.closeTracker = null;
175
			}
176
		} else if (((ReferenceBinding)allocation.resolvedType).hasTypeBit(TypeIds.BitWrapperCloseable)) {
177
			if (allocation.arguments != null &&  allocation.arguments.length > 0) { 
178
				FakedTrackingVariable innerTracker = analyseCloseableAllocationArgument(scope, flowInfo, allocation, allocation.arguments[0]);
179
				if (innerTracker != null) {
180
					if (innerTracker == allocation.closeTracker)
181
						return; // self wrap -> neither change (here) nor remove (below)
182
					if (allocation.closeTracker == null) {
183
						allocation.closeTracker = new FakedTrackingVariable(scope, allocation); // no local available, closeable is unassigned
184
					}
185
					allocation.closeTracker.innerTracker = innerTracker;
186
					innerTracker.globalClosingState |= WRAPPED;
187
					flowInfo.markAsDefinitelyNull(allocation.closeTracker.binding);
188
					return; // keep chaining wrapper
124
				}
189
				}
125
			}
190
			}
191
			// remove unnecessary attempts (wrapper has no relevant inner)
192
			if (allocation.closeTracker != null) {
193
				scope.removeTrackingVar(allocation.closeTracker);
194
				allocation.closeTracker = null;
195
			}
196
		} else {
197
			FakedTrackingVariable presetTracker = allocation.closeTracker;
198
			if (presetTracker != null && presetTracker.originalBinding != null) {
199
				int closeStatus = flowInfo.nullStatus(presetTracker.binding);
200
				if (closeStatus != FlowInfo.NON_NULL
201
						&& !flowInfo.isDefinitelyNull(presetTracker.originalBinding)
202
						&& !(presetTracker.currentAssignment instanceof LocalDeclaration))
203
					allocation.closeTracker.recordErrorLocation(presetTracker.currentAssignment, closeStatus);
204
			} else {
205
				allocation.closeTracker = new FakedTrackingVariable(scope, allocation); // no local available, closeable is unassigned
206
			}
207
			flowInfo.markAsDefinitelyNull(allocation.closeTracker.binding);
208
		}
209
	}
210
211
	/** Analyze the argument of an allocation for a resource wrapper. */
212
	public static FakedTrackingVariable analyseCloseableAllocationArgument(BlockScope scope, FlowInfo flowInfo, AllocationExpression allocation, Expression arg)
213
	{
214
		if (arg instanceof Assignment) {
215
			Assignment assign = (Assignment)arg;
216
			LocalVariableBinding innerLocal = assign.localVariableBinding();
217
			if (innerLocal != null) {
218
				// nested assignment has already been processed
219
				return innerLocal.closeTracker; // FIXME do we need a nested tracker here? see test061a/e
220
			} else {
221
				arg = assign.expression; // unwrap assignment and fall through
222
			}
223
		}
224
		if (arg instanceof SingleNameReference) {
225
			SingleNameReference ref = (SingleNameReference) arg;
226
			if (ref.binding instanceof LocalVariableBinding) {
227
				// allocation arg is a reference to an existing closeable?
228
				LocalVariableBinding innerLocal = (LocalVariableBinding)ref.binding;
229
				if (innerLocal.closeTracker != null)
230
					return innerLocal.closeTracker;
231
				if (innerLocal.isParameter() && isAutoCloseable(innerLocal.type)) {
232
					FakedTrackingVariable tracker = new FakedTrackingVariable(innerLocal, allocation);
233
					tracker.globalClosingState = PASSED_TO_OUTSIDE;
234
					flowInfo.markAsDefinitelyNonNull(tracker.binding); // assume we're not responsible for parameter value
235
					return tracker;
236
				}
237
			}
238
		} else if (arg instanceof AllocationExpression && arg.resolvedType instanceof ReferenceBinding) {
239
			// nested allocation
240
			return ((AllocationExpression)arg).closeTracker;
126
		}
241
		}
127
		return null;
242
		return null;
128
	}
243
	}
129
244
130
	/** 
245
	/** 
131
	 * Check if the rhs of an assignment or local declaration is an (Auto)Closeable.
246
	 * Check if the rhs of an assignment or local declaration is an (Auto)Closeable.
132
	 * If so create or re-use a tracking variable, and wire and initialize everything. 
247
	 * If so create or re-use a tracking variable, and wire and initialize everything.
248
	 * @param upstreamInfo info without analysis of the rhs, use this to determine the status of a resource being disconnected
249
	 * @param flowInfo info with analysis of the rhs, use this for recording resource status because this will be passed downstream
250
	 * @param location where to report warnigs/errors against
251
	 * @param rhs the right hand side of the assignment, this expression is to be analyzed.
252
	 *			The caller has already checked that the rhs is either of a closeable type or null.
253
	 * @param local the local variable into which the rhs is being assigned
133
	 */
254
	 */
134
	public static void handleResourceAssignment(FlowInfo flowInfo, Statement location, Expression rhs, LocalVariableBinding local,
255
	public static void handleResourceAssignment(FlowInfo upstreamInfo, FlowInfo flowInfo, ASTNode location, Expression rhs, LocalVariableBinding local)
135
				LocalVariableBinding previousTrackerBinding) 
136
	{
256
	{
137
		if (isAutoCloseable(rhs.resolvedType)) {
257
		// does the LHS (local) already have a tracker, indicating we may leak a resource by the assignment?
258
		FakedTrackingVariable previousTracker = null;
259
		FakedTrackingVariable disconnectedTracker = null;
260
		if (local.closeTracker != null) {
261
			// assigning to a variable already holding an AutoCloseable, has it been closed before?
262
			previousTracker = local.closeTracker;
263
			int status = upstreamInfo.nullStatus(local);
264
			if (status != FlowInfo.NULL && status != FlowInfo.UNKNOWN) // only if previous value may be relevant
265
				disconnectedTracker = previousTracker; // report error below, unless we have a self-wrap assignment
266
		}
267
268
		if (rhs.resolvedType != TypeBinding.NULL) {
138
			// new value is AutoCloseable, start tracking, possibly re-using existing tracker var:
269
			// new value is AutoCloseable, start tracking, possibly re-using existing tracker var:
139
	
140
			FakedTrackingVariable rhsTrackVar = getCloseTrackingVariable(rhs);
270
			FakedTrackingVariable rhsTrackVar = getCloseTrackingVariable(rhs);
141
			if (rhsTrackVar != null) {								// 1. share tracking variable with RHS?
271
			if (rhsTrackVar != null) {								// 1. if RHS has a tracking variable...
142
				local.closeTracker = rhsTrackVar;
272
				if (local.closeTracker == null) {
143
				// keep null-status unchanged across this assignment
273
					// null shouldn't occur but let's play safe
144
			} else if (previousTrackerBinding != null) {			// 2. re-use tracking variable from the LHS?
274
					if (rhsTrackVar.originalBinding != null)
145
				// re-assigning from a fresh, mark as not-closed again:
275
						local.closeTracker = rhsTrackVar;			//		a.: let fresh LHS share it 
146
				flowInfo.markAsDefinitelyNull(previousTrackerBinding);
276
				} else {
277
					if (rhsTrackVar == disconnectedTracker && rhs instanceof AllocationExpression)
278
						return; 									// 		b.: self wrapper: res = new Wrap(res); -> done!
279
					local.closeTracker = rhsTrackVar;				//		c.: conflicting LHS and RHS, proceed with recordErrorLocation below
280
				}
281
				// keep close-status of RHS unchanged across this assignment
282
			} else if (previousTracker != null) {					// 2. re-use tracking variable from the LHS?
283
				// re-assigning from a fresh value, mark as not-closed again:
284
				flowInfo.markAsDefinitelyNull(previousTracker.binding);
285
				local.closeTracker = analyseCloseableExpression(flowInfo, local, location, rhs, previousTracker);
147
			} else {												// 3. no re-use, create a fresh tracking variable:
286
			} else {												// 3. no re-use, create a fresh tracking variable:
148
				local.closeTracker = new FakedTrackingVariable(local, location);
287
				rhsTrackVar = analyseCloseableExpression(flowInfo, local, location, rhs, null);
149
				// a fresh resource, mark as not-closed:
288
				if (rhsTrackVar != null) {
150
				flowInfo.markAsDefinitelyNull(local.closeTracker.binding);
289
					local.closeTracker = rhsTrackVar;
290
					// a fresh resource, mark as not-closed:
291
					if ((rhsTrackVar.globalClosingState & PASSED_TO_OUTSIDE) == 0)
292
						flowInfo.markAsDefinitelyNull(rhsTrackVar.binding);
151
// TODO(stephan): this might be useful, but I could not find a test case for it: 
293
// TODO(stephan): this might be useful, but I could not find a test case for it: 
152
//				if (flowContext.initsOnFinally != null)
294
//					if (flowContext.initsOnFinally != null)
153
//					flowContext.initsOnFinally.markAsDefinitelyNonNull(trackerBinding);
295
//						flowContext.initsOnFinally.markAsDefinitelyNonNull(trackerBinding);
296
				}
154
			}
297
			}
298
		}
299
300
		if (disconnectedTracker != null)
301
			disconnectedTracker.recordErrorLocation(location, upstreamInfo.nullStatus(disconnectedTracker.binding));
302
	}
303
	/**
304
	 * Analyze structure of a closeable expression, matching (chained) resources against our white lists.
305
	 * See  Bug 358903 - Filter practically unimportant resource leak warnings
306
	 * @param flowInfo where to record close status
307
	 * @param local local variable to which the closeable is being assigned
308
	 * @param location where to flag errors/warnings against
309
	 * @param expression expression to be analyzed
310
	 * @param previousTracker when analyzing a re-assignment we may already have a tracking variable for local,
311
	 *  		which we should then re-use
312
	 * @return a tracking variable associated with local or null if no need to track
313
	 */
314
	private static FakedTrackingVariable analyseCloseableExpression(FlowInfo flowInfo, LocalVariableBinding local, 
315
									ASTNode location, Expression expression, FakedTrackingVariable previousTracker) 
316
	{
317
		if (expression instanceof AllocationExpression) {
318
			// allocation expressions already have their tracking variables analyzed by analyseCloseableAllocation(..)
319
			FakedTrackingVariable tracker = ((AllocationExpression) expression).closeTracker;
320
			if (tracker != null && tracker.originalBinding == null) {
321
				// tracker without original binding (unassigned closeable) shouldn't reach here but let's play safe
322
				return null;
323
			}
324
			return tracker;
325
		}
326
		if (expression.resolvedType instanceof ReferenceBinding) {
327
			ReferenceBinding resourceType = (ReferenceBinding) expression.resolvedType;
328
			
329
			if (expression instanceof CastExpression)
330
				expression = ((CastExpression) expression).expression;
331
			
332
			if (expression instanceof Assignment) {
333
				Expression innerExpression = ((Assignment)expression).expression;
334
				if (innerExpression instanceof AllocationExpression) {
335
					// allocation inside assignment has already been analyzed fully 
336
					return ((AllocationExpression) innerExpression).closeTracker;
337
				}
338
			} else if (expression instanceof MessageSend 
339
					|| expression instanceof FieldReference 
340
					|| expression instanceof QualifiedNameReference 
341
					|| expression instanceof ArrayReference) 
342
			{
343
				FakedTrackingVariable tracker = new FakedTrackingVariable(local, location);
344
				tracker.globalClosingState |= PASSED_TO_OUTSIDE;
345
				flowInfo.markPotentiallyNullBit(tracker.binding);
346
				return tracker;
347
			}
348
			if (resourceType.hasTypeBit(TypeIds.BitResourceFreeCloseable)) {
349
				// (a) resource-free closeable: -> null
350
				return null;
351
			}
352
		}
353
		if (local.closeTracker != null)
354
			// (c): inner has already been analyzed: -> re-use track var
355
			return local.closeTracker;
356
		return new FakedTrackingVariable(local, location);
357
	}
358
359
	public static void cleanUpAfterAssignment(BlockScope currentScope, int lhsBits, Expression expression) {
360
		// remove all remaining track vars with no original binding
361
		while (expression instanceof Assignment)
362
			expression = ((Assignment) expression).expression;
363
		if (expression instanceof AllocationExpression) {
364
			FakedTrackingVariable tracker = ((AllocationExpression) expression).closeTracker;
365
			if (tracker != null && tracker.originalBinding == null) {
366
				currentScope.removeTrackingVar(tracker);
367
				((AllocationExpression) expression).closeTracker = null;
368
			}
369
		} else {
370
			// assignment passing a local into a field?
371
			LocalVariableBinding local = expression.localVariableBinding();
372
			if (local != null && local.closeTracker != null && ((lhsBits & Binding.FIELD) != 0))
373
				currentScope.removeTrackingVar(local.closeTracker);
155
		}
374
		}
156
	}
375
	}
157
376
Lines 159-164 Link Here
159
	public static boolean isAutoCloseable(TypeBinding typeBinding) {
378
	public static boolean isAutoCloseable(TypeBinding typeBinding) {
160
		return typeBinding instanceof ReferenceBinding
379
		return typeBinding instanceof ReferenceBinding
161
			&& ((ReferenceBinding)typeBinding).hasTypeBit(TypeIds.BitAutoCloseable|TypeIds.BitCloseable);
380
			&& ((ReferenceBinding)typeBinding).hasTypeBit(TypeIds.BitAutoCloseable|TypeIds.BitCloseable);
381
	}
382
383
	public int findMostSpecificStatus(FlowInfo flowInfo, BlockScope currentScope, BlockScope locationScope) {
384
		int status = FlowInfo.UNKNOWN;
385
		FakedTrackingVariable currentTracker = this;
386
		// loop as to consider wrappers (per white list) encapsulating an inner resource.
387
		while (currentTracker != null) {
388
			LocalVariableBinding currentVar = currentTracker.binding;
389
			int currentStatus = getNullStatusAggressively(currentVar, flowInfo);
390
			if (locationScope != null) // only check at method exit points
391
				currentStatus = mergeCloseStatus(locationScope, currentStatus, currentVar, currentScope);
392
			if (currentStatus == FlowInfo.NON_NULL) {
393
				status = currentStatus;
394
				break; // closed -> stop searching
395
			} else if (status == FlowInfo.NULL || status == FlowInfo.UNKNOWN) {
396
				status = currentStatus; // improved although not yet safe -> keep searching for better
397
			}
398
			currentTracker = currentTracker.innerTracker;
399
		}
400
		return status;
401
	}
402
403
	/**
404
	 * Get the null status looking even into unreachable flows
405
	 * @param local
406
	 * @param flowInfo
407
	 * @return one of the constants FlowInfo.{NULL,POTENTIALLY_NULL,POTENTIALLY_NON_NULL,NON_NULL}.
408
	 */
409
	private int getNullStatusAggressively(LocalVariableBinding local, FlowInfo flowInfo) {
410
		int reachMode = flowInfo.reachMode();
411
		int status = 0;
412
		try {
413
			// unreachable flowInfo is too shy in reporting null-issues, temporarily forget reachability:
414
			if (reachMode != FlowInfo.REACHABLE)
415
				flowInfo.tagBits &= ~FlowInfo.UNREACHABLE;
416
			status = flowInfo.nullStatus(local);
417
		} finally {
418
			// reset
419
			flowInfo.tagBits |= reachMode;
420
		}
421
		// at this point some combinations are not useful so flatten to a single bit:
422
		if ((status & FlowInfo.NULL) != 0) {
423
			if ((status & (FlowInfo.NON_NULL | FlowInfo.POTENTIALLY_NON_NULL)) != 0)
424
				return FlowInfo.POTENTIALLY_NULL; 	// null + doubt = pot null
425
			return FlowInfo.NULL;
426
		} else if ((status & FlowInfo.NON_NULL) != 0) {
427
			if ((status & FlowInfo.POTENTIALLY_NULL) != 0)
428
				return FlowInfo.POTENTIALLY_NULL;	// non-null + doubt = pot null
429
			return FlowInfo.NON_NULL;
430
		} else if ((status & FlowInfo.POTENTIALLY_NULL) != 0)
431
			return FlowInfo.POTENTIALLY_NULL;
432
		return status;
433
	}
434
435
	public int mergeCloseStatus(BlockScope currentScope, int status, LocalVariableBinding local, BlockScope outerScope) {
436
		// get the most suitable null status representing whether resource 'binding' has been closed
437
		// start at 'currentScope' and potentially travel out until 'outerScope'
438
		// at each scope consult any recorded 'finallyInfo'.
439
		if (status != FlowInfo.NON_NULL) {
440
			if (currentScope.finallyInfo != null) {
441
				int finallyStatus = currentScope.finallyInfo.nullStatus(local);
442
				if (finallyStatus == FlowInfo.NON_NULL)
443
					return finallyStatus;
444
				if (finallyStatus != FlowInfo.NULL) // neither is NON_NULL, but not both are NULL => call it POTENTIALLY_NULL
445
					status = FlowInfo.POTENTIALLY_NULL;
446
			}
447
			if (currentScope != outerScope && currentScope.parent instanceof BlockScope)
448
				return mergeCloseStatus(((BlockScope) currentScope.parent), status, local, outerScope);
449
		}
450
		return status;
162
	}
451
	}
163
452
164
	/** Mark that this resource is closed locally. */
453
	/** Mark that this resource is closed locally. */
Lines 180-188 Link Here
180
	 * (as argument to a method/ctor call or as a return value from the current method), 
469
	 * (as argument to a method/ctor call or as a return value from the current method), 
181
	 * and thus should be considered as potentially closed.
470
	 * and thus should be considered as potentially closed.
182
	 */
471
	 */
183
	public static FlowInfo markPassedToOutside(BlockScope scope, Expression expression, FlowInfo flowInfo) {
472
	public static FlowInfo markPassedToOutside(BlockScope scope, Expression expression, FlowInfo flowInfo, TypeBinding allocatedType) {	
473
		if ((allocatedType instanceof ReferenceBinding) 
474
				&& ((ReferenceBinding) allocatedType).hasTypeBit(TypeIds.BitWrapperCloseable))
475
			return flowInfo; // wrapped closeables are analyzed separately
476
		
184
		FakedTrackingVariable trackVar = getCloseTrackingVariable(expression);
477
		FakedTrackingVariable trackVar = getCloseTrackingVariable(expression);
185
		if (trackVar != null) {
478
		if (trackVar != null) {
479
			if (trackVar.originalBinding == null) {
480
				// an allocation that never was assigned to a local variable -> drop it completely as we're not responsible
481
				scope.removeTrackingVar(trackVar);
482
				return flowInfo;
483
			}
186
			trackVar.globalClosingState |= PASSED_TO_OUTSIDE;
484
			trackVar.globalClosingState |= PASSED_TO_OUTSIDE;
187
			if (scope.methodScope() != trackVar.methodScope)
485
			if (scope.methodScope() != trackVar.methodScope)
188
				trackVar.globalClosingState |= CLOSED_IN_NESTED_METHOD;
486
				trackVar.globalClosingState |= CLOSED_IN_NESTED_METHOD;
Lines 201-209 Link Here
201
	}
499
	}
202
500
203
	public boolean reportRecordedErrors(Scope scope) {
501
	public boolean reportRecordedErrors(Scope scope) {
204
		if (this.globalClosingState == 0) {
502
		FakedTrackingVariable current = this;
205
			reportError(scope.problemReporter(), null, FlowInfo.NULL);
503
		while ((current.globalClosingState & DOUBT_MASK) == 0) {
206
			return true;
504
			current = current.innerTracker;
505
			if (current == null) {
506
				// no relevant state found -> report:
507
				reportError(scope.problemReporter(), null, FlowInfo.NULL);
508
				return true;
509
			}
207
		}
510
		}
208
		boolean hasReported = false;
511
		boolean hasReported = false;
209
		if (this.recordedLocations != null) {
512
		if (this.recordedLocations != null) {
Lines 218-223 Link Here
218
	}
521
	}
219
	
522
	
220
	public void reportError(ProblemReporter problemReporter, ASTNode location, int nullStatus) {
523
	public void reportError(ProblemReporter problemReporter, ASTNode location, int nullStatus) {
524
		if ((this.globalClosingState & WRAPPED) != 0)
525
			return;
221
		if (nullStatus == FlowInfo.NULL) {
526
		if (nullStatus == FlowInfo.NULL) {
222
			if ((this.globalClosingState & CLOSED_IN_NESTED_METHOD) != 0)
527
			if ((this.globalClosingState & CLOSED_IN_NESTED_METHOD) != 0)
223
				problemReporter.potentiallyUnclosedCloseable(this, location);
528
				problemReporter.potentiallyUnclosedCloseable(this, location);
Lines 225-231 Link Here
225
				problemReporter.unclosedCloseable(this, location);
530
				problemReporter.unclosedCloseable(this, location);
226
		} else if (nullStatus == FlowInfo.POTENTIALLY_NULL) {
531
		} else if (nullStatus == FlowInfo.POTENTIALLY_NULL) {
227
			problemReporter.potentiallyUnclosedCloseable(this, location);
532
			problemReporter.potentiallyUnclosedCloseable(this, location);
228
		}		
533
		}
229
	}
534
	}
230
535
231
	public void reportExplicitClosing(ProblemReporter problemReporter) {
536
	public void reportExplicitClosing(ProblemReporter problemReporter) {
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java (-2 / +17 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2011 IBM Corporation and others.
2
 * Copyright (c) 2000, 2012 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 74-84 Link Here
74
		this.initialization.checkNPE(currentScope, flowContext, flowInfo);
74
		this.initialization.checkNPE(currentScope, flowContext, flowInfo);
75
	}
75
	}
76
	
76
	
77
	FlowInfo preInitInfo = null;
78
	boolean shouldAnalyseResource = this.binding != null 
79
			&& flowInfo.reachMode() == FlowInfo.REACHABLE 
80
			&& FakedTrackingVariable.isAutoCloseable(this.initialization.resolvedType);
81
	if (shouldAnalyseResource) {
82
		preInitInfo = flowInfo.unconditionalCopy();
83
		// analysis of resource leaks needs additional context while analyzing the RHS:
84
		FakedTrackingVariable.preConnectTrackerAcrossAssignment(this, this.binding, this.initialization);
85
	}
86
77
	flowInfo =
87
	flowInfo =
78
		this.initialization
88
		this.initialization
79
			.analyseCode(currentScope, flowContext, flowInfo)
89
			.analyseCode(currentScope, flowContext, flowInfo)
80
			.unconditionalInits();
90
			.unconditionalInits();
81
	FakedTrackingVariable.handleResourceAssignment(flowInfo, this, this.initialization, this.binding, null);
91
92
	if (shouldAnalyseResource)
93
		FakedTrackingVariable.handleResourceAssignment(preInitInfo, flowInfo, this, this.initialization, this.binding);
94
	else
95
		FakedTrackingVariable.cleanUpAfterAssignment(currentScope, Binding.LOCAL, this.initialization);
96
82
	int nullStatus = this.initialization.nullStatus(flowInfo);
97
	int nullStatus = this.initialization.nullStatus(flowInfo);
83
	if (!flowInfo.isDefinitelyAssigned(this.binding)){// for local variable debug attributes
98
	if (!flowInfo.isDefinitelyAssigned(this.binding)){// for local variable debug attributes
84
		this.bits |= FirstAssignmentToLocal;
99
		this.bits |= FirstAssignmentToLocal;
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java (-3 / +3 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2011 IBM Corporation and others.
2
 * Copyright (c) 2000, 2012 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 96-104 Link Here
96
			if ((this.arguments[i].implicitConversion & TypeIds.UNBOXING) != 0) {
96
			if ((this.arguments[i].implicitConversion & TypeIds.UNBOXING) != 0) {
97
				this.arguments[i].checkNPE(currentScope, flowContext, flowInfo);
97
				this.arguments[i].checkNPE(currentScope, flowContext, flowInfo);
98
			}
98
			}
99
			// if argument is an AutoCloseable insert info that it *may* be closed (by the target method, i.e.)
100
			flowInfo = FakedTrackingVariable.markPassedToOutside(currentScope, this.arguments[i], flowInfo);
101
			flowInfo = this.arguments[i].analyseCode(currentScope, flowContext, flowInfo).unconditionalInits();
99
			flowInfo = this.arguments[i].analyseCode(currentScope, flowContext, flowInfo).unconditionalInits();
100
			// if argument is an AutoCloseable insert info that it *may* be closed (by the target method, i.e.)
101
			flowInfo = FakedTrackingVariable.markPassedToOutside(currentScope, this.arguments[i], flowInfo, null);
102
		}
102
		}
103
		analyseArguments(currentScope, flowContext, flowInfo, this.binding, this.arguments);
103
		analyseArguments(currentScope, flowContext, flowInfo, this.binding, this.arguments);
104
	}
104
	}
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java (-1 / +1 lines)
Lines 81-87 Link Here
81
		if (this.arguments != null) {
81
		if (this.arguments != null) {
82
			for (int i = 0, count = this.arguments.length; i < count; i++) {
82
			for (int i = 0, count = this.arguments.length; i < count; i++) {
83
				// if argument is an AutoCloseable insert info that it *may* be closed (by the target method, i.e.)
83
				// if argument is an AutoCloseable insert info that it *may* be closed (by the target method, i.e.)
84
				flowInfo = FakedTrackingVariable.markPassedToOutside(currentScope, this.arguments[i], flowInfo);
84
				flowInfo = FakedTrackingVariable.markPassedToOutside(currentScope, this.arguments[i], flowInfo, null);
85
				flowInfo = this.arguments[i].analyseCode(currentScope, flowContext, flowInfo);
85
				flowInfo = this.arguments[i].analyseCode(currentScope, flowContext, flowInfo);
86
				if ((this.arguments[i].implicitConversion & TypeIds.UNBOXING) != 0) {
86
				if ((this.arguments[i].implicitConversion & TypeIds.UNBOXING) != 0) {
87
					this.arguments[i].checkNPE(currentScope, flowContext, flowInfo);
87
					this.arguments[i].checkNPE(currentScope, flowContext, flowInfo);
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java (-1 / +1 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2011 IBM Corporation and others.
2
 * Copyright (c) 2000, 2012 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java (-2 / +2 lines)
Lines 134-140 Link Here
134
			if (resourceBinding.closeTracker != null) {
134
			if (resourceBinding.closeTracker != null) {
135
				// this was false alarm, we don't need to track the resource
135
				// this was false alarm, we don't need to track the resource
136
				this.tryBlock.scope.removeTrackingVar(resourceBinding.closeTracker);
136
				this.tryBlock.scope.removeTrackingVar(resourceBinding.closeTracker);
137
				resourceBinding.closeTracker = null;
137
				// keep the tracking variable in the resourceBinding in order to prevent creating a new one while analyzing the try block
138
			}
138
			}
139
			TypeBinding type = resourceBinding.type;
139
			TypeBinding type = resourceBinding.type;
140
			if (type != null && type.isValidBinding()) {
140
			if (type != null && type.isValidBinding()) {
Lines 276-282 Link Here
276
			if (resourceBinding.closeTracker != null) {
276
			if (resourceBinding.closeTracker != null) {
277
				// this was false alarm, we don't need to track the resource
277
				// this was false alarm, we don't need to track the resource
278
				this.tryBlock.scope.removeTrackingVar(resourceBinding.closeTracker);
278
				this.tryBlock.scope.removeTrackingVar(resourceBinding.closeTracker);
279
				resourceBinding.closeTracker = null;
279
				// keep the tracking variable in the resourceBinding in order to prevent creating a new one while analyzing the try block
280
			} 
280
			} 
281
			TypeBinding type = resourceBinding.type;
281
			TypeBinding type = resourceBinding.type;
282
			if (type != null && type.isValidBinding()) {
282
			if (type != null && type.isValidBinding()) {
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java (-3 / +5 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2011 IBM Corporation and others.
2
 * Copyright (c) 2000, 2012 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 1275-1281 Link Here
1275
			this.environment.mayTolerateMissingType = wasToleratingMissingTypeProcessingAnnotations;
1275
			this.environment.mayTolerateMissingType = wasToleratingMissingTypeProcessingAnnotations;
1276
		}
1276
		}
1277
	}
1277
	}
1278
	this.typeBits |= this.superclass.typeBits;
1278
	this.typeBits |= (this.superclass.typeBits & TypeIds.InheritableBits);
1279
	if ((this.typeBits & (TypeIds.BitAutoCloseable|TypeIds.BitCloseable)) != 0) // avoid the side-effects of hasTypeBit()! 
1280
		this.typeBits |= applyCloseableWhitelists();
1279
	return this.superclass;
1281
	return this.superclass;
1280
}
1282
}
1281
// NOTE: superInterfaces of binary types are resolved when needed
1283
// NOTE: superInterfaces of binary types are resolved when needed
Lines 1298-1304 Link Here
1298
				this.environment.mayTolerateMissingType = wasToleratingMissingTypeProcessingAnnotations;
1300
				this.environment.mayTolerateMissingType = wasToleratingMissingTypeProcessingAnnotations;
1299
			}	
1301
			}	
1300
		}
1302
		}
1301
		this.typeBits |= this.superInterfaces[i].typeBits;
1303
		this.typeBits |= (this.superInterfaces[i].typeBits & TypeIds.InheritableBits);
1302
	}
1304
	}
1303
	this.tagBits &= ~TagBits.HasUnresolvedSuperinterfaces;
1305
	this.tagBits &= ~TagBits.HasUnresolvedSuperinterfaces;
1304
	return this.superInterfaces;
1306
	return this.superInterfaces;
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java (-55 / +11 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2011 IBM Corporation and others.
2
 * Copyright (c) 2000, 2012 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 981-986 Link Here
981
}
981
}
982
/** When are no longer interested in this tracking variable - remove it. */
982
/** When are no longer interested in this tracking variable - remove it. */
983
public void removeTrackingVar(FakedTrackingVariable trackingVariable) {
983
public void removeTrackingVar(FakedTrackingVariable trackingVariable) {
984
	if (trackingVariable.innerTracker != null) {
985
		removeTrackingVar(trackingVariable.innerTracker);
986
		trackingVariable.innerTracker = null;
987
	}
984
	if (this.trackingVariables != null)
988
	if (this.trackingVariables != null)
985
		if (this.trackingVariables.remove(trackingVariable))
989
		if (this.trackingVariables.remove(trackingVariable))
986
			return;
990
			return;
Lines 1003-1012 Link Here
1003
		FakedTrackingVariable trackingVar = (FakedTrackingVariable) this.trackingVariables.get(i);
1007
		FakedTrackingVariable trackingVar = (FakedTrackingVariable) this.trackingVariables.get(i);
1004
		if (location != null && trackingVar.originalBinding != null && flowInfo.isDefinitelyNull(trackingVar.originalBinding))
1008
		if (location != null && trackingVar.originalBinding != null && flowInfo.isDefinitelyNull(trackingVar.originalBinding))
1005
			continue; // reporting against a specific location, resource is null at this flow, don't complain
1009
			continue; // reporting against a specific location, resource is null at this flow, don't complain
1006
		int status = getNullStatusAggressively(trackingVar.binding, flowInfo);
1010
		
1007
		// try to improve info if a close() inside finally was observed:
1011
		// compute the most specific null status for this resource,
1008
		if (locationScope != null) // only check at method exit points
1012
		int status = trackingVar.findMostSpecificStatus(flowInfo, this, locationScope);
1009
			status = locationScope.mergeCloseStatus(status, trackingVar.binding, this);
1013
		
1010
		if (status == FlowInfo.NULL) {
1014
		if (status == FlowInfo.NULL) {
1011
			// definitely unclosed: highest priority
1015
			// definitely unclosed: highest priority
1012
			reportResourceLeak(trackingVar, location, status);
1016
			reportResourceLeak(trackingVar, location, status);
Lines 1033-1056 Link Here
1033
			this.locals[i].closeTracker = null;		
1037
			this.locals[i].closeTracker = null;		
1034
		this.trackingVariables = null;
1038
		this.trackingVariables = null;
1035
	}
1039
	}
1036
}
1037
1038
private int mergeCloseStatus(int status, LocalVariableBinding binding, BlockScope outerScope) {
1039
	// get the most suitable null status representing whether resource 'binding' has been closed
1040
	// start at this scope and potentially travel out until 'outerScope'
1041
	// at each scope consult any recorded 'finallyInfo'.
1042
	if (status != FlowInfo.NON_NULL) {
1043
		if (this.finallyInfo != null) {
1044
			int finallyStatus = this.finallyInfo.nullStatus(binding);
1045
			if (finallyStatus == FlowInfo.NON_NULL)
1046
				return finallyStatus;
1047
			if (finallyStatus != FlowInfo.NULL) // neither is NON_NULL, but not both are NULL => call it POTENTIALLY_NULL
1048
				status = FlowInfo.POTENTIALLY_NULL;
1049
		}
1050
		if (this != outerScope && this.parent instanceof BlockScope)
1051
			return ((BlockScope) this.parent).mergeCloseStatus(status, binding, outerScope);
1052
	}
1053
	return status;
1054
}
1040
}
1055
1041
1056
private void reportResourceLeak(FakedTrackingVariable trackingVar, ASTNode location, int nullStatus) {
1042
private void reportResourceLeak(FakedTrackingVariable trackingVar, ASTNode location, int nullStatus) {
Lines 1083-1088 Link Here
1083
	if (this.trackingVariables != null) {
1069
	if (this.trackingVariables != null) {
1084
		for (int i=0; i<this.trackingVariables.size(); i++) {
1070
		for (int i=0; i<this.trackingVariables.size(); i++) {
1085
			FakedTrackingVariable trackingVar = (FakedTrackingVariable) this.trackingVariables.get(i);
1071
			FakedTrackingVariable trackingVar = (FakedTrackingVariable) this.trackingVariables.get(i);
1072
			if (trackingVar.originalBinding == null)
1073
				continue;
1086
			if (   thenFlowInfo.isDefinitelyNonNull(trackingVar.binding)			// closed in then branch
1074
			if (   thenFlowInfo.isDefinitelyNonNull(trackingVar.binding)			// closed in then branch
1087
				&& elseFlowInfo.isDefinitelyNull(trackingVar.originalBinding))		// null in else branch
1075
				&& elseFlowInfo.isDefinitelyNull(trackingVar.originalBinding))		// null in else branch
1088
			{
1076
			{
Lines 1097-1133 Link Here
1097
	}
1085
	}
1098
	if (this.parent instanceof BlockScope)
1086
	if (this.parent instanceof BlockScope)
1099
		((BlockScope) this.parent).correlateTrackingVarsIfElse(thenFlowInfo, elseFlowInfo);
1087
		((BlockScope) this.parent).correlateTrackingVarsIfElse(thenFlowInfo, elseFlowInfo);
1100
}
1101
1102
/**
1103
 * Get the null status looking even into unreachable flows
1104
 * @param local
1105
 * @param flowInfo
1106
 * @return one of the constants FlowInfo.{NULL,POTENTIALLY_NULL,POTENTIALLY_NON_NULL,NON_NULL}.
1107
 */
1108
private int getNullStatusAggressively(LocalVariableBinding local, FlowInfo flowInfo) {
1109
	int reachMode = flowInfo.reachMode();
1110
	int status = 0;
1111
	try {
1112
		// unreachable flowInfo is too shy in reporting null-issues, temporarily forget reachability:
1113
		if (reachMode != FlowInfo.REACHABLE)
1114
			flowInfo.tagBits &= ~FlowInfo.UNREACHABLE;
1115
		status = flowInfo.nullStatus(local);
1116
	} finally {
1117
		// reset
1118
		flowInfo.tagBits |= reachMode;
1119
	}
1120
	// at this point some combinations are not useful so flatten to a single bit:
1121
	if ((status & FlowInfo.NULL) != 0) {
1122
		if ((status & (FlowInfo.NON_NULL | FlowInfo.POTENTIALLY_NON_NULL)) != 0)
1123
			return FlowInfo.POTENTIALLY_NULL; 	// null + doubt = pot null
1124
		return FlowInfo.NULL;
1125
	} else if ((status & FlowInfo.NON_NULL) != 0) {
1126
		if ((status & FlowInfo.POTENTIALLY_NULL) != 0)
1127
			return FlowInfo.POTENTIALLY_NULL;	// non-null + doubt = pot null
1128
		return FlowInfo.NON_NULL;
1129
	} else if ((status & FlowInfo.POTENTIALLY_NULL) != 0)
1130
		return FlowInfo.POTENTIALLY_NULL;
1131
	return status;
1132
}
1088
}
1133
}
1089
}
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java (-3 / +6 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2011 IBM Corporation and others.
2
 * Copyright (c) 2000, 2012 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 909-915 Link Here
909
			} else {
909
			} else {
910
				// only want to reach here when no errors are reported
910
				// only want to reach here when no errors are reported
911
				sourceType.superclass = superclass;
911
				sourceType.superclass = superclass;
912
				sourceType.typeBits |= superclass.typeBits;
912
				sourceType.typeBits |= (superclass.typeBits & TypeIds.InheritableBits);
913
				// further analysis against white lists for the unlikely case we are compiling java.io.*:
914
				if ((sourceType.typeBits & (TypeIds.BitAutoCloseable|TypeIds.BitCloseable)) != 0)
915
					sourceType.typeBits |= sourceType.applyCloseableWhitelists();
913
				return true;
916
				return true;
914
			}
917
			}
915
		}
918
		}
Lines 1025-1031 Link Here
1025
				noProblems &= superInterfaceRef.resolvedType.isValidBinding();
1028
				noProblems &= superInterfaceRef.resolvedType.isValidBinding();
1026
			}
1029
			}
1027
			// only want to reach here when no errors are reported
1030
			// only want to reach here when no errors are reported
1028
			sourceType.typeBits |= superInterface.typeBits;
1031
			sourceType.typeBits |= (superInterface.typeBits & TypeIds.InheritableBits);
1029
			interfaceBindings[count++] = superInterface;
1032
			interfaceBindings[count++] = superInterface;
1030
		}
1033
		}
1031
		// hold onto all correctly resolved superinterfaces
1034
		// hold onto all correctly resolved superinterfaces
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java (-1 / +33 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2011 IBM Corporation and others.
2
 * Copyright (c) 2000, 2012 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 1469-1472 Link Here
1469
public FieldBinding[] unResolvedFields() {
1469
public FieldBinding[] unResolvedFields() {
1470
	return Binding.NO_FIELDS;
1470
	return Binding.NO_FIELDS;
1471
}
1471
}
1472
1473
/*
1474
 * If a type - known to be a Closeable - is mentioned in one of our white lists
1475
 * answer the typeBit for the white list (BitWrapperCloseable or BitResourceFreeCloseable).
1476
 */
1477
protected int applyCloseableWhitelists() {
1478
	switch (this.compoundName.length) {
1479
		case 3:
1480
			if (CharOperation.equals(TypeConstants.JAVA, this.compoundName[0])) {
1481
				if (CharOperation.equals(TypeConstants.IO, this.compoundName[1])) {
1482
					char[] simpleName = this.compoundName[2];
1483
					int l = TypeConstants.JAVA_IO_WRAPPER_CLOSEABLES.length;
1484
					for (int i = 0; i < l; i++) {
1485
						if (CharOperation.equals(simpleName, TypeConstants.JAVA_IO_WRAPPER_CLOSEABLES[i]))
1486
							return TypeIds.BitWrapperCloseable;
1487
					}
1488
					l = TypeConstants.JAVA_IO_RESOURCE_FREE_CLOSEABLES.length;
1489
					for (int i = 0; i < l; i++) {
1490
						if (CharOperation.equals(simpleName, TypeConstants.JAVA_IO_RESOURCE_FREE_CLOSEABLES[i]))
1491
							return TypeIds.BitResourceFreeCloseable;
1492
					}
1493
				}
1494
			}
1495
			break;
1496
	}
1497
	int l = TypeConstants.OTHER_WRAPPER_CLOSEABLES.length;
1498
	for (int i = 0; i < l; i++) {
1499
		if (CharOperation.equals(this.compoundName, TypeConstants.OTHER_WRAPPER_CLOSEABLES[i]))
1500
			return TypeIds.BitWrapperCloseable;
1501
	}	
1502
	return 0;
1503
}
1472
}
1504
}
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java (-1 / +28 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2011 IBM Corporation and others.
2
 * Copyright (c) 2000, 2012 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 154-159 Link Here
154
	};
154
	};
155
	char[][] JAVA_LANG_AUTOCLOSEABLE =  {JAVA, LANG, "AutoCloseable".toCharArray()}; //$NON-NLS-1$
155
	char[][] JAVA_LANG_AUTOCLOSEABLE =  {JAVA, LANG, "AutoCloseable".toCharArray()}; //$NON-NLS-1$
156
	char[] CLOSE = "close".toCharArray(); //$NON-NLS-1$
156
	char[] CLOSE = "close".toCharArray(); //$NON-NLS-1$
157
	// white lists of closeables:
158
	char[][] JAVA_IO_WRAPPER_CLOSEABLES = new char[][] {
159
		"BufferedInputStream".toCharArray(), //$NON-NLS-1$
160
		"BufferedOutputStream".toCharArray(), //$NON-NLS-1$
161
		"BufferedReader".toCharArray(), //$NON-NLS-1$
162
		"BufferedWriter".toCharArray(), //$NON-NLS-1$
163
		"InputStreamReader".toCharArray(), //$NON-NLS-1$
164
		"PrintWriter".toCharArray(),  //$NON-NLS-1$
165
		"LineNumberReader".toCharArray(), //$NON-NLS-1$
166
		"DataInputStream".toCharArray(), //$NON-NLS-1$
167
		"DataOutputStream".toCharArray(), //$NON-NLS-1$
168
		"ObjectInputStream".toCharArray(), //$NON-NLS-1$
169
		"ObjectOutputStream".toCharArray(), //$NON-NLS-1$
170
		"FilterInputStream".toCharArray(), //$NON-NLS-1$
171
		"FilterOutputStream".toCharArray(), //$NON-NLS-1$
172
	};
173
	char[][][] OTHER_WRAPPER_CLOSEABLES = new char[][][] { // NOTE: if this list should ever grow large we should think of smarter data structure
174
		{JAVA, UTIL, "zip".toCharArray(), "InflaterInputStream".toCharArray()},	 //$NON-NLS-1$ //$NON-NLS-2$
175
	};
176
	char[][] JAVA_IO_RESOURCE_FREE_CLOSEABLES = new char[][] {			
177
		"StringReader".toCharArray(), //$NON-NLS-1$
178
		"StringWriter".toCharArray(), //$NON-NLS-1$
179
		"ByteArrayInputStream".toCharArray(), //$NON-NLS-1$
180
		"ByteArrayOutputStream".toCharArray(), //$NON-NLS-1$
181
		"CharArrayReader".toCharArray(), //$NON-NLS-1$
182
		"CharArrayWriter".toCharArray(), //$NON-NLS-1$
183
	};
157
184
158
	// Constraints for generic type argument inference
185
	// Constraints for generic type argument inference
159
	int CONSTRAINT_EQUAL = 0;		// Actual = Formal
186
	int CONSTRAINT_EQUAL = 0;		// Actual = Formal
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java (-1 / +16 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2011 IBM Corporation and others.
2
 * Copyright (c) 2000, 2012 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 207-210 Link Here
207
	 * @see ReferenceBinding#hasTypeBit(int)
207
	 * @see ReferenceBinding#hasTypeBit(int)
208
	 */
208
	 */
209
	final int BitCloseable = 2;
209
	final int BitCloseable = 2;
210
	/**
211
	 * Bit for members of a white list:
212
	 * Subtypes of Closeable that wrap another resource without directly holding any OS resources. 
213
	 */
214
	final int BitWrapperCloseable = 4;
215
	/**
216
	 * Bit for members of a white list:
217
	 * Subtypes of Closeable that do not hold an OS resource that needs to be released.
218
	 */
219
	final int BitResourceFreeCloseable = 8;
220
	
221
	/**
222
	 * Set of type bits that should be inherited by any sub types.
223
	 */
224
	final int InheritableBits = BitAutoCloseable | BitCloseable;
210
}
225
}
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeVariableBinding.java (-3 / +3 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2011 IBM Corporation and others.
2
 * Copyright (c) 2000, 2012 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 316-326 Link Here
316
			// initialize from bounds
316
			// initialize from bounds
317
			this.typeBits = 0;
317
			this.typeBits = 0;
318
			if (this.superclass != null && this.superclass.hasTypeBit(~TypeIds.BitUninitialized))
318
			if (this.superclass != null && this.superclass.hasTypeBit(~TypeIds.BitUninitialized))
319
				this.typeBits |= this.superclass.typeBits;
319
				this.typeBits |= (this.superclass.typeBits & TypeIds.InheritableBits);
320
			if (this.superInterfaces != null)
320
			if (this.superInterfaces != null)
321
				for (int i = 0, l = this.superInterfaces.length; i < l; i++)
321
				for (int i = 0, l = this.superInterfaces.length; i < l; i++)
322
					if (this.superInterfaces[i].hasTypeBit(~TypeIds.BitUninitialized))
322
					if (this.superInterfaces[i].hasTypeBit(~TypeIds.BitUninitialized))
323
						this.typeBits |= this.superInterfaces[i].typeBits;
323
						this.typeBits |= (this.superInterfaces[i].typeBits & TypeIds.InheritableBits);
324
		}
324
		}
325
		return (this.typeBits & bit) != 0;
325
		return (this.typeBits & bit) != 0;
326
	}
326
	}
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/WildcardBinding.java (-3 / +3 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright (c) 2005, 2011 IBM Corporation and others.
2
 * Copyright (c) 2005, 2012 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 429-439 Link Here
429
			// initialize from upper bounds
429
			// initialize from upper bounds
430
			this.typeBits = 0;
430
			this.typeBits = 0;
431
			if (this.superclass != null && this.superclass.hasTypeBit(~TypeIds.BitUninitialized))
431
			if (this.superclass != null && this.superclass.hasTypeBit(~TypeIds.BitUninitialized))
432
				this.typeBits |= this.superclass.typeBits;
432
				this.typeBits |= (this.superclass.typeBits & TypeIds.InheritableBits);
433
			if (this.superInterfaces != null)
433
			if (this.superInterfaces != null)
434
				for (int i = 0, l = this.superInterfaces.length; i < l; i++)
434
				for (int i = 0, l = this.superInterfaces.length; i < l; i++)
435
					if (this.superInterfaces[i].hasTypeBit(~TypeIds.BitUninitialized))
435
					if (this.superInterfaces[i].hasTypeBit(~TypeIds.BitUninitialized))
436
						this.typeBits |= this.superInterfaces[i].typeBits;
436
						this.typeBits |= (this.superInterfaces[i].typeBits & TypeIds.InheritableBits);
437
		}
437
		}
438
		return (this.typeBits & bit) != 0;
438
		return (this.typeBits & bit) != 0;
439
	}
439
	}

Return to bug 358903