Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
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/NullReferenceTest.java (-63 / +50 lines)
Lines 15533-15538 Link Here
15533
			"public class X {\n" +
15533
			"public class X {\n" +
15534
			"  Object o;\n" +
15534
			"  Object o;\n" +
15535
			"  void foo() {\n" +
15535
			"  void foo() {\n" +
15536
			"      o = null;\n" +
15536
			"  }\n" +
15537
			"  }\n" +
15537
			"  void foo1() {\n" + 
15538
			"  void foo1() {\n" + 
15538
			"	 o.toString();\n" +
15539
			"	 o.toString();\n" +
Lines 15580-15586 Link Here
15580
			"            if (field == null) { \n" +
15581
			"            if (field == null) { \n" +
15581
			"                field = new Object();\n" +
15582
			"                field = new Object();\n" +
15582
			"            }\n" +
15583
			"            }\n" +
15583
			"            field.toString(); //Pot. NPE\n" +
15584
			"            field.toString(); // Wrong outcome was: Pot. NPE\n" +
15584
			"            i--;\n" +
15585
			"            i--;\n" +
15585
			"        }\n" +
15586
			"        }\n" +
15586
			"    }\n" +
15587
			"    }\n" +
Lines 16005-16011 Link Here
16005
			"  }\n" +
16006
			"  }\n" +
16006
			"  void foo1() {\n" +
16007
			"  void foo1() {\n" +
16007
			"    if (o == null) {\n" +
16008
			"    if (o == null) {\n" +
16008
			"        o.toString(); // danger" +
16009
			"        o.toString(); // danger\n" +
16009
			"        return;\n" +
16010
			"        return;\n" +
16010
			"    }\n" +
16011
			"    }\n" +
16011
			"	 o.toString(); // safe\n" +
16012
			"	 o.toString(); // safe\n" +
Lines 16019-16029 Link Here
16019
			"}\n"},
16020
			"}\n"},
16020
			"----------\n" + 
16021
			"----------\n" + 
16021
			"1. ERROR in X.java (at line 13)\n" + 
16022
			"1. ERROR in X.java (at line 13)\n" + 
16022
			"	o.toString(); // danger        return;\n" + 
16023
			"	o.toString(); // danger\n" + 
16023
			"	^\n" + 
16024
			"	^\n" + 
16024
			"Null pointer access: The field o can only be null at this location\n" + 
16025
			"Null pointer access: The field o can only be null at this location\n" + 
16025
			"----------\n" + 
16026
			"----------\n" + 
16026
			"2. ERROR in X.java (at line 21)\n" + 
16027
			"2. ERROR in X.java (at line 22)\n" + 
16027
			"	o.toString(); // uncertain\n" + 
16028
			"	o.toString(); // uncertain\n" + 
16028
			"	^\n" + 
16029
			"	^\n" + 
16029
			"Potential null pointer access: The field o may be null at this location\n" + 
16030
			"Potential null pointer access: The field o may be null at this location\n" + 
Lines 16075-16081 Link Here
16075
			"  }\n" +
16076
			"  }\n" +
16076
			"  void foo1() {\n" +
16077
			"  void foo1() {\n" +
16077
			"    if (o == null) {\n" +
16078
			"    if (o == null) {\n" +
16078
			"        o.toString(); // danger" +
16079
			"        o.toString(); // danger\n" +
16079
			"        return;\n" +
16080
			"        return;\n" +
16080
			"    }\n" +
16081
			"    }\n" +
16081
			"	 o.toString(); // safe\n" +
16082
			"	 o.toString(); // safe\n" +
Lines 16089-16099 Link Here
16089
			"}\n"},
16090
			"}\n"},
16090
			"----------\n" + 
16091
			"----------\n" + 
16091
			"1. ERROR in X.java (at line 39)\n" + 
16092
			"1. ERROR in X.java (at line 39)\n" + 
16092
			"	o.toString(); // danger        return;\n" + 
16093
			"	o.toString(); // danger\n" + 
16093
			"	^\n" + 
16094
			"	^\n" + 
16094
			"Null pointer access: The field o can only be null at this location\n" + 
16095
			"Null pointer access: The field o can only be null at this location\n" + 
16095
			"----------\n" + 
16096
			"----------\n" + 
16096
			"2. ERROR in X.java (at line 47)\n" + 
16097
			"2. ERROR in X.java (at line 48)\n" + 
16097
			"	o.toString(); // uncertain\n" + 
16098
			"	o.toString(); // uncertain\n" + 
16098
			"	^\n" + 
16099
			"	^\n" + 
16099
			"Potential null pointer access: The field o may be null at this location\n" + 
16100
			"Potential null pointer access: The field o may be null at this location\n" + 
Lines 16128-16133 Link Here
16128
			"	 if (o == null) {\n" +	// don't know o's nullness, so silent
16129
			"	 if (o == null) {\n" +	// don't know o's nullness, so silent
16129
			"		o.toString();\n" + // report NPE
16130
			"		o.toString();\n" + // report NPE
16130
			"	 }\n" +
16131
			"	 }\n" +
16132
			"    local.toString();\n" + // try to diffuse status for o / o2
16131
			"	 o.toString();\n" +	// already reported NPE above. So silent. Same behaviour as 'local'
16133
			"	 o.toString();\n" +	// already reported NPE above. So silent. Same behaviour as 'local'
16132
			"	 if (o2 == null) {\n" + // report always false null check
16134
			"	 if (o2 == null) {\n" + // report always false null check
16133
			"		o2.toString();\n" + // dead code
16135
			"		o2.toString();\n" + // dead code
Lines 16151-16162 Link Here
16151
			"	^\n" + 
16153
			"	^\n" + 
16152
			"Null pointer access: The field o can only be null at this location\n" + 
16154
			"Null pointer access: The field o can only be null at this location\n" + 
16153
			"----------\n" + 
16155
			"----------\n" + 
16154
			"4. ERROR in X.java (at line 22)\n" + 
16156
			"4. ERROR in X.java (at line 23)\n" + 
16155
			"	if (o2 == null) {\n" + 
16157
			"	if (o2 == null) {\n" + 
16156
			"	    ^^\n" + 
16158
			"	    ^^\n" + 
16157
			"Null comparison always yields false: The field o2 cannot be null at this location\n" + 
16159
			"Null comparison always yields false: The field o2 cannot be null at this location\n" + 
16158
			"----------\n" + 
16160
			"----------\n" + 
16159
			"5. WARNING in X.java (at line 22)\n" + 
16161
			"5. WARNING in X.java (at line 23)\n" + 
16160
			"	if (o2 == null) {\n" + 
16162
			"	if (o2 == null) {\n" + 
16161
			"		o2.toString();\n" + 
16163
			"		o2.toString();\n" + 
16162
			"	 }\n" + 
16164
			"	 }\n" + 
Lines 16166-16174 Link Here
16166
	);
16168
	);
16167
}
16169
}
16168
16170
16169
//null analysis -- case for static final field initialized inside static block with different values
16171
// null analysis -- case for static final field initialized inside static block with different values
16170
//check if the resetting works properly i.e. null status for constant fields should not be 
16172
// check if the resetting works properly i.e. null status for constant fields should not be 
16171
//reset on method calls. This test is for constructors
16173
// reset on method calls. This test is for constructors
16172
public void testBug247564b_6() {
16174
public void testBug247564b_6() {
16173
	this.runNegativeTest(
16175
	this.runNegativeTest(
16174
		new String[] {
16176
		new String[] {
Lines 16193-16198 Link Here
16193
			"	 if (o == null) {\n" +	// don't know o's nullness, so silent
16195
			"	 if (o == null) {\n" +	// don't know o's nullness, so silent
16194
			"		o.toString();\n" + // report NPE
16196
			"		o.toString();\n" + // report NPE
16195
			"	 }\n" +
16197
			"	 }\n" +
16198
			"    local.toString();\n" + // try to diffuse status for o / o2
16196
			"	 o.toString();\n" +	// already reported NPE above. So silent. Same behaviour as 'local'
16199
			"	 o.toString();\n" +	// already reported NPE above. So silent. Same behaviour as 'local'
16197
			"	 if (o2 == null) {\n" + // report always false null check
16200
			"	 if (o2 == null) {\n" + // report always false null check
16198
			"		o2.toString();\n" + // dead code
16201
			"		o2.toString();\n" + // dead code
Lines 16216-16227 Link Here
16216
			"	^\n" + 
16219
			"	^\n" + 
16217
			"Null pointer access: The field o can only be null at this location\n" + 
16220
			"Null pointer access: The field o can only be null at this location\n" + 
16218
			"----------\n" + 
16221
			"----------\n" + 
16219
			"4. ERROR in X.java (at line 22)\n" + 
16222
			"4. ERROR in X.java (at line 23)\n" + 
16220
			"	if (o2 == null) {\n" + 
16223
			"	if (o2 == null) {\n" + 
16221
			"	    ^^\n" + 
16224
			"	    ^^\n" + 
16222
			"Null comparison always yields false: The field o2 cannot be null at this location\n" + 
16225
			"Null comparison always yields false: The field o2 cannot be null at this location\n" + 
16223
			"----------\n" + 
16226
			"----------\n" + 
16224
			"5. WARNING in X.java (at line 22)\n" + 
16227
			"5. WARNING in X.java (at line 23)\n" + 
16225
			"	if (o2 == null) {\n" + 
16228
			"	if (o2 == null) {\n" + 
16226
			"		o2.toString();\n" + 
16229
			"		o2.toString();\n" + 
16227
			"	 }\n" + 
16230
			"	 }\n" + 
Lines 16231-16239 Link Here
16231
	);
16234
	);
16232
}
16235
}
16233
16236
16234
//null analysis -- case for static final field initialized inside static block with different values
16237
// null analysis -- case for static final field initialized inside static block with different values
16235
//check if the resetting works properly i.e. null status for constant fields should not be 
16238
// check if the resetting works properly i.e. null status for constant fields should not be 
16236
//reset on method calls. This test is for constructors
16239
// reset on method calls. This test is for constructors
16237
public void testBug247564b_6_2() {
16240
public void testBug247564b_6_2() {
16238
	this.runNegativeTest(
16241
	this.runNegativeTest(
16239
		new String[] {
16242
		new String[] {
Lines 16284-16289 Link Here
16284
			"	 if (o == null) {\n" +	// don't know o's nullness, so silent
16287
			"	 if (o == null) {\n" +	// don't know o's nullness, so silent
16285
			"		o.toString();\n" + // report NPE
16288
			"		o.toString();\n" + // report NPE
16286
			"	 }\n" +
16289
			"	 }\n" +
16290
			"    local.toString();\n" + // try to diffuse status for o / o2
16287
			"	 o.toString();\n" +	// already reported NPE above. So silent. Same behaviour as 'local'
16291
			"	 o.toString();\n" +	// already reported NPE above. So silent. Same behaviour as 'local'
16288
			"	 if (o2 == null) {\n" + // report always false null check
16292
			"	 if (o2 == null) {\n" + // report always false null check
16289
			"		o2.toString();\n" + // dead code
16293
			"		o2.toString();\n" + // dead code
Lines 16307-16318 Link Here
16307
			"	^\n" + 
16311
			"	^\n" + 
16308
			"Null pointer access: The field o can only be null at this location\n" + 
16312
			"Null pointer access: The field o can only be null at this location\n" + 
16309
			"----------\n" + 
16313
			"----------\n" + 
16310
			"4. ERROR in X.java (at line 48)\n" + 
16314
			"4. ERROR in X.java (at line 49)\n" + 
16311
			"	if (o2 == null) {\n" + 
16315
			"	if (o2 == null) {\n" + 
16312
			"	    ^^\n" + 
16316
			"	    ^^\n" + 
16313
			"Null comparison always yields false: The field o2 cannot be null at this location\n" + 
16317
			"Null comparison always yields false: The field o2 cannot be null at this location\n" + 
16314
			"----------\n" + 
16318
			"----------\n" + 
16315
			"5. WARNING in X.java (at line 48)\n" + 
16319
			"5. WARNING in X.java (at line 49)\n" + 
16316
			"	if (o2 == null) {\n" + 
16320
			"	if (o2 == null) {\n" + 
16317
			"		o2.toString();\n" + 
16321
			"		o2.toString();\n" + 
16318
			"	 }\n" + 
16322
			"	 }\n" + 
Lines 16349-16354 Link Here
16349
			"	 if (o1 == null) {\n" +	// can't be null, was dereferenced in static initializer
16353
			"	 if (o1 == null) {\n" +	// can't be null, was dereferenced in static initializer
16350
			"		o1.toString();\n" + // dead
16354
			"		o1.toString();\n" + // dead
16351
			"	 }\n" +
16355
			"	 }\n" +
16356
			"    local.toString();\n" + // try to diffuse status for o1 / o2
16352
			"	 o1.toString();\n" +	// safe
16357
			"	 o1.toString();\n" +	// safe
16353
			"	 if (o2 == null) {\n" + // report always false null check
16358
			"	 if (o2 == null) {\n" + // report always false null check
16354
			"		o2.toString();\n" + // dead code
16359
			"		o2.toString();\n" + // dead code
Lines 16384-16395 Link Here
16384
			"	                ^^^^^^^^^^^^^^^^^^^^^^\n" + 
16389
			"	                ^^^^^^^^^^^^^^^^^^^^^^\n" + 
16385
			"Dead code\n" + 
16390
			"Dead code\n" + 
16386
			"----------\n" + 
16391
			"----------\n" + 
16387
			"6. ERROR in X.java (at line 22)\n" + 
16392
			"6. ERROR in X.java (at line 23)\n" + 
16388
			"	if (o2 == null) {\n" + 
16393
			"	if (o2 == null) {\n" + 
16389
			"	    ^^\n" + 
16394
			"	    ^^\n" + 
16390
			"Null comparison always yields false: The field o2 cannot be null at this location\n" + 
16395
			"Null comparison always yields false: The field o2 cannot be null at this location\n" + 
16391
			"----------\n" + 
16396
			"----------\n" + 
16392
			"7. WARNING in X.java (at line 22)\n" + 
16397
			"7. WARNING in X.java (at line 23)\n" + 
16393
			"	if (o2 == null) {\n" + 
16398
			"	if (o2 == null) {\n" + 
16394
			"		o2.toString();\n" + 
16399
			"		o2.toString();\n" + 
16395
			"	 }\n" + 
16400
			"	 }\n" + 
Lines 16447-16452 Link Here
16447
			"	 if (o1 == null) {\n" +	// report redundant null check
16452
			"	 if (o1 == null) {\n" +	// report redundant null check
16448
			"		o1.toString();\n" + // report NPE
16453
			"		o1.toString();\n" + // report NPE
16449
			"	 }\n" +
16454
			"	 }\n" +
16455
			"    local.toString();\n" + // try to diffuse status for o1 / o2
16450
			"	 o1.toString();\n" +	// already reported NPE above. So silent. Same behaviour as 'local'
16456
			"	 o1.toString();\n" +	// already reported NPE above. So silent. Same behaviour as 'local'
16451
			"	 if (o2 == null) {\n" + // report always false null check
16457
			"	 if (o2 == null) {\n" + // report always false null check
16452
			"		o2.toString();\n" + // dead code
16458
			"		o2.toString();\n" + // dead code
Lines 16477-16488 Link Here
16477
		"	^^\n" + 
16483
		"	^^\n" + 
16478
		"Null pointer access: The field o1 can only be null at this location\n" + 
16484
		"Null pointer access: The field o1 can only be null at this location\n" + 
16479
		"----------\n" + 
16485
		"----------\n" + 
16480
		"5. ERROR in X.java (at line 40)\n" + 
16486
		"5. ERROR in X.java (at line 41)\n" + 
16481
		"	if (o2 == null) {\n" + 
16487
		"	if (o2 == null) {\n" + 
16482
		"	    ^^\n" + 
16488
		"	    ^^\n" + 
16483
		"Null comparison always yields false: The field o2 cannot be null at this location\n" + 
16489
		"Null comparison always yields false: The field o2 cannot be null at this location\n" + 
16484
		"----------\n" + 
16490
		"----------\n" + 
16485
		"6. WARNING in X.java (at line 40)\n" + 
16491
		"6. WARNING in X.java (at line 41)\n" + 
16486
		"	if (o2 == null) {\n" + 
16492
		"	if (o2 == null) {\n" + 
16487
		"		o2.toString();\n" + 
16493
		"		o2.toString();\n" + 
16488
		"	 }\n" + 
16494
		"	 }\n" + 
Lines 16517-16522 Link Here
16517
			"	 if (o1 == null) {\n" +	// report redundant null check
16523
			"	 if (o1 == null) {\n" +	// report redundant null check
16518
			"		o1.toString();\n" + // report NPE
16524
			"		o1.toString();\n" + // report NPE
16519
			"	 }\n" +
16525
			"	 }\n" +
16526
			"    local.toString();\n" + // try to diffuse status for o1 / o2
16520
			"	 o1.toString();\n" +	// already reported NPE above. So silent. Same behaviour as 'local'
16527
			"	 o1.toString();\n" +	// already reported NPE above. So silent. Same behaviour as 'local'
16521
			"	 if (o2 == null) {\n" + // report always false null check
16528
			"	 if (o2 == null) {\n" + // report always false null check
16522
			"		o2.toString();\n" + // dead code
16529
			"		o2.toString();\n" + // dead code
Lines 16547-16558 Link Here
16547
		"	^^\n" + 
16554
		"	^^\n" + 
16548
		"Null pointer access: The field o1 can only be null at this location\n" + 
16555
		"Null pointer access: The field o1 can only be null at this location\n" + 
16549
		"----------\n" + 
16556
		"----------\n" + 
16550
		"5. ERROR in X.java (at line 18)\n" + 
16557
		"5. ERROR in X.java (at line 19)\n" + 
16551
		"	if (o2 == null) {\n" + 
16558
		"	if (o2 == null) {\n" + 
16552
		"	    ^^\n" + 
16559
		"	    ^^\n" + 
16553
		"Null comparison always yields false: The field o2 cannot be null at this location\n" + 
16560
		"Null comparison always yields false: The field o2 cannot be null at this location\n" + 
16554
		"----------\n" + 
16561
		"----------\n" + 
16555
		"6. WARNING in X.java (at line 18)\n" + 
16562
		"6. WARNING in X.java (at line 19)\n" + 
16556
		"	if (o2 == null) {\n" + 
16563
		"	if (o2 == null) {\n" + 
16557
		"		o2.toString();\n" + 
16564
		"		o2.toString();\n" + 
16558
		"	 }\n" + 
16565
		"	 }\n" + 
Lines 17025-17050 Link Here
17025
	);
17032
	);
17026
}
17033
}
17027
17034
17028
// null analysis -- test redundant instanceof warning for static final fields
17029
public void testBug247564e_1() {
17030
	this.runNegativeTest(
17031
		new String[] {
17032
			"X.java",
17033
			"public class X {\n" +
17034
			"  static final Object o = null;\n" +
17035
			"  void foo() {\n" +
17036
			"      if (o instanceof X) return;\n" +
17037
			"  }\n" +
17038
			"}"},
17039
		"----------\n" + 
17040
		"1. ERROR in X.java (at line 4)\n" + 
17041
		"	if (o instanceof X) return;\n" + 
17042
		"	    ^\n" + 
17043
		"instanceof always yields false: The field o can only be null at this location\n" + 
17044
		"----------\n",
17045
		JavacTestOptions.Excuse.EclipseWarningConfiguredAsError);
17046
}
17047
17048
// null analysis -- test potential null ptr access warning because of static field access through object returned by method call
17035
// null analysis -- test potential null ptr access warning because of static field access through object returned by method call
17049
public void testBug247564f() {
17036
public void testBug247564f() {
17050
	Map compilerOptions = getCompilerOptions();
17037
	Map compilerOptions = getCompilerOptions();
Lines 17148-17154 Link Here
17148
			"      if (this.field99 == null && this.field99.hashCode() == 0){}\n" +
17135
			"      if (this.field99 == null && this.field99.hashCode() == 0){}\n" +
17149
			"	   this.field98 = null;\n" +
17136
			"	   this.field98 = null;\n" +
17150
			"	}\n" +
17137
			"	}\n" +
17151
			"	if (this.field98.hashCode() == 0) {}\n" +	// should not complain
17138
			"	if (this.field98.hashCode() == 0) {}\n" +
17152
			"	this.field97 = null;\n" +
17139
			"	this.field97 = null;\n" +
17153
			"	if (this.field97.hashCode() == 0) {}\n" +
17140
			"	if (this.field97.hashCode() == 0) {}\n" +
17154
			"	if (this.field100.hashCode() == 0) {}\n" +
17141
			"	if (this.field100.hashCode() == 0) {}\n" +
Lines 17212-17218 Link Here
17212
}
17199
}
17213
17200
17214
// null analysis -- simple case for field for inner class
17201
// null analysis -- simple case for field for inner class
17215
// to make sure that id's of local variables in inner classes dotn conflict with those of fields.
17202
// to make sure that id's of local variables in inner classes don't conflict with those of fields.
17216
public void testBug247564h_1() {
17203
public void testBug247564h_1() {
17217
	this.runNegativeTest(
17204
	this.runNegativeTest(
17218
		new String[] {
17205
		new String[] {
Lines 17240-17246 Link Here
17240
}
17227
}
17241
17228
17242
// null analysis -- simple case for field for inner class
17229
// null analysis -- simple case for field for inner class
17243
// to make sure that id's of local variables in inner classes dotn conflict with those of fields.
17230
// to make sure that id's of local variables in inner classes don't conflict with those of fields.
17244
public void testBug247564h_2() {
17231
public void testBug247564h_2() {
17245
	this.runNegativeTest(
17232
	this.runNegativeTest(
17246
		new String[] {
17233
		new String[] {
Lines 17254-17267 Link Here
17254
			"	 class X2 {\n" +
17241
			"	 class X2 {\n" +
17255
			"	 	Object field4;\n" +
17242
			"	 	Object field4;\n" +
17256
			"	 	Object field5;\n" +
17243
			"	 	Object field5;\n" +
17257
			"	 void goo(Object var) {\n" +
17244
			"	    void goo(Object var) {\n" +
17258
			"    	if (var == null && field4.toString() == \"\"){}\n" +
17245
			"    	   if (var == null && field4.toString() == \"\"){}\n" +
17259
			"    	if (var == null && field5.toString() == \"\"){}\n" +
17246
			"    	   if (var == null && field5.toString() == \"\"){}\n" +
17260
			"    	if (field3 == null && field3.toString() == \"\"){}\n" +
17247
			"    	   if (field3 == null && field3.toString() == \"\"){}\n" +
17261
			"    	if (field3 == null && field1.toString() == \"\"){}\n" +
17248
			"    	   if (field3 == null && field1.toString() == \"\"){}\n" +
17249
			"       }\n" +
17262
			"    }\n" +
17250
			"    }\n" +
17263
			"    }\n" +
17251
			"    Object field22;\n" +
17264
			"  Object field22;\n" +
17265
			"  }\n" +
17252
			"  }\n" +
17266
			"}\n"},
17253
			"}\n"},
17267
		"----------\n" + 
17254
		"----------\n" + 
Lines 17298-17304 Link Here
17298
			"    	if (X.field0 == null && X.field0.toString() == \"\"){}\n" +   // warn
17285
			"    	if (X.field0 == null && X.field0.toString() == \"\"){}\n" +   // warn
17299
			"    	if (this.field0 == null && X.field0.toString() == \"\"){}\n" +   // warn
17286
			"    	if (this.field0 == null && X.field0.toString() == \"\"){}\n" +   // warn
17300
			"    	if (X.field0 == null && this.field0.toString() == \"\"){}\n" +   // warn
17287
			"    	if (X.field0 == null && this.field0.toString() == \"\"){}\n" +   // warn
17301
			"    	if (X.field0 == null && getX().field0.toString() == \"\"){}\n" +   // no warn
17288
			"    	if (X.field0 == null && getX().field0.toString() == \"\"){}\n" +   // no warn (diffused by getX() call)
17302
			"  }\n" +
17289
			"  }\n" +
17303
			"}\n" +
17290
			"}\n" +
17304
			"class Y{\n" +
17291
			"class Y{\n" +
Lines 17412-17420 Link Here
17412
			"  static Y getY(){ return new Y();}\n" +
17399
			"  static Y getY(){ return new Y();}\n" +
17413
			"  static X getX() { return new X();}\n" +
17400
			"  static X getX() { return new X();}\n" +
17414
			"  static class XInner{\n" +
17401
			"  static class XInner{\n" +
17415
			"   static Object xinnerfield;\n" +
17402
			"    static Object xinnerfield;\n" +
17416
			"   XInner getXInner() { return new XInner();\n}" +
17403
			"    XInner getXInner() { return new XInner();\n}" +
17417
			"   void goo(Object var) {\n" +
17404
			"    void goo(Object var) {\n" +
17418
			"    	if (new Y().getY().yField1 == null && field0.toString() == \"\"){}\n" +  // no warn
17405
			"    	if (new Y().getY().yField1 == null && field0.toString() == \"\"){}\n" +  // no warn
17419
			"    	if (getY().yField1 == null && field0.toString() == \"\"){}\n" +  // no warn
17406
			"    	if (getY().yField1 == null && field0.toString() == \"\"){}\n" +  // no warn
17420
			"    	if (new Y().getX().field0 == null && field0.toString() == \"\"){}\n" +   // warn
17407
			"    	if (new Y().getX().field0 == null && field0.toString() == \"\"){}\n" +   // warn
Lines 17436-17442 Link Here
17436
			"    	if (Y.xiny.field1 == null && Y.yField1.toString() == \"\"){}\n" +  // no warn
17423
			"    	if (Y.xiny.field1 == null && Y.yField1.toString() == \"\"){}\n" +  // no warn
17437
			"    	if (X.field0 == null && X.field0.toString() == \"\"){}\n" +   // warn
17424
			"    	if (X.field0 == null && X.field0.toString() == \"\"){}\n" +   // warn
17438
			"    	if (X.field0 == null && getX().field0.toString() == \"\"){}\n" +   // no warn
17425
			"    	if (X.field0 == null && getX().field0.toString() == \"\"){}\n" +   // no warn
17439
			"   }\n" +
17426
			"    }\n" +
17440
			"  }\n" +
17427
			"  }\n" +
17441
			"}\n" +
17428
			"}\n" +
17442
			"class Y{\n" +
17429
			"class Y{\n" +
Lines 17890-17896 Link Here
17890
	this.runNegativeTest(
17877
	this.runNegativeTest(
17891
		new String[] {
17878
		new String[] {
17892
			"X.java",
17879
			"X.java",
17893
			"class MyException extends Exception{}" +
17880
			"class MyException extends Exception{}\n" +
17894
			"public class X {\n" +
17881
			"public class X {\n" +
17895
			"  private Object f;\n" +
17882
			"  private Object f;\n" +
17896
			"	 void gooCalls() throws MyException{}\n" +
17883
			"	 void gooCalls() throws MyException{}\n" +
Lines 17907-17917 Link Here
17907
			"}\n"},
17894
			"}\n"},
17908
		"----------\n" + 
17895
		"----------\n" + 
17909
		"1. WARNING in X.java (at line 1)\n" + 
17896
		"1. WARNING in X.java (at line 1)\n" + 
17910
		"	class MyException extends Exception{}public class X {\n" + 
17897
		"	class MyException extends Exception{}\n" + 
17911
		"	      ^^^^^^^^^^^\n" + 
17898
		"	      ^^^^^^^^^^^\n" + 
17912
		"The serializable class MyException does not declare a static final serialVersionUID field of type long\n" + 
17899
		"The serializable class MyException does not declare a static final serialVersionUID field of type long\n" + 
17913
		"----------\n" + 
17900
		"----------\n" + 
17914
		"2. ERROR in X.java (at line 11)\n" + 
17901
		"2. ERROR in X.java (at line 12)\n" + 
17915
		"	f.toString();\n" + 
17902
		"	f.toString();\n" + 
17916
		"	^\n" + 
17903
		"	^\n" + 
17917
		"Potential null pointer access: The field f may be null at this location\n" + 
17904
		"Potential null pointer access: The field f may be null at this location\n" + 
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java (-18 / +18 lines)
Lines 39-81 Link Here
39
			// TODO: handle all kinds of expressions (cf. also https://bugs.eclipse.org/364326)
39
			// TODO: handle all kinds of expressions (cf. also https://bugs.eclipse.org/364326)
40
		}
40
		}
41
41
42
		VariableBinding local = this.left.variableBinding(scope);
42
		VariableBinding var = this.left.variableBinding(scope);
43
		if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) {
43
		if (var != null && (var.type.tagBits & TagBits.IsBaseType) == 0) {
44
			checkVariableComparison(scope, flowContext, flowInfo, initsWhenTrue, initsWhenFalse, local, rightStatus, this.left);
44
			checkVariableComparison(scope, flowContext, flowInfo, initsWhenTrue, initsWhenFalse, var, rightStatus, this.left);
45
		}
45
		}
46
		local = this.right.variableBinding(scope);
46
		var = this.right.variableBinding(scope);
47
		if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) {
47
		if (var != null && (var.type.tagBits & TagBits.IsBaseType) == 0) {
48
			checkVariableComparison(scope, flowContext, flowInfo, initsWhenTrue, initsWhenFalse, local, leftStatus, this.right);
48
			checkVariableComparison(scope, flowContext, flowInfo, initsWhenTrue, initsWhenFalse, var, leftStatus, this.right);
49
		}
49
		}
50
	}
50
	}
51
	private void checkVariableComparison(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, FlowInfo initsWhenTrue, FlowInfo initsWhenFalse, VariableBinding local, int nullStatus, Expression reference) {
51
	private void checkVariableComparison(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, FlowInfo initsWhenTrue, FlowInfo initsWhenFalse, VariableBinding var, 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, var, 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(var); // from thereon it is set
58
					initsWhenFalse.markAsComparedEqualToNonNull(local); // from thereon it is set
58
					initsWhenFalse.markAsComparedEqualToNonNull(var); // from thereon it is set
59
				} else {
59
				} else {
60
					flowContext.recordUsingNullReference(scope, local, reference,
60
					flowContext.recordUsingNullReference(scope, var, 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);
62
					initsWhenTrue.markAsComparedEqualToNonNull(local); // from thereon it is set
62
					initsWhenTrue.markAsComparedEqualToNonNull(var); // from thereon it is set
63
					initsWhenFalse.markAsComparedEqualToNull(local); // from thereon it is set
63
					initsWhenFalse.markAsComparedEqualToNull(var); // from thereon it is set
64
				}
64
				}
65
				if ((flowContext.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) != 0) {
65
				if ((flowContext.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) != 0) {
66
					flowInfo.markedAsNullOrNonNullInAssertExpression(local);
66
					flowInfo.markedAsNullOrNonNullInAssertExpression(var);
67
				}
67
				}
68
				break;
68
				break;
69
			case FlowInfo.NON_NULL :
69
			case FlowInfo.NON_NULL :
70
				if (((this.bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL) {
70
				if (((this.bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL) {
71
					flowContext.recordUsingNullReference(scope, local, reference,
71
					flowContext.recordUsingNullReference(scope, var, reference,
72
							FlowContext.CAN_ONLY_NULL | FlowContext.IN_COMPARISON_NON_NULL, flowInfo);
72
							FlowContext.CAN_ONLY_NULL | FlowContext.IN_COMPARISON_NON_NULL, flowInfo);
73
					initsWhenTrue.markAsComparedEqualToNonNull(local); // from thereon it is set
73
					initsWhenTrue.markAsComparedEqualToNonNull(var); // from thereon it is set
74
					if ((flowContext.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) != 0) {
74
					if ((flowContext.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) != 0) {
75
						initsWhenTrue.markedAsNullOrNonNullInAssertExpression(local);
75
						initsWhenTrue.markedAsNullOrNonNullInAssertExpression(var);
76
					}
76
					}
77
				} else {
77
				} else {
78
					flowContext.recordUsingNullReference(scope, local, reference,
78
					flowContext.recordUsingNullReference(scope, var, reference,
79
							FlowContext.CAN_ONLY_NULL | FlowContext.IN_COMPARISON_NULL, flowInfo);
79
							FlowContext.CAN_ONLY_NULL | FlowContext.IN_COMPARISON_NULL, flowInfo);
80
				}
80
				}
81
				break;
81
				break;
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java (-11 / +11 lines)
Lines 526-547 Link Here
526
 * @param flowInfo the upstream flow info; caveat: may get modified
526
 * @param flowInfo the upstream flow info; caveat: may get modified
527
 */
527
 */
528
public void checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo) {
528
public void checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo) {
529
	VariableBinding local = variableBinding(scope);
529
	VariableBinding var = variableBinding(scope);
530
	if (local != null &&
530
	if (var != null &&
531
			(local.type.tagBits & TagBits.IsBaseType) == 0) {
531
			(var.type.tagBits & TagBits.IsBaseType) == 0) {
532
		if ((this.bits & ASTNode.IsNonNull) == 0) {
532
		if ((this.bits & ASTNode.IsNonNull) == 0) {
533
			flowContext.recordUsingNullReference(scope, local, this,
533
			flowContext.recordUsingNullReference(scope, var, this,
534
					FlowContext.MAY_NULL, flowInfo);
534
					FlowContext.MAY_NULL, flowInfo);
535
		}
535
		}
536
		flowInfo.markAsComparedEqualToNonNull(local );
536
		flowInfo.markAsComparedEqualToNonNull(var );
537
			// from thereon it is set
537
			// from thereon it is set
538
		if ((flowContext.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) != 0) {
538
		if ((flowContext.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) != 0) {
539
			flowInfo.markedAsNullOrNonNullInAssertExpression(local);
539
			flowInfo.markedAsNullOrNonNullInAssertExpression(var);
540
		}
540
		}
541
		if (flowContext.initsOnFinally != null) {
541
		if (flowContext.initsOnFinally != null) {
542
			flowContext.initsOnFinally.markAsComparedEqualToNonNull(local);
542
			flowContext.initsOnFinally.markAsComparedEqualToNonNull(var);
543
			if ((flowContext.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) != 0) {
543
			if ((flowContext.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) != 0) {
544
				flowContext.initsOnFinally.markedAsNullOrNonNullInAssertExpression(local);
544
				flowContext.initsOnFinally.markedAsNullOrNonNullInAssertExpression(var);
545
			}
545
			}
546
		}
546
		}
547
	}
547
	}
Lines 873-881 Link Here
873
		this.constant != null && this.constant != Constant.NotAConstant)
873
		this.constant != null && this.constant != Constant.NotAConstant)
874
	return FlowInfo.NON_NULL; // constant expression cannot be null
874
	return FlowInfo.NON_NULL; // constant expression cannot be null
875
875
876
	VariableBinding local = variableBinding(null);
876
	VariableBinding var = variableBinding(null);
877
	if (local != null)
877
	if (var != null)
878
		return flowInfo.nullStatus(local);
878
		return flowInfo.nullStatus(var);
879
	return FlowInfo.NON_NULL;
879
	return FlowInfo.NON_NULL;
880
}
880
}
881
881
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ConditionalFlowInfo.java (-60 / +60 lines)
Lines 80-98 Link Here
80
			&& this.initsWhenFalse.isDefinitelyAssigned(var);
80
			&& this.initsWhenFalse.isDefinitelyAssigned(var);
81
}
81
}
82
82
83
public boolean isDefinitelyNonNull(VariableBinding local) {
83
public boolean isDefinitelyNonNull(VariableBinding var) {
84
	return this.initsWhenTrue.isDefinitelyNonNull(local)
84
	return this.initsWhenTrue.isDefinitelyNonNull(var)
85
			&& this.initsWhenFalse.isDefinitelyNonNull(local);
85
			&& this.initsWhenFalse.isDefinitelyNonNull(var);
86
}
86
}
87
87
88
public boolean isDefinitelyNull(VariableBinding local) {
88
public boolean isDefinitelyNull(VariableBinding var) {
89
	return this.initsWhenTrue.isDefinitelyNull(local)
89
	return this.initsWhenTrue.isDefinitelyNull(var)
90
			&& this.initsWhenFalse.isDefinitelyNull(local);
90
			&& this.initsWhenFalse.isDefinitelyNull(var);
91
}
91
}
92
92
93
public boolean isDefinitelyUnknown(VariableBinding local) {
93
public boolean isDefinitelyUnknown(VariableBinding var) {
94
	return this.initsWhenTrue.isDefinitelyUnknown(local)
94
	return this.initsWhenTrue.isDefinitelyUnknown(var)
95
			&& this.initsWhenFalse.isDefinitelyUnknown(local);
95
			&& this.initsWhenFalse.isDefinitelyUnknown(var);
96
}
96
}
97
97
98
public boolean isPotentiallyAssigned(VariableBinding var) {
98
public boolean isPotentiallyAssigned(VariableBinding var) {
Lines 100-138 Link Here
100
			|| this.initsWhenFalse.isPotentiallyAssigned(var);
100
			|| this.initsWhenFalse.isPotentiallyAssigned(var);
101
}
101
}
102
102
103
public boolean isPotentiallyNonNull(VariableBinding local) {
103
public boolean isPotentiallyNonNull(VariableBinding var) {
104
	return this.initsWhenTrue.isPotentiallyNonNull(local)
104
	return this.initsWhenTrue.isPotentiallyNonNull(var)
105
		|| this.initsWhenFalse.isPotentiallyNonNull(local);
105
		|| this.initsWhenFalse.isPotentiallyNonNull(var);
106
}
106
}
107
107
108
public boolean isPotentiallyNull(VariableBinding local) {
108
public boolean isPotentiallyNull(VariableBinding var) {
109
	return this.initsWhenTrue.isPotentiallyNull(local)
109
	return this.initsWhenTrue.isPotentiallyNull(var)
110
		|| this.initsWhenFalse.isPotentiallyNull(local);
110
		|| this.initsWhenFalse.isPotentiallyNull(var);
111
}
111
}
112
112
113
public boolean isPotentiallyUnknown(VariableBinding local) {
113
public boolean isPotentiallyUnknown(VariableBinding var) {
114
	return this.initsWhenTrue.isPotentiallyUnknown(local)
114
	return this.initsWhenTrue.isPotentiallyUnknown(var)
115
		|| this.initsWhenFalse.isPotentiallyUnknown(local);
115
		|| this.initsWhenFalse.isPotentiallyUnknown(var);
116
}
116
}
117
117
118
public boolean isProtectedNonNull(VariableBinding local) {
118
public boolean isProtectedNonNull(VariableBinding var) {
119
	return this.initsWhenTrue.isProtectedNonNull(local)
119
	return this.initsWhenTrue.isProtectedNonNull(var)
120
		&& this.initsWhenFalse.isProtectedNonNull(local);
120
		&& this.initsWhenFalse.isProtectedNonNull(var);
121
}
121
}
122
122
123
public boolean isProtectedNull(VariableBinding local) {
123
public boolean isProtectedNull(VariableBinding var) {
124
	return this.initsWhenTrue.isProtectedNull(local)
124
	return this.initsWhenTrue.isProtectedNull(var)
125
		&& this.initsWhenFalse.isProtectedNull(local);
125
		&& this.initsWhenFalse.isProtectedNull(var);
126
}
126
}
127
127
128
public void markAsComparedEqualToNonNull(VariableBinding local) {
128
public void markAsComparedEqualToNonNull(VariableBinding var) {
129
	this.initsWhenTrue.markAsComparedEqualToNonNull(local);
129
	this.initsWhenTrue.markAsComparedEqualToNonNull(var);
130
	this.initsWhenFalse.markAsComparedEqualToNonNull(local);
130
	this.initsWhenFalse.markAsComparedEqualToNonNull(var);
131
}
131
}
132
132
133
public void markAsComparedEqualToNull(VariableBinding local) {
133
public void markAsComparedEqualToNull(VariableBinding var) {
134
	this.initsWhenTrue.markAsComparedEqualToNull(local);
134
	this.initsWhenTrue.markAsComparedEqualToNull(var);
135
    this.initsWhenFalse.markAsComparedEqualToNull(local);
135
    this.initsWhenFalse.markAsComparedEqualToNull(var);
136
}
136
}
137
137
138
public void markAsDefinitelyAssigned(VariableBinding var) {
138
public void markAsDefinitelyAssigned(VariableBinding var) {
Lines 140-158 Link Here
140
	this.initsWhenFalse.markAsDefinitelyAssigned(var);
140
	this.initsWhenFalse.markAsDefinitelyAssigned(var);
141
}
141
}
142
142
143
public void markAsDefinitelyNonNull(VariableBinding local) {
143
public void markAsDefinitelyNonNull(VariableBinding var) {
144
	this.initsWhenTrue.markAsDefinitelyNonNull(local);
144
	this.initsWhenTrue.markAsDefinitelyNonNull(var);
145
	this.initsWhenFalse.markAsDefinitelyNonNull(local);
145
	this.initsWhenFalse.markAsDefinitelyNonNull(var);
146
}
146
}
147
147
148
public void markAsDefinitelyNull(VariableBinding local) {
148
public void markAsDefinitelyNull(VariableBinding var) {
149
	this.initsWhenTrue.markAsDefinitelyNull(local);
149
	this.initsWhenTrue.markAsDefinitelyNull(var);
150
	this.initsWhenFalse.markAsDefinitelyNull(local);
150
	this.initsWhenFalse.markAsDefinitelyNull(var);
151
}
151
}
152
152
153
public void resetNullInfo(VariableBinding local) {
153
public void resetNullInfo(VariableBinding var) {
154
	this.initsWhenTrue.resetNullInfo(local);
154
	this.initsWhenTrue.resetNullInfo(var);
155
	this.initsWhenFalse.resetNullInfo(local);
155
	this.initsWhenFalse.resetNullInfo(var);
156
}
156
}
157
157
158
public void resetNullInfoForFields() {
158
public void resetNullInfoForFields() {
Lines 170-193 Link Here
170
	this.initsWhenFalse.addConstantFieldsMask(other);
170
	this.initsWhenFalse.addConstantFieldsMask(other);
171
}
171
}
172
172
173
public void markPotentiallyNullBit(VariableBinding local) {
173
public void markPotentiallyNullBit(VariableBinding var) {
174
	this.initsWhenTrue.markPotentiallyNullBit(local);
174
	this.initsWhenTrue.markPotentiallyNullBit(var);
175
	this.initsWhenFalse.markPotentiallyNullBit(local);
175
	this.initsWhenFalse.markPotentiallyNullBit(var);
176
}
176
}
177
177
178
public void markPotentiallyNonNullBit(VariableBinding local) {
178
public void markPotentiallyNonNullBit(VariableBinding var) {
179
	this.initsWhenTrue.markPotentiallyNonNullBit(local);
179
	this.initsWhenTrue.markPotentiallyNonNullBit(var);
180
	this.initsWhenFalse.markPotentiallyNonNullBit(local);
180
	this.initsWhenFalse.markPotentiallyNonNullBit(var);
181
}
181
}
182
182
183
public void markAsDefinitelyUnknown(VariableBinding local) {
183
public void markAsDefinitelyUnknown(VariableBinding var) {
184
	this.initsWhenTrue.markAsDefinitelyUnknown(local);
184
	this.initsWhenTrue.markAsDefinitelyUnknown(var);
185
	this.initsWhenFalse.markAsDefinitelyUnknown(local);
185
	this.initsWhenFalse.markAsDefinitelyUnknown(var);
186
}
186
}
187
187
188
public void markPotentiallyUnknownBit(VariableBinding local) {
188
public void markPotentiallyUnknownBit(VariableBinding var) {
189
	this.initsWhenTrue.markPotentiallyUnknownBit(local);
189
	this.initsWhenTrue.markPotentiallyUnknownBit(var);
190
	this.initsWhenFalse.markPotentiallyUnknownBit(local);
190
	this.initsWhenFalse.markPotentiallyUnknownBit(var);
191
}
191
}
192
192
193
public FlowInfo setReachMode(int reachMode) {
193
public FlowInfo setReachMode(int reachMode) {
Lines 243-260 Link Here
243
			mergedWith(this.initsWhenFalse.unconditionalInits());
243
			mergedWith(this.initsWhenFalse.unconditionalInits());
244
}
244
}
245
245
246
public void markedAsNullOrNonNullInAssertExpression(VariableBinding local) {
246
public void markedAsNullOrNonNullInAssertExpression(VariableBinding var) {
247
	this.initsWhenTrue.markedAsNullOrNonNullInAssertExpression(local);
247
	this.initsWhenTrue.markedAsNullOrNonNullInAssertExpression(var);
248
	this.initsWhenFalse.markedAsNullOrNonNullInAssertExpression(local);
248
	this.initsWhenFalse.markedAsNullOrNonNullInAssertExpression(var);
249
}
249
}
250
250
251
public boolean isMarkedAsNullOrNonNullInAssertExpression(VariableBinding local) {
251
public boolean isMarkedAsNullOrNonNullInAssertExpression(VariableBinding var) {
252
	return (this.initsWhenTrue.isMarkedAsNullOrNonNullInAssertExpression(local)
252
	return (this.initsWhenTrue.isMarkedAsNullOrNonNullInAssertExpression(var)
253
		|| this.initsWhenFalse.isMarkedAsNullOrNonNullInAssertExpression(local));
253
		|| this.initsWhenFalse.isMarkedAsNullOrNonNullInAssertExpression(var));
254
}
254
}
255
255
256
public void resetAssignmentInfo(LocalVariableBinding local) {
256
public void resetAssignmentInfo(LocalVariableBinding var) {
257
	this.initsWhenTrue.resetAssignmentInfo(local);
257
	this.initsWhenTrue.resetAssignmentInfo(var);
258
	this.initsWhenFalse.resetAssignmentInfo(local);
258
	this.initsWhenFalse.resetAssignmentInfo(var);
259
}
259
}
260
}
260
}
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FinallyFlowContext.java (-66 / +66 lines)
Lines 100-117 Link Here
100
		for (int i = 0; i < this.nullCount; i++) {
100
		for (int i = 0; i < this.nullCount; i++) {
101
			Expression expression = this.nullReferences[i];
101
			Expression expression = this.nullReferences[i];
102
			// final local variable
102
			// final local variable
103
			VariableBinding local = this.nullVariables[i];
103
			VariableBinding var = this.nullVariables[i];
104
			switch (this.nullCheckTypes[i]) {
104
			switch (this.nullCheckTypes[i]) {
105
				case CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NULL:
105
				case CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NULL:
106
				case CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL:
106
				case CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL:
107
					if (flowInfo.isDefinitelyNonNull(local)) {
107
					if (flowInfo.isDefinitelyNonNull(var)) {
108
						if (this.nullCheckTypes[i] == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL)) {
108
						if (this.nullCheckTypes[i] == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL)) {
109
							if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
109
							if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
110
								scope.problemReporter().variableRedundantCheckOnNonNull(local, expression);
110
								scope.problemReporter().variableRedundantCheckOnNonNull(var, expression);
111
							}
111
							}
112
						} else {
112
						} else {
113
							if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
113
							if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
114
								scope.problemReporter().variableNonNullComparedToNull(local, expression);
114
								scope.problemReporter().variableNonNullComparedToNull(var, expression);
115
							}
115
							}
116
						}
116
						}
117
						continue;
117
						continue;
Lines 121-166 Link Here
121
				case CAN_ONLY_NULL | IN_COMPARISON_NON_NULL:
121
				case CAN_ONLY_NULL | IN_COMPARISON_NON_NULL:
122
				case CAN_ONLY_NULL | IN_ASSIGNMENT:
122
				case CAN_ONLY_NULL | IN_ASSIGNMENT:
123
				case CAN_ONLY_NULL | IN_INSTANCEOF:
123
				case CAN_ONLY_NULL | IN_INSTANCEOF:
124
					if (flowInfo.isDefinitelyNull(local)) {
124
					if (flowInfo.isDefinitelyNull(var)) {
125
						switch(this.nullCheckTypes[i] & CONTEXT_MASK) {
125
						switch(this.nullCheckTypes[i] & CONTEXT_MASK) {
126
							case FlowContext.IN_COMPARISON_NULL:
126
							case FlowContext.IN_COMPARISON_NULL:
127
								if (((this.nullCheckTypes[i] & CHECK_MASK) == CAN_ONLY_NULL) && (expression.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
127
								if (((this.nullCheckTypes[i] & CHECK_MASK) == CAN_ONLY_NULL) && (expression.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
128
									scope.problemReporter().variableNullReference(local, expression);
128
									scope.problemReporter().variableNullReference(var, expression);
129
									continue;
129
									continue;
130
								}
130
								}
131
								if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
131
								if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
132
									scope.problemReporter().variableRedundantCheckOnNull(local, expression);
132
									scope.problemReporter().variableRedundantCheckOnNull(var, expression);
133
								}
133
								}
134
								continue;
134
								continue;
135
							case FlowContext.IN_COMPARISON_NON_NULL:
135
							case FlowContext.IN_COMPARISON_NON_NULL:
136
								if (((this.nullCheckTypes[i] & CHECK_MASK) == CAN_ONLY_NULL) && (expression.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
136
								if (((this.nullCheckTypes[i] & CHECK_MASK) == CAN_ONLY_NULL) && (expression.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
137
									scope.problemReporter().variableNullReference(local, expression);
137
									scope.problemReporter().variableNullReference(var, expression);
138
									continue;
138
									continue;
139
								}
139
								}
140
								if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
140
								if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
141
									scope.problemReporter().variableNullComparedToNonNull(local, expression);
141
									scope.problemReporter().variableNullComparedToNonNull(var, expression);
142
								}
142
								}
143
								continue;
143
								continue;
144
							case FlowContext.IN_ASSIGNMENT:
144
							case FlowContext.IN_ASSIGNMENT:
145
								scope.problemReporter().variableRedundantNullAssignment(local, expression);
145
								scope.problemReporter().variableRedundantNullAssignment(var, expression);
146
								continue;
146
								continue;
147
							case FlowContext.IN_INSTANCEOF:
147
							case FlowContext.IN_INSTANCEOF:
148
								scope.problemReporter().variableNullInstanceof(local, expression);
148
								scope.problemReporter().variableNullInstanceof(var, expression);
149
								continue;
149
								continue;
150
						}
150
						}
151
					} else if (flowInfo.isPotentiallyNull(local)) {
151
					} else if (flowInfo.isPotentiallyNull(var)) {
152
						switch(this.nullCheckTypes[i] & CONTEXT_MASK) {
152
						switch(this.nullCheckTypes[i] & CONTEXT_MASK) {
153
							case FlowContext.IN_COMPARISON_NULL:
153
							case FlowContext.IN_COMPARISON_NULL:
154
								this.nullReferences[i] = null;
154
								this.nullReferences[i] = null;
155
								if (((this.nullCheckTypes[i] & CHECK_MASK) == CAN_ONLY_NULL) && (expression.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
155
								if (((this.nullCheckTypes[i] & CHECK_MASK) == CAN_ONLY_NULL) && (expression.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
156
									scope.problemReporter().variablePotentialNullReference(local, expression);
156
									scope.problemReporter().variablePotentialNullReference(var, expression);
157
									continue;
157
									continue;
158
								}
158
								}
159
								break;
159
								break;
160
							case FlowContext.IN_COMPARISON_NON_NULL:
160
							case FlowContext.IN_COMPARISON_NON_NULL:
161
								this.nullReferences[i] = null;
161
								this.nullReferences[i] = null;
162
								if (((this.nullCheckTypes[i] & CHECK_MASK) == CAN_ONLY_NULL) && (expression.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
162
								if (((this.nullCheckTypes[i] & CHECK_MASK) == CAN_ONLY_NULL) && (expression.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
163
									scope.problemReporter().variablePotentialNullReference(local, expression);
163
									scope.problemReporter().variablePotentialNullReference(var, expression);
164
									continue;
164
									continue;
165
								}
165
								}
166
								break;
166
								break;
Lines 168-183 Link Here
168
					}
168
					}
169
					break;
169
					break;
170
				case MAY_NULL:
170
				case MAY_NULL:
171
					if (flowInfo.isDefinitelyNull(local)) {
171
					if (flowInfo.isDefinitelyNull(var)) {
172
						scope.problemReporter().variableNullReference(local, expression);
172
						scope.problemReporter().variableNullReference(var, expression);
173
						continue;
173
						continue;
174
					}
174
					}
175
					if (flowInfo.isPotentiallyNull(local)) {
175
					if (flowInfo.isPotentiallyNull(var)) {
176
						scope.problemReporter().variablePotentialNullReference(local, expression);
176
						scope.problemReporter().variablePotentialNullReference(var, expression);
177
					}
177
					}
178
					break;
178
					break;
179
				case ASSIGN_TO_NONNULL:
179
				case ASSIGN_TO_NONNULL:
180
					int nullStatus = flowInfo.nullStatus(local);
180
					int nullStatus = flowInfo.nullStatus(var);
181
					if (nullStatus != FlowInfo.NON_NULL) {
181
					if (nullStatus != FlowInfo.NON_NULL) {
182
						char[][] annotationName = scope.environment().getNonNullAnnotationName();
182
						char[][] annotationName = scope.environment().getNonNullAnnotationName();
183
						scope.problemReporter().nullityMismatch(expression, this.expectedTypes[i], nullStatus, annotationName);
183
						scope.problemReporter().nullityMismatch(expression, this.expectedTypes[i], nullStatus, annotationName);
Lines 228-236 Link Here
228
		return true;
228
		return true;
229
	}
229
	}
230
230
231
	public void recordUsingNullReference(Scope scope, VariableBinding local,
231
	public void recordUsingNullReference(Scope scope, VariableBinding var,
232
			Expression reference, int checkType, FlowInfo flowInfo) {
232
			Expression reference, int checkType, FlowInfo flowInfo) {
233
		if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0 && !flowInfo.isDefinitelyUnknown(local))	{
233
		if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0 && !flowInfo.isDefinitelyUnknown(var))	{
234
			if ((this.tagBits & FlowContext.DEFER_NULL_DIAGNOSTIC) != 0) { // within an enclosing loop, be conservative
234
			if ((this.tagBits & FlowContext.DEFER_NULL_DIAGNOSTIC) != 0) { // within an enclosing loop, be conservative
235
				switch (checkType) {
235
				switch (checkType) {
236
					case CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NULL:
236
					case CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NULL:
Lines 239-306 Link Here
239
					case CAN_ONLY_NULL | IN_COMPARISON_NON_NULL:
239
					case CAN_ONLY_NULL | IN_COMPARISON_NON_NULL:
240
					case CAN_ONLY_NULL | IN_ASSIGNMENT:
240
					case CAN_ONLY_NULL | IN_ASSIGNMENT:
241
					case CAN_ONLY_NULL | IN_INSTANCEOF:
241
					case CAN_ONLY_NULL | IN_INSTANCEOF:
242
						if (flowInfo.cannotBeNull(local)) {
242
						if (flowInfo.cannotBeNull(var)) {
243
							if (checkType == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL)) {
243
							if (checkType == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL)) {
244
								if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
244
								if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
245
									scope.problemReporter().variableRedundantCheckOnNonNull(local, reference);
245
									scope.problemReporter().variableRedundantCheckOnNonNull(var, reference);
246
								}
246
								}
247
								if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) {
247
								if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(var)) {
248
									flowInfo.initsWhenFalse().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
248
									flowInfo.initsWhenFalse().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
249
								}
249
								}
250
							} else if (checkType == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NULL)) {
250
							} else if (checkType == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NULL)) {
251
								if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
251
								if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
252
									scope.problemReporter().variableNonNullComparedToNull(local, reference);
252
									scope.problemReporter().variableNonNullComparedToNull(var, reference);
253
								}
253
								}
254
								if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) {
254
								if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(var)) {
255
									flowInfo.initsWhenTrue().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
255
									flowInfo.initsWhenTrue().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
256
								}
256
								}
257
							}
257
							}
258
							return;
258
							return;
259
						}
259
						}
260
						if (flowInfo.canOnlyBeNull(local)) {
260
						if (flowInfo.canOnlyBeNull(var)) {
261
							switch(checkType & CONTEXT_MASK) {
261
							switch(checkType & CONTEXT_MASK) {
262
								case FlowContext.IN_COMPARISON_NULL:
262
								case FlowContext.IN_COMPARISON_NULL:
263
									if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
263
									if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
264
										scope.problemReporter().variableNullReference(local, reference);
264
										scope.problemReporter().variableNullReference(var, reference);
265
										return;
265
										return;
266
									}
266
									}
267
									if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
267
									if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
268
										scope.problemReporter().variableRedundantCheckOnNull(local, reference);
268
										scope.problemReporter().variableRedundantCheckOnNull(var, reference);
269
									}
269
									}
270
									if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) {
270
									if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(var)) {
271
										flowInfo.initsWhenFalse().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
271
										flowInfo.initsWhenFalse().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
272
									}
272
									}
273
									return;
273
									return;
274
								case FlowContext.IN_COMPARISON_NON_NULL:
274
								case FlowContext.IN_COMPARISON_NON_NULL:
275
									if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
275
									if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
276
										scope.problemReporter().variableNullReference(local, reference);
276
										scope.problemReporter().variableNullReference(var, reference);
277
										return;
277
										return;
278
									}
278
									}
279
									if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
279
									if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
280
										scope.problemReporter().variableNullComparedToNonNull(local, reference);
280
										scope.problemReporter().variableNullComparedToNonNull(var, reference);
281
									}
281
									}
282
									if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) {
282
									if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(var)) {
283
										flowInfo.initsWhenTrue().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
283
										flowInfo.initsWhenTrue().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
284
									}
284
									}
285
									return;
285
									return;
286
								case FlowContext.IN_ASSIGNMENT:
286
								case FlowContext.IN_ASSIGNMENT:
287
									scope.problemReporter().variableRedundantNullAssignment(local, reference);
287
									scope.problemReporter().variableRedundantNullAssignment(var, reference);
288
									return;
288
									return;
289
								case FlowContext.IN_INSTANCEOF:
289
								case FlowContext.IN_INSTANCEOF:
290
									scope.problemReporter().variableNullInstanceof(local, reference);
290
									scope.problemReporter().variableNullInstanceof(var, reference);
291
									return;
291
									return;
292
							}
292
							}
293
						} else if (flowInfo.isPotentiallyNull(local)) {
293
						} else if (flowInfo.isPotentiallyNull(var)) {
294
							switch(checkType & CONTEXT_MASK) {
294
							switch(checkType & CONTEXT_MASK) {
295
								case FlowContext.IN_COMPARISON_NULL:
295
								case FlowContext.IN_COMPARISON_NULL:
296
									if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
296
									if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
297
										scope.problemReporter().variablePotentialNullReference(local, reference);
297
										scope.problemReporter().variablePotentialNullReference(var, reference);
298
										return;
298
										return;
299
									}
299
									}
300
									break;
300
									break;
301
								case FlowContext.IN_COMPARISON_NON_NULL:
301
								case FlowContext.IN_COMPARISON_NON_NULL:
302
									if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
302
									if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
303
										scope.problemReporter().variablePotentialNullReference(local, reference);
303
										scope.problemReporter().variablePotentialNullReference(var, reference);
304
										return;
304
										return;
305
									}
305
									}
306
									break;
306
									break;
Lines 308-318 Link Here
308
						}
308
						}
309
						break;
309
						break;
310
					case MAY_NULL :
310
					case MAY_NULL :
311
						if (flowInfo.cannotBeNull(local)) {
311
						if (flowInfo.cannotBeNull(var)) {
312
							return;
312
							return;
313
						}
313
						}
314
						if (flowInfo.canOnlyBeNull(local)) {
314
						if (flowInfo.canOnlyBeNull(var)) {
315
							scope.problemReporter().variableNullReference(local, reference);
315
							scope.problemReporter().variableNullReference(var, reference);
316
							return;
316
							return;
317
						}
317
						}
318
						break;
318
						break;
Lines 324-342 Link Here
324
				switch (checkType) {
324
				switch (checkType) {
325
					case CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NULL:
325
					case CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NULL:
326
					case CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL:
326
					case CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL:
327
						if (flowInfo.isDefinitelyNonNull(local)) {
327
						if (flowInfo.isDefinitelyNonNull(var)) {
328
							if (checkType == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL)) {
328
							if (checkType == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL)) {
329
								if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
329
								if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
330
									scope.problemReporter().variableRedundantCheckOnNonNull(local, reference);
330
									scope.problemReporter().variableRedundantCheckOnNonNull(var, reference);
331
								}
331
								}
332
								if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) {
332
								if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(var)) {
333
									flowInfo.initsWhenFalse().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
333
									flowInfo.initsWhenFalse().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
334
								}
334
								}
335
							} else {
335
							} else {
336
								if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
336
								if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
337
									scope.problemReporter().variableNonNullComparedToNull(local, reference);
337
									scope.problemReporter().variableNonNullComparedToNull(var, reference);
338
								}
338
								}
339
								if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) {
339
								if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(var)) {
340
									flowInfo.initsWhenTrue().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
340
									flowInfo.initsWhenTrue().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
341
								}
341
								}
342
							}
342
							}
Lines 347-396 Link Here
347
					case CAN_ONLY_NULL | IN_COMPARISON_NON_NULL:
347
					case CAN_ONLY_NULL | IN_COMPARISON_NON_NULL:
348
					case CAN_ONLY_NULL | IN_ASSIGNMENT:
348
					case CAN_ONLY_NULL | IN_ASSIGNMENT:
349
					case CAN_ONLY_NULL | IN_INSTANCEOF:
349
					case CAN_ONLY_NULL | IN_INSTANCEOF:
350
						if (flowInfo.isDefinitelyNull(local)) {
350
						if (flowInfo.isDefinitelyNull(var)) {
351
							switch(checkType & CONTEXT_MASK) {
351
							switch(checkType & CONTEXT_MASK) {
352
								case FlowContext.IN_COMPARISON_NULL:
352
								case FlowContext.IN_COMPARISON_NULL:
353
									if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
353
									if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
354
										scope.problemReporter().variableNullReference(local, reference);
354
										scope.problemReporter().variableNullReference(var, reference);
355
										return;
355
										return;
356
									}
356
									}
357
									if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
357
									if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
358
										scope.problemReporter().variableRedundantCheckOnNull(local, reference);
358
										scope.problemReporter().variableRedundantCheckOnNull(var, reference);
359
									}
359
									}
360
									if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) {
360
									if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(var)) {
361
										flowInfo.initsWhenFalse().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
361
										flowInfo.initsWhenFalse().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
362
									}
362
									}
363
									return;
363
									return;
364
								case FlowContext.IN_COMPARISON_NON_NULL:
364
								case FlowContext.IN_COMPARISON_NON_NULL:
365
									if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
365
									if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
366
										scope.problemReporter().variableNullReference(local, reference);
366
										scope.problemReporter().variableNullReference(var, reference);
367
										return;
367
										return;
368
									}
368
									}
369
									if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
369
									if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) {
370
										scope.problemReporter().variableNullComparedToNonNull(local, reference);
370
										scope.problemReporter().variableNullComparedToNonNull(var, reference);
371
									}
371
									}
372
									if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(local)) {
372
									if (!flowInfo.isMarkedAsNullOrNonNullInAssertExpression(var)) {
373
										flowInfo.initsWhenTrue().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
373
										flowInfo.initsWhenTrue().setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS);
374
									}
374
									}
375
									return;
375
									return;
376
								case FlowContext.IN_ASSIGNMENT:
376
								case FlowContext.IN_ASSIGNMENT:
377
									scope.problemReporter().variableRedundantNullAssignment(local, reference);
377
									scope.problemReporter().variableRedundantNullAssignment(var, reference);
378
									return;
378
									return;
379
								case FlowContext.IN_INSTANCEOF:
379
								case FlowContext.IN_INSTANCEOF:
380
									scope.problemReporter().variableNullInstanceof(local, reference);
380
									scope.problemReporter().variableNullInstanceof(var, reference);
381
									return;
381
									return;
382
							}
382
							}
383
						} else if (flowInfo.isPotentiallyNull(local)) {
383
						} else if (flowInfo.isPotentiallyNull(var)) {
384
							switch(checkType & CONTEXT_MASK) {
384
							switch(checkType & CONTEXT_MASK) {
385
								case FlowContext.IN_COMPARISON_NULL:
385
								case FlowContext.IN_COMPARISON_NULL:
386
									if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
386
									if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
387
										scope.problemReporter().variablePotentialNullReference(local, reference);
387
										scope.problemReporter().variablePotentialNullReference(var, reference);
388
										return;
388
										return;
389
									}
389
									}
390
									break;
390
									break;
391
								case FlowContext.IN_COMPARISON_NON_NULL:
391
								case FlowContext.IN_COMPARISON_NON_NULL:
392
									if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
392
									if (((checkType & CHECK_MASK) == CAN_ONLY_NULL) && (reference.implicitConversion & TypeIds.UNBOXING) != 0) { // check for auto-unboxing first and report appropriate warning
393
										scope.problemReporter().variablePotentialNullReference(local, reference);
393
										scope.problemReporter().variablePotentialNullReference(var, reference);
394
										return;
394
										return;
395
									}
395
									}
396
									break;
396
									break;
Lines 398-412 Link Here
398
						}
398
						}
399
						break;
399
						break;
400
					case MAY_NULL :
400
					case MAY_NULL :
401
						if (flowInfo.isDefinitelyNull(local)) {
401
						if (flowInfo.isDefinitelyNull(var)) {
402
							scope.problemReporter().variableNullReference(local, reference);
402
							scope.problemReporter().variableNullReference(var, reference);
403
							return;
403
							return;
404
						}
404
						}
405
						if (flowInfo.isPotentiallyNull(local)) {
405
						if (flowInfo.isPotentiallyNull(var)) {
406
							scope.problemReporter().variablePotentialNullReference(local, reference);
406
							scope.problemReporter().variablePotentialNullReference(var, reference);
407
							return;
407
							return;
408
						}
408
						}
409
						if (flowInfo.isDefinitelyNonNull(local)) {
409
						if (flowInfo.isDefinitelyNonNull(var)) {
410
							return; // shortcut: cannot be null
410
							return; // shortcut: cannot be null
411
						}
411
						}
412
						break;
412
						break;
Lines 419-425 Link Here
419
			if(((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) || checkType == MAY_NULL
419
			if(((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) == 0) || checkType == MAY_NULL
420
					|| (checkType & CONTEXT_MASK) == FlowContext.IN_ASSIGNMENT
420
					|| (checkType & CONTEXT_MASK) == FlowContext.IN_ASSIGNMENT
421
					|| (checkType & CONTEXT_MASK) == FlowContext.IN_INSTANCEOF) {
421
					|| (checkType & CONTEXT_MASK) == FlowContext.IN_INSTANCEOF) {
422
				recordNullReference(local, reference, checkType);
422
				recordNullReference(var, reference, checkType);
423
			}
423
			}
424
			// prepare to re-check with try/catch flow info
424
			// prepare to re-check with try/catch flow info
425
		}
425
		}
Lines 435-441 Link Here
435
		}
435
		}
436
	}
436
	}
437
437
438
protected void recordNullReference(VariableBinding local,
438
protected void recordNullReference(VariableBinding var,
439
	Expression expression, int status) {
439
	Expression expression, int status) {
440
	if (this.nullCount == 0) {
440
	if (this.nullCount == 0) {
441
		this.nullVariables = new VariableBinding[5];
441
		this.nullVariables = new VariableBinding[5];
Lines 454-460 Link Here
454
			this.nullCheckTypes = new int[newLength], 0,
454
			this.nullCheckTypes = new int[newLength], 0,
455
			this.nullCount);
455
			this.nullCount);
456
	}
456
	}
457
	this.nullVariables[this.nullCount] = local;
457
	this.nullVariables[this.nullCount] = var;
458
	this.nullReferences[this.nullCount] = expression;
458
	this.nullReferences[this.nullCount] = expression;
459
	this.nullCheckTypes[this.nullCount++] = status;
459
	this.nullCheckTypes[this.nullCount++] = status;
460
}
460
}
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowInfo.java (-1 / +1 lines)
Lines 277-283 Link Here
277
	/**
277
	/**
278
	 *  variant of {@link #resetNullInfo(VariableBinding)} for resetting null info for all fields
278
	 *  variant of {@link #resetNullInfo(VariableBinding)} for resetting null info for all fields
279
	 *  Note that each fields status after the reset will become def. unknown i.e. 1001
279
	 *  Note that each fields status after the reset will become def. unknown i.e. 1001
280
	 *  Also this method does not reset constant fields, which are identified by {@link #constantFieldsMask}
280
	 *  Also this method does not reset constant fields
281
	 */
281
	 */
282
	abstract public void resetNullInfoForFields();
282
	abstract public void resetNullInfoForFields();
283
	
283
	
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java (-73 / +73 lines)
Lines 525-536 Link Here
525
	return this;
525
	return this;
526
}
526
}
527
527
528
final public boolean cannotBeDefinitelyNullOrNonNull(VariableBinding local) {
528
final public boolean cannotBeDefinitelyNullOrNonNull(VariableBinding var) {
529
	if ((this.tagBits & NULL_FLAG_MASK) == 0 ||
529
	if ((this.tagBits & NULL_FLAG_MASK) == 0 ||
530
			(local.type.tagBits & TagBits.IsBaseType) != 0) {
530
			(var.type.tagBits & TagBits.IsBaseType) != 0) {
531
		return false;
531
		return false;
532
	}
532
	}
533
	int position = local.getAnalysisId(this.maxFieldCount);
533
	int position = var.getAnalysisId(this.maxFieldCount);
534
	if (position < BitCacheSize) {
534
	if (position < BitCacheSize) {
535
		// use bits
535
		// use bits
536
		return (
536
		return (
Lines 556-567 Link Here
556
		    & (1L << (position % BitCacheSize))) != 0;
556
		    & (1L << (position % BitCacheSize))) != 0;
557
}
557
}
558
558
559
final public boolean cannotBeNull(VariableBinding local) {
559
final public boolean cannotBeNull(VariableBinding var) {
560
	if ((this.tagBits & NULL_FLAG_MASK) == 0 ||
560
	if ((this.tagBits & NULL_FLAG_MASK) == 0 ||
561
			(local.type.tagBits & TagBits.IsBaseType) != 0) {
561
			(var.type.tagBits & TagBits.IsBaseType) != 0) {
562
		return false;
562
		return false;
563
	}
563
	}
564
	int position = local.getAnalysisId(this.maxFieldCount);
564
	int position = var.getAnalysisId(this.maxFieldCount);
565
	if (position < BitCacheSize) {
565
	if (position < BitCacheSize) {
566
		// use bits
566
		// use bits
567
		return (this.nullBit1 & this.nullBit3
567
		return (this.nullBit1 & this.nullBit3
Lines 583-594 Link Here
583
		    & (1L << (position % BitCacheSize))) != 0;
583
		    & (1L << (position % BitCacheSize))) != 0;
584
}
584
}
585
585
586
final public boolean canOnlyBeNull(VariableBinding local) {
586
final public boolean canOnlyBeNull(VariableBinding var) {
587
	if ((this.tagBits & NULL_FLAG_MASK) == 0 ||
587
	if ((this.tagBits & NULL_FLAG_MASK) == 0 ||
588
			(local.type.tagBits & TagBits.IsBaseType) != 0) {
588
			(var.type.tagBits & TagBits.IsBaseType) != 0) {
589
		return false;
589
		return false;
590
	}
590
	}
591
	int position = local.getAnalysisId(this.maxFieldCount);
591
	int position = var.getAnalysisId(this.maxFieldCount);
592
	if (position < BitCacheSize) {
592
	if (position < BitCacheSize) {
593
		// use bits
593
		// use bits
594
		return (this.nullBit1 & this.nullBit2
594
		return (this.nullBit1 & this.nullBit2
Lines 749-760 Link Here
749
	return isDefinitelyAssigned(field.getAnalysisId(this.maxFieldCount));
749
	return isDefinitelyAssigned(field.getAnalysisId(this.maxFieldCount));
750
}
750
}
751
751
752
final public boolean isDefinitelyAssigned(LocalVariableBinding local) {
752
final public boolean isDefinitelyAssigned(LocalVariableBinding var) {
753
	// do not want to complain in unreachable code if local declared in reachable code
753
	// do not want to complain in unreachable code if local declared in reachable code
754
	if ((this.tagBits & UNREACHABLE_OR_DEAD) != 0 && (local.declaration.bits & ASTNode.IsLocalDeclarationReachable) != 0) {
754
	if ((this.tagBits & UNREACHABLE_OR_DEAD) != 0 && (var.declaration.bits & ASTNode.IsLocalDeclarationReachable) != 0) {
755
		return true;
755
		return true;
756
	}
756
	}
757
	return isDefinitelyAssigned(local.id + this.maxFieldCount);
757
	return isDefinitelyAssigned(var.id + this.maxFieldCount);
758
}
758
}
759
759
760
final public boolean isDefinitelyAssigned(VariableBinding var) {
760
final public boolean isDefinitelyAssigned(VariableBinding var) {
Lines 765-772 Link Here
765
	}
765
	}
766
}
766
}
767
767
768
final public boolean isDefinitelyNonNull(VariableBinding local) {
768
final public boolean isDefinitelyNonNull(VariableBinding var) {
769
	boolean isField = local instanceof FieldBinding;
769
	boolean isField = var instanceof FieldBinding;
770
	if (isField && (this.tagBits & NULL_FLAG_MASK) == 0) {
770
	if (isField && (this.tagBits & NULL_FLAG_MASK) == 0) {
771
		// no local yet in scope. Came here because of a field being queried for non null
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
772
		// will only happen for final fields, since they are assigned in a constructor or static block
Lines 778-788 Link Here
778
			(this.tagBits & NULL_FLAG_MASK) == 0) {
778
			(this.tagBits & NULL_FLAG_MASK) == 0) {
779
		return false;
779
		return false;
780
	}
780
	}
781
	if ((local.type.tagBits & TagBits.IsBaseType) != 0 ||
781
	if ((var.type.tagBits & TagBits.IsBaseType) != 0 ||
782
			local.constant() != Constant.NotAConstant) { // String instances
782
			var.constant() != Constant.NotAConstant) { // String instances
783
		return true;
783
		return true;
784
	}
784
	}
785
	int position = local.getAnalysisId(this.maxFieldCount);
785
	int position = var.getAnalysisId(this.maxFieldCount);
786
	if (position < BitCacheSize) { // use bits
786
	if (position < BitCacheSize) { // use bits
787
		return ((this.nullBit1 & this.nullBit3 & (~this.nullBit2 | this.nullBit4))
787
		return ((this.nullBit1 & this.nullBit3 & (~this.nullBit2 | this.nullBit4))
788
			    & (1L << position)) != 0;
788
			    & (1L << position)) != 0;
Lines 801-808 Link Here
801
		    & (1L << (position % BitCacheSize))) != 0;
801
		    & (1L << (position % BitCacheSize))) != 0;
802
}
802
}
803
803
804
final public boolean isDefinitelyNull(VariableBinding local) {
804
final public boolean isDefinitelyNull(VariableBinding var) {
805
	boolean isField = local instanceof FieldBinding;
805
	boolean isField = var instanceof FieldBinding;
806
	if (isField && (this.tagBits & NULL_FLAG_MASK) == 0) {
806
	if (isField && (this.tagBits & NULL_FLAG_MASK) == 0) {
807
		// no local yet in scope. Came here because of a field being queried for non null
807
		// no local yet in scope. Came here because of a field being queried for non null
808
		// will only happen for final fields, since they are assigned in a constructor or static block
808
		// will only happen for final fields, since they are assigned in a constructor or static block
Lines 812-821 Link Here
812
	// do not want to complain in unreachable code
812
	// do not want to complain in unreachable code
813
	if ((this.tagBits & UNREACHABLE) != 0 ||
813
	if ((this.tagBits & UNREACHABLE) != 0 ||
814
			(this.tagBits & NULL_FLAG_MASK) == 0 ||
814
			(this.tagBits & NULL_FLAG_MASK) == 0 ||
815
			(local.type.tagBits & TagBits.IsBaseType) != 0) {
815
			(var.type.tagBits & TagBits.IsBaseType) != 0) {
816
		return false;
816
		return false;
817
	}
817
	}
818
	int position = local.getAnalysisId(this.maxFieldCount);
818
	int position = var.getAnalysisId(this.maxFieldCount);
819
	if (position < BitCacheSize) { // use bits
819
	if (position < BitCacheSize) { // use bits
820
		return ((this.nullBit1 & this.nullBit2
820
		return ((this.nullBit1 & this.nullBit2
821
			        & (~this.nullBit3 | ~this.nullBit4))
821
			        & (~this.nullBit3 | ~this.nullBit4))
Lines 835-847 Link Here
835
		    & (1L << (position % BitCacheSize))) != 0;
835
		    & (1L << (position % BitCacheSize))) != 0;
836
}
836
}
837
837
838
final public boolean isDefinitelyUnknown(VariableBinding local) {
838
final public boolean isDefinitelyUnknown(VariableBinding var) {
839
	// do not want to complain in unreachable code
839
	// do not want to complain in unreachable code
840
	if ((this.tagBits & UNREACHABLE) != 0 ||
840
	if ((this.tagBits & UNREACHABLE) != 0 ||
841
			(this.tagBits & NULL_FLAG_MASK) == 0) {
841
			(this.tagBits & NULL_FLAG_MASK) == 0) {
842
		return false;
842
		return false;
843
	}
843
	}
844
	int position = local.getAnalysisId(this.maxFieldCount);
844
	int position = var.getAnalysisId(this.maxFieldCount);
845
	if (position < BitCacheSize) { // use bits
845
	if (position < BitCacheSize) { // use bits
846
		return ((this.nullBit1 & this.nullBit4
846
		return ((this.nullBit1 & this.nullBit4
847
				& ~this.nullBit2 & ~this.nullBit3) & (1L << position)) != 0;
847
				& ~this.nullBit2 & ~this.nullBit3) & (1L << position)) != 0;
Lines 903-914 Link Here
903
}
903
}
904
904
905
// TODO (Ayush) Check why this method does not return true for protected non null (1111)
905
// TODO (Ayush) Check why this method does not return true for protected non null (1111)
906
final public boolean isPotentiallyNonNull(VariableBinding local) {
906
final public boolean isPotentiallyNonNull(VariableBinding var) {
907
	if ((this.tagBits & NULL_FLAG_MASK) == 0 ||
907
	if ((this.tagBits & NULL_FLAG_MASK) == 0 ||
908
			(local.type.tagBits & TagBits.IsBaseType) != 0) {
908
			(var.type.tagBits & TagBits.IsBaseType) != 0) {
909
		return false;
909
		return false;
910
	}
910
	}
911
	int position = local.getAnalysisId(this.maxFieldCount);
911
	int position = var.getAnalysisId(this.maxFieldCount);
912
	if (position < BitCacheSize) { // use bits
912
	if (position < BitCacheSize) { // use bits
913
		// use bits
913
		// use bits
914
		return ((this.nullBit3 & (~this.nullBit1 | ~this.nullBit2))
914
		return ((this.nullBit3 & (~this.nullBit1 | ~this.nullBit2))
Lines 929-940 Link Here
929
}
929
}
930
930
931
// TODO (Ayush) Check why this method does not return true for protected null
931
// TODO (Ayush) Check why this method does not return true for protected null
932
final public boolean isPotentiallyNull(VariableBinding local) {
932
final public boolean isPotentiallyNull(VariableBinding var) {
933
	if ((this.tagBits & NULL_FLAG_MASK) == 0 ||
933
	if ((this.tagBits & NULL_FLAG_MASK) == 0 ||
934
			(local.type.tagBits & TagBits.IsBaseType) != 0) {
934
			(var.type.tagBits & TagBits.IsBaseType) != 0) {
935
		return false;
935
		return false;
936
	}
936
	}
937
	int position = local.getAnalysisId(this.maxFieldCount);
937
	int position = var.getAnalysisId(this.maxFieldCount);
938
	if (position < BitCacheSize) {
938
	if (position < BitCacheSize) {
939
		// use bits
939
		// use bits
940
		return ((this.nullBit2 & (~this.nullBit1 | ~this.nullBit3))
940
		return ((this.nullBit2 & (~this.nullBit1 | ~this.nullBit3))
Lines 954-966 Link Here
954
		    & (1L << (position % BitCacheSize))) != 0;
954
		    & (1L << (position % BitCacheSize))) != 0;
955
}
955
}
956
956
957
final public boolean isPotentiallyUnknown(VariableBinding local) {
957
final public boolean isPotentiallyUnknown(VariableBinding var) {
958
	// do not want to complain in unreachable code
958
	// do not want to complain in unreachable code
959
	if ((this.tagBits & UNREACHABLE) != 0 ||
959
	if ((this.tagBits & UNREACHABLE) != 0 ||
960
			(this.tagBits & NULL_FLAG_MASK) == 0) {
960
			(this.tagBits & NULL_FLAG_MASK) == 0) {
961
		return false;
961
		return false;
962
	}
962
	}
963
	int position = local.getAnalysisId(this.maxFieldCount);
963
	int position = var.getAnalysisId(this.maxFieldCount);
964
	if (position < BitCacheSize) { // use bits
964
	if (position < BitCacheSize) { // use bits
965
		return (this.nullBit4
965
		return (this.nullBit4
966
			& (~this.nullBit1 | ~this.nullBit2 & ~this.nullBit3)
966
			& (~this.nullBit1 | ~this.nullBit2 & ~this.nullBit3)
Lines 981-992 Link Here
981
		    & (1L << (position % BitCacheSize))) != 0;
981
		    & (1L << (position % BitCacheSize))) != 0;
982
}
982
}
983
983
984
final public boolean isProtectedNonNull(VariableBinding local) {
984
final public boolean isProtectedNonNull(VariableBinding var) {
985
	if ((this.tagBits & NULL_FLAG_MASK) == 0 ||
985
	if ((this.tagBits & NULL_FLAG_MASK) == 0 ||
986
			(local.type.tagBits & TagBits.IsBaseType) != 0) {
986
			(var.type.tagBits & TagBits.IsBaseType) != 0) {
987
		return false;
987
		return false;
988
	}
988
	}
989
	int position = local.getAnalysisId(this.maxFieldCount);
989
	int position = var.getAnalysisId(this.maxFieldCount);
990
	if (position < BitCacheSize) { // use bits
990
	if (position < BitCacheSize) { // use bits
991
		return (this.nullBit1 & this.nullBit3 & this.nullBit4 & (1L << position)) != 0;
991
		return (this.nullBit1 & this.nullBit3 & this.nullBit4 & (1L << position)) != 0;
992
	}
992
	}
Lines 1005-1016 Link Here
1005
		    & (1L << (position % BitCacheSize))) != 0;
1005
		    & (1L << (position % BitCacheSize))) != 0;
1006
}
1006
}
1007
1007
1008
final public boolean isProtectedNull(VariableBinding local) {
1008
final public boolean isProtectedNull(VariableBinding var) {
1009
	if ((this.tagBits & NULL_FLAG_MASK) == 0 ||
1009
	if ((this.tagBits & NULL_FLAG_MASK) == 0 ||
1010
			(local.type.tagBits & TagBits.IsBaseType) != 0) {
1010
			(var.type.tagBits & TagBits.IsBaseType) != 0) {
1011
		return false;
1011
		return false;
1012
	}
1012
	}
1013
	int position = local.getAnalysisId(this.maxFieldCount);
1013
	int position = var.getAnalysisId(this.maxFieldCount);
1014
	if (position < BitCacheSize) {
1014
	if (position < BitCacheSize) {
1015
		// use bits
1015
		// use bits
1016
		return (this.nullBit1 & this.nullBit2
1016
		return (this.nullBit1 & this.nullBit2
Lines 1044-1065 Link Here
1044
		throw new AssertionFailedException("assertion failed: " + message); //$NON-NLS-1$
1044
		throw new AssertionFailedException("assertion failed: " + message); //$NON-NLS-1$
1045
	return expression;
1045
	return expression;
1046
}
1046
}
1047
public void markAsComparedEqualToNonNull(VariableBinding local) {
1047
public void markAsComparedEqualToNonNull(VariableBinding var) {
1048
	// protected from non-object locals in calling methods
1048
	// protected from non-object locals in calling methods
1049
	if (this != DEAD_END) {
1049
	if (this != DEAD_END) {
1050
		this.tagBits |= NULL_FLAG_MASK;
1050
		this.tagBits |= NULL_FLAG_MASK;
1051
		int position;
1051
		int position;
1052
		if (local instanceof FieldBinding) {
1052
		if (var instanceof FieldBinding) {
1053
			if ((local.modifiers & AccConstant) == AccConstant) {
1053
			if ((var.modifiers & AccConstant) == AccConstant) {
1054
				position = local.getAnalysisId(this.maxFieldCount);
1054
				position = var.getAnalysisId(this.maxFieldCount);
1055
			} else {
1055
			} else {
1056
				// non-final fields may be modified in separate threads and we cannot be sure about their
1056
				// non-final fields may be modified in separate threads and we cannot be sure about their
1057
				// definite nullness. Hence, marking as definitely unknown to avoid deferring null check for these fields
1057
				// definite nullness. Hence, marking as definitely unknown to avoid deferring null check for these fields
1058
				this.markAsDefinitelyUnknown(local);
1058
				this.markAsDefinitelyUnknown(var);
1059
				return;
1059
				return;
1060
			}
1060
			}
1061
		} else {
1061
		} else {
1062
			position = local.id + this.maxFieldCount;
1062
			position = var.id + this.maxFieldCount;
1063
		}
1063
		}
1064
		long mask;
1064
		long mask;
1065
		long a1, a2, a3, a4, na2;
1065
		long a1, a2, a3, a4, na2;
Lines 1153-1176 Link Here
1153
	}
1153
	}
1154
}
1154
}
1155
1155
1156
public void markAsComparedEqualToNull(VariableBinding local) {
1156
public void markAsComparedEqualToNull(VariableBinding var) {
1157
	// protected from non-object locals in calling methods
1157
	// protected from non-object locals in calling methods
1158
	if (this != DEAD_END) {
1158
	if (this != DEAD_END) {
1159
		this.tagBits |= NULL_FLAG_MASK;
1159
		this.tagBits |= NULL_FLAG_MASK;
1160
		int position;
1160
		int position;
1161
		long mask;
1161
		long mask;
1162
		// position is zero-based
1162
		// position is zero-based
1163
		if (local instanceof FieldBinding) {
1163
		if (var instanceof FieldBinding) {
1164
			if ((local.modifiers & AccConstant) == AccConstant) {
1164
			if ((var.modifiers & AccConstant) == AccConstant) {
1165
				position = local.getAnalysisId(this.maxFieldCount);
1165
				position = var.getAnalysisId(this.maxFieldCount);
1166
			} else {
1166
			} else {
1167
				// non-final fields may be modified in separate threads and we cannot be sure about their
1167
				// non-final fields may be modified in separate threads and we cannot be sure about their
1168
				// definite nullness. Hence, marking as potential null.
1168
				// definite nullness. Hence, marking as potential null.
1169
				this.markNullStatus(local, FlowInfo.POTENTIALLY_NULL);
1169
				this.markNullStatus(var, FlowInfo.POTENTIALLY_NULL);
1170
				return;
1170
				return;
1171
			}
1171
			}
1172
		} else {
1172
		} else {
1173
			position = local.id + this.maxFieldCount;
1173
			position = var.id + this.maxFieldCount;
1174
		}
1174
		}
1175
		if (position < BitCacheSize) {
1175
		if (position < BitCacheSize) {
1176
			// use bits
1176
			// use bits
Lines 1298-1321 Link Here
1298
		markAsDefinitelyAssigned(var.getAnalysisId(this.maxFieldCount));
1298
		markAsDefinitelyAssigned(var.getAnalysisId(this.maxFieldCount));
1299
}
1299
}
1300
1300
1301
public void markAsDefinitelyNonNull(VariableBinding local) {
1301
public void markAsDefinitelyNonNull(VariableBinding var) {
1302
	// protected from non-object locals in calling methods
1302
	// protected from non-object locals in calling methods
1303
	if (this != DEAD_END) {
1303
	if (this != DEAD_END) {
1304
    	this.tagBits |= NULL_FLAG_MASK;
1304
    	this.tagBits |= NULL_FLAG_MASK;
1305
    	long mask;
1305
    	long mask;
1306
    	int position;
1306
    	int position;
1307
    	// position is zero-based
1307
    	// position is zero-based
1308
    	if (local instanceof FieldBinding) {
1308
    	if (var instanceof FieldBinding) {
1309
			if ((local.modifiers & AccConstant) == AccConstant) {
1309
			if ((var.modifiers & AccConstant) == AccConstant) {
1310
				position = local.getAnalysisId(this.maxFieldCount);
1310
				position = var.getAnalysisId(this.maxFieldCount);
1311
			} else {
1311
			} else {
1312
	    		// non-final fields may be modified in separate threads and we cannot be sure about their
1312
	    		// non-final fields may be modified in separate threads and we cannot be sure about their
1313
	    		// definite nullness. Hence, marking as definitely unknown to avoid deferring null check for these fields.
1313
	    		// definite nullness. Hence, marking as definitely unknown to avoid deferring null check for these fields.
1314
	    		this.markAsDefinitelyUnknown(local);
1314
	    		this.markAsDefinitelyUnknown(var);
1315
	    		return;
1315
	    		return;
1316
			}
1316
			}
1317
    	} else {
1317
    	} else {
1318
    		position = local.id + this.maxFieldCount;
1318
    		position = var.id + this.maxFieldCount;
1319
    	}
1319
    	}
1320
    	if (position < BitCacheSize) { // use bits
1320
    	if (position < BitCacheSize) { // use bits
1321
    		// set assigned non null
1321
    		// set assigned non null
Lines 1364-1387 Link Here
1364
	}
1364
	}
1365
}
1365
}
1366
1366
1367
public void markAsDefinitelyNull(VariableBinding local) {
1367
public void markAsDefinitelyNull(VariableBinding var) {
1368
	// protected from non-object locals in calling methods
1368
	// protected from non-object locals in calling methods
1369
	if (this != DEAD_END) {
1369
	if (this != DEAD_END) {
1370
    	this.tagBits |= NULL_FLAG_MASK;
1370
    	this.tagBits |= NULL_FLAG_MASK;
1371
    	long mask;
1371
    	long mask;
1372
    	int position;
1372
    	int position;
1373
    	// position is zero-based
1373
    	// position is zero-based
1374
    	if (local instanceof FieldBinding) {
1374
    	if (var instanceof FieldBinding) {
1375
			if ((local.modifiers & AccConstant) == AccConstant) {
1375
			if ((var.modifiers & AccConstant) == AccConstant) {
1376
				position = local.getAnalysisId(this.maxFieldCount);
1376
				position = var.getAnalysisId(this.maxFieldCount);
1377
			} else {
1377
			} else {
1378
	    		// non-final fields may be modified in separate threads and we cannot be sure about their
1378
	    		// non-final fields may be modified in separate threads and we cannot be sure about their
1379
	    		// definite nullness. Hence, marking as potential null.
1379
	    		// definite nullness. Hence, marking as potential null.
1380
	    		this.markNullStatus(local, FlowInfo.POTENTIALLY_NULL);
1380
	    		this.markNullStatus(var, FlowInfo.POTENTIALLY_NULL);
1381
	    		return;
1381
	    		return;
1382
			}
1382
			}
1383
    	} else {
1383
    	} else {
1384
    		position = local.id + this.maxFieldCount;
1384
    		position = var.id + this.maxFieldCount;
1385
    	}
1385
    	}
1386
    	if (position < BitCacheSize) { // use bits
1386
    	if (position < BitCacheSize) { // use bits
1387
    		// mark assigned null
1387
    		// mark assigned null
Lines 1432-1447 Link Here
1432
1432
1433
/**
1433
/**
1434
 * Mark a local as having been assigned to an unknown value.
1434
 * Mark a local as having been assigned to an unknown value.
1435
 * @param local the local to mark
1435
 * @param var the local to mark
1436
 */
1436
 */
1437
// PREMATURE may try to get closer to markAsDefinitelyAssigned, but not
1437
// PREMATURE may try to get closer to markAsDefinitelyAssigned, but not
1438
//			 obvious
1438
//			 obvious
1439
public void markAsDefinitelyUnknown(VariableBinding local) {
1439
public void markAsDefinitelyUnknown(VariableBinding var) {
1440
	// protected from non-object locals in calling methods
1440
	// protected from non-object locals in calling methods
1441
	if (this != DEAD_END) {
1441
	if (this != DEAD_END) {
1442
		this.tagBits |= NULL_FLAG_MASK;
1442
		this.tagBits |= NULL_FLAG_MASK;
1443
		long mask;
1443
		long mask;
1444
		int position = local.getAnalysisId(this.maxFieldCount);
1444
		int position = var.getAnalysisId(this.maxFieldCount);
1445
		if (position < BitCacheSize) {
1445
		if (position < BitCacheSize) {
1446
			// use bits
1446
			// use bits
1447
			// mark assigned null
1447
			// mark assigned null
Lines 1490-1500 Link Here
1490
	}
1490
	}
1491
}
1491
}
1492
1492
1493
public void resetNullInfo(VariableBinding local) {
1493
public void resetNullInfo(VariableBinding var) {
1494
	if (this != DEAD_END) {
1494
	if (this != DEAD_END) {
1495
		this.tagBits |= NULL_FLAG_MASK;
1495
		this.tagBits |= NULL_FLAG_MASK;
1496
        long mask;
1496
        long mask;
1497
    	int position = local.getAnalysisId(this.maxFieldCount);
1497
    	int position = var.getAnalysisId(this.maxFieldCount);
1498
        if (position < BitCacheSize) {
1498
        if (position < BitCacheSize) {
1499
            // use bits
1499
            // use bits
1500
            this.nullBit1 &= (mask = ~(1L << position));
1500
            this.nullBit1 &= (mask = ~(1L << position));
Lines 1630-1643 Link Here
1630
1630
1631
/**
1631
/**
1632
 * Mark a local as potentially having been assigned to an unknown value.
1632
 * Mark a local as potentially having been assigned to an unknown value.
1633
 * @param local the local to mark
1633
 * @param var the local to mark
1634
 */
1634
 */
1635
public void markPotentiallyUnknownBit(VariableBinding local) {
1635
public void markPotentiallyUnknownBit(VariableBinding var) {
1636
	// protected from non-object locals in calling methods
1636
	// protected from non-object locals in calling methods
1637
	if (this != DEAD_END) {
1637
	if (this != DEAD_END) {
1638
		this.tagBits |= NULL_FLAG_MASK;
1638
		this.tagBits |= NULL_FLAG_MASK;
1639
        long mask;
1639
        long mask;
1640
    	int position = local.getAnalysisId(this.maxFieldCount);
1640
    	int position = var.getAnalysisId(this.maxFieldCount);
1641
        if (position < BitCacheSize) {
1641
        if (position < BitCacheSize) {
1642
            // use bits
1642
            // use bits
1643
        	mask = 1L << position;
1643
        	mask = 1L << position;
Lines 1680-1690 Link Here
1680
	}
1680
	}
1681
}
1681
}
1682
1682
1683
public void markPotentiallyNullBit(VariableBinding local) {
1683
public void markPotentiallyNullBit(VariableBinding var) {
1684
	if (this != DEAD_END) {
1684
	if (this != DEAD_END) {
1685
		this.tagBits |= NULL_FLAG_MASK;
1685
		this.tagBits |= NULL_FLAG_MASK;
1686
        long mask;
1686
        long mask;
1687
    	int position = local.getAnalysisId(this.maxFieldCount);
1687
    	int position = var.getAnalysisId(this.maxFieldCount);
1688
        if (position < BitCacheSize) {
1688
        if (position < BitCacheSize) {
1689
            // use bits
1689
            // use bits
1690
        	mask = 1L << position;
1690
        	mask = 1L << position;
Lines 1727-1737 Link Here
1727
	}
1727
	}
1728
}
1728
}
1729
1729
1730
public void markPotentiallyNonNullBit(VariableBinding local) {
1730
public void markPotentiallyNonNullBit(VariableBinding var) {
1731
	if (this != DEAD_END) {
1731
	if (this != DEAD_END) {
1732
		this.tagBits |= NULL_FLAG_MASK;
1732
		this.tagBits |= NULL_FLAG_MASK;
1733
        long mask;
1733
        long mask;
1734
    	int position = local.getAnalysisId(this.maxFieldCount);
1734
    	int position = var.getAnalysisId(this.maxFieldCount);
1735
        if (position < BitCacheSize) {
1735
        if (position < BitCacheSize) {
1736
            // use bits
1736
            // use bits
1737
        	mask = 1L << position;
1737
        	mask = 1L << position;

Return to bug 247564