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

Collapse All | Expand All

(-)compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java (-28 / +3 lines)
Lines 53-86 Link Here
53
		.analyseAssignment(currentScope, flowContext, flowInfo, this, false)
53
		.analyseAssignment(currentScope, flowContext, flowInfo, this, false)
54
		.unconditionalInits();
54
		.unconditionalInits();
55
	if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) {
55
	if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) {
56
		switch(nullStatus) {
56
		flowInfo.markNullStatus(local, nullStatus);
57
			case FlowInfo.NULL :
57
		if (flowContext.initsOnFinally != null)
58
				flowInfo.markAsDefinitelyNull(local);
58
			flowContext.initsOnFinally.markNullStatus(local, nullStatus);
59
				break;
60
			case FlowInfo.NON_NULL :
61
				flowInfo.markAsDefinitelyNonNull(local);
62
				break;
63
			case FlowInfo.POTENTIALLY_NULL :
64
				flowInfo.markAsPotentiallyNull(local);
65
				break;
66
			default:
67
				flowInfo.markAsDefinitelyUnknown(local);
68
		}
69
		if (flowContext.initsOnFinally != null) {
70
			switch(nullStatus) {
71
				case FlowInfo.NULL :
72
					flowContext.initsOnFinally.markAsDefinitelyNull(local);
73
					break;
74
				case FlowInfo.NON_NULL :
75
					flowContext.initsOnFinally.markAsDefinitelyNonNull(local);
76
					break;
77
				case FlowInfo.POTENTIALLY_NULL :
78
					flowContext.initsOnFinally.markAsPotentiallyNull(local);
79
					break;
80
				default:
81
					flowContext.initsOnFinally.markAsDefinitelyUnknown(local);
82
			}
83
		}
84
	}
59
	}
85
	return flowInfo;
60
	return flowInfo;
86
}
61
}
(-)compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java (-3 / +28 lines)
Lines 319-335 Link Here
319
	if (ifTrueNullStatus == ifFalseNullStatus) {
319
	if (ifTrueNullStatus == ifFalseNullStatus) {
320
		return ifTrueNullStatus;
320
		return ifTrueNullStatus;
321
	}
321
	}
322
	// is there a chance of null? -> potentially null
322
	// is there a chance of null (or non-null)? -> potentially null etc.
323
	// https://bugs.eclipse.org/bugs/show_bug.cgi?id=133125
323
	// https://bugs.eclipse.org/bugs/show_bug.cgi?id=133125
324
	boolean potentiallyNull = false;
325
	boolean potentiallyNonNull = false;
324
	switch (ifTrueNullStatus) {
326
	switch (ifTrueNullStatus) {
325
		case FlowInfo.NULL:
327
		case FlowInfo.NULL:
326
		case FlowInfo.POTENTIALLY_NULL:
328
		case FlowInfo.POTENTIALLY_NULL:
327
			return FlowInfo.POTENTIALLY_NULL;
329
			potentiallyNull = true;
330
			break;
331
		case FlowInfo.NON_NULL:
332
		case FlowInfo.POTENTIALLY_NON_NULL:
333
			potentiallyNonNull = true;
334
			break;
335
		case FlowInfo.POTENTIALLY_NULL_OR_NON_NULL:
336
			potentiallyNonNull = true;
337
			potentiallyNull = true;
328
	}
338
	}
329
	switch (ifFalseNullStatus) {
339
	switch (ifFalseNullStatus) {
330
		case FlowInfo.NULL:
340
		case FlowInfo.NULL:
331
		case FlowInfo.POTENTIALLY_NULL:
341
		case FlowInfo.POTENTIALLY_NULL:
332
			return FlowInfo.POTENTIALLY_NULL;
342
			potentiallyNull = true;
343
			break;
344
		case FlowInfo.NON_NULL:
345
		case FlowInfo.POTENTIALLY_NON_NULL:
346
			potentiallyNonNull = true;
347
			break;
348
		case FlowInfo.POTENTIALLY_NULL_OR_NON_NULL:
349
			potentiallyNonNull = true;
350
			potentiallyNull = true;
351
	}
352
	if (potentiallyNull) {
353
		if (potentiallyNonNull)
354
			return FlowInfo.POTENTIALLY_NULL_OR_NON_NULL;
355
		return FlowInfo.POTENTIALLY_NULL;
356
	} else if (potentiallyNonNull) {
357
		return FlowInfo.POTENTIALLY_NON_NULL;
333
	}
358
	}
334
	return FlowInfo.UNKNOWN;
359
	return FlowInfo.UNKNOWN;
335
	// cannot decide which branch to take, and they disagree
360
	// cannot decide which branch to take, and they disagree
(-)compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java (-9 / +2 lines)
Lines 837-851 Link Here
837
	return FlowInfo.NON_NULL; // constant expression cannot be null
837
	return FlowInfo.NON_NULL; // constant expression cannot be null
838
838
839
	LocalVariableBinding local = localVariableBinding();
839
	LocalVariableBinding local = localVariableBinding();
840
	if (local != null) {
840
	if (local != null)
841
		if (flowInfo.isDefinitelyNull(local))
841
		return flowInfo.nullStatus(local);
842
			return FlowInfo.NULL;
843
		if (flowInfo.isDefinitelyNonNull(local))
844
			return FlowInfo.NON_NULL;
845
		if (flowInfo.isPotentiallyNull(local))
846
			return FlowInfo.POTENTIALLY_NULL;
847
		return FlowInfo.UNKNOWN;
848
	}
849
	return FlowInfo.NON_NULL;
842
	return FlowInfo.NON_NULL;
850
}
843
}
851
844
(-)compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java (-13 / +1 lines)
Lines 57-75 Link Here
57
	}
57
	}
58
	flowInfo.markAsDefinitelyAssigned(this.binding);
58
	flowInfo.markAsDefinitelyAssigned(this.binding);
59
	if ((this.binding.type.tagBits & TagBits.IsBaseType) == 0) {
59
	if ((this.binding.type.tagBits & TagBits.IsBaseType) == 0) {
60
		switch(nullStatus) {
60
		flowInfo.markNullStatus(this.binding, nullStatus);
61
			case FlowInfo.NULL :
62
				flowInfo.markAsDefinitelyNull(this.binding);
63
				break;
64
			case FlowInfo.NON_NULL :
65
				flowInfo.markAsDefinitelyNonNull(this.binding);
66
				break;
67
			case FlowInfo.POTENTIALLY_NULL :
68
				flowInfo.markAsPotentiallyNull(this.binding);
69
				break;
70
			default:
71
				flowInfo.markAsDefinitelyUnknown(this.binding);
72
		}
73
		// no need to inform enclosing try block since its locals won't get
61
		// no need to inform enclosing try block since its locals won't get
74
		// known by the finally block
62
		// known by the finally block
75
	}
63
	}
(-)compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java (-9 / +2 lines)
Lines 770-784 Link Here
770
			return FlowInfo.UNKNOWN;
770
			return FlowInfo.UNKNOWN;
771
		case Binding.LOCAL : // reading a local variable
771
		case Binding.LOCAL : // reading a local variable
772
			LocalVariableBinding local = (LocalVariableBinding) this.binding;
772
			LocalVariableBinding local = (LocalVariableBinding) this.binding;
773
			if (local != null) {
773
			if (local != null)
774
				if (flowInfo.isDefinitelyNull(local))
774
				return flowInfo.nullStatus(local);
775
					return FlowInfo.NULL;
776
				if (flowInfo.isDefinitelyNonNull(local))
777
					return FlowInfo.NON_NULL;
778
				if (flowInfo.isPotentiallyNull(local))
779
					return FlowInfo.POTENTIALLY_NULL;
780
				return FlowInfo.UNKNOWN;
781
			}
782
	}
775
	}
783
	return FlowInfo.NON_NULL; // never get there
776
	return FlowInfo.NON_NULL; // never get there
784
}
777
}
(-)compiler/org/eclipse/jdt/internal/compiler/flow/ConditionalFlowInfo.java (+10 lines)
Lines 162-167 Link Here
162
	this.initsWhenFalse.markAsPotentiallyNull(local);
162
	this.initsWhenFalse.markAsPotentiallyNull(local);
163
}
163
}
164
164
165
public void markAsPotentiallyNonNull(LocalVariableBinding local) {
166
	this.initsWhenTrue.markAsPotentiallyNonNull(local);
167
	this.initsWhenFalse.markAsPotentiallyNonNull(local);
168
}
169
170
public void markAsPotentiallyNullOrNonNull(LocalVariableBinding local) {
171
	this.initsWhenTrue.markAsPotentiallyNullOrNonNull(local);
172
	this.initsWhenFalse.markAsPotentiallyNullOrNonNull(local);
173
}
174
165
public void markAsDefinitelyUnknown(LocalVariableBinding local) {
175
public void markAsDefinitelyUnknown(LocalVariableBinding local) {
166
	this.initsWhenTrue.markAsDefinitelyUnknown(local);
176
	this.initsWhenTrue.markAsDefinitelyUnknown(local);
167
	this.initsWhenFalse.markAsDefinitelyUnknown(local);
177
	this.initsWhenFalse.markAsDefinitelyUnknown(local);
(-)compiler/org/eclipse/jdt/internal/compiler/flow/FlowInfo.java (+60 lines)
Lines 27-32 Link Here
27
	public final static int NULL = 1;
27
	public final static int NULL = 1;
28
	public final static int NON_NULL = -1;
28
	public final static int NON_NULL = -1;
29
	public final static int POTENTIALLY_NULL = 2;
29
	public final static int POTENTIALLY_NULL = 2;
30
	public final static int POTENTIALLY_NON_NULL = 3;
31
	public final static int POTENTIALLY_NULL_OR_NON_NULL = 4;
30
32
31
	public static final UnconditionalFlowInfo DEAD_END; // Represents a dead branch status of initialization
33
	public static final UnconditionalFlowInfo DEAD_END; // Represents a dead branch status of initialization
32
	static {
34
	static {
Lines 255-260 Link Here
255
	abstract public void markAsPotentiallyNull(LocalVariableBinding local);
257
	abstract public void markAsPotentiallyNull(LocalVariableBinding local);
256
258
257
	/**
259
	/**
260
	 * Record a local may have got assigned to non-null.
261
	 */
262
	abstract public void markAsPotentiallyNonNull(LocalVariableBinding local);
263
264
	/**
265
	 * Record a local may have got assigned to null or to non-null.
266
	 */
267
	abstract public void markAsPotentiallyNullOrNonNull(LocalVariableBinding local);
268
	
269
	/**
258
	 * Record a local got definitely assigned.
270
	 * Record a local got definitely assigned.
259
	 */
271
	 */
260
	abstract public void markAsDefinitelyAssigned(LocalVariableBinding local);
272
	abstract public void markAsDefinitelyAssigned(LocalVariableBinding local);
Lines 265-270 Link Here
265
abstract public void markAsDefinitelyUnknown(LocalVariableBinding local);
277
abstract public void markAsDefinitelyUnknown(LocalVariableBinding local);
266
278
267
/**
279
/**
280
 * Mark the null status of the given local according to the given status
281
 * @param local
282
 * @param nullStatus one of FLowInfo.NULL ... FlowInfo.POTENTIALLY_NULL_OR_NON_NULL
283
 */
284
public void markNullStatus(LocalVariableBinding local, int nullStatus) {
285
	switch(nullStatus) {
286
		case NULL :
287
			markAsDefinitelyNull(local);
288
			break;
289
		case NON_NULL :
290
			markAsDefinitelyNonNull(local);
291
			break;
292
		case POTENTIALLY_NULL :
293
			markAsPotentiallyNull(local);
294
			break;
295
		case POTENTIALLY_NON_NULL :
296
			markAsPotentiallyNonNull(local);
297
			break;
298
		case POTENTIALLY_NULL_OR_NON_NULL :
299
			markAsPotentiallyNullOrNonNull(local);
300
			break;
301
		default:
302
			markAsDefinitelyUnknown(local);
303
	}
304
}
305
306
/**
307
 * Answer the null status of the given local
308
 * @param local
309
 * @return one of FLowInfo.NULL ... FlowInfo.POTENTIALLY_NULL_OR_NON_NULL
310
 */
311
public int nullStatus(LocalVariableBinding local) {
312
	if (isDefinitelyNull(local))
313
		return NULL;
314
	if (isDefinitelyNonNull(local))
315
		return NON_NULL;
316
	if (isPotentiallyNull(local)) {
317
		if (isPotentiallyNonNull(local))
318
			return POTENTIALLY_NULL_OR_NON_NULL;
319
		return POTENTIALLY_NULL;
320
	}
321
	if (isPotentiallyNonNull(local))
322
		return POTENTIALLY_NON_NULL;
323
	return UNKNOWN;
324
}
325
326
/**
268
 * Merge branches using optimized boolean conditions
327
 * Merge branches using optimized boolean conditions
269
 */
328
 */
270
public static UnconditionalFlowInfo mergedOptimizedBranches(
329
public static UnconditionalFlowInfo mergedOptimizedBranches(
Lines 482-485 Link Here
482
 */
541
 */
483
//https://bugs.eclipse.org/bugs/show_bug.cgi?id=303448
542
//https://bugs.eclipse.org/bugs/show_bug.cgi?id=303448
484
abstract public boolean isMarkedAsNullOrNonNullInAssertExpression(LocalVariableBinding local);
543
abstract public boolean isMarkedAsNullOrNonNullInAssertExpression(LocalVariableBinding local);
544
485
}
545
}
(-)compiler/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java (+66 lines)
Lines 1363-1368 Link Here
1363
	}
1363
	}
1364
}
1364
}
1365
1365
1366
public void markAsPotentiallyNonNull(LocalVariableBinding local) {
1367
	if (this != DEAD_END) {
1368
		this.tagBits |= NULL_FLAG_MASK;
1369
        int position;
1370
        long mask;
1371
        if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
1372
            // use bits
1373
            this.nullBit1 &= ~(mask = 1L << position);
1374
            this.nullBit2 &= ~mask;
1375
            this.nullBit3 |= mask;
1376
            this.nullBit4 &= ~mask;
1377
            if (COVERAGE_TEST_FLAG) {
1378
				if(CoverageTestId == 42) {
1379
				  	this.nullBit4 = ~0;
1380
				}
1381
			}
1382
        } else {
1383
    		// use extra vector
1384
    		int vectorIndex ;
1385
    		this.extra[2][vectorIndex = (position / BitCacheSize) - 1]
1386
    		    &= ~(mask = 1L << (position % BitCacheSize));
1387
    		this.extra[3][vectorIndex] &= ~mask;
1388
    		this.extra[4][vectorIndex] |= mask;
1389
    		this.extra[5][vectorIndex] &= ~mask;
1390
    		if (COVERAGE_TEST_FLAG) {
1391
				if(CoverageTestId == 43) {
1392
					this.extra[5][vectorIndex] = ~0;
1393
				}
1394
			}
1395
    	}
1396
	}
1397
}
1398
1399
public void markAsPotentiallyNullOrNonNull(LocalVariableBinding local) {
1400
	if (this != DEAD_END) {
1401
		this.tagBits |= NULL_FLAG_MASK;
1402
        int position;
1403
        long mask;
1404
        if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
1405
            // use bits
1406
            this.nullBit1 &= ~(mask = 1L << position);
1407
            this.nullBit2 |= mask;
1408
            this.nullBit3 |= mask;
1409
            this.nullBit4 &= ~mask;
1410
            if (COVERAGE_TEST_FLAG) {
1411
				if(CoverageTestId == 44) {
1412
				  	this.nullBit4 = ~0;
1413
				}
1414
			}
1415
        } else {
1416
    		// use extra vector
1417
    		int vectorIndex ;
1418
    		this.extra[2][vectorIndex = (position / BitCacheSize) - 1]
1419
    		    &= ~(mask = 1L << (position % BitCacheSize));
1420
    		this.extra[3][vectorIndex] |= mask;
1421
    		this.extra[4][vectorIndex] |= mask;
1422
    		this.extra[5][vectorIndex] &= ~mask;
1423
    		if (COVERAGE_TEST_FLAG) {
1424
				if(CoverageTestId == 45) {
1425
					this.extra[5][vectorIndex] = ~0;
1426
				}
1427
			}
1428
    	}
1429
	}
1430
}
1431
1366
public UnconditionalFlowInfo mergedWith(UnconditionalFlowInfo otherInits) {
1432
public UnconditionalFlowInfo mergedWith(UnconditionalFlowInfo otherInits) {
1367
	if ((otherInits.tagBits & UNREACHABLE) != 0 && this != DEAD_END) {
1433
	if ((otherInits.tagBits & UNREACHABLE) != 0 && this != DEAD_END) {
1368
		if (COVERAGE_TEST_FLAG) {
1434
		if (COVERAGE_TEST_FLAG) {
(-)src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceTest.java (-1 / +74 lines)
Lines 35-41 Link Here
35
// Only the highest compliance level is run; add the VM argument
35
// Only the highest compliance level is run; add the VM argument
36
// -Dcompliance=1.4 (for example) to lower it if needed
36
// -Dcompliance=1.4 (for example) to lower it if needed
37
static {
37
static {
38
//		TESTS_NAMES = new String[] { "testBug320414" };
38
//		TESTS_NAMES = new String[] { "testBug324762" };
39
//		TESTS_NUMBERS = new int[] { 561 };
39
//		TESTS_NUMBERS = new int[] { 561 };
40
//		TESTS_RANGE = new int[] { 1, 2049 };
40
//		TESTS_RANGE = new int[] { 1, 2049 };
41
}
41
}
Lines 13222-13225 Link Here
13222
		"Potential null pointer access: The variable y may be null at this location\n" + 
13222
		"Potential null pointer access: The variable y may be null at this location\n" + 
13223
		"----------\n");
13223
		"----------\n");
13224
}
13224
}
13225
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=292478 -  Report potentially null across variable assignment
13226
// test regression reported in comment 8
13227
public void testBug292478e() {
13228
	this.runConformTest(
13229
		new String[] {
13230
			"Test.java",
13231
			"public class Test {\n" +
13232
			"	Object foo(int i, boolean b1, boolean b2) {\n" +
13233
			"		Object o1 = null;\n" +
13234
			"		done : while (true) { \n" +
13235
			"			switch (i) {\n" +
13236
			"				case 1 :\n" +
13237
			"					Object o2 = null;\n" +
13238
			"					if (b2)\n" +
13239
			"						o2 = new Object();\n" +
13240
			"					o1 = o2;\n" +
13241
			"					break;\n" +
13242
			"				case 2 :\n" +
13243
			"					break done;\n" +
13244
			"			}\n" +
13245
			"		}		\n" +
13246
			"		if (o1 != null)\n" +
13247
			"			return o1;\n" +
13248
			"		return null;\n" +
13249
			"	}\n" +
13250
			"}\n"
13251
		});
13252
}
13253
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=292478 -  Report potentially null across variable assignment
13254
// variant where regression occurred inside the while-switch structure
13255
public void testBug292478f() {
13256
	this.runConformTest(
13257
		new String[] {
13258
			"Test.java",
13259
			"public class Test {\n" +
13260
			"	Object foo(int i, boolean b1, boolean b2) {\n" +
13261
			"		Object o1 = null;\n" +
13262
			"		done : while (true) { \n" +
13263
			"			switch (i) {\n" +
13264
			"				case 1 :\n" +
13265
			"					Object o2 = null;\n" +
13266
			"					if (b2)\n" +
13267
			"						o2 = new Object();\n" +
13268
			"					o1 = o2;\n" +
13269
			"					if (o1 != null)\n" +
13270
			"						return o1;\n" +
13271
			"					break;\n" +
13272
			"				case 2 :\n" +
13273
			"					break done;\n" +
13274
			"			}\n" +
13275
			"		}		\n" +
13276
			"		return null;\n" +
13277
			"	}\n" +
13278
			"}\n"
13279
		});
13280
}
13281
13282
public void testBug324762() {
13283
	this.runConformTest(
13284
		new String[] {
13285
			"Test.java",
13286
			"public class Test {\n" +
13287
			"	void zork(boolean b1) {\n" +
13288
			"		Object satisfied = null;\n" +
13289
			"		if (b1) {\n" +
13290
			"			String[] s = new String[] { \"a\", \"b\" };\n" +
13291
			"			for (int k = 0; k < s.length && satisfied == null; k++)\n" +
13292
			"				satisfied = s.length > 1 ? new Object() : null;\n" +
13293
			"		}\n" +
13294
			"	}\n" +
13295
			"}\n"
13296
		});
13297
}
13225
}
13298
}

Return to bug 292478