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 (-3 / +425 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[] { "test061"};
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 4444-4450 Link Here
4444
		options);
4449
		options);
4445
}
4450
}
4446
// Bug 349326 - [1.7] new warning for missing try-with-resources
4451
// Bug 349326 - [1.7] new warning for missing try-with-resources
4447
// closed in dead code
4452
// properly closed, dead code in between
4448
public void test056r() {
4453
public void test056r() {
4449
	Map options = getCompilerOptions();
4454
	Map options = getCompilerOptions();
4450
	options.put(JavaCore.COMPILER_PB_UNCLOSED_CLOSEABLE, CompilerOptions.ERROR);
4455
	options.put(JavaCore.COMPILER_PB_UNCLOSED_CLOSEABLE, CompilerOptions.ERROR);
Lines 5354-5360 Link Here
5354
		"X::~X\n" + 
5359
		"X::~X\n" + 
5355
		"true");
5360
		"true");
5356
}
5361
}
5357
5362
// Bug 358903 - Filter practically unimportant resource leak warnings
5363
// Bug 360908 - Avoid resource leak warning when the underlying/chained resource is closed explicitly
5364
// a resource wrapper is not closed but the underlying resource is
5365
public void test061a() {
5366
	Map options = getCompilerOptions();
5367
	options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR);
5368
	options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR);
5369
	this.runConformTest(
5370
		new String[] {
5371
			"X.java",
5372
			"import java.io.File;\n" +
5373
			"import java.io.BufferedInputStream;\n" +
5374
			"import java.io.FileInputStream;\n" +
5375
			"import java.io.IOException;\n" +
5376
			"public class X {\n" +
5377
			"    void foo() throws IOException {\n" +
5378
			"        File file = new File(\"somefile\");\n" +
5379
			"        FileInputStream fileStream  = new FileInputStream(file);\n" +
5380
			"        BufferedInputStream bis = new BufferedInputStream(fileStream);\n" +
5381
			"        BufferedInputStream doubleWrap = new BufferedInputStream(bis);\n" +
5382
			"        System.out.println(bis.available());\n" +
5383
			"        fileStream.close();\n" +
5384
			"    }\n" +
5385
			"    void inline() throws IOException {\n" +
5386
			"        File file = new File(\"somefile\");\n" +
5387
			"        FileInputStream fileStream;\n" +
5388
			"        BufferedInputStream bis = new BufferedInputStream(fileStream = new FileInputStream(file));\n" +
5389
			"        System.out.println(bis.available());\n" +
5390
			"        fileStream.close();\n" +
5391
			"    }\n" +
5392
			"    public static void main(String[] args) throws IOException {\n" +
5393
			"        try {\n" +
5394
			"            new X().foo();\n" +
5395
			"        } catch (IOException ex) {" +
5396
			"            System.out.println(\"Got IO Exception\");\n" +
5397
			"        }\n" +
5398
			"    }\n" +
5399
			"}\n"
5400
		},
5401
		"Got IO Exception",
5402
		null,
5403
		true,
5404
		null,
5405
		options,
5406
		null);
5407
}
5408
// Bug 358903 - Filter practically unimportant resource leak warnings
5409
// a closeable without OS resource is not closed
5410
public void test061b() {
5411
	Map options = getCompilerOptions();
5412
	options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR);
5413
	options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR);
5414
	this.runConformTest(
5415
		new String[] {
5416
			"X.java",
5417
			"import java.io.StringReader;\n" +
5418
			"import java.io.IOException;\n" +
5419
			"public class X {\n" +
5420
			"    void foo() throws IOException {\n" +
5421
			"        StringReader string  = new StringReader(\"content\");\n" +
5422
			"        System.out.println(string.read());\n" +
5423
			"    }\n" +
5424
			"    public static void main(String[] args) throws IOException {\n" +
5425
			"        new X().foo();\n" +
5426
			"    }\n" +
5427
			"}\n"
5428
		},
5429
		"99", // character 'c'
5430
		null,
5431
		true,
5432
		null,
5433
		options,
5434
		null);
5435
}
5436
// Bug 358903 - Filter practically unimportant resource leak warnings
5437
// a resource wrapper is not closed but the underlying closeable is resource-free
5438
public void test061c() {
5439
	Map options = getCompilerOptions();
5440
	options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR);
5441
	options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR);
5442
	this.runConformTest(
5443
		new String[] {
5444
			"X.java",
5445
			"import java.io.BufferedReader;\n" +
5446
			"import java.io.StringReader;\n" +
5447
			"import java.io.IOException;\n" +
5448
			"public class X {\n" +
5449
			"    void foo() throws IOException {\n" +
5450
			"        StringReader input = new StringReader(\"content\");\n" +
5451
			"        BufferedReader br = new BufferedReader(input);\n" +
5452
			"        BufferedReader doubleWrap = new BufferedReader(br);\n" +
5453
			"        System.out.println(br.read());\n" +
5454
			"    }\n" +
5455
			"    void inline() throws IOException {\n" +
5456
			"        BufferedReader br = new BufferedReader(new StringReader(\"content\"));\n" +
5457
			"        System.out.println(br.read());\n" +
5458
			"    }\n" +
5459
			"    public static void main(String[] args) throws IOException {\n" +
5460
			"        new X().foo();\n" +
5461
			"    }\n" +
5462
			"}\n"
5463
		},
5464
		"99",
5465
		null,
5466
		true,
5467
		null,
5468
		options,
5469
		null);
5470
}
5471
// Bug 358903 - Filter practically unimportant resource leak warnings
5472
// a resource wrapper is not closed neither is the underlying resource
5473
public void test061d() {
5474
	Map options = getCompilerOptions();
5475
	options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR);
5476
	options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.WARNING);
5477
	this.runNegativeTest(
5478
		new String[] {
5479
			"X.java",
5480
			"import java.io.File;\n" +
5481
			"import java.io.BufferedInputStream;\n" +
5482
			"import java.io.FileInputStream;\n" +
5483
			"import java.io.IOException;\n" +
5484
			"public class X {\n" +
5485
			"    void foo() throws IOException {\n" +
5486
			"        File file = new File(\"somefile\");\n" +
5487
			"        FileInputStream fileStream  = new FileInputStream(file);\n" +
5488
			"        BufferedInputStream bis = new BufferedInputStream(fileStream);\n" +
5489
			"        BufferedInputStream doubleWrap = new BufferedInputStream(bis);\n" +
5490
			"        System.out.println(bis.available());\n" +
5491
			"    }\n" +
5492
			"    void inline() throws IOException {\n" +
5493
			"        File file = new File(\"somefile\");\n" +
5494
			"        BufferedInputStream bis2 = new BufferedInputStream(new FileInputStream(file));\n" +
5495
			"        System.out.println(bis2.available());\n" +
5496
			"    }\n" +
5497
			"    public static void main(String[] args) throws IOException {\n" +
5498
			"        try {\n" +
5499
			"            new X().foo();\n" +
5500
			"        } catch (IOException ex) {" +
5501
			"            System.out.println(\"Got IO Exception\");\n" +
5502
			"        }\n" +
5503
			"    }\n" +
5504
			"}\n"
5505
		},
5506
		"----------\n" + 
5507
		"1. ERROR in X.java (at line 10)\n" + 
5508
		"	BufferedInputStream doubleWrap = new BufferedInputStream(bis);\n" + 
5509
		"	                    ^^^^^^^^^^\n" + 
5510
		"Resource leak: \'doubleWrap\' is never closed\n" + 
5511
		"----------\n" + 
5512
		"2. ERROR in X.java (at line 15)\n" + 
5513
		"	BufferedInputStream bis2 = new BufferedInputStream(new FileInputStream(file));\n" + 
5514
		"	                    ^^^^\n" + 
5515
		"Resource leak: \'bis2\' is never closed\n" + 
5516
		"----------\n",
5517
		null,
5518
		true,
5519
		options);
5520
}
5521
// Bug 358903 - Filter practically unimportant resource leak warnings
5522
// Bug 361073 - Avoid resource leak warning when the top level resource is closed explicitly
5523
// a resource wrapper is closed closing also the underlying resource
5524
public void test061e() {
5525
	Map options = getCompilerOptions();
5526
	options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR);
5527
	options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR);
5528
	this.runConformTest(
5529
		new String[] {
5530
			"X.java",
5531
			"import java.io.File;\n" +
5532
			"import java.io.BufferedInputStream;\n" +
5533
			"import java.io.FileInputStream;\n" +
5534
			"import java.io.IOException;\n" +
5535
			"public class X {\n" +
5536
			"    FileInputStream fis;" +
5537
			"    void foo() throws IOException {\n" +
5538
			"        File file = new File(\"somefile\");\n" +
5539
			"        FileInputStream fileStream  = new FileInputStream(file);\n" +
5540
			"        BufferedInputStream bis = new BufferedInputStream(fileStream);\n" +
5541
			"        BufferedInputStream doubleWrap = new BufferedInputStream(bis);\n" +
5542
			"        System.out.println(bis.available());\n" +
5543
			"        bis.close();\n" +
5544
			"    }\n" +
5545
			"    void inline() throws IOException {\n" +
5546
			"        File file = new File(\"somefile\");\n" +
5547
			"        BufferedInputStream bis2 = new BufferedInputStream(fis = new FileInputStream(file));\n" + // field assignment
5548
			"        System.out.println(bis2.available());\n" +
5549
			"        bis2.close();\n" +
5550
			"        FileInputStream fileStream  = null;\n" +
5551
			"        BufferedInputStream bis3 = new BufferedInputStream(fileStream = new FileInputStream(file));\n" +
5552
			"        System.out.println(bis3.available());\n" +
5553
			"        bis3.close();\n" +
5554
			"    }\n" +
5555
			"    public static void main(String[] args) throws IOException {\n" +
5556
			"        try {\n" +
5557
			"            new X().foo();\n" +
5558
			"        } catch (IOException ex) {" +
5559
			"            System.out.println(\"Got IO Exception\");\n" +
5560
			"        }\n" +
5561
			"    }\n" +
5562
			"}\n"
5563
		},
5564
		"Got IO Exception",
5565
		null,
5566
		true,
5567
		null,
5568
		options,
5569
		null);
5570
}
5571
// Bug 358903 - Filter practically unimportant resource leak warnings
5572
// Bug 361073 - Avoid resource leak warning when the top level resource is closed explicitly
5573
// a resource wrapper is closed closing also the underlying resource - original test case
5574
public void test061f() throws IOException {
5575
	Map options = getCompilerOptions();
5576
	options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR);
5577
	options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR);
5578
	URL url = FileLocator.toFileURL(FileLocator.find(Platform.getBundle("org.eclipse.jdt.core.tests.compiler"), new Path("META-INF/MANIFEST.MF"), null));
5579
	this.runConformTest(
5580
		new String[] {
5581
			"X.java",
5582
			"import java.io.InputStream;\n" +
5583
			"import java.io.InputStreamReader;\n" +
5584
			"import java.io.BufferedReader;\n" +
5585
			"import java.io.IOException;\n" +
5586
			"import java.net.URL;\n" +
5587
			"public class X {\n" +
5588
			"    boolean loadURL(final URL url) throws IOException {\n" + 
5589
			"    InputStream stream = null;\n" + 
5590
			"        BufferedReader reader = null;\n" + 
5591
			"        try {\n" + 
5592
			"            stream = url.openStream();\n" + 
5593
			"            reader = new BufferedReader(new InputStreamReader(stream));\n" + 
5594
			"            System.out.println(reader.readLine());\n" +
5595
			"        } finally {\n" + 
5596
			"            try {\n" + 
5597
			"                if (reader != null)\n" + 
5598
			"                    reader.close();\n" + 
5599
			"            } catch (IOException x) {\n" + 
5600
			"            }\n" + 
5601
			"        }\n" + 
5602
			"        return false; // 'stream' may not be closed at this location\n" + 
5603
			"    }\n" + 
5604
			"    public static void main(String[] args) throws IOException {\n" +
5605
			"        try {\n" +
5606
			"            new X().loadURL(new URL(\""+url.toString()+"\"));\n" +
5607
			"        } catch (IOException ex) {\n" +
5608
			"            System.out.println(\"Got IO Exception\"+ex);\n" +
5609
			"        }\n" +
5610
			"    }\n" +
5611
			"}\n"
5612
		},
5613
		"Manifest-Version: 1.0",
5614
		null,
5615
		true,
5616
		null,
5617
		options,
5618
		null);
5619
}
5620
// Bug 358903 - Filter practically unimportant resource leak warnings
5621
// Bug 360908 - Avoid resource leak warning when the underlying/chained resource is closed explicitly
5622
// Different points in a resource chain are closed
5623
public void test061g() {
5624
	Map options = getCompilerOptions();
5625
	options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR);
5626
	options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR);
5627
	this.runNegativeTest(
5628
		new String[] {
5629
			"X.java",
5630
			"import java.io.File;\n" +
5631
			"import java.io.BufferedInputStream;\n" +
5632
			"import java.io.FileInputStream;\n" +
5633
			"import java.io.IOException;\n" +
5634
			"public class X {\n" +
5635
			"    void closeMiddle() throws IOException {\n" +
5636
			"        File file = new File(\"somefile\");\n" +
5637
			"        FileInputStream fileStream  = new FileInputStream(file);\n" +
5638
			"        BufferedInputStream bis = new BufferedInputStream(fileStream);\n" +
5639
			"        BufferedInputStream doubleWrap = new BufferedInputStream(bis);\n" +
5640
			"        System.out.println(bis.available());\n" +
5641
			"        bis.close();\n" +
5642
			"    }\n" +
5643
			"    void closeOuter() throws IOException {\n" +
5644
			"        File file2 = new File(\"somefile\");\n" +
5645
			"        FileInputStream fileStream2  = new FileInputStream(file2);\n" +
5646
			"        BufferedInputStream bis2 = new BufferedInputStream(fileStream2);\n" +
5647
			"        BufferedInputStream doubleWrap2 = new BufferedInputStream(bis2);\n" +
5648
			"        System.out.println(bis2.available());\n" +
5649
			"        doubleWrap2.close();\n" +
5650
			"    }\n" +
5651
			"    void neverClosed() throws IOException {\n" +
5652
			"        File file3 = new File(\"somefile\");\n" +
5653
			"        FileInputStream fileStream3  = new FileInputStream(file3);\n" +
5654
			"        BufferedInputStream bis3 = new BufferedInputStream(fileStream3);\n" +
5655
			"        BufferedInputStream doubleWrap3 = new BufferedInputStream(bis3);\n" +
5656
			"        System.out.println(doubleWrap3.available());\n" +
5657
			"    }\n" +
5658
			"}\n"
5659
		},
5660
		"----------\n" + 
5661
		"1. ERROR in X.java (at line 26)\n" + 
5662
		"	BufferedInputStream doubleWrap3 = new BufferedInputStream(bis3);\n" + 
5663
		"	                    ^^^^^^^^^^^\n" + 
5664
		"Resource leak: \'doubleWrap3\' is never closed\n" + 
5665
		"----------\n",
5666
		null,
5667
		true,
5668
		options);
5669
}
5670
// Bug 358903 - Filter practically unimportant resource leak warnings
5671
// Bug 360908 - Avoid resource leak warning when the underlying/chained resource is closed explicitly
5672
// Different points in a resource chain are potentially closed
5673
public void test061h() {
5674
	Map options = getCompilerOptions();
5675
	options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR);
5676
	options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR);
5677
	this.runNegativeTest(
5678
		new String[] {
5679
			"X.java",
5680
			"import java.io.File;\n" +
5681
			"import java.io.BufferedInputStream;\n" +
5682
			"import java.io.FileInputStream;\n" +
5683
			"import java.io.IOException;\n" +
5684
			"public class X {\n" +
5685
			"    void closeMiddle(boolean b) throws IOException {\n" +
5686
			"        File file = new File(\"somefile\");\n" +
5687
			"        FileInputStream fileStream  = new FileInputStream(file);\n" +
5688
			"        BufferedInputStream bis = new BufferedInputStream(fileStream);\n" +
5689
			"        BufferedInputStream doubleWrap = new BufferedInputStream(bis);\n" +
5690
			"        System.out.println(bis.available());\n" +
5691
			"        if (b)\n" +
5692
			"            bis.close();\n" +
5693
			"    }\n" +
5694
			"    void closeOuter(boolean b) throws IOException {\n" +
5695
			"        File file2 = new File(\"somefile\");\n" +
5696
			"        FileInputStream fileStream2  = new FileInputStream(file2);\n" +
5697
			"        BufferedInputStream bis2 = new BufferedInputStream(fileStream2);\n" +
5698
			"        BufferedInputStream doubleWrap2 = new BufferedInputStream(bis2);\n" +
5699
			"        System.out.println(bis2.available());\n" +
5700
			"        if (b)\n" +
5701
			"            doubleWrap2.close();\n" +
5702
			"    }\n" +
5703
			"    void potAndDef(boolean b) throws IOException {\n" +
5704
			"        File file3 = new File(\"somefile\");\n" +
5705
			"        FileInputStream fileStream3  = new FileInputStream(file3);\n" +
5706
			"        BufferedInputStream bis3 = new BufferedInputStream(fileStream3);\n" +
5707
			"        BufferedInputStream doubleWrap3 = new BufferedInputStream(bis3);\n" +
5708
			"        System.out.println(doubleWrap3.available());\n" +
5709
			"        if (b) bis3.close();\n" +
5710
			"        fileStream3.close();\n" +
5711
			"    }\n" +
5712
			"}\n"
5713
		},
5714
		"----------\n" + 
5715
		"1. ERROR in X.java (at line 10)\n" + 
5716
		"	BufferedInputStream doubleWrap = new BufferedInputStream(bis);\n" + 
5717
		"	                    ^^^^^^^^^^\n" + 
5718
		"Potential resource leak: \'doubleWrap\' may not be closed\n" + 
5719
		"----------\n" + 
5720
		"2. ERROR in X.java (at line 19)\n" + 
5721
		"	BufferedInputStream doubleWrap2 = new BufferedInputStream(bis2);\n" + 
5722
		"	                    ^^^^^^^^^^^\n" + 
5723
		"Potential resource leak: \'doubleWrap2\' may not be closed\n" + 
5724
		"----------\n",
5725
		null,
5726
		true,
5727
		options);
5728
}
5729
// Bug 358903 - Filter practically unimportant resource leak warnings
5730
// local var is re-used for two levels of wrappers
5731
public void test061i() {
5732
	Map options = getCompilerOptions();
5733
	options.put(CompilerOptions.OPTION_ReportUnclosedCloseable, CompilerOptions.ERROR);
5734
	options.put(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, CompilerOptions.ERROR);
5735
	this.runNegativeTest(
5736
		new String[] {
5737
			"X.java",
5738
			"import java.io.File;\n" +
5739
			"import java.io.InputStream;\n" +
5740
			"import java.io.BufferedInputStream;\n" +
5741
			"import java.io.FileInputStream;\n" +
5742
			"import java.io.IOException;\n" +
5743
			"public class X {\n" +
5744
			"    void closeMiddle() throws IOException {\n" +
5745
			"        File file = new File(\"somefile\");\n" +
5746
			"        InputStream stream  = new FileInputStream(file);\n" +
5747
			"        stream = new BufferedInputStream(stream);\n" +
5748
			"        InputStream middle;\n" +
5749
			"        stream = new BufferedInputStream(middle = stream);\n" +
5750
			"        System.out.println(stream.available());\n" +
5751
			"        middle.close();\n" +
5752
			"    }\n" +
5753
			"    void closeOuter() throws IOException {\n" +
5754
			"        File file = new File(\"somefile\");\n" +
5755
			"        InputStream stream  = new FileInputStream(file);\n" +
5756
			"        stream = new BufferedInputStream(stream);\n" +
5757
			"        stream = new BufferedInputStream(stream);\n" +
5758
			"        System.out.println(stream.available());\n" +
5759
			"        stream.close();\n" +
5760
			"    }\n" +
5761
			"    void neverClosed() throws IOException {\n" +
5762
			"        File file = new File(\"somefile\");\n" +
5763
			"        InputStream stream  = new FileInputStream(file);\n" +
5764
			"        stream = new BufferedInputStream(stream);\n" +
5765
			"        stream = new BufferedInputStream(stream);\n" +
5766
			"        System.out.println(stream.available());\n" +
5767
			"    }\n" +
5768
			"}\n"
5769
		},
5770
		"----------\n" + 
5771
		"1. ERROR in X.java (at line 26)\n" + 
5772
		"	InputStream stream  = new FileInputStream(file);\n" + 
5773
		"	            ^^^^^^\n" + 
5774
		"Resource leak: \'stream\' is never closed\n" + 
5775
		"----------\n",
5776
		null,
5777
		true,
5778
		options);
5779
}
5358
public static Class testClass() {
5780
public static Class testClass() {
5359
	return TryWithResourcesStatementTest.class;
5781
	return TryWithResourcesStatementTest.class;
5360
}
5782
}
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java (-2 / +2 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 45-51 Link Here
45
	if (this.arguments != null) {
45
	if (this.arguments != null) {
46
		for (int i = 0, count = this.arguments.length; i < count; i++) {
46
		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.)
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);
48
			flowInfo = FakedTrackingVariable.markPassedToOutside(currentScope, this.arguments[i], flowInfo, this.resolvedType);
49
			flowInfo =
49
			flowInfo =
50
				this.arguments[i]
50
				this.arguments[i]
51
					.analyseCode(currentScope, flowContext, flowInfo)
51
					.analyseCode(currentScope, flowContext, flowInfo)
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java (-11 / +14 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.id == TypeIds.T_null);
55
	if (shouldAnalyseResource)
56
		preInitInfo = flowInfo.unconditionalCopy();
57
	
49
	flowInfo = ((Reference) this.lhs)
58
	flowInfo = ((Reference) this.lhs)
50
		.analyseAssignment(currentScope, flowContext, flowInfo, this, false)
59
		.analyseAssignment(currentScope, flowContext, flowInfo, this, false)
51
		.unconditionalInits();
60
		.unconditionalInits();
52
	if (local != null) {
61
53
		LocalVariableBinding previousTrackerBinding = null;
62
	if (shouldAnalyseResource)
54
		if (local.closeTracker != null) {
63
		FakedTrackingVariable.handleResourceAssignment(preInitInfo, flowInfo, this, this.expression, local);
55
			// Assigning to a variable already holding an AutoCloseable, has it been closed before?
64
56
			previousTrackerBinding = local.closeTracker.binding;
57
			if (!flowInfo.isDefinitelyNull(local)) // only if previous value may be non-null
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);
65
	int nullStatus = this.expression.nullStatus(flowInfo);
63
	if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) {
66
	if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) {
64
		if (nullStatus == FlowInfo.NULL) {
67
		if (nullStatus == FlowInfo.NULL) {
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FakedTrackingVariable.java (-20 / +251 lines)
Lines 48-56 Link Here
48
	private static final int CLOSED_IN_NESTED_METHOD = 4;
48
	private static final int CLOSED_IN_NESTED_METHOD = 4;
49
	// a location independent issue has been reported already against this resource:
49
	// a location independent issue has been reported already against this resource:
50
	private static final int REPORTED = 8;
50
	private static final int REPORTED = 8;
51
	// a resource is wrapped in another resource:
52
	private static final int WRAPPED = 16;
51
	
53
	
52
	/**
54
	/**
53
	 * Bitset of {@link #CLOSE_SEEN}, {@link #PASSED_TO_OUTSIDE}, {@link #CLOSED_IN_NESTED_METHOD} and {@link #REPORTED}.
55
	 * Bitset of {@link #CLOSE_SEEN}, {@link #PASSED_TO_OUTSIDE}, {@link #CLOSED_IN_NESTED_METHOD}, {@link #REPORTED} and {@link #WRAPPED}.
54
	 */
56
	 */
55
	private int globalClosingState = 0;
57
	private int globalClosingState = 0;
56
58
Lines 58-67 Link Here
58
	
60
	
59
	public LocalVariableBinding originalBinding; // the real local being tracked
61
	public LocalVariableBinding originalBinding; // the real local being tracked
60
	
62
	
61
	HashMap recordedLocations; // initially null, ASTNode -> Integer 
63
	HashMap recordedLocations; // initially null, ASTNode -> Integer
62
64
65
	public FakedTrackingVariable innerTracker; // chained tracking variable of a chained (wrapped) resource
63
66
64
	public FakedTrackingVariable(LocalVariableBinding original, Statement location) {
67
	// marker instance to signal this pattern: resource = new Wrapper(resource);
68
	final private static FakedTrackingVariable SELF_WRAP = new FakedTrackingVariable();
69
70
	private FakedTrackingVariable() {
71
		super(null, 0, 0);
72
		/* empty ctor for marker instance */ 
73
	}
74
75
	public FakedTrackingVariable(LocalVariableBinding original, ASTNode location) {
65
		super(original.name, location.sourceStart, location.sourceEnd);
76
		super(original.name, location.sourceStart, location.sourceEnd);
66
		this.type = new SingleTypeReference(
77
		this.type = new SingleTypeReference(
67
				TypeConstants.OBJECT,
78
				TypeConstants.OBJECT,
Lines 129-164 Link Here
129
140
130
	/** 
141
	/** 
131
	 * Check if the rhs of an assignment or local declaration is an (Auto)Closeable.
142
	 * 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. 
143
	 * If so create or re-use a tracking variable, and wire and initialize everything.
144
	 * @param upstreamInfo info without analysis of the rhs, use this to determine the status of a resource being disconnected
145
	 * @param flowInfo info with analysis of the rhs, use this for recording resource status because this will be passed downstream
146
	 * @param location where to report warnigs/errors against
147
	 * @param rhs the right hand side of the assignment, this expression is to be analyzed.
148
	 *			The caller has already checked that the rhs is either of a closeable type or null.
149
	 * @param local the local variable into which the rhs is being assigned
133
	 */
150
	 */
134
	public static void handleResourceAssignment(FlowInfo flowInfo, Statement location, Expression rhs, LocalVariableBinding local,
151
	public static void handleResourceAssignment(FlowInfo upstreamInfo, FlowInfo flowInfo, ASTNode location, Expression rhs, LocalVariableBinding local)
135
				LocalVariableBinding previousTrackerBinding) 
136
	{
152
	{
137
		if (isAutoCloseable(rhs.resolvedType)) {
153
		FakedTrackingVariable previousTracker = null;
154
		FakedTrackingVariable disconnectedTracker = null;
155
		if (local.closeTracker != null) {
156
			// assigning to a variable already holding an AutoCloseable, has it been closed before?
157
			previousTracker = local.closeTracker;
158
			int status = upstreamInfo.nullStatus(local);
159
			if (status != FlowInfo.NULL && status != FlowInfo.UNKNOWN) // only if previous value may be relevant
160
				disconnectedTracker = previousTracker;
161
		}
162
163
		if (rhs.resolvedType.id != TypeIds.T_null) {
138
			// new value is AutoCloseable, start tracking, possibly re-using existing tracker var:
164
			// new value is AutoCloseable, start tracking, possibly re-using existing tracker var:
139
	
140
			FakedTrackingVariable rhsTrackVar = getCloseTrackingVariable(rhs);
165
			FakedTrackingVariable rhsTrackVar = getCloseTrackingVariable(rhs);
141
			if (rhsTrackVar != null) {								// 1. share tracking variable with RHS?
166
			if (rhsTrackVar != null) {								// 1. share tracking variable with RHS?
142
				local.closeTracker = rhsTrackVar;
167
				local.closeTracker = rhsTrackVar;
143
				// keep null-status unchanged across this assignment
168
				// keep null-status unchanged across this assignment
144
			} else if (previousTrackerBinding != null) {			// 2. re-use tracking variable from the LHS?
169
			} else if (previousTracker != null) {					// 2. re-use tracking variable from the LHS?
145
				// re-assigning from a fresh, mark as not-closed again:
170
				// re-assigning from a fresh, mark as not-closed again:
146
				flowInfo.markAsDefinitelyNull(previousTrackerBinding);
171
				flowInfo.markAsDefinitelyNull(previousTracker.binding);
172
				local.closeTracker = analyseCloseableExpression(flowInfo, local, location, rhs, previousTracker);
173
				if (local.closeTracker == SELF_WRAP) {
174
					local.closeTracker = previousTracker;
175
					return; // avoid calling recordErrorLocation below
176
				}
147
			} else {												// 3. no re-use, create a fresh tracking variable:
177
			} else {												// 3. no re-use, create a fresh tracking variable:
148
				local.closeTracker = new FakedTrackingVariable(local, location);
178
				rhsTrackVar = analyseCloseableExpression(flowInfo, local, location, rhs, null);
149
				// a fresh resource, mark as not-closed:
179
				if (rhsTrackVar != null) {
150
				flowInfo.markAsDefinitelyNull(local.closeTracker.binding);
180
					local.closeTracker = rhsTrackVar;
181
					// a fresh resource, mark as not-closed:
182
					flowInfo.markAsDefinitelyNull(local.closeTracker.binding);
151
// TODO(stephan): this might be useful, but I could not find a test case for it: 
183
// TODO(stephan): this might be useful, but I could not find a test case for it: 
152
//				if (flowContext.initsOnFinally != null)
184
//					if (flowContext.initsOnFinally != null)
153
//					flowContext.initsOnFinally.markAsDefinitelyNonNull(trackerBinding);
185
//						flowContext.initsOnFinally.markAsDefinitelyNonNull(trackerBinding);
186
				}
154
			}
187
			}
155
		}
188
		}
189
190
		if (disconnectedTracker != null)
191
			disconnectedTracker.recordErrorLocation(location, upstreamInfo.nullStatus(disconnectedTracker.binding));
192
	}
193
	/**
194
	 * analyze structure of a closeable expression, matching (chained) resources against our white lists.
195
	 * See  Bug 358903 - Filter practically unimportant resource leak warnings
196
	 * @param flowInfo used when recursing back into {@link #handleResourceAssignment}
197
	 * @param local local variable to which the closeable is being assigned
198
	 * @param location where to flag errors/warnings against
199
	 * @param expression expression to be analyzed
200
	 * @param previousTracker when analyzing a re-assignment we may already have a tracking variable for local,
201
	 *  		which we should then re-use
202
	 * @return a tracking variable associated with local or null if no need to track
203
	 */
204
	private static FakedTrackingVariable analyseCloseableExpression(FlowInfo flowInfo, 
205
				LocalVariableBinding local, ASTNode location, Expression expression, FakedTrackingVariable previousTracker) 
206
	{
207
		if (expression.resolvedType instanceof ReferenceBinding) {
208
			ReferenceBinding resourceType = (ReferenceBinding) expression.resolvedType;
209
			
210
			if (resourceType.hasTypeBit(TypeIds.BitResourceFreeCloseable)) {
211
				// (a) resource-free closeable: -> null
212
				return null;
213
			}					
214
			
215
			if (resourceType.hasTypeBit(TypeIds.BitWrapperCloseable)) {
216
				// (b) wrapper
217
				Expression innerExpression = expression; 
218
				if (innerExpression instanceof Assignment)
219
					innerExpression = ((Assignment)innerExpression).expression;
220
				if (innerExpression instanceof AllocationExpression) {
221
					Expression[] args = ((AllocationExpression) innerExpression).arguments;
222
					if (args != null && args.length == 1) {
223
						// (b.1) wrapper allocation with argument
224
						return analyseCloseableAllocationArgument(flowInfo, local, location, args[0], previousTracker);
225
					}
226
				}
227
				LocalVariableBinding innerLocal = innerExpression.localVariableBinding();
228
				if (innerLocal != null && innerLocal.closeTracker != null) {
229
					FakedTrackingVariable outerTracker = previousTracker != null ? previousTracker : new FakedTrackingVariable(local, location); 
230
					outerTracker.innerTracker = innerLocal.closeTracker;
231
					innerLocal.closeTracker.globalClosingState |= WRAPPED;
232
					return outerTracker;
233
				}
234
				// (b.2) wrapper with irrelevant inner: -> null
235
				return null;
236
			}
237
		}
238
		if (local.closeTracker != null)
239
			// (c): inner has already been analysed: -> re-use track var
240
			return local.closeTracker;
241
		// (d): normal resource: -> normal tracking var
242
		if (previousTracker != null)
243
			return previousTracker; // (d.1): re-use existing tracking var
244
		return new FakedTrackingVariable(local, location);
245
	}
246
247
	// an outer allocation expression has an argument, recursively analyze whether the arg is closeable 
248
	// return (1) a possible nested tracker for the outer expression or (2) null signaling no relevant resource contained  
249
	static FakedTrackingVariable analyseCloseableAllocationArgument(FlowInfo flowInfo, LocalVariableBinding outerLocal, ASTNode outerLocation, 
250
			Expression arg, FakedTrackingVariable previousTracker)
251
	{
252
		if (arg instanceof Assignment) {
253
			Assignment assign = (Assignment)arg;
254
			LocalVariableBinding innerLocal = assign.localVariableBinding();
255
			if (innerLocal != null) {
256
				// nested assignment has already been processed
257
				if (innerLocal.closeTracker != null && innerLocal.closeTracker.originalBinding == outerLocal)
258
					return SELF_WRAP; // signal special case to our caller: resource = new Wrapper(resource);
259
				return innerLocal.closeTracker; // FIXME do we need a nested tracker here? see test061a/e
260
			} else {
261
				arg = assign.expression; // unwrap assignment and fall through
262
			}
263
		}
264
		if (arg instanceof SingleNameReference) {
265
			SingleNameReference ref = (SingleNameReference) arg;
266
			if (ref.binding instanceof LocalVariableBinding) {
267
				// allocation arg is a reference to an existing closeable?
268
				return getTrackingVarForNested(flowInfo, outerLocal, outerLocation, (LocalVariableBinding)ref.binding, ref, ref, previousTracker);
269
			}
270
		} else if (arg instanceof AllocationExpression && arg.resolvedType instanceof ReferenceBinding) {
271
			// nested allocation
272
			ReferenceBinding innerType = (ReferenceBinding)arg.resolvedType;
273
			if (innerType.hasTypeBit(TypeIds.BitResourceFreeCloseable)) {
274
				return null; // leaf of wrapper-chain is irrelevant
275
			} else if (innerType.hasTypeBit(TypeIds.BitWrapperCloseable)) {
276
				// nested wrapper -> nested tracking variables may skip this level as it is not bound to a local variable
277
				Expression[] args = ((AllocationExpression) arg).arguments;
278
				if (args != null && args.length > 0)
279
					return analyseCloseableAllocationArgument(flowInfo, outerLocal, arg, args[0], previousTracker);
280
				return null; // wrapper with no arg? shouldn't occur actually
281
			} else {
282
				// (c) wrapper alloc with direct nested alloc of regular: -> normal track var (no local represents inner)
283
				return previousTracker != null ? previousTracker : new FakedTrackingVariable(outerLocal, outerLocation);
284
			}
285
		}
286
		return null;
287
	}
288
	
289
	// an outer allocation expression has an argument, create/link outer and inner tracking variable and return the outer
290
	// return null if inner is not tracked
291
	private static FakedTrackingVariable getTrackingVarForNested(FlowInfo flowInfo, LocalVariableBinding outerLocal, ASTNode outerLocation, 
292
			LocalVariableBinding innerLocal, ASTNode innerLocation, Expression innerExpression, FakedTrackingVariable previousTracker)
293
	{
294
		if (outerLocal == innerLocal)
295
			return SELF_WRAP;
296
		FakedTrackingVariable innerTracker = analyseCloseableExpression(flowInfo, innerLocal, innerLocation, innerExpression, null);
297
		if (innerTracker == SELF_WRAP)
298
			return SELF_WRAP;
299
		if (innerTracker != null) {
300
			FakedTrackingVariable outerTracker = previousTracker != null ? previousTracker : new FakedTrackingVariable(outerLocal, outerLocation); 
301
			outerTracker.innerTracker = innerTracker;
302
			innerTracker.globalClosingState |= WRAPPED;
303
			return outerTracker;
304
		}
305
		return null;
156
	}
306
	}
157
307
158
	/** Answer wither the given type binding is a subtype of java.lang.AutoCloseable. */
308
	/** Answer wither the given type binding is a subtype of java.lang.AutoCloseable. */
159
	public static boolean isAutoCloseable(TypeBinding typeBinding) {
309
	public static boolean isAutoCloseable(TypeBinding typeBinding) {
160
		return typeBinding instanceof ReferenceBinding
310
		return typeBinding instanceof ReferenceBinding
161
			&& ((ReferenceBinding)typeBinding).hasTypeBit(TypeIds.BitAutoCloseable|TypeIds.BitCloseable);
311
			&& ((ReferenceBinding)typeBinding).hasTypeBit(TypeIds.BitAutoCloseable|TypeIds.BitCloseable);
312
	}
313
314
	public int findMostSpecificStatus(FlowInfo flowInfo, BlockScope currentScope, BlockScope locationScope) {
315
		int status = FlowInfo.UNKNOWN;
316
		FakedTrackingVariable currentTracker = this;
317
		// loop as to consider wrappers (per white list) encapsulating an inner resource.
318
		while (currentTracker != null) {
319
			LocalVariableBinding currentVar = currentTracker.binding;
320
			int currentStatus = getNullStatusAggressively(currentVar, flowInfo);
321
			if (locationScope != null) // only check at method exit points
322
				currentStatus = mergeCloseStatus(locationScope, currentStatus, currentVar, currentScope);
323
			if (currentStatus == FlowInfo.NON_NULL) {
324
				status = currentStatus;
325
				break; // closed -> stop searching
326
			} else if (status == FlowInfo.NULL || status == FlowInfo.UNKNOWN) {
327
				status = currentStatus; // improved although not yet safe -> keep searching for better
328
			}
329
			currentTracker = currentTracker.innerTracker;
330
		}
331
		return status;
332
	}
333
334
	/**
335
	 * Get the null status looking even into unreachable flows
336
	 * @param local
337
	 * @param flowInfo
338
	 * @return one of the constants FlowInfo.{NULL,POTENTIALLY_NULL,POTENTIALLY_NON_NULL,NON_NULL}.
339
	 */
340
	private int getNullStatusAggressively(LocalVariableBinding local, FlowInfo flowInfo) {
341
		int reachMode = flowInfo.reachMode();
342
		int status = 0;
343
		try {
344
			// unreachable flowInfo is too shy in reporting null-issues, temporarily forget reachability:
345
			if (reachMode != FlowInfo.REACHABLE)
346
				flowInfo.tagBits &= ~FlowInfo.UNREACHABLE;
347
			status = flowInfo.nullStatus(local);
348
		} finally {
349
			// reset
350
			flowInfo.tagBits |= reachMode;
351
		}
352
		// at this point some combinations are not useful so flatten to a single bit:
353
		if ((status & FlowInfo.NULL) != 0) {
354
			if ((status & (FlowInfo.NON_NULL | FlowInfo.POTENTIALLY_NON_NULL)) != 0)
355
				return FlowInfo.POTENTIALLY_NULL; 	// null + doubt = pot null
356
			return FlowInfo.NULL;
357
		} else if ((status & FlowInfo.NON_NULL) != 0) {
358
			if ((status & FlowInfo.POTENTIALLY_NULL) != 0)
359
				return FlowInfo.POTENTIALLY_NULL;	// non-null + doubt = pot null
360
			return FlowInfo.NON_NULL;
361
		} else if ((status & FlowInfo.POTENTIALLY_NULL) != 0)
362
			return FlowInfo.POTENTIALLY_NULL;
363
		return status;
364
	}
365
366
	public int mergeCloseStatus(BlockScope currentScope, int status, LocalVariableBinding local, BlockScope outerScope) {
367
		// get the most suitable null status representing whether resource 'binding' has been closed
368
		// start at 'currentScope' and potentially travel out until 'outerScope'
369
		// at each scope consult any recorded 'finallyInfo'.
370
		if (status != FlowInfo.NON_NULL) {
371
			if (currentScope.finallyInfo != null) {
372
				int finallyStatus = currentScope.finallyInfo.nullStatus(local);
373
				if (finallyStatus == FlowInfo.NON_NULL)
374
					return finallyStatus;
375
				if (finallyStatus != FlowInfo.NULL) // neither is NON_NULL, but not both are NULL => call it POTENTIALLY_NULL
376
					status = FlowInfo.POTENTIALLY_NULL;
377
			}
378
			if (currentScope != outerScope && currentScope.parent instanceof BlockScope)
379
				return mergeCloseStatus(((BlockScope) currentScope.parent), status, local, outerScope);
380
		}
381
		return status;
162
	}
382
	}
163
383
164
	/** Mark that this resource is closed locally. */
384
	/** Mark that this resource is closed locally. */
Lines 180-186 Link Here
180
	 * (as argument to a method/ctor call or as a return value from the current method), 
400
	 * (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.
401
	 * and thus should be considered as potentially closed.
182
	 */
402
	 */
183
	public static FlowInfo markPassedToOutside(BlockScope scope, Expression expression, FlowInfo flowInfo) {
403
	public static FlowInfo markPassedToOutside(BlockScope scope, Expression expression, FlowInfo flowInfo, TypeBinding allocatedType) {	
404
		if ((allocatedType instanceof ReferenceBinding) 
405
				&& ((ReferenceBinding) allocatedType).hasTypeBit(TypeIds.BitWrapperCloseable))
406
			return flowInfo; // wrapped closeables are analyzed separately:
407
		
184
		FakedTrackingVariable trackVar = getCloseTrackingVariable(expression);
408
		FakedTrackingVariable trackVar = getCloseTrackingVariable(expression);
185
		if (trackVar != null) {
409
		if (trackVar != null) {
186
			trackVar.globalClosingState |= PASSED_TO_OUTSIDE;
410
			trackVar.globalClosingState |= PASSED_TO_OUTSIDE;
Lines 201-209 Link Here
201
	}
425
	}
202
426
203
	public boolean reportRecordedErrors(Scope scope) {
427
	public boolean reportRecordedErrors(Scope scope) {
204
		if (this.globalClosingState == 0) {
428
		FakedTrackingVariable current = this;
205
			reportError(scope.problemReporter(), null, FlowInfo.NULL);
429
		while (current.globalClosingState == 0) {
206
			return true;
430
			current = current.innerTracker;
431
			if (current == null) {
432
				// no relevant state found -> report:
433
				reportError(scope.problemReporter(), null, FlowInfo.NULL);
434
				return true;
435
			}
207
		}
436
		}
208
		boolean hasReported = false;
437
		boolean hasReported = false;
209
		if (this.recordedLocations != null) {
438
		if (this.recordedLocations != null) {
Lines 218-223 Link Here
218
	}
447
	}
219
	
448
	
220
	public void reportError(ProblemReporter problemReporter, ASTNode location, int nullStatus) {
449
	public void reportError(ProblemReporter problemReporter, ASTNode location, int nullStatus) {
450
		if ((this.globalClosingState & WRAPPED) != 0)
451
			return;
221
		if (nullStatus == FlowInfo.NULL) {
452
		if (nullStatus == FlowInfo.NULL) {
222
			if ((this.globalClosingState & CLOSED_IN_NESTED_METHOD) != 0)
453
			if ((this.globalClosingState & CLOSED_IN_NESTED_METHOD) != 0)
223
				problemReporter.potentiallyUnclosedCloseable(this, location);
454
				problemReporter.potentiallyUnclosedCloseable(this, location);
Lines 225-231 Link Here
225
				problemReporter.unclosedCloseable(this, location);
456
				problemReporter.unclosedCloseable(this, location);
226
		} else if (nullStatus == FlowInfo.POTENTIALLY_NULL) {
457
		} else if (nullStatus == FlowInfo.POTENTIALLY_NULL) {
227
			problemReporter.potentiallyUnclosedCloseable(this, location);
458
			problemReporter.potentiallyUnclosedCloseable(this, location);
228
		}		
459
		}
229
	}
460
	}
230
461
231
	public void reportExplicitClosing(ProblemReporter problemReporter) {
462
	public void reportExplicitClosing(ProblemReporter problemReporter) {
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java (-2 / +12 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
77
	flowInfo =
84
	flowInfo =
78
		this.initialization
85
		this.initialization
79
			.analyseCode(currentScope, flowContext, flowInfo)
86
			.analyseCode(currentScope, flowContext, flowInfo)
80
			.unconditionalInits();
87
			.unconditionalInits();
81
	FakedTrackingVariable.handleResourceAssignment(flowInfo, this, this.initialization, this.binding, null);
88
89
	if (shouldAnalyseResource)
90
		FakedTrackingVariable.handleResourceAssignment(preInitInfo, flowInfo, this, this.initialization, this.binding);
91
82
	int nullStatus = this.initialization.nullStatus(flowInfo);
92
	int nullStatus = this.initialization.nullStatus(flowInfo);
83
	if (!flowInfo.isDefinitelyAssigned(this.binding)){// for local variable debug attributes
93
	if (!flowInfo.isDefinitelyAssigned(this.binding)){// for local variable debug attributes
84
		this.bits |= FirstAssignmentToLocal;
94
		this.bits |= FirstAssignmentToLocal;
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java (-1 / +1 lines)
Lines 97-103 Link Here
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.)
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);
100
			flowInfo = FakedTrackingVariable.markPassedToOutside(currentScope, this.arguments[i], flowInfo, null);
101
			flowInfo = this.arguments[i].analyseCode(currentScope, flowContext, flowInfo).unconditionalInits();
101
			flowInfo = this.arguments[i].analyseCode(currentScope, flowContext, flowInfo).unconditionalInits();
102
		}
102
		}
103
		analyseArguments(currentScope, flowContext, flowInfo, this.binding, this.arguments);
103
		analyseArguments(currentScope, flowContext, flowInfo, this.binding, this.arguments);
(-)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/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 / +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 1003-1012 Link Here
1003
		FakedTrackingVariable trackingVar = (FakedTrackingVariable) this.trackingVariables.get(i);
1003
		FakedTrackingVariable trackingVar = (FakedTrackingVariable) this.trackingVariables.get(i);
1004
		if (location != null && trackingVar.originalBinding != null && flowInfo.isDefinitelyNull(trackingVar.originalBinding))
1004
		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
1005
			continue; // reporting against a specific location, resource is null at this flow, don't complain
1006
		int status = getNullStatusAggressively(trackingVar.binding, flowInfo);
1006
		
1007
		// try to improve info if a close() inside finally was observed:
1007
		// compute the most specific null status for this resource,
1008
		if (locationScope != null) // only check at method exit points
1008
		int status = trackingVar.findMostSpecificStatus(flowInfo, this, locationScope);
1009
			status = locationScope.mergeCloseStatus(status, trackingVar.binding, this);
1009
		
1010
		if (status == FlowInfo.NULL) {
1010
		if (status == FlowInfo.NULL) {
1011
			// definitely unclosed: highest priority
1011
			// definitely unclosed: highest priority
1012
			reportResourceLeak(trackingVar, location, status);
1012
			reportResourceLeak(trackingVar, location, status);
Lines 1033-1056 Link Here
1033
			this.locals[i].closeTracker = null;		
1033
			this.locals[i].closeTracker = null;		
1034
		this.trackingVariables = null;
1034
		this.trackingVariables = null;
1035
	}
1035
	}
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
}
1036
}
1055
1037
1056
private void reportResourceLeak(FakedTrackingVariable trackingVar, ASTNode location, int nullStatus) {
1038
private void reportResourceLeak(FakedTrackingVariable trackingVar, ASTNode location, int nullStatus) {
Lines 1097-1133 Link Here
1097
	}
1079
	}
1098
	if (this.parent instanceof BlockScope)
1080
	if (this.parent instanceof BlockScope)
1099
		((BlockScope) this.parent).correlateTrackingVarsIfElse(thenFlowInfo, elseFlowInfo);
1081
		((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
}
1082
}
1133
}
1083
}
(-)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 (+27 lines)
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
	return 0;
1498
}
1472
}
1499
}
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java (-1 / +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 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
	};
167
	char[][] JAVA_IO_RESOURCE_FREE_CLOSEABLES = new char[][] {			
168
		"StringReader".toCharArray(), //$NON-NLS-1$
169
		"StringWriter".toCharArray(), //$NON-NLS-1$
170
		"ByteArrayInputStream".toCharArray(), //$NON-NLS-1$
171
		"ByteArrayOutputStream".toCharArray(), //$NON-NLS-1$
172
		"CharArrayReader".toCharArray(), //$NON-NLS-1$
173
		"CharArrayWriter".toCharArray(), //$NON-NLS-1$
174
	};
157
175
158
	// Constraints for generic type argument inference
176
	// Constraints for generic type argument inference
159
	int CONSTRAINT_EQUAL = 0;		// Actual = Formal
177
	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