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/compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java (-4 / +18 lines)
Lines 49-64 Link Here
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 local, int nullStatus, Expression reference) {
52
		boolean report = true;
53
		if (local instanceof FieldBinding) {
54
			FieldBinding field = (FieldBinding) local;
55
			report = field.isStatic() && field.isFinal();
56
			// or if field has null-annotation
57
		}
52
		switch (nullStatus) {
58
		switch (nullStatus) {
53
			case FlowInfo.NULL :
59
			case FlowInfo.NULL :
54
				if (((this.bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL) {
60
				if (((this.bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL) {
55
					flowContext.recordUsingNullReference(scope, local, reference,
61
					if (report) {
62
						flowContext.recordUsingNullReference(scope, local, reference,
56
							FlowContext.CAN_ONLY_NULL_NON_NULL | FlowContext.IN_COMPARISON_NULL, flowInfo);
63
							FlowContext.CAN_ONLY_NULL_NON_NULL | FlowContext.IN_COMPARISON_NULL, flowInfo);
64
					}
57
					initsWhenTrue.markAsComparedEqualToNull(local); // from thereon it is set
65
					initsWhenTrue.markAsComparedEqualToNull(local); // from thereon it is set
58
					initsWhenFalse.markAsComparedEqualToNonNull(local); // from thereon it is set
66
					initsWhenFalse.markAsComparedEqualToNonNull(local); // from thereon it is set
59
				} else {
67
				} else {
60
					flowContext.recordUsingNullReference(scope, local, reference,
68
					if (report) {
69
						flowContext.recordUsingNullReference(scope, local, reference,
61
							FlowContext.CAN_ONLY_NULL_NON_NULL | FlowContext.IN_COMPARISON_NON_NULL, flowInfo);
70
							FlowContext.CAN_ONLY_NULL_NON_NULL | FlowContext.IN_COMPARISON_NON_NULL, flowInfo);
71
					}
62
					initsWhenTrue.markAsComparedEqualToNonNull(local); // from thereon it is set
72
					initsWhenTrue.markAsComparedEqualToNonNull(local); // from thereon it is set
63
					initsWhenFalse.markAsComparedEqualToNull(local); // from thereon it is set
73
					initsWhenFalse.markAsComparedEqualToNull(local); // from thereon it is set
64
				}
74
				}
Lines 68-82 Link Here
68
				break;
78
				break;
69
			case FlowInfo.NON_NULL :
79
			case FlowInfo.NON_NULL :
70
				if (((this.bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL) {
80
				if (((this.bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL) {
71
					flowContext.recordUsingNullReference(scope, local, reference,
81
					if (report) {
82
						flowContext.recordUsingNullReference(scope, local, reference,
72
							FlowContext.CAN_ONLY_NULL | FlowContext.IN_COMPARISON_NON_NULL, flowInfo);
83
							FlowContext.CAN_ONLY_NULL | FlowContext.IN_COMPARISON_NON_NULL, flowInfo);
84
					}
73
					initsWhenTrue.markAsComparedEqualToNonNull(local); // from thereon it is set
85
					initsWhenTrue.markAsComparedEqualToNonNull(local); // from thereon it is set
74
					if ((flowContext.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) != 0) {
86
					if ((flowContext.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) != 0) {
75
						initsWhenTrue.markedAsNullOrNonNullInAssertExpression(local);
87
						initsWhenTrue.markedAsNullOrNonNullInAssertExpression(local);
76
					}
88
					}
77
				} else {
89
				} else {
78
					flowContext.recordUsingNullReference(scope, local, reference,
90
					if (report) {
91
						flowContext.recordUsingNullReference(scope, local, reference,
79
							FlowContext.CAN_ONLY_NULL | FlowContext.IN_COMPARISON_NULL, flowInfo);
92
							FlowContext.CAN_ONLY_NULL | FlowContext.IN_COMPARISON_NULL, flowInfo);
93
					}
80
				}
94
				}
81
				break;
95
				break;
82
		}
96
		}
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java (-2 / +32 lines)
Lines 529-537 Link Here
529
	VariableBinding local = variableBinding(scope);
529
	VariableBinding local = variableBinding(scope);
530
	if (local != null &&
530
	if (local != null &&
531
			(local.type.tagBits & TagBits.IsBaseType) == 0) {
531
			(local.type.tagBits & TagBits.IsBaseType) == 0) {
532
		if ((this.bits & ASTNode.IsNonNull) == 0) {
532
		boolean suppressReporting = false;
533
		FlowInfo infoForReporting = flowInfo;
534
		if (local instanceof FieldBinding) {
535
			FieldBinding field = (FieldBinding) local;
536
			if (!(field.isStatic() && field.isFinal())) {
537
				// non-constant
538
				int fieldStatus = flowInfo.nullStatus(local);
539
				if (fieldStatus == FlowInfo.NULL) {
540
					// weaken null to pot.null
541
// 					infoForReporting=flowInfo.copy();
542
					infoForReporting=FlowInfo.initial(flowInfo); // we're only interested in the bits for this one field
543
					infoForReporting.markNullStatus(local, FlowInfo.POTENTIALLY_NULL);
544
				} else if ((fieldStatus & FlowInfo.POTENTIALLY_NULL) != 0) {
545
					// report pot.null as-is
546
//				} else {
547
//					// don't report others
548
//					suppressReporting = true;
549
				}
550
			}
551
		}
552
// DOES NOT WORK
553
//		if (local instanceof FieldBinding) {
554
//			FieldBinding field = (FieldBinding) local;
555
//			if (!(field.isStatic() && field.isFinal())) {
556
//				// non-constant
557
//				FlowInfo doubtInfo = flowInfo.copy();
558
//				doubtInfo.markAsDefinitelyUnknown(field);
559
//				infoForReporting = FlowInfo.conditional(flowInfo, doubtInfo);
560
//			}
561
//		}
562
		if ((this.bits & ASTNode.IsNonNull) == 0 && !suppressReporting) {
533
			flowContext.recordUsingNullReference(scope, local, this,
563
			flowContext.recordUsingNullReference(scope, local, this,
534
					FlowContext.MAY_NULL, flowInfo);
564
					FlowContext.MAY_NULL, infoForReporting);
535
		}
565
		}
536
		flowInfo.markAsComparedEqualToNonNull(local );
566
		flowInfo.markAsComparedEqualToNonNull(local );
537
			// from thereon it is set
567
			// from thereon it is set
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowInfo.java (+9 lines)
Lines 144-149 Link Here
144
		return info;
144
		return info;
145
	}
145
	}
146
146
147
	public static UnconditionalFlowInfo initial(FlowInfo other) {
148
		UnconditionalFlowInfo info = new UnconditionalFlowInfo();
149
		while(other instanceof ConditionalFlowInfo) {
150
			other = other.initsWhenTrue();
151
		}
152
		info.maxFieldCount = ((UnconditionalFlowInfo) other).maxFieldCount;
153
		return info;
154
	}
155
147
/**
156
/**
148
 * Return the flow info that would result from the path associated to the
157
 * Return the flow info that would result from the path associated to the
149
 * value false for the condition expression that generated this flow info.
158
 * value false for the condition expression that generated this flow info.
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java (-43 / +4 lines)
Lines 1070-1086 Link Here
1070
	// protected from non-object locals in calling methods
1070
	// protected from non-object locals in calling methods
1071
	if (this != DEAD_END) {
1071
	if (this != DEAD_END) {
1072
		this.tagBits |= NULL_FLAG_MASK;
1072
		this.tagBits |= NULL_FLAG_MASK;
1073
		int position;
1073
		int position = local.getAnalysisId(this.maxFieldCount);
1074
		if (local instanceof FieldBinding) {
1075
			// non-final fields may be modified in separate threads and we cannot be sure about their
1076
			// definite nullness. Hence, marking as potential non null.
1077
			// Also marking it as definitely unknown to avoid deferring null check for these fields
1078
			this.markNullStatus(local, FlowInfo.POTENTIALLY_NON_NULL);
1079
			this.markAsDefinitelyUnknown(local);
1080
			return;
1081
		} else {
1082
			position = local.id + this.maxFieldCount;
1083
		}
1084
		long mask;
1074
		long mask;
1085
		long a1, a2, a3, a4, na2;
1075
		long a1, a2, a3, a4, na2;
1086
		// position is zero-based
1076
		// position is zero-based
Lines 1177-1193 Link Here
1177
	// protected from non-object locals in calling methods
1167
	// protected from non-object locals in calling methods
1178
	if (this != DEAD_END) {
1168
	if (this != DEAD_END) {
1179
		this.tagBits |= NULL_FLAG_MASK;
1169
		this.tagBits |= NULL_FLAG_MASK;
1180
		int position;
1181
		long mask;
1170
		long mask;
1182
		// position is zero-based
1171
		int position = local.getAnalysisId(this.maxFieldCount);
1183
		if (local instanceof FieldBinding) {
1184
			// non-final fields may be modified in separate threads and we cannot be sure about their
1185
			// definite nullness. Hence, marking as potential null.
1186
			this.markNullStatus(local, FlowInfo.POTENTIALLY_NULL);
1187
			return;
1188
		} else {
1189
			position = local.id + this.maxFieldCount;
1190
		}
1191
		if (position < BitCacheSize) {
1172
		if (position < BitCacheSize) {
1192
			// use bits
1173
			// use bits
1193
			if (((mask = 1L << position) & this.nullBit1) != 0) {
1174
			if (((mask = 1L << position) & this.nullBit1) != 0) {
Lines 1319-1336 Link Here
1319
	if (this != DEAD_END) {
1300
	if (this != DEAD_END) {
1320
    	this.tagBits |= NULL_FLAG_MASK;
1301
    	this.tagBits |= NULL_FLAG_MASK;
1321
    	long mask;
1302
    	long mask;
1322
    	int position;
1303
    	int position = local.getAnalysisId(this.maxFieldCount);
1323
    	// position is zero-based
1324
    	if (local instanceof FieldBinding) {
1325
    		// non-final fields may be modified in separate threads and we cannot be sure about their
1326
    		// definite nullness. Hence, marking as potential non null.
1327
    		// Also marking it as definitely unknown to avoid deferring null check for these fields
1328
    		this.markNullStatus(local, FlowInfo.POTENTIALLY_NON_NULL);
1329
    		this.markAsDefinitelyUnknown(local);
1330
    		return;
1331
    	} else {
1332
    		position = local.id + this.maxFieldCount;
1333
    	}
1334
    	if (position < BitCacheSize) { // use bits
1304
    	if (position < BitCacheSize) { // use bits
1335
    		// set assigned non null
1305
    		// set assigned non null
1336
    		this.nullBit1 |= (mask = 1L << position);
1306
    		this.nullBit1 |= (mask = 1L << position);
Lines 1383-1398 Link Here
1383
	if (this != DEAD_END) {
1353
	if (this != DEAD_END) {
1384
    	this.tagBits |= NULL_FLAG_MASK;
1354
    	this.tagBits |= NULL_FLAG_MASK;
1385
    	long mask;
1355
    	long mask;
1386
    	int position;
1356
    	int position = local.getAnalysisId(this.maxFieldCount);
1387
    	// position is zero-based
1388
    	if (local instanceof FieldBinding) {
1389
    		// non-final fields may be modified in separate threads and we cannot be sure about their
1390
    		// definite nullness. Hence, marking as potential null.
1391
    		this.markNullStatus(local, FlowInfo.POTENTIALLY_NULL);
1392
    		return;
1393
    	} else {
1394
    		position = local.id + this.maxFieldCount;
1395
    	}
1396
    	if (position < BitCacheSize) { // use bits
1357
    	if (position < BitCacheSize) { // use bits
1397
    		// mark assigned null
1358
    		// mark assigned null
1398
    		this.nullBit1 |= (mask = 1L << position);
1359
    		this.nullBit1 |= (mask = 1L << position);

Return to bug 247564