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

Collapse All | Expand All

(-)a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceImplTests.java (-6 / +26 lines)
Lines 34-42 Link Here
34
import org.eclipse.jdt.internal.compiler.flow.UnconditionalFlowInfo;
34
import org.eclipse.jdt.internal.compiler.flow.UnconditionalFlowInfo;
35
import org.eclipse.jdt.internal.compiler.flow.UnconditionalFlowInfo.AssertionFailedException;
35
import org.eclipse.jdt.internal.compiler.flow.UnconditionalFlowInfo.AssertionFailedException;
36
import org.eclipse.jdt.internal.compiler.impl.Constant;
36
import org.eclipse.jdt.internal.compiler.impl.Constant;
37
import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
37
import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
38
import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
38
import org.eclipse.jdt.internal.compiler.lookup.PackageBinding;
39
import org.eclipse.jdt.internal.compiler.lookup.PackageBinding;
39
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
40
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
41
import org.eclipse.jdt.internal.compiler.lookup.VariableBinding;
40
42
41
/**
43
/**
42
 * A tests series especially meant to validate the internals of our null
44
 * A tests series especially meant to validate the internals of our null
Lines 1083-1100 Link Here
1083
	return copy;
1085
	return copy;
1084
}
1086
}
1085
1087
1086
public void markAsDefinitelyNonNull(LocalVariableBinding local) {
1088
public void markAsDefinitelyNonNull(VariableBinding local) {
1087
	grow(local.id + this.maxFieldCount);
1089
	int position;
1090
	if (local instanceof FieldBinding) {
1091
		position = local.id;
1092
	} else {
1093
		position = local.id + this.maxFieldCount;
1094
	}
1095
	grow(position);
1088
	super.markAsDefinitelyNonNull(local);
1096
	super.markAsDefinitelyNonNull(local);
1089
}
1097
}
1090
1098
1091
public void markAsDefinitelyNull(LocalVariableBinding local) {
1099
public void markAsDefinitelyNull(VariableBinding local) {
1092
	grow(local.id + this.maxFieldCount);
1100
	int position;
1101
	if (local instanceof FieldBinding) {
1102
		position = local.id;
1103
	} else {
1104
		position = local.id + this.maxFieldCount;
1105
	}
1106
	grow(position);
1093
	super.markAsDefinitelyNull(local);
1107
	super.markAsDefinitelyNull(local);
1094
}
1108
}
1095
1109
1096
public void markAsDefinitelyUnknown(LocalVariableBinding local) {
1110
public void markAsDefinitelyUnknown(VariableBinding local) {
1097
	grow(local.id + this.maxFieldCount);
1111
	int position;
1112
	if (local instanceof FieldBinding) {
1113
		position = local.id;
1114
	} else {
1115
		position = local.id + this.maxFieldCount;
1116
	}
1117
	grow(position);
1098
	super.markAsDefinitelyUnknown(local);
1118
	super.markAsDefinitelyUnknown(local);
1099
}
1119
}
1100
1120
(-)a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceTest.java (-35 / +573 lines)
Lines 108-120 Link Here
108
			"    o.toString();\n" +
108
			"    o.toString();\n" +
109
			"  }\n" +
109
			"  }\n" +
110
			"}\n"},
110
			"}\n"},
111
	""
111
		"----------\n" + 
112
//      "----------\n" +
112
		"1. ERROR in X.java (at line 5)\n" + 
113
//      "1. ERROR in X.java (at line 5)\n" +
113
		"	o.toString();\n" + 
114
//      "	o.toString();\n" +
114
		"	^\n" + 
115
//      "	^\n" +
115
		"Potential null pointer access: The field o may be null at this location\n" + 
116
//      "The field o is likely null; it was either set to null or checked for null when last used\n" +
116
		"----------\n"
117
//      "----------\n"
118
	);
117
	);
119
}
118
}
120
119
Lines 345-357 Link Here
345
			"    this.o.toString();\n" +
344
			"    this.o.toString();\n" +
346
			"  }\n" +
345
			"  }\n" +
347
			"}\n"},
346
			"}\n"},
348
		""
347
		"----------\n" + 
349
//      "----------\n" +
348
		"1. ERROR in X.java (at line 5)\n" + 
350
//      "1. ERROR in X.java (at line 5)\n" +
349
		"	this.o.toString();\n" + 
351
//      "	this.o.toString();\n" +
350
		"	     ^\n" + 
352
//      "	^^^^^^\n" +
351
		"Potential null pointer access: The field o may be null at this location\n" + 
353
//      "The field o is likely null; it was either set to null or checked for null when last used\n" +
352
		"----------\n"
354
//      "----------\n"
355
	);
353
	);
356
}
354
}
357
355
Lines 367-379 Link Here
367
			"    o.toString();\n" +
365
			"    o.toString();\n" +
368
			"  }\n" +
366
			"  }\n" +
369
			"}\n"},
367
			"}\n"},
370
		""
368
		"----------\n" + 
371
//      "----------\n" +
369
		"1. ERROR in X.java (at line 5)\n" + 
372
//      "1. ERROR in X.java (at line 5)\n" +
370
		"	o.toString();\n" + 
373
//      "	o.toString();\n" +
371
		"	^\n" + 
374
//      "	^\n" +
372
		"Potential null pointer access: The field o may be null at this location\n" + 
375
//      "The field o is likely null; it was either set to null or checked for null when last used\n" +
373
		"----------\n"
376
//      "----------\n"
377
	);
374
	);
378
}
375
}
379
376
Lines 423-435 Link Here
423
			"    }\n" +
420
			"    }\n" +
424
			"  }\n" +
421
			"  }\n" +
425
			"}\n"},
422
			"}\n"},
426
		""
423
		"----------\n" + 
427
//      "----------\n" +
424
		"1. ERROR in X.java (at line 6)\n" + 
428
//      "1. ERROR in X.java (at line 6)\n" +
425
		"	X.this.o.toString();\n" + 
429
//      "	X.this.o.toString();\n" +
426
		"	       ^\n" + 
430
//      "	^^^^^^^^\n" +
427
		"Potential null pointer access: The field o may be null at this location\n" + 
431
//      "The field o is likely null; it was either set to null or checked for null when last used\n" +
428
		"----------\n"
432
//      "----------\n"
433
	);
429
	);
434
}
430
}
435
431
Lines 448-460 Link Here
448
			"  }\n" +
444
			"  }\n" +
449
			"  void bar() {/* */}\n" +
445
			"  void bar() {/* */}\n" +
450
			"}\n"},
446
			"}\n"},
451
		""
447
		"----------\n" + 
452
//      "----------\n" +
448
		"1. ERROR in X.java (at line 5)\n" + 
453
//      "1. ERROR in X.java (at line 5)\n" +
449
		"	o.toString();\n" + 
454
//      "	o.toString();\n" +
450
		"	^\n" + 
455
//      "	^\n" +
451
		"Potential null pointer access: The field o may be null at this location\n" + 
456
//      "The field o is likely null; it was either set to null or checked for null when last used\n" +
452
		"----------\n"
457
//      "----------\n"
458
	);
453
	);
459
}
454
}
460
455
Lines 15396-15399 Link Here
15396
		"",/* expected error */
15391
		"",/* expected error */
15397
	    JavacTestOptions.Excuse.EclipseWarningConfiguredAsError);
15392
	    JavacTestOptions.Excuse.EclipseWarningConfiguredAsError);
15398
}
15393
}
15394
15395
// null analysis -- simple case for field
15396
public void testBug247564a() {
15397
	this.runNegativeTest(
15398
		new String[] {
15399
			"X.java",
15400
			"public class X {\n" +
15401
			"  Object o;\n" +
15402
			"  void foo() {\n" +
15403
			"    if (o == null && o.toString() == \"\"){}\n" +
15404
			"    else {}\n" +
15405
			"    o.toString();\n" + // toString() call above defuses null info, so no warning here
15406
			"  }\n" +
15407
			"}\n"},
15408
		"----------\n" + 
15409
		"1. ERROR in X.java (at line 4)\n" + 
15410
		"	if (o == null && o.toString() == \"\"){}\n" + 
15411
		"	                 ^\n" + 
15412
		"Potential null pointer access: The field o may be null at this location\n" + 
15413
		"----------\n"
15414
	);
15415
}
15416
15417
// null analysis -- simple case for field
15418
// no redundant null check warnings should be obtained since value of field
15419
// may be changed in another thread.
15420
public void testBug247564a_1() {
15421
	this.runNegativeTest(
15422
		new String[] {
15423
			"X.java",
15424
			"public class X {\n" +
15425
			"  Object o;\n" +
15426
			"  void foo() {\n" +
15427
			"	 o = null;" +
15428
			"    if (o == null){}\n" +
15429
			"    if (o != null){}\n" +	
15430
			"    o.toString();\n" +	// warn here
15431
			"  }\n" +
15432
			"}\n"},
15433
		"----------\n" +  
15434
		"1. ERROR in X.java (at line 6)\n" + 
15435
		"	o.toString();\n" + 
15436
		"	^\n" + 
15437
		"Potential null pointer access: The field o may be null at this location\n" + 
15438
		"----------\n"
15439
	);
15440
}
15441
15442
// null analysis -- simple case for field
15443
public void testBug247564a_2() {
15444
	this.runNegativeTest(
15445
		new String[] {
15446
			"X.java",
15447
			"public class X {\n" +
15448
			"  Object o;\n" +
15449
			"  void foo() {\n" +
15450
			"    if (o == null){\n" +	// o is null inside the if block
15451
			"		o.toString();\n" +
15452
			"    }\n" +
15453
			"  }\n" +
15454
			"}\n"},
15455
		"----------\n" + 
15456
		"1. ERROR in X.java (at line 5)\n" + 
15457
		"	o.toString();\n" + 
15458
		"	^\n" + 
15459
		"Potential null pointer access: The field o may be null at this location\n" + 
15460
		"----------\n"
15461
	);
15462
}
15463
15464
// null analysis -- simple case for field
15465
// null info from one method should not be present in the other (for instance fields)
15466
public void testBug247564a_3() {
15467
	this.runNegativeTest(
15468
		new String[] {
15469
			"X.java",
15470
			"public class X {\n" +
15471
			"  Object o;\n" +
15472
			"  void foo() {\n" +
15473
			"  }\n" +
15474
			"  void foo1() {\n" + 
15475
			"	 o.toString();\n" +
15476
			"  }\n" +
15477
			"}\n"},
15478
		""
15479
	);
15480
}
15481
15482
// null analysis -- simple case for static final field
15483
public void testBug247564b() {
15484
	this.runNegativeTest(
15485
		new String[] {
15486
			"X.java",
15487
			"public class X {\n" +
15488
			"  static final Object o = null;\n" +
15489
			"  static final Object o1 = new Object();\n" +
15490
			"  void foo() {\n" +
15491
			"    if (o.toString() == \"\") {}\n" +
15492
			"    if (o == null) {}\n" +
15493
			"	 if (o != null) {}\n" +
15494
			"	 if (o1 == null) {}\n" +
15495
			"	 if (o1 != null) {}\n" +
15496
			"  }\n" +
15497
			"}\n"},
15498
		"----------\n" + 
15499
		"1. ERROR in X.java (at line 5)\n" + 
15500
		"	if (o.toString() == \"\") {}\n" + 
15501
		"	    ^\n" + 
15502
		"Null pointer access: The field o can only be null at this location\n" + 
15503
		"----------\n" + 
15504
		"2. ERROR in X.java (at line 6)\n" + 
15505
		"	if (o == null) {}\n" + 
15506
		"	    ^\n" + 
15507
		"Redundant null check: The field o can only be null at this location\n" + 
15508
		"----------\n" + 
15509
		"3. ERROR in X.java (at line 7)\n" + 
15510
		"	if (o != null) {}\n" + 
15511
		"	    ^\n" + 
15512
		"Null comparison always yields false: The field o can only be null at this location\n" + 
15513
		"----------\n" + 
15514
		"4. WARNING in X.java (at line 7)\n" + 
15515
		"	if (o != null) {}\n" + 
15516
		"	               ^^\n" + 
15517
		"Dead code\n" + 
15518
		"----------\n" + 
15519
		"5. ERROR in X.java (at line 8)\n" + 
15520
		"	if (o1 == null) {}\n" + 
15521
		"	    ^^\n" + 
15522
		"Null comparison always yields false: The field o1 cannot be null at this location\n" + 
15523
		"----------\n" + 
15524
		"6. WARNING in X.java (at line 8)\n" + 
15525
		"	if (o1 == null) {}\n" + 
15526
		"	                ^^\n" + 
15527
		"Dead code\n" + 
15528
		"----------\n" + 
15529
		"7. ERROR in X.java (at line 9)\n" + 
15530
		"	if (o1 != null) {}\n" + 
15531
		"	    ^^\n" + 
15532
		"Redundant null check: The field o1 cannot be null at this location\n" + 
15533
		"----------\n"
15534
	);
15535
}
15536
15537
// null analysis -- simple case for static final field
15538
public void testBug247564b_1() {
15539
	this.runNegativeTest(
15540
		new String[] {
15541
			"X.java",
15542
			"public class X {\n" +
15543
			"  static final Object o;\n" +
15544
			"  static final Object o1;\n" +
15545
			"  static {\n" +
15546
			"		o = null;\n" +
15547
			"		o1 = new Object();\n" +
15548
			"  }\n" +
15549
			"  void foo() {\n" +
15550
			"    if (o.toString() == \"\") {}\n" +
15551
			"    if (o == null) {}\n" +
15552
			"	 if (o != null) {}\n" +
15553
			"	 if (o1 == null) {}\n" +
15554
			"	 if (o1 != null) {}\n" +
15555
			"  }\n" +
15556
			"}\n"},
15557
		"----------\n" + 
15558
		"1. ERROR in X.java (at line 9)\n" + 
15559
		"	if (o.toString() == \"\") {}\n" + 
15560
		"	    ^\n" + 
15561
		"Null pointer access: The field o can only be null at this location\n" + 
15562
		"----------\n" + 
15563
		"2. ERROR in X.java (at line 10)\n" + 
15564
		"	if (o == null) {}\n" + 
15565
		"	    ^\n" + 
15566
		"Redundant null check: The field o can only be null at this location\n" + 
15567
		"----------\n" + 
15568
		"3. ERROR in X.java (at line 11)\n" + 
15569
		"	if (o != null) {}\n" + 
15570
		"	    ^\n" + 
15571
		"Null comparison always yields false: The field o can only be null at this location\n" + 
15572
		"----------\n" + 
15573
		"4. WARNING in X.java (at line 11)\n" + 
15574
		"	if (o != null) {}\n" + 
15575
		"	               ^^\n" + 
15576
		"Dead code\n" + 
15577
		"----------\n" + 
15578
		"5. ERROR in X.java (at line 12)\n" + 
15579
		"	if (o1 == null) {}\n" + 
15580
		"	    ^^\n" + 
15581
		"Null comparison always yields false: The field o1 cannot be null at this location\n" + 
15582
		"----------\n" + 
15583
		"6. WARNING in X.java (at line 12)\n" + 
15584
		"	if (o1 == null) {}\n" + 
15585
		"	                ^^\n" + 
15586
		"Dead code\n" + 
15587
		"----------\n" + 
15588
		"7. ERROR in X.java (at line 13)\n" + 
15589
		"	if (o1 != null) {}\n" + 
15590
		"	    ^^\n" + 
15591
		"Redundant null check: The field o1 cannot be null at this location\n" + 
15592
		"----------\n"
15593
	);
15594
}
15595
15596
// null analysis -- fields in synchronized methods
15597
// check that null analysis for fields in synchronized methods
15598
// behave as it does in ordinary methods.
15599
public void testBug247564c() {
15600
	this.runNegativeTest(
15601
		new String[] {
15602
			"X.java",
15603
			"public class X {\n" +
15604
			"  Object o;\n" +
15605
			"  Object o1;\n" +
15606
			"  static final Object o2 = null;\n" +
15607
			"  static final Object o3 = new Object();\n" +
15608
			"  synchronized void foo() {\n" +
15609
			"		o = null;\n" +
15610
			"		if (o == null) {\n" +
15611
			"			o.toString();\n" +
15612
			"		}\n" +
15613
			"		o1 = new Object();\n" +
15614
			"		if (o1 == null) {\n" +
15615
			"			o1.toString();\n" +
15616
			"		}\n" +
15617
			"		if (o2 != null) {\n" +
15618
			"		}\n" +
15619
			"		else {\n" +
15620
			"			o2.toString();\n" +
15621
			"		}\n" +
15622
			"		if (o3 == null) {\n" +
15623
			"		}\n" +
15624
			"		else {\n" +
15625
			"			o3.toString();\n" +
15626
			"		}\n" +
15627
			"  }\n" +
15628
			"  void foo1() {\n" + 
15629
			"	 o.toString();\n" +
15630
			"  }\n" +
15631
			"}\n"},
15632
		"----------\n" + 
15633
		"1. ERROR in X.java (at line 9)\n" + 
15634
		"	o.toString();\n" + 
15635
		"	^\n" + 
15636
		"Potential null pointer access: The field o may be null at this location\n" + 
15637
		"----------\n" + 
15638
		"2. ERROR in X.java (at line 13)\n" + 
15639
		"	o1.toString();\n" + 
15640
		"	^^\n" + 
15641
		"Potential null pointer access: The field o1 may be null at this location\n" + 
15642
		"----------\n" + 
15643
		"3. ERROR in X.java (at line 15)\n" + 
15644
		"	if (o2 != null) {\n" + 
15645
		"	    ^^\n" + 
15646
		"Null comparison always yields false: The field o2 can only be null at this location\n" + 
15647
		"----------\n" + 
15648
		"4. WARNING in X.java (at line 15)\n" + 
15649
		"	if (o2 != null) {\n" + 
15650
		"		}\n" + 
15651
		"	                ^^^^^\n" + 
15652
		"Dead code\n" + 
15653
		"----------\n" + 
15654
		"5. ERROR in X.java (at line 18)\n" + 
15655
		"	o2.toString();\n" + 
15656
		"	^^\n" + 
15657
		"Null pointer access: The field o2 can only be null at this location\n" + 
15658
		"----------\n" + 
15659
		"6. ERROR in X.java (at line 20)\n" + 
15660
		"	if (o3 == null) {\n" + 
15661
		"	    ^^\n" + 
15662
		"Null comparison always yields false: The field o3 cannot be null at this location\n" + 
15663
		"----------\n" + 
15664
		"7. WARNING in X.java (at line 20)\n" + 
15665
		"	if (o3 == null) {\n" + 
15666
		"		}\n" + 
15667
		"	                ^^^^^\n" + 
15668
		"Dead code\n" + 
15669
		"----------\n"
15670
	);
15671
}
15672
15673
// null analysis -- test redundant instanceof warning for static final field
15674
public void testBug247564d() {
15675
	this.runNegativeTest(
15676
		new String[] {
15677
			"X.java",
15678
			"public class X {\n" +
15679
			"  static final Object o = null;\n" +
15680
			"  static final Object o1 = new Object();\n" +
15681
			"  void foo() {\n" +
15682
			"    if (o instanceof String) {}\n" +
15683
			"    if (o1 instanceof String) {}\n" +
15684
			"  }\n" +
15685
			"}\n"},
15686
		"----------\n" + 
15687
		"1. ERROR in X.java (at line 5)\n" + 
15688
		"	if (o instanceof String) {}\n" + 
15689
		"	    ^\n" + 
15690
		"instanceof always yields false: The field o can only be null at this location\n" + 
15691
		"----------\n"
15692
	);
15693
}
15694
15695
// null analysis -- test redundant instanceof warning for static final fields
15696
public void testBug247564e_1() {
15697
	this.runNegativeTest(
15698
		new String[] {
15699
			"X.java",
15700
			"public class X {\n" +
15701
			"  static final Object o = null;\n" +
15702
			"  void foo() {\n" +
15703
			"      if (o instanceof X) return;\n" +
15704
			"  }\n" +
15705
			"}"},
15706
		"----------\n" + 
15707
		"1. ERROR in X.java (at line 4)\n" + 
15708
		"	if (o instanceof X) return;\n" + 
15709
		"	    ^\n" + 
15710
		"instanceof always yields false: The field o can only be null at this location\n" + 
15711
		"----------\n",
15712
		JavacTestOptions.Excuse.EclipseWarningConfiguredAsError);
15713
}
15714
15715
// null analysis -- test potential null ptr access warning because of static field access through object returned by method call
15716
public void testBug247564f() {
15717
	Map compilerOptions = getCompilerOptions();
15718
	compilerOptions.put(CompilerOptions.OPTION_ReportNonStaticAccessToStatic, CompilerOptions.IGNORE);
15719
	this.runNegativeTest(
15720
		false,
15721
		new String[] {
15722
			"X.java",
15723
			"public class X {\n" +
15724
			"  static Object o;\n" +
15725
			"  static Object o1;\n" +
15726
			"  Object o2;\n" +
15727
			"  X getX() { return new X();\n}\n" +
15728
			"  void foo() {\n" +
15729
			"      if (getX().o == null && this.o.hashCode() == 0) return;\n" +
15730
			"      if (getX().o2 == null && this.o2.hashCode() == 0) return;\n" +
15731
			"  }\n" +
15732
			"}"},
15733
		null,
15734
		compilerOptions,
15735
		"----------\n" +
15736
		"1. ERROR in X.java (at line 8)\n" + 
15737
		"	if (getX().o == null && this.o.hashCode() == 0) return;\n" + 
15738
		"	                             ^\n" + 
15739
		"Potential null pointer access: The field o may be null at this location\n" + 
15740
		"----------\n",
15741
		JavacTestOptions.Excuse.EclipseWarningConfiguredAsError);
15742
}
15743
15744
// null analysis -- test potential null ptr access warning because of static field access through object returned by method call
15745
public void testBug247564f_1() {
15746
	Map compilerOptions = getCompilerOptions();
15747
	compilerOptions.put(CompilerOptions.OPTION_ReportNonStaticAccessToStatic, CompilerOptions.IGNORE);
15748
	this.runNegativeTest(
15749
		false,
15750
		new String[] {
15751
			"X.java",
15752
			"public class X {\n" +
15753
			"  static Object o;\n" +
15754
			"  X getX() { return new X();\n}\n" +
15755
			"  Y getY() { return new Y();\n}\n" +
15756
			"  void foo() {\n" +
15757
			"      if (getY().o == null && this.o.hashCode() == 0) return;\n" +
15758
			"      if (getX().o == null && this.o.hashCode() == 0) return;\n" +
15759
			"  }\n" +
15760
			"}\n" +
15761
			"class Y{\n" +
15762
			"	static Object o;\n" +
15763
			"}\n"},
15764
		null,
15765
		compilerOptions,
15766
		"----------\n" +
15767
		"1. ERROR in X.java (at line 9)\n" + 
15768
		"	if (getX().o == null && this.o.hashCode() == 0) return;\n" + 
15769
		"	                             ^\n" + 
15770
		"Potential null pointer access: The field o may be null at this location\n" + 
15771
		"----------\n",
15772
		JavacTestOptions.Excuse.EclipseWarningConfiguredAsError);
15773
}
15774
15775
// null analysis -- test field analysis in case of more than 64 fields
15776
public void testBug247564g() {
15777
	Map compilerOptions = getCompilerOptions();
15778
	compilerOptions.put(CompilerOptions.OPTION_ReportNonStaticAccessToStatic, CompilerOptions.IGNORE);
15779
	this.runNegativeTest(
15780
		false,
15781
		new String[] {
15782
			"X.java",
15783
			"public class X {\n" +
15784
			"Object field0, \n" +
15785
			"field1, field2, field3, field4, \n" +
15786
			"field5, field6, field7, field8, \n" +
15787
			"field9, field10, field11, field12, \n" +
15788
			"field13, field14, field15, field16, \n" +
15789
			"field17, field18, field19, field20, \n" +
15790
			"field21, field22, field23, field24, \n" +
15791
			"field25, field26, field27, field28, \n" +
15792
			"field29, field30, field31, field32, \n" +
15793
			"field33, field34, field35, field36, \n" +
15794
			"field37, field38, field39, field40, \n" +
15795
			"field41, field42, field43, field44, \n" +
15796
			"field45, field46, field47, field48, \n" +
15797
			"field49, field50, field51, field52, \n" +
15798
			"field53, field54, field55, field56, \n" +
15799
			"field57, field58, field59, field60, \n" +
15800
			"field61, field62, field63, field64, \n" +
15801
			"field65, field66, field67, field68, \n" +
15802
			"field69, field70, field71, field72, \n" +
15803
			"field73, field74, field75, field76, \n" +
15804
			"field77, field78, field79, field80, \n" +
15805
			"field81, field82, field83, field84, \n" +
15806
			"field85, field86, field87, field88, \n" +
15807
			"field89, field90, field91, field92, \n" +
15808
			"field93, field94, field95, field96, \n" +
15809
			"field97, field98, field99;\n" +
15810
			"static final Object field100 = null;\n" +
15811
			"  void foo() {\n" +
15812
			"	int i = 0;" +
15813
			"   while (i<10){\n" +
15814
			"      i++;\n" +
15815
			"      if (this.field99 == null && this.field99.hashCode() == 0){}\n" +
15816
			"	   this.field98 = null;\n" +
15817
			"	}\n" +
15818
			"	if (this.field98.hashCode() == 0) {}\n" +	// should not complain
15819
			"	this.field97 = null;\n" +
15820
			"	if (this.field97.hashCode() == 0) {}\n" +
15821
			"	if (this.field100.hashCode() == 0) {}\n" +
15822
			"  }\n" +
15823
			"}"},
15824
		null,
15825
		compilerOptions,
15826
		"----------\n" +
15827
		"1. ERROR in X.java (at line 32)\n" + 
15828
		"	if (this.field99 == null && this.field99.hashCode() == 0){}\n" + 
15829
		"	                                 ^^^^^^^\n" + 
15830
		"Potential null pointer access: The field field99 may be null at this location\n" + 
15831
		"----------\n" + 
15832
		"2. ERROR in X.java (at line 37)\n" + 
15833
		"	if (this.field97.hashCode() == 0) {}\n" + 
15834
		"	         ^^^^^^^\n" + 
15835
		"Potential null pointer access: The field field97 may be null at this location\n" + 
15836
		"----------\n" + 
15837
		"3. ERROR in X.java (at line 38)\n" + 
15838
		"	if (this.field100.hashCode() == 0) {}\n" + 
15839
		"	         ^^^^^^^^\n" + 
15840
		"Null pointer access: The field field100 can only be null at this location\n" + 
15841
		"----------\n",
15842
		JavacTestOptions.Excuse.EclipseWarningConfiguredAsError);
15843
}
15844
15845
// null analysis -- simple case for field for inner class
15846
// to make sure field id's of inner and outer classes are not same for flow analysis
15847
public void testBug247564h() {
15848
	this.runNegativeTest(
15849
		new String[] {
15850
			"X.java",
15851
			"public class X {\n" +
15852
			"  Object o;\n" +
15853
			"  class X1 {\n" +
15854
			"	 Object x;" +
15855
			"	 Object x1;" +
15856
			"	 Object x2;" +
15857
			"	 void goo() {\n" +
15858
			"    	if (o == null && x.toString() == \"\"){}\n" +
15859
			"	 	if (o2 == null && o2.toString() == \"\"){}\n" +
15860
			"	 	if (o2 == null && x2.toString() == \"\"){}\n" +
15861
			"    }\n" +
15862
			
15863
			"  }\n" +
15864
			"  Object o1;\n" +
15865
			"  static Object o2;\n" +
15866
			"}\n"},
15867
		"----------\n" + 
15868
		"1. ERROR in X.java (at line 6)\n" + 
15869
		"	if (o2 == null && o2.toString() == \"\"){}\n" + 
15870
		"	                  ^^\n" + 
15871
		"Potential null pointer access: The field o2 may be null at this location\n" + 
15872
		"----------\n"
15873
	);
15874
}
15875
15876
// null analysis -- simple case for field for inner class
15877
// to make sure that id's of local variables in inner classes dotn conflict with those of fields.
15878
public void testBug247564h_1() {
15879
	this.runNegativeTest(
15880
		new String[] {
15881
			"X.java",
15882
			"public class X {\n" +
15883
			"  Object field0;\n" +
15884
			"  Object field1;\n" +
15885
			"  class X1 {\n" +
15886
			"	 Object field2;" +
15887
			"	 Object field3;" +
15888
			"	 void goo(Object var) {\n" +
15889
			"    	if (var == null && field2.toString() == \"\"){}\n" +
15890
			"    	if (var == null && field3.toString() == \"\"){}\n" +
15891
			"    	if (field2 == null && field2.toString() == \"\"){}\n" +
15892
			"    }\n" +
15893
			"  }\n" +
15894
			"}\n"},
15895
		"----------\n" + 
15896
		"1. ERROR in X.java (at line 8)\n" + 
15897
		"	if (field2 == null && field2.toString() == \"\"){}\n" + 
15898
		"	                      ^^^^^^\n" + 
15899
		"Potential null pointer access: The field field2 may be null at this location\n" + 
15900
		"----------\n"
15901
	);
15902
}
15903
15904
// null analysis -- simple case for field for inner class
15905
// to make sure that id's of local variables in inner classes dotn conflict with those of fields.
15906
public void testBug247564h_2() {
15907
	this.runNegativeTest(
15908
		new String[] {
15909
			"X.java",
15910
			"public class X {\n" +
15911
			"  Object field0;\n" +
15912
			"  Object field1;\n" +
15913
			"  class X1 {\n" +
15914
			"	 Object field2;\n" +
15915
			"	 Object field3;\n" +
15916
			"	 class X2 {\n" +
15917
			"	 	Object field4;\n" +
15918
			"	 	Object field5;\n" +
15919
			"	 void goo(Object var) {\n" +
15920
			"    	if (var == null && field4.toString() == \"\"){}\n" +
15921
			"    	if (var == null && field5.toString() == \"\"){}\n" +
15922
			"    	if (field3 == null && field3.toString() == \"\"){}\n" +
15923
			"    	if (field3 == null && field1.toString() == \"\"){}\n" +
15924
			"    }\n" +
15925
			"    }\n" +
15926
			"  Object field22;\n" +
15927
			"  }\n" +
15928
			"}\n"},
15929
		"----------\n" + 
15930
		"1. ERROR in X.java (at line 13)\n" + 
15931
		"	if (field3 == null && field3.toString() == \"\"){}\n" + 
15932
		"	                      ^^^^^^\n" + 
15933
		"Potential null pointer access: The field field3 may be null at this location\n" + 
15934
		"----------\n"
15935
	);
15936
}
15399
}
15937
}
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java (+20 lines)
Lines 1267-1272 Link Here
1267
    /** @since 3.4 */
1267
    /** @since 3.4 */
1268
    int UnusedTypeArgumentsForConstructorInvocation = MethodRelated + 660;
1268
    int UnusedTypeArgumentsForConstructorInvocation = MethodRelated + 660;
1269
1269
1270
    /**
1271
	 * Null analysis for fields
1272
	 */
1273
    /** @since 3.8*/
1274
	int NullFieldReference = Internal + FieldRelated + 670;
1275
	/** @since 3.8*/
1276
	int PotentialNullFieldReference = Internal + FieldRelated + 671;
1277
	/** @since 3.8*/
1278
	int RedundantNullCheckOnNullField = Internal + FieldRelated + 672;
1279
	/** @since 3.8*/
1280
	int NullFieldComparisonYieldsFalse = Internal + FieldRelated + 673;
1281
	/** @since 3.8*/
1282
	int RedundantNullCheckOnNonNullField = Internal + FieldRelated + 674;
1283
	/** @since 3.8*/
1284
	int NonNullFieldComparisonYieldsFalse = Internal + FieldRelated + 675;
1285
	/** @since 3.8*/
1286
	int RedundantFieldNullAssignment = Internal + FieldRelated + 676;
1287
	/** @since 3.8*/
1288
	int NullFieldInstanceofYieldsFalse = Internal + FieldRelated + 677;
1289
	
1270
	/**
1290
	/**
1271
	 * Corrupted binaries
1291
	 * Corrupted binaries
1272
	 */
1292
	 */
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Block.java (+2 lines)
Lines 37-42 Link Here
37
			flowInfo = stat.analyseCode(this.scope, flowContext, flowInfo);
37
			flowInfo = stat.analyseCode(this.scope, flowContext, flowInfo);
38
		}
38
		}
39
	}
39
	}
40
	// don't let the flow info collected for fields from this block persist.
41
	flowInfo.resetNullInfoForFields();
40
	if (this.explicitDeclarations > 0) // if block has its own scope analyze tracking vars now:
42
	if (this.explicitDeclarations > 0) // if block has its own scope analyze tracking vars now:
41
		this.scope.checkUnclosedCloseables(flowInfo, null, null);
43
		this.scope.checkUnclosedCloseables(flowInfo, null, null);
42
	return flowInfo;
44
	return flowInfo;
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java (+8 lines)
Lines 33-38 Link Here
33
import org.eclipse.jdt.internal.compiler.lookup.TagBits;
33
import org.eclipse.jdt.internal.compiler.lookup.TagBits;
34
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
34
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
35
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
35
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
36
import org.eclipse.jdt.internal.compiler.lookup.VariableBinding;
36
import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
37
import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
37
38
38
public class CastExpression extends Expression {
39
public class CastExpression extends Expression {
Lines 445-450 Link Here
445
	return this.expression.localVariableBinding();
446
	return this.expression.localVariableBinding();
446
}
447
}
447
448
449
/**
450
 * @see org.eclipse.jdt.internal.compiler.ast.Expression#variableBinding()
451
 */
452
public VariableBinding variableBinding() {
453
	return this.expression.variableBinding();
454
}
455
448
public int nullStatus(FlowInfo flowInfo) {
456
public int nullStatus(FlowInfo flowInfo) {
449
	return this.expression.nullStatus(flowInfo);
457
	return this.expression.nullStatus(flowInfo);
450
}
458
}
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java (-4 / +4 lines)
Lines 39-61 Link Here
39
			scope.problemReporter().messageSendRedundantCheckOnNonNull(rightMessage.binding, rightMessage);
39
			scope.problemReporter().messageSendRedundantCheckOnNonNull(rightMessage.binding, rightMessage);
40
		}
40
		}
41
41
42
		LocalVariableBinding local = this.left.localVariableBinding();
42
		VariableBinding local = this.left.variableBinding();
43
		if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) {
43
		if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) {
44
			checkVariableComparison(scope, flowContext, flowInfo, initsWhenTrue, initsWhenFalse, local, this.right.nullStatus(flowInfo), this.left);
44
			checkVariableComparison(scope, flowContext, flowInfo, initsWhenTrue, initsWhenFalse, local, this.right.nullStatus(flowInfo), this.left);
45
		}
45
		}
46
		local = this.right.localVariableBinding();
46
		local = this.right.variableBinding();
47
		if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) {
47
		if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) {
48
			checkVariableComparison(scope, flowContext, flowInfo, initsWhenTrue, initsWhenFalse, local, this.left.nullStatus(flowInfo), this.right);
48
			checkVariableComparison(scope, flowContext, flowInfo, initsWhenTrue, initsWhenFalse, local, this.left.nullStatus(flowInfo), this.right);
49
		}
49
		}
50
	}
50
	}
51
	private void checkVariableComparison(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, FlowInfo initsWhenTrue, FlowInfo initsWhenFalse, LocalVariableBinding local, int nullStatus, Expression reference) {
51
	private void checkVariableComparison(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, FlowInfo initsWhenTrue, FlowInfo initsWhenFalse, VariableBinding local, int nullStatus, Expression reference) {
52
		switch (nullStatus) {
52
		switch (nullStatus) {
53
			case FlowInfo.NULL :
53
			case FlowInfo.NULL :
54
				if (((this.bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL) {
54
				if (((this.bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL) {
55
					flowContext.recordUsingNullReference(scope, local, reference,
55
					flowContext.recordUsingNullReference(scope, local, reference,
56
							FlowContext.CAN_ONLY_NULL_NON_NULL | FlowContext.IN_COMPARISON_NULL, flowInfo);
56
							FlowContext.CAN_ONLY_NULL_NON_NULL | FlowContext.IN_COMPARISON_NULL, flowInfo);
57
					initsWhenTrue.markAsComparedEqualToNull(local); // from thereon it is set
57
					initsWhenTrue.markAsComparedEqualToNull(local); // from thereon it is set
58
					initsWhenFalse.markAsComparedEqualToNonNull(local); // from thereon it is set
58
					initsWhenFalse.markAsComparedEqualToNonNull(local ); // from thereon it is set
59
				} else {
59
				} else {
60
					flowContext.recordUsingNullReference(scope, local, reference,
60
					flowContext.recordUsingNullReference(scope, local, reference,
61
							FlowContext.CAN_ONLY_NULL_NON_NULL | FlowContext.IN_COMPARISON_NON_NULL, flowInfo);
61
							FlowContext.CAN_ONLY_NULL_NON_NULL | FlowContext.IN_COMPARISON_NON_NULL, flowInfo);
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java (-3 / +12 lines)
Lines 36-41 Link Here
36
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
36
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
37
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
37
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
38
import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
38
import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
39
import org.eclipse.jdt.internal.compiler.lookup.VariableBinding;
39
import org.eclipse.jdt.internal.compiler.lookup.WildcardBinding;
40
import org.eclipse.jdt.internal.compiler.lookup.WildcardBinding;
40
import org.eclipse.jdt.internal.compiler.problem.ShouldNotImplement;
41
import org.eclipse.jdt.internal.compiler.problem.ShouldNotImplement;
41
import org.eclipse.jdt.internal.compiler.util.Messages;
42
import org.eclipse.jdt.internal.compiler.util.Messages;
Lines 525-538 Link Here
525
 * @param flowInfo the upstream flow info; caveat: may get modified
526
 * @param flowInfo the upstream flow info; caveat: may get modified
526
 */
527
 */
527
public void checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo) {
528
public void checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo) {
528
	LocalVariableBinding local = localVariableBinding();
529
	VariableBinding local = variableBinding();
529
	if (local != null &&
530
	if (local != null &&
530
			(local.type.tagBits & TagBits.IsBaseType) == 0) {
531
			(local.type.tagBits & TagBits.IsBaseType) == 0) {
531
		if ((this.bits & ASTNode.IsNonNull) == 0) {
532
		if ((this.bits & ASTNode.IsNonNull) == 0) {
532
			flowContext.recordUsingNullReference(scope, local, this,
533
			flowContext.recordUsingNullReference(scope, local, this,
533
					FlowContext.MAY_NULL, flowInfo);
534
					FlowContext.MAY_NULL, flowInfo);
534
		}
535
		}
535
		flowInfo.markAsComparedEqualToNonNull(local);
536
		flowInfo.markAsComparedEqualToNonNull(local );
536
			// from thereon it is set
537
			// from thereon it is set
537
		if ((flowContext.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) != 0) {
538
		if ((flowContext.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) != 0) {
538
			flowInfo.markedAsNullOrNonNullInAssertExpression(local);
539
			flowInfo.markedAsNullOrNonNullInAssertExpression(local);
Lines 872-878 Link Here
872
		this.constant != null && this.constant != Constant.NotAConstant)
873
		this.constant != null && this.constant != Constant.NotAConstant)
873
	return FlowInfo.NON_NULL; // constant expression cannot be null
874
	return FlowInfo.NON_NULL; // constant expression cannot be null
874
875
875
	LocalVariableBinding local = localVariableBinding();
876
	VariableBinding local = variableBinding();
876
	if (local != null)
877
	if (local != null)
877
		return flowInfo.nullStatus(local);
878
		return flowInfo.nullStatus(local);
878
	return FlowInfo.NON_NULL;
879
	return FlowInfo.NON_NULL;
Lines 1112-1115 Link Here
1112
public void traverse(ASTVisitor visitor, ClassScope scope) {
1113
public void traverse(ASTVisitor visitor, ClassScope scope) {
1113
	// nothing to do
1114
	// nothing to do
1114
}
1115
}
1116
1117
/**
1118
 * Returns the field or local variable referenced by this node. Can be a direct reference (SingleNameReference)
1119
 * or thru a cast expression etc...
1120
 */
1121
public VariableBinding variableBinding() {
1122
	return null;
1123
}
1115
}
1124
}
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldDeclaration.java (+7 lines)
Lines 74-79 Link Here
74
				.analyseCode(initializationScope, flowContext, flowInfo)
74
				.analyseCode(initializationScope, flowContext, flowInfo)
75
				.unconditionalInits();
75
				.unconditionalInits();
76
		flowInfo.markAsDefinitelyAssigned(this.binding);
76
		flowInfo.markAsDefinitelyAssigned(this.binding);
77
		if (this.binding.isFinal() && this.binding.isStatic()) {
78
			int nullStatus = this.initialization.nullStatus(flowInfo);
79
			// static final field being initialized. Record its null status for future reference
80
			// since the flowInfo from an initialization wont be available in a method
81
			
82
			this.binding.setNullStatusForStaticFinalField(nullStatus);
83
		}
77
	}
84
	}
78
	return flowInfo;
85
	return flowInfo;
79
}
86
}
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java (+14 lines)
Lines 35-40 Link Here
35
import org.eclipse.jdt.internal.compiler.lookup.TagBits;
35
import org.eclipse.jdt.internal.compiler.lookup.TagBits;
36
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
36
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
37
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
37
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
38
import org.eclipse.jdt.internal.compiler.lookup.VariableBinding;
38
39
39
public class FieldReference extends Reference implements InvocationSite {
40
public class FieldReference extends Reference implements InvocationSite {
40
41
Lines 668-671 Link Here
668
	}
669
	}
669
	visitor.endVisit(this, scope);
670
	visitor.endVisit(this, scope);
670
}
671
}
672
673
public VariableBinding variableBinding() {
674
	if (this.receiver.isThis() || this.binding.isStatic()) {
675
		if (this.receiver instanceof MessageSend) {
676
			if (((MessageSend) this.receiver).actualReceiverType == this.receiver.resolvedType) {
677
				return this.binding;
678
			}
679
		} else {
680
			return this.binding;
681
		}
682
	}
683
	return super.variableBinding();
684
}
671
}
685
}
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java (-5 / +5 lines)
Lines 31-46 Link Here
31
}
31
}
32
32
33
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
33
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
34
	LocalVariableBinding local = this.expression.localVariableBinding();
34
	VariableBinding variable = this.expression.variableBinding();
35
	if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) {
35
	if (variable != null && (variable.type.tagBits & TagBits.IsBaseType) == 0) {
36
		flowInfo = this.expression.analyseCode(currentScope, flowContext, flowInfo).
36
		flowInfo = this.expression.analyseCode(currentScope, flowContext, flowInfo).
37
			unconditionalInits();
37
			unconditionalInits();
38
		FlowInfo initsWhenTrue = flowInfo.copy();
38
		FlowInfo initsWhenTrue = flowInfo.copy();
39
		initsWhenTrue.markAsComparedEqualToNonNull(local);
39
		initsWhenTrue.markAsComparedEqualToNonNull(variable );
40
		if ((flowContext.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) != 0) {
40
		if ((flowContext.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) != 0) {
41
			initsWhenTrue.markedAsNullOrNonNullInAssertExpression(local);
41
			initsWhenTrue.markedAsNullOrNonNullInAssertExpression(variable);
42
		}
42
		}
43
		flowContext.recordUsingNullReference(currentScope, local,
43
		flowContext.recordUsingNullReference(currentScope, variable,
44
				this.expression, FlowContext.CAN_ONLY_NULL | FlowContext.IN_INSTANCEOF, flowInfo);
44
				this.expression, FlowContext.CAN_ONLY_NULL | FlowContext.IN_INSTANCEOF, flowInfo);
45
		// no impact upon enclosing try context
45
		// no impact upon enclosing try context
46
		return FlowInfo.conditional(initsWhenTrue, flowInfo.copy());
46
		return FlowInfo.conditional(initsWhenTrue, flowInfo.copy());
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java (+3 lines)
Lines 114-119 Link Here
114
		//               NullReferenceTest#test0510
114
		//               NullReferenceTest#test0510
115
	}
115
	}
116
	manageSyntheticAccessIfNecessary(currentScope, flowInfo);
116
	manageSyntheticAccessIfNecessary(currentScope, flowInfo);
117
	// a method call can result in changed values for fields, 
118
	// so wipe out null info for fields collected till now.
119
	flowInfo.resetNullInfoForFields();
117
	return flowInfo;
120
	return flowInfo;
118
}
121
}
119
public void checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo) {
122
public void checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo) {
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java (-4 / +12 lines)
Lines 807-812 Link Here
807
	return null;
807
	return null;
808
}
808
}
809
809
810
public VariableBinding variableBinding() {
811
	switch (this.bits & ASTNode.RestrictiveFlagMASK) {
812
		case Binding.FIELD : 
813
			// reading a field
814
		case Binding.LOCAL : // reading a local variable
815
			return (VariableBinding) this.binding;
816
	}
817
	return null;
818
}
810
public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
819
public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
811
	//If inlinable field, forget the access emulation, the code gen will directly target it
820
	//If inlinable field, forget the access emulation, the code gen will directly target it
812
	if (((this.bits & ASTNode.DepthMASK) == 0) || (this.constant != Constant.NotAConstant)) {
821
	if (((this.bits & ASTNode.DepthMASK) == 0) || (this.constant != Constant.NotAConstant)) {
Lines 859-869 Link Here
859
	}
868
	}
860
	switch (this.bits & ASTNode.RestrictiveFlagMASK) {
869
	switch (this.bits & ASTNode.RestrictiveFlagMASK) {
861
		case Binding.FIELD : // reading a field
870
		case Binding.FIELD : // reading a field
862
			return FlowInfo.UNKNOWN;
863
		case Binding.LOCAL : // reading a local variable
871
		case Binding.LOCAL : // reading a local variable
864
			LocalVariableBinding local = (LocalVariableBinding) this.binding;
872
			VariableBinding variable = (VariableBinding) this.binding;
865
			if (local != null)
873
			if (variable != null)
866
				return flowInfo.nullStatus(local);
874
				return flowInfo.nullStatus(variable);
867
	}
875
	}
868
	return FlowInfo.NON_NULL; // never get there
876
	return FlowInfo.NON_NULL; // never get there
869
}
877
}
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java (-11 / +39 lines)
Lines 651-657 Link Here
651
				// branch, since the previous initializer already got the blame.
651
				// branch, since the previous initializer already got the blame.
652
				if (staticFieldInfo == FlowInfo.DEAD_END) {
652
				if (staticFieldInfo == FlowInfo.DEAD_END) {
653
					this.staticInitializerScope.problemReporter().initializerMustCompleteNormally(field);
653
					this.staticInitializerScope.problemReporter().initializerMustCompleteNormally(field);
654
					staticFieldInfo = FlowInfo.initial(this.maxFieldCount).setReachMode(FlowInfo.UNREACHABLE_OR_DEAD);
654
					staticFieldInfo = FlowInfo.initial(this.scope.cumulativeFieldCount).setReachMode(FlowInfo.UNREACHABLE);
655
				}
655
				}
656
			} else {
656
			} else {
657
				if ((nonStaticFieldInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) != 0)
657
				if ((nonStaticFieldInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) != 0)
Lines 667-673 Link Here
667
				// branch, since the previous initializer already got the blame.
667
				// branch, since the previous initializer already got the blame.
668
				if (nonStaticFieldInfo == FlowInfo.DEAD_END) {
668
				if (nonStaticFieldInfo == FlowInfo.DEAD_END) {
669
					this.initializerScope.problemReporter().initializerMustCompleteNormally(field);
669
					this.initializerScope.problemReporter().initializerMustCompleteNormally(field);
670
					nonStaticFieldInfo = FlowInfo.initial(this.maxFieldCount).setReachMode(FlowInfo.UNREACHABLE_OR_DEAD);
670
					nonStaticFieldInfo = FlowInfo.initial(this.scope.cumulativeFieldCount).setReachMode(FlowInfo.UNREACHABLE);
671
				}
671
				}
672
			}
672
			}
673
		}
673
		}
Lines 683-688 Link Here
683
	}
683
	}
684
	if (this.methods != null) {
684
	if (this.methods != null) {
685
		UnconditionalFlowInfo outerInfo = flowInfo.unconditionalFieldLessCopy();
685
		UnconditionalFlowInfo outerInfo = flowInfo.unconditionalFieldLessCopy();
686
		//int fieldOffset = isLocal ? this.scope.cumulativeFieldCount : this.maxFieldCount;
687
		//int fieldStart = isLocal ? this.scope.localTypeFieldIdStart : 0;
686
		FlowInfo constructorInfo = nonStaticFieldInfo.unconditionalInits().discardNonFieldInitializations().addInitializationsFrom(outerInfo);
688
		FlowInfo constructorInfo = nonStaticFieldInfo.unconditionalInits().discardNonFieldInitializations().addInitializationsFrom(outerInfo);
687
		for (int i = 0, count = this.methods.length; i < count; i++) {
689
		for (int i = 0, count = this.methods.length; i < count; i++) {
688
			AbstractMethodDeclaration method = this.methods[i];
690
			AbstractMethodDeclaration method = this.methods[i];
Lines 1038-1045 Link Here
1038
				}
1040
				}
1039
			} while ((current = current.enclosingType()) != null);
1041
			} while ((current = current.enclosingType()) != null);
1040
		}
1042
		}
1041
		// this.maxFieldCount might already be set
1042
		int localMaxFieldCount = 0;
1043
		int lastVisibleFieldID = -1;
1043
		int lastVisibleFieldID = -1;
1044
		boolean hasEnumConstants = false;
1044
		boolean hasEnumConstants = false;
1045
		FieldDeclaration[] enumConstantsWithoutBody = null;
1045
		FieldDeclaration[] enumConstantsWithoutBody = null;
Lines 1049-1059 Link Here
1049
				this.typeParameters[i].resolve(this.scope);
1049
				this.typeParameters[i].resolve(this.scope);
1050
			}
1050
			}
1051
		}
1051
		}
1052
		if (this.memberTypes != null) {
1052
		// field count from supertypes should be included in maxFieldCount,
1053
			for (int i = 0, count = this.memberTypes.length; i < count; i++) {
1053
		// so that a field from supertype doesn't end up with same id as a local variable
1054
				this.memberTypes[i].resolve(this.scope);
1054
		// in a method being analyzed.
1055
		int superFieldsCount = 0;
1056
		ReferenceBinding superClassBinding = sourceType.superclass;
1057
		while (superClassBinding != null) {
1058
			FieldBinding[] unResolvedFields = superClassBinding.unResolvedFields();
1059
			if (unResolvedFields != null) {
1060
				superFieldsCount += unResolvedFields.length;
1055
			}
1061
			}
1062
			superFieldsCount += findFieldCountFromSuperInterfaces(superClassBinding.superInterfaces());
1063
			superClassBinding = superClassBinding.superclass();
1056
		}
1064
		}
1065
		ReferenceBinding[] superInterfacesBinding = this.binding.superInterfaces;
1066
		superFieldsCount += findFieldCountFromSuperInterfaces(superInterfacesBinding);
1067
		this.scope.cumulativeFieldCount += superFieldsCount;
1057
		if (this.fields != null) {
1068
		if (this.fields != null) {
1058
			for (int i = 0, count = this.fields.length; i < count; i++) {
1069
			for (int i = 0, count = this.fields.length; i < count; i++) {
1059
				FieldDeclaration field = this.fields[i];
1070
				FieldDeclaration field = this.fields[i];
Lines 1074-1086 Link Here
1074
							this.ignoreFurtherInvestigation = true;
1085
							this.ignoreFurtherInvestigation = true;
1075
							continue;
1086
							continue;
1076
						}
1087
						}
1088
						field.binding.id += superFieldsCount;
1077
						if (needSerialVersion
1089
						if (needSerialVersion
1078
								&& ((fieldBinding.modifiers & (ClassFileConstants.AccStatic | ClassFileConstants.AccFinal)) == (ClassFileConstants.AccStatic | ClassFileConstants.AccFinal))
1090
								&& ((fieldBinding.modifiers & (ClassFileConstants.AccStatic | ClassFileConstants.AccFinal)) == (ClassFileConstants.AccStatic | ClassFileConstants.AccFinal))
1079
								&& CharOperation.equals(TypeConstants.SERIALVERSIONUID, fieldBinding.name)
1091
								&& CharOperation.equals(TypeConstants.SERIALVERSIONUID, fieldBinding.name)
1080
								&& TypeBinding.LONG == fieldBinding.type) {
1092
								&& TypeBinding.LONG == fieldBinding.type) {
1081
							needSerialVersion = false;
1093
							needSerialVersion = false;
1082
						}
1094
						}
1083
						localMaxFieldCount++;
1084
						lastVisibleFieldID = field.binding.id;
1095
						lastVisibleFieldID = field.binding.id;
1085
						break;
1096
						break;
1086
1097
Lines 1090-1098 Link Here
1090
				}
1101
				}
1091
				field.resolve(field.isStatic() ? this.staticInitializerScope : this.initializerScope);
1102
				field.resolve(field.isStatic() ? this.staticInitializerScope : this.initializerScope);
1092
			}
1103
			}
1093
		}
1104
		}		
1094
		if (this.maxFieldCount < localMaxFieldCount) {
1105
		//		if (this.maxFieldCount < localMaxFieldCount) {
1095
			this.maxFieldCount = localMaxFieldCount;
1106
		//			this.maxFieldCount = localMaxFieldCount;
1107
		//		}
1108
		this.maxFieldCount = this.scope.cumulativeFieldCount;
1109
		if (this.memberTypes != null) {
1110
			for (int i = 0, count = this.memberTypes.length; i < count; i++) {
1111
				this.memberTypes[i].resolve(this.scope);
1112
			}
1096
		}
1113
		}
1097
		if (needSerialVersion) {
1114
		if (needSerialVersion) {
1098
			//check that the current type doesn't extend javax.rmi.CORBA.Stub
1115
			//check that the current type doesn't extend javax.rmi.CORBA.Stub
Lines 1180-1185 Link Here
1180
	}
1197
	}
1181
}
1198
}
1182
1199
1200
private int findFieldCountFromSuperInterfaces(ReferenceBinding[] superinterfaces) {
1201
	int numOfFields = 0;
1202
	if (superinterfaces == null)
1203
		return numOfFields ;
1204
	for (int i = 0; i < superinterfaces.length; i++) {
1205
		numOfFields += superinterfaces[i].fieldCount();
1206
		numOfFields += findFieldCountFromSuperInterfaces(superinterfaces[i].superInterfaces());		
1207
	}
1208
	return numOfFields;
1209
}
1210
1183
/**
1211
/**
1184
 * Resolve a local type declaration
1212
 * Resolve a local type declaration
1185
 */
1213
 */
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ConditionalFlowInfo.java (-19 / +25 lines)
Lines 13-18 Link Here
13
13
14
import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
14
import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
15
import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
15
import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
16
import org.eclipse.jdt.internal.compiler.lookup.VariableBinding;
16
17
17
/**
18
/**
18
 * Record conditional initialization status during definite assignment analysis
19
 * Record conditional initialization status during definite assignment analysis
Lines 85-101 Link Here
85
			&& this.initsWhenFalse.isDefinitelyAssigned(local);
86
			&& this.initsWhenFalse.isDefinitelyAssigned(local);
86
}
87
}
87
88
88
public boolean isDefinitelyNonNull(LocalVariableBinding local) {
89
public boolean isDefinitelyNonNull(VariableBinding local) {
89
	return this.initsWhenTrue.isDefinitelyNonNull(local)
90
	return this.initsWhenTrue.isDefinitelyNonNull(local)
90
			&& this.initsWhenFalse.isDefinitelyNonNull(local);
91
			&& this.initsWhenFalse.isDefinitelyNonNull(local);
91
}
92
}
92
93
93
public boolean isDefinitelyNull(LocalVariableBinding local) {
94
public boolean isDefinitelyNull(VariableBinding local) {
94
	return this.initsWhenTrue.isDefinitelyNull(local)
95
	return this.initsWhenTrue.isDefinitelyNull(local)
95
			&& this.initsWhenFalse.isDefinitelyNull(local);
96
			&& this.initsWhenFalse.isDefinitelyNull(local);
96
}
97
}
97
98
98
public boolean isDefinitelyUnknown(LocalVariableBinding local) {
99
public boolean isDefinitelyUnknown(VariableBinding local) {
99
	return this.initsWhenTrue.isDefinitelyUnknown(local)
100
	return this.initsWhenTrue.isDefinitelyUnknown(local)
100
			&& this.initsWhenFalse.isDefinitelyUnknown(local);
101
			&& this.initsWhenFalse.isDefinitelyUnknown(local);
101
}
102
}
Lines 110-146 Link Here
110
			|| this.initsWhenFalse.isPotentiallyAssigned(local);
111
			|| this.initsWhenFalse.isPotentiallyAssigned(local);
111
}
112
}
112
113
113
public boolean isPotentiallyNonNull(LocalVariableBinding local) {
114
public boolean isPotentiallyNonNull(VariableBinding local) {
114
	return this.initsWhenTrue.isPotentiallyNonNull(local)
115
	return this.initsWhenTrue.isPotentiallyNonNull(local)
115
		|| this.initsWhenFalse.isPotentiallyNonNull(local);
116
		|| this.initsWhenFalse.isPotentiallyNonNull(local);
116
}
117
}
117
118
118
public boolean isPotentiallyNull(LocalVariableBinding local) {
119
public boolean isPotentiallyNull(VariableBinding local) {
119
	return this.initsWhenTrue.isPotentiallyNull(local)
120
	return this.initsWhenTrue.isPotentiallyNull(local)
120
		|| this.initsWhenFalse.isPotentiallyNull(local);
121
		|| this.initsWhenFalse.isPotentiallyNull(local);
121
}
122
}
122
123
123
public boolean isPotentiallyUnknown(LocalVariableBinding local) {
124
public boolean isPotentiallyUnknown(VariableBinding local) {
124
	return this.initsWhenTrue.isPotentiallyUnknown(local)
125
	return this.initsWhenTrue.isPotentiallyUnknown(local)
125
		|| this.initsWhenFalse.isPotentiallyUnknown(local);
126
		|| this.initsWhenFalse.isPotentiallyUnknown(local);
126
}
127
}
127
128
128
public boolean isProtectedNonNull(LocalVariableBinding local) {
129
public boolean isProtectedNonNull(VariableBinding local) {
129
	return this.initsWhenTrue.isProtectedNonNull(local)
130
	return this.initsWhenTrue.isProtectedNonNull(local)
130
		&& this.initsWhenFalse.isProtectedNonNull(local);
131
		&& this.initsWhenFalse.isProtectedNonNull(local);
131
}
132
}
132
133
133
public boolean isProtectedNull(LocalVariableBinding local) {
134
public boolean isProtectedNull(VariableBinding local) {
134
	return this.initsWhenTrue.isProtectedNull(local)
135
	return this.initsWhenTrue.isProtectedNull(local)
135
		&& this.initsWhenFalse.isProtectedNull(local);
136
		&& this.initsWhenFalse.isProtectedNull(local);
136
}
137
}
137
138
138
public void markAsComparedEqualToNonNull(LocalVariableBinding local) {
139
public void markAsComparedEqualToNonNull(VariableBinding local) {
139
	this.initsWhenTrue.markAsComparedEqualToNonNull(local);
140
	this.initsWhenTrue.markAsComparedEqualToNonNull(local);
140
	this.initsWhenFalse.markAsComparedEqualToNonNull(local);
141
	this.initsWhenFalse.markAsComparedEqualToNonNull(local);
141
}
142
}
142
143
143
public void markAsComparedEqualToNull(LocalVariableBinding local) {
144
public void markAsComparedEqualToNull(VariableBinding local) {
144
	this.initsWhenTrue.markAsComparedEqualToNull(local);
145
	this.initsWhenTrue.markAsComparedEqualToNull(local);
145
    this.initsWhenFalse.markAsComparedEqualToNull(local);
146
    this.initsWhenFalse.markAsComparedEqualToNull(local);
146
}
147
}
Lines 155-191 Link Here
155
	this.initsWhenFalse.markAsDefinitelyAssigned(local);
156
	this.initsWhenFalse.markAsDefinitelyAssigned(local);
156
}
157
}
157
158
158
public void markAsDefinitelyNonNull(LocalVariableBinding local) {
159
public void markAsDefinitelyNonNull(VariableBinding local) {
159
	this.initsWhenTrue.markAsDefinitelyNonNull(local);
160
	this.initsWhenTrue.markAsDefinitelyNonNull(local);
160
	this.initsWhenFalse.markAsDefinitelyNonNull(local);
161
	this.initsWhenFalse.markAsDefinitelyNonNull(local);
161
}
162
}
162
163
163
public void markAsDefinitelyNull(LocalVariableBinding local) {
164
public void markAsDefinitelyNull(VariableBinding local) {
164
	this.initsWhenTrue.markAsDefinitelyNull(local);
165
	this.initsWhenTrue.markAsDefinitelyNull(local);
165
	this.initsWhenFalse.markAsDefinitelyNull(local);
166
	this.initsWhenFalse.markAsDefinitelyNull(local);
166
}
167
}
167
168
168
public void resetNullInfo(LocalVariableBinding local) {
169
public void resetNullInfo(VariableBinding local) {
169
	this.initsWhenTrue.resetNullInfo(local);
170
	this.initsWhenTrue.resetNullInfo(local);
170
	this.initsWhenFalse.resetNullInfo(local);
171
	this.initsWhenFalse.resetNullInfo(local);
171
}
172
}
172
173
173
public void markPotentiallyNullBit(LocalVariableBinding local) {
174
public void resetNullInfoForFields() {
175
	this.initsWhenTrue.resetNullInfoForFields();
176
	this.initsWhenFalse.resetNullInfoForFields();
177
}
178
179
public void markPotentiallyNullBit(VariableBinding local) {
174
	this.initsWhenTrue.markPotentiallyNullBit(local);
180
	this.initsWhenTrue.markPotentiallyNullBit(local);
175
	this.initsWhenFalse.markPotentiallyNullBit(local);
181
	this.initsWhenFalse.markPotentiallyNullBit(local);
176
}
182
}
177
183
178
public void markPotentiallyNonNullBit(LocalVariableBinding local) {
184
public void markPotentiallyNonNullBit(VariableBinding local) {
179
	this.initsWhenTrue.markPotentiallyNonNullBit(local);
185
	this.initsWhenTrue.markPotentiallyNonNullBit(local);
180
	this.initsWhenFalse.markPotentiallyNonNullBit(local);
186
	this.initsWhenFalse.markPotentiallyNonNullBit(local);
181
}
187
}
182
188
183
public void markAsDefinitelyUnknown(LocalVariableBinding local) {
189
public void markAsDefinitelyUnknown(VariableBinding local) {
184
	this.initsWhenTrue.markAsDefinitelyUnknown(local);
190
	this.initsWhenTrue.markAsDefinitelyUnknown(local);
185
	this.initsWhenFalse.markAsDefinitelyUnknown(local);
191
	this.initsWhenFalse.markAsDefinitelyUnknown(local);
186
}
192
}
187
193
188
public void markPotentiallyUnknownBit(LocalVariableBinding local) {
194
public void markPotentiallyUnknownBit(VariableBinding local) {
189
	this.initsWhenTrue.markPotentiallyUnknownBit(local);
195
	this.initsWhenTrue.markPotentiallyUnknownBit(local);
190
	this.initsWhenFalse.markPotentiallyUnknownBit(local);
196
	this.initsWhenFalse.markPotentiallyUnknownBit(local);
191
}
197
}
Lines 243-254 Link Here
243
			mergedWith(this.initsWhenFalse.unconditionalInits());
249
			mergedWith(this.initsWhenFalse.unconditionalInits());
244
}
250
}
245
251
246
public void markedAsNullOrNonNullInAssertExpression(LocalVariableBinding local) {
252
public void markedAsNullOrNonNullInAssertExpression(VariableBinding local) {
247
	this.initsWhenTrue.markedAsNullOrNonNullInAssertExpression(local);
253
	this.initsWhenTrue.markedAsNullOrNonNullInAssertExpression(local);
248
	this.initsWhenFalse.markedAsNullOrNonNullInAssertExpression(local);
254
	this.initsWhenFalse.markedAsNullOrNonNullInAssertExpression(local);
249
}
255
}
250
256
251
public boolean isMarkedAsNullOrNonNullInAssertExpression(LocalVariableBinding local) {
257
public boolean isMarkedAsNullOrNonNullInAssertExpression(VariableBinding local) {
252
	return (this.initsWhenTrue.isMarkedAsNullOrNonNullInAssertExpression(local)
258
	return (this.initsWhenTrue.isMarkedAsNullOrNonNullInAssertExpression(local)
253
		|| this.initsWhenFalse.isMarkedAsNullOrNonNullInAssertExpression(local));
259
		|| this.initsWhenFalse.isMarkedAsNullOrNonNullInAssertExpression(local));
254
}
260
}
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowContext.java (-14 / +14 lines)
Lines 585-591 Link Here
585
 *      combined with a context indicator (one of {@link #IN_COMPARISON_NULL},
585
 *      combined with a context indicator (one of {@link #IN_COMPARISON_NULL},
586
 *      {@link #IN_COMPARISON_NON_NULL}, {@link #IN_ASSIGNMENT} or {@link #IN_INSTANCEOF})
586
 *      {@link #IN_COMPARISON_NON_NULL}, {@link #IN_ASSIGNMENT} or {@link #IN_INSTANCEOF})
587
 */
587
 */
588
protected void recordNullReference(LocalVariableBinding local,
588
protected void recordNullReference(VariableBinding local,
589
	Expression expression, int status) {
589
	Expression expression, int status) {
590
	// default implementation: do nothing
590
	// default implementation: do nothing
591
}
591
}
Lines 628-634 Link Here
628
 *  	be known at the time of calling this method (they are influenced by
628
 *  	be known at the time of calling this method (they are influenced by
629
 * 		code that follows the current point)
629
 * 		code that follows the current point)
630
 */
630
 */
631
public void recordUsingNullReference(Scope scope, LocalVariableBinding local,
631
public void recordUsingNullReference(Scope scope, VariableBinding local,
632
		Expression reference, int checkType, FlowInfo flowInfo) {
632
		Expression reference, int checkType, FlowInfo flowInfo) {
633
	if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) != 0 ||
633
	if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) != 0 ||
634
			flowInfo.isDefinitelyUnknown(local)) {
634
			flowInfo.isDefinitelyUnknown(local)) {
Lines 640-653 Link Here
640
			if (flowInfo.isDefinitelyNonNull(local)) {
640
			if (flowInfo.isDefinitelyNonNull(local)) {
641
				if (checkType == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL)) {
641
				if (checkType == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL)) {
642
					if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
642
					if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
643
						scope.problemReporter().localVariableRedundantCheckOnNonNull(local, reference);
643
						scope.problemReporter().variableRedundantCheckOnNonNull(local, reference);
644
					}
644
					}
645
					if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) {
645
					if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) {
646
						flowInfo.initsWhenFalse().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
646
						flowInfo.initsWhenFalse().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
647
					}
647
					}
648
				} else {
648
				} else {
649
					if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
649
					if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
650
						scope.problemReporter().localVariableNonNullComparedToNull(local, reference);
650
						scope.problemReporter().variableNonNullComparedToNull(local, reference);
651
					}
651
					}
652
					if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) {
652
					if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) {
653
						flowInfo.initsWhenTrue().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
653
						flowInfo.initsWhenTrue().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
Lines 667-677 Link Here
667
				switch(checkType & CONTEXT_MASK) {
667
				switch(checkType & CONTEXT_MASK) {
668
					case FlowContext.IN_COMPARISON_NULL:
668
					case FlowContext.IN_COMPARISON_NULL:
669
						if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
669
						if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
670
							scope.problemReporter().localVariableNullReference(local, reference);
670
							scope.problemReporter().variableNullReference(local, reference);
671
							return;
671
							return;
672
						}
672
						}
673
						if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
673
						if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
674
							scope.problemReporter().localVariableRedundantCheckOnNull(local, reference);
674
							scope.problemReporter().variableRedundantCheckOnNull(local, reference);
675
						}
675
						}
676
						if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) {
676
						if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) {
677
							flowInfo.initsWhenFalse().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
677
							flowInfo.initsWhenFalse().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
Lines 679-712 Link Here
679
						return;
679
						return;
680
					case FlowContext.IN_COMPARISON_NON_NULL:
680
					case FlowContext.IN_COMPARISON_NON_NULL:
681
						if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
681
						if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
682
							scope.problemReporter().localVariableNullReference(local, reference);
682
							scope.problemReporter().variableNullReference(local, reference);
683
							return;
683
							return;
684
						}
684
						}
685
						if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
685
						if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
686
							scope.problemReporter().localVariableNullComparedToNonNull(local, reference);
686
							scope.problemReporter().variableNullComparedToNonNull(local, reference);
687
						}
687
						}
688
						if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) {
688
						if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) {
689
							flowInfo.initsWhenTrue().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
689
							flowInfo.initsWhenTrue().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
690
						}
690
						}
691
						return;
691
						return;
692
					case FlowContext.IN_ASSIGNMENT:
692
					case FlowContext.IN_ASSIGNMENT:
693
						scope.problemReporter().localVariableRedundantNullAssignment(local, reference);
693
						scope.problemReporter().variableRedundantNullAssignment(local, reference);
694
						return;
694
						return;
695
					case FlowContext.IN_INSTANCEOF:
695
					case FlowContext.IN_INSTANCEOF:
696
						scope.problemReporter().localVariableNullInstanceof(local, reference);
696
						scope.problemReporter().variableNullInstanceof(local, reference);
697
						return;
697
						return;
698
				}
698
				}
699
			} else if (flowInfo.isPotentiallyNull(local)) {
699
			} else if (flowInfo.isPotentiallyNull(local)) {
700
				switch(checkType & CONTEXT_MASK) {
700
				switch(checkType & CONTEXT_MASK) {
701
					case FlowContext.IN_COMPARISON_NULL:
701
					case FlowContext.IN_COMPARISON_NULL:
702
						if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
702
						if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
703
							scope.problemReporter().localVariablePotentialNullReference(local, reference);
703
							scope.problemReporter().variablePotentialNullReference(local, reference);
704
							return;
704
							return;
705
						}
705
						}
706
						break;
706
						break;
707
					case FlowContext.IN_COMPARISON_NON_NULL:
707
					case FlowContext.IN_COMPARISON_NON_NULL:
708
						if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
708
						if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
709
							scope.problemReporter().localVariablePotentialNullReference(local, reference);
709
							scope.problemReporter().variablePotentialNullReference(local, reference);
710
							return;
710
							return;
711
						}
711
						}
712
						break;
712
						break;
Lines 717-727 Link Here
717
			break;
717
			break;
718
		case MAY_NULL :
718
		case MAY_NULL :
719
			if (flowInfo.isDefinitelyNull(local)) {
719
			if (flowInfo.isDefinitelyNull(local)) {
720
				scope.problemReporter().localVariableNullReference(local, reference);
720
				scope.problemReporter().variableNullReference(local, reference);
721
				return;
721
				return;
722
			}
722
			}
723
			if (flowInfo.isPotentiallyNull(local)) {
723
			if (flowInfo.isPotentiallyNull(local)) {
724
				scope.problemReporter().localVariablePotentialNullReference(local, reference);
724
				scope.problemReporter().variablePotentialNullReference(local, reference);
725
				return;
725
				return;
726
			}
726
			}
727
			break;
727
			break;
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowInfo.java (-91 / +103 lines)
Lines 17-22 Link Here
17
import org.eclipse.jdt.internal.compiler.ast.IfStatement;
17
import org.eclipse.jdt.internal.compiler.ast.IfStatement;
18
import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
18
import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
19
import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
19
import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
20
import org.eclipse.jdt.internal.compiler.lookup.VariableBinding;
20
21
21
public abstract class FlowInfo {
22
public abstract class FlowInfo {
22
23
Lines 94-132 Link Here
94
	}
95
	}
95
96
96
/**
97
/**
97
 * Check whether a given local variable is known to be unable to gain a definite
98
 * Check whether a given field or local variable is known to be unable to gain a definite
98
 * non null or definite null status by the use of an enclosing flow info. The
99
 * non null or definite null status by the use of an enclosing flow info. The
99
 * semantics are that if the current flow info marks the variable as potentially
100
 * semantics are that if the current flow info marks the variable as potentially
100
 * unknown or else as being both potentially null and potentially non null,
101
 * unknown or else as being both potentially null and potentially non null,
101
 * then it won't ever be promoted as definitely null or definitely non null. (It
102
 * then it won't ever be promoted as definitely null or definitely non null. (It
102
 * could still get promoted to definite unknown).
103
 * could still get promoted to definite unknown).
103
 * @param local the variable to check
104
 * @param binding the field or local variable to check
104
 * @return true iff this flow info prevents local from being promoted to
105
 * @return true iff this flow info prevents field or local from being promoted to
105
 *         definite non null or definite null against an enclosing flow info
106
 *         definite non null or definite null against an enclosing flow info
106
 */
107
 */
107
public boolean cannotBeDefinitelyNullOrNonNull(LocalVariableBinding local) {
108
public boolean cannotBeDefinitelyNullOrNonNull(VariableBinding binding) {
108
	return isPotentiallyUnknown(local) ||
109
	return isPotentiallyUnknown(binding) ||
109
		isPotentiallyNonNull(local) && isPotentiallyNull(local);
110
		isPotentiallyNonNull(binding) && isPotentiallyNull(binding);
110
}
111
}
111
112
112
/**
113
/**
113
 * Check whether a given local variable is known to be non null, either because
114
 * Check whether a given field or local variable is known to be non null, either because
114
 * it is definitely non null, or because is has been tested against non null.
115
 * it is definitely non null, or because is has been tested against non null.
115
 * @param local the variable to ckeck
116
 * @param binding the field or local to check
116
 * @return true iff local cannot be null for this flow info
117
 * @return true iff field or local cannot be null for this flow info
117
 */
118
 */
118
public boolean cannotBeNull(LocalVariableBinding local) {
119
public boolean cannotBeNull(VariableBinding binding) {
119
	return isDefinitelyNonNull(local) || isProtectedNonNull(local);
120
	return isDefinitelyNonNull(binding) || isProtectedNonNull(binding);
120
}
121
}
121
122
122
/**
123
/**
123
 * Check whether a given local variable is known to be null, either because it
124
 * Check whether a given field or local variable is known to be null, either because it
124
 * is definitely null, or because is has been tested against null.
125
 * is definitely null, or because is has been tested against null. Note that for fields, 
125
 * @param local the variable to ckeck
126
 * this method only takes compile time analysis into account and there's no 
126
 * @return true iff local can only be null for this flow info
127
 * guarantee of the field being definitely null during runtime
128
 * since it can be modified in some other thread.
129
 * @param binding the field or local to check
130
 * @return true iff field or local can only be null for this flow info
127
 */
131
 */
128
public boolean canOnlyBeNull(LocalVariableBinding local) {
132
public boolean canOnlyBeNull(VariableBinding binding) {
129
	return isDefinitelyNull(local) || isProtectedNull(local);
133
	return isDefinitelyNull(binding) || isProtectedNull(binding);
130
}
134
}
131
135
132
/**
136
/**
Lines 174-198 Link Here
174
	public abstract boolean isDefinitelyAssigned(LocalVariableBinding local);
178
	public abstract boolean isDefinitelyAssigned(LocalVariableBinding local);
175
179
176
/**
180
/**
177
 * Check status of definite non-null value for a given local variable.
181
 * Check status of definite non-null value for a given field or local variable. Note that for fields, this method only
178
 * @param local the variable to ckeck
182
 * takes compile time analysis into account and there's no guarantee of the field being definitely non null during runtime
179
 * @return true iff local is definitely non null for this flow info
183
 * since it can be modified in some other thread.
184
 * @param binding the field or local to check
185
 * @return true iff field or local is definitely non null for this flow info
180
 */
186
 */
181
	public abstract boolean isDefinitelyNonNull(LocalVariableBinding local);
187
	public abstract boolean isDefinitelyNonNull(VariableBinding binding);
182
188
183
/**
189
/**
184
 * Check status of definite null value for a given local variable.
190
 * Check status of definite null value for a given field or local variable. Note that for fields, this method only
185
 * @param local the variable to ckeck
191
 * takes compile time analysis into account and there's no guarantee of the field being definitely null during runtime
186
 * @return true iff local is definitely null for this flow info
192
 * since it can be modified in some other thread.
193
 * @param binding the field or local to check
194
 * @return true iff field or local is definitely null for this flow info
187
 */
195
 */
188
public abstract boolean isDefinitelyNull(LocalVariableBinding local);
196
public abstract boolean isDefinitelyNull(VariableBinding binding);
189
197
190
/**
198
/**
191
 * Check status of definite unknown value for a given local variable.
199
 * Check status of definite unknown value for a given field or local variable.
192
 * @param local the variable to ckeck
200
 * @param binding the field or local to check
193
 * @return true iff local is definitely unknown for this flow info
201
 * @return true iff field or local is definitely unknown for this flow info
194
 */
202
 */
195
public abstract boolean isDefinitelyUnknown(LocalVariableBinding local);
203
public abstract boolean isDefinitelyUnknown(VariableBinding binding);
196
204
197
	/**
205
	/**
198
	 * Check status of potential assignment for a field.
206
	 * Check status of potential assignment for a field.
Lines 206-264 Link Here
206
	 abstract public boolean isPotentiallyAssigned(LocalVariableBinding field);
214
	 abstract public boolean isPotentiallyAssigned(LocalVariableBinding field);
207
215
208
/**
216
/**
209
 * Check status of potential null assignment for a local. Return true if there
217
 * Check status of potential null assignment for a field or local. Return true if there
210
 * is a reasonable expectation that the variable be non null at this point.
218
 * is a reasonable expectation that the variable be non null at this point.
211
 * @param local LocalVariableBinding - the binding for the checked local
219
 * @param binding VariableBinding - the binding for the checked field or local
212
 * @return true if there is a reasonable expectation that local be non null at
220
 * @return true if there is a reasonable expectation that the field or local be non null at
213
 * this point
221
 * this point
214
 */
222
 */
215
public abstract boolean isPotentiallyNonNull(LocalVariableBinding local);
223
public abstract boolean isPotentiallyNonNull(VariableBinding binding);
216
224
217
/**
225
/**
218
 * Check status of potential null assignment for a local. Return true if there
226
 * Check status of potential null assignment for a field or local. Return true if there
219
 * is a reasonable expectation that the variable be null at this point. This
227
 * is a reasonable expectation that the variable be null at this point. This
220
 * includes the protected null case, so as to augment diagnostics, but does not
228
 * includes the protected null case, so as to augment diagnostics, but does not
221
 * really check that someone deliberately assigned to null on any specific
229
 * really check that someone deliberately assigned to null on any specific
222
 * path
230
 * path
223
 * @param local LocalVariableBinding - the binding for the checked local
231
 * @param binding VariableBinding - the binding for the checked field or local
224
 * @return true if there is a reasonable expectation that local be null at
232
 * @return true if there is a reasonable expectation that the field or local be null at
225
 * this point
233
 * this point
226
 */
234
 */
227
public abstract boolean isPotentiallyNull(LocalVariableBinding local);
235
public abstract boolean isPotentiallyNull(VariableBinding binding);
228
236
229
/**
237
/**
230
 * Return true if the given local may have been assigned to an unknown value.
238
 * Return true if the given field or local may have been assigned to an unknown value.
231
 * @param local the local to check
239
 * @param binding the field or local to check
232
 * @return true if the given local may have been assigned to an unknown value
240
 * @return true if the given field or local may have been assigned to an unknown value
233
 */
241
 */
234
public abstract boolean isPotentiallyUnknown(LocalVariableBinding local);
242
public abstract boolean isPotentiallyUnknown(VariableBinding binding);
235
243
236
/**
244
/**
237
 * Return true if the given local is protected by a test against a non null
245
 * Return true if the given field or local is protected by a test against a non null
238
 * value.
246
 * value.
239
 * @param local the local to check
247
 * @param binding the field or local to check
240
 * @return true if the given local is protected by a test against a non null
248
 * @return true if the given field or local is protected by a test against a non null
241
 */
249
 */
242
public abstract boolean isProtectedNonNull(LocalVariableBinding local);
250
public abstract boolean isProtectedNonNull(VariableBinding binding);
243
251
244
/**
252
/**
245
 * Return true if the given local is protected by a test against null.
253
 * Return true if the given field or local is protected by a test against null.
246
 * @param local the local to check
254
 * @param binding the field or local to check
247
 * @return true if the given local is protected by a test against null
255
 * @return true if the given field or local is protected by a test against null
248
 */
256
 */
249
public abstract boolean isProtectedNull(LocalVariableBinding local);
257
public abstract boolean isProtectedNull(VariableBinding binding);
250
258
251
/**
259
/**
252
 * Record that a local variable got checked to be non null.
260
 * Record that a field or local variable got checked to be non null.
253
 * @param local the checked local variable
261
 * @param binding the checked field or local variable
254
 */
262
 */
255
abstract public void markAsComparedEqualToNonNull(LocalVariableBinding local);
263
abstract public void markAsComparedEqualToNonNull(VariableBinding binding);
256
264
257
/**
265
/**
258
 * Record that a local variable got checked to be null.
266
 * Record that a field or local variable got checked to be null.
259
 * @param local the checked local variable
267
 * @param binding the checked field or local variable
260
 */
268
 */
261
abstract public void markAsComparedEqualToNull(LocalVariableBinding local);
269
abstract public void markAsComparedEqualToNull(VariableBinding binding);
262
270
263
	/**
271
	/**
264
	 * Record a field got definitely assigned.
272
	 * Record a field got definitely assigned.
Lines 266-299 Link Here
266
	abstract public void markAsDefinitelyAssigned(FieldBinding field);
274
	abstract public void markAsDefinitelyAssigned(FieldBinding field);
267
275
268
	/**
276
	/**
269
	 * Record a local got definitely assigned to a non-null value.
277
	 * Record a field or local got definitely assigned to a non-null value.
270
	 */
278
	 */
271
	abstract public void markAsDefinitelyNonNull(LocalVariableBinding local);
279
	abstract public void markAsDefinitelyNonNull(VariableBinding binding);
272
280
273
	/**
281
	/**
274
	 * Record a local got definitely assigned to null.
282
	 * Record a field or local got definitely assigned to null.
275
	 */
283
	 */
276
	abstract public void markAsDefinitelyNull(LocalVariableBinding local);
284
	abstract public void markAsDefinitelyNull(VariableBinding binding);
277
285
278
	/**
286
	/**
279
	 * Reset all null-information about a given local.
287
	 * Reset all null-information about a given field or local.
280
	 */
288
	 */
281
	abstract public void resetNullInfo(LocalVariableBinding local);
289
	abstract public void resetNullInfo(VariableBinding binding);
282
290
283
	/**
291
	/**
284
	 * Record a local may have got assigned to unknown (set the bit on existing info).
292
	 *  variant of {@link #resetNullInfo(VariableBinding)} for resetting null info for all fields
285
	 */
293
	 */
286
	abstract public void markPotentiallyUnknownBit(LocalVariableBinding local);
294
	abstract public void resetNullInfoForFields();
295
	/**
296
	 * Record a field or local may have got assigned to unknown (set the bit on existing info).
297
	 */
298
	abstract public void markPotentiallyUnknownBit(VariableBinding binding);
287
299
288
	/**
300
	/**
289
	 * Record a local may have got assigned to null (set the bit on existing info).
301
	 * Record a field or local may have got assigned to null (set the bit on existing info).
290
	 */
302
	 */
291
	abstract public void markPotentiallyNullBit(LocalVariableBinding local);
303
	abstract public void markPotentiallyNullBit(VariableBinding binding);
292
304
293
	/**
305
	/**
294
	 * Record a local may have got assigned to non-null (set the bit on existing info).
306
	 * Record a field or local may have got assigned to non-null (set the bit on existing info).
295
	 */
307
	 */
296
	abstract public void markPotentiallyNonNullBit(LocalVariableBinding local);
308
	abstract public void markPotentiallyNonNullBit(VariableBinding binding);
297
309
298
	/**
310
	/**
299
	 * Record a local got definitely assigned.
311
	 * Record a local got definitely assigned.
Lines 301-359 Link Here
301
	abstract public void markAsDefinitelyAssigned(LocalVariableBinding local);
313
	abstract public void markAsDefinitelyAssigned(LocalVariableBinding local);
302
314
303
/**
315
/**
304
 * Record a local got definitely assigned to an unknown value.
316
 * Record a field or local got definitely assigned to an unknown value.
305
 */
317
 */
306
abstract public void markAsDefinitelyUnknown(LocalVariableBinding local);
318
abstract public void markAsDefinitelyUnknown(VariableBinding binding);
307
319
308
/**
320
/**
309
 * Mark the null status of the given local according to the given status
321
 * Mark the null status of the given field or local according to the given status
310
 * @param local
322
 * @param binding
311
 * @param nullStatus bitset of FLowInfo.UNKNOWN ... FlowInfo.POTENTIALLY_NON_NULL
323
 * @param nullStatus bitset of FLowInfo.UNKNOWN ... FlowInfo.POTENTIALLY_NON_NULL
312
 */
324
 */
313
public void markNullStatus(LocalVariableBinding local, int nullStatus) {
325
public void markNullStatus(VariableBinding binding, int nullStatus) {
314
	switch(nullStatus) {
326
	switch(nullStatus) {
315
		// definite status?
327
		// definite status?
316
		case FlowInfo.UNKNOWN :
328
		case FlowInfo.UNKNOWN :
317
			markAsDefinitelyUnknown(local);
329
			markAsDefinitelyUnknown(binding);
318
			break;
330
			break;
319
		case FlowInfo.NULL :
331
		case FlowInfo.NULL :
320
			markAsDefinitelyNull(local);
332
			markAsDefinitelyNull(binding);
321
			break;
333
			break;
322
		case FlowInfo.NON_NULL :
334
		case FlowInfo.NON_NULL :
323
			markAsDefinitelyNonNull(local);
335
			markAsDefinitelyNonNull(binding);
324
			break;
336
			break;
325
		default:
337
		default:
326
			// collect potential status:
338
			// collect potential status:
327
			resetNullInfo(local);
339
			resetNullInfo(binding);
328
			if ((nullStatus & FlowInfo.POTENTIALLY_UNKNOWN) != 0)
340
			if ((nullStatus & FlowInfo.POTENTIALLY_UNKNOWN) != 0)
329
				markPotentiallyUnknownBit(local);
341
				markPotentiallyUnknownBit(binding);
330
			if ((nullStatus & FlowInfo.POTENTIALLY_NULL) != 0)
342
			if ((nullStatus & FlowInfo.POTENTIALLY_NULL) != 0)
331
				markPotentiallyNullBit(local);
343
				markPotentiallyNullBit(binding);
332
			if ((nullStatus & FlowInfo.POTENTIALLY_NON_NULL) != 0)
344
			if ((nullStatus & FlowInfo.POTENTIALLY_NON_NULL) != 0)
333
				markPotentiallyNonNullBit(local);
345
				markPotentiallyNonNullBit(binding);
334
			if ((nullStatus & (FlowInfo.POTENTIALLY_NULL|FlowInfo.POTENTIALLY_NON_NULL|FlowInfo.POTENTIALLY_UNKNOWN)) == 0)
346
			if ((nullStatus & (FlowInfo.POTENTIALLY_NULL|FlowInfo.POTENTIALLY_NON_NULL|FlowInfo.POTENTIALLY_UNKNOWN)) == 0)
335
				markAsDefinitelyUnknown(local);
347
				markAsDefinitelyUnknown(binding);
336
	}
348
	}
337
}
349
}
338
350
339
/**
351
/**
340
 * Answer the null status of the given local
352
 * Answer the null status of the given field or local
341
 * @param local
353
 * @param binding
342
 * @return bitset of FlowInfo.UNKNOWN ... FlowInfo.POTENTIALLY_NON_NULL
354
 * @return bitset of FlowInfo.UNKNOWN ... FlowInfo.POTENTIALLY_NON_NULL
343
 */
355
 */
344
public int nullStatus(LocalVariableBinding local) {
356
public int nullStatus(VariableBinding binding) {
345
	if (isDefinitelyUnknown(local))
357
	if (isDefinitelyUnknown(binding))
346
		return FlowInfo.UNKNOWN;
358
		return FlowInfo.UNKNOWN;
347
	if (isDefinitelyNull(local))
359
	if (isDefinitelyNull(binding))
348
		return FlowInfo.NULL;
360
		return FlowInfo.NULL;
349
	if (isDefinitelyNonNull(local))
361
	if (isDefinitelyNonNull(binding))
350
		return FlowInfo.NON_NULL;
362
		return FlowInfo.NON_NULL;
351
	int status = 0;
363
	int status = 0;
352
	if (isPotentiallyUnknown(local))
364
	if (isPotentiallyUnknown(binding))
353
		status |= FlowInfo.POTENTIALLY_UNKNOWN;
365
		status |= FlowInfo.POTENTIALLY_UNKNOWN;
354
	if (isPotentiallyNull(local))
366
	if (isPotentiallyNull(binding))
355
		status |= FlowInfo.POTENTIALLY_NULL;
367
		status |= FlowInfo.POTENTIALLY_NULL;
356
	if (isPotentiallyNonNull(local))
368
	if (isPotentiallyNonNull(binding))
357
		status |= FlowInfo.POTENTIALLY_NON_NULL;
369
		status |= FlowInfo.POTENTIALLY_NON_NULL;
358
	if (status > 0)
370
	if (status > 0)
359
		return status;
371
		return status;
Lines 601-614 Link Here
601
 * where this variable is being checked against null
613
 * where this variable is being checked against null
602
 */
614
 */
603
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=303448
615
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=303448
604
abstract public void markedAsNullOrNonNullInAssertExpression(LocalVariableBinding local);
616
abstract public void markedAsNullOrNonNullInAssertExpression(VariableBinding binding);
605
617
606
/** 
618
/** 
607
 * Returns true if the local variable being checked for was marked as null or not null
619
 * Returns true if the local variable being checked for was marked as null or not null
608
 * inside an assert expression due to comparison against null.
620
 * inside an assert expression due to comparison against null.
609
 */
621
 */
610
//https://bugs.eclipse.org/bugs/show_bug.cgi?id=303448
622
//https://bugs.eclipse.org/bugs/show_bug.cgi?id=303448
611
abstract public boolean isMarkedAsNullOrNonNullInAssertExpression(LocalVariableBinding local);
623
abstract public boolean isMarkedAsNullOrNonNullInAssertExpression(VariableBinding binding);
612
624
613
/**
625
/**
614
 * Resets the definite and potential initialization info for the given local variable
626
 * Resets the definite and potential initialization info for the given local variable
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/LoopingFlowContext.java (-51 / +51 lines)
Lines 45-51 Link Here
45
	VariableBinding finalVariables[];
45
	VariableBinding finalVariables[];
46
	int assignCount = 0;
46
	int assignCount = 0;
47
47
48
	LocalVariableBinding[] nullLocals;
48
	VariableBinding[] nullVariables;
49
	Expression[] nullReferences;
49
	Expression[] nullReferences;
50
	int[] nullCheckTypes;
50
	int[] nullCheckTypes;
51
	int nullCount;
51
	int nullCount;
Lines 141-147 Link Here
141
	if ((this.tagBits & FlowContext.DEFER_NULL_DIAGNOSTIC) != 0) {
141
	if ((this.tagBits & FlowContext.DEFER_NULL_DIAGNOSTIC) != 0) {
142
		// check only immutable null checks on innermost looping context
142
		// check only immutable null checks on innermost looping context
143
		for (int i = 0; i < this.nullCount; i++) {
143
		for (int i = 0; i < this.nullCount; i++) {
144
			LocalVariableBinding local = this.nullLocals[i];
144
			VariableBinding local = this.nullVariables[i];
145
			Expression expression = this.nullReferences[i];
145
			Expression expression = this.nullReferences[i];
146
			// final local variable
146
			// final local variable
147
			switch (this.nullCheckTypes[i]) {
147
			switch (this.nullCheckTypes[i]) {
Lines 151-161 Link Here
151
						this.nullReferences[i] = null;
151
						this.nullReferences[i] = null;
152
						if (this.nullCheckTypes[i] == (CAN_ONLY_NON_NULL | IN_COMPARISON_NON_NULL)) {
152
						if (this.nullCheckTypes[i] == (CAN_ONLY_NON_NULL | IN_COMPARISON_NON_NULL)) {
153
							if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
153
							if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
154
								scope.problemReporter().localVariableRedundantCheckOnNonNull(local, expression);
154
								scope.problemReporter().variableRedundantCheckOnNonNull(local, expression);
155
							}
155
							}
156
						} else {
156
						} else {
157
							if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
157
							if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
158
								scope.problemReporter().localVariableNonNullComparedToNull(local, expression);
158
								scope.problemReporter().variableNonNullComparedToNull(local, expression);
159
							}
159
							}
160
						}
160
						}
161
						continue;
161
						continue;
Lines 167-177 Link Here
167
						this.nullReferences[i] = null;
167
						this.nullReferences[i] = null;
168
						if (this.nullCheckTypes[i] == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL)) {
168
						if (this.nullCheckTypes[i] == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL)) {
169
							if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
169
							if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
170
								scope.problemReporter().localVariableRedundantCheckOnNonNull(local, expression);
170
								scope.problemReporter().variableRedundantCheckOnNonNull(local, expression);
171
							}
171
							}
172
						} else {
172
						} else {
173
							if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
173
							if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
174
								scope.problemReporter().localVariableNonNullComparedToNull(local, expression);
174
								scope.problemReporter().variableNonNullComparedToNull(local, expression);
175
							}
175
							}
176
						}
176
						}
177
						continue;
177
						continue;
Lines 180-190 Link Here
180
						this.nullReferences[i] = null;
180
						this.nullReferences[i] = null;
181
						if (this.nullCheckTypes[i] == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NULL)) {
181
						if (this.nullCheckTypes[i] == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NULL)) {
182
							if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
182
							if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
183
								scope.problemReporter().localVariableRedundantCheckOnNull(local, expression);
183
								scope.problemReporter().variableRedundantCheckOnNull(local, expression);
184
							}
184
							}
185
						} else {
185
						} else {
186
							if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
186
							if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
187
								scope.problemReporter().localVariableNullComparedToNonNull(local, expression);
187
								scope.problemReporter().variableNullComparedToNonNull(local, expression);
188
							}
188
							}
189
						}
189
						}
190
						continue;
190
						continue;
Lines 199-225 Link Here
199
						switch(this.nullCheckTypes[i] & CONTEXT_MASK) {
199
						switch(this.nullCheckTypes[i] & CONTEXT_MASK) {
200
							case FlowContext.IN_COMPARISON_NULL:
200
							case FlowContext.IN_COMPARISON_NULL:
201
								if (((this.nullCheckTypes[i] & CHECK_MASK) == CAN_ONLY_NULL) && (expression.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
201
								if (((this.nullCheckTypes[i] & CHECK_MASK) == CAN_ONLY_NULL) && (expression.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
202
									scope.problemReporter().localVariableNullReference(local, expression);
202
									scope.problemReporter().variableNullReference(local, expression);
203
									continue;
203
									continue;
204
								}
204
								}
205
								if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
205
								if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
206
									scope.problemReporter().localVariableRedundantCheckOnNull(local, expression);
206
									scope.problemReporter().variableRedundantCheckOnNull(local, expression);
207
								}
207
								}
208
								continue;
208
								continue;
209
							case FlowContext.IN_COMPARISON_NON_NULL:
209
							case FlowContext.IN_COMPARISON_NON_NULL:
210
								if (((this.nullCheckTypes[i] & CHECK_MASK) == CAN_ONLY_NULL) && (expression.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
210
								if (((this.nullCheckTypes[i] & CHECK_MASK) == CAN_ONLY_NULL) && (expression.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
211
									scope.problemReporter().localVariableNullReference(local, expression);
211
									scope.problemReporter().variableNullReference(local, expression);
212
									continue;
212
									continue;
213
								}
213
								}
214
								if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
214
								if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
215
									scope.problemReporter().localVariableNullComparedToNonNull(local, expression);
215
									scope.problemReporter().variableNullComparedToNonNull(local, expression);
216
								}
216
								}
217
								continue;
217
								continue;
218
							case FlowContext.IN_ASSIGNMENT:
218
							case FlowContext.IN_ASSIGNMENT:
219
								scope.problemReporter().localVariableRedundantNullAssignment(local, expression);
219
								scope.problemReporter().variableRedundantNullAssignment(local, expression);
220
								continue;
220
								continue;
221
							case FlowContext.IN_INSTANCEOF:
221
							case FlowContext.IN_INSTANCEOF:
222
								scope.problemReporter().localVariableNullInstanceof(local, expression);
222
								scope.problemReporter().variableNullInstanceof(local, expression);
223
								continue;
223
								continue;
224
						}
224
						}
225
					} else if (flowInfo.isPotentiallyNull(local)) {
225
					} else if (flowInfo.isPotentiallyNull(local)) {
Lines 227-240 Link Here
227
							case FlowContext.IN_COMPARISON_NULL:
227
							case FlowContext.IN_COMPARISON_NULL:
228
								this.nullReferences[i] = null;
228
								this.nullReferences[i] = null;
229
								if (((this.nullCheckTypes[i] & CHECK_MASK) == CAN_ONLY_NULL) && (expression.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
229
								if (((this.nullCheckTypes[i] & CHECK_MASK) == CAN_ONLY_NULL) && (expression.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
230
									scope.problemReporter().localVariablePotentialNullReference(local, expression);
230
									scope.problemReporter().variablePotentialNullReference(local, expression);
231
									continue;
231
									continue;
232
								}
232
								}
233
								break;
233
								break;
234
							case FlowContext.IN_COMPARISON_NON_NULL:
234
							case FlowContext.IN_COMPARISON_NON_NULL:
235
								this.nullReferences[i] = null;
235
								this.nullReferences[i] = null;
236
								if (((this.nullCheckTypes[i] & CHECK_MASK) == CAN_ONLY_NULL) && (expression.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
236
								if (((this.nullCheckTypes[i] & CHECK_MASK) == CAN_ONLY_NULL) && (expression.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
237
									scope.problemReporter().localVariablePotentialNullReference(local, expression);
237
									scope.problemReporter().variablePotentialNullReference(local, expression);
238
									continue;
238
									continue;
239
								}
239
								}
240
								break;
240
								break;
Lines 244-250 Link Here
244
				case MAY_NULL:
244
				case MAY_NULL:
245
					if (flowInfo.isDefinitelyNull(local)) {
245
					if (flowInfo.isDefinitelyNull(local)) {
246
						this.nullReferences[i] = null;
246
						this.nullReferences[i] = null;
247
						scope.problemReporter().localVariableNullReference(local, expression);
247
						scope.problemReporter().variableNullReference(local, expression);
248
						continue;
248
						continue;
249
					}
249
					}
250
					break;
250
					break;
Lines 263-269 Link Here
263
		for (int i = 0; i < this.nullCount; i++) {
263
		for (int i = 0; i < this.nullCount; i++) {
264
			Expression expression = this.nullReferences[i];
264
			Expression expression = this.nullReferences[i];
265
			// final local variable
265
			// final local variable
266
			LocalVariableBinding local = this.nullLocals[i];
266
			VariableBinding local = this.nullVariables[i];
267
			switch (this.nullCheckTypes[i]) {
267
			switch (this.nullCheckTypes[i]) {
268
				case CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NULL:
268
				case CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NULL:
269
				case CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL:
269
				case CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL:
Lines 271-281 Link Here
271
						this.nullReferences[i] = null;
271
						this.nullReferences[i] = null;
272
						if (this.nullCheckTypes[i] == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL)) {
272
						if (this.nullCheckTypes[i] == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL)) {
273
							if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
273
							if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
274
								scope.problemReporter().localVariableRedundantCheckOnNonNull(local, expression);
274
								scope.problemReporter().variableRedundantCheckOnNonNull(local, expression);
275
							}
275
							}
276
						} else {
276
						} else {
277
							if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
277
							if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
278
								scope.problemReporter().localVariableNonNullComparedToNull(local, expression);
278
								scope.problemReporter().variableNonNullComparedToNull(local, expression);
279
							}
279
							}
280
						}
280
						}
281
						continue;
281
						continue;
Lines 290-316 Link Here
290
						switch(this.nullCheckTypes[i] & CONTEXT_MASK) {
290
						switch(this.nullCheckTypes[i] & CONTEXT_MASK) {
291
							case FlowContext.IN_COMPARISON_NULL:
291
							case FlowContext.IN_COMPARISON_NULL:
292
								if (((this.nullCheckTypes[i] & CHECK_MASK) == CAN_ONLY_NULL) && (expression.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
292
								if (((this.nullCheckTypes[i] & CHECK_MASK) == CAN_ONLY_NULL) && (expression.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
293
									scope.problemReporter().localVariableNullReference(local, expression);
293
									scope.problemReporter().variableNullReference(local, expression);
294
									continue;
294
									continue;
295
								}
295
								}
296
								if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
296
								if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
297
									scope.problemReporter().localVariableRedundantCheckOnNull(local, expression);
297
									scope.problemReporter().variableRedundantCheckOnNull(local, expression);
298
								}
298
								}
299
								continue;
299
								continue;
300
							case FlowContext.IN_COMPARISON_NON_NULL:
300
							case FlowContext.IN_COMPARISON_NON_NULL:
301
								if (((this.nullCheckTypes[i] & CHECK_MASK) == CAN_ONLY_NULL) && (expression.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
301
								if (((this.nullCheckTypes[i] & CHECK_MASK) == CAN_ONLY_NULL) && (expression.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
302
									scope.problemReporter().localVariableNullReference(local, expression);
302
									scope.problemReporter().variableNullReference(local, expression);
303
									continue;
303
									continue;
304
								}
304
								}
305
								if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
305
								if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
306
									scope.problemReporter().localVariableNullComparedToNonNull(local, expression);
306
									scope.problemReporter().variableNullComparedToNonNull(local, expression);
307
								}
307
								}
308
								continue;
308
								continue;
309
							case FlowContext.IN_ASSIGNMENT:
309
							case FlowContext.IN_ASSIGNMENT:
310
								scope.problemReporter().localVariableRedundantNullAssignment(local, expression);
310
								scope.problemReporter().variableRedundantNullAssignment(local, expression);
311
								continue;
311
								continue;
312
							case FlowContext.IN_INSTANCEOF:
312
							case FlowContext.IN_INSTANCEOF:
313
								scope.problemReporter().localVariableNullInstanceof(local, expression);
313
								scope.problemReporter().variableNullInstanceof(local, expression);
314
								continue;
314
								continue;
315
						}
315
						}
316
					} else if (flowInfo.isPotentiallyNull(local)) {
316
					} else if (flowInfo.isPotentiallyNull(local)) {
Lines 318-331 Link Here
318
							case FlowContext.IN_COMPARISON_NULL:
318
							case FlowContext.IN_COMPARISON_NULL:
319
								this.nullReferences[i] = null;
319
								this.nullReferences[i] = null;
320
								if (((this.nullCheckTypes[i] & CHECK_MASK) == CAN_ONLY_NULL) && (expression.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
320
								if (((this.nullCheckTypes[i] & CHECK_MASK) == CAN_ONLY_NULL) && (expression.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
321
									scope.problemReporter().localVariablePotentialNullReference(local, expression);
321
									scope.problemReporter().variablePotentialNullReference(local, expression);
322
									continue;
322
									continue;
323
								}
323
								}
324
								break;
324
								break;
325
							case FlowContext.IN_COMPARISON_NON_NULL:
325
							case FlowContext.IN_COMPARISON_NON_NULL:
326
								this.nullReferences[i] = null;
326
								this.nullReferences[i] = null;
327
								if (((this.nullCheckTypes[i] & CHECK_MASK) == CAN_ONLY_NULL) && (expression.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
327
								if (((this.nullCheckTypes[i] & CHECK_MASK) == CAN_ONLY_NULL) && (expression.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
328
									scope.problemReporter().localVariablePotentialNullReference(local, expression);
328
									scope.problemReporter().variablePotentialNullReference(local, expression);
329
									continue;
329
									continue;
330
								}
330
								}
331
								break;
331
								break;
Lines 335-346 Link Here
335
				case MAY_NULL:
335
				case MAY_NULL:
336
					if (flowInfo.isDefinitelyNull(local)) {
336
					if (flowInfo.isDefinitelyNull(local)) {
337
						this.nullReferences[i] = null;
337
						this.nullReferences[i] = null;
338
						scope.problemReporter().localVariableNullReference(local, expression);
338
						scope.problemReporter().variableNullReference(local, expression);
339
						continue;
339
						continue;
340
					}
340
					}
341
					if (flowInfo.isPotentiallyNull(local)) {
341
					if (flowInfo.isPotentiallyNull(local)) {
342
						this.nullReferences[i] = null;
342
						this.nullReferences[i] = null;
343
						scope.problemReporter().localVariablePotentialNullReference(local, expression);
343
						scope.problemReporter().variablePotentialNullReference(local, expression);
344
						continue;
344
						continue;
345
					}
345
					}
346
					break;
346
					break;
Lines 472-498 Link Here
472
		return true;
472
		return true;
473
	}
473
	}
474
474
475
protected void recordNullReference(LocalVariableBinding local,
475
protected void recordNullReference(VariableBinding local,
476
	Expression expression, int status) {
476
	Expression expression, int status) {
477
	if (this.nullCount == 0) {
477
	if (this.nullCount == 0) {
478
		this.nullLocals = new LocalVariableBinding[5];
478
		this.nullVariables = new VariableBinding[5];
479
		this.nullReferences = new Expression[5];
479
		this.nullReferences = new Expression[5];
480
		this.nullCheckTypes = new int[5];
480
		this.nullCheckTypes = new int[5];
481
	}
481
	}
482
	else if (this.nullCount == this.nullLocals.length) {
482
	else if (this.nullCount == this.nullVariables.length) {
483
		System.arraycopy(this.nullLocals, 0,
483
		System.arraycopy(this.nullVariables, 0,
484
			this.nullLocals = new LocalVariableBinding[this.nullCount * 2], 0, this.nullCount);
484
			this.nullVariables = new VariableBinding[this.nullCount * 2], 0, this.nullCount);
485
		System.arraycopy(this.nullReferences, 0,
485
		System.arraycopy(this.nullReferences, 0,
486
			this.nullReferences = new Expression[this.nullCount * 2], 0, this.nullCount);
486
			this.nullReferences = new Expression[this.nullCount * 2], 0, this.nullCount);
487
		System.arraycopy(this.nullCheckTypes, 0,
487
		System.arraycopy(this.nullCheckTypes, 0,
488
			this.nullCheckTypes = new int[this.nullCount * 2], 0, this.nullCount);
488
			this.nullCheckTypes = new int[this.nullCount * 2], 0, this.nullCount);
489
	}
489
	}
490
	this.nullLocals[this.nullCount] = local;
490
	this.nullVariables[this.nullCount] = local;
491
	this.nullReferences[this.nullCount] = expression;
491
	this.nullReferences[this.nullCount] = expression;
492
	this.nullCheckTypes[this.nullCount++] = status;
492
	this.nullCheckTypes[this.nullCount++] = status;
493
}
493
}
494
494
495
public void recordUsingNullReference(Scope scope, LocalVariableBinding local,
495
public void recordUsingNullReference(Scope scope, VariableBinding local,
496
		Expression reference, int checkType, FlowInfo flowInfo) {
496
		Expression reference, int checkType, FlowInfo flowInfo) {
497
	if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) != 0 ||
497
	if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) != 0 ||
498
			flowInfo.isDefinitelyUnknown(local)) {
498
			flowInfo.isDefinitelyUnknown(local)) {
Lines 504-517 Link Here
504
			if (flowInfo.isDefinitelyNonNull(local)) {
504
			if (flowInfo.isDefinitelyNonNull(local)) {
505
				if (checkType == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL)) {
505
				if (checkType == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL)) {
506
					if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
506
					if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
507
						scope.problemReporter().localVariableRedundantCheckOnNonNull(local, reference);
507
						scope.problemReporter().variableRedundantCheckOnNonNull(local, reference);
508
					}
508
					}
509
					if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) {
509
					if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) {
510
						flowInfo.initsWhenFalse().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
510
						flowInfo.initsWhenFalse().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
511
					}
511
					}
512
				} else {
512
				} else {
513
					if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
513
					if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
514
						scope.problemReporter().localVariableNonNullComparedToNull(local, reference);
514
						scope.problemReporter().variableNonNullComparedToNull(local, reference);
515
					}
515
					}
516
					if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) {
516
					if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) {
517
						flowInfo.initsWhenTrue().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
517
						flowInfo.initsWhenTrue().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
Lines 520-533 Link Here
520
			} else if (flowInfo.isDefinitelyNull(local)) {
520
			} else if (flowInfo.isDefinitelyNull(local)) {
521
				if (checkType == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NULL)) {
521
				if (checkType == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NULL)) {
522
					if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
522
					if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
523
						scope.problemReporter().localVariableRedundantCheckOnNull(local, reference);
523
						scope.problemReporter().variableRedundantCheckOnNull(local, reference);
524
					}
524
					}
525
					if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) {
525
					if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) {
526
						flowInfo.initsWhenFalse().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
526
						flowInfo.initsWhenFalse().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
527
					}
527
					}
528
				} else {
528
				} else {
529
					if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
529
					if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
530
						scope.problemReporter().localVariableNullComparedToNonNull(local, reference);
530
						scope.problemReporter().variableNullComparedToNonNull(local, reference);
531
					}
531
					}
532
					if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) {
532
					if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) {
533
						flowInfo.initsWhenTrue().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
533
						flowInfo.initsWhenTrue().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
Lines 571-581 Link Here
571
				switch(checkType & CONTEXT_MASK) {
571
				switch(checkType & CONTEXT_MASK) {
572
					case FlowContext.IN_COMPARISON_NULL:
572
					case FlowContext.IN_COMPARISON_NULL:
573
						if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
573
						if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
574
							scope.problemReporter().localVariableNullReference(local, reference);
574
							scope.problemReporter().variableNullReference(local, reference);
575
							return;
575
							return;
576
						}
576
						}
577
						if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
577
						if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
578
							scope.problemReporter().localVariableRedundantCheckOnNull(local, reference);
578
							scope.problemReporter().variableRedundantCheckOnNull(local, reference);
579
						}
579
						}
580
						if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) {
580
						if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) {
581
							flowInfo.initsWhenFalse().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
581
							flowInfo.initsWhenFalse().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
Lines 583-616 Link Here
583
						return;
583
						return;
584
					case FlowContext.IN_COMPARISON_NON_NULL:
584
					case FlowContext.IN_COMPARISON_NON_NULL:
585
						if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
585
						if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
586
							scope.problemReporter().localVariableNullReference(local, reference);
586
							scope.problemReporter().variableNullReference(local, reference);
587
							return;
587
							return;
588
						}
588
						}
589
						if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
589
						if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
590
							scope.problemReporter().localVariableNullComparedToNonNull(local, reference);
590
							scope.problemReporter().variableNullComparedToNonNull(local, reference);
591
						}
591
						}
592
						if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) {
592
						if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) {
593
							flowInfo.initsWhenTrue().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
593
							flowInfo.initsWhenTrue().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
594
						}
594
						}
595
						return;
595
						return;
596
					case FlowContext.IN_ASSIGNMENT:
596
					case FlowContext.IN_ASSIGNMENT:
597
						scope.problemReporter().localVariableRedundantNullAssignment(local, reference);
597
						scope.problemReporter().variableRedundantNullAssignment(local, reference);
598
						return;
598
						return;
599
					case FlowContext.IN_INSTANCEOF:
599
					case FlowContext.IN_INSTANCEOF:
600
						scope.problemReporter().localVariableNullInstanceof(local, reference);
600
						scope.problemReporter().variableNullInstanceof(local, reference);
601
						return;
601
						return;
602
				}
602
				}
603
			} else if (flowInfo.isPotentiallyNull(local)) {
603
			} else if (flowInfo.isPotentiallyNull(local)) {
604
				switch(checkType & CONTEXT_MASK) {
604
				switch(checkType & CONTEXT_MASK) {
605
					case FlowContext.IN_COMPARISON_NULL:
605
					case FlowContext.IN_COMPARISON_NULL:
606
						if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
606
						if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
607
							scope.problemReporter().localVariablePotentialNullReference(local, reference);
607
							scope.problemReporter().variablePotentialNullReference(local, reference);
608
							return;
608
							return;
609
						}
609
						}
610
						break;
610
						break;
611
					case FlowContext.IN_COMPARISON_NON_NULL:
611
					case FlowContext.IN_COMPARISON_NON_NULL:
612
						if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
612
						if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
613
							scope.problemReporter().localVariablePotentialNullReference(local, reference);
613
							scope.problemReporter().variablePotentialNullReference(local, reference);
614
							return;
614
							return;
615
						}
615
						}
616
						break;
616
						break;
Lines 629-639 Link Here
629
				return;
629
				return;
630
			}
630
			}
631
			if (flowInfo.isDefinitelyNull(local)) {
631
			if (flowInfo.isDefinitelyNull(local)) {
632
				scope.problemReporter().localVariableNullReference(local, reference);
632
				scope.problemReporter().variableNullReference(local, reference);
633
				return;
633
				return;
634
			}
634
			}
635
			if (flowInfo.isPotentiallyNull(local)) {
635
			if (flowInfo.isPotentiallyNull(local)) {
636
				scope.problemReporter().localVariablePotentialNullReference(local, reference);
636
				scope.problemReporter().variablePotentialNullReference(local, reference);
637
				return;
637
				return;
638
			}
638
			}
639
			recordNullReference(local, reference, checkType);
639
			recordNullReference(local, reference, checkType);
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/NullInfoRegistry.java (-15 / +51 lines)
Lines 11-17 Link Here
11
 *******************************************************************************/
11
 *******************************************************************************/
12
package org.eclipse.jdt.internal.compiler.flow;
12
package org.eclipse.jdt.internal.compiler.flow;
13
13
14
import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
14
import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
15
import org.eclipse.jdt.internal.compiler.lookup.VariableBinding;
15
16
16
/**
17
/**
17
 * A degenerate form of UnconditionalFlowInfo explicitly meant to capture
18
 * A degenerate form of UnconditionalFlowInfo explicitly meant to capture
Lines 116-128 Link Here
116
	return this;
117
	return this;
117
}
118
}
118
119
119
public void markAsComparedEqualToNonNull(LocalVariableBinding local) {
120
public void markAsComparedEqualToNonNull(VariableBinding local) {
120
	// protected from non-object locals in calling methods
121
	// protected from non-object locals in calling methods
121
	if (this != DEAD_END) {
122
	if (this != DEAD_END) {
122
    	this.tagBits |= NULL_FLAG_MASK;
123
    	this.tagBits |= NULL_FLAG_MASK;
123
    	int position;
124
    	int position;
125
    	if (local instanceof FieldBinding) {
126
			position = local.id;
127
		} else {
128
			position = local.id + this.maxFieldCount;
129
		}
124
    	// position is zero-based
130
    	// position is zero-based
125
    	if ((position = local.id + this.maxFieldCount) < BitCacheSize) { // use bits
131
    	if (position < BitCacheSize) { // use bits
126
    		// set protected non null
132
    		// set protected non null
127
    		this.nullBit1 |= (1L << position);
133
    		this.nullBit1 |= (1L << position);
128
    		if (COVERAGE_TEST_FLAG) {
134
    		if (COVERAGE_TEST_FLAG) {
Lines 161-173 Link Here
161
	}
167
	}
162
}
168
}
163
169
164
public void markAsDefinitelyNonNull(LocalVariableBinding local) {
170
public void markAsDefinitelyNonNull(VariableBinding local) {
165
	// protected from non-object locals in calling methods
171
	// protected from non-object locals in calling methods
166
	if (this != DEAD_END) {
172
	if (this != DEAD_END) {
167
    	this.tagBits |= NULL_FLAG_MASK;
173
    	this.tagBits |= NULL_FLAG_MASK;
168
    	int position;
174
    	int position;
169
    	// position is zero-based
175
    	// position is zero-based
170
    	if ((position = local.id + this.maxFieldCount) < BitCacheSize) { // use bits
176
    	if (local instanceof FieldBinding) {
177
    		position = local.id;
178
    	} else {
179
    		position = local.id + this.maxFieldCount;
180
    	}
181
    	if (position < BitCacheSize) { // use bits
171
    		// set assigned non null
182
    		// set assigned non null
172
    		this.nullBit3 |= (1L << position);
183
    		this.nullBit3 |= (1L << position);
173
    		if (COVERAGE_TEST_FLAG) {
184
    		if (COVERAGE_TEST_FLAG) {
Lines 207-219 Link Here
207
}
218
}
208
// PREMATURE consider ignoring extra 0 to 2 included - means a1 should not be used either
219
// PREMATURE consider ignoring extra 0 to 2 included - means a1 should not be used either
209
// PREMATURE project protected non null onto something else
220
// PREMATURE project protected non null onto something else
210
public void markAsDefinitelyNull(LocalVariableBinding local) {
221
public void markAsDefinitelyNull(VariableBinding local) {
211
	// protected from non-object locals in calling methods
222
	// protected from non-object locals in calling methods
212
	if (this != DEAD_END) {
223
	if (this != DEAD_END) {
213
    	this.tagBits |= NULL_FLAG_MASK;
224
    	this.tagBits |= NULL_FLAG_MASK;
214
    	int position;
225
    	int position;
226
    	if (local instanceof FieldBinding) {
227
    		position = local.id;
228
    	} else {
229
    		position = local.id + this.maxFieldCount;
230
    	}
215
    	// position is zero-based
231
    	// position is zero-based
216
    	if ((position = local.id + this.maxFieldCount) < BitCacheSize) { // use bits
232
    	if (position < BitCacheSize) { // use bits
217
    		// set assigned null
233
    		// set assigned null
218
    		this.nullBit2 |= (1L << position);
234
    		this.nullBit2 |= (1L << position);
219
    		if (COVERAGE_TEST_FLAG) {
235
    		if (COVERAGE_TEST_FLAG) {
Lines 252-264 Link Here
252
	}
268
	}
253
}
269
}
254
270
255
public void markAsDefinitelyUnknown(LocalVariableBinding local) {
271
public void markAsDefinitelyUnknown(VariableBinding local) {
256
	// protected from non-object locals in calling methods
272
	// protected from non-object locals in calling methods
257
	if (this != DEAD_END) {
273
	if (this != DEAD_END) {
258
    	this.tagBits |= NULL_FLAG_MASK;
274
    	this.tagBits |= NULL_FLAG_MASK;
259
    	int position;
275
    	int position;
276
    	if (local instanceof FieldBinding) {
277
    		position = local.id;
278
    	} else {
279
    		position = local.id + this.maxFieldCount;
280
    	}
260
    	// position is zero-based
281
    	// position is zero-based
261
    	if ((position = local.id + this.maxFieldCount) < BitCacheSize) { // use bits
282
    	if (position < BitCacheSize) { // use bits
262
    		// set assigned unknown
283
    		// set assigned unknown
263
    		this.nullBit4 |= (1L << position);
284
    		this.nullBit4 |= (1L << position);
264
    		if (COVERAGE_TEST_FLAG) {
285
    		if (COVERAGE_TEST_FLAG) {
Lines 407-419 Link Here
407
 * Mark a local as potentially having been assigned to an unknown value.
428
 * Mark a local as potentially having been assigned to an unknown value.
408
 * @param local the local to mark
429
 * @param local the local to mark
409
 */
430
 */
410
public void markPotentiallyUnknownBit(LocalVariableBinding local) {
431
public void markPotentiallyUnknownBit(VariableBinding local) {
411
	// protected from non-object locals in calling methods
432
	// protected from non-object locals in calling methods
412
	if (this != DEAD_END) {
433
	if (this != DEAD_END) {
413
		this.tagBits |= NULL_FLAG_MASK;
434
		this.tagBits |= NULL_FLAG_MASK;
414
        int position;
435
        int position;
415
        long mask;
436
        long mask;
416
        if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
437
        if (local instanceof FieldBinding) {
438
        	position = local.id;
439
        } else {
440
        	position = local.id + this.maxFieldCount;
441
        }
442
        if (position < BitCacheSize) {
417
            // use bits
443
            // use bits
418
        	mask = 1L << position;
444
        	mask = 1L << position;
419
        	isTrue((this.nullBit1 & mask) == 0, "Adding 'unknown' mark in unexpected state"); //$NON-NLS-1$
445
        	isTrue((this.nullBit1 & mask) == 0, "Adding 'unknown' mark in unexpected state"); //$NON-NLS-1$
Lines 454-465 Link Here
454
	}
480
	}
455
}
481
}
456
482
457
public void markPotentiallyNullBit(LocalVariableBinding local) {
483
public void markPotentiallyNullBit(VariableBinding local) {
458
	if (this != DEAD_END) {
484
	if (this != DEAD_END) {
459
		this.tagBits |= NULL_FLAG_MASK;
485
		this.tagBits |= NULL_FLAG_MASK;
460
        int position;
486
        int position;
461
        long mask;
487
        long mask;
462
        if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
488
        if (local instanceof FieldBinding) {
489
        	position = local.id;
490
        } else {
491
        	position = local.id + this.maxFieldCount;
492
        }
493
        if (position < BitCacheSize) {
463
            // use bits
494
            // use bits
464
        	mask = 1L << position;
495
        	mask = 1L << position;
465
        	isTrue((this.nullBit1 & mask) == 0, "Adding 'potentially null' mark in unexpected state"); //$NON-NLS-1$
496
        	isTrue((this.nullBit1 & mask) == 0, "Adding 'potentially null' mark in unexpected state"); //$NON-NLS-1$
Lines 500-511 Link Here
500
	}
531
	}
501
}
532
}
502
533
503
public void markPotentiallyNonNullBit(LocalVariableBinding local) {
534
public void markPotentiallyNonNullBit(VariableBinding local) {
504
	if (this != DEAD_END) {
535
	if (this != DEAD_END) {
505
		this.tagBits |= NULL_FLAG_MASK;
536
		this.tagBits |= NULL_FLAG_MASK;
506
        int position;
537
        int position;
507
        long mask;
538
        long mask;
508
        if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
539
        if (local instanceof FieldBinding) {
540
        	position = local.id;
541
        } else {
542
        	position = local.id + this.maxFieldCount;
543
        }
544
        if (position < BitCacheSize) {
509
            // use bits
545
            // use bits
510
        	mask = 1L << position;
546
        	mask = 1L << position;
511
        	isTrue((this.nullBit1 & mask) == 0, "Adding 'potentially non-null' mark in unexpected state"); //$NON-NLS-1$
547
        	isTrue((this.nullBit1 & mask) == 0, "Adding 'potentially non-null' mark in unexpected state"); //$NON-NLS-1$
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java (-45 / +215 lines)
Lines 23-28 Link Here
23
import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
23
import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
24
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
24
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
25
import org.eclipse.jdt.internal.compiler.lookup.TagBits;
25
import org.eclipse.jdt.internal.compiler.lookup.TagBits;
26
import org.eclipse.jdt.internal.compiler.lookup.VariableBinding;
26
27
27
/**
28
/**
28
 * Record initialization status during definite assignment analysis
29
 * Record initialization status during definite assignment analysis
Lines 520-532 Link Here
520
	return this;
521
	return this;
521
}
522
}
522
523
523
final public boolean cannotBeDefinitelyNullOrNonNull(LocalVariableBinding local) {
524
final public boolean cannotBeDefinitelyNullOrNonNull(VariableBinding local) {
524
	if ((this.tagBits & NULL_FLAG_MASK) == 0 ||
525
	if ((this.tagBits & NULL_FLAG_MASK) == 0 ||
525
			(local.type.tagBits & TagBits.IsBaseType) != 0) {
526
			(local.type.tagBits & TagBits.IsBaseType) != 0) {
526
		return false;
527
		return false;
527
	}
528
	}
528
	int position;
529
	int position;
529
	if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
530
	if (local instanceof FieldBinding) {
531
		position = local.id;
532
	} else {
533
		position = local.id + this.maxFieldCount;
534
	}
535
	if (position < BitCacheSize) {
530
		// use bits
536
		// use bits
531
		return (
537
		return (
532
			(~this.nullBit1
538
			(~this.nullBit1
Lines 551-563 Link Here
551
		    & (1L << (position % BitCacheSize))) != 0;
557
		    & (1L << (position % BitCacheSize))) != 0;
552
}
558
}
553
559
554
final public boolean cannotBeNull(LocalVariableBinding local) {
560
final public boolean cannotBeNull(VariableBinding local) {
555
	if ((this.tagBits & NULL_FLAG_MASK) == 0 ||
561
	if ((this.tagBits & NULL_FLAG_MASK) == 0 ||
556
			(local.type.tagBits & TagBits.IsBaseType) != 0) {
562
			(local.type.tagBits & TagBits.IsBaseType) != 0) {
557
		return false;
563
		return false;
558
	}
564
	}
559
	int position;
565
	int position;
560
	if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
566
	if (local instanceof FieldBinding) {
567
		position = local.id;
568
	} else {
569
		position = local.id + this.maxFieldCount;
570
	}
571
	if (position < BitCacheSize) {
561
		// use bits
572
		// use bits
562
		return (this.nullBit1 & this.nullBit3
573
		return (this.nullBit1 & this.nullBit3
563
			& ((this.nullBit2 & this.nullBit4) | ~this.nullBit2)
574
			& ((this.nullBit2 & this.nullBit4) | ~this.nullBit2)
Lines 578-590 Link Here
578
		    & (1L << (position % BitCacheSize))) != 0;
589
		    & (1L << (position % BitCacheSize))) != 0;
579
}
590
}
580
591
581
final public boolean canOnlyBeNull(LocalVariableBinding local) {
592
final public boolean canOnlyBeNull(VariableBinding local) {
582
	if ((this.tagBits & NULL_FLAG_MASK) == 0 ||
593
	if ((this.tagBits & NULL_FLAG_MASK) == 0 ||
583
			(local.type.tagBits & TagBits.IsBaseType) != 0) {
594
			(local.type.tagBits & TagBits.IsBaseType) != 0) {
584
		return false;
595
		return false;
585
	}
596
	}
586
	int position;
597
	int position;
587
	if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
598
	if (local instanceof FieldBinding) {
599
		position = local.id;
600
	} else {
601
		position = local.id + this.maxFieldCount;
602
	}
603
	if (position < BitCacheSize) {
588
		// use bits
604
		// use bits
589
		return (this.nullBit1 & this.nullBit2
605
		return (this.nullBit1 & this.nullBit2
590
			& (~this.nullBit3 | ~this.nullBit4)
606
			& (~this.nullBit3 | ~this.nullBit4)
Lines 750-756 Link Here
750
	return isDefinitelyAssigned(local.id + this.maxFieldCount);
766
	return isDefinitelyAssigned(local.id + this.maxFieldCount);
751
}
767
}
752
768
753
final public boolean isDefinitelyNonNull(LocalVariableBinding local) {
769
final public boolean isDefinitelyNonNull(VariableBinding local) {
770
	if (local instanceof FieldBinding && (this.tagBits & NULL_FLAG_MASK) == 0) {
771
		// no local yet in scope. Came here because of a field being queried for non null
772
		// will only happen for final fields, since they are assigned in a constructor or static block
773
		// and we may currently be in some other method
774
		this.tagBits |= NULL_FLAG_MASK;
775
	}
754
	// do not want to complain in unreachable code
776
	// do not want to complain in unreachable code
755
	if ((this.tagBits & UNREACHABLE) != 0 ||
777
	if ((this.tagBits & UNREACHABLE) != 0 ||
756
			(this.tagBits & NULL_FLAG_MASK) == 0) {
778
			(this.tagBits & NULL_FLAG_MASK) == 0) {
Lines 760-766 Link Here
760
			local.constant() != Constant.NotAConstant) { // String instances
782
			local.constant() != Constant.NotAConstant) { // String instances
761
		return true;
783
		return true;
762
	}
784
	}
763
	int position = local.id + this.maxFieldCount;
785
	int position;
786
	if (local instanceof FieldBinding) {
787
		if (local.isFinal() && ((FieldBinding)local).isStatic()) {
788
			// static final field's null status may not be in the flow info
789
			return (((FieldBinding) local).getNullStatusForStaticFinalField() == FlowInfo.NON_NULL);
790
		}
791
		position = local.id;
792
	} else {
793
		position = local.id + this.maxFieldCount;
794
	}
764
	if (position < BitCacheSize) { // use bits
795
	if (position < BitCacheSize) { // use bits
765
		return ((this.nullBit1 & this.nullBit3 & (~this.nullBit2 | this.nullBit4))
796
		return ((this.nullBit1 & this.nullBit3 & (~this.nullBit2 | this.nullBit4))
766
			    & (1L << position)) != 0;
797
			    & (1L << position)) != 0;
Lines 779-792 Link Here
779
		    & (1L << (position % BitCacheSize))) != 0;
810
		    & (1L << (position % BitCacheSize))) != 0;
780
}
811
}
781
812
782
final public boolean isDefinitelyNull(LocalVariableBinding local) {
813
final public boolean isDefinitelyNull(VariableBinding local) {
814
	if (local instanceof FieldBinding && (this.tagBits & NULL_FLAG_MASK) == 0) {
815
		// no local yet in scope. Came here because of a field being queried for non null
816
		// will only happen for final fields, since they are assigned in a constructor or static block
817
		// and we may currently be in some other method
818
		this.tagBits |= NULL_FLAG_MASK;
819
	}
783
	// do not want to complain in unreachable code
820
	// do not want to complain in unreachable code
784
	if ((this.tagBits & UNREACHABLE) != 0 ||
821
	if ((this.tagBits & UNREACHABLE) != 0 ||
785
			(this.tagBits & NULL_FLAG_MASK) == 0 ||
822
			(this.tagBits & NULL_FLAG_MASK) == 0 ||
786
			(local.type.tagBits & TagBits.IsBaseType) != 0) {
823
			(local.type.tagBits & TagBits.IsBaseType) != 0) {
787
		return false;
824
		return false;
788
	}
825
	}
789
	int position = local.id + this.maxFieldCount;
826
	int position;
827
	if (local instanceof FieldBinding) {
828
		if (local.isFinal() && ((FieldBinding)local).isStatic()) {
829
			// static final field's null status may not be in the flow info
830
			return (((FieldBinding) local).getNullStatusForStaticFinalField() == FlowInfo.NULL);
831
		}
832
		position = local.id;
833
	} else {
834
		position = local.id + this.maxFieldCount;
835
	}
790
	if (position < BitCacheSize) { // use bits
836
	if (position < BitCacheSize) { // use bits
791
		return ((this.nullBit1 & this.nullBit2
837
		return ((this.nullBit1 & this.nullBit2
792
			        & (~this.nullBit3 | ~this.nullBit4))
838
			        & (~this.nullBit3 | ~this.nullBit4))
Lines 806-818 Link Here
806
		    & (1L << (position % BitCacheSize))) != 0;
852
		    & (1L << (position % BitCacheSize))) != 0;
807
}
853
}
808
854
809
final public boolean isDefinitelyUnknown(LocalVariableBinding local) {
855
final public boolean isDefinitelyUnknown(VariableBinding local) {
810
	// do not want to complain in unreachable code
856
	// do not want to complain in unreachable code
811
	if ((this.tagBits & UNREACHABLE) != 0 ||
857
	if ((this.tagBits & UNREACHABLE) != 0 ||
812
			(this.tagBits & NULL_FLAG_MASK) == 0) {
858
			(this.tagBits & NULL_FLAG_MASK) == 0) {
813
		return false;
859
		return false;
814
	}
860
	}
815
	int position = local.id + this.maxFieldCount;
861
	int position;
862
	if (local instanceof FieldBinding) {
863
		position = local.id;
864
	} else {
865
		position = local.id + this.maxFieldCount;
866
	}
816
	if (position < BitCacheSize) { // use bits
867
	if (position < BitCacheSize) { // use bits
817
		return ((this.nullBit1 & this.nullBit4
868
		return ((this.nullBit1 & this.nullBit4
818
				& ~this.nullBit2 & ~this.nullBit3) & (1L << position)) != 0;
869
				& ~this.nullBit2 & ~this.nullBit3) & (1L << position)) != 0;
Lines 866-878 Link Here
866
}
917
}
867
918
868
// TODO (Ayush) Check why this method does not return true for protected non null (1111)
919
// TODO (Ayush) Check why this method does not return true for protected non null (1111)
869
final public boolean isPotentiallyNonNull(LocalVariableBinding local) {
920
final public boolean isPotentiallyNonNull(VariableBinding local) {
870
	if ((this.tagBits & NULL_FLAG_MASK) == 0 ||
921
	if ((this.tagBits & NULL_FLAG_MASK) == 0 ||
871
			(local.type.tagBits & TagBits.IsBaseType) != 0) {
922
			(local.type.tagBits & TagBits.IsBaseType) != 0) {
872
		return false;
923
		return false;
873
	}
924
	}
874
	int position;
925
	int position;
875
	if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
926
	if (local instanceof FieldBinding) {
927
		position = local.id;
928
	} else {
929
		position = local.id + this.maxFieldCount;
930
	}
931
	if (position < BitCacheSize) { // use bits
876
		// use bits
932
		// use bits
877
		return ((this.nullBit3 & (~this.nullBit1 | ~this.nullBit2))
933
		return ((this.nullBit3 & (~this.nullBit1 | ~this.nullBit2))
878
			    & (1L << position)) != 0;
934
			    & (1L << position)) != 0;
Lines 892-904 Link Here
892
}
948
}
893
949
894
// TODO (Ayush) Check why this method does not return true for protected null
950
// TODO (Ayush) Check why this method does not return true for protected null
895
final public boolean isPotentiallyNull(LocalVariableBinding local) {
951
final public boolean isPotentiallyNull(VariableBinding local) {
896
	if ((this.tagBits & NULL_FLAG_MASK) == 0 ||
952
	if ((this.tagBits & NULL_FLAG_MASK) == 0 ||
897
			(local.type.tagBits & TagBits.IsBaseType) != 0) {
953
			(local.type.tagBits & TagBits.IsBaseType) != 0) {
898
		return false;
954
		return false;
899
	}
955
	}
900
	int position;
956
	int position;
901
	if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
957
	if (local instanceof FieldBinding) {
958
		if (local.isFinal() && ((FieldBinding)local).isStatic()) {
959
			// static final field's null status may not be in the flow info
960
			return (((FieldBinding) local).getNullStatusForStaticFinalField() == FlowInfo.POTENTIALLY_NULL);
961
		}
962
		position = local.id;
963
	} else {
964
		position = local.id + this.maxFieldCount;
965
	}
966
	if (position < BitCacheSize) {
902
		// use bits
967
		// use bits
903
		return ((this.nullBit2 & (~this.nullBit1 | ~this.nullBit3))
968
		return ((this.nullBit2 & (~this.nullBit1 | ~this.nullBit3))
904
			    & (1L << position)) != 0;
969
			    & (1L << position)) != 0;
Lines 917-929 Link Here
917
		    & (1L << (position % BitCacheSize))) != 0;
982
		    & (1L << (position % BitCacheSize))) != 0;
918
}
983
}
919
984
920
final public boolean isPotentiallyUnknown(LocalVariableBinding local) {
985
final public boolean isPotentiallyUnknown(VariableBinding local) {
921
	// do not want to complain in unreachable code
986
	// do not want to complain in unreachable code
922
	if ((this.tagBits & UNREACHABLE) != 0 ||
987
	if ((this.tagBits & UNREACHABLE) != 0 ||
923
			(this.tagBits & NULL_FLAG_MASK) == 0) {
988
			(this.tagBits & NULL_FLAG_MASK) == 0) {
924
		return false;
989
		return false;
925
	}
990
	}
926
	int position = local.id + this.maxFieldCount;
991
	int position;
992
	if (local instanceof FieldBinding) {
993
		position = local.id;
994
	} else {
995
		position = local.id + this.maxFieldCount;
996
	}
927
	if (position < BitCacheSize) { // use bits
997
	if (position < BitCacheSize) { // use bits
928
		return (this.nullBit4
998
		return (this.nullBit4
929
			& (~this.nullBit1 | ~this.nullBit2 & ~this.nullBit3)
999
			& (~this.nullBit1 | ~this.nullBit2 & ~this.nullBit3)
Lines 944-957 Link Here
944
		    & (1L << (position % BitCacheSize))) != 0;
1014
		    & (1L << (position % BitCacheSize))) != 0;
945
}
1015
}
946
1016
947
final public boolean isProtectedNonNull(LocalVariableBinding local) {
1017
final public boolean isProtectedNonNull(VariableBinding local) {
948
	if ((this.tagBits & NULL_FLAG_MASK) == 0 ||
1018
	if ((this.tagBits & NULL_FLAG_MASK) == 0 ||
949
			(local.type.tagBits & TagBits.IsBaseType) != 0) {
1019
			(local.type.tagBits & TagBits.IsBaseType) != 0) {
950
		return false;
1020
		return false;
951
	}
1021
	}
952
	int position;
1022
	int position;
953
	if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
1023
	if (local instanceof FieldBinding) {
954
		// use bits
1024
		position = local.id;
1025
	} else {
1026
		position = local.id + this.maxFieldCount;
1027
	}
1028
	if (position < BitCacheSize) { // use bits
955
		return (this.nullBit1 & this.nullBit3 & this.nullBit4 & (1L << position)) != 0;
1029
		return (this.nullBit1 & this.nullBit3 & this.nullBit4 & (1L << position)) != 0;
956
	}
1030
	}
957
	// use extra vector
1031
	// use extra vector
Lines 969-981 Link Here
969
		    & (1L << (position % BitCacheSize))) != 0;
1043
		    & (1L << (position % BitCacheSize))) != 0;
970
}
1044
}
971
1045
972
final public boolean isProtectedNull(LocalVariableBinding local) {
1046
final public boolean isProtectedNull(VariableBinding local) {
973
	if ((this.tagBits & NULL_FLAG_MASK) == 0 ||
1047
	if ((this.tagBits & NULL_FLAG_MASK) == 0 ||
974
			(local.type.tagBits & TagBits.IsBaseType) != 0) {
1048
			(local.type.tagBits & TagBits.IsBaseType) != 0) {
975
		return false;
1049
		return false;
976
	}
1050
	}
977
	int position;
1051
	int position;
978
	if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
1052
	if (local instanceof FieldBinding) {
1053
		position = local.id;
1054
	} else {
1055
		position = local.id + this.maxFieldCount;
1056
	}
1057
	if (position < BitCacheSize) {
979
		// use bits
1058
		// use bits
980
		return (this.nullBit1 & this.nullBit2
1059
		return (this.nullBit1 & this.nullBit2
981
			& (this.nullBit3 ^ this.nullBit4)
1060
			& (this.nullBit3 ^ this.nullBit4)
Lines 1008-1022 Link Here
1008
		throw new AssertionFailedException("assertion failed: " + message); //$NON-NLS-1$
1087
		throw new AssertionFailedException("assertion failed: " + message); //$NON-NLS-1$
1009
	return expression;
1088
	return expression;
1010
}
1089
}
1011
public void markAsComparedEqualToNonNull(LocalVariableBinding local) {
1090
public void markAsComparedEqualToNonNull(VariableBinding local) {
1012
	// protected from non-object locals in calling methods
1091
	// protected from non-object locals in calling methods
1013
	if (this != DEAD_END) {
1092
	if (this != DEAD_END) {
1014
		this.tagBits |= NULL_FLAG_MASK;
1093
		this.tagBits |= NULL_FLAG_MASK;
1015
		int position;
1094
		int position;
1095
		if (local instanceof FieldBinding) {
1096
			this.markNullStatus(local, FlowInfo.POTENTIALLY_NON_NULL);
1097
			return;
1098
		} else {
1099
			position = local.id + this.maxFieldCount;
1100
		}
1016
		long mask;
1101
		long mask;
1017
		long a1, a2, a3, a4, na2;
1102
		long a1, a2, a3, a4, na2;
1018
		// position is zero-based
1103
		// position is zero-based
1019
		if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
1104
		if (position < BitCacheSize) {
1020
			// use bits
1105
			// use bits
1021
			if (((mask = 1L << position)
1106
			if (((mask = 1L << position)
1022
				& (a1 = this.nullBit1)
1107
				& (a1 = this.nullBit1)
Lines 1105-1118 Link Here
1105
	}
1190
	}
1106
}
1191
}
1107
1192
1108
public void markAsComparedEqualToNull(LocalVariableBinding local) {
1193
public void markAsComparedEqualToNull(VariableBinding local) {
1109
	// protected from non-object locals in calling methods
1194
	// protected from non-object locals in calling methods
1110
	if (this != DEAD_END) {
1195
	if (this != DEAD_END) {
1111
		this.tagBits |= NULL_FLAG_MASK;
1196
		this.tagBits |= NULL_FLAG_MASK;
1112
		int position;
1197
		int position;
1113
		long mask;
1198
		long mask;
1114
		// position is zero-based
1199
		// position is zero-based
1115
		if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
1200
		if (local instanceof FieldBinding) {
1201
			this.markNullStatus(local, FlowInfo.POTENTIALLY_NULL);
1202
			return;
1203
		} else {
1204
			position = local.id + this.maxFieldCount;
1205
		}
1206
		if (position < BitCacheSize) {
1116
			// use bits
1207
			// use bits
1117
			if (((mask = 1L << position) & this.nullBit1) != 0) {
1208
			if (((mask = 1L << position) & this.nullBit1) != 0) {
1118
  			  	if ((mask
1209
  			  	if ((mask
Lines 1243-1256 Link Here
1243
		markAsDefinitelyAssigned(local.id + this.maxFieldCount);
1334
		markAsDefinitelyAssigned(local.id + this.maxFieldCount);
1244
}
1335
}
1245
1336
1246
public void markAsDefinitelyNonNull(LocalVariableBinding local) {
1337
public void markAsDefinitelyNonNull(VariableBinding local) {
1247
	// protected from non-object locals in calling methods
1338
	// protected from non-object locals in calling methods
1248
	if (this != DEAD_END) {
1339
	if (this != DEAD_END) {
1249
    	this.tagBits |= NULL_FLAG_MASK;
1340
    	this.tagBits |= NULL_FLAG_MASK;
1250
    	long mask;
1341
    	long mask;
1251
    	int position;
1342
    	int position;
1252
    	// position is zero-based
1343
    	// position is zero-based
1253
    	if ((position = local.id + this.maxFieldCount) < BitCacheSize) { // use bits
1344
    	if (local instanceof FieldBinding) {
1345
    		this.markNullStatus(local, FlowInfo.POTENTIALLY_NON_NULL);
1346
    		return;
1347
    	} else {
1348
    		position = local.id + this.maxFieldCount;
1349
    	}
1350
    	if (position < BitCacheSize) { // use bits
1254
    		// set assigned non null
1351
    		// set assigned non null
1255
    		this.nullBit1 |= (mask = 1L << position);
1352
    		this.nullBit1 |= (mask = 1L << position);
1256
    		this.nullBit3 |= mask;
1353
    		this.nullBit3 |= mask;
Lines 1297-1310 Link Here
1297
	}
1394
	}
1298
}
1395
}
1299
1396
1300
public void markAsDefinitelyNull(LocalVariableBinding local) {
1397
public void markAsDefinitelyNull(VariableBinding local) {
1301
	// protected from non-object locals in calling methods
1398
	// protected from non-object locals in calling methods
1302
	if (this != DEAD_END) {
1399
	if (this != DEAD_END) {
1303
    	this.tagBits |= NULL_FLAG_MASK;
1400
    	this.tagBits |= NULL_FLAG_MASK;
1304
    	long mask;
1401
    	long mask;
1305
    	int position;
1402
    	int position;
1306
    	// position is zero-based
1403
    	// position is zero-based
1307
    	if ((position = local.id + this.maxFieldCount) < BitCacheSize) { // use bits
1404
    	if (local instanceof FieldBinding) {
1405
    		this.markNullStatus(local, FlowInfo.POTENTIALLY_NULL);
1406
    		return;
1407
    	} else {
1408
    		position = local.id + this.maxFieldCount;
1409
    	}
1410
    	if (position < BitCacheSize) { // use bits
1308
    		// mark assigned null
1411
    		// mark assigned null
1309
    		this.nullBit1 |= (mask = 1L << position);
1412
    		this.nullBit1 |= (mask = 1L << position);
1310
    		this.nullBit2 |= mask;
1413
    		this.nullBit2 |= mask;
Lines 1357-1370 Link Here
1357
 */
1460
 */
1358
// PREMATURE may try to get closer to markAsDefinitelyAssigned, but not
1461
// PREMATURE may try to get closer to markAsDefinitelyAssigned, but not
1359
//			 obvious
1462
//			 obvious
1360
public void markAsDefinitelyUnknown(LocalVariableBinding local) {
1463
public void markAsDefinitelyUnknown(VariableBinding local) {
1361
	// protected from non-object locals in calling methods
1464
	// protected from non-object locals in calling methods
1362
	if (this != DEAD_END) {
1465
	if (this != DEAD_END) {
1363
		this.tagBits |= NULL_FLAG_MASK;
1466
		this.tagBits |= NULL_FLAG_MASK;
1364
		long mask;
1467
		long mask;
1365
		int position;
1468
		int position;
1366
		// position is zero-based
1469
		// position is zero-based
1367
		if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
1470
		if (local instanceof FieldBinding) {
1471
			position = local.id;
1472
		} else {
1473
			position = local.id + this.maxFieldCount;
1474
		}
1475
		if (position < BitCacheSize) {
1368
			// use bits
1476
			// use bits
1369
			// mark assigned null
1477
			// mark assigned null
1370
			this.nullBit1 |= (mask = 1L << position);
1478
			this.nullBit1 |= (mask = 1L << position);
Lines 1412-1423 Link Here
1412
	}
1520
	}
1413
}
1521
}
1414
1522
1415
public void resetNullInfo(LocalVariableBinding local) {
1523
public void resetNullInfo(VariableBinding local) {
1416
	if (this != DEAD_END) {
1524
	if (this != DEAD_END) {
1417
		this.tagBits |= NULL_FLAG_MASK;
1525
		this.tagBits |= NULL_FLAG_MASK;
1418
        int position;
1526
        int position;
1419
        long mask;
1527
        long mask;
1420
        if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
1528
        if (local instanceof FieldBinding) {
1529
        	position = local.id;
1530
        } else {
1531
        	position = local.id + this.maxFieldCount;
1532
        }
1533
        if (position < BitCacheSize) {
1421
            // use bits
1534
            // use bits
1422
            this.nullBit1 &= (mask = ~(1L << position));
1535
            this.nullBit1 &= (mask = ~(1L << position));
1423
            this.nullBit2 &= mask;
1536
            this.nullBit2 &= mask;
Lines 1440-1456 Link Here
1440
	}
1553
	}
1441
}
1554
}
1442
1555
1556
public void resetNullInfoForFields() {
1557
	if (this != DEAD_END) {
1558
		long mask;
1559
		if (this.maxFieldCount < BitCacheSize) {
1560
			 // use bits
1561
	        this.nullBit1 &= (mask = -1L << this.maxFieldCount);
1562
	        this.nullBit2 &= mask;
1563
	        this.nullBit3 &= mask;
1564
	        this.nullBit4 &= mask;
1565
		}
1566
		else {
1567
			 this.nullBit1 &= (mask = 0L);
1568
		     this.nullBit2 &= mask;
1569
		     this.nullBit3 &= mask;
1570
		     this.nullBit4 &= mask;
1571
			if (this.extra != null){
1572
				for (int position = BitCacheSize; position < this.maxFieldCount; position++) {
1573
					// use extra vector
1574
				    int vectorIndex = (position / BitCacheSize) - 1;
1575
				    if (vectorIndex >= this.extra[2].length)
1576
						break;   // No null info about fields beyond this point in the extra vector
1577
					this.extra[2][vectorIndex]
1578
					    &= (mask = ~(1L << (position % BitCacheSize)));
1579
					this.extra[3][vectorIndex] &= mask;
1580
					this.extra[4][vectorIndex] &= mask;
1581
					this.extra[5][vectorIndex] &= mask;
1582
				}
1583
			}
1584
		}
1585
	}
1586
}
1587
1443
/**
1588
/**
1444
 * Mark a local as potentially having been assigned to an unknown value.
1589
 * Mark a local as potentially having been assigned to an unknown value.
1445
 * @param local the local to mark
1590
 * @param local the local to mark
1446
 */
1591
 */
1447
public void markPotentiallyUnknownBit(LocalVariableBinding local) {
1592
public void markPotentiallyUnknownBit(VariableBinding local) {
1448
	// protected from non-object locals in calling methods
1593
	// protected from non-object locals in calling methods
1449
	if (this != DEAD_END) {
1594
	if (this != DEAD_END) {
1450
		this.tagBits |= NULL_FLAG_MASK;
1595
		this.tagBits |= NULL_FLAG_MASK;
1451
        int position;
1596
        int position;
1452
        long mask;
1597
        long mask;
1453
        if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
1598
        if (local instanceof FieldBinding) {
1599
        	position = local.id;
1600
        } else {
1601
        	position = local.id + this.maxFieldCount;
1602
        }
1603
        if (position < BitCacheSize) {
1454
            // use bits
1604
            // use bits
1455
        	mask = 1L << position;
1605
        	mask = 1L << position;
1456
        	isTrue((this.nullBit1 & mask) == 0, "Adding 'unknown' mark in unexpected state"); //$NON-NLS-1$
1606
        	isTrue((this.nullBit1 & mask) == 0, "Adding 'unknown' mark in unexpected state"); //$NON-NLS-1$
Lines 1492-1503 Link Here
1492
	}
1642
	}
1493
}
1643
}
1494
1644
1495
public void markPotentiallyNullBit(LocalVariableBinding local) {
1645
public void markPotentiallyNullBit(VariableBinding local) {
1496
	if (this != DEAD_END) {
1646
	if (this != DEAD_END) {
1497
		this.tagBits |= NULL_FLAG_MASK;
1647
		this.tagBits |= NULL_FLAG_MASK;
1498
        int position;
1648
        int position;
1499
        long mask;
1649
        long mask;
1500
        if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
1650
        if (local instanceof FieldBinding) {
1651
        	position = local.id;
1652
        } else {
1653
        	position = local.id + this.maxFieldCount;
1654
        }
1655
        if (position < BitCacheSize) {
1501
            // use bits
1656
            // use bits
1502
        	mask = 1L << position;
1657
        	mask = 1L << position;
1503
        	isTrue((this.nullBit1 & mask) == 0, "Adding 'potentially null' mark in unexpected state"); //$NON-NLS-1$
1658
        	isTrue((this.nullBit1 & mask) == 0, "Adding 'potentially null' mark in unexpected state"); //$NON-NLS-1$
Lines 1539-1550 Link Here
1539
	}
1694
	}
1540
}
1695
}
1541
1696
1542
public void markPotentiallyNonNullBit(LocalVariableBinding local) {
1697
public void markPotentiallyNonNullBit(VariableBinding local) {
1543
	if (this != DEAD_END) {
1698
	if (this != DEAD_END) {
1544
		this.tagBits |= NULL_FLAG_MASK;
1699
		this.tagBits |= NULL_FLAG_MASK;
1545
        int position;
1700
        int position;
1546
        long mask;
1701
        long mask;
1547
        if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
1702
        if (local instanceof FieldBinding) {
1703
        	position = local.id;
1704
        } else {
1705
        	position = local.id + this.maxFieldCount;
1706
        }
1707
        if (position < BitCacheSize) {
1548
            // use bits
1708
            // use bits
1549
        	mask = 1L << position;
1709
        	mask = 1L << position;
1550
        	isTrue((this.nullBit1 & mask) == 0, "Adding 'potentially non-null' mark in unexpected state"); //$NON-NLS-1$
1710
        	isTrue((this.nullBit1 & mask) == 0, "Adding 'potentially non-null' mark in unexpected state"); //$NON-NLS-1$
Lines 2077-2084 Link Here
2077
	return this;
2237
	return this;
2078
}
2238
}
2079
2239
2080
public void markedAsNullOrNonNullInAssertExpression(LocalVariableBinding local) {
2240
public void markedAsNullOrNonNullInAssertExpression(VariableBinding binding) {
2081
	int position = local.id + this.maxFieldCount;
2241
	int position;
2242
	if (binding instanceof FieldBinding) {
2243
		position = binding.id;
2244
	} else {
2245
		position = binding.id + this.maxFieldCount;
2246
	}
2082
	int oldLength;
2247
	int oldLength;
2083
	if (this.nullStatusChangedInAssert == null) {
2248
	if (this.nullStatusChangedInAssert == null) {
2084
		this.nullStatusChangedInAssert = new int[position + 1];
2249
		this.nullStatusChangedInAssert = new int[position + 1];
Lines 2091-2098 Link Here
2091
	this.nullStatusChangedInAssert[position] = 1;
2256
	this.nullStatusChangedInAssert[position] = 1;
2092
}
2257
}
2093
2258
2094
public boolean isMarkedAsNullOrNonNullInAssertExpression(LocalVariableBinding local) {
2259
public boolean isMarkedAsNullOrNonNullInAssertExpression(VariableBinding binding) {
2095
	int position = local.id + this.maxFieldCount;
2260
	int position;
2261
	if (binding instanceof FieldBinding) {
2262
		position = binding.id;
2263
	} else {
2264
		position = binding.id + this.maxFieldCount;
2265
	}
2096
	if(this.nullStatusChangedInAssert == null || position >= this.nullStatusChangedInAssert.length) {
2266
	if(this.nullStatusChangedInAssert == null || position >= this.nullStatusChangedInAssert.length) {
2097
		return false;
2267
		return false;
2098
	}
2268
	}
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java (-2 / +26 lines)
Lines 39-49 Link Here
39
	public TypeDeclaration referenceContext;
39
	public TypeDeclaration referenceContext;
40
	public TypeReference superTypeReference;
40
	public TypeReference superTypeReference;
41
	java.util.ArrayList deferredBoundChecks;
41
	java.util.ArrayList deferredBoundChecks;
42
42
	public int cumulativeFieldCount;   // cumulative field count from all enclosing types, used to build unique field id's for member types.
43
	public int localTypeFieldIdStart;
43
	public ClassScope(Scope parent, TypeDeclaration context) {
44
	public ClassScope(Scope parent, TypeDeclaration context) {
44
		super(Scope.CLASS_SCOPE, parent);
45
		super(Scope.CLASS_SCOPE, parent);
45
		this.referenceContext = context;
46
		this.referenceContext = context;
46
		this.deferredBoundChecks = null; // initialized if required
47
		this.deferredBoundChecks = null; // initialized if required
48
		this.localTypeFieldIdStart = this.cumulativeFieldCount = 0;
47
	}
49
	}
48
50
49
	void buildAnonymousTypeBinding(SourceTypeBinding enclosingType, ReferenceBinding supertype) {
51
	void buildAnonymousTypeBinding(SourceTypeBinding enclosingType, ReferenceBinding supertype) {
Lines 80-85 Link Here
80
				}
82
				}
81
			}
83
			}
82
		}
84
		}
85
		this.cumulativeFieldCount += outerMostMethodScope().analysisIndex;
86
		this.localTypeFieldIdStart = outerMostMethodScope().analysisIndex;
83
		connectMemberTypes();
87
		connectMemberTypes();
84
		buildFieldsAndMethods();
88
		buildFieldsAndMethods();
85
		anonymousType.faultInTypesForFieldsAndMethods();
89
		anonymousType.faultInTypesForFieldsAndMethods();
Lines 109-114 Link Here
109
		FieldBinding[] fieldBindings = new FieldBinding[count];
113
		FieldBinding[] fieldBindings = new FieldBinding[count];
110
		HashtableOfObject knownFieldNames = new HashtableOfObject(count);
114
		HashtableOfObject knownFieldNames = new HashtableOfObject(count);
111
		count = 0;
115
		count = 0;
116
		ClassScope enclosingClass = this.enclosingClassScope();
117
		if (enclosingClass != null) {
118
			this.cumulativeFieldCount += enclosingClass.cumulativeFieldCount;
119
		}
120
//		SourceTypeBinding enclosingSourceType = this.enclosingSourceType();
121
//		if (enclosingSourceType != null) {
122
//			ReferenceBinding superClassBinding = sourceType.superclass;
123
//			while (superClassBinding != null) {
124
//				FieldBinding[] unResolvedFields = superClassBinding.unResolvedFields();
125
//				if (unResolvedFields != null) {
126
//					this.cumulativeFieldCount += unResolvedFields.length;
127
//				}
128
//				superClassBinding = superClassBinding.superclass();
129
//			}
130
//			ReferenceBinding[] superInterfacesBinding = enclosingSourceType.superInterfaces;
131
//			this.cumulativeFieldCount += findFieldCountFromSuperInterfaces(superInterfacesBinding);
132
//		}
112
		for (int i = 0; i < size; i++) {
133
		for (int i = 0; i < size; i++) {
113
			FieldDeclaration field = fields[i];
134
			FieldDeclaration field = fields[i];
114
			if (field.getKind() == AbstractVariableDeclaration.INITIALIZER) {
135
			if (field.getKind() == AbstractVariableDeclaration.INITIALIZER) {
Lines 116-122 Link Here
116
				// now this error reporting is moved into the parser itself. See https://bugs.eclipse.org/bugs/show_bug.cgi?id=212713
137
				// now this error reporting is moved into the parser itself. See https://bugs.eclipse.org/bugs/show_bug.cgi?id=212713
117
			} else {
138
			} else {
118
				FieldBinding fieldBinding = new FieldBinding(field, null, field.modifiers | ExtraCompilerModifiers.AccUnresolved, sourceType);
139
				FieldBinding fieldBinding = new FieldBinding(field, null, field.modifiers | ExtraCompilerModifiers.AccUnresolved, sourceType);
119
				fieldBinding.id = count;
140
				fieldBinding.id = count + this.cumulativeFieldCount;
120
				// field's type will be resolved when needed for top level types
141
				// field's type will be resolved when needed for top level types
121
				checkAndSetModifiersForField(fieldBinding, field);
142
				checkAndSetModifiersForField(fieldBinding, field);
122
143
Lines 144-149 Link Here
144
		// remove duplicate fields
165
		// remove duplicate fields
145
		if (count != fieldBindings.length)
166
		if (count != fieldBindings.length)
146
			System.arraycopy(fieldBindings, 0, fieldBindings = new FieldBinding[count], 0, count);
167
			System.arraycopy(fieldBindings, 0, fieldBindings = new FieldBinding[count], 0, count);
168
		this.cumulativeFieldCount += count;
147
		sourceType.tagBits &= ~(TagBits.AreFieldsSorted|TagBits.AreFieldsComplete); // in case some static imports reached already into this type
169
		sourceType.tagBits &= ~(TagBits.AreFieldsSorted|TagBits.AreFieldsComplete); // in case some static imports reached already into this type
148
		sourceType.setFields(fieldBindings);
170
		sourceType.setFields(fieldBindings);
149
	}
171
	}
Lines 226-231 Link Here
226
			checkParameterizedTypeBounds();
248
			checkParameterizedTypeBounds();
227
			checkParameterizedSuperTypeCollisions();
249
			checkParameterizedSuperTypeCollisions();
228
		}
250
		}
251
		this.cumulativeFieldCount += outerMostMethodScope().analysisIndex;
252
		this.localTypeFieldIdStart = outerMostMethodScope().analysisIndex;
229
		buildFieldsAndMethods();
253
		buildFieldsAndMethods();
230
		localType.faultInTypesForFieldsAndMethods();
254
		localType.faultInTypesForFieldsAndMethods();
231
255
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/FieldBinding.java (+12 lines)
Lines 16-26 Link Here
16
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
16
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
17
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
17
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
18
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
18
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
19
import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
19
import org.eclipse.jdt.internal.compiler.impl.Constant;
20
import org.eclipse.jdt.internal.compiler.impl.Constant;
20
21
21
public class FieldBinding extends VariableBinding {
22
public class FieldBinding extends VariableBinding {
22
	public ReferenceBinding declaringClass;
23
	public ReferenceBinding declaringClass;
23
	public int compoundUseFlag = 0; // number or accesses via postIncrement or compoundAssignment
24
	public int compoundUseFlag = 0; // number or accesses via postIncrement or compoundAssignment
25
	private int nullStatus;
24
	
26
	
25
protected FieldBinding() {
27
protected FieldBinding() {
26
	super(null, null, 0, null);
28
	super(null, null, 0, null);
Lines 29-40 Link Here
29
public FieldBinding(char[] name, TypeBinding type, int modifiers, ReferenceBinding declaringClass, Constant constant) {
31
public FieldBinding(char[] name, TypeBinding type, int modifiers, ReferenceBinding declaringClass, Constant constant) {
30
	super(name, type, modifiers, constant);
32
	super(name, type, modifiers, constant);
31
	this.declaringClass = declaringClass;
33
	this.declaringClass = declaringClass;
34
	this.nullStatus = FlowInfo.UNKNOWN;
32
}
35
}
33
// special API used to change field declaring class for runtime visibility check
36
// special API used to change field declaring class for runtime visibility check
34
public FieldBinding(FieldBinding initialFieldBinding, ReferenceBinding declaringClass) {
37
public FieldBinding(FieldBinding initialFieldBinding, ReferenceBinding declaringClass) {
35
	super(initialFieldBinding.name, initialFieldBinding.type, initialFieldBinding.modifiers, initialFieldBinding.constant());
38
	super(initialFieldBinding.name, initialFieldBinding.type, initialFieldBinding.modifiers, initialFieldBinding.constant());
36
	this.declaringClass = declaringClass;
39
	this.declaringClass = declaringClass;
37
	this.id = initialFieldBinding.id;
40
	this.id = initialFieldBinding.id;
41
	this.nullStatus = FlowInfo.UNKNOWN;
38
	setAnnotations(initialFieldBinding.getAnnotations());
42
	setAnnotations(initialFieldBinding.getAnnotations());
39
}
43
}
40
/* API
44
/* API
Lines 386-389 Link Here
386
	}
390
	}
387
	return null;
391
	return null;
388
}
392
}
393
394
public int getNullStatusForStaticFinalField() {
395
	return this.nullStatus;
396
}
397
398
public void setNullStatusForStaticFinalField(int nullStatusToMark) {
399
	this.nullStatus = nullStatusToMark;
400
}
389
}
401
}
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties (+10 lines)
Lines 580-585 Link Here
580
### MORE GENERICS
580
### MORE GENERICS
581
660 = Unused type arguments for the non generic constructor {0}({1}) of type {2}; it should not be parameterized with arguments <{3}>
581
660 = Unused type arguments for the non generic constructor {0}({1}) of type {2}; it should not be parameterized with arguments <{3}>
582
582
583
### NULL ANALYSIS FOR FIELDS
584
670 = Null pointer access: The field {0} can only be null at this location
585
671 = Potential null pointer access: The field {0} may be null at this location
586
672 = Redundant null check: The field {0} can only be null at this location
587
673 = Null comparison always yields false: The field {0} can only be null at this location
588
674 = Redundant null check: The field {0} cannot be null at this location
589
675 = Null comparison always yields false: The field {0} cannot be null at this location
590
676 = Redundant assignment: The field {0} can only be null at this location
591
677 = instanceof always yields false: The field {0} can only be null at this location
592
583
### CORRUPTED BINARIES
593
### CORRUPTED BINARIES
584
700 = The class file {0} contains a signature ''{1}'' ill-formed at position {2}
594
700 = The class file {0} contains a signature ''{1}'' ill-formed at position {2}
585
595
(-)a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetClassFile.java (-1 / +1 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2010 IBM Corporation and others.
2
 * Copyright (c) 2000, 2011 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

Return to bug 247564