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

Collapse All | Expand All

(-)compiler/org/eclipse/jdt/core/compiler/IProblem.java (+2 lines)
Lines 688-693 Link Here
688
	int LocalVariableCannotBeNull = MethodRelated + 397;
688
	int LocalVariableCannotBeNull = MethodRelated + 397;
689
	/** @since 3.1 */
689
	/** @since 3.1 */
690
	int LocalVariableCanOnlyBeNull = MethodRelated + 398;
690
	int LocalVariableCanOnlyBeNull = MethodRelated + 398;
691
	/** @since 3.2 */
692
	int LocalVariableMayBeNull = MethodRelated + 399;
691
693
692
	// method verifier problems
694
	// method verifier problems
693
	int AbstractMethodMustBeImplemented = MethodRelated + 400;
695
	int AbstractMethodMustBeImplemented = MethodRelated + 400;
(-)compiler/org/eclipse/jdt/internal/compiler/ast/AND_AND_Expression.java (-6 / +5 lines)
Lines 49-55 Link Here
49
		// need to be careful of scenario:
49
		// need to be careful of scenario:
50
		//  (x && y) && !z, if passing the left info to the right, it would be
50
		//  (x && y) && !z, if passing the left info to the right, it would be
51
		// swapped by the !
51
		// swapped by the !
52
		FlowInfo rightInfo = leftInfo.initsWhenTrue().unconditionalInits().copy();
52
		FlowInfo rightInfo = leftInfo.initsWhenTrue().unconditionalCopy();
53
		rightInitStateIndex = currentScope.methodScope().recordInitializationStates(rightInfo);
53
		rightInitStateIndex = currentScope.methodScope().recordInitializationStates(rightInfo);
54
54
55
		int previousMode = rightInfo.reachMode();
55
		int previousMode = rightInfo.reachMode();
Lines 57-68 Link Here
57
			rightInfo.setReachMode(FlowInfo.UNREACHABLE);
57
			rightInfo.setReachMode(FlowInfo.UNREACHABLE);
58
		}
58
		}
59
		rightInfo = right.analyseCode(currentScope, flowContext, rightInfo);
59
		rightInfo = right.analyseCode(currentScope, flowContext, rightInfo);
60
		FlowInfo trueMergedInfo = rightInfo.initsWhenTrue().copy();
61
		rightInfo.setReachMode(previousMode); // reset after trueMergedInfo got extracted
62
		FlowInfo mergedInfo = FlowInfo.conditional(
60
		FlowInfo mergedInfo = FlowInfo.conditional(
63
				trueMergedInfo, 
61
				rightInfo.safeInitsWhenTrue(), 
64
				leftInfo.initsWhenFalse().copy().unconditionalInits().mergedWith(
62
				leftInfo.initsWhenFalse().unconditionalInits().mergedWith(
65
						rightInfo.initsWhenFalse().copy().unconditionalInits()));
63
						rightInfo.initsWhenFalse().setReachMode(previousMode).unconditionalInits()));
64
		// reset after trueMergedInfo got extracted
66
		mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo);
65
		mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo);
67
		return mergedInfo;
66
		return mergedInfo;
68
	}
67
	}
(-)compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java (-1 / +4 lines)
Lines 39-45 Link Here
39
	public final static int Bit15 = 0x4000; 				// is unnecessary cast (expression) | is varargs (type ref)
39
	public final static int Bit15 = 0x4000; 				// is unnecessary cast (expression) | is varargs (type ref)
40
	public final static int Bit16 = 0x8000; 				// in javadoc comment (name ref, type ref, msg)
40
	public final static int Bit16 = 0x8000; 				// in javadoc comment (name ref, type ref, msg)
41
	public final static int Bit17 = 0x10000; 				// compound assigned (reference lhs)
41
	public final static int Bit17 = 0x10000; 				// compound assigned (reference lhs)
42
	public final static int Bit18 = 0x20000; 				
42
	public final static int Bit18 = 0x20000;				// non null (expression)				
43
	public final static int Bit19 = 0x40000; 
43
	public final static int Bit19 = 0x40000; 
44
	public final static int Bit20 = 0x80000; 
44
	public final static int Bit20 = 0x80000; 
45
	public final static int Bit21 = 0x100000; 		
45
	public final static int Bit21 = 0x100000; 		
Lines 158-163 Link Here
158
	// for array initializer
158
	// for array initializer
159
	public static final int IsAnnotationDefaultValue = Bit1;
159
	public static final int IsAnnotationDefaultValue = Bit1;
160
	
160
	
161
	// for null refenrence analysis
162
	public static final int IsNonNull = Bit18;
163
	
161
	public ASTNode() {
164
	public ASTNode() {
162
165
163
		super();
166
		super();
(-)compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java (-2 / +4 lines)
Lines 164-170 Link Here
164
	 */
164
	 */
165
	public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
165
	public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
166
166
167
		if (!flowInfo.isReachable()) return;
167
		if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) {
168
		ReferenceBinding allocatedTypeErasure = (ReferenceBinding) binding.declaringClass.erasure();
168
		ReferenceBinding allocatedTypeErasure = (ReferenceBinding) binding.declaringClass.erasure();
169
169
170
		// perform some emulation work in case there is some and we are inside a local type only
170
		// perform some emulation work in case there is some and we are inside a local type only
Lines 180-190 Link Here
180
				// request cascade of accesses
180
				// request cascade of accesses
181
			}
181
			}
182
		}
182
		}
183
		}
183
	}
184
	}
184
185
185
	public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
186
	public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
186
187
187
		if (!flowInfo.isReachable()) return;
188
		if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) {
188
189
189
		// if constructor from parameterized type got found, use the original constructor at codegen time
190
		// if constructor from parameterized type got found, use the original constructor at codegen time
190
		this.codegenBinding = this.binding.original();
191
		this.codegenBinding = this.binding.original();
Lines 201-206 Link Here
201
				currentScope.problemReporter().needToEmulateMethodAccess(this.codegenBinding, this);
202
				currentScope.problemReporter().needToEmulateMethodAccess(this.codegenBinding, this);
202
			}
203
			}
203
		}
204
		}
205
		}
204
	}
206
	}
205
207
206
	public StringBuffer printExpression(int indent, StringBuffer output) {
208
	public StringBuffer printExpression(int indent, StringBuffer output) {
(-)compiler/org/eclipse/jdt/internal/compiler/ast/ArrayReference.java (-19 / +21 lines)
Lines 27-60 Link Here
27
		sourceStart = rec.sourceStart;
27
		sourceStart = rec.sourceStart;
28
	}
28
	}
29
29
30
	public FlowInfo analyseAssignment(
30
public FlowInfo analyseAssignment(
31
		BlockScope currentScope,
31
		BlockScope currentScope,
32
		FlowContext flowContext,
32
		FlowContext flowContext,
33
		FlowInfo flowInfo,
33
		FlowInfo flowInfo,
34
		Assignment assignment,
34
		Assignment assignment,
35
		boolean compoundAssignment) {
35
		boolean compoundAssignment) {
36
	// TODO (maxime) optimization: unconditionalInits is applied to all existing calls
37
	if (assignment.expression == null) {
38
		return analyseCode(currentScope, flowContext, flowInfo);
39
	}
40
	return assignment
41
		.expression
42
		.analyseCode(
43
			currentScope,
44
			flowContext,
45
			analyseCode(currentScope, flowContext, flowInfo).unconditionalInits());
46
}
36
47
37
		if (assignment.expression == null) {
48
public FlowInfo analyseCode(
38
			return analyseCode(currentScope, flowContext, flowInfo).unconditionalInits();
39
		}
40
		return assignment
41
			.expression
42
			.analyseCode(
43
				currentScope,
44
				flowContext,
45
				analyseCode(currentScope, flowContext, flowInfo).unconditionalInits())
46
			.unconditionalInits();
47
	}
48
49
	public FlowInfo analyseCode(
50
		BlockScope currentScope,
49
		BlockScope currentScope,
51
		FlowContext flowContext,
50
		FlowContext flowContext,
52
		FlowInfo flowInfo) {
51
		FlowInfo flowInfo) {
53
52
	receiver.checkNPE(currentScope, flowContext, flowInfo, true);
54
		flowInfo = receiver.analyseCode(currentScope, flowContext, flowInfo);
53
	flowInfo = receiver.analyseCode(currentScope, flowContext, flowInfo);
55
		receiver.checkNullStatus(currentScope, flowContext, flowInfo, FlowInfo.NON_NULL);
54
	return position.analyseCode(currentScope, flowContext, flowInfo);
56
		return position.analyseCode(currentScope, flowContext, flowInfo);
55
}
57
	}
58
56
59
	public void generateAssignment(
57
	public void generateAssignment(
60
		BlockScope currentScope,
58
		BlockScope currentScope,
Lines 179-184 Link Here
179
		codeStream.arrayAtPut(this.resolvedType.id, false);
177
		codeStream.arrayAtPut(this.resolvedType.id, false);
180
	}
178
	}
181
179
180
public int nullStatus(FlowInfo flowInfo) {
181
	return FlowInfo.UNKNOWN;
182
}
183
182
	public StringBuffer printExpression(int indent, StringBuffer output) {
184
	public StringBuffer printExpression(int indent, StringBuffer output) {
183
185
184
		receiver.printExpression(0, output).append('[');
186
		receiver.printExpression(0, output).append('[');
(-)compiler/org/eclipse/jdt/internal/compiler/ast/AssertStatement.java (-4 / +6 lines)
Lines 54-64 Link Here
54
		boolean isOptimizedTrueAssertion = cst != Constant.NotAConstant && cst.booleanValue() == true;
54
		boolean isOptimizedTrueAssertion = cst != Constant.NotAConstant && cst.booleanValue() == true;
55
		boolean isOptimizedFalseAssertion = cst != Constant.NotAConstant && cst.booleanValue() == false;
55
		boolean isOptimizedFalseAssertion = cst != Constant.NotAConstant && cst.booleanValue() == false;
56
56
57
		FlowInfo assertInfo = flowInfo.copy();
57
		UnconditionalFlowInfo assertInfo = assertExpression.
58
			analyseCode(currentScope, flowContext, flowInfo.copy()).
59
			unconditionalInits();
58
		if (isOptimizedTrueAssertion) {
60
		if (isOptimizedTrueAssertion) {
59
			assertInfo.setReachMode(FlowInfo.UNREACHABLE);
61
			assertInfo.setReachMode(FlowInfo.UNREACHABLE);
60
		}
62
		}
61
		assertInfo = assertExpression.analyseCode(currentScope, flowContext, assertInfo).unconditionalInits();
62
		
63
		
63
		if (exceptionArgument != null) {
64
		if (exceptionArgument != null) {
64
			// only gets evaluated when escaping - results are not taken into account
65
			// only gets evaluated when escaping - results are not taken into account
Lines 80-86 Link Here
80
		if (isOptimizedFalseAssertion) {
81
		if (isOptimizedFalseAssertion) {
81
			return flowInfo; // if assertions are enabled, the following code will be unreachable
82
			return flowInfo; // if assertions are enabled, the following code will be unreachable
82
		} else {
83
		} else {
83
			return flowInfo.mergedWith(assertInfo.unconditionalInits()); 
84
			return flowInfo.mergedWith(assertInfo); 
84
		}
85
		}
85
	}
86
	}
86
87
Lines 163-169 Link Here
163
	
164
	
164
	public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
165
	public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
165
166
166
		if (!flowInfo.isReachable()) return;
167
		if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) {
167
		
168
		
168
		// need assertion flag: $assertionsDisabled on outer most source clas
169
		// need assertion flag: $assertionsDisabled on outer most source clas
169
		// (in case of static member of interface, will use the outermost static member - bug 22334)
170
		// (in case of static member of interface, will use the outermost static member - bug 22334)
Lines 186-191 Link Here
186
				break;
187
				break;
187
			}
188
			}
188
		}
189
		}
190
		}
189
	}
191
	}
190
192
191
	public StringBuffer printStatement(int tab, StringBuffer output) {
193
	public StringBuffer printStatement(int tab, StringBuffer output) {
(-)compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java (-28 / +36 lines)
Lines 36-69 Link Here
36
		this.sourceEnd = sourceEnd;
36
		this.sourceEnd = sourceEnd;
37
	}
37
	}
38
38
39
	public FlowInfo analyseCode(
39
public FlowInfo analyseCode(
40
		BlockScope currentScope,
40
	BlockScope currentScope,
41
		FlowContext flowContext,
41
	FlowContext flowContext,
42
		FlowInfo flowInfo) {
42
	FlowInfo flowInfo) {
43
		// record setting a variable: various scenarii are possible, setting an array reference, 
43
	// record setting a variable: various scenarii are possible, setting an array reference, 
44
		// a field reference, a blank final field reference, a field of an enclosing instance or 
44
	// a field reference, a blank final field reference, a field of an enclosing instance or 
45
		// just a local variable.
45
	// just a local variable.
46
46
	LocalVariableBinding local = this.lhs.localVariableBinding();
47
		LocalVariableBinding local = this.lhs.localVariableBinding();
47
	int nullStatus = this.expression.nullStatus(flowInfo);
48
		int nullStatus = this.expression.nullStatus(flowInfo);
48
	if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) {
49
		if (local != null && nullStatus == FlowInfo.NULL) {
49
		if (nullStatus == FlowInfo.NULL) {
50
				flowContext.recordUsingNullReference(currentScope, local, this.lhs, FlowInfo.NON_NULL, flowInfo);
50
			flowContext.recordUsingNullReference(currentScope, local, this.lhs, 
51
		}
51
				FlowContext.CAN_ONLY_NULL, flowInfo);
52
		flowInfo = ((Reference) lhs)
52
		}
53
			.analyseAssignment(currentScope, flowContext, flowInfo, this, false)
53
	}
54
			.unconditionalInits();
54
	flowInfo = ((Reference) lhs)
55
		if (local != null) {
55
		.analyseAssignment(currentScope, flowContext, flowInfo, this, false)
56
			switch(nullStatus) {
56
		.unconditionalInits();
57
				case FlowInfo.NULL :
57
	if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) {
58
					flowInfo.markAsDefinitelyNull(local);
58
		switch(nullStatus) {
59
					break;
59
			case FlowInfo.NULL :
60
				case FlowInfo.NON_NULL :
60
				flowInfo.markAsDefinitelyNull(local);
61
					flowInfo.markAsDefinitelyNonNull(local);
61
				break;
62
					break;
62
			case FlowInfo.NON_NULL :
63
			}
63
				flowInfo.markAsDefinitelyNonNull(local);
64
		}		
64
				break;
65
		return flowInfo;
65
			default:
66
	}
66
				flowInfo.markAsDefinitelyUnknown(local);
67
		}
68
	}		
69
	return flowInfo;
70
}
67
71
68
	void checkAssignmentEffect(BlockScope scope) {
72
	void checkAssignmentEffect(BlockScope scope) {
69
		
73
		
Lines 250-253 Link Here
250
		}
254
		}
251
		visitor.endVisit(this, scope);
255
		visitor.endVisit(this, scope);
252
	}
256
	}
257
258
public LocalVariableBinding localVariableBinding() {
259
	return lhs.localVariableBinding();
260
}
253
}
261
}
(-)compiler/org/eclipse/jdt/internal/compiler/ast/BinaryExpression.java (-9 / +8 lines)
Lines 31-48 Link Here
31
		this.sourceEnd = right.sourceEnd;
31
		this.sourceEnd = right.sourceEnd;
32
	}
32
	}
33
33
34
	public FlowInfo analyseCode(
34
public FlowInfo analyseCode(
35
		BlockScope currentScope,
35
		BlockScope currentScope,
36
		FlowContext flowContext,
36
		FlowContext flowContext,
37
		FlowInfo flowInfo) {
37
		FlowInfo flowInfo) {
38
38
	left.checkNPE(currentScope, flowContext, flowInfo, false /* skip String */);
39
		return right
39
	flowInfo = left.analyseCode(currentScope, flowContext, flowInfo).
40
			.analyseCode(
40
		unconditionalInits();
41
				currentScope,
41
	right.checkNPE(currentScope, flowContext, flowInfo, false /* skip String */);
42
				flowContext,
42
	return right.analyseCode(currentScope, flowContext, flowInfo).
43
				left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits())
43
		unconditionalInits();
44
			.unconditionalInits();
44
}
45
	}
46
45
47
	public void computeConstant(BlockScope scope, int leftId, int rightId) {
46
	public void computeConstant(BlockScope scope, int leftId, int rightId) {
48
47
(-)compiler/org/eclipse/jdt/internal/compiler/ast/Clinit.java (-1 / +2 lines)
Lines 45-51 Link Here
45
					FlowInfo.DEAD_END);
45
					FlowInfo.DEAD_END);
46
46
47
			// check for missing returning path
47
			// check for missing returning path
48
			this.needFreeReturn = flowInfo.isReachable();
48
			this.needFreeReturn = (flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0;
49
49
50
50
			// check missing blank final field initializations
51
			// check missing blank final field initializations
51
			flowInfo = flowInfo.mergedWith(staticInitializerFlowContext.initsOnReturn);
52
			flowInfo = flowInfo.mergedWith(staticInitializerFlowContext.initsOnReturn);
(-)compiler/org/eclipse/jdt/internal/compiler/ast/CompoundAssignment.java (-10 / +12 lines)
Lines 34-46 Link Here
34
		this.operator = operator ;
34
		this.operator = operator ;
35
	}
35
	}
36
	
36
	
37
	public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
37
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, 
38
		// record setting a variable: various scenarii are possible, setting an array reference, 
38
		FlowInfo flowInfo) {
39
		// a field reference, a blank final field reference, a field of an enclosing instance or 
39
	// record setting a variable: various scenarii are possible, setting an array reference, 
40
		// just a local variable.
40
	// a field reference, a blank final field reference, a field of an enclosing instance or 
41
	
41
	// just a local variable.
42
		return  ((Reference) lhs).analyseAssignment(currentScope, flowContext, flowInfo, this, true).unconditionalInits();
42
	lhs.checkNPE(currentScope, flowContext, flowInfo, false /* skip String */);
43
	}
43
	return  ((Reference) lhs).analyseAssignment(currentScope, flowContext, flowInfo, this, true).unconditionalInits();
44
}
44
	
45
	
45
	public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
46
	public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
46
	
47
	
Lines 56-64 Link Here
56
		codeStream.recordPositionsFrom(pc, this.sourceStart);
57
		codeStream.recordPositionsFrom(pc, this.sourceStart);
57
	}
58
	}
58
	
59
	
59
	public int nullStatus(FlowInfo flowInfo) {
60
public int nullStatus(FlowInfo flowInfo) {
60
		return FlowInfo.NON_NULL;
61
	return FlowInfo.NON_NULL;
61
	}
62
	// we may have complained on checkNPE, but we avoid duplicate error 
63
}
62
	
64
	
63
	public String operatorToString() {
65
	public String operatorToString() {
64
		switch (operator) {
66
		switch (operator) {
(-)compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java (-11 / +22 lines)
Lines 40-50 Link Here
40
		sourceEnd = valueIfFalse.sourceEnd;
40
		sourceEnd = valueIfFalse.sourceEnd;
41
	}
41
	}
42
42
43
	public FlowInfo analyseCode(
43
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext,
44
		BlockScope currentScope,
45
		FlowContext flowContext,
46
		FlowInfo flowInfo) {
44
		FlowInfo flowInfo) {
47
48
		Constant cst = this.condition.optimizedBooleanConstant();
45
		Constant cst = this.condition.optimizedBooleanConstant();
49
		boolean isConditionOptimizedTrue = cst != Constant.NotAConstant && cst.booleanValue() == true;
46
		boolean isConditionOptimizedTrue = cst != Constant.NotAConstant && cst.booleanValue() == true;
50
		boolean isConditionOptimizedFalse = cst != Constant.NotAConstant && cst.booleanValue() == false;
47
		boolean isConditionOptimizedFalse = cst != Constant.NotAConstant && cst.booleanValue() == false;
Lines 84-99 Link Here
84
			boolean isValueIfFalseOptimizedTrue = cst != null && cst != Constant.NotAConstant && cst.booleanValue() == true;
81
			boolean isValueIfFalseOptimizedTrue = cst != null && cst != Constant.NotAConstant && cst.booleanValue() == true;
85
			boolean isValueIfFalseOptimizedFalse = cst != null && cst != Constant.NotAConstant && cst.booleanValue() == false;
82
			boolean isValueIfFalseOptimizedFalse = cst != null && cst != Constant.NotAConstant && cst.booleanValue() == false;
86
83
87
			UnconditionalFlowInfo trueInfoWhenTrue = trueFlowInfo.initsWhenTrue().copy().unconditionalInits();
84
			UnconditionalFlowInfo trueInfoWhenTrue = trueFlowInfo.initsWhenTrue().unconditionalCopy();
85
			UnconditionalFlowInfo falseInfoWhenTrue = falseFlowInfo.initsWhenTrue().unconditionalCopy();
86
			UnconditionalFlowInfo trueInfoWhenFalse = trueFlowInfo.initsWhenFalse().unconditionalInits();
87
			UnconditionalFlowInfo falseInfoWhenFalse = falseFlowInfo.initsWhenFalse().unconditionalInits();
88
			if (isValueIfTrueOptimizedFalse) trueInfoWhenTrue.setReachMode(FlowInfo.UNREACHABLE); 
88
			if (isValueIfTrueOptimizedFalse) trueInfoWhenTrue.setReachMode(FlowInfo.UNREACHABLE); 
89
90
			UnconditionalFlowInfo falseInfoWhenTrue = falseFlowInfo.initsWhenTrue().copy().unconditionalInits();
91
			if (isValueIfFalseOptimizedFalse) falseInfoWhenTrue.setReachMode(FlowInfo.UNREACHABLE); 
89
			if (isValueIfFalseOptimizedFalse) falseInfoWhenTrue.setReachMode(FlowInfo.UNREACHABLE); 
92
			
93
			UnconditionalFlowInfo trueInfoWhenFalse = trueFlowInfo.initsWhenFalse().copy().unconditionalInits();
94
			if (isValueIfTrueOptimizedTrue) trueInfoWhenFalse.setReachMode(FlowInfo.UNREACHABLE); 
90
			if (isValueIfTrueOptimizedTrue) trueInfoWhenFalse.setReachMode(FlowInfo.UNREACHABLE); 
95
96
			UnconditionalFlowInfo falseInfoWhenFalse = falseFlowInfo.initsWhenFalse().copy().unconditionalInits();
97
			if (isValueIfFalseOptimizedTrue) falseInfoWhenFalse.setReachMode(FlowInfo.UNREACHABLE); 
91
			if (isValueIfFalseOptimizedTrue) falseInfoWhenFalse.setReachMode(FlowInfo.UNREACHABLE); 
98
92
99
			mergedInfo =
93
			mergedInfo =
Lines 271-276 Link Here
271
		// no implicit conversion for boolean values
265
		// no implicit conversion for boolean values
272
		codeStream.updateLastRecordedEndPC(currentScope, codeStream.position);
266
		codeStream.updateLastRecordedEndPC(currentScope, codeStream.position);
273
	}
267
	}
268
	
269
public int nullStatus(FlowInfo flowInfo) {
270
	Constant cst = this.condition.optimizedBooleanConstant();
271
	if (cst != Constant.NotAConstant) {
272
		if (cst.booleanValue()) {
273
			return valueIfTrue.nullStatus(flowInfo);
274
		}
275
		return valueIfFalse.nullStatus(flowInfo);
276
	}
277
	int ifTrueNullStatus = valueIfTrue.nullStatus(flowInfo),
278
	    ifFalseNullStatus = valueIfFalse.nullStatus(flowInfo);
279
	if (ifTrueNullStatus == ifFalseNullStatus) {
280
		return ifTrueNullStatus;
281
	}
282
	return FlowInfo.UNKNOWN;
283
	// cannot decide which branch to take, and they disagree
284
}
274
285
275
	public Constant optimizedBooleanConstant() {
286
	public Constant optimizedBooleanConstant() {
276
287
(-)compiler/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java (-1 / +2 lines)
Lines 112-118 Link Here
112
				}
112
				}
113
			}
113
			}
114
			// check for missing returning path
114
			// check for missing returning path
115
			this.needFreeReturn = flowInfo.isReachable();
115
			this.needFreeReturn = (flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0;
116
116
117
117
			// check missing blank final field initializations
118
			// check missing blank final field initializations
118
			if ((constructorCall != null)
119
			if ((constructorCall != null)
(-)compiler/org/eclipse/jdt/internal/compiler/ast/ContinueStatement.java (-1 / +1 lines)
Lines 71-77 Link Here
71
				flowInfo.addInitializationsFrom(tryStatement.subRoutineInits); // collect inits			
71
				flowInfo.addInitializationsFrom(tryStatement.subRoutineInits); // collect inits			
72
			} else if (traversedContext == targetContext) {
72
			} else if (traversedContext == targetContext) {
73
				// only record continue info once accumulated through subroutines, and only against target context
73
				// only record continue info once accumulated through subroutines, and only against target context
74
				targetContext.recordContinueFrom(flowInfo);
74
				targetContext.recordContinueFrom(flowContext, flowInfo);
75
				break;
75
				break;
76
			}
76
			}
77
		} while ((traversedContext = traversedContext.parent) != null);
77
		} while ((traversedContext = traversedContext.parent) != null);
(-)compiler/org/eclipse/jdt/internal/compiler/ast/DoStatement.java (-9 / +30 lines)
Lines 46-51 Link Here
46
		LoopingFlowContext loopingContext =
46
		LoopingFlowContext loopingContext =
47
			new LoopingFlowContext(
47
			new LoopingFlowContext(
48
				flowContext,
48
				flowContext,
49
				flowInfo,
49
				this,
50
				this,
50
				breakLabel,
51
				breakLabel,
51
				continueLabel,
52
				continueLabel,
Lines 59-70 Link Here
59
60
60
		int previousMode = flowInfo.reachMode();
61
		int previousMode = flowInfo.reachMode();
61
				
62
				
62
		FlowInfo actionInfo = flowInfo.copy().unconditionalInits().discardNullRelatedInitializations();
63
		UnconditionalFlowInfo actionInfo = flowInfo.nullInfoLessUnconditionalCopy();
64
		// we need to collect the contribution to nulls of the coming paths through the
65
		// loop, be they falling through normally or branched to break, continue labels
66
		// or catch blocks
63
		if ((action != null) && !action.isEmptyBlock()) {
67
		if ((action != null) && !action.isEmptyBlock()) {
64
			actionInfo = action.analyseCode(currentScope, loopingContext, actionInfo);
68
			actionInfo = action.
69
				analyseCode(currentScope, loopingContext, actionInfo).
70
				unconditionalInits();
65
71
66
			// code generation can be optimized when no need to continue in the loop
72
			// code generation can be optimized when no need to continue in the loop
67
			if (!actionInfo.isReachable() && !loopingContext.initsOnContinue.isReachable()) {
73
			if ((actionInfo.tagBits & 
74
					loopingContext.initsOnContinue.tagBits & 
75
					FlowInfo.UNREACHABLE) != 0) {
68
				continueLabel = null;
76
				continueLabel = null;
69
			}
77
			}
70
		}
78
		}
Lines 75-96 Link Here
75
		 */
83
		 */
76
		actionInfo.setReachMode(previousMode);
84
		actionInfo.setReachMode(previousMode);
77
		
85
		
78
		actionInfo =
86
		LoopingFlowContext condLoopContext;
87
		FlowInfo condInfo =
79
			condition.analyseCode(
88
			condition.analyseCode(
80
				currentScope,
89
				currentScope,
81
				loopingContext,
90
				(condLoopContext =
91
					new LoopingFlowContext(flowContext,	flowInfo, this, null, 
92
						null, currentScope)),
82
				(action == null
93
				(action == null
83
					? actionInfo
94
					? actionInfo
84
					: (actionInfo.mergedWith(loopingContext.initsOnContinue))));
95
					: (actionInfo.mergedWith(loopingContext.initsOnContinue))).copy());
85
		if (!isConditionOptimizedFalse && continueLabel != null) {
96
		if (!isConditionOptimizedFalse && continueLabel != null) {
86
			loopingContext.complainOnDeferredChecks(currentScope, actionInfo);
97
			loopingContext.complainOnDeferredFinalChecks(currentScope, condInfo);
98
			condLoopContext.complainOnDeferredFinalChecks(currentScope, condInfo);
99
			UnconditionalFlowInfo checkFlowInfo;
100
			loopingContext.complainOnDeferredNullChecks(currentScope, 
101
					checkFlowInfo = actionInfo.
102
						addPotentialNullInfoFrom(
103
						  condInfo.initsWhenTrue().unconditionalInits()));
104
			condLoopContext.complainOnDeferredNullChecks(currentScope, 
105
					checkFlowInfo);
87
		}
106
		}
88
107
89
		// end of loop
108
		// end of loop
90
		FlowInfo mergedInfo = FlowInfo.mergedOptimizedBranches(
109
		FlowInfo mergedInfo = FlowInfo.mergedOptimizedBranches(
91
				loopingContext.initsOnBreak, 
110
				loopingContext.initsOnBreak, 
92
				isConditionOptimizedTrue, 
111
				isConditionOptimizedTrue,
93
				actionInfo.initsWhenFalse().addInitializationsFrom(flowInfo), // recover null inits from before condition analysis
112
				(condInfo.tagBits & FlowInfo.UNREACHABLE) == 0 ?
113
						flowInfo.addInitializationsFrom(condInfo.initsWhenFalse()) : condInfo, 
114
					// recover null inits from before condition analysis
94
				false, // never consider opt false case for DO loop, since break can always occur (47776)
115
				false, // never consider opt false case for DO loop, since break can always occur (47776)
95
				!isConditionTrue /*do{}while(true); unreachable(); */);
116
				!isConditionTrue /*do{}while(true); unreachable(); */);
96
		mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo);
117
		mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo);
(-)compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java (-29 / +44 lines)
Lines 22-105 Link Here
22
	public EqualExpression(Expression left, Expression right,int operator) {
22
	public EqualExpression(Expression left, Expression right,int operator) {
23
		super(left,right,operator);
23
		super(left,right,operator);
24
	}
24
	}
25
	public void checkNullComparison(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, FlowInfo initsWhenTrue, FlowInfo initsWhenFalse) {
25
	private void checkNullComparison(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, FlowInfo initsWhenTrue, FlowInfo initsWhenFalse) {
26
		
26
		
27
		LocalVariableBinding local = this.left.localVariableBinding();
27
		LocalVariableBinding local = this.left.localVariableBinding();
28
		if (local != null) {
28
		if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) {
29
			checkVariableComparison(scope, flowContext, flowInfo, initsWhenTrue, initsWhenFalse, local, right.nullStatus(flowInfo), this.left);
29
			checkVariableComparison(scope, flowContext, flowInfo, initsWhenTrue, initsWhenFalse, local, right.nullStatus(flowInfo), this.left);
30
		}
30
		}
31
		local = this.right.localVariableBinding();
31
		local = this.right.localVariableBinding();
32
		if (local != null) {
32
		if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) {
33
			checkVariableComparison(scope, flowContext, flowInfo, initsWhenTrue, initsWhenFalse, local, left.nullStatus(flowInfo), this.right);
33
			checkVariableComparison(scope, flowContext, flowInfo, initsWhenTrue, initsWhenFalse, local, left.nullStatus(flowInfo), this.right);
34
		}
34
		}
35
	}
35
	}
36
	private void checkVariableComparison(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, FlowInfo initsWhenTrue, FlowInfo initsWhenFalse, LocalVariableBinding local, int nullStatus, Expression reference) {
36
	private void checkVariableComparison(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, FlowInfo initsWhenTrue, FlowInfo initsWhenFalse, LocalVariableBinding local, int nullStatus, Expression reference) {
37
		switch (nullStatus) {
37
		switch (nullStatus) {
38
			case FlowInfo.NULL :
38
			case FlowInfo.NULL :
39
				flowContext.recordUsingNullReference(scope, local, reference, FlowInfo.NULL, flowInfo);
39
				flowContext.recordUsingNullReference(scope, local, reference, 
40
					FlowContext.CAN_ONLY_NULL_NON_NULL, flowInfo);
40
				if (((this.bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL) {
41
				if (((this.bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL) {
41
					initsWhenTrue.markAsDefinitelyNull(local); // from thereon it is set
42
					initsWhenTrue.markAsComparedEqualToNull(local); // from thereon it is set
42
					initsWhenFalse.markAsDefinitelyNonNull(local); // from thereon it is set
43
					initsWhenFalse.markAsComparedEqualToNonNull(local); // from thereon it is set
43
				} else {
44
				} else {
44
					initsWhenTrue.markAsDefinitelyNonNull(local); // from thereon it is set
45
					initsWhenTrue.markAsComparedEqualToNonNull(local); // from thereon it is set
45
					initsWhenFalse.markAsDefinitelyNull(local); // from thereon it is set
46
					initsWhenFalse.markAsComparedEqualToNull(local); // from thereon it is set
46
				}
47
				}
47
				break;
48
				break;
48
			case FlowInfo.NON_NULL :
49
			case FlowInfo.NON_NULL :
49
				flowContext.recordUsingNullReference(scope, local, reference, FlowInfo.NON_NULL, flowInfo);
50
				flowContext.recordUsingNullReference(scope, local, reference, 
51
					FlowContext.CAN_ONLY_NULL, flowInfo);
50
				if (((this.bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL) {
52
				if (((this.bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL) {
51
					initsWhenTrue.markAsDefinitelyNonNull(local); // from thereon it is set
53
					initsWhenTrue.markAsComparedEqualToNonNull(local); // from thereon it is set
52
				}
54
				}
53
				break;
55
				break;
54
		}	
56
		}	
55
	}
57
	}
56
	
58
	
57
	public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
59
	public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
60
		FlowInfo result;
58
		if (((bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL) {
61
		if (((bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL) {
59
			if ((left.constant != Constant.NotAConstant) && (left.constant.typeID() == T_boolean)) {
62
			if ((left.constant != Constant.NotAConstant) && (left.constant.typeID() == T_boolean)) {
60
				if (left.constant.booleanValue()) { //  true == anything
63
				if (left.constant.booleanValue()) { //  true == anything
61
					//  this is equivalent to the right argument inits 
64
					//  this is equivalent to the right argument inits 
62
					return right.analyseCode(currentScope, flowContext, flowInfo);
65
					result = right.analyseCode(currentScope, flowContext, flowInfo);
63
				} else { // false == anything
66
				} else { // false == anything
64
					//  this is equivalent to the right argument inits negated
67
					//  this is equivalent to the right argument inits negated
65
					return right.analyseCode(currentScope, flowContext, flowInfo).asNegatedCondition();
68
					result = right.analyseCode(currentScope, flowContext, flowInfo).asNegatedCondition();
66
				}
69
				}
67
			}
70
			} 
68
			if ((right.constant != Constant.NotAConstant) && (right.constant.typeID() == T_boolean)) {
71
			else if ((right.constant != Constant.NotAConstant) && (right.constant.typeID() == T_boolean)) {
69
				if (right.constant.booleanValue()) { //  anything == true
72
				if (right.constant.booleanValue()) { //  anything == true
70
					//  this is equivalent to the right argument inits 
73
					//  this is equivalent to the left argument inits 
71
					return left.analyseCode(currentScope, flowContext, flowInfo);
74
					result = left.analyseCode(currentScope, flowContext, flowInfo);
72
				} else { // anything == false
75
				} else { // anything == false
73
					//  this is equivalent to the right argument inits negated
76
					//  this is equivalent to the right argument inits negated
74
					return left.analyseCode(currentScope, flowContext, flowInfo).asNegatedCondition();
77
					result = left.analyseCode(currentScope, flowContext, flowInfo).asNegatedCondition();
75
				}
78
				}
79
			} 
80
			else {
81
				result = right.analyseCode(
82
					currentScope, flowContext, 
83
					left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits()).unconditionalInits();
76
			}
84
			}
77
			return right.analyseCode(
78
				currentScope, flowContext, 
79
				left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits()).unconditionalInits();
80
		} else { //NOT_EQUAL :
85
		} else { //NOT_EQUAL :
81
			if ((left.constant != Constant.NotAConstant) && (left.constant.typeID() == T_boolean)) {
86
			if ((left.constant != Constant.NotAConstant) && (left.constant.typeID() == T_boolean)) {
82
				if (!left.constant.booleanValue()) { //  false != anything
87
				if (!left.constant.booleanValue()) { //  false != anything
83
					//  this is equivalent to the right argument inits 
88
					//  this is equivalent to the right argument inits 
84
					return right.analyseCode(currentScope, flowContext, flowInfo);
89
					result = right.analyseCode(currentScope, flowContext, flowInfo);
85
				} else { // true != anything
90
				} else { // true != anything
86
					//  this is equivalent to the right argument inits negated
91
					//  this is equivalent to the right argument inits negated
87
					return right.analyseCode(currentScope, flowContext, flowInfo).asNegatedCondition();
92
					result = right.analyseCode(currentScope, flowContext, flowInfo).asNegatedCondition();
88
				}
93
				}
89
			}
94
			}
90
			if ((right.constant != Constant.NotAConstant) && (right.constant.typeID() == T_boolean)) {
95
			else if ((right.constant != Constant.NotAConstant) && (right.constant.typeID() == T_boolean)) {
91
				if (!right.constant.booleanValue()) { //  anything != false
96
				if (!right.constant.booleanValue()) { //  anything != false
92
					//  this is equivalent to the right argument inits 
97
					//  this is equivalent to the right argument inits 
93
					return left.analyseCode(currentScope, flowContext, flowInfo);
98
					result = left.analyseCode(currentScope, flowContext, flowInfo);
94
				} else { // anything != true
99
				} else { // anything != true
95
					//  this is equivalent to the right argument inits negated
100
					//  this is equivalent to the right argument inits negated
96
					return left.analyseCode(currentScope, flowContext, flowInfo).asNegatedCondition();
101
					result = left.analyseCode(currentScope, flowContext, flowInfo).asNegatedCondition();
97
				}
102
				}
98
			}
103
			} 
99
			return right.analyseCode(
104
			else {
100
				currentScope, flowContext, 
105
				result = right.analyseCode(
101
				left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits()).asNegatedCondition().unconditionalInits();
106
					currentScope, flowContext, 
107
					left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits()).
108
					/* unneeded since we flatten it: asNegatedCondition(). */
109
					unconditionalInits();
110
			}
111
		}
112
		if (result instanceof UnconditionalFlowInfo && 
113
				(result.tagBits & FlowInfo.UNREACHABLE) == 0) { // the flow info is flat
114
			result = FlowInfo.conditional(result, result.copy());
102
		}
115
		}
116
	  checkNullComparison(currentScope, flowContext, result, result.initsWhenTrue(), result.initsWhenFalse());
117
	  return result;
103
	}
118
	}
104
	
119
	
105
	public final void computeConstant(TypeBinding leftType, TypeBinding rightType) {
120
	public final void computeConstant(TypeBinding leftType, TypeBinding rightType) {
(-)compiler/org/eclipse/jdt/internal/compiler/ast/ExplicitConstructorCall.java (-2 / +4 lines)
Lines 178-184 Link Here
178
	void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
178
	void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
179
		ReferenceBinding superTypeErasure = (ReferenceBinding) binding.declaringClass.erasure();
179
		ReferenceBinding superTypeErasure = (ReferenceBinding) binding.declaringClass.erasure();
180
180
181
		if (!flowInfo.isReachable()) return;
181
		if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0)	{
182
		// perform some emulation work in case there is some and we are inside a local type only
182
		// perform some emulation work in case there is some and we are inside a local type only
183
		if (superTypeErasure.isNestedType()
183
		if (superTypeErasure.isNestedType()
184
			&& currentScope.enclosingSourceType().isLocalType()) {
184
			&& currentScope.enclosingSourceType().isLocalType()) {
Lines 190-200 Link Here
190
				currentScope.propagateInnerEmulation(superTypeErasure, qualification != null);
190
				currentScope.propagateInnerEmulation(superTypeErasure, qualification != null);
191
			}
191
			}
192
		}
192
		}
193
		}
193
	}
194
	}
194
195
195
	public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
196
	public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
196
197
197
		if (!flowInfo.isReachable()) return;
198
		if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0)	{
198
		// if constructor from parameterized type got found, use the original constructor at codegen time
199
		// if constructor from parameterized type got found, use the original constructor at codegen time
199
		this.codegenBinding = this.binding.original();
200
		this.codegenBinding = this.binding.original();
200
		
201
		
Lines 210-215 Link Here
210
				currentScope.problemReporter().needToEmulateMethodAccess(this.codegenBinding, this);
211
				currentScope.problemReporter().needToEmulateMethodAccess(this.codegenBinding, this);
211
			}
212
			}
212
		}
213
		}
214
		}
213
	}
215
	}
214
216
215
	public StringBuffer printStatement(int indent, StringBuffer output) {
217
	public StringBuffer printStatement(int indent, StringBuffer output) {
(-)compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java (-24 / +34 lines)
Lines 481-511 Link Here
481
		}
481
		}
482
	}	
482
	}	
483
	
483
	
484
	public void checkNullComparison(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, FlowInfo initsWhenTrue, FlowInfo initsWhenFalse) {
484
/**
485
		// do nothing by default - see EqualExpression
485
 * Check the local variable of this expression, if any, against potential NPEs 
486
	}
486
 * given a flow context and an upstream flow info. If so, report the risk to
487
487
 * the context. Marks the local as checked, which affects the flow info.
488
	public FlowInfo checkNullStatus(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, int nullStatus) {
488
 * @param scope the scope of the analysis
489
489
 * @param flowContext the current flow context
490
		LocalVariableBinding local = this.localVariableBinding();
490
 * @param flowInfo the upstream flow info; caveat: may get modified
491
		if (local != null) {
491
 * @param checkString if true, a local variable of type String is checked; else
492
			switch(nullStatus) {
492
 *        it is skipped
493
				case FlowInfo.NULL :
493
 */
494
					flowContext.recordUsingNullReference(scope, local, this, FlowInfo.NULL, flowInfo);
494
public void checkNPE(BlockScope scope, FlowContext flowContext, 
495
					flowInfo.markAsDefinitelyNull(local); // from thereon it is set
495
		FlowInfo flowInfo, boolean checkString) {
496
					break;
496
	LocalVariableBinding local = this.localVariableBinding();
497
				case FlowInfo.NON_NULL :
497
	if (local != null && 
498
					flowContext.recordUsingNullReference(scope, local, this, FlowInfo.NON_NULL, flowInfo);
498
			(local.type.tagBits & TagBits.IsBaseType) == 0 &&
499
					flowInfo.markAsDefinitelyNonNull(local); // from thereon it is set
499
			(checkString || local.type.id != T_JavaLangString)) {
500
					break;
500
		if ((this.bits & IsNonNull) == 0) {
501
				case FlowInfo.UNKNOWN :
501
			flowContext.recordUsingNullReference(scope, local, this, 
502
					break;
502
					FlowContext.MAY_NULL, flowInfo);
503
			}
504
		}
503
		}
505
		return flowInfo;
504
		flowInfo.markAsComparedEqualToNonNull(local); 
505
			// from thereon it is set
506
	}
506
	}
507
	
507
}
508
	public boolean checkUnsafeCast(Scope scope, TypeBinding castType, TypeBinding expressionType, TypeBinding match, boolean isNarrowing) {
508
509
public boolean checkUnsafeCast(Scope scope, TypeBinding castType, TypeBinding expressionType, TypeBinding match, boolean isNarrowing) {
509
		if (match == castType) {
510
		if (match == castType) {
510
			if (!isNarrowing) tagAsUnnecessaryCast(scope, castType);
511
			if (!isNarrowing) tagAsUnnecessaryCast(scope, castType);
511
			return true;
512
			return true;
Lines 795-803 Link Here
795
		return null;
796
		return null;
796
	}
797
	}
797
	
798
	
799
/**
800
 * Mark this expression as being non null, per a NON-NULL or NN tag in the
801
 * source code.
802
 */
803
public void markAsNonNull() {
804
	this.bits |= IsNonNull;
805
}
806
798
	public int nullStatus(FlowInfo flowInfo) {
807
	public int nullStatus(FlowInfo flowInfo) {
799
		
808
		
800
		if (this.constant != null && this.constant != Constant.NotAConstant)
809
		if ((this.bits & IsNonNull) != 0 || 
810
				this.constant != null && this.constant != Constant.NotAConstant)
801
			return FlowInfo.NON_NULL; // constant expression cannot be null
811
			return FlowInfo.NON_NULL; // constant expression cannot be null
802
		
812
		
803
		LocalVariableBinding local = localVariableBinding();
813
		LocalVariableBinding local = localVariableBinding();
(-)compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java (-2 / +9 lines)
Lines 98-104 Link Here
98
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
98
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
99
	boolean nonStatic = !binding.isStatic();
99
	boolean nonStatic = !binding.isStatic();
100
	receiver.analyseCode(currentScope, flowContext, flowInfo, nonStatic);
100
	receiver.analyseCode(currentScope, flowContext, flowInfo, nonStatic);
101
	if (nonStatic) receiver.checkNullStatus(currentScope, flowContext, flowInfo, FlowInfo.NON_NULL);
101
	if (nonStatic) {
102
		receiver.checkNPE(currentScope, flowContext, flowInfo, true);
103
	}
102
	
104
	
103
	if (valueRequired || currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4) {
105
	if (valueRequired || currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4) {
104
		manageSyntheticAccessIfNecessary(currentScope, flowInfo, true /*read-access*/);
106
		manageSyntheticAccessIfNecessary(currentScope, flowInfo, true /*read-access*/);
Lines 349-355 Link Here
349
 * No need to emulate access to protected fields since not implicitly accessed
351
 * No need to emulate access to protected fields since not implicitly accessed
350
 */
352
 */
351
public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo, boolean isReadAccess) {
353
public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo, boolean isReadAccess) {
352
	if (!flowInfo.isReachable()) return;
354
	if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) != 0)	return;
355
353
	// if field from parameterized type got found, use the original field at codegen time
356
	// if field from parameterized type got found, use the original field at codegen time
354
	this.codegenBinding = this.binding.original();
357
	this.codegenBinding = this.binding.original();
355
	
358
	
Lines 415-420 Link Here
415
	}		
418
	}		
416
}
419
}
417
420
421
public int nullStatus(FlowInfo flowInfo) {
422
	return FlowInfo.UNKNOWN;
423
}
424
418
public Constant optimizedBooleanConstant() {
425
public Constant optimizedBooleanConstant() {
419
	switch (this.resolvedType.id) {
426
	switch (this.resolvedType.id) {
420
		case T_boolean :
427
		case T_boolean :
(-)compiler/org/eclipse/jdt/internal/compiler/ast/ForStatement.java (-23 / +58 lines)
Lines 83-120 Link Here
83
		
83
		
84
		// process the condition
84
		// process the condition
85
		LoopingFlowContext condLoopContext = null;
85
		LoopingFlowContext condLoopContext = null;
86
		FlowInfo condInfo = flowInfo.copy().unconditionalInits().discardNullRelatedInitializations();
86
		FlowInfo condInfo = flowInfo.nullInfoLessUnconditionalCopy();
87
		if (condition != null) {
87
		if (condition != null) {
88
			if (!isConditionTrue) {
88
			if (!isConditionTrue) {
89
				condInfo =
89
				condInfo =
90
					condition.analyseCode(
90
					condition.analyseCode(
91
						scope,
91
						scope,
92
						(condLoopContext =
92
						(condLoopContext =
93
							new LoopingFlowContext(flowContext, this, null, null, scope)),
93
							new LoopingFlowContext(flowContext, flowInfo, this, null, 
94
								null, scope)),
94
						condInfo);
95
						condInfo);
95
			}
96
			}
96
		}
97
		}
97
98
98
		// process the action
99
		// process the action
99
		LoopingFlowContext loopingContext;
100
		LoopingFlowContext loopingContext;
100
		FlowInfo actionInfo;
101
		UnconditionalFlowInfo actionInfo;
101
		if (action == null 
102
		if (action == null 
102
			|| (action.isEmptyBlock() && currentScope.compilerOptions().complianceLevel <= ClassFileConstants.JDK1_3)) {
103
			|| (action.isEmptyBlock() && currentScope.compilerOptions().complianceLevel <= ClassFileConstants.JDK1_3)) {
103
			if (condLoopContext != null)
104
			if (condLoopContext != null)
104
				condLoopContext.complainOnDeferredChecks(scope, condInfo);
105
				condLoopContext.complainOnDeferredFinalChecks(scope, condInfo);
105
			if (isConditionTrue) {
106
			if (isConditionTrue) {
107
				if (condLoopContext != null) {
108
					condLoopContext.complainOnDeferredNullChecks(currentScope,
109
						condInfo);
110
				}
106
				return FlowInfo.DEAD_END;
111
				return FlowInfo.DEAD_END;
107
			} else {
112
			} else {
108
				if (isConditionFalse){
113
				if (isConditionFalse){
109
					continueLabel = null; // for(;false;p());
114
					continueLabel = null; // for(;false;p());
110
				}
115
				}
111
				actionInfo = condInfo.initsWhenTrue().copy().unconditionalInits().discardNullRelatedInitializations();
116
				actionInfo = condInfo.initsWhenTrue().unconditionalCopy();
112
				loopingContext =
117
				loopingContext =
113
					new LoopingFlowContext(flowContext, this, breakLabel, continueLabel, scope);
118
					new LoopingFlowContext(flowContext, flowInfo, this, 
119
						breakLabel, continueLabel, scope);
114
			}
120
			}
115
		} else {
121
		} 
122
		else {
116
			loopingContext =
123
			loopingContext =
117
				new LoopingFlowContext(flowContext, this, breakLabel, continueLabel, scope);
124
				new LoopingFlowContext(flowContext, flowInfo, this, breakLabel, 
125
					continueLabel, scope);
118
			FlowInfo initsWhenTrue = condInfo.initsWhenTrue();
126
			FlowInfo initsWhenTrue = condInfo.initsWhenTrue();
119
			condIfTrueInitStateIndex =
127
			condIfTrueInitStateIndex =
120
				currentScope.methodScope().recordInitializationStates(initsWhenTrue);
128
				currentScope.methodScope().recordInitializationStates(initsWhenTrue);
Lines 122-159 Link Here
122
				if (isConditionFalse) {
130
				if (isConditionFalse) {
123
					actionInfo = FlowInfo.DEAD_END;
131
					actionInfo = FlowInfo.DEAD_END;
124
				} else {
132
				} else {
125
					actionInfo = initsWhenTrue.copy().unconditionalInits().discardNullRelatedInitializations();
133
					actionInfo = initsWhenTrue.unconditionalCopy();
126
					if (isConditionOptimizedFalse){
134
					if (isConditionOptimizedFalse){
127
						actionInfo.setReachMode(FlowInfo.UNREACHABLE);
135
						actionInfo.setReachMode(FlowInfo.UNREACHABLE);
128
					}
136
					}
129
				}
137
				}
130
			if (!this.action.complainIfUnreachable(actionInfo, scope, false)) {
138
			if (!this.action.complainIfUnreachable(actionInfo, scope, false)) {
131
				actionInfo = action.analyseCode(scope, loopingContext, actionInfo);
139
				actionInfo = action.analyseCode(scope, loopingContext, actionInfo).
140
					unconditionalInits();
132
			}
141
			}
133
142
134
			// code generation can be optimized when no need to continue in the loop
143
			// code generation can be optimized when no need to continue in the loop
135
			if (!actionInfo.isReachable() && !loopingContext.initsOnContinue.isReachable()) {
144
			if ((actionInfo.tagBits & 
145
					loopingContext.initsOnContinue.tagBits &
146
					FlowInfo.UNREACHABLE) != 0) {
136
				continueLabel = null;
147
				continueLabel = null;
137
			} else {
148
			} 
138
				if (condLoopContext != null)
149
			else {
139
					condLoopContext.complainOnDeferredChecks(scope, condInfo);
150
				if (condLoopContext != null) {
140
				actionInfo = actionInfo.mergedWith(loopingContext.initsOnContinue.unconditionalInits());
151
					condLoopContext.complainOnDeferredFinalChecks(scope, 
141
				loopingContext.complainOnDeferredChecks(scope, actionInfo);
152
							condInfo);
153
				}
154
				actionInfo = actionInfo.mergedWith(loopingContext.initsOnContinue);
155
				loopingContext.complainOnDeferredFinalChecks(scope, 
156
						actionInfo);
142
			}
157
			}
143
		}
158
		}
144
		// for increments
159
		// for increments
145
		FlowInfo exitBranch = condInfo.initsWhenFalse();
160
		FlowInfo exitBranch = flowInfo.copy();
146
		exitBranch.addInitializationsFrom(flowInfo); // recover null inits from before condition analysis
161
		// recover null inits from before condition analysis
162
		LoopingFlowContext incrementContext = null;
147
		if (continueLabel != null) {
163
		if (continueLabel != null) {
148
			if (increments != null) {
164
			if (increments != null) {
149
				LoopingFlowContext loopContext =
165
				incrementContext =
150
					new LoopingFlowContext(flowContext, this, null, null, scope);
166
					new LoopingFlowContext(flowContext, flowInfo, this, null, 
167
						null, scope);
168
				FlowInfo incrementInfo = actionInfo;
151
				for (int i = 0, count = increments.length; i < count; i++) {
169
				for (int i = 0, count = increments.length; i < count; i++) {
152
					actionInfo = increments[i].analyseCode(scope, loopContext, actionInfo);
170
					incrementInfo = increments[i].
171
						analyseCode(scope, incrementContext, incrementInfo);
153
				}
172
				}
154
				loopContext.complainOnDeferredChecks(scope, actionInfo);
173
				incrementContext.complainOnDeferredFinalChecks(scope,
174
						actionInfo = incrementInfo.unconditionalInits());
155
			}
175
			}
156
			exitBranch.addPotentialInitializationsFrom(actionInfo.unconditionalInits());
176
			exitBranch.addPotentialInitializationsFrom(actionInfo).
177
				addInitializationsFrom(condInfo.initsWhenFalse());
178
		}
179
		else {
180
			exitBranch.addInitializationsFrom(condInfo.initsWhenFalse());
181
		}
182
		// nulls checks
183
		if (condLoopContext != null) {
184
			condLoopContext.complainOnDeferredNullChecks(currentScope, 
185
				actionInfo);
186
		}
187
		loopingContext.complainOnDeferredNullChecks(currentScope, 
188
			actionInfo);
189
		if (incrementContext != null) {
190
			incrementContext.complainOnDeferredNullChecks(currentScope, 
191
				actionInfo);
157
		}
192
		}
158
193
159
		//end of loop
194
		//end of loop
(-)compiler/org/eclipse/jdt/internal/compiler/ast/ForeachStatement.java (-11 / +21 lines)
Lines 17-22 Link Here
17
import org.eclipse.jdt.internal.compiler.flow.FlowContext;
17
import org.eclipse.jdt.internal.compiler.flow.FlowContext;
18
import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
18
import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
19
import org.eclipse.jdt.internal.compiler.flow.LoopingFlowContext;
19
import org.eclipse.jdt.internal.compiler.flow.LoopingFlowContext;
20
import org.eclipse.jdt.internal.compiler.flow.UnconditionalFlowInfo;
20
import org.eclipse.jdt.internal.compiler.impl.Constant;
21
import org.eclipse.jdt.internal.compiler.impl.Constant;
21
import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
22
import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
22
import org.eclipse.jdt.internal.compiler.lookup.Binding;
23
import org.eclipse.jdt.internal.compiler.lookup.Binding;
Lines 80-88 Link Here
80
		continueLabel = new Label();
81
		continueLabel = new Label();
81
82
82
		// process the element variable and collection
83
		// process the element variable and collection
84
		this.collection.checkNPE(currentScope, flowContext, flowInfo, true);
83
		flowInfo = this.elementVariable.analyseCode(scope, flowContext, flowInfo);
85
		flowInfo = this.elementVariable.analyseCode(scope, flowContext, flowInfo);
84
		FlowInfo condInfo = flowInfo.copy().unconditionalInits().discardNullRelatedInitializations();
86
		FlowInfo condInfo = this.collection.analyseCode(scope, flowContext, flowInfo.copy());
85
		condInfo = this.collection.analyseCode(scope, flowContext, condInfo);
86
87
87
		// element variable will be assigned when iterating
88
		// element variable will be assigned when iterating
88
		condInfo.markAsDefinitelyAssigned(this.elementVariable.binding);
89
		condInfo.markAsDefinitelyAssigned(this.elementVariable.binding);
Lines 90-114 Link Here
90
		this.postCollectionInitStateIndex = currentScope.methodScope().recordInitializationStates(condInfo);
91
		this.postCollectionInitStateIndex = currentScope.methodScope().recordInitializationStates(condInfo);
91
		
92
		
92
		// process the action
93
		// process the action
93
		LoopingFlowContext loopingContext = new LoopingFlowContext(flowContext, this, breakLabel, continueLabel, scope);
94
		LoopingFlowContext loopingContext = 
94
		FlowInfo actionInfo = condInfo.initsWhenTrue().copy();
95
			new LoopingFlowContext(flowContext, flowInfo, this, breakLabel, 
96
				continueLabel, scope);
97
		UnconditionalFlowInfo actionInfo = 
98
			condInfo.nullInfoLessUnconditionalCopy();
95
		FlowInfo exitBranch;
99
		FlowInfo exitBranch;
96
		if (!(action == null || (action.isEmptyBlock() 
100
		if (!(action == null || (action.isEmptyBlock() 
97
		        	&& currentScope.compilerOptions().complianceLevel <= ClassFileConstants.JDK1_3))) {
101
		        	&& currentScope.compilerOptions().complianceLevel <= ClassFileConstants.JDK1_3))) {
98
102
99
			if (!this.action.complainIfUnreachable(actionInfo, scope, false)) {
103
			if (!this.action.complainIfUnreachable(actionInfo, scope, false)) {
100
				actionInfo = action.analyseCode(scope, loopingContext, actionInfo);
104
				actionInfo = action.
105
					analyseCode(scope, loopingContext, actionInfo).
106
					unconditionalCopy();
101
			}
107
			}
102
108
103
			// code generation can be optimized when no need to continue in the loop
109
			// code generation can be optimized when no need to continue in the loop
104
			exitBranch = condInfo.initsWhenFalse();
110
			exitBranch = flowInfo.unconditionalCopy().
105
			exitBranch.addInitializationsFrom(flowInfo); // recover null inits from before condition analysis			
111
				addInitializationsFrom(condInfo.initsWhenFalse()); 
106
			if (!actionInfo.isReachable() && !loopingContext.initsOnContinue.isReachable()) {
112
			// TODO (maxime) no need to test when false: can optimize (same for action being unreachable above) 
113
			if ((actionInfo.tagBits & loopingContext.initsOnContinue.tagBits &
114
					FlowInfo.UNREACHABLE) != 0) {
107
				continueLabel = null;
115
				continueLabel = null;
108
			} else {
116
			} else {
109
				actionInfo = actionInfo.mergedWith(loopingContext.initsOnContinue.unconditionalInits());
117
				actionInfo = actionInfo.mergedWith(loopingContext.initsOnContinue);
110
				loopingContext.complainOnDeferredChecks(scope, actionInfo);
118
				loopingContext.complainOnDeferredFinalChecks(scope, actionInfo);
111
				exitBranch.addPotentialInitializationsFrom(actionInfo.unconditionalInits());
119
				exitBranch.addPotentialInitializationsFrom(actionInfo);
112
			}
120
			}
113
		} else {
121
		} else {
114
			exitBranch = condInfo.initsWhenFalse();
122
			exitBranch = condInfo.initsWhenFalse();
Lines 132-137 Link Here
132
			}
140
			}
133
		}
141
		}
134
		//end of loop
142
		//end of loop
143
		loopingContext.complainOnDeferredNullChecks(currentScope, actionInfo);
144
135
		FlowInfo mergedInfo = FlowInfo.mergedOptimizedBranches(
145
		FlowInfo mergedInfo = FlowInfo.mergedOptimizedBranches(
136
				loopingContext.initsOnBreak, 
146
				loopingContext.initsOnBreak, 
137
				false, 
147
				false, 
(-)compiler/org/eclipse/jdt/internal/compiler/ast/IfStatement.java (-10 / +10 lines)
Lines 60-81 Link Here
60
		FlowInfo flowInfo) {
60
		FlowInfo flowInfo) {
61
61
62
		// process the condition
62
		// process the condition
63
		flowInfo = condition.analyseCode(currentScope, flowContext, flowInfo);
63
		FlowInfo conditionFlowInfo =
64
			condition.analyseCode(currentScope, flowContext, flowInfo);
64
65
65
		Constant cst = this.condition.optimizedBooleanConstant();
66
		Constant cst = this.condition.optimizedBooleanConstant();
66
		boolean isConditionOptimizedTrue = cst != Constant.NotAConstant && cst.booleanValue() == true;
67
		boolean isConditionOptimizedTrue = cst != Constant.NotAConstant && cst.booleanValue() == true;
67
		boolean isConditionOptimizedFalse = cst != Constant.NotAConstant && cst.booleanValue() == false;
68
		boolean isConditionOptimizedFalse = cst != Constant.NotAConstant && cst.booleanValue() == false;
68
		
69
		
69
		// process the THEN part
70
		// process the THEN part
70
		FlowInfo thenFlowInfo = flowInfo.initsWhenTrue().copy();
71
		FlowInfo thenFlowInfo = conditionFlowInfo.safeInitsWhenTrue();
71
		if (isConditionOptimizedFalse) {
72
		if (isConditionOptimizedFalse) {
72
			thenFlowInfo.setReachMode(FlowInfo.UNREACHABLE); 
73
			thenFlowInfo.setReachMode(FlowInfo.UNREACHABLE); 
73
		}
74
		}
74
		FlowInfo elseFlowInfo = flowInfo.initsWhenFalse().copy();
75
		FlowInfo elseFlowInfo = conditionFlowInfo.initsWhenFalse();
75
		if (isConditionOptimizedTrue) {
76
		if (isConditionOptimizedTrue) {
76
			elseFlowInfo.setReachMode(FlowInfo.UNREACHABLE); 
77
			elseFlowInfo.setReachMode(FlowInfo.UNREACHABLE); 
77
		}
78
		}
78
		this.condition.checkNullComparison(currentScope, flowContext, flowInfo, thenFlowInfo, elseFlowInfo);
79
		if (this.thenStatement != null) {
79
		if (this.thenStatement != null) {
80
			// Save info for code gen
80
			// Save info for code gen
81
			thenInitStateIndex =
81
			thenInitStateIndex =
Lines 86-92 Link Here
86
			}
86
			}
87
		}
87
		}
88
		// code gen: optimizing the jump around the ELSE part
88
		// code gen: optimizing the jump around the ELSE part
89
		this.thenExit =  !thenFlowInfo.isReachable();
89
		this.thenExit = (thenFlowInfo.tagBits & FlowInfo.UNREACHABLE) != 0;
90
90
91
		// process the ELSE part
91
		// process the ELSE part
92
		if (this.elseStatement != null) {
92
		if (this.elseStatement != null) {
Lines 107-117 Link Here
107
107
108
		// merge THEN & ELSE initializations
108
		// merge THEN & ELSE initializations
109
		FlowInfo mergedInfo = FlowInfo.mergedOptimizedBranches(
109
		FlowInfo mergedInfo = FlowInfo.mergedOptimizedBranches(
110
				thenFlowInfo, 
110
			thenFlowInfo, 
111
				isConditionOptimizedTrue, 
111
			isConditionOptimizedTrue, 
112
				elseFlowInfo, 
112
			elseFlowInfo, 
113
				isConditionOptimizedFalse,
113
			isConditionOptimizedFalse,
114
				true /*if(true){ return; }  fake-reachable(); */);
114
			true /*if(true){ return; }  fake-reachable(); */);
115
		mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo);
115
		mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo);
116
		return mergedInfo;
116
		return mergedInfo;
117
	}
117
	}
(-)compiler/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java (-7 / +13 lines)
Lines 31-47 Link Here
31
		this.sourceEnd = type.sourceEnd;
31
		this.sourceEnd = type.sourceEnd;
32
	}
32
	}
33
33
34
	public FlowInfo analyseCode(
34
public FlowInfo analyseCode(
35
		BlockScope currentScope,
35
		BlockScope currentScope,
36
		FlowContext flowContext,
36
		FlowContext flowContext,
37
		FlowInfo flowInfo) {
37
		FlowInfo flowInfo) {
38
38
	LocalVariableBinding local = this.expression.localVariableBinding();
39
		flowInfo = expression
39
	if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) {
40
			.analyseCode(currentScope, flowContext, flowInfo)
40
		flowContext.recordUsingNullReference(currentScope, local, 
41
			.unconditionalInits();
41
			this.expression, FlowContext.CAN_ONLY_NULL, flowInfo);
42
		expression.checkNullStatus(currentScope, flowContext, flowInfo, FlowInfo.NON_NULL);
42
		flowInfo = expression.analyseCode(currentScope, flowContext, flowInfo).
43
		return flowInfo;
43
			unconditionalInits();
44
		FlowInfo initsWhenFalse = flowInfo.copy();
45
		flowInfo.markAsComparedEqualToNonNull(local);
46
		return FlowInfo.conditional(flowInfo, initsWhenFalse);
44
	}
47
	}
48
	return expression.analyseCode(currentScope, flowContext, flowInfo).
49
			unconditionalInits();
50
}
45
51
46
	/**
52
	/**
47
	 * Code generation for instanceOfExpression
53
	 * Code generation for instanceOfExpression
(-)compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java (-19 / +19 lines)
Lines 32-56 Link Here
32
		this.declarationEnd = sourceEnd;
32
		this.declarationEnd = sourceEnd;
33
	}
33
	}
34
34
35
	public FlowInfo analyseCode(
35
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext,
36
		BlockScope currentScope,
37
		FlowContext flowContext,
38
		FlowInfo flowInfo) {
36
		FlowInfo flowInfo) {
39
37
	// record variable initialization if any
40
		// record variable initialization if any
38
	if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) {
41
		if (flowInfo.isReachable()) {
39
		bits |= IsLocalDeclarationReachable; // only set if actually reached
42
			bits |= IsLocalDeclarationReachable; // only set if actually reached
40
	}
43
		}
41
	if (this.initialization == null) { 
44
		if (this.initialization == null) 
42
		return flowInfo;
45
			return flowInfo;
43
	}
46
			
44
	int nullStatus = this.initialization.nullStatus(flowInfo);
47
		int nullStatus = this.initialization.nullStatus(flowInfo);
45
	flowInfo =
48
		flowInfo =
46
		this.initialization
49
			this.initialization
47
			.analyseCode(currentScope, flowContext, flowInfo)
50
				.analyseCode(currentScope, flowContext, flowInfo)
48
			.unconditionalInits();
51
				.unconditionalInits();
49
	flowInfo.markAsDefinitelyAssigned(binding);
52
		
50
	if ((this.binding.type.tagBits & TagBits.IsBaseType) == 0) {
53
		flowInfo.markAsDefinitelyAssigned(binding);
54
		switch(nullStatus) {
51
		switch(nullStatus) {
55
			case FlowInfo.NULL :
52
			case FlowInfo.NULL :
56
				flowInfo.markAsDefinitelyNull(this.binding);
53
				flowInfo.markAsDefinitelyNull(this.binding);
Lines 58-66 Link Here
58
			case FlowInfo.NON_NULL :
55
			case FlowInfo.NON_NULL :
59
				flowInfo.markAsDefinitelyNonNull(this.binding);
56
				flowInfo.markAsDefinitelyNonNull(this.binding);
60
				break;
57
				break;
58
			default:
59
				flowInfo.markAsDefinitelyUnknown(this.binding);
61
		}
60
		}
62
		return flowInfo;
63
	}
61
	}
62
	return flowInfo;
63
}
64
64
65
	public void checkModifiers() {
65
	public void checkModifiers() {
66
66
(-)compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java (-3 / +8 lines)
Lines 42-48 Link Here
42
42
43
	boolean nonStatic = !binding.isStatic();
43
	boolean nonStatic = !binding.isStatic();
44
	flowInfo = receiver.analyseCode(currentScope, flowContext, flowInfo, nonStatic).unconditionalInits();
44
	flowInfo = receiver.analyseCode(currentScope, flowContext, flowInfo, nonStatic).unconditionalInits();
45
	if (nonStatic) receiver.checkNullStatus(currentScope, flowContext, flowInfo, FlowInfo.NON_NULL);
45
	if (nonStatic) {
46
		receiver.checkNPE(currentScope, flowContext, flowInfo, true);
47
	}
46
48
47
	if (arguments != null) {
49
	if (arguments != null) {
48
		int length = arguments.length;
50
		int length = arguments.length;
Lines 53-59 Link Here
53
	ReferenceBinding[] thrownExceptions;
55
	ReferenceBinding[] thrownExceptions;
54
	if ((thrownExceptions = binding.thrownExceptions) != Binding.NO_EXCEPTIONS) {
56
	if ((thrownExceptions = binding.thrownExceptions) != Binding.NO_EXCEPTIONS) {
55
		// must verify that exceptions potentially thrown by this expression are caught in the method
57
		// must verify that exceptions potentially thrown by this expression are caught in the method
56
		flowContext.checkExceptionHandlers(thrownExceptions, this, flowInfo, currentScope);
58
		flowContext.checkExceptionHandlers(thrownExceptions, this, flowInfo.copy(), currentScope);
59
		// TODO (maxime) the copy above is needed because of a side effect into 
60
		//               checkExceptionHandlers; consider protecting there instead of here;
61
		//               NullReferenceTest#test0510
57
	}
62
	}
58
	manageSyntheticAccessIfNecessary(currentScope, flowInfo);	
63
	manageSyntheticAccessIfNecessary(currentScope, flowInfo);	
59
	return flowInfo;
64
	return flowInfo;
Lines 169-175 Link Here
169
}
174
}
170
public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo){
175
public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo){
171
176
172
	if (!flowInfo.isReachable()) return;
177
	if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) != 0)	return;
173
178
174
	// if method from parameterized type got found, use the original method at codegen time
179
	// if method from parameterized type got found, use the original method at codegen time
175
	this.codegenBinding = this.binding.original();
180
	this.codegenBinding = this.binding.original();
(-)compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java (-1 / +2 lines)
Lines 90-96 Link Here
90
			// check for missing returning path
90
			// check for missing returning path
91
			TypeBinding returnTypeBinding = binding.returnType;
91
			TypeBinding returnTypeBinding = binding.returnType;
92
			if ((returnTypeBinding == TypeBinding.VOID) || isAbstract()) {
92
			if ((returnTypeBinding == TypeBinding.VOID) || isAbstract()) {
93
				this.needFreeReturn = flowInfo.isReachable();
93
				this.needFreeReturn =
94
					(flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0;
94
			} else {
95
			} else {
95
				if (flowInfo != FlowInfo.DEAD_END) { 
96
				if (flowInfo != FlowInfo.DEAD_END) { 
96
					scope.problemReporter().shouldReturn(returnTypeBinding, this);
97
					scope.problemReporter().shouldReturn(returnTypeBinding, this);
(-)compiler/org/eclipse/jdt/internal/compiler/ast/OR_OR_Expression.java (-7 / +4 lines)
Lines 50-56 Link Here
50
	
50
	
51
		 // need to be careful of scenario:
51
		 // need to be careful of scenario:
52
		//		(x || y) || !z, if passing the left info to the right, it would be swapped by the !
52
		//		(x || y) || !z, if passing the left info to the right, it would be swapped by the !
53
		FlowInfo rightInfo = leftInfo.initsWhenFalse().unconditionalInits().copy();
53
		FlowInfo rightInfo = leftInfo.initsWhenFalse().unconditionalCopy();
54
		rightInitStateIndex =
54
		rightInitStateIndex =
55
			currentScope.methodScope().recordInitializationStates(rightInfo);
55
			currentScope.methodScope().recordInitializationStates(rightInfo);
56
56
Lines 59-72 Link Here
59
			rightInfo.setReachMode(FlowInfo.UNREACHABLE); 
59
			rightInfo.setReachMode(FlowInfo.UNREACHABLE); 
60
		}
60
		}
61
		rightInfo = right.analyseCode(currentScope, flowContext, rightInfo);
61
		rightInfo = right.analyseCode(currentScope, flowContext, rightInfo);
62
		FlowInfo falseMergedInfo = rightInfo.initsWhenFalse().copy();
63
		rightInfo.setReachMode(previousMode); // reset after falseMergedInfo got extracted
64
65
		FlowInfo mergedInfo = FlowInfo.conditional(
62
		FlowInfo mergedInfo = FlowInfo.conditional(
66
					// merging two true initInfos for such a negative case: if ((t && (b = t)) || f) r = b; // b may not have been initialized
63
					// merging two true initInfos for such a negative case: if ((t && (b = t)) || f) r = b; // b may not have been initialized
67
					leftInfo.initsWhenTrue().copy().unconditionalInits().mergedWith(
64
					leftInfo.initsWhenTrue().unconditionalInits().mergedWith(
68
						rightInfo.initsWhenTrue().copy().unconditionalInits()),
65
						rightInfo.safeInitsWhenTrue().setReachMode(previousMode).unconditionalInits()),
69
					falseMergedInfo);
66
					rightInfo.initsWhenFalse());
70
		mergedInitStateIndex =
67
		mergedInitStateIndex =
71
			currentScope.methodScope().recordInitializationStates(mergedInfo);
68
			currentScope.methodScope().recordInitializationStates(mergedInfo);
72
		return mergedInfo;
69
		return mergedInfo;
(-)compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java (-1 / +2 lines)
Lines 161-167 Link Here
161
	 */
161
	 */
162
	public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
162
	public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
163
163
164
		if (!flowInfo.isReachable()) return;
164
		if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0)	{
165
		ReferenceBinding allocatedTypeErasure = (ReferenceBinding) binding.declaringClass.erasure();
165
		ReferenceBinding allocatedTypeErasure = (ReferenceBinding) binding.declaringClass.erasure();
166
166
167
		// perform some extra emulation work in case there is some and we are inside a local type only
167
		// perform some extra emulation work in case there is some and we are inside a local type only
Lines 175-180 Link Here
175
				currentScope.propagateInnerEmulation(allocatedTypeErasure, enclosingInstance != null);
175
				currentScope.propagateInnerEmulation(allocatedTypeErasure, enclosingInstance != null);
176
			}
176
			}
177
		}
177
		}
178
		}
178
	}
179
	}
179
180
180
	public StringBuffer printExpression(int indent, StringBuffer output) {
181
	public StringBuffer printExpression(int indent, StringBuffer output) {
(-)compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java (-9 / +33 lines)
Lines 93-104 Link Here
93
					.isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding)) {
93
					.isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding)) {
94
					currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
94
					currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
95
				}
95
				}
96
				if (flowInfo.isReachable()) {
96
				if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0)	{
97
					localBinding.useFlag = LocalVariableBinding.USED;
97
					localBinding.useFlag = LocalVariableBinding.USED;
98
				} else if (localBinding.useFlag == LocalVariableBinding.UNUSED) {
98
				} else if (localBinding.useFlag == LocalVariableBinding.UNUSED) {
99
					localBinding.useFlag = LocalVariableBinding.FAKE_USED;
99
					localBinding.useFlag = LocalVariableBinding.FAKE_USED;
100
				}
100
				}
101
				this.checkNullStatus(currentScope, flowContext, flowInfo, FlowInfo.NON_NULL);
101
				checkNPE(currentScope, flowContext, flowInfo, true);
102
		}
102
		}
103
		
103
		
104
		if (needValue) {
104
		if (needValue) {
Lines 252-263 Link Here
252
					.isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding)) {
252
					.isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding)) {
253
					currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
253
					currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
254
				}
254
				}
255
				if (flowInfo.isReachable()) {
255
				if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0)	{
256
					localBinding.useFlag = LocalVariableBinding.USED;
256
					localBinding.useFlag = LocalVariableBinding.USED;
257
				} else if (localBinding.useFlag == LocalVariableBinding.UNUSED) {
257
				} else if (localBinding.useFlag == LocalVariableBinding.UNUSED) {
258
					localBinding.useFlag = LocalVariableBinding.FAKE_USED;
258
					localBinding.useFlag = LocalVariableBinding.FAKE_USED;
259
				}
259
				}
260
				this.checkNullStatus(currentScope, flowContext, flowInfo, FlowInfo.NON_NULL);
260
				checkNPE(currentScope, flowContext, flowInfo, true);
261
		}
261
		}
262
		if (needValue) {
262
		if (needValue) {
263
			manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo);
263
			manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo);
Lines 304-310 Link Here
304
		bits |= Binding.FIELD;
304
		bits |= Binding.FIELD;
305
		return getOtherFieldBindings(scope);
305
		return getOtherFieldBindings(scope);
306
	}
306
	}
307
	
307
308
public void checkNPE(BlockScope scope, FlowContext flowContext, 
309
		FlowInfo flowInfo, boolean checkString) {
310
	// cannot override localVariableBinding because this would project o.m onto o when
311
	// analysing assignments
312
	if ((bits & RestrictiveFlagMASK) == Binding.LOCAL) {
313
		LocalVariableBinding local = (LocalVariableBinding) this.binding;
314
		if (local != null && 
315
			(local.type.tagBits & TagBits.IsBaseType) == 0 &&
316
			(checkString || local.type.id != T_JavaLangString)) {
317
			if ((this.bits & IsNonNull) == 0) {
318
				flowContext.recordUsingNullReference(scope, local, this, 
319
					FlowContext.MAY_NULL, flowInfo);
320
			}
321
			flowInfo.markAsComparedEqualToNonNull(local); 
322
				// from thereon it is set
323
		}
324
	}
325
}
308
	/**
326
	/**
309
	 * @see org.eclipse.jdt.internal.compiler.ast.Expression#computeConversion(org.eclipse.jdt.internal.compiler.lookup.Scope, org.eclipse.jdt.internal.compiler.lookup.TypeBinding, org.eclipse.jdt.internal.compiler.lookup.TypeBinding)
327
	 * @see org.eclipse.jdt.internal.compiler.ast.Expression#computeConversion(org.eclipse.jdt.internal.compiler.lookup.Scope, org.eclipse.jdt.internal.compiler.lookup.TypeBinding, org.eclipse.jdt.internal.compiler.lookup.TypeBinding)
310
	 */
328
	 */
Lines 779-787 Link Here
779
				? type.capture(scope, this.sourceEnd)
797
				? type.capture(scope, this.sourceEnd)
780
				: type;		
798
				: type;		
781
	}
799
	}
782
	
800
783
	public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
801
	public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
784
		if (!flowInfo.isReachable()) return;
802
		if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0)	{
785
		//If inlinable field, forget the access emulation, the code gen will directly target it
803
		//If inlinable field, forget the access emulation, the code gen will directly target it
786
		if (((bits & DepthMASK) == 0) || (constant != Constant.NotAConstant)) {
804
		if (((bits & DepthMASK) == 0) || (constant != Constant.NotAConstant)) {
787
			return;
805
			return;
Lines 789-794 Link Here
789
		if ((bits & RestrictiveFlagMASK) == Binding.LOCAL) {
807
		if ((bits & RestrictiveFlagMASK) == Binding.LOCAL) {
790
			currentScope.emulateOuterAccess((LocalVariableBinding) binding);
808
			currentScope.emulateOuterAccess((LocalVariableBinding) binding);
791
		}
809
		}
810
		}
792
	}
811
	}
793
	/**
812
	/**
794
	 * index is <0 to denote write access emulation
813
	 * index is <0 to denote write access emulation
Lines 799-806 Link Here
799
			TypeBinding lastReceiverType,
818
			TypeBinding lastReceiverType,
800
			int index,
819
			int index,
801
			FlowInfo flowInfo) {
820
			FlowInfo flowInfo) {
802
	    
821
803
		if (!flowInfo.isReachable()) return;
822
		if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) != 0)	return;
804
		// index == 0 denotes the first fieldBinding, index > 0 denotes one of the 'otherBindings', index < 0 denotes a write access (to last binding)
823
		// index == 0 denotes the first fieldBinding, index > 0 denotes one of the 'otherBindings', index < 0 denotes a write access (to last binding)
805
		if (fieldBinding.constant() != Constant.NotAConstant)
824
		if (fieldBinding.constant() != Constant.NotAConstant)
806
			return;
825
			return;
Lines 855-860 Link Here
855
			}
874
			}
856
		}			
875
		}			
857
	}
876
	}
877
878
public int nullStatus(FlowInfo flowInfo) {
879
	return FlowInfo.UNKNOWN;
880
}
881
858
	public Constant optimizedBooleanConstant() {
882
	public Constant optimizedBooleanConstant() {
859
883
860
		switch (this.resolvedType.id) {
884
		switch (this.resolvedType.id) {
(-)compiler/org/eclipse/jdt/internal/compiler/ast/Reference.java (-17 lines)
Lines 12-18 Link Here
12
12
13
import org.eclipse.jdt.internal.compiler.codegen.*;
13
import org.eclipse.jdt.internal.compiler.codegen.*;
14
import org.eclipse.jdt.internal.compiler.flow.*;
14
import org.eclipse.jdt.internal.compiler.flow.*;
15
import org.eclipse.jdt.internal.compiler.impl.Constant;
16
import org.eclipse.jdt.internal.compiler.lookup.*;
15
import org.eclipse.jdt.internal.compiler.lookup.*;
17
16
18
public abstract class Reference extends Expression  {
17
public abstract class Reference extends Expression  {
Lines 68-87 Link Here
68
public abstract void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired);
67
public abstract void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired);
69
68
70
public abstract void generatePostIncrement(BlockScope currentScope, CodeStream codeStream, CompoundAssignment postIncrement, boolean valueRequired);
69
public abstract void generatePostIncrement(BlockScope currentScope, CodeStream codeStream, CompoundAssignment postIncrement, boolean valueRequired);
71
72
public int nullStatus(FlowInfo flowInfo) {
73
74
	if (this.constant != null && this.constant != Constant.NotAConstant)
75
		return FlowInfo.NON_NULL; // constant expression cannot be null
76
	
77
	LocalVariableBinding local = localVariableBinding();
78
	if (local != null) {
79
		if (flowInfo.isDefinitelyNull(local))
80
			return FlowInfo.NULL;
81
		if (flowInfo.isDefinitelyNonNull(local))
82
			return FlowInfo.NON_NULL;
83
	}	
84
	return FlowInfo.UNKNOWN;
85
}
86
87
}
70
}
(-)compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java (-4 / +27 lines)
Lines 34-40 Link Here
34
	}
34
	}
35
	public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound) {
35
	public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound) {
36
	
36
	
37
		boolean isReachable = flowInfo.isReachable();
37
		boolean isReachable = (flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0;
38
		// compound assignment extra work
38
		// compound assignment extra work
39
		if (isCompound) { // check the variable part is initialized if blank final
39
		if (isCompound) { // check the variable part is initialized if blank final
40
			switch (bits & RestrictiveFlagMASK) {
40
			switch (bits & RestrictiveFlagMASK) {
Lines 163-169 Link Here
163
				if (!flowInfo.isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding)) {
163
				if (!flowInfo.isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding)) {
164
					currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
164
					currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
165
				}
165
				}
166
				if (flowInfo.isReachable()) {
166
				if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0)	{
167
					localBinding.useFlag = LocalVariableBinding.USED;
167
					localBinding.useFlag = LocalVariableBinding.USED;
168
				} else if (localBinding.useFlag == LocalVariableBinding.UNUSED) {
168
				} else if (localBinding.useFlag == LocalVariableBinding.UNUSED) {
169
					localBinding.useFlag = LocalVariableBinding.FAKE_USED;
169
					localBinding.useFlag = LocalVariableBinding.FAKE_USED;
Lines 641-657 Link Here
641
	
641
	
642
	public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
642
	public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
643
	
643
	
644
		if (!flowInfo.isReachable()) return;
644
		if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0)	{
645
		//If inlinable field, forget the access emulation, the code gen will directly target it
645
		//If inlinable field, forget the access emulation, the code gen will directly target it
646
		if (((bits & DepthMASK) == 0) || (constant != Constant.NotAConstant)) return;
646
		if (((bits & DepthMASK) == 0) || (constant != Constant.NotAConstant)) return;
647
	
647
	
648
		if ((bits & RestrictiveFlagMASK) == Binding.LOCAL) {
648
		if ((bits & RestrictiveFlagMASK) == Binding.LOCAL) {
649
			currentScope.emulateOuterAccess((LocalVariableBinding) binding);
649
			currentScope.emulateOuterAccess((LocalVariableBinding) binding);
650
		}
650
		}
651
		}
651
	}
652
	}
652
	public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo, boolean isReadAccess) {
653
	public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo, boolean isReadAccess) {
653
	
654
	
654
		if (!flowInfo.isReachable()) return;
655
		if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) != 0)	return;
655
	
656
	
656
		//If inlinable field, forget the access emulation, the code gen will directly target it
657
		//If inlinable field, forget the access emulation, the code gen will directly target it
657
		if (constant != Constant.NotAConstant)
658
		if (constant != Constant.NotAConstant)
Lines 695-700 Link Here
695
			}					
696
			}					
696
		}
697
		}
697
	}
698
	}
699
700
public int nullStatus(FlowInfo flowInfo) {
701
	if (this.constant != null && this.constant != Constant.NotAConstant) {
702
		return FlowInfo.NON_NULL; // constant expression cannot be null
703
	}
704
	switch (bits & RestrictiveFlagMASK) {
705
		case Binding.FIELD : // reading a field
706
			return FlowInfo.UNKNOWN;
707
		case Binding.LOCAL : // reading a local variable
708
			LocalVariableBinding local = (LocalVariableBinding) this.binding;
709
			if (local != null) {
710
				if (flowInfo.isDefinitelyNull(local))
711
					return FlowInfo.NULL;
712
				if (flowInfo.isDefinitelyNonNull(local))
713
					return FlowInfo.NON_NULL;
714
				return FlowInfo.UNKNOWN;
715
			}
716
	}
717
	return FlowInfo.NON_NULL; 
718
// REVIEW should never get here?
719
}
720
698
	/**
721
	/**
699
	 * @see org.eclipse.jdt.internal.compiler.ast.Expression#postConversionType(Scope)
722
	 * @see org.eclipse.jdt.internal.compiler.ast.Expression#postConversionType(Scope)
700
	 */
723
	 */
(-)compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java (-2 / +2 lines)
Lines 62-72 Link Here
62
					if ((caseIndex < caseCount) && (statement == cases[caseIndex])) { // statement is a case
62
					if ((caseIndex < caseCount) && (statement == cases[caseIndex])) { // statement is a case
63
						this.scope.enclosingCase = cases[caseIndex]; // record entering in a switch case block
63
						this.scope.enclosingCase = cases[caseIndex]; // record entering in a switch case block
64
						caseIndex++;
64
						caseIndex++;
65
						caseInits = caseInits.mergedWith(flowInfo.copy().unconditionalInits());
65
						caseInits = caseInits.mergedWith(flowInfo.unconditionalInits());
66
						didAlreadyComplain = false; // reset complaint
66
						didAlreadyComplain = false; // reset complaint
67
					} else if (statement == defaultCase) { // statement is the default case
67
					} else if (statement == defaultCase) { // statement is the default case
68
						this.scope.enclosingCase = defaultCase; // record entering in a switch case block
68
						this.scope.enclosingCase = defaultCase; // record entering in a switch case block
69
						caseInits = caseInits.mergedWith(flowInfo.copy().unconditionalInits());
69
						caseInits = caseInits.mergedWith(flowInfo.unconditionalInits());
70
						didAlreadyComplain = false; // reset complaint
70
						didAlreadyComplain = false; // reset complaint
71
					}
71
					}
72
					if (!statement.complainIfUnreachable(caseInits, scope, didAlreadyComplain)) {
72
					if (!statement.complainIfUnreachable(caseInits, scope, didAlreadyComplain)) {
(-)compiler/org/eclipse/jdt/internal/compiler/ast/SynchronizedStatement.java (-1 / +1 lines)
Lines 56-62 Link Here
56
				expression.analyseCode(scope, flowContext, flowInfo));
56
				expression.analyseCode(scope, flowContext, flowInfo));
57
57
58
		// optimizing code gen
58
		// optimizing code gen
59
		this.blockExit = !flowInfo.isReachable();
59
		this.blockExit = (flowInfo.tagBits & FlowInfo.UNREACHABLE) != 0;
60
60
61
		return flowInfo;
61
		return flowInfo;
62
	}
62
	}
(-)compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java (-13 / +24 lines)
Lines 85-91 Link Here
85
					.analyseCode(
85
					.analyseCode(
86
						currentScope,
86
						currentScope,
87
						finallyContext = new FinallyFlowContext(flowContext, finallyBlock),
87
						finallyContext = new FinallyFlowContext(flowContext, finallyBlock),
88
						flowInfo.copy().unconditionalInits().discardNullRelatedInitializations())
88
						flowInfo.nullInfoLessUnconditionalCopy())
89
					.unconditionalInits();
89
					.unconditionalInits();
90
			if (subInfo == FlowInfo.DEAD_END) {
90
			if (subInfo == FlowInfo.DEAD_END) {
91
				isSubRoutineEscaping = true;
91
				isSubRoutineEscaping = true;
Lines 108-114 Link Here
108
			tryBlockExit = false;
108
			tryBlockExit = false;
109
		} else {
109
		} else {
110
			tryInfo = tryBlock.analyseCode(currentScope, handlingContext, flowInfo.copy());
110
			tryInfo = tryBlock.analyseCode(currentScope, handlingContext, flowInfo.copy());
111
			tryBlockExit = !tryInfo.isReachable();
111
			tryBlockExit = (tryInfo.tagBits & FlowInfo.UNREACHABLE) != 0;
112
		}
112
		}
113
113
114
		// check unreachable catch blocks
114
		// check unreachable catch blocks
Lines 121-133 Link Here
121
			for (int i = 0; i < catchCount; i++) {
121
			for (int i = 0; i < catchCount; i++) {
122
				// keep track of the inits that could potentially have led to this exception handler (for final assignments diagnosis)
122
				// keep track of the inits that could potentially have led to this exception handler (for final assignments diagnosis)
123
				FlowInfo catchInfo =
123
				FlowInfo catchInfo =
124
					flowInfo
124
					flowInfo.unconditionalCopy().
125
						.copy()
125
						addPotentialInitializationsFrom(
126
						.unconditionalInits()
126
							handlingContext.initsOnException(
127
								caughtExceptionTypes[i]))
127
						.addPotentialInitializationsFrom(
128
						.addPotentialInitializationsFrom(
128
							handlingContext.initsOnException(caughtExceptionTypes[i]).unconditionalInits())
129
							tryInfo.nullInfoLessUnconditionalCopy())
129
						.addPotentialInitializationsFrom(tryInfo.unconditionalInits())
130
							// remove null info to protect point of 
130
						.addPotentialInitializationsFrom(handlingContext.initsOnReturn);
131
							// exception null info 
132
						.addPotentialInitializationsFrom(
133
							handlingContext.initsOnReturn.
134
								nullInfoLessUnconditionalCopy());
131
135
132
				// catch var is always set
136
				// catch var is always set
133
				LocalVariableBinding catchArg = catchArguments[i].binding;
137
				LocalVariableBinding catchArg = catchArguments[i].binding;
Lines 149-155 Link Here
149
						currentScope,
153
						currentScope,
150
						catchContext,
154
						catchContext,
151
						catchInfo);
155
						catchInfo);
152
				catchExits[i] = !catchInfo.isReachable();
156
				catchExits[i] = 
157
					(catchInfo.tagBits & FlowInfo.UNREACHABLE) != 0;
153
				tryInfo = tryInfo.mergedWith(catchInfo.unconditionalInits());
158
				tryInfo = tryInfo.mergedWith(catchInfo.unconditionalInits());
154
			}
159
			}
155
		}
160
		}
Lines 162-171 Link Here
162
167
163
		// we also need to check potential multiple assignments of final variables inside the finally block
168
		// we also need to check potential multiple assignments of final variables inside the finally block
164
		// need to include potential inits from returns inside the try/catch parts - 1GK2AOF
169
		// need to include potential inits from returns inside the try/catch parts - 1GK2AOF
165
		finallyContext.complainOnDeferredChecks(
170
		finallyContext/* NN null with subRoutineStartLabel, which returns */.complainOnDeferredChecks( 
166
			tryInfo.isReachable() 
171
			(tryInfo.tagBits & FlowInfo.UNREACHABLE) == 0 
167
				? (tryInfo.addPotentialInitializationsFrom(insideSubContext.initsOnReturn))
172
				? flowInfo.unconditionalCopy().
168
				: insideSubContext.initsOnReturn, 
173
					addPotentialInitializationsFrom(tryInfo).
174
						// lighten the influence of the try block, which may have 
175
						// exited at any point
176
					addPotentialInitializationsFrom(
177
						insideSubContext/* NN null with subRoutineStartLabel, which returns */.
178
							initsOnReturn)
179
				: insideSubContext.initsOnReturn,
169
			currentScope);
180
			currentScope);
170
		if (subInfo == FlowInfo.DEAD_END) {
181
		if (subInfo == FlowInfo.DEAD_END) {
171
			mergedInitStateIndex =
182
			mergedInitStateIndex =
(-)compiler/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java (-10 / +11 lines)
Lines 201-207 Link Here
201
		if (ignoreFurtherInvestigation)
201
		if (ignoreFurtherInvestigation)
202
			return flowInfo;
202
			return flowInfo;
203
		try {
203
		try {
204
			if (flowInfo.isReachable()) {
204
			if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) {
205
				bits |= IsReachable;
205
				bits |= IsReachable;
206
				LocalTypeBinding localType = (LocalTypeBinding) binding;
206
				LocalTypeBinding localType = (LocalTypeBinding) binding;
207
				localType.setConstantPoolName(currentScope.compilationUnitScope().computeConstantPoolName(localType));
207
				localType.setConstantPoolName(currentScope.compilationUnitScope().computeConstantPoolName(localType));
Lines 244-250 Link Here
244
		if (ignoreFurtherInvestigation)
244
		if (ignoreFurtherInvestigation)
245
			return;
245
			return;
246
		try {
246
		try {
247
			if (flowInfo.isReachable()) {
247
			if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) {
248
				bits |= IsReachable;
248
				bits |= IsReachable;
249
				LocalTypeBinding localType = (LocalTypeBinding) binding;
249
				LocalTypeBinding localType = (LocalTypeBinding) binding;
250
				localType.setConstantPoolName(currentScope.compilationUnitScope().computeConstantPoolName(localType));
250
				localType.setConstantPoolName(currentScope.compilationUnitScope().computeConstantPoolName(localType));
Lines 634-640 Link Here
634
	 *	Common flow analysis for all types
634
	 *	Common flow analysis for all types
635
	 *
635
	 *
636
	 */
636
	 */
637
	public void internalAnalyseCode(FlowContext flowContext, FlowInfo flowInfo) {
637
	private void internalAnalyseCode(FlowContext flowContext, FlowInfo flowInfo) {
638
638
639
		if ((this.binding.isPrivate()/* || (this.binding.tagBits & (TagBits.IsAnonymousType|TagBits.IsLocalType)) == TagBits.IsLocalType*/) && !this.binding.isUsed()) {
639
		if ((this.binding.isPrivate()/* || (this.binding.tagBits & (TagBits.IsAnonymousType|TagBits.IsLocalType)) == TagBits.IsLocalType*/) && !this.binding.isUsed()) {
640
			if (!scope.referenceCompilationUnit().compilationResult.hasSyntaxError) {
640
			if (!scope.referenceCompilationUnit().compilationResult.hasSyntaxError) {
Lines 644-656 Link Here
644
644
645
		InitializationFlowContext initializerContext = new InitializationFlowContext(null, this, initializerScope);
645
		InitializationFlowContext initializerContext = new InitializationFlowContext(null, this, initializerScope);
646
		InitializationFlowContext staticInitializerContext = new InitializationFlowContext(null, this, staticInitializerScope);
646
		InitializationFlowContext staticInitializerContext = new InitializationFlowContext(null, this, staticInitializerScope);
647
		FlowInfo nonStaticFieldInfo = flowInfo.copy().unconditionalInits().discardFieldInitializations();
647
		FlowInfo nonStaticFieldInfo = flowInfo.unconditionalFieldLessCopy();
648
		FlowInfo staticFieldInfo = flowInfo.copy().unconditionalInits().discardFieldInitializations();
648
		FlowInfo staticFieldInfo = flowInfo.unconditionalFieldLessCopy();
649
		if (fields != null) {
649
		if (fields != null) {
650
			for (int i = 0, count = fields.length; i < count; i++) {
650
			for (int i = 0, count = fields.length; i < count; i++) {
651
				FieldDeclaration field = fields[i];
651
				FieldDeclaration field = fields[i];
652
				if (field.isStatic()) {
652
				if (field.isStatic()) {
653
					if (!staticFieldInfo.isReachable())
653
					if ((staticFieldInfo.tagBits & FlowInfo.UNREACHABLE) != 0)
654
						field.bits &= ~ASTNode.IsReachable;
654
						field.bits &= ~ASTNode.IsReachable;
655
					
655
					
656
					/*if (field.isField()){
656
					/*if (field.isField()){
Lines 670-676 Link Here
670
						staticFieldInfo = FlowInfo.initial(maxFieldCount).setReachMode(FlowInfo.UNREACHABLE);
670
						staticFieldInfo = FlowInfo.initial(maxFieldCount).setReachMode(FlowInfo.UNREACHABLE);
671
					}
671
					}
672
				} else {
672
				} else {
673
					if (!nonStaticFieldInfo.isReachable())
673
					if ((nonStaticFieldInfo.tagBits & FlowInfo.UNREACHABLE) != 0)
674
						field.bits &= ~ASTNode.IsReachable;
674
						field.bits &= ~ASTNode.IsReachable;
675
					
675
					
676
					/*if (field.isField()){
676
					/*if (field.isField()){
Lines 699-705 Link Here
699
			}
699
			}
700
		}
700
		}
701
		if (methods != null) {
701
		if (methods != null) {
702
			UnconditionalFlowInfo outerInfo = flowInfo.copy().unconditionalInits().discardFieldInitializations();
702
			UnconditionalFlowInfo outerInfo = flowInfo.unconditionalFieldLessCopy();
703
			FlowInfo constructorInfo = nonStaticFieldInfo.unconditionalInits().discardNonFieldInitializations().addInitializationsFrom(outerInfo);
703
			FlowInfo constructorInfo = nonStaticFieldInfo.unconditionalInits().discardNonFieldInitializations().addInitializationsFrom(outerInfo);
704
			for (int i = 0, count = methods.length; i < count; i++) {
704
			for (int i = 0, count = methods.length; i < count; i++) {
705
				AbstractMethodDeclaration method = methods[i];
705
				AbstractMethodDeclaration method = methods[i];
Lines 748-754 Link Here
748
	 */
748
	 */
749
	public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
749
	public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
750
750
751
 		if (!flowInfo.isReachable()) return;
751
 		if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) != 0) return;
752
		NestedTypeBinding nestedType = (NestedTypeBinding) binding;
752
		NestedTypeBinding nestedType = (NestedTypeBinding) binding;
753
		
753
		
754
		MethodScope methodScope = currentScope.methodScope();
754
		MethodScope methodScope = currentScope.methodScope();
Lines 800-808 Link Here
800
	 */
800
	 */
801
	public void manageEnclosingInstanceAccessIfNecessary(ClassScope currentScope, FlowInfo flowInfo) {
801
	public void manageEnclosingInstanceAccessIfNecessary(ClassScope currentScope, FlowInfo flowInfo) {
802
802
803
		if (!flowInfo.isReachable()) return;
803
		if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) {
804
		NestedTypeBinding nestedType = (NestedTypeBinding) binding;
804
		NestedTypeBinding nestedType = (NestedTypeBinding) binding;
805
		nestedType.addSyntheticArgumentAndField(binding.enclosingType());
805
		nestedType.addSyntheticArgumentAndField(binding.enclosingType());
806
		}
806
	}	
807
	}	
807
	
808
	
808
	/**
809
	/**
(-)compiler/org/eclipse/jdt/internal/compiler/ast/UnaryExpression.java (-9 / +10 lines)
Lines 27-45 Link Here
27
		this.bits |= operator << OperatorSHIFT; // encode operator
27
		this.bits |= operator << OperatorSHIFT; // encode operator
28
	}
28
	}
29
29
30
	public FlowInfo analyseCode(
30
public FlowInfo analyseCode(
31
		BlockScope currentScope,
31
		BlockScope currentScope,
32
		FlowContext flowContext,
32
		FlowContext flowContext,
33
		FlowInfo flowInfo) {
33
		FlowInfo flowInfo) {
34
			
34
	this.expression.checkNPE(currentScope, flowContext, flowInfo, true);	
35
		if (((bits & OperatorMASK) >> OperatorSHIFT) == NOT) {
35
	if (((bits & OperatorMASK) >> OperatorSHIFT) == NOT) {
36
			return this.expression
36
		return this.expression.
37
				.analyseCode(currentScope, flowContext, flowInfo)
37
			analyseCode(currentScope, flowContext, flowInfo).
38
				.asNegatedCondition();
38
			asNegatedCondition();
39
		} else {
39
	} else {
40
			return this.expression.analyseCode(currentScope, flowContext, flowInfo);
40
		return this.expression.
41
		}
41
			analyseCode(currentScope, flowContext, flowInfo);
42
	}
42
	}
43
}
43
44
44
	public Constant optimizedBooleanConstant() {
45
	public Constant optimizedBooleanConstant() {
45
		
46
		
(-)compiler/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java (-11 / +34 lines)
Lines 55-65 Link Here
55
		preCondInitStateIndex =
55
		preCondInitStateIndex =
56
			currentScope.methodScope().recordInitializationStates(flowInfo);
56
			currentScope.methodScope().recordInitializationStates(flowInfo);
57
		LoopingFlowContext condLoopContext;
57
		LoopingFlowContext condLoopContext;
58
		FlowInfo condInfo = flowInfo.copy().unconditionalInits().discardNullRelatedInitializations();
58
		FlowInfo condInfo =	flowInfo.nullInfoLessUnconditionalCopy();
59
		// we need to collect the contribution to nulls of the coming paths through the
60
		// loop, be they falling through normally or branched to break, continue labels
61
		// or catch blocks
59
		condInfo = this.condition.analyseCode(
62
		condInfo = this.condition.analyseCode(
60
				currentScope,
63
				currentScope,
61
				(condLoopContext =
64
				(condLoopContext =
62
					new LoopingFlowContext(flowContext, this, null, null, currentScope)),
65
					new LoopingFlowContext(flowContext, flowInfo, this, null, 
66
						null, currentScope)),
63
				condInfo);
67
				condInfo);
64
68
65
		LoopingFlowContext loopingContext;
69
		LoopingFlowContext loopingContext;
Lines 67-83 Link Here
67
		FlowInfo exitBranch;
71
		FlowInfo exitBranch;
68
		if (action == null 
72
		if (action == null 
69
			|| (action.isEmptyBlock() && currentScope.compilerOptions().complianceLevel <= ClassFileConstants.JDK1_3)) {
73
			|| (action.isEmptyBlock() && currentScope.compilerOptions().complianceLevel <= ClassFileConstants.JDK1_3)) {
70
			condLoopContext.complainOnDeferredChecks(currentScope, condInfo);
74
			condLoopContext.complainOnDeferredFinalChecks(currentScope, 
75
					condInfo);
76
			condLoopContext.complainOnDeferredNullChecks(currentScope,
77
				condInfo.unconditionalInits());
71
			if (isConditionTrue) {
78
			if (isConditionTrue) {
72
				return FlowInfo.DEAD_END;
79
				return FlowInfo.DEAD_END;
73
			} else {
80
			} else {
74
				FlowInfo mergedInfo = condInfo.initsWhenFalse().unconditionalInits();
81
				FlowInfo mergedInfo = condInfo.initsWhenFalse();
75
				if (isConditionOptimizedTrue){
82
				if (isConditionOptimizedTrue){
76
					mergedInfo.setReachMode(FlowInfo.UNREACHABLE);
83
					mergedInfo.setReachMode(FlowInfo.UNREACHABLE);
77
				}
84
				}
78
				mergedInitStateIndex =
85
				mergedInitStateIndex =
79
					currentScope.methodScope().recordInitializationStates(mergedInfo);
86
					currentScope.methodScope().recordInitializationStates(mergedInfo);
80
				return mergedInfo;
87
				return flowInfo.unconditionalInits().
88
					addPotentialNullInfoFrom(
89
							condInfo.initsWhenFalse().unconditionalInits()); 
81
			}
90
			}
82
		} else {
91
		} else {
83
			// in case the condition was inlined to false, record the fact that there is no way to reach any 
92
			// in case the condition was inlined to false, record the fact that there is no way to reach any 
Lines 85-90 Link Here
85
			loopingContext =
94
			loopingContext =
86
				new LoopingFlowContext(
95
				new LoopingFlowContext(
87
					flowContext,
96
					flowContext,
97
					flowInfo,
88
					this,
98
					this,
89
					breakLabel,
99
					breakLabel,
90
					continueLabel,
100
					continueLabel,
Lines 108-122 Link Here
108
			}
118
			}
109
119
110
			// code generation can be optimized when no need to continue in the loop
120
			// code generation can be optimized when no need to continue in the loop
111
			exitBranch = condInfo.initsWhenFalse();
121
			exitBranch = flowInfo.copy();
112
			exitBranch.addInitializationsFrom(flowInfo); // recover null inits from before condition analysis
122
			// need to start over from flowInfo so as to get null inits
113
			if (!actionInfo.isReachable() && !loopingContext.initsOnContinue.isReachable()) {
123
124
			if ((actionInfo.tagBits & 
125
					loopingContext.initsOnContinue.tagBits &
126
					FlowInfo.UNREACHABLE) != 0) {
114
				continueLabel = null;
127
				continueLabel = null;
128
				exitBranch.addInitializationsFrom(condInfo.initsWhenFalse());
115
			} else {
129
			} else {
116
				condLoopContext.complainOnDeferredChecks(currentScope, condInfo);
130
				condLoopContext.complainOnDeferredFinalChecks(currentScope, 
131
						condInfo);
117
				actionInfo = actionInfo.mergedWith(loopingContext.initsOnContinue.unconditionalInits());
132
				actionInfo = actionInfo.mergedWith(loopingContext.initsOnContinue.unconditionalInits());
118
				loopingContext.complainOnDeferredChecks(currentScope, actionInfo);
133
				condLoopContext.complainOnDeferredNullChecks(currentScope, 
119
				exitBranch.addPotentialInitializationsFrom(actionInfo.unconditionalInits());
134
						actionInfo);
135
				loopingContext.complainOnDeferredFinalChecks(currentScope, 
136
						actionInfo);
137
				loopingContext.complainOnDeferredNullChecks(currentScope, 
138
						actionInfo);
139
				exitBranch.
140
					addPotentialInitializationsFrom(
141
						actionInfo.unconditionalInits()).
142
					addInitializationsFrom(condInfo.initsWhenFalse());
120
			}
143
			}
121
		}
144
		}
122
145
(-)compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java (-1 / +1 lines)
Lines 4549-4555 Link Here
4549
	bCodeStream[classFileOffset++] = Opcodes.OPC_ireturn;
4549
	bCodeStream[classFileOffset++] = Opcodes.OPC_ireturn;
4550
}
4550
}
4551
public boolean isDefinitelyAssigned(Scope scope, int initStateIndex, LocalVariableBinding local) {
4551
public boolean isDefinitelyAssigned(Scope scope, int initStateIndex, LocalVariableBinding local) {
4552
	// Dependant of UnconditionalFlowInfo.isDefinitelyAssigned(..)
4552
	// Mirror of UnconditionalFlowInfo.isDefinitelyAssigned(..)
4553
	if (initStateIndex == -1)
4553
	if (initStateIndex == -1)
4554
		return false;
4554
		return false;
4555
	if (local.isArgument) {
4555
	if (local.isArgument) {
(-)compiler/org/eclipse/jdt/internal/compiler/flow/ConditionalFlowInfo.java (-85 / +93 lines)
Lines 83-134 Link Here
83
				&& initsWhenFalse.isDefinitelyAssigned(local);
83
				&& initsWhenFalse.isDefinitelyAssigned(local);
84
	}
84
	}
85
	
85
	
86
	/**
86
public boolean isDefinitelyNonNull(LocalVariableBinding local) {
87
	 * Check status of definite non-null assignment for a field.
87
	return initsWhenTrue.isDefinitelyNonNull(local) 
88
	 */
88
			&& initsWhenFalse.isDefinitelyNonNull(local);
89
	public boolean isDefinitelyNonNull(FieldBinding field) {
89
}
90
		
91
		return initsWhenTrue.isDefinitelyNonNull(field) 
92
				&& initsWhenFalse.isDefinitelyNonNull(field);
93
	}
94
95
	/**
96
	 * Check status of definite non-null assignment for a local variable.
97
	 */
98
	public boolean isDefinitelyNonNull(LocalVariableBinding local) {
99
		
100
		return initsWhenTrue.isDefinitelyNonNull(local) 
101
				&& initsWhenFalse.isDefinitelyNonNull(local);
102
	}
103
	
90
	
104
	/**
91
public boolean isDefinitelyNull(LocalVariableBinding local) {
105
	 * Check status of definite null assignment for a field.
92
	return initsWhenTrue.isDefinitelyNull(local) 
106
	 */
93
			&& initsWhenFalse.isDefinitelyNull(local);
107
	public boolean isDefinitelyNull(FieldBinding field) {
94
}
108
		
109
		return initsWhenTrue.isDefinitelyNull(field) 
110
				&& initsWhenFalse.isDefinitelyNull(field);
111
	}
112
113
	/**
114
	 * Check status of definite null assignment for a local variable.
115
	 */
116
	public boolean isDefinitelyNull(LocalVariableBinding local) {
117
		
118
		return initsWhenTrue.isDefinitelyNull(local) 
119
				&& initsWhenFalse.isDefinitelyNull(local);
120
	}
121
95
122
	public int reachMode(){
96
public boolean isDefinitelyUnknown(LocalVariableBinding local) {
123
		return unconditionalInits().reachMode();
97
	return initsWhenTrue.isDefinitelyUnknown(local) 
124
	}
98
			&& initsWhenFalse.isDefinitelyUnknown(local);
125
	
99
}
126
	public boolean isReachable(){
127
		
128
		return unconditionalInits().isReachable();	
129
		//should maybe directly be: false
130
	}
131
	
132
	/**
100
	/**
133
	 * Check status of potential assignment for a field.
101
	 * Check status of potential assignment for a field.
134
	 */
102
	 */
Lines 147-152 Link Here
147
				|| initsWhenFalse.isPotentiallyAssigned(local);
115
				|| initsWhenFalse.isPotentiallyAssigned(local);
148
	}
116
	}
149
	
117
	
118
public boolean isPotentiallyNull(LocalVariableBinding local) {
119
	return initsWhenTrue.isPotentiallyNull(local) 
120
		|| initsWhenFalse.isPotentiallyNull(local);
121
}	
122
123
public boolean isPotentiallyUnknown(LocalVariableBinding local) {
124
	return initsWhenTrue.isPotentiallyUnknown(local) 
125
		|| initsWhenFalse.isPotentiallyUnknown(local);
126
}	
127
128
public boolean isProtectedNonNull(LocalVariableBinding local) {
129
	return initsWhenTrue.isProtectedNonNull(local) 
130
		&& initsWhenFalse.isProtectedNonNull(local);
131
}		
132
	
133
public boolean isProtectedNull(LocalVariableBinding local) {
134
	return initsWhenTrue.isProtectedNull(local) 
135
		&& initsWhenFalse.isProtectedNull(local);
136
}		
137
	
138
public void markAsComparedEqualToNonNull(LocalVariableBinding local) {
139
	initsWhenTrue.markAsComparedEqualToNonNull(local);
140
	initsWhenFalse.markAsComparedEqualToNonNull(local);
141
}
142
143
public void markAsComparedEqualToNull(LocalVariableBinding local) {
144
	initsWhenTrue.markAsComparedEqualToNull(local);
145
    initsWhenFalse.markAsComparedEqualToNull(local);
146
}
147
	
150
	/**
148
	/**
151
	 * Record a field got definitely assigned.
149
	 * Record a field got definitely assigned.
152
	 */
150
	 */
Lines 201-250 Link Here
201
		initsWhenFalse.markAsDefinitelyNull(local);	
199
		initsWhenFalse.markAsDefinitelyNull(local);	
202
	}
200
	}
203
201
204
	/**
202
public void markAsDefinitelyUnknown(LocalVariableBinding local) {
205
	 * Clear the initialization info for a field
203
	initsWhenTrue.markAsDefinitelyUnknown(local);
206
	 */
204
	initsWhenFalse.markAsDefinitelyUnknown(local);	
207
	public void markAsDefinitelyNotAssigned(FieldBinding field) {
205
}
208
		
206
209
		initsWhenTrue.markAsDefinitelyNotAssigned(field);
207
public FlowInfo setReachMode(int reachMode) {
210
		initsWhenFalse.markAsDefinitelyNotAssigned(field);	
208
	if (reachMode == REACHABLE) {
211
	}
209
		this.tagBits &= ~UNREACHABLE;
212
	
210
	}
213
	/**
211
	else {
214
	 * Clear the initialization info for a local variable
212
		this.tagBits |= UNREACHABLE;
215
	 */
213
	}
216
	public void markAsDefinitelyNotAssigned(LocalVariableBinding local) {
214
	initsWhenTrue.setReachMode(reachMode);
217
		
215
	initsWhenFalse.setReachMode(reachMode);
218
		initsWhenTrue.markAsDefinitelyNotAssigned(local);
216
	return this;
219
		initsWhenFalse.markAsDefinitelyNotAssigned(local);	
217
}
220
	}
221
	
222
	public FlowInfo setReachMode(int reachMode) {
223
		
224
		initsWhenTrue.setReachMode(reachMode);
225
		initsWhenFalse.setReachMode(reachMode);
226
		return this;
227
	}
228
	
229
	/**
230
	 * Converts conditional receiver into inconditional one, updated in the following way: <ul>
231
	 * <li> intersection of definitely assigned variables, 
232
	 * <li> union of potentially assigned variables.
233
	 * </ul>
234
	 */
235
	public UnconditionalFlowInfo mergedWith(UnconditionalFlowInfo otherInits) {
236
		
237
		return unconditionalInits().mergedWith(otherInits);
238
	}
239
	
218
	
219
public UnconditionalFlowInfo mergedWith(UnconditionalFlowInfo otherInits) {
220
	return unconditionalInits().mergedWith(otherInits);
221
}
222
223
public UnconditionalFlowInfo nullInfoLessUnconditionalCopy() {
224
	return unconditionalInitsWithoutSideEffect().
225
		nullInfoLessUnconditionalCopy();
226
}
240
	public String toString() {
227
	public String toString() {
241
		
228
		
242
		return "FlowInfo<true: " + initsWhenTrue.toString() + ", false: " + initsWhenFalse.toString() + ">"; //$NON-NLS-1$ //$NON-NLS-3$ //$NON-NLS-2$
229
		return "FlowInfo<true: " + initsWhenTrue.toString() + ", false: " + initsWhenFalse.toString() + ">"; //$NON-NLS-1$ //$NON-NLS-3$ //$NON-NLS-2$
243
	}
230
	}
244
	
231
245
	public UnconditionalFlowInfo unconditionalInits() {
232
public FlowInfo safeInitsWhenTrue() {
246
		
233
	return initsWhenTrue;
247
		return initsWhenTrue.unconditionalInits().copy()
234
}
248
				.mergedWith(initsWhenFalse.unconditionalInits());
235
249
	}
236
public UnconditionalFlowInfo unconditionalCopy() {
237
	return initsWhenTrue.unconditionalCopy().
238
			mergedWith(initsWhenFalse.unconditionalInits());
239
}
240
241
public UnconditionalFlowInfo unconditionalFieldLessCopy() {
242
	return initsWhenTrue.unconditionalFieldLessCopy().
243
		mergedWith(initsWhenFalse.unconditionalFieldLessCopy()); 
244
	// should never happen, hence suboptimal does not hurt
245
}
246
247
public UnconditionalFlowInfo unconditionalInits() {
248
	return initsWhenTrue.unconditionalInits().
249
			mergedWith(initsWhenFalse.unconditionalInits());
250
}
251
252
public UnconditionalFlowInfo unconditionalInitsWithoutSideEffect() {
253
	// cannot do better here than unconditionalCopy - but still a different 
254
	// operation for UnconditionalFlowInfo
255
	return initsWhenTrue.unconditionalCopy().
256
			mergedWith(initsWhenFalse.unconditionalInits());
257
}
250
}
258
}
(-)compiler/org/eclipse/jdt/internal/compiler/flow/ExceptionHandlingFlowContext.java (-11 / +12 lines)
Lines 62-68 Link Here
62
			int cacheIndex = i / BitCacheSize, bitMask = 1 << (i % BitCacheSize);
62
			int cacheIndex = i / BitCacheSize, bitMask = 1 << (i % BitCacheSize);
63
			if (handledExceptions[i].isUncheckedException(true)) {
63
			if (handledExceptions[i].isUncheckedException(true)) {
64
				isReached[cacheIndex] |= bitMask;
64
				isReached[cacheIndex] |= bitMask;
65
				this.initsOnExceptions[i] = flowInfo.copy().unconditionalInits();
65
				this.initsOnExceptions[i] = flowInfo.unconditionalCopy();
66
			} else {
66
			} else {
67
				this.initsOnExceptions[i] = FlowInfo.DEAD_END;
67
				this.initsOnExceptions[i] = FlowInfo.DEAD_END;
68
			}
68
			}
Lines 168-187 Link Here
168
		this.isReached[cacheIndex] |= bitMask;
168
		this.isReached[cacheIndex] |= bitMask;
169
		
169
		
170
		initsOnExceptions[index] =
170
		initsOnExceptions[index] =
171
			initsOnExceptions[index] == FlowInfo.DEAD_END
171
			(initsOnExceptions[index].tagBits & FlowInfo.UNREACHABLE) == 0 ?
172
				? flowInfo.copy().unconditionalInits()
172
				initsOnExceptions[index].mergedWith(flowInfo):
173
				: initsOnExceptions[index].mergedWith(flowInfo.copy().unconditionalInits());
173
				flowInfo.unconditionalCopy();
174
	}
174
	}
175
	
175
	
176
	public void recordReturnFrom(FlowInfo flowInfo) {
176
public void recordReturnFrom(UnconditionalFlowInfo flowInfo) {
177
177
	if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) {
178
		if (!flowInfo.isReachable()) return; 
178
		if ((initsOnReturn.tagBits & FlowInfo.UNREACHABLE) == 0) {
179
		if (initsOnReturn == FlowInfo.DEAD_END) {
179
			initsOnReturn = initsOnReturn.mergedWith(flowInfo);
180
			initsOnReturn = flowInfo.copy().unconditionalInits();
180
		} 
181
		} else {
181
		else {
182
			initsOnReturn = initsOnReturn.mergedWith(flowInfo.copy().unconditionalInits());
182
			initsOnReturn = (UnconditionalFlowInfo) flowInfo.copy();
183
		}
183
		}
184
	}
184
	}
185
}
185
	
186
	
186
	/*
187
	/*
187
	 * Compute a merged list of unhandled exception types (keeping only the most generic ones).
188
	 * Compute a merged list of unhandled exception types (keeping only the most generic ones).
(-)compiler/org/eclipse/jdt/internal/compiler/flow/FinallyFlowContext.java (-65 / +188 lines)
Lines 16-21 Link Here
16
import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
16
import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
17
import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
17
import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
18
import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
18
import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
19
import org.eclipse.jdt.internal.compiler.lookup.Scope;
19
import org.eclipse.jdt.internal.compiler.lookup.VariableBinding;
20
import org.eclipse.jdt.internal.compiler.lookup.VariableBinding;
20
21
21
/**
22
/**
Lines 28-104 Link Here
28
	VariableBinding[] finalVariables;
29
	VariableBinding[] finalVariables;
29
	int assignCount;
30
	int assignCount;
30
31
32
	LocalVariableBinding[] nullLocals;	
31
	Expression[] nullReferences;
33
	Expression[] nullReferences;
32
	int[] nullStatus;
34
	int[] nullCheckTypes;
33
	int nullCount;
35
	int nullCount;
34
	
36
	
35
	public FinallyFlowContext(FlowContext parent, ASTNode associatedNode) {
37
	public FinallyFlowContext(FlowContext parent, ASTNode associatedNode) {
36
		super(parent, associatedNode);
38
		super(parent, associatedNode);
37
	}
39
	}
38
40
39
	/**
41
/**
40
	 * Given some contextual initialization info (derived from a try block or a catch block), this 
42
 * Given some contextual initialization info (derived from a try block or a catch block), this 
41
	 * code will check that the subroutine context does not also initialize a final variable potentially set
43
 * code will check that the subroutine context does not also initialize a final variable potentially set
42
	 * redundantly.
44
 * redundantly.
43
	 */
45
 */
44
	public void complainOnDeferredChecks(FlowInfo flowInfo, BlockScope scope) {
46
public void complainOnDeferredChecks(FlowInfo flowInfo, BlockScope scope) {
47
	
48
	// check redundant final assignments
49
	for (int i = 0; i < this.assignCount; i++) {
50
		VariableBinding variable = this.finalVariables[i];
51
		if (variable == null) continue;
45
		
52
		
46
		// check redundant final assignments
53
		boolean complained = false; // remember if have complained on this final assignment
47
		for (int i = 0; i < assignCount; i++) {
54
		if (variable instanceof FieldBinding) {
48
			VariableBinding variable = finalVariables[i];
55
			// final field
49
			if (variable == null) continue;
56
			if (flowInfo.isPotentiallyAssigned((FieldBinding)variable)) {
50
			
57
				complained = true;
51
			boolean complained = false; // remember if have complained on this final assignment
58
				scope.problemReporter().duplicateInitializationOfBlankFinalField((FieldBinding)variable, finalAssignments[i]);
52
			if (variable instanceof FieldBinding) {
59
			}
53
				// final field
60
		} else {
54
				if (flowInfo.isPotentiallyAssigned((FieldBinding)variable)) {
61
			// final local variable
55
					complained = true;
62
			if (flowInfo.isPotentiallyAssigned((LocalVariableBinding) variable)) {
56
					scope.problemReporter().duplicateInitializationOfBlankFinalField((FieldBinding)variable, finalAssignments[i]);
63
				complained = true;
57
				}
64
				scope.problemReporter().duplicateInitializationOfFinalLocal(
58
			} else {
65
					(LocalVariableBinding) variable,
59
				// final local variable
66
					this.finalAssignments[i]);
60
				if (flowInfo.isPotentiallyAssigned((LocalVariableBinding) variable)) {
61
					complained = true;
62
					scope.problemReporter().duplicateInitializationOfFinalLocal(
63
						(LocalVariableBinding) variable,
64
						finalAssignments[i]);
65
				}
66
			}
67
			// any reference reported at this level is removed from the parent context 
68
			// where it could also be reported again
69
			if (complained) {
70
				FlowContext currentContext = parent;
71
				while (currentContext != null) {
72
					//if (currentContext.isSubRoutine()) {
73
					currentContext.removeFinalAssignmentIfAny(finalAssignments[i]);
74
					//}
75
					currentContext = currentContext.parent;
76
				}
77
			}
67
			}
78
		}
68
		}
79
		
69
		// any reference reported at this level is removed from the parent context 
80
		// check inconsistent null checks
70
		// where it could also be reported again
81
		for (int i = 0; i < nullCount; i++) {
71
		if (complained) {
82
			Expression expression = nullReferences[i];
72
			FlowContext currentContext = this.parent;
83
			if (expression == null) continue;
73
			while (currentContext != null) {
74
				//if (currentContext.isSubRoutine()) {
75
				currentContext.removeFinalAssignmentIfAny(this.finalAssignments[i]);
76
				//}
77
				currentContext = currentContext.parent;
78
			}
79
		}
80
	}
81
	
82
	// check inconsistent null checks
83
	if (this.deferNullDiagnostic) { // within an enclosing loop, be conservative
84
		for (int i = 0; i < this.nullCount; i++) {
85
			Expression expression = this.nullReferences[i];
86
			LocalVariableBinding local = this.nullLocals[i];
87
			switch (this.nullCheckTypes[i]) {
88
				case CAN_ONLY_NULL_NON_NULL :
89
				case CAN_ONLY_NULL:
90
					if (flowInfo.isProtectedNonNull(local)) {
91
						if (nullCheckTypes[i] == CAN_ONLY_NULL_NON_NULL) {
92
							scope.problemReporter().localVariableCannotBeNull(local, expression);
93
						}
94
						return;
95
					}
96
					if (flowInfo.isProtectedNull(local)) {
97
						scope.problemReporter().localVariableCanOnlyBeNull(local, expression);
98
						return;
99
					}
100
					break;
101
				case MAY_NULL :
102
					if (flowInfo.isProtectedNonNull(local)) {
103
						return;
104
					}
105
					if (flowInfo.isProtectedNull(local)) {
106
						scope.problemReporter().localVariableCanOnlyBeNull(local, expression);
107
						return;
108
					}
109
					break;
110
				default:
111
					// never happens
112
			}
113
			this.parent.recordUsingNullReference(scope, local, expression, 
114
					this.nullCheckTypes[i], flowInfo);
115
		}
116
	}
117
	else { // no enclosing loop, be as precise as possible right now
118
		for (int i = 0; i < this.nullCount; i++) {
119
			Expression expression = this.nullReferences[i];
84
			// final local variable
120
			// final local variable
85
			LocalVariableBinding local = expression.localVariableBinding();
121
			LocalVariableBinding local = this.nullLocals[i];
86
			switch (nullStatus[i]) {
122
			switch (this.nullCheckTypes[i]) {
87
				case FlowInfo.NULL :
123
				case CAN_ONLY_NULL_NON_NULL :
124
					if (flowInfo.isDefinitelyNonNull(local)) {
125
						scope.problemReporter().localVariableCannotBeNull(local, expression);				
126
						return;
127
					}
128
				case CAN_ONLY_NULL:
88
					if (flowInfo.isDefinitelyNull(local)) {
129
					if (flowInfo.isDefinitelyNull(local)) {
89
						nullReferences[i] = null;
130
						scope.problemReporter().localVariableCanOnlyBeNull(local, expression);
90
						this.parent.recordUsingNullReference(scope, local, expression, nullStatus[i], flowInfo);
131
						return;
91
					}
132
					}
92
					break;
133
					break;
93
				case FlowInfo.NON_NULL :
134
				case MAY_NULL :
94
					if (flowInfo.isDefinitelyNonNull(local)) {
135
					if (flowInfo.isDefinitelyNull(local)) {
95
						nullReferences[i] = null;
136
						scope.problemReporter().localVariableCanOnlyBeNull(local, expression);
96
						this.parent.recordUsingNullReference(scope, local, expression, nullStatus[i], flowInfo);
137
						return;
138
					}
139
					if (flowInfo.isPotentiallyNull(local)) {
140
						scope.problemReporter().localVariableMayBeNull(local, expression);
141
						return;
97
					}
142
					}
98
					break;
143
					break;
144
				default:
145
					// should not happen
99
			}
146
			}
100
		}
147
		}
101
	}
148
	}
149
}
102
	
150
	
103
	public String individualToString() {
151
	public String individualToString() {
104
		
152
		
Lines 138-143 Link Here
138
		return true;
186
		return true;
139
	}
187
	}
140
188
189
	public void recordUsingNullReference(Scope scope, LocalVariableBinding local, 
190
			Expression reference, int checkType, FlowInfo flowInfo) {
191
		if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0)	{
192
		if (deferNullDiagnostic) { // within an enclosing loop, be conservative
193
			switch (checkType) {
194
				case CAN_ONLY_NULL_NON_NULL :
195
				case CAN_ONLY_NULL:
196
					if (flowInfo.isProtectedNonNull(local)) {
197
						if (checkType == CAN_ONLY_NULL_NON_NULL) {
198
							scope.problemReporter().localVariableCannotBeNull(local, reference);
199
						}
200
						return;
201
					}
202
					if (flowInfo.isProtectedNull(local)) {
203
						scope.problemReporter().localVariableCanOnlyBeNull(local, reference);
204
						return;
205
					}
206
					break;
207
				case MAY_NULL :
208
					if (flowInfo.isProtectedNonNull(local)) {
209
						return;
210
					}
211
					if (flowInfo.isProtectedNull(local)) {
212
						scope.problemReporter().localVariableCanOnlyBeNull(local, reference);
213
						return;
214
					}
215
					break;
216
				default:
217
					// never happens
218
			}
219
		}
220
		else { // no enclosing loop, be as precise as possible right now
221
			switch (checkType) {
222
				case CAN_ONLY_NULL_NON_NULL :
223
					if (flowInfo.isDefinitelyNonNull(local)) {
224
						scope.problemReporter().localVariableCannotBeNull(local, reference);				
225
						return;
226
					}
227
				case CAN_ONLY_NULL:
228
					if (flowInfo.isDefinitelyNull(local)) {
229
						scope.problemReporter().localVariableCanOnlyBeNull(local, reference);
230
						return;
231
					}
232
					break;
233
				case MAY_NULL :
234
					if (flowInfo.isDefinitelyNull(local)) {
235
						scope.problemReporter().localVariableCanOnlyBeNull(local, reference);
236
						return;
237
					}
238
					if (flowInfo.isPotentiallyNull(local)) {
239
						scope.problemReporter().localVariableMayBeNull(local, reference);
240
						return;
241
					}
242
					if (flowInfo.isDefinitelyNonNull(local)) {
243
						return; // shortcut: cannot be null
244
					}
245
					break;
246
				default:
247
					// never happens
248
			}
249
		}
250
		recordNullReference(local, reference, checkType); 
251
		// prepare to re-check with try/catch flow info
252
		}
253
	}
254
	
141
	void removeFinalAssignmentIfAny(Reference reference) {
255
	void removeFinalAssignmentIfAny(Reference reference) {
142
		for (int i = 0; i < assignCount; i++) {
256
		for (int i = 0; i < assignCount; i++) {
143
			if (finalAssignments[i] == reference) {
257
			if (finalAssignments[i] == reference) {
Lines 148-165 Link Here
148
		}
262
		}
149
	}
263
	}
150
264
151
	protected boolean recordNullReference(Expression expression, int status) {
265
protected void recordNullReference(LocalVariableBinding local, 
152
		if (nullCount == 0) {
266
	Expression expression, int status) {
153
			nullReferences = new Expression[5];
267
	if (this.nullCount == 0) {
154
			nullStatus = new int[5];
268
		this.nullLocals = new LocalVariableBinding[5];
155
		} else {
269
		this.nullReferences = new Expression[5];
156
			if (nullCount == nullReferences.length) {
270
		this.nullCheckTypes = new int[5];
157
				System.arraycopy(nullReferences, 0, nullReferences = new Expression[nullCount * 2], 0, nullCount);
271
	} 
158
				System.arraycopy(nullStatus, 0, nullStatus = new int[nullCount * 2], 0, nullCount);
272
	else if (this.nullCount == this.nullLocals.length) {
159
			}
273
		int newLength = this.nullCount * 2;
160
		}
274
		System.arraycopy(this.nullLocals, 0, 
161
		nullReferences[nullCount] = expression;
275
			this.nullLocals = new LocalVariableBinding[newLength], 0, 
162
		nullStatus[nullCount++] = status;
276
			this.nullCount);
163
		return true;
277
		System.arraycopy(this.nullReferences, 0, 
278
			this.nullReferences = new Expression[newLength], 0,
279
			this.nullCount);
280
		System.arraycopy(this.nullCheckTypes, 0, 
281
			this.nullCheckTypes = new int[newLength], 0, 
282
			this.nullCount);
164
	}
283
	}
284
	this.nullLocals[this.nullCount] = local;
285
	this.nullReferences[this.nullCount] = expression;
286
	this.nullCheckTypes[this.nullCount++] = status;
287
}
165
}
288
}
(-)compiler/org/eclipse/jdt/internal/compiler/flow/FlowContext.java (-26 / +78 lines)
Lines 36-47 Link Here
36
	
36
	
37
	public ASTNode associatedNode;
37
	public ASTNode associatedNode;
38
	public FlowContext parent;
38
	public FlowContext parent;
39
39
	boolean deferNullDiagnostic, preemptNullDiagnostic; 
40
		// preempt marks looping contexts
40
	public final static FlowContext NotContinuableContext = new FlowContext(null, null);
41
	public final static FlowContext NotContinuableContext = new FlowContext(null, null);
41
		
42
		
42
public FlowContext(FlowContext parent, ASTNode associatedNode) {
43
public FlowContext(FlowContext parent, ASTNode associatedNode) {
43
	this.parent = parent;
44
	this.parent = parent;
44
	this.associatedNode = associatedNode;
45
	this.associatedNode = associatedNode;
46
	deferNullDiagnostic = parent != null && 
47
		(parent.deferNullDiagnostic || parent.preemptNullDiagnostic); 
45
}
48
}
46
49
47
public Label breakLabel() {
50
public Label breakLabel() {
Lines 164-170 Link Here
164
		traversedContext.recordReturnFrom(flowInfo.unconditionalInits());
167
		traversedContext.recordReturnFrom(flowInfo.unconditionalInits());
165
		if (traversedContext.associatedNode instanceof TryStatement){
168
		if (traversedContext.associatedNode instanceof TryStatement){
166
			TryStatement tryStatement = (TryStatement) traversedContext.associatedNode;
169
			TryStatement tryStatement = (TryStatement) traversedContext.associatedNode;
167
			flowInfo = flowInfo.copy().addInitializationsFrom(tryStatement.subRoutineInits);
170
				flowInfo = flowInfo.addInitializationsFrom(tryStatement.subRoutineInits);
168
		}
171
		}
169
		traversedContext = traversedContext.parent;
172
		traversedContext = traversedContext.parent;
170
	}
173
	}
Lines 257-263 Link Here
257
		traversedContext.recordReturnFrom(flowInfo.unconditionalInits());
260
		traversedContext.recordReturnFrom(flowInfo.unconditionalInits());
258
		if (traversedContext.associatedNode instanceof TryStatement){
261
		if (traversedContext.associatedNode instanceof TryStatement){
259
			TryStatement tryStatement = (TryStatement) traversedContext.associatedNode;
262
			TryStatement tryStatement = (TryStatement) traversedContext.associatedNode;
260
			flowInfo = flowInfo.copy().addInitializationsFrom(tryStatement.subRoutineInits);
263
				flowInfo = flowInfo.addInitializationsFrom(tryStatement.subRoutineInits);
261
		}
264
		}
262
		traversedContext = traversedContext.parent;
265
		traversedContext = traversedContext.parent;
263
	}
266
	}
Lines 404-410 Link Here
404
	// default implementation: do nothing
407
	// default implementation: do nothing
405
}
408
}
406
409
407
public void recordContinueFrom(FlowInfo flowInfo) {
410
public void recordContinueFrom(FlowContext innerFlowContext, FlowInfo flowInfo) {
408
	// default implementation: do nothing
411
	// default implementation: do nothing
409
}
412
}
410
413
Lines 412-428 Link Here
412
	return true; // keep going
415
	return true; // keep going
413
}
416
}
414
417
415
protected boolean recordNullReference(Expression expression, int status) {
418
/**
416
	return false; // keep going
419
 * Record a null reference for use by deferred checks. Only looping or 
420
 * finally contexts really record that information.
421
 * @param local the local variable involved in the check
422
 * @param expression the expression within which local lays
423
 * @param status the status against which the check must be performed; one of
424
 * 		{@link #CAN_ONLY_NULL CAN_ONLY_NULL}, {@link #CAN_ONLY_NULL_NON_NULL 
425
 * 		CAN_ONLY_NULL_NON_NULL}, {@link #MAY_NULL MAY_NULL} 
426
 */
427
protected void recordNullReference(LocalVariableBinding local, 
428
	Expression expression, int status) {
429
	// default implementation: do nothing
417
}
430
}
418
431
419
public void recordReturnFrom(FlowInfo flowInfo) {
432
public void recordReturnFrom(UnconditionalFlowInfo flowInfo) {
420
	// default implementation: do nothing
433
	// default implementation: do nothing
421
}
434
}
422
435
423
public void recordSettingFinal(VariableBinding variable, Reference finalReference, FlowInfo flowInfo) {
436
public void recordSettingFinal(VariableBinding variable, Reference finalReference, FlowInfo flowInfo) {
424
	if (!flowInfo.isReachable()) return;
437
	if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0)	{
425
426
	// for initialization inside looping statement that effectively loops
438
	// for initialization inside looping statement that effectively loops
427
	FlowContext context = this;
439
	FlowContext context = this;
428
	while (context != null) {
440
	while (context != null) {
Lines 431-466 Link Here
431
		}
443
		}
432
		context = context.parent;
444
		context = context.parent;
433
	}
445
	}
446
	}
434
}
447
}
435
448
436
public void recordUsingNullReference(Scope scope, LocalVariableBinding local, Expression reference, int status, FlowInfo flowInfo) {
449
public static final int 
437
	if (!flowInfo.isReachable()) return;
450
  CAN_ONLY_NULL_NON_NULL = 20, 
438
451
  	// check against null and non null, with definite values -- comparisons
439
	switch (status) {
452
  CAN_ONLY_NULL = 21,
440
		case FlowInfo.NULL :
453
  	// check against null, with definite values -- assignment to null
454
  MAY_NULL = 22;
455
		// check against null, with potential values -- NPE guard
456
457
/**
458
 * Record a null reference for use by deferred checks. Only looping or 
459
 * finally contexts really record that information. The context may
460
 * emit an error immediately depending on the status of local against
461
 * flowInfo and its nature (only looping of finally contexts defer part
462
 * of the checks; nonetheless, contexts that are nested into a looping or a
463
 * finally context get affected and delegate some checks to their enclosing
464
 * context).
465
 * @param scope the scope into which the check is performed
466
 * @param local the local variable involved in the check
467
 * @param reference the expression within which local lays
468
 * @param checkType the status against which the check must be performed; one 
469
 * 		of {@link #CAN_ONLY_NULL CAN_ONLY_NULL}, {@link #CAN_ONLY_NULL_NON_NULL 
470
 * 		CAN_ONLY_NULL_NON_NULL}, {@link #MAY_NULL MAY_NULL}
471
 * @param flowInfo the flow info at the check point; deferring contexts will
472
 *  	perform supplementary checks against flow info instances that cannot
473
 *  	be known at the time of calling this method (they are influenced by
474
 * 		code that follows the current point)
475
 */
476
public void recordUsingNullReference(Scope scope, LocalVariableBinding local, 
477
		Expression reference, int checkType, FlowInfo flowInfo) {
478
	if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) != 0 || 
479
			flowInfo.isDefinitelyUnknown(local)) {
480
		return;
481
	}
482
	switch (checkType) {
483
		case CAN_ONLY_NULL_NON_NULL :
484
			if (flowInfo.isDefinitelyNonNull(local)) {
485
				scope.problemReporter().localVariableCannotBeNull(local, reference);				
486
				return;
487
			}
488
			else if (flowInfo.isPotentiallyUnknown(local)) {
489
				return;
490
			}
491
		case CAN_ONLY_NULL:
441
			if (flowInfo.isDefinitelyNull(local)) {
492
			if (flowInfo.isDefinitelyNull(local)) {
442
				scope.problemReporter().localVariableCanOnlyBeNull(local, reference);
493
				scope.problemReporter().localVariableCanOnlyBeNull(local, reference);
443
				return;
494
				return;
444
			} else if (flowInfo.isDefinitelyNonNull(local)) {
495
			}
445
				scope.problemReporter().localVariableCannotBeNull(local, reference);				
496
			else if (flowInfo.isPotentiallyUnknown(local)) {
446
				return;
497
				return;
447
			}
498
			}
448
			break;
499
			break;
449
		case FlowInfo.NON_NULL :
500
		case MAY_NULL :
450
			if (flowInfo.isDefinitelyNull(local)) {
501
			if (flowInfo.isDefinitelyNull(local)) {
451
				scope.problemReporter().localVariableCanOnlyBeNull(local, reference);				
502
				scope.problemReporter().localVariableCanOnlyBeNull(local, reference);
503
				return;
504
			}
505
			if (flowInfo.isPotentiallyNull(local)) {
506
				scope.problemReporter().localVariableMayBeNull(local, reference);
452
				return;
507
				return;
453
			}
508
			}
454
			break;
509
			break;
510
		default:
511
			// never happens
455
	}
512
	}
456
	
513
	if (parent != null) {
457
	// for initialization inside looping statement that effectively loops
514
		parent.recordUsingNullReference(scope, local, reference, checkType, 
458
	FlowContext context = this;
515
				flowInfo);
459
	while (context != null) {
460
		if (context.recordNullReference(reference, status)) {
461
			return; // no need to keep going
462
		}
463
		context = context.parent;
464
	}
516
	}
465
}
517
}
466
518
(-)compiler/org/eclipse/jdt/internal/compiler/flow/FlowInfo.java (-69 / +230 lines)
Lines 15-22 Link Here
15
15
16
public abstract class FlowInfo {
16
public abstract class FlowInfo {
17
17
18
	public int tagBits; // REACHABLE by default
18
	public final static int REACHABLE = 0;
19
	public final static int REACHABLE = 0;
19
	public final static int UNREACHABLE = 1;
20
	public final static int UNREACHABLE = 1;
21
	public final static int NULL_FLAG_MASK = 2;
20
	
22
	
21
	public final static int UNKNOWN = 0;
23
	public final static int UNKNOWN = 0;
22
	public final static int NULL = 1;
24
	public final static int NULL = 1;
Lines 25-35 Link Here
25
	public static final UnconditionalFlowInfo DEAD_END; // Represents a dead branch status of initialization
27
	public static final UnconditionalFlowInfo DEAD_END; // Represents a dead branch status of initialization
26
	static {
28
	static {
27
		DEAD_END = new UnconditionalFlowInfo();
29
		DEAD_END = new UnconditionalFlowInfo();
28
		DEAD_END.reachMode = UNREACHABLE;
30
		DEAD_END.tagBits = UNREACHABLE;
29
	}
31
	}
30
	abstract public FlowInfo addInitializationsFrom(FlowInfo otherInits);
31
32
32
	abstract public FlowInfo addPotentialInitializationsFrom(FlowInfo otherInits);
33
/**
34
 * Add other inits to this flow info, then return this. The operation semantics
35
 * are to match as closely as possible the application to this flow info of all
36
 * the operations that resulted into otherInits. 
37
 * @param otherInits other inits to add to this
38
 * @return this, modified according to otherInits information
39
 */
40
abstract public FlowInfo addInitializationsFrom(FlowInfo otherInits);
41
42
43
/**
44
 * Compose other inits over this flow info, then return this. The operation
45
 * semantics are to wave into this flow info the consequences of a possible
46
 * path into the operations that resulted into otherInits. The fact that this
47
 * path may be left unexecuted under peculiar conditions results into less
48
 * specific results than {@link #addInitializationsFrom(FlowInfo) 
49
 * addInitializationsFrom}.
50
 * @param otherInits other inits to compose over this
51
 * @return this, modified according to otherInits information
52
 */
53
abstract public FlowInfo addPotentialInitializationsFrom(FlowInfo otherInits);
33
54
34
	public FlowInfo asNegatedCondition() {
55
	public FlowInfo asNegatedCondition() {
35
56
Lines 42-47 Link Here
42
		return new ConditionalFlowInfo(initsWhenTrue, initsWhenFalse);
63
		return new ConditionalFlowInfo(initsWhenTrue, initsWhenFalse);
43
	}
64
	}
44
65
66
/**
67
 * Return a deep copy of the current instance.
68
 * @return a deep copy of this flow info
69
 */
45
	abstract public FlowInfo copy();
70
	abstract public FlowInfo copy();
46
71
47
	public static UnconditionalFlowInfo initial(int maxFieldCount) {
72
	public static UnconditionalFlowInfo initial(int maxFieldCount) {
Lines 49-57 Link Here
49
		info.maxFieldCount = maxFieldCount;
74
		info.maxFieldCount = maxFieldCount;
50
		return info;
75
		return info;
51
	}
76
	}
52
77
	
53
	abstract public FlowInfo initsWhenFalse();
78
/**
54
79
 * Return the flow info that would result from the path associated to the
80
 * value false for the condition expression that generated this flow info.
81
 * May be this flow info if it is not an instance of {@link 
82
 * ConditionalFlowInfo}. May have a side effect on subparts of this flow
83
 * info (subtrees get merged).
84
 * @return the flow info associated to the false branch of the condition
85
 * 			that generated this flow info
86
 */
87
abstract public FlowInfo initsWhenFalse();
88
89
/**
90
 * Return the flow info that would result from the path associated to the
91
 * value true for the condition expression that generated this flow info.
92
 * May be this flow info if it is not an instance of {@link 
93
 * ConditionalFlowInfo}. May have a side effect on subparts of this flow
94
 * info (subtrees get merged).
95
 * @return the flow info associated to the true branch of the condition
96
 * 			that generated this flow info
97
 */
55
	abstract public FlowInfo initsWhenTrue();
98
	abstract public FlowInfo initsWhenTrue();
56
99
57
	/**
100
	/**
Lines 64-88 Link Here
64
	 */
107
	 */
65
	public abstract boolean isDefinitelyAssigned(LocalVariableBinding local);
108
	public abstract boolean isDefinitelyAssigned(LocalVariableBinding local);
66
109
67
	/**
110
/**
68
	 * Check status of definite null assignment for a field.
111
 * Check status of definite non-null value for a given local variable.
69
	 */
112
 * @param local the variable to ckeck
70
	 abstract public boolean isDefinitelyNonNull(FieldBinding field);   
113
 * @return true iff local is definitely non null for this flow info
71
114
 */
72
	/**
73
	 * Check status of definite null assignment for a local.
74
	 */
75
	public abstract boolean isDefinitelyNonNull(LocalVariableBinding local);
115
	public abstract boolean isDefinitelyNonNull(LocalVariableBinding local);
76
116
77
	/**
117
/**
78
	 * Check status of definite null assignment for a field.
118
 * Check status of definite null value for a given local variable.
79
	 */
119
 * @param local the variable to ckeck
80
	 abstract public boolean isDefinitelyNull(FieldBinding field);   
120
 * @return true iff local is definitely null for this flow info
81
121
 */
82
	/**
122
public abstract boolean isDefinitelyNull(LocalVariableBinding local);
83
	 * Check status of definite null assignment for a local.
123
84
	 */
124
/**
85
	public abstract boolean isDefinitelyNull(LocalVariableBinding local);
125
 * Check status of definite unknown value for a given local variable.
126
 * @param local the variable to ckeck
127
 * @return true iff local is definitely unknown for this flow info
128
 */
129
public abstract boolean isDefinitelyUnknown(LocalVariableBinding local);
86
130
87
	/**
131
	/**
88
	 * Check status of potential assignment for a field.
132
	 * Check status of potential assignment for a field.
Lines 95-101 Link Here
95
139
96
	 abstract public boolean isPotentiallyAssigned(LocalVariableBinding field);   
140
	 abstract public boolean isPotentiallyAssigned(LocalVariableBinding field);   
97
141
98
	abstract public boolean isReachable();
142
/**
143
 * Check status of potential null assignment for a local.
144
 */
145
public abstract boolean isPotentiallyNull(LocalVariableBinding local);
146
	
147
/**
148
 * Return true if the given local may have been assigned to an unknown value.
149
 * @param local the local to check
150
 * @return true if the given local may have been assigned to an unknown value
151
 */
152
public abstract boolean isPotentiallyUnknown(LocalVariableBinding local);
153
154
/**
155
 * Return true if the given local is protected by a test against a non null
156
 * value.
157
 * @param local the local to check
158
 * @return true if the given local is protected by a test against a non null
159
 */
160
public abstract boolean isProtectedNonNull(LocalVariableBinding local);
161
162
/**
163
 * Return true if the given local is protected by a test against null.
164
 * @param local the local to check
165
 * @return true if the given local is protected by a test against null
166
 */
167
public abstract boolean isProtectedNull(LocalVariableBinding local);
168
169
/**
170
 * Record that a local variable got checked to be non null.
171
 * @param local the checked local variable
172
 */
173
abstract public void markAsComparedEqualToNonNull(LocalVariableBinding local);
174
	
175
/**
176
 * Record that a local variable got checked to be null.
177
 * @param local the checked local variable
178
 */
179
abstract public void markAsComparedEqualToNull(LocalVariableBinding local);
99
	
180
	
100
	/**
181
	/**
101
	 * Record a field got definitely assigned.
182
	 * Record a field got definitely assigned.
Lines 118-124 Link Here
118
	abstract public void markAsDefinitelyNull(LocalVariableBinding local);
199
	abstract public void markAsDefinitelyNull(LocalVariableBinding local);
119
200
120
	/**
201
	/**
121
	 * Record a field got definitely assigned.
202
	 * Record a field got definitely assigned to null.
122
	 */
203
	 */
123
	abstract public void markAsDefinitelyNull(FieldBinding field);
204
	abstract public void markAsDefinitelyNull(FieldBinding field);
124
205
Lines 127-178 Link Here
127
	 */
208
	 */
128
	abstract public void markAsDefinitelyAssigned(LocalVariableBinding local);
209
	abstract public void markAsDefinitelyAssigned(LocalVariableBinding local);
129
210
130
	/**
211
/**
131
	 * Clear the initialization info for a field
212
 * Record a local got definitely assigned to an unknown value.
132
	 */
213
 */
133
	abstract public void markAsDefinitelyNotAssigned(FieldBinding field);
214
abstract public void markAsDefinitelyUnknown(LocalVariableBinding local);
134
215
135
	/**
216
/**
136
	 * Clear the initialization info for a local variable
217
 * Merge branches using optimized boolean conditions
137
	 */
218
 */
138
	abstract public void markAsDefinitelyNotAssigned(LocalVariableBinding local);
219
public static UnconditionalFlowInfo mergedOptimizedBranches(
139
220
		FlowInfo initsWhenTrue, boolean isOptimizedTrue, 
140
	/**
221
		FlowInfo initsWhenFalse, boolean isOptimizedFalse, 
141
	 * Merge branches using optimized boolean conditions
222
		boolean allowFakeDeadBranch) {
142
	 */
223
	UnconditionalFlowInfo mergedInfo;
143
	public static FlowInfo mergedOptimizedBranches(FlowInfo initsWhenTrue, boolean isOptimizedTrue, FlowInfo initsWhenFalse, boolean isOptimizedFalse, boolean allowFakeDeadBranch) {
224
	if (isOptimizedTrue){
144
		FlowInfo mergedInfo;
225
		if (initsWhenTrue == FlowInfo.DEAD_END && allowFakeDeadBranch) {
145
		if (isOptimizedTrue){
226
			mergedInfo = initsWhenFalse.setReachMode(FlowInfo.UNREACHABLE).
146
			if (initsWhenTrue == FlowInfo.DEAD_END && allowFakeDeadBranch) {
227
				unconditionalInits();
147
				mergedInfo = initsWhenFalse.setReachMode(FlowInfo.UNREACHABLE);
228
		} 
148
			} else {
229
		else {
149
				mergedInfo = initsWhenTrue.addPotentialInitializationsFrom(initsWhenFalse);
230
			mergedInfo = 
150
			}
231
				initsWhenTrue.addPotentialInitializationsFrom(initsWhenFalse.
151
232
					nullInfoLessUnconditionalCopy()).
152
		} else if (isOptimizedFalse) {
233
				unconditionalInits();
153
			if (initsWhenFalse == FlowInfo.DEAD_END && allowFakeDeadBranch) {
154
				mergedInfo = initsWhenTrue.setReachMode(FlowInfo.UNREACHABLE);
155
			} else {
156
				mergedInfo = initsWhenFalse.addPotentialInitializationsFrom(initsWhenTrue);
157
			}
158
159
		} else {
160
			mergedInfo = initsWhenTrue.unconditionalInits().mergedWith(initsWhenFalse.unconditionalInits());
161
		}
234
		}
162
		return mergedInfo;
235
	} 
236
	else if (isOptimizedFalse) {
237
		if (initsWhenFalse == FlowInfo.DEAD_END && allowFakeDeadBranch) {
238
			mergedInfo = initsWhenTrue.setReachMode(FlowInfo.UNREACHABLE).
239
				unconditionalInits();
240
		} 
241
		else {
242
			mergedInfo = 
243
				initsWhenFalse.addPotentialInitializationsFrom(initsWhenTrue.
244
					nullInfoLessUnconditionalCopy()).
245
				unconditionalInits();
246
		}
247
	} 
248
	else {
249
		mergedInfo = initsWhenTrue.
250
			mergedWith(initsWhenFalse.unconditionalInits());
163
	}
251
	}
252
	return mergedInfo;
253
}
164
	
254
	
165
	abstract public int reachMode();
255
/**
166
256
 * Return REACHABLE if this flow info is reachable, UNREACHABLE
167
	abstract public FlowInfo setReachMode(int reachMode);
257
 * else.
168
258
 * @return REACHABLE if this flow info is reachable, UNREACHABLE
169
	/**
259
 *         else
170
	 * Returns the receiver updated in the following way: <ul>
260
 */
171
	 * <li> intersection of definitely assigned variables, 
261
public int reachMode() {
172
	 * <li> union of potentially assigned variables.
262
	return this.tagBits & UNREACHABLE;
173
	 * </ul>
263
}
174
	 */
264
	
175
	abstract public UnconditionalFlowInfo mergedWith(UnconditionalFlowInfo otherInits);
265
/**
266
 * Return a flow info that carries the same information as the result of
267
 * {@link #initsWhenTrue() initsWhenTrue}, but warrantied to be different 
268
 * from this.<br>
269
 * Caveat: side effects on the result may affect components of this. 
270
 * @return the result of initsWhenTrue or a copy of it
271
 */
272
abstract public FlowInfo safeInitsWhenTrue();
273
274
/**
275
 * Set this flow info reach mode and return this.
276
 * @param reachMode one of {@link #REACHABLE REACHABLE} or {@link #UNREACHABLE UNREACHABLE}
277
 * @return this, with the reach mode set to reachMode
278
 */
279
abstract public FlowInfo setReachMode(int reachMode);
280
281
/**
282
 * Return the intersection of this and otherInits, that is 
283
 * one of:<ul>
284
 *   <li>the receiver updated in the following way:<ul>
285
 *     <li>intersection of definitely assigned variables, 
286
 *     <li>union of potentially assigned variables,
287
 *     <li>similar operations for null,</ul>
288
 *   <li>or the receiver or otherInits if the other one is non
289
 *       reachable.</ul>
290
 * otherInits is not affected, and is not returned either (no
291
 * need to protect the result).
292
 * @param otherInits the flow info to merge with this
293
 * @return the intersection of this and otherInits.
294
 */
295
abstract public UnconditionalFlowInfo mergedWith(
296
		UnconditionalFlowInfo otherInits);
297
298
/**
299
 * Return a copy of this unconditional flow info, deprived from its null
300
 * info. {@link #DEAD_END DEAD_END} is returned unmodified.
301
 * @return a copy of this unconditional flow info deprived from its null info
302
 */
303
abstract public UnconditionalFlowInfo nullInfoLessUnconditionalCopy();
176
304
177
	public String toString(){
305
	public String toString(){
178
306
Lines 182-186 Link Here
182
		return super.toString();
310
		return super.toString();
183
	}
311
	}
184
312
185
	abstract public UnconditionalFlowInfo unconditionalInits();
313
/**
314
 * Return a new flow info that holds the same information as this would after
315
 * a call to unconditionalInits, but leaving this info unaffected. Moreover,
316
 * the result can be modified without affecting this.
317
 * @return a new flow info carrying this unconditional flow info
318
 */
319
abstract public UnconditionalFlowInfo unconditionalCopy();
320
321
/**
322
 * Return a new flow info that holds the same information as this would after
323
 * a call to {@link #unconditionalInits() unconditionalInits} followed by the 
324
 * erasure of fields specific information, but leaving this flow info unaffected.
325
 * @return a new flow info carrying the unconditional flow info for local variables
326
 */
327
abstract public UnconditionalFlowInfo unconditionalFieldLessCopy();
328
329
/**
330
 * Return a flow info that merges the possible paths of execution described by
331
 * this flow info. In case of an unconditional flow info, return this. In case
332
 * of a conditional flow info, merge branches recursively. Caveat: this may
333
 * be affected, and modifying the result may affect this. 
334
 * @return a flow info that merges the possible paths of execution described by
335
 * 			this
336
 */
337
abstract public UnconditionalFlowInfo unconditionalInits();
338
339
/**
340
 * Return a new flow info that holds the same information as this would after
341
 * a call to {@link #unconditionalInits() unconditionalInits}, but leaving 
342
 * this info unaffected. Side effects on the result might affect this though 
343
 * (consider it as read only).
344
 * @return a flow info carrying this unconditional flow info
345
 */
346
abstract public UnconditionalFlowInfo unconditionalInitsWithoutSideEffect();
186
}
347
}
(-)compiler/org/eclipse/jdt/internal/compiler/flow/InsideSubRoutineFlowContext.java (-8 / +8 lines)
Lines 47-59 Link Here
47
		return (SubRoutineStatement)associatedNode;
47
		return (SubRoutineStatement)associatedNode;
48
	}
48
	}
49
	
49
	
50
	public void recordReturnFrom(FlowInfo flowInfo) {
50
public void recordReturnFrom(UnconditionalFlowInfo flowInfo) {
51
51
	if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0)	{
52
		if (!flowInfo.isReachable()) return; 
52
	if (initsOnReturn == FlowInfo.DEAD_END) {
53
		if (initsOnReturn == FlowInfo.DEAD_END) {
53
		initsOnReturn = (UnconditionalFlowInfo) flowInfo.copy();
54
			initsOnReturn = flowInfo.copy().unconditionalInits();
54
	} else {
55
		} else {
55
		initsOnReturn = initsOnReturn.mergedWith(flowInfo);
56
			initsOnReturn = initsOnReturn.mergedWith(flowInfo.copy().unconditionalInits());
57
		}
58
	}
56
	}
57
	}
58
}
59
}
59
}
(-)compiler/org/eclipse/jdt/internal/compiler/flow/LoopingFlowContext.java (-65 / +226 lines)
Lines 28-109 Link Here
28
	
28
	
29
	public Label continueLabel;
29
	public Label continueLabel;
30
	public UnconditionalFlowInfo initsOnContinue = FlowInfo.DEAD_END;
30
	public UnconditionalFlowInfo initsOnContinue = FlowInfo.DEAD_END;
31
	private UnconditionalFlowInfo upstreamNullFlowInfo;
32
	private LoopingFlowContext innerFlowContexts[] = null;
33
	private UnconditionalFlowInfo innerFlowInfos[] = null;
34
	private int innerFlowContextsNb = 0;
35
	
31
	Reference finalAssignments[];
36
	Reference finalAssignments[];
32
	VariableBinding finalVariables[];
37
	VariableBinding finalVariables[];
33
	int assignCount = 0;
38
	int assignCount = 0;
34
	
39
	
40
	LocalVariableBinding[] nullLocals;
35
	Expression[] nullReferences;
41
	Expression[] nullReferences;
36
	int[] nullStatus;
42
	int[] nullCheckTypes;
37
	int nullCount;
43
	int nullCount;
38
	
44
	
39
	Scope associatedScope;
45
	Scope associatedScope;
40
	
46
	
41
	public LoopingFlowContext(
47
	public LoopingFlowContext(
42
		FlowContext parent,
48
		FlowContext parent,
49
		FlowInfo upstreamNullFlowInfo,
43
		ASTNode associatedNode,
50
		ASTNode associatedNode,
44
		Label breakLabel,
51
		Label breakLabel,
45
		Label continueLabel,
52
		Label continueLabel,
46
		Scope associatedScope) {
53
		Scope associatedScope) {
47
		super(parent, associatedNode, breakLabel);
54
		super(parent, associatedNode, breakLabel);
55
		preemptNullDiagnostic = true; 
56
			// children will defer to this, which may defer to its own parent 
48
		this.continueLabel = continueLabel;
57
		this.continueLabel = continueLabel;
49
		this.associatedScope = associatedScope;
58
		this.associatedScope = associatedScope;
59
		this.upstreamNullFlowInfo = upstreamNullFlowInfo.unconditionalCopy();
50
	}
60
	}
51
	
61
52
	public void complainOnDeferredChecks(BlockScope scope, FlowInfo flowInfo) {
62
/**
53
		
63
 * Perform deferred checks relative to final variables duplicate initialization 
54
		// complain on final assignments in loops
64
 * of lack of initialization.
55
		for (int i = 0; i < assignCount; i++) {
65
 * @param scope the scope to which this context is associated
56
			VariableBinding variable = finalVariables[i];
66
 * @param flowInfo the flow info against which checks must be performed
57
			if (variable == null) continue;
67
 */
58
			boolean complained = false; // remember if have complained on this final assignment
68
public void complainOnDeferredFinalChecks(BlockScope scope, FlowInfo flowInfo) {
59
			if (variable instanceof FieldBinding) {
69
	// complain on final assignments in loops
60
				if (flowInfo.isPotentiallyAssigned((FieldBinding) variable)) {
70
	for (int i = 0; i < assignCount; i++) {
61
					complained = true;
71
		VariableBinding variable = finalVariables[i];
62
					scope.problemReporter().duplicateInitializationOfBlankFinalField(
72
		if (variable == null) continue;
63
						(FieldBinding) variable,
73
		boolean complained = false; // remember if have complained on this final assignment
64
						finalAssignments[i]);
74
		if (variable instanceof FieldBinding) {
65
				}
75
			if (flowInfo.isPotentiallyAssigned((FieldBinding) variable)) {
66
			} else {
76
				complained = true;
67
				if (flowInfo.isPotentiallyAssigned((LocalVariableBinding) variable)) {
77
				scope.problemReporter().duplicateInitializationOfBlankFinalField(
68
					complained = true;
78
					(FieldBinding) variable,
69
					scope.problemReporter().duplicateInitializationOfFinalLocal(
79
					finalAssignments[i]);
70
						(LocalVariableBinding) variable,
71
						finalAssignments[i]);
72
				}
73
			}
80
			}
74
			// any reference reported at this level is removed from the parent context where it 
81
		} else {
75
			// could also be reported again
82
			if (flowInfo.isPotentiallyAssigned((LocalVariableBinding) variable)) {
76
			if (complained) {
83
				complained = true;
77
				FlowContext context = parent;
84
				scope.problemReporter().duplicateInitializationOfFinalLocal(
78
				while (context != null) {
85
					(LocalVariableBinding) variable,
79
					context.removeFinalAssignmentIfAny(finalAssignments[i]);
86
					finalAssignments[i]);
80
					context = context.parent;
81
				}
82
			}
87
			}
83
		}
88
		}
84
		// check inconsistent null checks
89
		// any reference reported at this level is removed from the parent context where it 
85
		for (int i = 0; i < nullCount; i++) {
90
		// could also be reported again
86
			Expression expression = nullReferences[i];
91
		if (complained) {
87
			if (expression == null) continue;
92
			FlowContext context = parent;
93
			while (context != null) {
94
				context.removeFinalAssignmentIfAny(finalAssignments[i]);
95
				context = context.parent;
96
			}
97
		}
98
	}
99
}
100
101
/**
102
 * Perform deferred checks relative to the null status of local variables.
103
 * @param scope the scope to which this context is associated
104
 * @param flowInfo the flow info against which checks must be performed
105
 */
106
public void complainOnDeferredNullChecks(BlockScope scope, FlowInfo flowInfo) {
107
	for (int i = 0 ; i < this.innerFlowContextsNb ; i++) {
108
		this.upstreamNullFlowInfo.
109
			addPotentialNullInfoFrom(
110
				this.innerFlowContexts[i].upstreamNullFlowInfo).
111
			addPotentialNullInfoFrom(this.innerFlowInfos[i]);
112
	}
113
	this.innerFlowContextsNb = 0;
114
	flowInfo = this.upstreamNullFlowInfo.
115
		addPotentialNullInfoFrom(
116
			flowInfo.unconditionalInitsWithoutSideEffect());
117
	if (this.deferNullDiagnostic) {
118
		// check only immutable null checks on innermost looping context
119
		for (int i = 0; i < this.nullCount; i++) {
120
			LocalVariableBinding local = this.nullLocals[i];
121
			Expression expression = this.nullReferences[i];
88
			// final local variable
122
			// final local variable
89
			LocalVariableBinding local = expression.localVariableBinding();
123
			switch (this.nullCheckTypes[i]) {
90
			switch (nullStatus[i]) {
124
				case CAN_ONLY_NULL_NON_NULL :
91
				case FlowInfo.NULL :
125
					if (flowInfo.isDefinitelyNonNull(local)) {
126
						this.nullReferences[i] = null;
127
						scope.problemReporter().localVariableCannotBeNull(local, expression);
128
						continue;
129
					}
130
				case CAN_ONLY_NULL :
92
					if (flowInfo.isDefinitelyNull(local)) {
131
					if (flowInfo.isDefinitelyNull(local)) {
93
						nullReferences[i] = null;
132
						this.nullReferences[i] = null;
94
						this.parent.recordUsingNullReference(scope, local, expression, nullStatus[i], flowInfo);
133
						scope.problemReporter().localVariableCanOnlyBeNull(local, expression);
134
						continue;
95
					}
135
					}
96
					break;
136
					break;
97
				case FlowInfo.NON_NULL :
137
				case MAY_NULL:
138
					if (flowInfo.isDefinitelyNull(local)) {
139
						this.nullReferences[i] = null;
140
						scope.problemReporter().localVariableCanOnlyBeNull(local, expression);
141
						continue;
142
					}
143
					break;
144
				default:
145
					// never happens	
146
			}
147
			this.parent.recordUsingNullReference(scope, local, expression, 
148
					this.nullCheckTypes[i], flowInfo);
149
		}
150
	}
151
	else {
152
		// check inconsistent null checks on outermost looping context
153
		for (int i = 0; i < this.nullCount; i++) {
154
			Expression expression = this.nullReferences[i];
155
			// final local variable
156
			LocalVariableBinding local = this.nullLocals[i];
157
			switch (this.nullCheckTypes[i]) {
158
				case CAN_ONLY_NULL_NON_NULL :
98
					if (flowInfo.isDefinitelyNonNull(local)) {
159
					if (flowInfo.isDefinitelyNonNull(local)) {
99
						nullReferences[i] = null;
160
						this.nullReferences[i] = null;
100
						this.parent.recordUsingNullReference(scope, local, expression, nullStatus[i], flowInfo);
161
						scope.problemReporter().localVariableCannotBeNull(local, expression);
162
						continue;
163
					}
164
				case CAN_ONLY_NULL :
165
					if (flowInfo.isDefinitelyNull(local)) {
166
						this.nullReferences[i] = null;
167
						scope.problemReporter().localVariableCanOnlyBeNull(local, expression);
168
						continue;
101
					}
169
					}
102
					break;
170
					break;
171
				case MAY_NULL:
172
					if (flowInfo.isDefinitelyNull(local)) {
173
						this.nullReferences[i] = null;
174
						scope.problemReporter().localVariableCanOnlyBeNull(local, expression);
175
						continue;
176
					}
177
					if (flowInfo.isPotentiallyNull(local)) {
178
						this.nullReferences[i] = null;
179
						scope.problemReporter().localVariableMayBeNull(local, expression);
180
						continue;
181
					}
182
					break;
183
				default:
184
					// never happens	
103
			}
185
			}
104
		}		
186
		}
105
	}
187
	}
106
188
}
189
	
107
	public Label continueLabel() {
190
	public Label continueLabel() {
108
		return continueLabel;
191
		return continueLabel;
109
	}
192
	}
Lines 125-139 Link Here
125
		return initsOnContinue != FlowInfo.DEAD_END;
208
		return initsOnContinue != FlowInfo.DEAD_END;
126
	}
209
	}
127
210
128
	public void recordContinueFrom(FlowInfo flowInfo) {
211
public void recordContinueFrom(FlowContext innerFlowContext, FlowInfo flowInfo) {
129
212
	if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0)	{
130
		if (!flowInfo.isReachable()) return;
213
	if ((initsOnContinue.tagBits & FlowInfo.UNREACHABLE) == 0) {
131
		if (initsOnContinue == FlowInfo.DEAD_END) {
214
		initsOnContinue = initsOnContinue.
132
			initsOnContinue = flowInfo.copy().unconditionalInits();
215
			mergedWith(flowInfo.unconditionalInitsWithoutSideEffect());
133
		} else {
216
	} 
134
			initsOnContinue = initsOnContinue.mergedWith(flowInfo.copy().unconditionalInits());
217
	else {
218
		initsOnContinue = flowInfo.unconditionalCopy();
219
	}
220
	FlowContext inner = innerFlowContext;
221
	while (inner != this && !(inner instanceof LoopingFlowContext)) {
222
		inner = inner.parent;
223
	}
224
	if (inner == this) {
225
		this.upstreamNullFlowInfo.
226
			addPotentialNullInfoFrom(
227
				flowInfo.unconditionalInitsWithoutSideEffect());
228
	}
229
	else {
230
		int length = 0;
231
		if (this.innerFlowContexts == null) {
232
			this.innerFlowContexts = new LoopingFlowContext[5];
233
			this.innerFlowInfos = new UnconditionalFlowInfo[5];
234
		}
235
		else if (this.innerFlowContextsNb == 
236
				(length = this.innerFlowContexts.length) - 1) {
237
			System.arraycopy(this.innerFlowContexts, 0, 
238
				(this.innerFlowContexts = new LoopingFlowContext[length + 5]), 
239
				0, length);
240
			System.arraycopy(this.innerFlowInfos, 0, 
241
				(this.innerFlowInfos= new UnconditionalFlowInfo[length + 5]), 
242
				0, length);
135
		}
243
		}
244
		this.innerFlowContexts[this.innerFlowContextsNb] = (LoopingFlowContext) inner;
245
		this.innerFlowInfos[this.innerFlowContextsNb++] = 
246
			flowInfo.unconditionalInitsWithoutSideEffect();
136
	}
247
	}
248
	}
249
}
137
250
138
	protected boolean recordFinalAssignment(
251
	protected boolean recordFinalAssignment(
139
		VariableBinding binding,
252
		VariableBinding binding,
Lines 170-189 Link Here
170
		return true;
283
		return true;
171
	}
284
	}
172
285
173
	protected boolean recordNullReference(Expression expression, int status) {
286
protected void recordNullReference(LocalVariableBinding local, 
174
		if (nullCount == 0) {
287
	Expression expression, int status) {
175
			nullReferences = new Expression[5];
288
	if (nullCount == 0) {
176
			nullStatus = new int[5];
289
		nullLocals = new LocalVariableBinding[5];
177
		} else {
290
		nullReferences = new Expression[5];
178
			if (nullCount == nullReferences.length) {
291
		nullCheckTypes = new int[5];
179
				System.arraycopy(nullReferences, 0, nullReferences = new Expression[nullCount * 2], 0, nullCount);
292
	} 
180
				System.arraycopy(nullStatus, 0, nullStatus = new int[nullCount * 2], 0, nullCount);
293
	else if (nullCount == nullLocals.length) {
294
		System.arraycopy(nullLocals, 0, 
295
			nullLocals = new LocalVariableBinding[nullCount * 2], 0, nullCount);
296
		System.arraycopy(nullReferences, 0, 
297
			nullReferences = new Expression[nullCount * 2], 0, nullCount);
298
		System.arraycopy(nullCheckTypes, 0, 
299
			nullCheckTypes = new int[nullCount * 2], 0, nullCount);
300
	}
301
	nullLocals[nullCount] = local;
302
	nullReferences[nullCount] = expression;
303
	nullCheckTypes[nullCount++] = status;
304
}
305
	
306
public void recordUsingNullReference(Scope scope, LocalVariableBinding local,
307
		Expression reference, int checkType, FlowInfo flowInfo) {
308
	if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) != 0 || 
309
			flowInfo.isDefinitelyUnknown(local)) {
310
		return;
311
	}
312
	switch (checkType) {
313
		case CAN_ONLY_NULL_NON_NULL :
314
		case CAN_ONLY_NULL:
315
			if (flowInfo.isDefinitelyNonNull(local)) {
316
				if (checkType == CAN_ONLY_NULL_NON_NULL) {
317
					scope.problemReporter().localVariableCannotBeNull(local, reference);
318
				}
319
				return;
181
			}
320
			}
182
		}
321
			if (flowInfo.isDefinitelyNull(local)) {
183
		nullReferences[nullCount] = expression;
322
				scope.problemReporter().localVariableCanOnlyBeNull(local, reference);
184
		nullStatus[nullCount++] = status;
323
				return;
185
		return true;
324
			}
186
	}	
325
			if (flowInfo.isPotentiallyUnknown(local)) {
326
				return;
327
			}
328
			recordNullReference(local, reference, checkType);
329
			return;
330
		case MAY_NULL :
331
			if (flowInfo.isDefinitelyNonNull(local)) {
332
				return;
333
			}
334
			if (flowInfo.isDefinitelyNull(local)) {
335
				scope.problemReporter().localVariableCanOnlyBeNull(local, reference);
336
				return;
337
			}
338
			if (flowInfo.isPotentiallyNull(local)) {
339
				scope.problemReporter().localVariableMayBeNull(local, reference);
340
				return;
341
			}
342
			recordNullReference(local, reference, checkType);
343
			return;
344
		default:
345
			// never happens
346
	}
347
}
187
	
348
	
188
	void removeFinalAssignmentIfAny(Reference reference) {
349
	void removeFinalAssignmentIfAny(Reference reference) {
189
		for (int i = 0; i < assignCount; i++) {
350
		for (int i = 0; i < assignCount; i++) {
(-)compiler/org/eclipse/jdt/internal/compiler/flow/SwitchFlowContext.java (-4 / +5 lines)
Lines 42-51 Link Here
42
}
42
}
43
43
44
public void recordBreakFrom(FlowInfo flowInfo) {
44
public void recordBreakFrom(FlowInfo flowInfo) {
45
	if (initsOnBreak == FlowInfo.DEAD_END) {
45
	if ((initsOnBreak.tagBits & FlowInfo.UNREACHABLE) == 0) {
46
		initsOnBreak = flowInfo.copy().unconditionalInits();
46
		initsOnBreak = initsOnBreak.mergedWith(flowInfo.unconditionalInits());
47
	} else {
47
	} 
48
		initsOnBreak = initsOnBreak.mergedWith(flowInfo.copy().unconditionalInits());
48
	else {
49
		initsOnBreak = flowInfo.unconditionalCopy();
49
	}
50
	}
50
}
51
}
51
}
52
}
(-)compiler/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java (-715 / +1609 lines)
Lines 10-19 Link Here
10
 *******************************************************************************/
10
 *******************************************************************************/
11
package org.eclipse.jdt.internal.compiler.flow;
11
package org.eclipse.jdt.internal.compiler.flow;
12
12
13
import org.eclipse.jdt.internal.core.Assert.AssertionFailedException; // for coverage tests
13
import org.eclipse.jdt.internal.compiler.impl.Constant;
14
import org.eclipse.jdt.internal.compiler.impl.Constant;
14
import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
15
import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
15
import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
16
import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
16
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
17
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
18
import org.eclipse.jdt.internal.compiler.lookup.TagBits;
17
19
18
/**
20
/**
19
 * Record initialization status during definite assignment analysis
21
 * Record initialization status during definite assignment analysis
Lines 21-828 Link Here
21
 * No caching of pre-allocated instances.
23
 * No caching of pre-allocated instances.
22
 */
24
 */
23
public class UnconditionalFlowInfo extends FlowInfo {
25
public class UnconditionalFlowInfo extends FlowInfo {
26
	// Coverage tests
27
	// Coverage tests need that the code be instrumented. The following flag
28
	// controls whether the instrumented code is compiled in or not, and whether
29
	// the coverage tests methods run or not.
30
	public final static boolean coverageTestFlag = false;
31
	// never release with the coverageTestFlag set to true
32
	public static int coverageTestId;
24
33
25
	
26
	public long definiteInits;
34
	public long definiteInits;
27
	public long potentialInits;
35
	public long potentialInits;
28
	public long extraDefiniteInits[];
29
	public long extraPotentialInits[];
30
	
36
	
31
	public long definiteNulls;
37
	public long nullAssignmentStatusBit1;
32
	public long definiteNonNulls;
38
	public long nullAssignmentStatusBit2;
33
	public long extraDefiniteNulls[];
39
	// 0 0 is potential (bit 1 is leftmost here)
34
	public long extraDefiniteNonNulls[];
40
	// 1 0 is assigned
35
41
	// 0 1 is protected null (aka if (o == null) { // here o protected null...)
36
	public int reachMode; // by default
42
	// 1 1 is protected non null
43
	public long nullAssignmentValueBit1;
44
	public long nullAssignmentValueBit2;
45
	// information only relevant for potential and assigned
46
	// 0 0 is start -- nothing known at all
47
	// 0 1 is assigned non null or potential anything but null
48
	// 1 0 is assigned null or potential null
49
	// 1 1 is potential null and potential anything but null or definite unknown
50
	// REVIEW consider reintroducing the difference between potential non null and potential
51
	// REVIEW unknown; if this is done, rename to nullAssignmentBit[1-4] since the semantics
52
	// REVIEW would be ever less clear
53
	// REVIEW went public in order to grant access to tests; do not like it...
54
55
	public static final int extraLength = 6;
56
	public long extra[][];
57
		// extra bit fields for larger numbers of fields/variables
58
		// extra[0] holds definiteInits values, extra[1] potentialInits, etc.
59
		// lifecycle is extra == null or else all extra[]'s are allocated
60
		// arrays which have the same size
37
61
38
	public int maxFieldCount;
62
	public int maxFieldCount; // limit between fields and locals
39
	
63
	
40
	// Constants
64
	// Constants
41
	public static final int BitCacheSize = 64; // 64 bits in a long.
65
	public static final int BitCacheSize = 64; // 64 bits in a long.
42
66
43
	UnconditionalFlowInfo() {
67
public FlowInfo addInitializationsFrom(FlowInfo inits) {
44
		this.reachMode = REACHABLE;
68
	if (this == DEAD_END)
45
	}
69
		return this;
46
70
	if (inits == DEAD_END)
47
	// unions of both sets of initialization - used for try/finally
71
		return this;
48
	public FlowInfo addInitializationsFrom(FlowInfo inits) {
72
	UnconditionalFlowInfo otherInits = inits.unconditionalInits();		
49
73
50
		if (this == DEAD_END)
74
	// union of definitely assigned variables, 
51
			return this;
75
	this.definiteInits |= otherInits.definiteInits;
52
76
	// union of potentially set ones
53
		UnconditionalFlowInfo otherInits = inits.unconditionalInits();	
77
	this.potentialInits |= otherInits.potentialInits;
54
		if (otherInits == DEAD_END)
78
	// combine null information
55
			return this;
79
	// note: we may have both forms of protection (null and non null) 
56
			
80
	// coming with otherInits, because of loops
57
		// union of definitely assigned variables, 
81
	boolean considerNulls = (otherInits.tagBits & NULL_FLAG_MASK) != 0;
58
		definiteInits |= otherInits.definiteInits;
82
	long a1, na1, a2, na2, a3, a4, na4, b1, b2, nb2, b3, nb3, b4, nb4;
59
		// union of potentially set ones
83
	// REVIEW does an inner declaration save stack space? does duplicate declaration waste time?
60
		potentialInits |= otherInits.potentialInits;
84
	if (considerNulls) {
61
	
85
		if ((this.tagBits & NULL_FLAG_MASK) == 0) {
62
		// union of definitely null variables, 
86
			this.nullAssignmentStatusBit1 = otherInits.nullAssignmentStatusBit1;
63
		definiteNulls = (definiteNulls | otherInits.definiteNulls) & ~otherInits.definiteNonNulls;
87
			this.nullAssignmentStatusBit2 = otherInits.nullAssignmentStatusBit2;
64
		// union of definitely non null variables,
88
			this.nullAssignmentValueBit1 = otherInits.nullAssignmentValueBit1;
65
		definiteNonNulls = (definiteNonNulls | otherInits.definiteNonNulls) & ~otherInits.definiteNulls;
89
			this.nullAssignmentValueBit2 = otherInits.nullAssignmentValueBit2;
66
		// fix-up null/non-null infos since cannot overlap: <defN1:0,defNoN1:1>  + <defN2:1,defNoN2:0>  --> <defN:0,defNon:0>
90
			if (coverageTestFlag && coverageTestId == 1) {
67
91
				this.nullAssignmentValueBit2 = ~0;
68
		// treating extra storage
92
			}
69
		if (extraDefiniteInits != null) {
93
		}
70
			if (otherInits.extraDefiniteInits != null) {
94
		else {
95
		// TODO (maxime) indent as follows: 
96
			/*
97
			 *   a 
98
			 *   	| (b
99
			 *   		& c)
100
			 *   
101
			 */
102
			// REVIEW indentation example
103
			this.nullAssignmentStatusBit1 =
104
				(b1 = otherInits.nullAssignmentStatusBit1) 
105
					| ((a1 = this.nullAssignmentStatusBit1) 
106
						& (((nb2 = ~(b2 = otherInits.nullAssignmentStatusBit2)) 
107
								& (nb3 = ~(b3 = otherInits.nullAssignmentValueBit1)) 
108
								& ((nb4 = ~(b4 = otherInits.nullAssignmentValueBit2)) 
109
									| ((a2 = this.nullAssignmentStatusBit2) 
110
										^ (a4 = this.nullAssignmentValueBit2)))) 
111
							| nb4 &	(na2 = ~a2)	& (na4 = ~a4)));
112
			this.nullAssignmentStatusBit2 =
113
				(b1 & b2) 
114
					| (~b1 
115
						& ((((na1 = ~a1) | a4) & b2) 
116
							| (a2 
117
								& (b2 
118
									| (a1 & (na4 = ~a4) & nb2 & nb3) 
119
									| ((~(a3 = this.nullAssignmentValueBit1) & nb3) 
120
											| (na1 & na4)) 
121
										& nb4))));
122
			this.nullAssignmentValueBit1 = 
123
				nb2 & b3 |
124
				~b1 & ((a1 & na2 & na4 | na1 & a3) & (nb2 | nb4) |
125
						a1 & na2 & a3 & nb2 |
126
						(a1 | a2 | na4) & b3);
127
			this.nullAssignmentValueBit2 =
128
				b4 |
129
				a4 & (nb2 & nb3 | ~(b1 ^ b2));
130
			if (coverageTestFlag && coverageTestId == 2) {
131
				this.nullAssignmentValueBit2 = ~0;
132
			}
133
		}
134
		this.tagBits |= NULL_FLAG_MASK; // in all cases - avoid forgetting extras
135
	}
136
	// treating extra storage
137
	if (this.extra != null || otherInits.extra != null) {
138
		int mergeLimit = 0, copyLimit = 0;
139
		if (this.extra != null) {
140
			if (otherInits.extra != null) {
71
				// both sides have extra storage
141
				// both sides have extra storage
72
				int i = 0, length, otherLength;
142
				int length, otherLength;
73
				if ((length = extraDefiniteInits.length) < (otherLength = otherInits.extraDefiniteInits.length)) {
143
				if ((length = this.extra[0].length) < 
74
					// current storage is shorter -> grow current (could maybe reuse otherInits extra storage?)
144
						(otherLength = otherInits.extra[0].length)) {
75
					System.arraycopy(extraDefiniteInits, 0, (extraDefiniteInits = new long[otherLength]), 0, length);
145
					if (coverageTestFlag && coverageTestId == 3) {
76
					System.arraycopy(extraPotentialInits, 0, (extraPotentialInits = new long[otherLength]), 0, length);
146
						throw new AssertionFailedException("COVERAGE 3"); //$NON-NLS-1$
77
					System.arraycopy(extraDefiniteNulls, 0, (extraDefiniteNulls = new long[otherLength]), 0, length);
78
					System.arraycopy(extraDefiniteNonNulls, 0, (extraDefiniteNonNulls = new long[otherLength]), 0, length);					
79
					for (; i < length; i++) {
80
						extraDefiniteInits[i] |= otherInits.extraDefiniteInits[i];
81
						extraPotentialInits[i] |= otherInits.extraPotentialInits[i];
82
						extraDefiniteNulls[i] = (extraDefiniteNulls[i] | otherInits.extraDefiniteNulls[i]) & ~otherInits.extraDefiniteNonNulls[i];
83
						extraDefiniteNonNulls[i] = (extraDefiniteNonNulls[i] | otherInits.extraDefiniteNonNulls[i]) & ~otherInits.extraDefiniteNulls[i];
84
					}
147
					}
85
					for (; i < otherLength; i++) {
148
					// current storage is shorter -> grow current
86
						extraPotentialInits[i] = otherInits.extraPotentialInits[i];
149
					for (int j = 0; j < extraLength; j++) {
150
						System.arraycopy(this.extra[j], 0, 
151
							(this.extra[j] = new long[otherLength]), 0, length);
87
					}
152
					}
153
					mergeLimit = length;
154
					copyLimit = otherLength;
88
				} else {
155
				} else {
156
					if (coverageTestFlag && coverageTestId == 4) {
157
						throw new AssertionFailedException("COVERAGE 4"); //$NON-NLS-1$
158
					}
89
					// current storage is longer
159
					// current storage is longer
90
					for (; i < otherLength; i++) {
160
					mergeLimit = otherLength;
91
						extraDefiniteInits[i] |= otherInits.extraDefiniteInits[i];
161
				}
92
						extraPotentialInits[i] |= otherInits.extraPotentialInits[i];
162
			} 
93
						extraDefiniteNulls[i] = (extraDefiniteNulls[i] | otherInits.extraDefiniteNulls[i]) & ~otherInits.extraDefiniteNonNulls[i];
163
		} 
94
						extraDefiniteNonNulls[i] = (extraDefiniteNonNulls[i] | otherInits.extraDefiniteNonNulls[i]) & ~otherInits.extraDefiniteNulls[i];
164
		else if (otherInits.extra != null) {
95
					}
165
			// no storage here, but other has extra storage.
96
					for (; i < length; i++) {
166
			// shortcut regular copy because array copy is better
97
						extraDefiniteInits[i] = 0;
167
			int otherLength;
98
						extraDefiniteNulls[i] = 0;
168
			this.extra = new long[extraLength][];
99
						extraDefiniteNonNulls[i] = 0;
169
			System.arraycopy(otherInits.extra[0], 0, 
100
					}
170
				(this.extra[0] = new long[otherLength = 
101
				}
171
					otherInits.extra[0].length]), 0, otherLength);			
102
			} else {
172
			System.arraycopy(otherInits.extra[1], 0, 
103
				// no extra storage on otherInits
173
				(this.extra[1] = new long[otherLength]), 0, otherLength);
104
			}
174
			if (considerNulls) {
105
		} else
175
				for (int j = 2; j < extraLength; j++) {
106
			if (otherInits.extraDefiniteInits != null) {
176
					System.arraycopy(otherInits.extra[j], 0, 
107
				// no storage here, but other has extra storage.
177
						(this.extra[j] = new long[otherLength]), 0, otherLength);
108
				int otherLength;
178
				}
109
				System.arraycopy(otherInits.extraDefiniteInits, 0, (extraDefiniteInits = new long[otherLength = otherInits.extraDefiniteInits.length]), 0, otherLength);			
179
				if (coverageTestFlag && coverageTestId == 5) {
110
				System.arraycopy(otherInits.extraPotentialInits, 0, (extraPotentialInits = new long[otherLength]), 0, otherLength);
180
					this.extra[5][otherLength - 1] = ~0;
111
				System.arraycopy(otherInits.extraDefiniteNulls, 0, (extraDefiniteNulls = new long[otherLength]), 0, otherLength);			
181
				}
112
				System.arraycopy(otherInits.extraDefiniteNonNulls, 0, (extraDefiniteNonNulls = new long[otherLength]), 0, otherLength);			
182
			}
183
			else {
184
				for (int j = 2; j < extraLength; j++) {
185
					this.extra[j] = new long[otherLength];			
186
				}
187
				if (coverageTestFlag && coverageTestId == 6) {
188
					this.extra[5][otherLength - 1] = ~0;
189
				}
113
			}
190
			}
114
		return this;
115
	}
116
117
	// unions of both sets of initialization - used for try/finally
118
	public FlowInfo addPotentialInitializationsFrom(FlowInfo inits) {
119
	
120
		if (this == DEAD_END){
121
			return this;
122
		}
191
		}
123
192
		int i = 0;
124
		UnconditionalFlowInfo otherInits = inits.unconditionalInits();
193
		for (; i < mergeLimit; i++) {
125
		if (otherInits == DEAD_END){
194
			this.extra[0][i] |= otherInits.extra[0][i];
126
			return this;
195
			this.extra[1][i] |= otherInits.extra[1][i];
127
		}
196
			if (considerNulls) { // could consider pushing the test outside the loop
128
		// union of potentially set ones
197
				if (this.extra[2][i] == 0 &&
129
		this.potentialInits |= otherInits.potentialInits;
198
						this.extra[3][i] == 0 &&
130
		// also merge null check information (affected by potential inits)
199
						this.extra[4][i] == 0 &&
131
		this.definiteNulls &= otherInits.definiteNulls;
200
						this.extra[5][i] == 0) {
132
		this.definiteNonNulls &= otherInits.definiteNonNulls;
201
					for (int j = 2; j < extraLength; j++) {
133
	
202
						this.extra[j][i] = otherInits.extra[j][i];
134
		// treating extra storage
135
		if (this.extraDefiniteInits != null) {
136
			if (otherInits.extraDefiniteInits != null) {
137
				// both sides have extra storage
138
				int i = 0, length, otherLength;
139
				if ((length = this.extraDefiniteInits.length) < (otherLength = otherInits.extraDefiniteInits.length)) {
140
					// current storage is shorter -> grow current (could maybe reuse otherInits extra storage?)
141
					System.arraycopy(this.extraDefiniteInits, 0, (this.extraDefiniteInits = new long[otherLength]), 0, length);
142
					System.arraycopy(this.extraPotentialInits, 0, (this.extraPotentialInits = new long[otherLength]), 0, length);
143
					System.arraycopy(this.extraDefiniteNulls, 0, (this.extraDefiniteNulls = new long[otherLength]), 0, length);
144
					System.arraycopy(this.extraDefiniteNonNulls, 0, (this.extraDefiniteNonNulls = new long[otherLength]), 0, length);
145
					while (i < length) {
146
						this.extraPotentialInits[i] |= otherInits.extraPotentialInits[i];
147
						this.extraDefiniteNulls[i] &= otherInits.extraDefiniteNulls[i];
148
						this.extraDefiniteNonNulls[i] &= otherInits.extraDefiniteNonNulls[i++];
149
					}
150
					while (i < otherLength) {
151
						this.extraPotentialInits[i] = otherInits.extraPotentialInits[i];
152
						this.extraDefiniteNulls[i] &= otherInits.extraDefiniteNulls[i];
153
						this.extraDefiniteNonNulls[i] &= otherInits.extraDefiniteNonNulls[i++];
154
					}
203
					}
155
				} else {
204
					if (coverageTestFlag && coverageTestId == 7) {
156
					// current storage is longer
205
						this.extra[5][i] = ~0;
157
					while (i < otherLength) {
158
						this.extraPotentialInits[i] |= otherInits.extraPotentialInits[i];
159
						this.extraDefiniteNulls[i] &= otherInits.extraDefiniteNulls[i];
160
						this.extraDefiniteNonNulls[i] &= otherInits.extraDefiniteNonNulls[i++];
161
					}
206
					}
162
				}
207
				}
208
				else {
209
					this.extra[2][i] =
210
						(b1 = otherInits.extra[2][i]) |
211
						(a1	 = this.extra[2][i]) & 
212
							((nb2 = ~(b2 = otherInits.extra[3][i])) &
213
								(nb3 = ~(b3 = otherInits.extra[4][i])) &
214
								((nb4 = ~(b4 = otherInits.extra[5][i])) |
215
									((a2 = this.extra[3][i]) ^ 
216
										(a4 = this.extra[5][i]))) | 
217
							nb4 & (na2 = ~a2) & (na4 = ~a4));
218
					this.extra[3][i] =
219
						b1 & b2 |
220
						~b1 & (((na1 = ~a1) | a4) & b2 |
221
								a2 & (b2 |
222
									a1 & (na4 = ~a4) & nb2 & nb3 |
223
									(~(a3 = this.extra[4][i]) & nb3 | na1 & na4) & nb4));
224
					this.extra[4][i] = 
225
						nb2 & b3 |
226
						~b1 & ((a1 & na2 & na4 | na1 & a3) & (nb2 | nb4) |
227
								a1 & na2 & a3 & nb2 |
228
								(a1 | a2 | na4) & b3);
229
					this.extra[5][i] =
230
						b4 |
231
						a4 & (nb2 & nb3 | ~(b1 ^ b2));
232
						if (coverageTestFlag && coverageTestId == 8) {
233
							this.extra[5][i] = ~0;
234
						}
235
				}
163
			}
236
			}
164
		} else
237
		}
165
			if (otherInits.extraDefiniteInits != null) {
238
		for (; i < copyLimit; i++) {
166
				// no storage here, but other has extra storage.
239
			this.extra[0][i] = otherInits.extra[0][i];
167
				int otherLength;
240
			this.extra[1][i] = otherInits.extra[1][i];
168
				this.extraDefiniteInits = new long[otherLength = otherInits.extraDefiniteInits.length];			
241
			if (considerNulls) {
169
				System.arraycopy(otherInits.extraPotentialInits, 0, (this.extraPotentialInits = new long[otherLength]), 0, otherLength);
242
				for (int j = 2; j < extraLength; j++) {
170
				this.extraDefiniteNulls = new long[otherLength];			
243
					this.extra[j][i] = otherInits.extra[j][i];
171
				this.extraDefiniteNonNulls = new long[otherLength];			
244
				}
245
				if (coverageTestFlag && coverageTestId == 9) {
246
					this.extra[5][i] = ~0;
247
				}
172
			}
248
			}
173
		return this;
174
	}
175
176
	/**
177
	 * Answers a copy of the current instance
178
	 */
179
	public FlowInfo copy() {
180
		
181
		// do not clone the DeadEnd
182
		if (this == DEAD_END)
183
			return this;
184
	
185
		// look for an unused preallocated object
186
		UnconditionalFlowInfo copy = new UnconditionalFlowInfo();
187
	
188
		// copy slots
189
		copy.definiteInits = this.definiteInits;
190
		copy.potentialInits = this.potentialInits;
191
		copy.definiteNulls = this.definiteNulls;
192
		copy.definiteNonNulls = this.definiteNonNulls;
193
		copy.reachMode = this.reachMode;
194
		copy.maxFieldCount = this.maxFieldCount;
195
		
196
		if (this.extraDefiniteInits != null) {
197
			int length;
198
			System.arraycopy(this.extraDefiniteInits, 0, (copy.extraDefiniteInits = new long[length = extraDefiniteInits.length]), 0, length);
199
			System.arraycopy(this.extraPotentialInits, 0, (copy.extraPotentialInits = new long[length]), 0, length);
200
			System.arraycopy(this.extraDefiniteNulls, 0, (copy.extraDefiniteNulls = new long[length]), 0, length);
201
			System.arraycopy(this.extraDefiniteNonNulls, 0, (copy.extraDefiniteNonNulls = new long[length]), 0, length);
202
		}
249
		}
203
		return copy;
204
	}
250
	}
205
	
251
	return this;
206
	public UnconditionalFlowInfo discardFieldInitializations(){
252
}
207
		
208
		int limit = this.maxFieldCount;
209
		
210
		if (limit < BitCacheSize) {
211
			long mask = (1L << limit)-1;
212
			this.definiteInits &= ~mask;
213
			this.potentialInits &= ~mask;
214
			this.definiteNulls &= ~mask;
215
			this.definiteNonNulls &= ~mask;
216
			return this;
217
		} 
218
253
219
		this.definiteInits = 0;
254
public FlowInfo addPotentialInitializationsFrom(FlowInfo inits) {
220
		this.potentialInits = 0;
255
	if (this == DEAD_END){
221
		this.definiteNulls = 0;
256
		return this;
222
		this.definiteNonNulls = 0;
257
	}
223
		
258
	if (inits == DEAD_END){
224
		// use extra vector
225
		if (extraDefiniteInits == null) {
226
			return this; // if vector not yet allocated, then not initialized
227
		}
228
		int vectorIndex, length = this.extraDefiniteInits.length;
229
		if ((vectorIndex = (limit / BitCacheSize) - 1) >= length) {
230
			return this; // not enough room yet
231
		}
232
		for (int i = 0; i < vectorIndex; i++) {
233
			this.extraDefiniteInits[i] = 0L;
234
			this.extraPotentialInits[i] = 0L;
235
			this.extraDefiniteNulls[i] = 0L;
236
			this.extraDefiniteNonNulls[i] = 0L;
237
		}
238
		long mask = (1L << (limit % BitCacheSize))-1;
239
		this.extraDefiniteInits[vectorIndex] &= ~mask;
240
		this.extraPotentialInits[vectorIndex] &= ~mask;
241
		this.extraDefiniteNulls[vectorIndex] &= ~mask;
242
		this.extraDefiniteNonNulls[vectorIndex] &= ~mask;
243
		return this;
259
		return this;
244
	}
260
	}
261
	UnconditionalFlowInfo otherInits = inits.unconditionalInits();
262
	// union of potentially set ones
263
	this.potentialInits |= otherInits.potentialInits;
264
	// treating extra storage
265
	if (this.extra != null) {
266
		if (otherInits.extra != null) {
267
			// both sides have extra storage
268
			int i = 0, length, otherLength;
269
			if ((length = this.extra[0].length) < (otherLength = otherInits.extra[0].length)) {
270
				// current storage is shorter -> grow current
271
				for (int j = 0; j < extraLength; j++) {
272
					System.arraycopy(this.extra[j], 0, 
273
						(this.extra[j] = new long[otherLength]), 0, length);
274
				}
275
				for (; i < length; i++) {
276
					this.extra[1][i] |= otherInits.extra[1][i];
277
				}
278
				for (; i < otherLength; i++) {
279
					this.extra[1][i] = otherInits.extra[1][i];
280
				}
281
			} 
282
			else {
283
				// current storage is longer
284
				for (; i < otherLength; i++) {
285
					this.extra[1][i] |= otherInits.extra[1][i];
286
				}
287
			}
288
		}
289
	} 
290
	else if (otherInits.extra != null) {
291
		// no storage here, but other has extra storage.
292
		int otherLength = otherInits.extra[0].length;
293
		this.extra = new long[extraLength][];
294
		for (int j = 0; j < extraLength; j++) {
295
			this.extra[j] = new long[otherLength];			
296
		}
297
		System.arraycopy(otherInits.extra[1], 0, this.extra[1], 0, 
298
			otherLength);
299
	}
300
	this.addPotentialNullInfoFrom(otherInits);
301
	// REVIEW inline?
302
	return this;
303
}
245
304
246
	public UnconditionalFlowInfo discardNonFieldInitializations(){
305
/**
247
		
306
 * Compose other inits over this flow info, then return this. The operation
248
		int limit = this.maxFieldCount;
307
 * semantics are to wave into this flow info the consequences upon null 
249
		
308
 * information of a possible path into the operations that resulted into 
250
		if (limit < BitCacheSize) {
309
 * otherInits. The fact that this path may be left unexecuted under peculiar 
251
			long mask = (1L << limit)-1;
310
 * conditions results into less specific results than 
252
			this.definiteInits &= mask;
311
 * {@link #addInitializationsFrom(FlowInfo) addInitializationsFrom}; moreover,
253
			this.potentialInits &= mask;
312
 * only the null information is affected.
254
			this.definiteNulls &= mask;
313
 * @param otherInits other null inits to compose over this
255
			this.definiteNonNulls &= mask;
314
 * @return this, modified according to otherInits information
256
			return this;
315
 */
257
		} 
316
public UnconditionalFlowInfo addPotentialNullInfoFrom(
258
		// use extra vector
317
		UnconditionalFlowInfo otherInits) {
259
		if (extraDefiniteInits == null) {
318
	if ((this.tagBits & UNREACHABLE) != 0 ||
260
			return this; // if vector not yet allocated, then not initialized
319
			(otherInits.tagBits & UNREACHABLE) != 0 ||
320
			(otherInits.tagBits & NULL_FLAG_MASK) == 0) {
321
		return this;
322
	}
323
	// if we get here, otherInits has some null info
324
	boolean thisHasNulls = (this.tagBits & NULL_FLAG_MASK) != 0;
325
	if (thisHasNulls) {
326
		long a1, a2, na2, a3, na3, a4, na4, b1, nb1, b2, nb2, b3, nb3, b4, nb4;
327
		this.nullAssignmentStatusBit1 =
328
			((a1 = this.nullAssignmentStatusBit1) &
329
					(na4 = ~(a4 = this.nullAssignmentValueBit2)) &	
330
					((na3 = ~(a3 = this.nullAssignmentValueBit1)) | 
331
							(a2 = this.nullAssignmentStatusBit2)) | 
332
							a2 & na3 &	a4) & 
333
					(nb3 = ~(b3 = otherInits.nullAssignmentValueBit1)) &
334
					((b2 = otherInits.nullAssignmentStatusBit2) | 
335
					(nb4 = ~(b4 = otherInits.nullAssignmentValueBit2))) |
336
			a1 & (na2 = ~a2) & 
337
				(a4 & ((nb1 = ~(b1 = otherInits.nullAssignmentStatusBit1)) & 
338
						nb3 | b1 &
339
						(b4 | b2)) |
340
				na4 & (nb1 & (((nb2 = ~b2) & nb4 | b2) & nb3 | b3 & nb4) | 
341
						b1 & nb4 & (nb2 | nb3)));
342
		this.nullAssignmentStatusBit2 =
343
			a2 & (~a1 & na4 & nb4 |
344
					a1 & na3 & nb3 & (nb1 & (nb2 & nb4 | b2) |
345
										b1 & (nb4 |b2 & b4)));
346
		this.nullAssignmentValueBit1 =
347
			a3 |
348
			b1 & nb2 & nb4 |
349
			nb1 & b3 |
350
			a1 & na2 & (b1 & b3 | nb1 & b4);
351
//			b1 & (~b2 & ~b4 | a1 & ~a2 & b3) |
352
//			~b1 & (b3 | a1 & ~a2 & b4); -- same op nb
353
		this.nullAssignmentValueBit2 =
354
			a4 & (na2 | a2 & na3) |
355
			b4 & (nb2 | b2 & nb3);
356
		if (coverageTestFlag && coverageTestId == 15) {
357
			this.nullAssignmentValueBit2 = ~0;
358
		}
359
		// extra storage management
360
		if (otherInits.extra != null) {
361
			int mergeLimit = 0, copyLimit = 0;
362
			int otherLength = otherInits.extra[0].length;
363
			if (this.extra == null) {
364
				this.extra = new long[extraLength][];
365
				for (int j = 0; j < extraLength; j++) {
366
					this.extra[j] = new long[otherLength];
367
				}
368
				copyLimit = otherLength;
369
				if (coverageTestFlag && coverageTestId == 16) {
370
					this.extra[2][0] = ~0; thisHasNulls = true;
371
				}
372
			}
373
			else {
374
				mergeLimit = otherLength;
375
				if (mergeLimit > this.extra[0].length) {
376
					copyLimit = mergeLimit;
377
					mergeLimit = this.extra[0].length;
378
					for (int j = 0; j < extraLength; j++) {
379
						System.arraycopy(this.extra[j], 0,
380
								this.extra[j] = new long[otherLength], 0,
381
								mergeLimit);
382
					}
383
				}
384
				int i;
385
				for (i = 0; i < mergeLimit; i++) {
386
					this.extra[2][i] =
387
						((a1 = this.extra[2][i]) &
388
								(na4 = ~(a4 = this.extra[5][i])) &	
389
								((na3 = ~(a3 = this.extra[4][i])) | 
390
										(a2 = this.extra[3][i])) | 
391
										a2 & na3 &	a4) & 
392
								(nb3 = ~(b3 = otherInits.extra[4][i])) &
393
								((b2 = otherInits.extra[3][i]) | 
394
								(nb4 = ~(b4 = otherInits.extra[5][i]))) |
395
						a1 & (na2 = ~a2) & 
396
							(a4 & ((nb1 = ~(b1 = otherInits.extra[2][i])) & 
397
									nb3 | b1 &
398
									(b4 | b2)) |
399
							na4 & (nb1 & (((nb2 = ~b2) & nb4 | b2) & nb3 | b3 & nb4) | 
400
									b1 & nb4 & (nb2 | nb3)));
401
					this.extra[3][i] =
402
						a2 & (~a1 & na4 & nb4 |
403
								a1 & na3 & nb3 & (nb1 & (nb2 & nb4 | b2) |
404
													b1 & (nb4 |b2 & b4)));
405
					this.extra[4][i] =
406
						a3 |
407
						b1 & nb2 & nb4 |
408
						nb1 & b3 |
409
						a1 & na2 & (b1 & b3 | nb1 & b4);
410
					this.extra[5][i] =
411
						a4 & (na2 | a2 & na3) |
412
						b4 & (nb2 | b2 & nb3);
413
					if (coverageTestFlag && coverageTestId == 17) {
414
						this.nullAssignmentValueBit2 = ~0;
415
					}
416
				}
417
				for (; i < copyLimit; i++) {
418
					if (otherInits.extra[4][i] != 0 ||
419
						otherInits.extra[5][i] != 0) {
420
						this.tagBits |= NULL_FLAG_MASK; 
421
						this.extra[4][i] = 
422
							otherInits.extra[4][i] &
423
							~(otherInits.extra[2][i] &
424
							  ~otherInits.extra[3][i] &
425
							  otherInits.extra[5][i]);
426
						this.extra[5][i] = 
427
							otherInits.extra[5][i];
428
						if (coverageTestFlag && coverageTestId == 18) {
429
							this.extra[5][i] = ~0;
430
						}
431
					}
432
				}
433
			}
261
		}
434
		}
262
		int vectorIndex, length = this.extraDefiniteInits.length;
435
	}
263
		if ((vectorIndex = (limit / BitCacheSize) - 1) >= length) {
436
	else {
264
			return this; // not enough room yet
437
		if (otherInits.nullAssignmentValueBit1 != 0 ||
438
			otherInits.nullAssignmentValueBit2 != 0) {
439
			// add potential values
440
			this.nullAssignmentValueBit1 = 
441
				otherInits.nullAssignmentValueBit1 & 
442
					~(otherInits.nullAssignmentStatusBit1 &
443
					  ~otherInits.nullAssignmentStatusBit2 &
444
					  otherInits.nullAssignmentValueBit2); // exclude assigned unknown
445
			this.nullAssignmentValueBit2 = 
446
				otherInits.nullAssignmentValueBit2;
447
			thisHasNulls = 
448
				this.nullAssignmentValueBit1 != 0 ||
449
				this.nullAssignmentValueBit2 != 0;
450
			if (coverageTestFlag && coverageTestId == 10) {
451
				this.nullAssignmentValueBit2 = ~0;
452
			}
265
		}
453
		}
266
		long mask = (1L << (limit % BitCacheSize))-1;
454
		// extra storage management
267
		this.extraDefiniteInits[vectorIndex] &= mask;
455
		if (otherInits.extra != null) {
268
		this.extraPotentialInits[vectorIndex] &= mask;
456
			int mergeLimit = 0, copyLimit = 0;
269
		this.extraDefiniteNulls[vectorIndex] &= mask;
457
			int otherLength = otherInits.extra[0].length;
270
		this.extraDefiniteNonNulls[vectorIndex] &= mask;
458
			if (this.extra == null) {
271
		for (int i = vectorIndex+1; i < length; i++) {
459
				copyLimit = otherLength; 
272
			this.extraDefiniteInits[i] = 0L;
460
					// cannot happen when called from addPotentialInitializationsFrom
273
			this.extraPotentialInits[i] = 0L;
461
				this.extra = new long[extraLength][];
274
			this.extraDefiniteNulls[i] = 0L;
462
				for (int j = 0; j < extraLength; j++) {
275
			this.extraDefiniteNonNulls[i] = 0L;
463
					this.extra[j] = new long[otherLength];
464
				}
465
				if (coverageTestFlag && coverageTestId == 11) {
466
					this.extra[5][0] = ~0; this.tagBits |= NULL_FLAG_MASK;
467
				}
468
			}
469
			else {
470
				mergeLimit = otherLength;
471
				if (mergeLimit > this.extra[0].length) {
472
					copyLimit = mergeLimit;
473
					mergeLimit = this.extra[0].length;
474
					System.arraycopy(this.extra[0], 0,
475
							this.extra[0] = new long[otherLength], 0,
476
							mergeLimit);
477
					System.arraycopy(this.extra[1], 0,
478
							this.extra[1] = new long[otherLength], 0,
479
							mergeLimit);
480
					for (int j = 2; j < extraLength; j++) {
481
						this.extra[j] = new long[otherLength];
482
					}
483
					if (coverageTestFlag && coverageTestId == 12) {
484
						throw new AssertionFailedException("COVERAGE 12"); //$NON-NLS-1$
485
					}
486
				}
487
			}
488
			int i;
489
			for (i = 0; i < mergeLimit; i++) {
490
				if (otherInits.extra[4][i] != 0 ||
491
					otherInits.extra[5][i] != 0) {
492
					this.extra[4][i] |= 
493
						otherInits.extra[4][i] &
494
						~(otherInits.extra[2][i] &
495
						  ~otherInits.extra[3][i] &
496
						  otherInits.extra[5][i]);
497
					this.extra[5][i] |= 
498
						otherInits.extra[5][i];
499
					thisHasNulls = thisHasNulls ||
500
						this.extra[4][i] != 0 ||
501
						this.extra[5][i] != 0;
502
					if (coverageTestFlag && coverageTestId == 13) {
503
						this.extra[5][i] = ~0;
504
					}
505
				}
506
			}
507
			for (; i < copyLimit; i++) {
508
				if (otherInits.extra[4][i] != 0 ||
509
					otherInits.extra[5][i] != 0) {
510
					this.extra[4][i] = 
511
						otherInits.extra[4][i] &
512
						~(otherInits.extra[2][i] &
513
						  ~otherInits.extra[3][i] &
514
						  otherInits.extra[5][i]);
515
					this.extra[5][i] = 
516
						otherInits.extra[5][i];
517
					thisHasNulls = thisHasNulls ||
518
						this.extra[4][i] != 0 ||
519
						this.extra[5][i] != 0;
520
					if (coverageTestFlag && coverageTestId == 14) {
521
						this.extra[5][i] = ~0;
522
					}
523
				}
524
			}
276
		}
525
		}
277
		return this;
278
	}
526
	}
279
	
527
	if (thisHasNulls) {
280
	public UnconditionalFlowInfo discardNullRelatedInitializations(){
528
		this.tagBits |= NULL_FLAG_MASK; 
281
		
282
		this.definiteNulls = 0;
283
		this.definiteNonNulls = 0;
284
		
285
		int length = this.extraDefiniteInits == null ? 0 : this.extraDefiniteInits.length;
286
		for (int i = 0; i < length; i++) {
287
			this.extraDefiniteNulls[i] = 0L;
288
			this.extraDefiniteNonNulls[i] = 0L;
289
		}
290
		return this;
291
	}
529
	}
292
530
	else {
293
	public FlowInfo initsWhenFalse() {
531
		this.tagBits &= NULL_FLAG_MASK; 
294
		
295
		return this;
296
	}
532
	}
297
	
533
	return this;
298
	public FlowInfo initsWhenTrue() {
534
}
299
		
535
536
public FlowInfo copy() {
537
	// do not clone the DeadEnd
538
	if (this == DEAD_END) {
300
		return this;
539
		return this;
301
	}
540
	}
302
	
541
	UnconditionalFlowInfo copy = new UnconditionalFlowInfo();
303
	/**
542
	// copy slots
304
	 * Check status of definite assignment at a given position.
543
	copy.definiteInits = this.definiteInits;
305
	 * It deals with the dual representation of the InitializationInfo2:
544
	copy.potentialInits = this.potentialInits;
306
	 * bits for the first 64 entries, then an array of booleans.
545
	boolean hasNullInfo = (this.tagBits & NULL_FLAG_MASK) != 0;
307
	 */
546
	if (hasNullInfo) { 
308
	final private boolean isDefinitelyAssigned(int position) {
547
		copy.nullAssignmentStatusBit1 = this.nullAssignmentStatusBit1;
309
		
548
		copy.nullAssignmentStatusBit2 = this.nullAssignmentStatusBit2;
310
		// Dependant of CodeStream.isDefinitelyAssigned(..)
549
		copy.nullAssignmentValueBit1 = this.nullAssignmentValueBit1;
311
		// id is zero-based
550
		copy.nullAssignmentValueBit2 = this.nullAssignmentValueBit2;
312
		if (position < BitCacheSize) {
551
	}
313
			return (definiteInits & (1L << position)) != 0; // use bits
552
	copy.tagBits = this.tagBits;
553
	copy.maxFieldCount = this.maxFieldCount;
554
	if (this.extra != null) {
555
		int length;
556
		copy.extra = new long[extraLength][];
557
		System.arraycopy(this.extra[0], 0, 
558
			(copy.extra[0] = new long[length = this.extra[0].length]), 0, 
559
			length);
560
		System.arraycopy(this.extra[1], 0, 
561
			(copy.extra[1] = new long[length]), 0, length);
562
		if (hasNullInfo) {
563
			for (int j = 2; j < extraLength; j++) {
564
				System.arraycopy(this.extra[j], 0, 
565
					(copy.extra[j] = new long[length]), 0, length);
566
			}
314
		}
567
		}
315
		// use extra vector
568
		else {
316
		if (extraDefiniteInits == null)
569
			for (int j = 2; j < extraLength; j++) {
317
			return false; // if vector not yet allocated, then not initialized
570
				copy.extra[j] = new long[length];
318
		int vectorIndex;
571
			}
319
		if ((vectorIndex = (position / BitCacheSize) - 1) >= extraDefiniteInits.length)
320
			return false; // if not enough room in vector, then not initialized 
321
		return ((extraDefiniteInits[vectorIndex]) & (1L << (position % BitCacheSize))) != 0;
322
	}
323
	
324
	/**
325
	 * Check status of definite non-null assignment at a given position.
326
	 * It deals with the dual representation of the InitializationInfo2:
327
	 * bits for the first 64 entries, then an array of booleans.
328
	 */
329
	final private boolean isDefinitelyNonNull(int position) {
330
		
331
		// Dependant of CodeStream.isDefinitelyAssigned(..)
332
		// id is zero-based
333
		if (position < BitCacheSize) {
334
			return (definiteNonNulls & (1L << position)) != 0; // use bits
335
		}
572
		}
336
		// use extra vector
573
	}
337
		if (extraDefiniteNonNulls == null)
574
	return copy;
338
			return false; // if vector not yet allocated, then not initialized
575
}
339
		int vectorIndex;
576
340
		if ((vectorIndex = (position / BitCacheSize) - 1) >= extraDefiniteNonNulls.length)
577
/**
341
			return false; // if not enough room in vector, then not initialized 
578
 * Remove local variables information from this flow info and return this.
342
		return ((extraDefiniteNonNulls[vectorIndex]) & (1L << (position % BitCacheSize))) != 0;
579
 * @return this, deprived from any local variable information
343
	}
580
 */
344
581
public UnconditionalFlowInfo discardNonFieldInitializations() {
345
	/**
582
	int limit = this.maxFieldCount;
346
	 * Check status of definite null assignment at a given position.
583
	if (limit < BitCacheSize) {
347
	 * It deals with the dual representation of the InitializationInfo2:
584
		long mask = (1L << limit)-1;
348
	 * bits for the first 64 entries, then an array of booleans.
585
		this.definiteInits &= mask;
349
	 */
586
		this.potentialInits &= mask;
350
	final private boolean isDefinitelyNull(int position) {
587
		this.nullAssignmentStatusBit1 &= mask;
351
		
588
		this.nullAssignmentStatusBit2 &= mask;
352
		// Dependant of CodeStream.isDefinitelyAssigned(..)
589
		this.nullAssignmentValueBit1 &= mask;
353
		// id is zero-based
590
		this.nullAssignmentValueBit2 &= mask;
354
		if (position < BitCacheSize) {
591
	} 
355
			return (definiteNulls & (1L << position)) != 0; // use bits
592
	// use extra vector
593
	if (this.extra == null) {
594
		return this; // if vector not yet allocated, then not initialized
595
	}
596
	int vectorIndex, length = this.extra[0].length;
597
	if ((vectorIndex = (limit / BitCacheSize) - 1) >= length) {
598
		return this; // not enough room yet
599
	}
600
	if (vectorIndex >= 0) { 
601
		// else we only have complete non field array items left
602
		long mask = (1L << (limit % BitCacheSize))-1;
603
		for (int j = 0; j < extraLength; j++) {
604
			this.extra[j][vectorIndex] &= mask;
356
		}
605
		}
357
		// use extra vector
358
		if (extraDefiniteNulls == null)
359
			return false; // if vector not yet allocated, then not initialized
360
		int vectorIndex;
361
		if ((vectorIndex = (position / BitCacheSize) - 1) >= extraDefiniteNulls.length)
362
			return false; // if not enough room in vector, then not initialized 
363
		return ((extraDefiniteNulls[vectorIndex]) & (1L << (position % BitCacheSize))) != 0;
364
	}
365
366
	/**
367
	 * Check status of definite assignment for a field.
368
	 */
369
	final public boolean isDefinitelyAssigned(FieldBinding field) {
370
		
371
		// Dependant of CodeStream.isDefinitelyAssigned(..)
372
		// We do not want to complain in unreachable code
373
		if ((this.reachMode & UNREACHABLE) != 0)  
374
			return true;
375
		return isDefinitelyAssigned(field.id); 
376
	}
606
	}
377
	
607
	for (int i = vectorIndex + 1; i < length; i++) {
378
	/**
608
		for (int j = 0; j < extraLength; j++) {
379
	 * Check status of definite assignment for a local.
609
			this.extra[j][i] = 0;
380
	 */
381
	final public boolean isDefinitelyAssigned(LocalVariableBinding local) {
382
		
383
		// Dependant of CodeStream.isDefinitelyAssigned(..)
384
		// We do not want to complain in unreachable code
385
		if ((this.reachMode & UNREACHABLE) != 0)
386
			return true;
387
388
		// final constants are inlined, and thus considered as always initialized
389
		if (local.constant() != Constant.NotAConstant) {
390
			return true;
391
		}
610
		}
392
		return isDefinitelyAssigned(local.id + maxFieldCount);
393
	}
611
	}
394
	
612
	return this;
395
	/**
613
}
396
	 * Check status of definite non-null assignment for a field.
614
397
	 */
615
public FlowInfo initsWhenFalse() {
398
	final public boolean isDefinitelyNonNull(FieldBinding field) {
616
	return this;
399
		
617
}
400
		// Dependant of CodeStream.isDefinitelyAssigned(..)
618
401
		// We do not want to complain in unreachable code
619
public FlowInfo initsWhenTrue() {
402
		if ((this.reachMode & UNREACHABLE) != 0)  
620
	return this;
403
			return false;
621
}
404
		return isDefinitelyNonNull(field.id); 
622
623
/**
624
 * Check status of definite assignment at a given position.
625
 * It deals with the dual representation of the InitializationInfo2:
626
 * bits for the first 64 entries, then an array of booleans.
627
 */
628
final private boolean isDefinitelyAssigned(int position) {
629
	if (position < BitCacheSize) {
630
		// use bits
631
		return (this.definiteInits & (1L << position)) != 0; 
632
	}
633
	// use extra vector
634
	if (this.extra == null)
635
		return false; // if vector not yet allocated, then not initialized
636
	int vectorIndex;
637
	if ((vectorIndex = (position / BitCacheSize) - 1) 
638
			>= this.extra[0].length) {
639
		return false; // if not enough room in vector, then not initialized
405
	}
640
	}
406
	
641
	return ((this.extra[0][vectorIndex]) & 
407
	/**
642
				(1L << (position % BitCacheSize))) != 0;
408
	 * Check status of definite non-null assignment for a local.
643
}
409
	 */
644
410
	final public boolean isDefinitelyNonNull(LocalVariableBinding local) {
645
final public boolean isDefinitelyAssigned(FieldBinding field) {
411
		
646
	// Mirrored in CodeStream.isDefinitelyAssigned(..) 
412
		// Dependant of CodeStream.isDefinitelyAssigned(..)
647
	// do not want to complain in unreachable code
413
		// We do not want to complain in unreachable code
648
	if ((this.tagBits & UNREACHABLE) != 0) { 
414
		if ((this.reachMode & UNREACHABLE) != 0)
649
		return true;
415
			return false;
416
		// final constants are inlined, and thus considered as always initialized
417
		if (local.constant() != Constant.NotAConstant) {
418
			return true;
419
		}
420
		return isDefinitelyNonNull(local.id + maxFieldCount);
421
	}
422
423
	/**
424
	 * Check status of definite null assignment for a field.
425
	 */
426
	final public boolean isDefinitelyNull(FieldBinding field) {
427
		
428
		// Dependant of CodeStream.isDefinitelyAssigned(..)
429
		// We do not want to complain in unreachable code
430
		if ((this.reachMode & UNREACHABLE) != 0)  
431
			return false;
432
		return isDefinitelyNull(field.id); 
433
	}
650
	}
434
	
651
	return isDefinitelyAssigned(field.id); 
435
	/**
652
}
436
	 * Check status of definite null assignment for a local.
653
437
	 */
654
final public boolean isDefinitelyAssigned(LocalVariableBinding local) {
438
	final public boolean isDefinitelyNull(LocalVariableBinding local) {
655
	// do not want to complain in unreachable code
439
		
656
	if ((this.tagBits & UNREACHABLE) != 0) {
440
		// Dependant of CodeStream.isDefinitelyAssigned(..)
657
		return true;
441
		// We do not want to complain in unreachable code
658
	}
442
		if ((this.reachMode & UNREACHABLE) != 0)
659
	// final constants are inlined, and thus considered as always initialized
443
			return false;
660
	if (local.constant() != Constant.NotAConstant) {
444
		return isDefinitelyNull(local.id + maxFieldCount);
661
		return true;
445
	}
662
	}
663
	return isDefinitelyAssigned(local.id + this.maxFieldCount);
664
}
665
666
final public boolean isDefinitelyNonNull(LocalVariableBinding local) {
667
	// do not want to complain in unreachable code
668
	if ((this.tagBits & UNREACHABLE) != 0 || 
669
			(this.tagBits & NULL_FLAG_MASK) == 0) {
670
		return false;
671
	}
672
	if ((local.type.tagBits & TagBits.IsBaseType) != 0 || 
673
			local.constant() != Constant.NotAConstant) { 
674
		// REVIEW only true if local is of a non object type, hence 
675
		// REVIEW		second test is useless?
676
		return true;
677
	}
678
	int position = local.id + this.maxFieldCount;
679
	long mask;
680
	if (position < BitCacheSize) { // use bits
681
		return 
682
			(this.nullAssignmentStatusBit2 & 
683
				(mask = 1L << position)) != 0 ?
684
			(this.nullAssignmentStatusBit1 & mask) != 0 :
685
			(this.nullAssignmentStatusBit1 & 
686
				this.nullAssignmentValueBit2 & mask) != 0 &&
687
			(this.nullAssignmentValueBit1 & mask) == 0; 
688
	}
689
	// use extra vector
690
	if (this.extra == null) {
691
		return false; // if vector not yet allocated, then not initialized
692
	}
693
	int vectorIndex;
694
	if ((vectorIndex = (position / BitCacheSize) - 1)  
695
			>= this.extra[0].length) {
696
		return false; // if not enough room in vector, then not initialized
697
	}
698
	return 
699
		(this.extra[3][vectorIndex] & 
700
			(mask = 1L << (position % BitCacheSize))) != 0 ?
701
		(this.extra[2][vectorIndex] & mask) != 0 :
702
		(this.extra[2][vectorIndex] & 
703
			this.extra[5][vectorIndex] & mask) != 0 &&
704
		(this.extra[4][vectorIndex] & mask) == 0;
705
}
446
706
447
	public boolean isReachable() {
707
final public boolean isDefinitelyNull(LocalVariableBinding local) {
448
		
708
	// do not want to complain in unreachable code
449
		return this.reachMode == REACHABLE;
709
	if ((this.tagBits & UNREACHABLE) != 0 || 
710
			(this.tagBits & NULL_FLAG_MASK) == 0 || 
711
			(local.type.tagBits & TagBits.IsBaseType) != 0) {
712
		return false;
713
	}
714
	int position = local.id + this.maxFieldCount;
715
	long mask;
716
	if (position < BitCacheSize) { // use bits
717
		return 
718
			(this.nullAssignmentStatusBit2 & (mask = 1L << position)) != 0 ?
719
			(this.nullAssignmentStatusBit1 & mask) == 0 :
720
			(this.nullAssignmentStatusBit1 & 
721
				this.nullAssignmentValueBit1 & mask) != 0 &&
722
			(this.nullAssignmentValueBit2 & mask) == 0; 
723
	}
724
	// use extra vector
725
	if (this.extra == null) {
726
		return false; // if vector not yet allocated, then not initialized
727
	}
728
	int vectorIndex;
729
	if ((vectorIndex = (position / BitCacheSize) - 1) >= 
730
			this.extra[0].length) {
731
		return false; // if not enough room in vector, then not initialized
732
	}
733
	return
734
		(this.extra[3][vectorIndex] & 
735
			(mask = 1L << (position % BitCacheSize))) != 0 ?
736
		(this.extra[2][vectorIndex] & mask) == 0 :
737
		(this.extra[2][vectorIndex] & 
738
			this.extra[4][vectorIndex] & mask) != 0 &&
739
		(this.extra[5][vectorIndex] & mask) == 0;
740
}
741
742
final public boolean isDefinitelyUnknown(LocalVariableBinding local) {
743
	// do not want to complain in unreachable code
744
	if ((this.tagBits & UNREACHABLE) != 0 || 
745
			(this.tagBits & NULL_FLAG_MASK) == 0) {
746
		return false;
747
	}
748
	int position = local.id + this.maxFieldCount;
749
	long mask;
750
	if (position < BitCacheSize) { // use bits
751
		return 
752
			(this.nullAssignmentStatusBit2 & (mask = 1L << position)) != 0 ?
753
			false :
754
			(this.nullAssignmentStatusBit1 & 
755
				this.nullAssignmentValueBit1 & 
756
				this.nullAssignmentValueBit2 & mask) != 0; 
757
	}
758
	// use extra vector
759
	if (this.extra == null) {
760
		return false; // if vector not yet allocated, then not initialized
761
	}
762
	int vectorIndex;
763
	if ((vectorIndex = (position / BitCacheSize) - 1) >= 
764
			this.extra[0].length) {
765
		return false; // if not enough room in vector, then not initialized
766
	}
767
	return
768
		(this.extra[3][vectorIndex] & 
769
			(mask = 1L << (position % BitCacheSize))) != 0 ?
770
		false :
771
		(this.extra[2][vectorIndex] & 
772
			this.extra[4][vectorIndex] &
773
			this.extra[5][vectorIndex] &
774
			mask) != 0;
775
}
776
777
/**
778
 * Check status of potential assignment at a given position.
779
 */
780
final private boolean isPotentiallyAssigned(int position) {
781
	// id is zero-based
782
	if (position < BitCacheSize) {
783
		// use bits
784
		return (this.potentialInits & (1L << position)) != 0;
785
	}
786
	// use extra vector
787
	if (this.extra == null) {
788
		return false; // if vector not yet allocated, then not initialized
789
	}
790
	int vectorIndex;
791
	if ((vectorIndex = (position / BitCacheSize) - 1) 
792
			>= this.extra[0].length) {
793
		return false; // if not enough room in vector, then not initialized
450
	}
794
	}
451
	
795
	return ((this.extra[1][vectorIndex]) & 
452
	/**
796
			(1L << (position % BitCacheSize))) != 0;
453
	 * Check status of potential assignment at a given position.
797
}
454
	 * It deals with the dual representation of the InitializationInfo3:
798
455
	 * bits for the first 64 entries, then an array of booleans.
799
/**
456
	 */
800
 * REVIEW wrong comment?
457
	final private boolean isPotentiallyAssigned(int position) {
801
 * Check status of definite assignment for a field.
458
		
802
 */
459
		// id is zero-based
803
final public boolean isPotentiallyAssigned(FieldBinding field) {
460
		if (position < BitCacheSize) {
804
	return isPotentiallyAssigned(field.id); 
805
}
806
807
/**
808
 * Check status of potential assignment for a local.
809
 */
810
final public boolean isPotentiallyAssigned(LocalVariableBinding local) {
811
	// final constants are inlined, and thus considered as always initialized
812
	if (local.constant() != Constant.NotAConstant) {
813
		return true;
814
	}
815
	return isPotentiallyAssigned(local.id + this.maxFieldCount);
816
}
817
818
// REVIEW should rename this -- what we do is that we ask if there is a reasonable
819
// REVIEW	expectation that the variable be null at this point; which means that
820
// REVIEW	we add the protected null case, to augment diagnostics, but we do not
821
// REVIEW	really check that someone deliberately has assigned to null on a given 
822
// REVIEW	path
823
final public boolean isPotentiallyNull(LocalVariableBinding local) {
824
	if ((this.tagBits & NULL_FLAG_MASK) == 0 || 
825
			(local.type.tagBits & TagBits.IsBaseType) != 0) {
826
		return false;
827
	}
828
	int position;
829
	long mask;
830
	if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
831
		// use bits
832
		return
833
			(this.nullAssignmentStatusBit2 & (mask = 1L << position)) != 0 ?
834
			(this.nullAssignmentStatusBit1 & mask) == 0 : // protected null
835
			(this.nullAssignmentValueBit1 & mask) != 0 && // null bit set and
836
				((this.nullAssignmentStatusBit1 & mask) == 0 || // (potential or
837
				 (this.nullAssignmentValueBit2 & mask) == 0); 
838
											// assigned, but not unknown)
839
	}
840
	// use extra vector
841
	if (this.extra == null) {
842
		return false; // if vector not yet allocated, then not initialized
843
	}
844
	int vectorIndex;
845
	if ((vectorIndex = (position / BitCacheSize) - 1) >= 
846
			this.extra[0].length) {
847
		return false; // if not enough room in vector, then not initialized
848
	}
849
	return 
850
		(this.extra[3][vectorIndex] & 
851
			(mask = 1L << (position % BitCacheSize))) != 0 ?
852
		(this.extra[2][vectorIndex] & mask) == 0 :
853
		(this.extra[4][vectorIndex] & mask) != 0 && 
854
			((this.extra[2][vectorIndex] & mask) == 0 || 
855
			 (this.extra[5][vectorIndex] & mask) == 0); 
856
}
857
858
final public boolean isPotentiallyUnknown(LocalVariableBinding local) {
859
	// do not want to complain in unreachable code
860
	if ((this.tagBits & UNREACHABLE) != 0 || 
861
			(this.tagBits & NULL_FLAG_MASK) == 0) {
862
		return false;
863
	}
864
	int position = local.id + this.maxFieldCount;
865
	long mask;
866
	if (position < BitCacheSize) { // use bits
867
		return 
868
			(this.nullAssignmentStatusBit2 & (mask = 1L << position)) != 0 ?
869
			false :
870
			((this.nullAssignmentStatusBit1 & 
871
				this.nullAssignmentValueBit1 |
872
			 ~this.nullAssignmentStatusBit1 &
873
				~this.nullAssignmentValueBit1) & 
874
				this.nullAssignmentValueBit2 & mask) != 0; 
875
	}
876
	// use extra vector
877
	if (this.extra == null) {
878
		return false; // if vector not yet allocated, then not initialized
879
	}
880
	int vectorIndex;
881
	if ((vectorIndex = (position / BitCacheSize) - 1) >= 
882
			this.extra[0].length) {
883
		return false; // if not enough room in vector, then not initialized
884
	}
885
	return
886
		(this.extra[3][vectorIndex] & 
887
			(mask = 1L << (position % BitCacheSize))) != 0 ?
888
		false :
889
		((this.extra[2][vectorIndex] & 
890
			this.extra[4][vectorIndex] |
891
		  ~this.extra[2][vectorIndex] &
892
			~this.extra[4][vectorIndex]) &
893
			this.extra[5][vectorIndex] &
894
			mask) != 0;
895
}
896
897
final public boolean isProtectedNonNull(LocalVariableBinding local) {
898
	if ((this.tagBits & NULL_FLAG_MASK) == 0 ||
899
			(local.type.tagBits & TagBits.IsBaseType) != 0) {
900
		return false;
901
	}
902
	int position;
903
	if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
904
		// use bits
905
		return (this.nullAssignmentStatusBit1 &
906
				this.nullAssignmentStatusBit2 & (1L << position)) != 0;
907
	}
908
	// use extra vector
909
	if (this.extra == null) {
910
		return false; // if vector not yet allocated, then not initialized
911
	}
912
	int vectorIndex;
913
	if ((vectorIndex = (position / BitCacheSize) - 1) >= 
914
		this.extra[0].length) {
915
		return false; // if not enough room in vector, then not initialized
916
	}
917
	return (this.extra[4][vectorIndex] & 
918
			this.extra[5][vectorIndex] & 
919
			(1L << (position % BitCacheSize))) != 0;
920
}
921
922
final public boolean isProtectedNull(LocalVariableBinding local) {
923
	if ((this.tagBits & NULL_FLAG_MASK) == 0 || 
924
			(local.type.tagBits & TagBits.IsBaseType) != 0) {
925
		return false;
926
	}
927
	int position;
928
	if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
929
		// use bits
930
		return (~this.nullAssignmentStatusBit1 &
931
				this.nullAssignmentStatusBit2 & (1L << position)) != 0;
932
	}
933
	// use extra vector
934
	if (this.extra == null) {
935
		return false; // if vector not yet allocated, then not initialized
936
	}
937
	int vectorIndex;
938
	if ((vectorIndex = (position / BitCacheSize) - 1) >= 
939
			this.extra[0].length) {
940
		return false; // if not enough room in vector, then not initialized
941
	}
942
	return (~this.extra[4][vectorIndex] & 
943
			this.extra[5][vectorIndex] &
944
			(1L << (position % BitCacheSize))) != 0;
945
}
946
947
public void markAsComparedEqualToNonNull(LocalVariableBinding local) {
948
	// protected from non-object locals in calling methods
949
	if (this != DEAD_END) {
950
		this.tagBits |= NULL_FLAG_MASK;
951
		int position;
952
		long mask;
953
		// position is zero-based
954
		if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
461
			// use bits
955
			// use bits
462
			return (potentialInits & (1L << position)) != 0;
956
			if (((mask = 1L << position) & // leave assigned non null unchanged 
957
					this.nullAssignmentStatusBit1 &
958
					~this.nullAssignmentStatusBit2 &
959
					~this.nullAssignmentValueBit1 &
960
					this.nullAssignmentValueBit2) == 0) {
961
				// set protected non null
962
				this.nullAssignmentStatusBit1 |= mask;
963
				this.nullAssignmentStatusBit2 |= mask;
964
				 // clear potential null
965
				this.nullAssignmentValueBit1 &= ~mask;
966
				if (coverageTestFlag && coverageTestId == 19) {
967
					this.nullAssignmentValueBit2 = ~0;
968
				}
969
			}
970
			if (coverageTestFlag && coverageTestId == 20) {
971
				this.nullAssignmentValueBit2 = ~0;
972
			}
973
		} 
974
		else {
975
			// use extra vector
976
			int vectorIndex = (position / BitCacheSize) - 1;
977
			if (this.extra == null) {
978
				int length = vectorIndex + 1;
979
				this.extra = new long[extraLength][];
980
				for (int j = 0; j < extraLength; j++) {
981
					this.extra[j] = new long[length];
982
				}
983
				if (coverageTestFlag && coverageTestId == 21) {
984
					throw new AssertionFailedException("COVERAGE 21"); //$NON-NLS-1$
985
				}
986
			}
987
			else {
988
				int oldLength;
989
				if (vectorIndex >= (oldLength = this.extra[0].length)) {
990
					int newLength = vectorIndex + 1;
991
					for (int j = 0; j < extraLength; j++) {
992
						System.arraycopy(this.extra[j], 0, 
993
							(this.extra[j] = new long[newLength]), 0, 
994
							oldLength);
995
					}
996
					if (coverageTestFlag && coverageTestId == 22) {
997
						throw new AssertionFailedException("COVERAGE 22"); //$NON-NLS-1$
998
					}
999
				}
1000
			}
1001
			if (((mask = 1L << (position % BitCacheSize)) & 
1002
					this.extra[2][vectorIndex] &
1003
					~this.extra[3][vectorIndex] &
1004
					~this.extra[4][vectorIndex] &
1005
					this.extra[5][vectorIndex]) == 0) {
1006
				this.extra[2][vectorIndex] |= mask;
1007
				this.extra[3][vectorIndex] |= mask;
1008
				this.extra[4][vectorIndex] &= ~mask;
1009
				if (coverageTestFlag && coverageTestId == 23) {
1010
					this.extra[5][vectorIndex] = ~0;
1011
				}
1012
			}
463
		}
1013
		}
464
		// use extra vector
465
		if (extraPotentialInits == null)
466
			return false; // if vector not yet allocated, then not initialized
467
		int vectorIndex;
468
		if ((vectorIndex = (position / BitCacheSize) - 1) >= extraPotentialInits.length)
469
			return false; // if not enough room in vector, then not initialized 
470
		return ((extraPotentialInits[vectorIndex]) & (1L << (position % BitCacheSize))) != 0;
471
	}
1014
	}
472
	
1015
}
473
	/**
1016
474
	 * Check status of definite assignment for a field.
1017
// REVIEW javadoc policy?
475
	 */
1018
public void markAsComparedEqualToNull(LocalVariableBinding local) {
476
	final public boolean isPotentiallyAssigned(FieldBinding field) {
1019
	// protected from non-object locals in calling methods
477
		
1020
	if (this != DEAD_END) {
478
		return isPotentiallyAssigned(field.id); 
1021
		this.tagBits |= NULL_FLAG_MASK;
479
	}
1022
		int position;
480
	
1023
		long mask, unknownAssigned;
481
	/**
1024
		// position is zero-based
482
	 * Check status of potential assignment for a local.
1025
		if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
483
	 */
1026
			// use bits
484
	final public boolean isPotentiallyAssigned(LocalVariableBinding local) {
1027
			mask = 1L << position;
485
		
1028
			if ((mask & // leave assigned null unchanged
486
		// final constants are inlined, and thus considered as always initialized
1029
					this.nullAssignmentStatusBit1 &
487
		if (local.constant() != Constant.NotAConstant) {
1030
					~this.nullAssignmentStatusBit2 &
488
			return true;
1031
					this.nullAssignmentValueBit1 &
1032
					~this.nullAssignmentValueBit2) == 0) {
1033
				unknownAssigned = this.nullAssignmentStatusBit1 &
1034
					~this.nullAssignmentStatusBit2 &
1035
					this.nullAssignmentValueBit1 &
1036
					this.nullAssignmentValueBit2;
1037
				// set protected
1038
				this.nullAssignmentStatusBit2 |= mask;
1039
				this.nullAssignmentStatusBit1 &= (mask = ~mask);
1040
				// protected is null
1041
				this.nullAssignmentValueBit1 &= mask | ~unknownAssigned;
1042
				this.nullAssignmentValueBit2 &= mask;
1043
				// clear potential anything but null
1044
				// REVIEW coûts relatifs d'un assignment et d'une négation?
1045
				if (coverageTestFlag && coverageTestId == 24) {
1046
					this.nullAssignmentValueBit2 = ~0;
1047
				}
1048
			}
1049
			if (coverageTestFlag && coverageTestId == 25) {
1050
				this.nullAssignmentValueBit2 = ~0;
1051
			}
1052
		} 
1053
		else {
1054
			// use extra vector
1055
			int vectorIndex = (position / BitCacheSize) - 1;
1056
			mask = 1L << (position % BitCacheSize);
1057
			if (this.extra == null) {
1058
				int length = vectorIndex + 1;
1059
				this.extra = new long[extraLength][];
1060
				for (int j = 0; j < extraLength; j++) {
1061
					this.extra[j] = new long[length ];
1062
				}
1063
				if (coverageTestFlag && coverageTestId == 26) {
1064
					throw new AssertionFailedException("COVERAGE 26"); //$NON-NLS-1$
1065
				}
1066
			}
1067
			else {
1068
				int oldLength;
1069
				if (vectorIndex >= (oldLength = this.extra[0].length)) {
1070
					int newLength = vectorIndex + 1;
1071
					for (int j = 0; j < extraLength; j++) {
1072
						System.arraycopy(this.extra[j], 0, 
1073
							(this.extra[j] = new long[newLength]), 0,
1074
							oldLength);
1075
					}
1076
					if (coverageTestFlag && coverageTestId == 27) {
1077
						throw new AssertionFailedException("COVERAGE 27"); //$NON-NLS-1$
1078
					}
1079
				}
1080
			}
1081
			if ((mask &
1082
					this.extra[2][vectorIndex] &
1083
					~this.extra[3][vectorIndex] &
1084
					this.extra[4][vectorIndex] &
1085
					~this.extra[5][vectorIndex]) == 0) {
1086
				unknownAssigned = this.extra[2][vectorIndex] &
1087
					~this.extra[3][vectorIndex] &
1088
					this.extra[4][vectorIndex] &
1089
					this.extra[5][vectorIndex];
1090
				this.extra[3][vectorIndex]	 |= mask;
1091
				this.extra[2][vectorIndex] &= (mask = ~mask);
1092
				this.extra[4][vectorIndex] &= mask | ~unknownAssigned;
1093
				this.extra[5][vectorIndex]	&= mask;
1094
				if (coverageTestFlag && coverageTestId == 28) {
1095
					this.extra[5][vectorIndex] = ~0;
1096
				}
1097
			}
489
		}
1098
		}
490
		return isPotentiallyAssigned(local.id + maxFieldCount);
491
	}
1099
	}
1100
}
1101
1102
/**
1103
 * Record a definite assignment at a given position.
1104
 * REVIEW wrong comment?
1105
 * It deals with the dual representation of the InitializationInfo2:
1106
 * bits for the first 64 entries, then an array of booleans.
1107
 */
1108
final private void markAsDefinitelyAssigned(int position) {
492
	
1109
	
493
	/**
1110
	if (this != DEAD_END) {
494
	 * Record a definite assignment at a given position.
1111
		// position is zero-based
495
	 * It deals with the dual representation of the InitializationInfo2:
1112
		if (position < BitCacheSize) {
496
	 * bits for the first 64 entries, then an array of booleans.
1113
			// use bits
497
	 */
1114
			long mask;
498
	final private void markAsDefinitelyAssigned(int position) {
1115
			this.definiteInits |= (mask = 1L << position);
499
		
1116
			this.potentialInits |= mask;
500
		if (this != DEAD_END) {
1117
		} 
501
	
1118
		else {
502
			// position is zero-based
1119
			// use extra vector
503
			if (position < BitCacheSize) {
1120
			int vectorIndex = (position / BitCacheSize) - 1;
504
				// use bits
1121
			if (this.extra == null) {
505
				long mask;
1122
				int length = vectorIndex + 1;
506
				definiteInits |= (mask = 1L << position);
1123
				this.extra = new long[extraLength][];
507
				potentialInits |= mask;
1124
				for (int j = 0; j < extraLength; j++) {
508
				definiteNulls &= ~mask;
1125
					this.extra[j] = new long[length];
509
				definiteNonNulls &= ~mask;
1126
				}
510
			} else {
1127
			} 
511
				// use extra vector
1128
			else {
512
				int vectorIndex = (position / BitCacheSize) - 1;
1129
				int oldLength; // might need to grow the arrays
513
				if (extraDefiniteInits == null) {
1130
				if (vectorIndex >= (oldLength = this.extra[0].length)) {
514
					int length;
1131
					for (int j = 0; j < extraLength; j++) {
515
					extraDefiniteInits = new long[length = vectorIndex + 1];
1132
						System.arraycopy(this.extra[j], 0, 
516
					extraPotentialInits = new long[length];
1133
							(this.extra[j] = new long[vectorIndex + 1]), 0, 
517
					extraDefiniteNulls = new long[length];
1134
							oldLength);
518
					extraDefiniteNonNulls = new long[length];
519
				} else {
520
					int oldLength; // might need to grow the arrays
521
					if (vectorIndex >= (oldLength = extraDefiniteInits.length)) {
522
						System.arraycopy(extraDefiniteInits, 0, (extraDefiniteInits = new long[vectorIndex + 1]), 0, oldLength);
523
						System.arraycopy(extraPotentialInits, 0, (extraPotentialInits = new long[vectorIndex + 1]), 0, oldLength);
524
						System.arraycopy(extraDefiniteNulls, 0, (extraDefiniteNulls = new long[vectorIndex + 1]), 0, oldLength);
525
						System.arraycopy(extraDefiniteNonNulls, 0, (extraDefiniteNonNulls = new long[vectorIndex + 1]), 0, oldLength);
526
					}
1135
					}
527
				}
1136
				}
528
				long mask;
529
				extraDefiniteInits[vectorIndex] |= (mask = 1L << (position % BitCacheSize));
530
				extraPotentialInits[vectorIndex] |= mask;
531
				extraDefiniteNulls[vectorIndex] &= ~mask;
532
				extraDefiniteNonNulls[vectorIndex] &= ~mask;
533
			}
1137
			}
1138
			long mask;
1139
			this.extra[0][vectorIndex] |= 
1140
				(mask = 1L << (position % BitCacheSize));
1141
			this.extra[1][vectorIndex] |= mask;
534
		}
1142
		}
535
	}
1143
	}
536
	
1144
}
537
	/**
1145
538
	 * Record a field got definitely assigned.
1146
public void markAsDefinitelyAssigned(FieldBinding field) {
539
	 */
1147
	if (this != DEAD_END)
540
	public void markAsDefinitelyAssigned(FieldBinding field) {
1148
		markAsDefinitelyAssigned(field.id);
541
		if (this != DEAD_END)
1149
}
542
			markAsDefinitelyAssigned(field.id);
1150
543
	}
1151
public void markAsDefinitelyAssigned(LocalVariableBinding local) {
544
	
1152
	if (this != DEAD_END)
545
	/**
1153
		markAsDefinitelyAssigned(local.id + this.maxFieldCount);
546
	 * Record a local got definitely assigned.
1154
}
547
	 */
1155
548
	public void markAsDefinitelyAssigned(LocalVariableBinding local) {
1156
/**
549
		if (this != DEAD_END)
1157
 * Record a definite non-null assignment at a given position.
550
			markAsDefinitelyAssigned(local.id + maxFieldCount);
1158
 */
551
	}
1159
final private void markAsDefinitelyNonNull(int position) {
552
1160
	// DEAD_END guarded above
553
	/**
1161
	this.tagBits |= NULL_FLAG_MASK;
554
	 * Record a definite non-null assignment at a given position.
1162
	long mask;
555
	 * It deals with the dual representation of the InitializationInfo2:
1163
	// position is zero-based
556
	 * bits for the first 64 entries, then an array of booleans.
1164
	if (position < BitCacheSize) {
557
	 */
1165
		// use bits
558
	final private void markAsDefinitelyNonNull(int position) {
1166
		this.nullAssignmentStatusBit1 |= (mask = 1L << position);
559
		
1167
		this.nullAssignmentValueBit2 |= mask; // set non null
560
		if (this != DEAD_END) {
1168
		this.nullAssignmentStatusBit2 &= ~mask; // clear protection
561
	
1169
		this.nullAssignmentValueBit1 &= ~mask; // clear null
562
			// position is zero-based
1170
		if (coverageTestFlag && coverageTestId == 29) {
563
			if (position < BitCacheSize) {
1171
			this.nullAssignmentStatusBit1 = 0;
564
				// use bits
1172
		}
565
				long mask;
1173
	} 
566
				definiteNonNulls |= (mask = 1L << position);
1174
	else {
567
				definiteNulls &= ~mask;
1175
		// use extra vector
568
			} else {
1176
		int vectorIndex = (position / BitCacheSize) - 1;
569
				// use extra vector
1177
		// REVIEW seems to be guarded
570
				int vectorIndex = (position / BitCacheSize) - 1;
1178
		this.extra[2][vectorIndex] |= 
571
				long mask;
1179
			(mask = 1L << (position % BitCacheSize));
572
				extraDefiniteNonNulls[vectorIndex] |= (mask = 1L << (position % BitCacheSize));
1180
		this.extra[5][vectorIndex] |= mask;
573
				extraDefiniteNulls[vectorIndex] &= ~mask;
1181
		this.extra[3][vectorIndex] &= ~mask;
574
			}
1182
		this.extra[4][vectorIndex] &= ~mask;
1183
		if (coverageTestFlag && coverageTestId == 30) {
1184
			this.extra[5][vectorIndex] = ~0;
575
		}
1185
		}
576
	}
1186
	}
1187
}
577
1188
578
	/**
1189
public void markAsDefinitelyNonNull(FieldBinding field) {
579
	 * Record a field got definitely assigned to non-null value.
1190
	if (this != DEAD_END) {
580
	 */
1191
		markAsDefinitelyNonNull(field.id);
581
	public void markAsDefinitelyNonNull(FieldBinding field) {
582
		if (this != DEAD_END)
583
			markAsDefinitelyNonNull(field.id);
584
	}
1192
	}
585
	
1193
}
586
	/**
1194
587
	 * Record a local got definitely assigned to non-null value.
1195
public void markAsDefinitelyNonNull(LocalVariableBinding local) {
588
	 */
1196
	// protected from non-object locals in calling methods
589
	public void markAsDefinitelyNonNull(LocalVariableBinding local) {
1197
	if (this != DEAD_END) {
590
		if (this != DEAD_END)
1198
		markAsDefinitelyNonNull(local.id + this.maxFieldCount);
591
			markAsDefinitelyNonNull(local.id + maxFieldCount);
1199
	}
592
	}
1200
}
593
1201
594
	/**
1202
/**
595
	 * Record a definite null assignment at a given position.
1203
 * Record a definite null assignment at a given position.
596
	 * It deals with the dual representation of the InitializationInfo2:
1204
 */
597
	 * bits for the first 64 entries, then an array of booleans.
1205
final private void markAsDefinitelyNull(int position) {
598
	 */
1206
	// DEAD_END guarded above
599
	final private void markAsDefinitelyNull(int position) {
1207
	this.tagBits |= NULL_FLAG_MASK;
600
		
1208
	long mask;
601
		if (this != DEAD_END) {
1209
	if (position < BitCacheSize) {
602
	
1210
		// use bits
603
			// position is zero-based
1211
		this.nullAssignmentStatusBit1 |= (mask = 1L << position); // set assignment
604
			if (position < BitCacheSize) {
1212
		this.nullAssignmentStatusBit2 &= ~mask; // clear protection
605
				// use bits
1213
		this.nullAssignmentValueBit1 |= mask; // set null
606
				long mask;
1214
		this.nullAssignmentValueBit2 &= ~mask; // clear non null
607
				definiteNulls |= (mask = 1L << position);
1215
		if (coverageTestFlag && coverageTestId == 31) {
608
				definiteNonNulls &= ~mask;
1216
			this.nullAssignmentValueBit2 = ~0;
609
			} else {
1217
		}
610
				// use extra vector
1218
	} 
611
				int vectorIndex = (position / BitCacheSize) - 1;
1219
	else {
612
				long mask;
1220
		// use extra vector
613
				extraDefiniteNulls[vectorIndex] |= (mask = 1L << (position % BitCacheSize));
1221
		int vectorIndex = (position / BitCacheSize) - 1;
614
				extraDefiniteNonNulls[vectorIndex] &= ~mask;
1222
		// REVIEW seems to be guarded
615
			}
1223
		this.extra[2][vectorIndex] |= 
1224
			(mask = 1L << (position % BitCacheSize));
1225
		this.extra[3][vectorIndex] &= ~mask;
1226
		this.extra[4][vectorIndex] |= mask;
1227
		this.extra[5][vectorIndex] &= ~mask;
1228
		if (coverageTestFlag && coverageTestId == 32) {
1229
			this.extra[5][vectorIndex] = ~0;
616
		}
1230
		}
617
	}
1231
	}
1232
}
618
1233
619
	/**
1234
public void markAsDefinitelyNull(FieldBinding field) {
620
	 * Record a field got definitely assigned to null.
1235
	if (this != DEAD_END) {
621
	 */
1236
		markAsDefinitelyNull(field.id);
622
	public void markAsDefinitelyNull(FieldBinding field) {
623
		if (this != DEAD_END)
624
			markAsDefinitelyAssigned(field.id);
625
	}
1237
	}
626
	
1238
}
627
	/**
1239
628
	 * Record a local got definitely assigned to null.
1240
public void markAsDefinitelyNull(LocalVariableBinding local) {
629
	 */
1241
	// protected from non-object locals in calling methods
630
	public void markAsDefinitelyNull(LocalVariableBinding local) {
1242
	if (this != DEAD_END) {
631
		if (this != DEAD_END)
1243
		markAsDefinitelyNull(local.id + this.maxFieldCount);
632
			markAsDefinitelyNull(local.id + maxFieldCount);
633
	}
1244
	}
634
	
1245
}
635
	/**
1246
636
	 * Clear initialization information at a given position.
1247
/**
637
	 * It deals with the dual representation of the InitializationInfo2:
1248
 * Mark a local as having been assigned to an unknown value.
638
	 * bits for the first 64 entries, then an array of booleans.
1249
 * @param local the local to mark
639
	 */
1250
 */
640
	final private void markAsDefinitelyNotAssigned(int position) {
1251
// PREMATURE may try to get closer to markAsDefinitelyAssigned, but not
641
		if (this != DEAD_END) {
1252
//			 obvious
642
	
1253
public void markAsDefinitelyUnknown(LocalVariableBinding local) {
643
			// position is zero-based
1254
	// protected from non-object locals in calling methods
644
			if (position < BitCacheSize) {
1255
	if (this != DEAD_END) {
645
				// use bits
1256
		this.tagBits |= NULL_FLAG_MASK;
646
				long mask;
1257
		long mask;
647
				definiteInits &= ~(mask = 1L << position);
1258
		int position;
648
				potentialInits &= ~mask;
1259
		// position is zero-based
649
				definiteNulls &= ~mask;
1260
		if ((position = local.id + this.maxFieldCount) < BitCacheSize) {
650
				definiteNonNulls &= ~mask;
1261
			// use bits
651
			} else {
1262
			this.nullAssignmentValueBit1 |= (mask = 1L << position);
652
				// use extra vector
1263
			this.nullAssignmentValueBit2 |= mask;
653
				int vectorIndex = (position / BitCacheSize) - 1;
1264
			// set unknown
654
				if (extraDefiniteInits == null) {
1265
			this.nullAssignmentStatusBit1 |= mask;
655
					return; // nothing to do, it was not yet set 
1266
			// set assignment
656
				}
1267
			this.nullAssignmentStatusBit2 &= ~mask;
657
				// might need to grow the arrays
1268
			// clear protection
658
				if (vectorIndex >= extraDefiniteInits.length) {
1269
			if (coverageTestFlag && coverageTestId == 33) {
659
					return; // nothing to do, it was not yet set 
1270
				this.nullAssignmentValueBit2 = ~0;
660
				}
1271
			}
661
				long mask;
1272
		} 
662
				extraDefiniteInits[vectorIndex] &= ~(mask = 1L << (position % BitCacheSize));
1273
		else {
663
				extraPotentialInits[vectorIndex] &= ~mask;
1274
			// use extra vector
664
				extraDefiniteNulls[vectorIndex] &= ~mask;
1275
			int vectorIndex = (position / BitCacheSize) - 1;
665
				extraDefiniteNonNulls[vectorIndex] &= ~mask;
1276
			// REVIEW seems to be guarded
1277
			this.extra[4][vectorIndex] |=
1278
				(mask = 1L << (position % BitCacheSize));
1279
			this.extra[5][vectorIndex] |= mask;
1280
			this.extra[2][vectorIndex] |= mask;
1281
			this.extra[3][vectorIndex] &= ~mask;
1282
			if (coverageTestFlag && coverageTestId == 34) {
1283
				this.extra[5][vectorIndex] = ~0;
666
			}
1284
			}
667
		}
1285
		}
668
	}
1286
	}
669
	
1287
}
670
	/**
1288
671
	 * Clear the initialization info for a field
1289
public UnconditionalFlowInfo mergedWith(UnconditionalFlowInfo otherInits) {
672
	 */
1290
	if ((otherInits.tagBits & UNREACHABLE) != 0 && this != DEAD_END) {
673
	public void markAsDefinitelyNotAssigned(FieldBinding field) {
1291
		if (coverageTestFlag && coverageTestId == 35) {
674
		
1292
			throw new AssertionFailedException("COVERAGE 35"); //$NON-NLS-1$
675
		if (this != DEAD_END)
676
			markAsDefinitelyNotAssigned(field.id);
677
	}
678
	
679
	/**
680
	 * Clear the initialization info for a local variable
681
	 */
682
	
683
	public void markAsDefinitelyNotAssigned(LocalVariableBinding local) {
684
		
685
		if (this != DEAD_END)
686
			markAsDefinitelyNotAssigned(local.id + maxFieldCount);
687
	}
688
		
689
	/**
690
	 * Returns the receiver updated in the following way: <ul>
691
	 * <li> intersection of definitely assigned variables, 
692
	 * <li> union of potentially assigned variables.
693
	 * </ul>
694
	 */
695
	public UnconditionalFlowInfo mergedWith(UnconditionalFlowInfo otherInits) {
696
	
697
		if (this == DEAD_END) return otherInits;
698
		if (otherInits == DEAD_END) return this;
699
	
700
		if ((this.reachMode & UNREACHABLE) != (otherInits.reachMode & UNREACHABLE)){
701
			if ((this.reachMode & UNREACHABLE) != 0){
702
				return otherInits;
703
			} 
704
			return this;
705
		}
1293
		}
706
		
1294
		// DEAD_END + unreachable other -> other
707
		// if one branch is not fake reachable, then the merged one is reachable
1295
		return this;
708
		this.reachMode &= otherInits.reachMode;
1296
	}
709
	
1297
	if ((this.tagBits & UNREACHABLE) != 0) {
710
		// intersection of definitely assigned variables, 
1298
		if (coverageTestFlag && coverageTestId == 36) {
711
		this.definiteInits &= otherInits.definiteInits;
1299
			throw new AssertionFailedException("COVERAGE 36"); //$NON-NLS-1$
712
		// union of potentially set ones
1300
		}
713
		this.potentialInits |= otherInits.potentialInits;
1301
		return (UnconditionalFlowInfo) otherInits.copy(); // make sure otherInits won't be affected
714
		// intersection of definitely null variables, 
1302
	} 
715
		this.definiteNulls &= otherInits.definiteNulls;
1303
	
716
		// intersection of definitely non-null variables, 
1304
	// intersection of definitely assigned variables, 
717
		this.definiteNonNulls &= otherInits.definiteNonNulls;
1305
	this.definiteInits &= otherInits.definiteInits;
718
	
1306
	// union of potentially set ones
719
		// treating extra storage
1307
	this.potentialInits |= otherInits.potentialInits;
720
		if (this.extraDefiniteInits != null) {
1308
721
			if (otherInits.extraDefiniteInits != null) {
1309
	// null combinations
1310
	boolean otherHasNulls = (otherInits.tagBits & NULL_FLAG_MASK) != 0,
1311
		thisHasNulls = false;
1312
	long a1, a2, na2, a3, na3, a4, na4, b1, nb1, b2, nb2, b3, nb3, b4, nb4;
1313
	if (otherHasNulls) {
1314
		this.nullAssignmentStatusBit1 =
1315
			(a1 = this.nullAssignmentStatusBit1) & 
1316
			(b1 = otherInits.nullAssignmentStatusBit1) & (
1317
				(nb4 = ~(b4 = otherInits.nullAssignmentValueBit2)) & 
1318
				((b2 = otherInits.nullAssignmentStatusBit2) & 
1319
						(nb3 = ~(b3 = otherInits.nullAssignmentValueBit1)) & 
1320
						(na3 = ~(a3 = this.nullAssignmentValueBit1)) & 
1321
						((a2 = this.nullAssignmentStatusBit2) & 
1322
							(na4 = ~(a4 = this.nullAssignmentValueBit2)) | a4) |
1323
						(na2 = ~a2) & a3 & na4 & (nb2 = ~b2) & b3 ) |
1324
				b4 & (na3 & nb3 & (na4 & a2 | a4) |
1325
						na2 & a4 & nb2));
1326
		this.nullAssignmentStatusBit2 =
1327
			a2 & b2 & ~(a1 ^ b1) & (na3 & nb3 | na4 & nb4) |
1328
			a1 & b1 & (a2 ^ b2) & na3 & nb3 |
1329
			(a1 & na2 & (nb1 = ~b1) & b2 | ~a1 & a2 & b1 & nb2) & na4 & nb4;
1330
		this.nullAssignmentValueBit1 =
1331
			b1 & nb2 & nb4 |
1332
			~a1 & (a3 |
1333
					a2 & na3 & (b1 | nb2)) |
1334
			(a1 | na2) & nb1 & b2 & nb3 |
1335
			nb1 & b3 |
1336
			a1 & na2 & (na4 |
1337
						b1 & nb2 & (a3 | b3));
1338
		this.nullAssignmentValueBit2 =
1339
			a4 | b4;
1340
		if (coverageTestFlag && coverageTestId == 37) {
1341
			this.nullAssignmentValueBit2 = ~0;
1342
		}
1343
	}
1344
	else {
1345
		// tune potentials
1346
		this.nullAssignmentValueBit1 =
1347
			~(~this.nullAssignmentStatusBit1 &
1348
					~this.nullAssignmentStatusBit2 &
1349
					~this.nullAssignmentValueBit1) &
1350
			~(this.nullAssignmentStatusBit1 & 
1351
					(this.nullAssignmentStatusBit2 | this.nullAssignmentValueBit2));
1352
		// reset assignment and protected
1353
		this.nullAssignmentStatusBit1 = 
1354
		this.nullAssignmentStatusBit2 = 0;
1355
		if (coverageTestFlag && coverageTestId == 38) {
1356
			this.nullAssignmentValueBit2 = ~0;
1357
		}
1358
	}
1359
	thisHasNulls = this.nullAssignmentStatusBit1 != 0 || 
1360
		this.nullAssignmentStatusBit2 != 0 ||
1361
		this.nullAssignmentValueBit1 != 0 ||
1362
		this.nullAssignmentValueBit2 != 0;
1363
1364
	// treating extra storage
1365
	if (this.extra != null || otherInits.extra != null) {
1366
		int mergeLimit = 0, copyLimit = 0, resetLimit = 0;
1367
		if (this.extra != null) {
1368
			if (otherInits.extra != null) {
722
				// both sides have extra storage
1369
				// both sides have extra storage
723
				int i = 0, length, otherLength;
1370
				int length, otherLength;
724
				if ((length = this.extraDefiniteInits.length) < (otherLength = otherInits.extraDefiniteInits.length)) {
1371
				if ((length = this.extra[0].length) < 
725
					// current storage is shorter -> grow current (could maybe reuse otherInits extra storage?)
1372
						(otherLength = otherInits.extra[0].length)) {
726
					System.arraycopy(this.extraDefiniteInits, 0, (this.extraDefiniteInits = new long[otherLength]), 0, length);
1373
					// current storage is shorter -> grow current 
727
					System.arraycopy(this.extraPotentialInits, 0, (this.extraPotentialInits = new long[otherLength]), 0, length);
1374
					for (int j = 0; j < extraLength; j++) {
728
					System.arraycopy(this.extraDefiniteNulls, 0, (this.extraDefiniteNulls = new long[otherLength]), 0, length);
1375
						System.arraycopy(this.extra[j], 0, 
729
					System.arraycopy(this.extraDefiniteNonNulls, 0, (this.extraDefiniteNonNulls = new long[otherLength]), 0, length);
1376
							(this.extra[j] = new long[otherLength]), 0, length);
730
					while (i < length) {
731
						this.extraDefiniteInits[i] &= otherInits.extraDefiniteInits[i];
732
						this.extraPotentialInits[i] |= otherInits.extraPotentialInits[i];
733
						this.extraDefiniteNulls[i] &= otherInits.extraDefiniteNulls[i];
734
						this.extraDefiniteNonNulls[i] &= otherInits.extraDefiniteNonNulls[i++];
735
					}
1377
					}
736
					while (i < otherLength) {
1378
					mergeLimit = length;
737
						this.extraPotentialInits[i] = otherInits.extraPotentialInits[i++];
1379
					copyLimit = otherLength;
1380
					if (coverageTestFlag && coverageTestId == 39) {
1381
						throw new AssertionFailedException("COVERAGE 39"); //$NON-NLS-1$
738
					}
1382
					}
739
				} else {
1383
				} 
1384
				else {
740
					// current storage is longer
1385
					// current storage is longer
741
					while (i < otherLength) {
1386
					mergeLimit = otherLength;
742
						this.extraDefiniteInits[i] &= otherInits.extraDefiniteInits[i];
1387
					resetLimit = length;
743
						this.extraPotentialInits[i] |= otherInits.extraPotentialInits[i];
1388
					if (coverageTestFlag && coverageTestId == 40) {
744
						this.extraDefiniteNulls[i] &= otherInits.extraDefiniteNulls[i];
1389
						throw new AssertionFailedException("COVERAGE 40"); //$NON-NLS-1$
745
						this.extraDefiniteNonNulls[i] &= otherInits.extraDefiniteNonNulls[i++];
1390
					}
746
					}
1391
				}
747
					while (i < length) {
1392
			} 
748
						this.extraDefiniteInits[i] = 0;
1393
			else {
749
						this.extraDefiniteNulls[i] = 0;
1394
				resetLimit = this.extra[0].length;
750
						this.extraDefiniteNonNulls[i++] = 0;
1395
				if (coverageTestFlag && coverageTestId == 41) {
751
					}
1396
					throw new AssertionFailedException("COVERAGE 41"); //$NON-NLS-1$
752
				}
1397
				}
753
			} else {
754
				// no extra storage on otherInits
755
				int i = 0, length = this.extraDefiniteInits.length;
756
				while (i < length) {
757
					this.extraDefiniteInits[i] = 0;
758
					this.extraDefiniteNulls[i] = 0;
759
					this.extraDefiniteNonNulls[i++] = 0;
760
				}
761
			}
762
		} else
763
			if (otherInits.extraDefiniteInits != null) {
764
				// no storage here, but other has extra storage.
765
				int otherLength;
766
				this.extraDefiniteInits = new long[otherLength = otherInits.extraDefiniteInits.length];
767
				System.arraycopy(otherInits.extraPotentialInits, 0, (this.extraPotentialInits = new long[otherLength]), 0, otherLength);
768
				this.extraDefiniteNulls = new long[otherLength];
769
				this.extraDefiniteNonNulls = new long[otherLength];
770
			}
1398
			}
771
		return this;
1399
		} 
1400
		else if (otherInits.extra != null) {
1401
			// no storage here, but other has extra storage.
1402
			int otherLength = otherInits.extra[0].length;
1403
			this.extra = new long[extraLength][];
1404
			for (int j = 0; j < extraLength; j++) {
1405
				this.extra[j] = new long[otherLength];
1406
			}
1407
			System.arraycopy(otherInits.extra[1], 0, 
1408
				this.extra[1], 0, otherLength);
1409
			copyLimit = otherLength;
1410
			if (coverageTestFlag && coverageTestId == 42) {
1411
				throw new AssertionFailedException("COVERAGE 42"); //$NON-NLS-1$
1412
			}
1413
		}
1414
		int i;
1415
		if (otherHasNulls) {
1416
			for (i = 0; i < mergeLimit; i++) {
1417
				this.extra[2][i] =
1418
					(a1 = this.extra[2][i]) & 
1419
					(b1 = otherInits.extra[2][i]) & (
1420
						(nb4 = ~(b4 = otherInits.extra[5][i])) & 
1421
						((b2 = otherInits.extra[3][i]) & 
1422
								(nb3 = ~(b3 = otherInits.extra[4][i])) & 
1423
								(na3 = ~(a3 = this.extra[4][i])) & 
1424
								((a2 = this.extra[3][i]) & 
1425
									(na4 = ~(a4 = this.extra[5][i])) | a4) |
1426
								(na2 = ~a2) & a3 & na4 & (nb2 = ~b2) & b3 ) |
1427
						b4 & (na3 & nb3 & (na4 & a2 | a4) |
1428
								na2 & a4 & nb2));
1429
				this.extra[3][i] =
1430
					a2 & b2 & ~(a1 ^ b1) & (na3 & nb3 | na4 & nb4) |
1431
					a1 & b1 & (a2 ^ b2) & na3 & nb3 |
1432
					(a1 & na2 & (nb1 = ~b1) & b2 | ~a1 & a2 & b1 & nb2) & na4 & nb4;
1433
				this.extra[4][i] =
1434
					b1 & nb2 & nb4 |
1435
					~a1 & (a3 |
1436
							a2 & na3 & (b1 | nb2)) |
1437
					(a1 | na2) & nb1 & b2 & nb3 |
1438
					nb1 & b3 |
1439
					a1 & na2 & (na4 |
1440
								b1 & nb2 & (a3 | b3));
1441
				this.extra[5][i] =
1442
					a4 | b4;
1443
				thisHasNulls = thisHasNulls ||
1444
					this.extra[5][i] != 0 ||
1445
					this.extra[2][i] != 0 ||
1446
					this.extra[3][i] != 0 ||
1447
					this.extra[4][i] != 0;
1448
				if (coverageTestFlag && coverageTestId == 43) {
1449
					this.extra[5][i] = ~0;
1450
				}
1451
			}
1452
		}
1453
		else {
1454
			for (i = 0; i < mergeLimit; i++) {
1455
				this.extra[0][i] &= 
1456
					otherInits.extra[0][i];
1457
				this.extra[1][i] |= 
1458
					otherInits.extra[1][i];
1459
				this.extra[4][i] =
1460
					~(~this.extra[2][i] &
1461
							~this.extra[3][i] &
1462
							~this.extra[4][i]) &
1463
					~(this.extra[2][i] & 
1464
							(this.extra[3][i] | 
1465
							this.extra[5][i]));
1466
				this.extra[2][i] = 
1467
				this.extra[3][i] = 0;
1468
				thisHasNulls = thisHasNulls ||
1469
					this.extra[4][i] != 0 ||
1470
					this.extra[5][i] != 0;
1471
				if (coverageTestFlag && coverageTestId == 44) {
1472
					this.extra[5][i] = ~0;
1473
				}
1474
			}
1475
		}
1476
		for (; i < copyLimit; i++) {
1477
			this.extra[1][i] = otherInits.extra[1][i];
1478
			this.extra[4][i] =
1479
				~(~otherInits.extra[2][i] &
1480
					~otherInits.extra[3][i] &
1481
					~otherInits.extra[4][i]) &
1482
				~(otherInits.extra[2][i] & 
1483
					(otherInits.extra[3][i] |
1484
					otherInits.extra[5][i]));
1485
			this.extra[5][i] = otherInits.extra[5][i];
1486
			thisHasNulls = thisHasNulls ||
1487
				this.extra[4][i] != 0 ||
1488
				this.extra[5][i] != 0;
1489
			if (coverageTestFlag && coverageTestId == 45) {
1490
				this.extra[5][i] = ~0;
1491
			}
1492
		}
1493
		for (; i < resetLimit; i++) {
1494
			this.extra[4][i] =
1495
				~(~this.extra[2][i] &
1496
						~this.extra[3][i] &
1497
						~this.extra[4][i]) &
1498
				~(this.extra[2][i] & 
1499
						(this.extra[3][i] | 
1500
						this.extra[5][i]));
1501
			this.extra[0][i] = 
1502
			this.extra[2][i] = 
1503
			this.extra[3][i] = 0;
1504
			thisHasNulls = thisHasNulls ||
1505
				this.extra[4][i] != 0 ||
1506
				this.extra[5][i] != 0;
1507
			if (coverageTestFlag && coverageTestId == 46) {
1508
				this.extra[5][i] = ~0;
1509
			}
1510
		}
772
	}
1511
	}
773
	
1512
	if (thisHasNulls) {
774
	/*
1513
		this.tagBits |= NULL_FLAG_MASK;
775
	 * Answer the total number of fields in enclosing types of a given type
1514
	}
776
	 */
1515
	else {
777
	static int numberOfEnclosingFields(ReferenceBinding type){
1516
		this.tagBits &= ~NULL_FLAG_MASK;
778
		
1517
	}
779
		int count = 0;
1518
	return this;
1519
}
1520
1521
/*
1522
 * Answer the total number of fields in enclosing types of a given type
1523
 */
1524
static int numberOfEnclosingFields(ReferenceBinding type){
1525
	int count = 0;
1526
	type = type.enclosingType();
1527
	while(type != null) {
1528
		count += type.fieldCount();
780
		type = type.enclosingType();
1529
		type = type.enclosingType();
781
		while(type != null) {
782
			count += type.fieldCount();
783
			type = type.enclosingType();
784
		}
785
		return count;
786
	}
1530
	}
787
	
1531
	return count;
788
	public int reachMode(){
1532
}
789
		return this.reachMode;
1533
1534
public UnconditionalFlowInfo nullInfoLessUnconditionalCopy() {
1535
	if (this == DEAD_END) {
1536
		return this;
790
	}
1537
	}
791
	
1538
	UnconditionalFlowInfo copy = new UnconditionalFlowInfo();
792
	public FlowInfo setReachMode(int reachMode) {
1539
	copy.definiteInits = this.definiteInits;
793
		
1540
	copy.potentialInits = this.potentialInits;
794
		if (this == DEAD_END) return this; // cannot modify DEAD_END
1541
	copy.tagBits = this.tagBits & ~NULL_FLAG_MASK;
795
	
1542
	copy.maxFieldCount = this.maxFieldCount;
796
		// reset optional inits when becoming unreachable
1543
	if (this.extra != null) {
797
		if ((this.reachMode & UNREACHABLE) == 0 && (reachMode & UNREACHABLE) != 0) {
1544
		int length;
1545
		copy.extra = new long[extraLength][];
1546
		System.arraycopy(this.extra[0], 0, 
1547
			(copy.extra[0] = 
1548
				new long[length = this.extra[0].length]), 0, length);
1549
		System.arraycopy(this.extra[1], 0, 
1550
			(copy.extra[1] = new long[length]), 0, length);
1551
		for (int j = 2; j < extraLength; j++) {
1552
			copy.extra[j] = new long[length];
1553
		}
1554
	}
1555
	return copy;
1556
}
1557
1558
public FlowInfo safeInitsWhenTrue() {
1559
	return copy();
1560
}
1561
1562
public FlowInfo setReachMode(int reachMode) {
1563
	if (reachMode == REACHABLE && this != DEAD_END) { // cannot modify DEAD_END
1564
		this.tagBits &= ~UNREACHABLE;
1565
	}
1566
	else {
1567
		if ((this.tagBits & UNREACHABLE) == 0) {
1568
			// reset optional inits when becoming unreachable
1569
			// see InitializationTest#test090 (and others)
798
			this.potentialInits = 0;
1570
			this.potentialInits = 0;
799
			if (this.extraPotentialInits != null){
1571
			if (this.extra != null) {
800
				for (int i = 0, length = this.extraPotentialInits.length; i < length; i++){
1572
				for (int i = 0, length = this.extra[0].length; 
801
					this.extraPotentialInits[i] = 0;
1573
						i < length; i++) {
1574
					this.extra[1][i] = 0;
802
				}
1575
				}
803
			}
1576
			}
804
		}				
1577
		}				
805
		this.reachMode = reachMode;
1578
		this.tagBits |= UNREACHABLE;
806
	
807
		return this;
808
	}
1579
	}
1580
	return this;
1581
}
809
1582
810
	public String toString(){
1583
public String toString(){
811
		
1584
	// PREMATURE consider printing bit fields as 0001 0001 1000 0001...
812
		if (this == DEAD_END){
1585
	if (this == DEAD_END){
813
			return "FlowInfo.DEAD_END"; //$NON-NLS-1$
1586
		return "FlowInfo.DEAD_END"; //$NON-NLS-1$
814
		}
1587
	}
815
		return "FlowInfo<def: "+ this.definiteInits //$NON-NLS-1$
1588
	if ((this.tagBits & NULL_FLAG_MASK) != 0) {
816
			+", pot: " + this.potentialInits  //$NON-NLS-1$
1589
		if (this.extra == null) {
817
			+ ", reachable:" + ((this.reachMode & UNREACHABLE) == 0) //$NON-NLS-1$
1590
			return "FlowInfo<def: " + this.definiteInits //$NON-NLS-1$
818
			+", defNull: " + this.definiteNulls  //$NON-NLS-1$
1591
				+", pot: " + this.potentialInits  //$NON-NLS-1$
819
			+", defNonNull: " + this.definiteNonNulls  //$NON-NLS-1$
1592
				+ ", reachable:" + ((this.tagBits & UNREACHABLE) == 0) //$NON-NLS-1$
820
			+">"; //$NON-NLS-1$
1593
				+", nullS1: " + this.nullAssignmentStatusBit1 //$NON-NLS-1$
1594
				+", nullS2: " + this.nullAssignmentStatusBit2 //$NON-NLS-1$
1595
				+", nullV1: " + this.nullAssignmentValueBit1 //$NON-NLS-1$
1596
				+", nullV2: " + this.nullAssignmentValueBit2 //$NON-NLS-1$
1597
				+">"; //$NON-NLS-1$
1598
		}
1599
		else {
1600
			String def = "FlowInfo<def:[" + this.definiteInits, //$NON-NLS-1$
1601
				pot = "], pot:[" + this.potentialInits, //$NON-NLS-1$
1602
				nullS1 = ", nullS1:[" + this.nullAssignmentStatusBit1, //$NON-NLS-1$
1603
				nullS2 = "], nullS2:[" + this.nullAssignmentStatusBit2, //$NON-NLS-1$
1604
				nullV1 = "], nullV1:[" + this.nullAssignmentValueBit1, //$NON-NLS-1$
1605
				nullV2 = "], nullV2:[" + this.nullAssignmentValueBit2; //$NON-NLS-1$
1606
			int i, ceil;
1607
			for (i = 0, ceil = this.extra[0].length > 3 ? 
1608
								3 : 
1609
								this.extra[0].length;
1610
				i < ceil; i++) {
1611
				def += "," + this.extra[0][i]; //$NON-NLS-1$
1612
				pot += "," + this.extra[1][i]; //$NON-NLS-1$
1613
				nullS1 += "," + this.extra[2][i]; //$NON-NLS-1$
1614
				nullS2 += "," + this.extra[3][i]; //$NON-NLS-1$
1615
				nullV1 += "," + this.extra[4][i]; //$NON-NLS-1$
1616
				nullV2 += "," + this.extra[5][i]; //$NON-NLS-1$
1617
			}
1618
			if (ceil < this.extra[0].length) {
1619
				def += ",..."; //$NON-NLS-1$
1620
				pot += ",..."; //$NON-NLS-1$
1621
				nullS1 += ",..."; //$NON-NLS-1$
1622
				nullS2 += ",..."; //$NON-NLS-1$
1623
				nullV1 += ",..."; //$NON-NLS-1$
1624
				nullV2 += ",..."; //$NON-NLS-1$
1625
			}
1626
			return def + pot 
1627
				+ "], reachable:" + ((this.tagBits & UNREACHABLE) == 0) //$NON-NLS-1$
1628
				+ nullS1 + nullS2 + nullV1 + nullV2
1629
				+ "]>"; //$NON-NLS-1$
1630
		}
1631
	}
1632
	else {
1633
		if (this.extra == null) {
1634
			return "FlowInfo<def: " + this.definiteInits //$NON-NLS-1$
1635
				+", pot: " + this.potentialInits  //$NON-NLS-1$
1636
				+ ", reachable:" + ((this.tagBits & UNREACHABLE) == 0) //$NON-NLS-1$
1637
				+", no null info>"; //$NON-NLS-1$
1638
		}
1639
		else {
1640
			String def = "FlowInfo<def:[" + this.definiteInits, //$NON-NLS-1$
1641
				pot = "], pot:[" + this.potentialInits; //$NON-NLS-1$
1642
			int i, ceil;
1643
			for (i = 0, ceil = this.extra[0].length > 3 ? 
1644
								3 : 
1645
								this.extra[0].length;
1646
				i < ceil; i++) {
1647
				def += "," + this.extra[0][i]; //$NON-NLS-1$
1648
				pot += "," + this.extra[1][i]; //$NON-NLS-1$
1649
			}
1650
			if (ceil < this.extra[0].length) {
1651
				def += ",..."; //$NON-NLS-1$
1652
				pot += ",..."; //$NON-NLS-1$
1653
			}
1654
			return def + pot 
1655
				+ "], reachable:" + ((this.tagBits & UNREACHABLE) == 0) //$NON-NLS-1$
1656
				+ ", no null info>"; //$NON-NLS-1$
1657
		}
821
	}
1658
	}
1659
}
1660
1661
public UnconditionalFlowInfo unconditionalCopy() {
1662
	return (UnconditionalFlowInfo) copy();
1663
}
822
	
1664
	
823
	public UnconditionalFlowInfo unconditionalInits() {
1665
public UnconditionalFlowInfo unconditionalFieldLessCopy() {
824
		
1666
	// TODO (maxime) may consider leveraging null contribution verification as it is done in copy
825
		// also see conditional inits, where it requests them to merge
1667
	UnconditionalFlowInfo copy = new UnconditionalFlowInfo();
826
		return this;
1668
	copy.tagBits = this.tagBits;
1669
	copy.maxFieldCount = this.maxFieldCount;
1670
	int limit = this.maxFieldCount;
1671
	if (limit < BitCacheSize) {
1672
		long mask;
1673
		copy.definiteInits = this.definiteInits & (mask = ~((1L << limit)-1));
1674
		copy.potentialInits = this.potentialInits & mask;
1675
		copy.nullAssignmentStatusBit1 = this.nullAssignmentStatusBit1 & mask;
1676
		copy.nullAssignmentStatusBit2 = this.nullAssignmentStatusBit2 & mask;
1677
		copy.nullAssignmentValueBit1 = this.nullAssignmentValueBit1 & mask;
1678
		copy.nullAssignmentValueBit2 = this.nullAssignmentValueBit2 & mask;
1679
	} 
1680
	// use extra vector
1681
	if (this.extra == null) {
1682
		return copy; // if vector not yet allocated, then not initialized
1683
	}
1684
	int vectorIndex, length, copyStart;
1685
	if ((vectorIndex = (limit / BitCacheSize) - 1) >= 
1686
			(length = this.extra[0].length)) {
1687
		return copy; // not enough room yet
1688
	}
1689
	long mask;
1690
	copy.extra = new long[extraLength][];
1691
	if ((copyStart = vectorIndex + 1) < length) {
1692
		int copyLength = length - copyStart;
1693
		for (int j = 0; j < extraLength; j++) {
1694
			System.arraycopy(this.extra[j], copyStart, 
1695
				(copy.extra[j] = new long[length]), copyStart, 
1696
				copyLength);
1697
		}
1698
	}
1699
	else if (vectorIndex >= 0) {
1700
		for (int j = 0; j < extraLength; j++) {
1701
			copy.extra[j] = new long[length];
1702
		}
1703
	}
1704
	if (vectorIndex >= 0) {
1705
		mask = ~((1L << (limit % BitCacheSize))-1);
1706
		for (int j = 0; j < extraLength; j++) {
1707
			copy.extra[j][vectorIndex] = 
1708
				this.extra[j][vectorIndex] & mask;
1709
		}
827
	}
1710
	}
1711
	return copy;
1712
}
1713
1714
public UnconditionalFlowInfo unconditionalInits() {
1715
	// also see conditional inits, where it requests them to merge
1716
	return this;
1717
}
1718
1719
public UnconditionalFlowInfo unconditionalInitsWithoutSideEffect() {
1720
	return this;
1721
}
828
}
1722
}
(-)compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java (+2 lines)
Lines 1001-1006 Link Here
1001
			case 'n' :
1001
			case 'n' :
1002
				if ("nls".equals(warningToken)) //$NON-NLS-1$
1002
				if ("nls".equals(warningToken)) //$NON-NLS-1$
1003
					return NonExternalizedString;
1003
					return NonExternalizedString;
1004
				if ("null".equals(warningToken)) //$NON-NLS-1$
1005
					return NullReference;
1004
				break;
1006
				break;
1005
			case 's' :
1007
			case 's' :
1006
				if ("serial".equals(warningToken)) //$NON-NLS-1$
1008
				if ("serial".equals(warningToken)) //$NON-NLS-1$
(-)compiler/org/eclipse/jdt/internal/compiler/lookup/ExtraCompilerModifiers.java (-1 / +3 lines)
Lines 18-24 Link Here
18
	// those constants are depending upon ClassFileConstants (relying that classfiles only use the 16 lower bits)
18
	// those constants are depending upon ClassFileConstants (relying that classfiles only use the 16 lower bits)
19
	final int AccJustFlag = 0xFFFF;// 16 lower bits
19
	final int AccJustFlag = 0xFFFF;// 16 lower bits
20
20
21
	// bit17 - free
21
	// bit17 - used below
22
	// bit18 - use by ClassFileConstants.AccAnnotationDefault
22
	// bit18 - use by ClassFileConstants.AccAnnotationDefault
23
	final int AccRestrictedAccess = ASTNode.Bit19; 
23
	final int AccRestrictedAccess = ASTNode.Bit19; 
24
	final int AccFromClassFile = ASTNode.Bit20; 
24
	final int AccFromClassFile = ASTNode.Bit20; 
Lines 38-41 Link Here
38
	final int AccOverriding = ASTNode.Bit29; // record fact a method overrides another one
38
	final int AccOverriding = ASTNode.Bit29; // record fact a method overrides another one
39
	final int AccImplementing = ASTNode.Bit30; // record fact a method implements another one (it is concrete and overrides an abstract one)
39
	final int AccImplementing = ASTNode.Bit30; // record fact a method implements another one (it is concrete and overrides an abstract one)
40
	final int AccGenericSignature = ASTNode.Bit31; // record fact a type/method/field involves generics in its signature (and need special signature attr)
40
	final int AccGenericSignature = ASTNode.Bit31; // record fact a type/method/field involves generics in its signature (and need special signature attr)
41
	final int AccNotNull = ASTNode.Bit32; // record fact a local/method/parameter cannot evaluate to null
42
	final int AccNullable = ASTNode.Bit17; // record fact a local/method/parameter can evaluate to null
41
}
43
}
(-)compiler/org/eclipse/jdt/internal/compiler/lookup/MethodScope.java (-3 / +4 lines)
Lines 395-404 Link Here
395
395
396
	public final int recordInitializationStates(FlowInfo flowInfo) {
396
	public final int recordInitializationStates(FlowInfo flowInfo) {
397
397
398
		if (!flowInfo.isReachable()) return -1;
398
		if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) != 0) return -1;
399
399
400
		UnconditionalFlowInfo unconditionalFlowInfo = flowInfo.unconditionalInits();
400
		UnconditionalFlowInfo unconditionalFlowInfo = flowInfo.unconditionalInitsWithoutSideEffect();
401
		long[] extraInits = unconditionalFlowInfo.extraDefiniteInits;
401
		long[] extraInits = unconditionalFlowInfo.extra == null ?
402
				null : unconditionalFlowInfo.extra[0];
402
		long inits = unconditionalFlowInfo.definiteInits;
403
		long inits = unconditionalFlowInfo.definiteInits;
403
		checkNextEntry : for (int i = lastIndex; --i >= 0;) {
404
		checkNextEntry : for (int i = lastIndex; --i >= 0;) {
404
			if (definiteInits[i] == inits) {
405
			if (definiteInits[i] == inits) {
(-)compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java (+3 lines)
Lines 553-558 Link Here
553
	// check @Deprecated annotation
553
	// check @Deprecated annotation
554
	if ((this.getAnnotationTagBits() & TagBits.AnnotationDeprecated) != 0) {
554
	if ((this.getAnnotationTagBits() & TagBits.AnnotationDeprecated) != 0) {
555
		this.modifiers |= ClassFileConstants.AccDeprecated;
555
		this.modifiers |= ClassFileConstants.AccDeprecated;
556
		// REVIEW already done in getAnnotationsTagBits
556
	}
557
	}
557
	ReferenceBinding enclosingType = this.enclosingType();
558
	ReferenceBinding enclosingType = this.enclosingType();
558
	if (enclosingType != null && enclosingType.isViewedAsDeprecated() && !this.isDeprecated())
559
	if (enclosingType != null && enclosingType.isViewedAsDeprecated() && !this.isDeprecated())
Lines 1108-1113 Link Here
1108
	if (this.scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5) {
1109
	if (this.scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5) {
1109
		if ((field.getAnnotationTagBits() & TagBits.AnnotationDeprecated) != 0)
1110
		if ((field.getAnnotationTagBits() & TagBits.AnnotationDeprecated) != 0)
1110
			field.modifiers |= ClassFileConstants.AccDeprecated;
1111
			field.modifiers |= ClassFileConstants.AccDeprecated;
1112
		// REVIEW in the case of fields, getAnnotationTagBits does not mark, whereas it
1113
		//        does it for types
1111
	}
1114
	}
1112
	if (isViewedAsDeprecated() && !field.isDeprecated())
1115
	if (isViewedAsDeprecated() && !field.isDeprecated())
1113
		field.modifiers |= ExtraCompilerModifiers.AccDeprecatedImplicitly;	
1116
		field.modifiers |= ExtraCompilerModifiers.AccDeprecatedImplicitly;	
(-)compiler/org/eclipse/jdt/internal/compiler/parser/AbstractCommentParser.java (+4 lines)
Lines 53-58 Link Here
53
	// Results
53
	// Results
54
	protected long inheritedPositions;
54
	protected long inheritedPositions;
55
	protected boolean deprecated;
55
	protected boolean deprecated;
56
	public boolean notNull; // TODO (maxime) replace with other style of multi-return check
57
	public boolean nullable;
56
	protected Object returnStatement;
58
	protected Object returnStatement;
57
	
59
	
58
	// Positions
60
	// Positions
Lines 140-145 Link Here
140
			this.returnStatement = null;
142
			this.returnStatement = null;
141
			this.inheritedPositions = -1;
143
			this.inheritedPositions = -1;
142
			this.deprecated = false;
144
			this.deprecated = false;
145
			this.notNull = false;
146
			this.nullable = false;
143
			this.lastLinePtr = getLineNumber(javadocEnd);
147
			this.lastLinePtr = getLineNumber(javadocEnd);
144
			this.lineEnd = (this.linePtr == this.lastLinePtr) ? this.javadocEnd: this.scanner.getLineEnd(this.linePtr) - 1;
148
			this.lineEnd = (this.linePtr == this.lastLinePtr) ? this.javadocEnd: this.scanner.getLineEnd(this.linePtr) - 1;
145
			this.textStart = -1;
149
			this.textStart = -1;
(-)compiler/org/eclipse/jdt/internal/compiler/parser/JavadocParser.java (-2 / +47 lines)
Lines 81-87 Link Here
81
				this.index = javadocStart +3;
81
				this.index = javadocStart +3;
82
	
82
	
83
				// scan line per line, since tags must be at beginning of lines only
83
				// scan line per line, since tags must be at beginning of lines only
84
				this.deprecated = false;
84
				this.deprecated = this.notNull = this.nullable = false;
85
				nextLine : for (int line = firstLineNumber; line <= lastLineNumber; line++) {
85
				nextLine : for (int line = firstLineNumber; line <= lastLineNumber; line++) {
86
					int lineStart = line == firstLineNumber
86
					int lineStart = line == firstLineNumber
87
							? javadocStart + 3 // skip leading /**
87
							? javadocStart + 3 // skip leading /**
Lines 103-109 Link Here
103
						        continue nextCharacter;
103
						        continue nextCharacter;
104
						    case '@' :
104
						    case '@' :
105
						    	parseSimpleTag();
105
						    	parseSimpleTag();
106
						    	if (this.tagValue == TAG_DEPRECATED_VALUE) {
106
						    	if (this.tagValue == TAG_DEPRECATED_VALUE ||
107
						    			this.tagValue == TAG_NOT_NULL_VALUE ||
108
						    			this.tagValue == TAG_NULLABLE_VALUE) {
107
						    		if (this.abort) break nextCharacter;
109
						    		if (this.abort) break nextCharacter;
108
						    	}
110
						    	}
109
						}
111
						}
Lines 346-351 Link Here
346
					}
348
					}
347
		        }
349
		        }
348
				break;
350
				break;
351
			case 'n':
352
				switch (readChar()) {
353
					case 'o':
354
				        if ((readChar() == 't') &&
355
								(readChar() == 'N') && (readChar() == 'u') &&
356
								(readChar() == 'l') && (readChar() == 'l')) {
357
							// ensure the tag is properly ended: either followed by a space, a tab, line end or asterisk.
358
							char c = readChar();
359
							if (Character.isWhitespace(c) || c == '*') {
360
								this.abort = true;
361
					    		this.notNull = true;
362
								this.tagValue = TAG_NOT_NULL_VALUE;
363
							}
364
				        }
365
				        break;
366
					case 'u':
367
				        if ((readChar() == 'l') &&
368
								(readChar() == 'l') && (readChar() == 'a') &&
369
								(readChar() == 'b') && (readChar() == 'l') &&
370
								(readChar() == 'e')) {
371
							// ensure the tag is properly ended: either followed by a space, a tab, line end or asterisk.
372
							char c = readChar();
373
							if (Character.isWhitespace(c) || c == '*') {
374
								this.abort = true;
375
					    		this.nullable = true;
376
								this.tagValue = TAG_NULLABLE_VALUE;
377
							}
378
				        }
379
				        break;
380
				}
381
				break;
349
		}
382
		}
350
	}
383
	}
351
384
Lines 479-484 Link Here
479
							}
512
							}
480
						}
513
						}
481
						break;
514
						break;
515
					case 'n':
516
						if (length == TAG_NOT_NULL_LENGTH && CharOperation.equals(TAG_NOT_NULL, tagName)) {
517
							this.notNull = true;
518
							valid = true;
519
							this.tagValue = TAG_NOT_NULL_VALUE;
520
						} 
521
						else if (length == TAG_NULLABLE_LENGTH && CharOperation.equals(TAG_NULLABLE, tagName)) {
522
							this.nullable = true;
523
							valid = true;
524
							this.tagValue = TAG_NULLABLE_VALUE;
525
						} 
526
						break;
482
					case 'p':
527
					case 'p':
483
						if (length == TAG_PARAM_LENGTH && CharOperation.equals(TAG_PARAM, tagName)) {
528
						if (length == TAG_PARAM_LENGTH && CharOperation.equals(TAG_PARAM, tagName)) {
484
							this.tagValue = TAG_PARAM_VALUE;
529
							this.tagValue = TAG_PARAM_VALUE;
(-)compiler/org/eclipse/jdt/internal/compiler/parser/JavadocTagConstants.java (-1 / +6 lines)
Lines 39-44 Link Here
39
	public static final char[] TAG_SINCE = "since".toCharArray(); //$NON-NLS-1$
39
	public static final char[] TAG_SINCE = "since".toCharArray(); //$NON-NLS-1$
40
	public static final char[] TAG_VERSION = "version".toCharArray(); //$NON-NLS-1$
40
	public static final char[] TAG_VERSION = "version".toCharArray(); //$NON-NLS-1$
41
	public static final char[] TAG_CATEGORY = "category".toCharArray(); //$NON-NLS-1$
41
	public static final char[] TAG_CATEGORY = "category".toCharArray(); //$NON-NLS-1$
42
	public static final char[] TAG_NOT_NULL = "notNull".toCharArray(); //$NON-NLS-1$
43
	public static final char[] TAG_NULLABLE = "nullable".toCharArray(); //$NON-NLS-1$
42
44
43
	// tags lengthes
45
	// tags lengthes
44
	public static final int TAG_DEPRECATED_LENGTH = TAG_DEPRECATED.length;
46
	public static final int TAG_DEPRECATED_LENGTH = TAG_DEPRECATED.length;
Lines 52-58 Link Here
52
	public static final int TAG_INHERITDOC_LENGTH = TAG_INHERITDOC.length;
54
	public static final int TAG_INHERITDOC_LENGTH = TAG_INHERITDOC.length;
53
	public static final int TAG_VALUE_LENGTH = TAG_VALUE.length;
55
	public static final int TAG_VALUE_LENGTH = TAG_VALUE.length;
54
	public static final int TAG_CATEGORY_LENGTH = TAG_CATEGORY.length;
56
	public static final int TAG_CATEGORY_LENGTH = TAG_CATEGORY.length;
55
57
	public static final int TAG_NOT_NULL_LENGTH = TAG_NOT_NULL.length;
58
	public static final int TAG_NULLABLE_LENGTH = TAG_NULLABLE.length;
56
59
57
	// tags value
60
	// tags value
58
	public static final int NO_TAG_VALUE = 0;
61
	public static final int NO_TAG_VALUE = 0;
Lines 67-72 Link Here
67
	public static final int TAG_INHERITDOC_VALUE = 9;
70
	public static final int TAG_INHERITDOC_VALUE = 9;
68
	public static final int TAG_VALUE_VALUE = 10;
71
	public static final int TAG_VALUE_VALUE = 10;
69
	public static final int TAG_CATEGORY_VALUE = 11;
72
	public static final int TAG_CATEGORY_VALUE = 11;
73
	public static final int TAG_NOT_NULL_VALUE = 50; // JDT custom
74
	public static final int TAG_NULLABLE_VALUE = 51; // JDT custom
70
	public static final int TAG_OTHERS_VALUE = 100;
75
	public static final int TAG_OTHERS_VALUE = 100;
71
	
76
	
72
	// tags expected positions
77
	// tags expected positions
(-)compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java (-2 / +36 lines)
Lines 1026-1033 Link Here
1026
	is zeroed when a copy of modifiers-buffer is push
1026
	is zeroed when a copy of modifiers-buffer is push
1027
	onto the this.astStack. */
1027
	onto the this.astStack. */
1028
1028
1029
	if ((this.modifiers & flag) != 0){ // duplicate modifier
1029
	if ((this.modifiers & flag) != 0 // duplicate modifier
1030
			|| ((this.modifiers & ExtraCompilerModifiers.AccNotNull) != 0  // conflicting flags
1031
				&& (flag & ExtraCompilerModifiers.AccNullable) != 0)
1032
			|| ((flag & ExtraCompilerModifiers.AccNotNull) != 0  // conflicting flags
1033
				&& (this.modifiers & ExtraCompilerModifiers.AccNullable) != 0)) { 
1030
		this.modifiers |= ExtraCompilerModifiers.AccAlternateModifierProblem;
1034
		this.modifiers |= ExtraCompilerModifiers.AccAlternateModifierProblem;
1035
		// TODO (maxime) check error message
1031
	}
1036
	}
1032
	this.modifiers |= flag;
1037
	this.modifiers |= flag;
1033
			
1038
			
Lines 1059-1064 Link Here
1059
			if (this.javadocParser.checkDeprecation(lastComment)) {
1064
			if (this.javadocParser.checkDeprecation(lastComment)) {
1060
				checkAndSetModifiers(ClassFileConstants.AccDeprecated);
1065
				checkAndSetModifiers(ClassFileConstants.AccDeprecated);
1061
			}
1066
			}
1067
			if (this.javadocParser.notNull) {
1068
				checkAndSetModifiers(ExtraCompilerModifiers.AccNotNull);
1069
			}
1070
			if (this.javadocParser.nullable) { // no else on purpose
1071
				checkAndSetModifiers(ExtraCompilerModifiers.AccNullable);
1072
			}
1062
			this.javadoc = this.javadocParser.docComment;	// null if check javadoc is not activated
1073
			this.javadoc = this.javadocParser.docComment;	// null if check javadoc is not activated
1063
			if (currentElement == null) this.lastJavadocEnd = commentEnd;
1074
			if (currentElement == null) this.lastJavadocEnd = commentEnd;
1064
		}
1075
		}
Lines 8240-8245 Link Here
8240
				(int) (this.identifierPositionStack[this.identifierPtr + 1] >> 32), // sourceStart
8251
				(int) (this.identifierPositionStack[this.identifierPtr + 1] >> 32), // sourceStart
8241
				(int) this.identifierPositionStack[this.identifierPtr + length]); // sourceEnd
8252
				(int) this.identifierPositionStack[this.identifierPtr + length]); // sourceEnd
8242
	}
8253
	}
8254
8255
	if (this.scanner.gotNonNullTag) {
8256
		ref.markAsNonNull();
8257
	}
8258
8243
	return ref;
8259
	return ref;
8244
}
8260
}
8245
protected NameReference getUnspecifiedReferenceOptimized() {
8261
protected NameReference getUnspecifiedReferenceOptimized() {
Lines 8260-8265 Link Here
8260
				this.identifierPositionStack[this.identifierPtr--]); 
8276
				this.identifierPositionStack[this.identifierPtr--]); 
8261
		ref.bits &= ~ASTNode.RestrictiveFlagMASK;
8277
		ref.bits &= ~ASTNode.RestrictiveFlagMASK;
8262
		ref.bits |= Binding.LOCAL | Binding.FIELD;
8278
		ref.bits |= Binding.LOCAL | Binding.FIELD;
8279
		if (this.scanner.gotNonNullTag) {
8280
			ref.markAsNonNull();
8281
		}
8263
		return ref;
8282
		return ref;
8264
	}
8283
	}
8265
8284
Lines 8281-8286 Link Here
8281
			(int) this.identifierPositionStack[this.identifierPtr + length]); // sourceEnd
8300
			(int) this.identifierPositionStack[this.identifierPtr + length]); // sourceEnd
8282
	ref.bits &= ~ASTNode.RestrictiveFlagMASK;
8301
	ref.bits &= ~ASTNode.RestrictiveFlagMASK;
8283
	ref.bits |= Binding.LOCAL | Binding.FIELD;
8302
	ref.bits |= Binding.LOCAL | Binding.FIELD;
8303
	if (this.scanner.gotNonNullTag) {
8304
		ref.markAsNonNull();
8305
	}
8284
	return ref;
8306
	return ref;
8285
}
8307
}
8286
public void goForBlockStatementsopt() {
8308
public void goForBlockStatementsopt() {
Lines 8428-8433 Link Here
8428
	final boolean checkNLS = this.options.getSeverity(CompilerOptions.NonExternalizedString) != ProblemSeverities.Ignore;
8450
	final boolean checkNLS = this.options.getSeverity(CompilerOptions.NonExternalizedString) != ProblemSeverities.Ignore;
8429
	this.checkExternalizeStrings = checkNLS;
8451
	this.checkExternalizeStrings = checkNLS;
8430
	this.scanner.checkNonExternalizedStringLiterals = initializeNLS && checkNLS;
8452
	this.scanner.checkNonExternalizedStringLiterals = initializeNLS && checkNLS;
8453
	this.scanner.checkNullReferences = 
8454
		this.options.getSeverity(CompilerOptions.NullReference) != 
8455
			ProblemSeverities.Ignore;
8456
	this.scanner.gotNonNullTag = false;
8431
8457
8432
	resetModifiers();
8458
	resetModifiers();
8433
8459
Lines 8461-8467 Link Here
8461
		this.options.complianceLevel /*complianceLevel*/, 
8487
		this.options.complianceLevel /*complianceLevel*/, 
8462
		this.options.taskTags/*taskTags*/,
8488
		this.options.taskTags/*taskTags*/,
8463
		this.options.taskPriorites/*taskPriorities*/,
8489
		this.options.taskPriorites/*taskPriorities*/,
8464
		this.options.isTaskCaseSensitive/*taskCaseSensitive*/);
8490
		this.options.isTaskCaseSensitive/*taskCaseSensitive*/,
8491
		this.options.getSeverity(CompilerOptions.NullReference) != 
8492
			ProblemSeverities.Ignore /* checkNullReferences */); 
8465
}
8493
}
8466
public void jumpOverMethodBody() {
8494
public void jumpOverMethodBody() {
8467
	//on diet parsing.....do not buffer method statements
8495
	//on diet parsing.....do not buffer method statements
Lines 8544-8549 Link Here
8544
		}
8572
		}
8545
	}
8573
	}
8546
}
8574
}
8575
8547
/*
8576
/*
8548
 * Move checkpoint location (current implementation is moving it by one token)
8577
 * Move checkpoint location (current implementation is moving it by one token)
8549
 *
8578
 *
Lines 9314-9319 Link Here
9314
	Increase the total number of identifier in the stack.
9343
	Increase the total number of identifier in the stack.
9315
	identifierPtr points on the next top */
9344
	identifierPtr points on the next top */
9316
9345
9346
	if (this.scanner.gotNonNullTag && this.identifierPtr < 0) {
9347
		this.scanner.gotNonNullTag = false;
9348
	}
9349
	
9317
	int stackLength = this.identifierStack.length;
9350
	int stackLength = this.identifierStack.length;
9318
	if (++this.identifierPtr >= stackLength) {
9351
	if (++this.identifierPtr >= stackLength) {
9319
		System.arraycopy(
9352
		System.arraycopy(
Lines 9853-9858 Link Here
9853
protected boolean resumeOnSyntaxError() {
9886
protected boolean resumeOnSyntaxError() {
9854
	this.checkExternalizeStrings = false;
9887
	this.checkExternalizeStrings = false;
9855
	this.scanner.checkNonExternalizedStringLiterals = false;
9888
	this.scanner.checkNonExternalizedStringLiterals = false;
9889
	// REVIEW don't know if we should reset checkNullReferences here as well...
9856
	/* request recovery initialization */
9890
	/* request recovery initialization */
9857
	if (this.currentElement == null){
9891
	if (this.currentElement == null){
9858
		// Reset javadoc before restart parsing after recovery
9892
		// Reset javadoc before restart parsing after recovery
(-)compiler/org/eclipse/jdt/internal/compiler/parser/Scanner.java (-3 / +109 lines)
Lines 155-160 Link Here
155
	private NLSTag[] nlsTags = null;
155
	private NLSTag[] nlsTags = null;
156
	protected int nlsTagsPtr;
156
	protected int nlsTagsPtr;
157
	public boolean checkNonExternalizedStringLiterals;
157
	public boolean checkNonExternalizedStringLiterals;
158
	
159
	// support for tagging references as non null
160
	boolean checkNullReferences;
161
	public boolean gotNonNullTag;
158
162
159
	// generic support
163
	// generic support
160
	public boolean returnOnlyGreater = false;
164
	public boolean returnOnlyGreater = false;
Lines 198-204 Link Here
198
	long complianceLevel,
202
	long complianceLevel,
199
	char[][] taskTags,
203
	char[][] taskTags,
200
	char[][] taskPriorities,
204
	char[][] taskPriorities,
201
	boolean isTaskCaseSensitive) {
205
	boolean isTaskCaseSensitive,
206
	boolean checkNullReferences) {
202
207
203
	this.eofPosition = Integer.MAX_VALUE;
208
	this.eofPosition = Integer.MAX_VALUE;
204
	this.tokenizeComments = tokenizeComments;
209
	this.tokenizeComments = tokenizeComments;
Lines 209-214 Link Here
209
	this.taskTags = taskTags;
214
	this.taskTags = taskTags;
210
	this.taskPriorities = taskPriorities;
215
	this.taskPriorities = taskPriorities;
211
	this.isTaskCaseSensitive = isTaskCaseSensitive;
216
	this.isTaskCaseSensitive = isTaskCaseSensitive;
217
	this.checkNullReferences = checkNullReferences;
218
}
219
220
public Scanner(
221
	boolean tokenizeComments, 
222
	boolean tokenizeWhiteSpace, 
223
	boolean checkNonExternalizedStringLiterals, 
224
	long sourceLevel,
225
	long complianceLevel,
226
	char[][] taskTags,
227
	char[][] taskPriorities,
228
	boolean isTaskCaseSensitive) {
229
	this(
230
		tokenizeComments,
231
		tokenizeWhiteSpace,
232
		checkNonExternalizedStringLiterals,
233
		sourceLevel,
234
		complianceLevel,
235
		taskTags,
236
		taskPriorities,
237
		isTaskCaseSensitive,
238
		false);
212
}
239
}
213
240
214
public Scanner(
241
public Scanner(
Lines 228-234 Link Here
228
		sourceLevel,
255
		sourceLevel,
229
		taskTags,
256
		taskTags,
230
		taskPriorities,
257
		taskPriorities,
231
		isTaskCaseSensitive);
258
		isTaskCaseSensitive,
259
		false);
232
}
260
}
233
261
234
public  final boolean atEnd() {
262
public  final boolean atEnd() {
Lines 237-242 Link Here
237
265
238
	return this.source.length == this.currentPosition;
266
	return this.source.length == this.currentPosition;
239
}
267
}
268
269
// Check presence of non null tags.
270
private final void checkNonNullTag(int commentStart, int commentEnd) {
271
	for (int i = commentStart + 2, state = 0; state < 9;) {
272
		if (i >= commentEnd || i >= this.eofPosition) {
273
			return;
274
		}
275
		char currentChar = this.source[i++];
276
		switch (state) {
277
			case 0: // start
278
				if (currentChar == 'N') {
279
					state++;
280
				}
281
				else if (!CharOperation.isWhitespace(currentChar)) {
282
					return;
283
				}
284
				continue;
285
			case 1: // got a N
286
				switch (currentChar) {
287
					case 'O':
288
						state++;
289
						continue;
290
					case 'N':
291
						state = 8;
292
						continue;
293
					default:
294
						return;
295
				}
296
				// never get there
297
			case 2: // got NO
298
			case 4: // got NON-
299
				if (currentChar == 'N') {
300
					state++;
301
					continue;
302
				}
303
				return;
304
			case 3: // got NON
305
				if (currentChar == '-') {
306
					state++;
307
					continue;
308
				}
309
				return;
310
			case 5: // got NON-N
311
				if (currentChar == 'U') {
312
					state++;
313
					continue;
314
				}
315
				return;
316
			case 6: // got NON-NU
317
			case 7: // got NON-NUL
318
				if (currentChar == 'L') {
319
					state++;
320
					continue;
321
				}
322
				return;
323
			case 8:	// got NON-NULL or NN
324
				if (currentChar != '*' && !CharOperation.isWhitespace(currentChar)) {
325
					return;
326
				}
327
				state = 9; // got a marker
328
		}
329
	}
330
	// got a non null marker
331
	this.gotNonNullTag = true;
332
}
333
240
// chech presence of task: tags
334
// chech presence of task: tags
241
// TODO (frederic) see if we need to take unicode characters into account...
335
// TODO (frederic) see if we need to take unicode characters into account...
242
public void checkTaskTag(int commentStart, int commentEnd) throws InvalidInputException {
336
public void checkTaskTag(int commentStart, int commentEnd) throws InvalidInputException {
Lines 1282-1287 Link Here
1282
							   	}
1376
							   	}
1283
								recordComment(TokenNameCOMMENT_LINE);
1377
								recordComment(TokenNameCOMMENT_LINE);
1284
								if (this.taskTags != null) checkTaskTag(this.startPosition, this.currentPosition);
1378
								if (this.taskTags != null) checkTaskTag(this.startPosition, this.currentPosition);
1379
								if (this.checkNullReferences) {
1380
									checkNonNullTag(this.startPosition, 
1381
											this.currentPosition);
1382
								}
1285
								if ((this.currentCharacter == '\r') || (this.currentCharacter == '\n')) {
1383
								if ((this.currentCharacter == '\r') || (this.currentCharacter == '\n')) {
1286
									if (this.checkNonExternalizedStringLiterals) {
1384
									if (this.checkNonExternalizedStringLiterals) {
1287
										parseTags();
1385
										parseTags();
Lines 1301-1306 Link Here
1301
								this.currentPosition--;
1399
								this.currentPosition--;
1302
								recordComment(TokenNameCOMMENT_LINE);
1400
								recordComment(TokenNameCOMMENT_LINE);
1303
								if (this.taskTags != null) checkTaskTag(this.startPosition, this.currentPosition);
1401
								if (this.taskTags != null) checkTaskTag(this.startPosition, this.currentPosition);
1402
								if (this.checkNullReferences) {
1403
									checkNonNullTag(this.startPosition, 
1404
											this.currentPosition);
1405
								}
1304
								if (this.checkNonExternalizedStringLiterals) {
1406
								if (this.checkNonExternalizedStringLiterals) {
1305
									parseTags();
1407
									parseTags();
1306
								}
1408
								}
Lines 1406-1411 Link Here
1406
								recordComment(token);
1508
								recordComment(token);
1407
								this.commentTagStarts[this.commentPtr] = firstTag;
1509
								this.commentTagStarts[this.commentPtr] = firstTag;
1408
								if (this.taskTags != null) checkTaskTag(this.startPosition, this.currentPosition);
1510
								if (this.taskTags != null) checkTaskTag(this.startPosition, this.currentPosition);
1511
								if (this.checkNullReferences) {
1512
									checkNonNullTag(this.startPosition, 
1513
											this.currentPosition);
1514
								}
1409
								if (this.tokenizeComments) {
1515
								if (this.tokenizeComments) {
1410
									/*
1516
									/*
1411
									if (isJavadoc)
1517
									if (isJavadoc)
Lines 1738-1744 Link Here
1738
										getNextUnicodeChar();
1844
										getNextUnicodeChar();
1739
									}
1845
									}
1740
							   	}
1846
							   	}
1741
								recordComment(TokenNameCOMMENT_LINE);
1847
								recordComment(TokenNameCOMMENT_LINE);  // REVIEW why do we record comments while jumping over (method bodies)?
1742
								if (this.recordLineSeparator
1848
								if (this.recordLineSeparator
1743
									&& ((this.currentCharacter == '\r') || (this.currentCharacter == '\n'))) {
1849
									&& ((this.currentCharacter == '\r') || (this.currentCharacter == '\n'))) {
1744
										if (this.checkNonExternalizedStringLiterals) {
1850
										if (this.checkNonExternalizedStringLiterals) {
(-)compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java (+10 lines)
Lines 1418-1423 Link Here
1418
1418
1419
		case IProblem.LocalVariableCannotBeNull :
1419
		case IProblem.LocalVariableCannotBeNull :
1420
		case IProblem.LocalVariableCanOnlyBeNull :
1420
		case IProblem.LocalVariableCanOnlyBeNull :
1421
		case IProblem.LocalVariableMayBeNull :
1421
			return CompilerOptions.NullReference;
1422
			return CompilerOptions.NullReference;
1422
			
1423
			
1423
		case IProblem.BoxingConversion :
1424
		case IProblem.BoxingConversion :
Lines 4049-4054 Link Here
4049
			local.sourceEnd);
4050
			local.sourceEnd);
4050
	}
4051
	}
4051
}
4052
}
4053
public void localVariableMayBeNull(LocalVariableBinding local, ASTNode location) {
4054
	String[] arguments = new String[] {new String(local.name)};
4055
	this.handle(
4056
		IProblem.LocalVariableMayBeNull,
4057
		arguments,
4058
		arguments,
4059
		location.sourceStart,
4060
		location.sourceEnd);
4061
}
4052
public void methodMustOverride(AbstractMethodDeclaration method) {
4062
public void methodMustOverride(AbstractMethodDeclaration method) {
4053
	MethodBinding binding = method.binding;
4063
	MethodBinding binding = method.binding;
4054
	this.handle(
4064
	this.handle(
(-)compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties (+1 lines)
Lines 324-329 Link Here
324
396 = Illegal modifier for the variable {0}; only final is permitted
324
396 = Illegal modifier for the variable {0}; only final is permitted
325
397 = The variable {0} cannot be null; it was either set to a non-null value or assumed to be non-null when last used
325
397 = The variable {0} cannot be null; it was either set to a non-null value or assumed to be non-null when last used
326
398 = The variable {0} can only be null; it was either set to null or checked for null when last used
326
398 = The variable {0} can only be null; it was either set to null or checked for null when last used
327
399 = The variable {0} may be null
327
	
328
	
328
400 = The type {3} must implement the inherited abstract method {2}.{0}({1})
329
400 = The type {3} must implement the inherited abstract method {2}.{0}({1})
329
401 = Cannot override the final method from {0}
330
401 = Cannot override the final method from {0}
(-)dom/org/eclipse/jdt/core/dom/DocCommentParser.java (+14 lines)
Lines 436-441 Link Here
436
						}
436
						}
437
						createTag();
437
						createTag();
438
					break;
438
					break;
439
					case 'n':
440
						if (length == TAG_NOT_NULL_LENGTH && CharOperation.equals(TAG_NOT_NULL, tagName)) {
441
							this.notNull = true;
442
							this.tagValue = TAG_NOT_NULL_VALUE;
443
						} 
444
						else if (length == TAG_NULLABLE_LENGTH && CharOperation.equals(TAG_NULLABLE, tagName)) {
445
							this.nullable = true;
446
							this.tagValue = TAG_NULLABLE_VALUE;
447
						} 
448
						else {
449
							this.tagValue = TAG_OTHERS_VALUE;
450
						}
451
						createTag();
452
					break;
439
					case 'p':
453
					case 'p':
440
						if (length == TAG_PARAM_LENGTH && CharOperation.equals(TAG_PARAM, tagName)) {
454
						if (length == TAG_PARAM_LENGTH && CharOperation.equals(TAG_PARAM, tagName)) {
441
							this.tagValue = TAG_PARAM_VALUE;
455
							this.tagValue = TAG_PARAM_VALUE;
(-)eval/org/eclipse/jdt/internal/eval/CodeSnippetAllocationExpression.java (-1 / +2 lines)
Lines 115-124 Link Here
115
	// not supported yet
115
	// not supported yet
116
}
116
}
117
public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
117
public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
118
		if (!flowInfo.isReachable()) return;
118
		if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) {
119
119
120
		// if constructor from parameterized type got found, use the original constructor at codegen time
120
		// if constructor from parameterized type got found, use the original constructor at codegen time
121
		this.codegenBinding = this.binding.original();
121
		this.codegenBinding = this.binding.original();
122
		}
122
}
123
}
123
public TypeBinding resolveType(BlockScope scope) {
124
public TypeBinding resolveType(BlockScope scope) {
124
	// Propagate the type checking to the arguments, and check if the constructor is defined.
125
	// Propagate the type checking to the arguments, and check if the constructor is defined.
(-)eval/org/eclipse/jdt/internal/eval/CodeSnippetFieldReference.java (-1 / +2 lines)
Lines 291-297 Link Here
291
public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo, boolean isReadAccess){
291
public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo, boolean isReadAccess){
292
	// The private access will be managed through the code generation
292
	// The private access will be managed through the code generation
293
293
294
	if (!flowInfo.isReachable()) return;
294
	if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) != 0) return;
295
	
295
	// if field from parameterized type got found, use the original field at codegen time
296
	// if field from parameterized type got found, use the original field at codegen time
296
	if (this.binding instanceof ParameterizedFieldBinding) {
297
	if (this.binding instanceof ParameterizedFieldBinding) {
297
	    ParameterizedFieldBinding parameterizedField = (ParameterizedFieldBinding) this.binding;
298
	    ParameterizedFieldBinding parameterizedField = (ParameterizedFieldBinding) this.binding;
(-)eval/org/eclipse/jdt/internal/eval/CodeSnippetMessageSend.java (-2 / +3 lines)
Lines 162-168 Link Here
162
}
162
}
163
public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
163
public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
164
164
165
	if (!flowInfo.isReachable()) return;
165
	if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) {
166
166
167
	// if method from parameterized type got found, use the original method at codegen time
167
	// if method from parameterized type got found, use the original method at codegen time
168
	this.codegenBinding = this.binding.original();
168
	this.codegenBinding = this.binding.original();
Lines 193-199 Link Here
193
		}
193
		}
194
		// Post 1.4.0 target, array clone() invocations are qualified with array type 
194
		// Post 1.4.0 target, array clone() invocations are qualified with array type 
195
		// This is handled in array type #clone method binding resolution (see Scope and UpdatedMethodBinding)
195
		// This is handled in array type #clone method binding resolution (see Scope and UpdatedMethodBinding)
196
	}	
196
	}
197
	}
197
}
198
}
198
public TypeBinding resolveType(BlockScope scope) {
199
public TypeBinding resolveType(BlockScope scope) {
199
	// Answer the signature return type
200
	// Answer the signature return type
(-)eval/org/eclipse/jdt/internal/eval/CodeSnippetQualifiedNameReference.java (-1 / +1 lines)
Lines 499-505 Link Here
499
		int index,
499
		int index,
500
		FlowInfo flowInfo) {
500
		FlowInfo flowInfo) {
501
501
502
		if (!flowInfo.isReachable()) return;
502
		if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) != 0) return;
503
	
503
	
504
		// if the binding declaring class is not visible, need special action
504
		// if the binding declaring class is not visible, need special action
505
		// for runtime compatibility on 1.2 VMs : change the declaring class of the binding
505
		// for runtime compatibility on 1.2 VMs : change the declaring class of the binding
(-)eval/org/eclipse/jdt/internal/eval/CodeSnippetSingleNameReference.java (-2 / +2 lines)
Lines 67-73 Link Here
67
			if (!flowInfo.isDefinitelyAssigned(localBinding = (LocalVariableBinding) this.binding)) {
67
			if (!flowInfo.isDefinitelyAssigned(localBinding = (LocalVariableBinding) this.binding)) {
68
				currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
68
				currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
69
			}
69
			}
70
			if (flowInfo.isReachable()) {
70
			if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) {
71
				localBinding.useFlag = LocalVariableBinding.USED;
71
				localBinding.useFlag = LocalVariableBinding.USED;
72
			} else if (localBinding.useFlag == LocalVariableBinding.UNUSED) {
72
			} else if (localBinding.useFlag == LocalVariableBinding.UNUSED) {
73
				localBinding.useFlag = LocalVariableBinding.FAKE_USED;
73
				localBinding.useFlag = LocalVariableBinding.FAKE_USED;
Lines 567-573 Link Here
567
		return;
567
		return;
568
	}
568
	}
569
569
570
	if (!flowInfo.isReachable()) return;
570
	if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) != 0) return;
571
	//If inlinable field, forget the access emulation, the code gen will directly target it
571
	//If inlinable field, forget the access emulation, the code gen will directly target it
572
	if (this.constant != Constant.NotAConstant)
572
	if (this.constant != Constant.NotAConstant)
573
		return;	
573
		return;	
(-)model/org/eclipse/jdt/core/JavaCore.java (-2 / +3 lines)
Lines 3154-3161 Link Here
3154
			IClasspathAttribute[] extraAttributes,
3154
			IClasspathAttribute[] extraAttributes,
3155
			boolean isExported) {
3155
			boolean isExported) {
3156
			
3156
			
3157
		if (containerPath == null) Assert.isTrue(false, "Container path cannot be null"); //$NON-NLS-1$
3157
		if (containerPath == null) {
3158
		if (containerPath.segmentCount() < 1) {
3158
			Assert.isTrue(false, "Container path cannot be null"); //$NON-NLS-1$
3159
		} else if (containerPath.segmentCount() < 1) {
3159
			Assert.isTrue(
3160
			Assert.isTrue(
3160
				false,
3161
				false,
3161
				"Illegal classpath container path: \'" + containerPath.makeRelative().toString() + "\', must have at least one segment (containerID+hints)"); //$NON-NLS-1$//$NON-NLS-2$
3162
				"Illegal classpath container path: \'" + containerPath.makeRelative().toString() + "\', must have at least one segment (containerID+hints)"); //$NON-NLS-1$//$NON-NLS-2$
(-)model/org/eclipse/jdt/internal/compiler/DocumentElementParser.java (-15 / +11 lines)
Lines 10-34 Link Here
10
 *******************************************************************************/
10
 *******************************************************************************/
11
package org.eclipse.jdt.internal.compiler;
11
package org.eclipse.jdt.internal.compiler;
12
12
13
/*
14
 * A document element parser extracts structural information
15
 * from a piece of source, providing detailed source positions info.
16
 *
17
 * also see @IDocumentElementRequestor
18
 *
19
 * The structural investigation includes:
20
 * - the package statement
21
 * - import statements
22
 * - top-level types: package member, member types (member types of member types...)
23
 * - fields
24
 * - methods
25
 *
26
 * Any (parsing) problem encountered is also provided.
27
 */
28
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
13
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
29
import org.eclipse.jdt.internal.compiler.env.*;
14
import org.eclipse.jdt.internal.compiler.env.*;
30
15
31
import org.eclipse.jdt.internal.compiler.impl.*;
16
import org.eclipse.jdt.internal.compiler.impl.*;
17
import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers;
32
import org.eclipse.jdt.core.compiler.*;
18
import org.eclipse.jdt.core.compiler.*;
33
import org.eclipse.jdt.internal.compiler.ast.*;
19
import org.eclipse.jdt.internal.compiler.ast.*;
34
import org.eclipse.jdt.internal.compiler.parser.*;
20
import org.eclipse.jdt.internal.compiler.parser.*;
Lines 77-82 Link Here
77
	/* persisting javadoc positions */
63
	/* persisting javadoc positions */
78
	pushOnIntArrayStack(this.getJavaDocPositions());
64
	pushOnIntArrayStack(this.getJavaDocPositions());
79
	boolean deprecated = false;
65
	boolean deprecated = false;
66
	boolean notNull = false;
67
	boolean nullable = false;
80
	int lastCommentIndex = -1;
68
	int lastCommentIndex = -1;
81
	int commentPtr = scanner.commentPtr;
69
	int commentPtr = scanner.commentPtr;
82
70
Lines 93-103 Link Here
93
		}
81
		}
94
		deprecated =
82
		deprecated =
95
			this.javadocParser.checkDeprecation(lastCommentIndex);
83
			this.javadocParser.checkDeprecation(lastCommentIndex);
84
		notNull = this.javadocParser.notNull;
85
		nullable = this.javadocParser.nullable;
96
		break nextComment;
86
		break nextComment;
97
	}
87
	}
98
	if (deprecated) {
88
	if (deprecated) {
99
		checkAndSetModifiers(ClassFileConstants.AccDeprecated);
89
		checkAndSetModifiers(ClassFileConstants.AccDeprecated);
100
	}
90
	}
91
	if (notNull) {
92
		checkAndSetModifiers(ExtraCompilerModifiers.AccNotNull);
93
	}
94
	if (nullable) { // no else on purpose
95
		checkAndSetModifiers(ExtraCompilerModifiers.AccNullable);
96
	}
101
	// modify the modifier source start to point at the first comment
97
	// modify the modifier source start to point at the first comment
102
	if (commentPtr >= 0) {
98
	if (commentPtr >= 0) {
103
		declarationSourceStart = scanner.commentStarts[0];
99
		declarationSourceStart = scanner.commentStarts[0];
(-)model/org/eclipse/jdt/internal/compiler/SourceElementParser.java (+6 lines)
Lines 157-162 Link Here
157
			if (this.javadocParser.checkDeprecation(lastComment)) {
157
			if (this.javadocParser.checkDeprecation(lastComment)) {
158
				checkAndSetModifiers(ClassFileConstants.AccDeprecated);
158
				checkAndSetModifiers(ClassFileConstants.AccDeprecated);
159
			}
159
			}
160
			if (this.javadocParser.notNull) {
161
				checkAndSetModifiers(ExtraCompilerModifiers.AccNotNull);
162
			}
163
			if (this.javadocParser.nullable) { // no else on purpose
164
				checkAndSetModifiers(ExtraCompilerModifiers.AccNullable);
165
			}
160
			this.javadoc = this.javadocParser.docComment;	// null if check javadoc is not activated
166
			this.javadoc = this.javadocParser.docComment;	// null if check javadoc is not activated
161
			if (currentElement == null) this.lastJavadocEnd = commentEnd;
167
			if (currentElement == null) this.lastJavadocEnd = commentEnd;
162
		}
168
		}
(-)model/org/eclipse/jdt/internal/compiler/SourceJavadocParser.java (+29 lines)
Lines 133-138 Link Here
133
				}
133
				}
134
	        }
134
	        }
135
			break;
135
			break;
136
		case 'n': // perhaps @notNull or @nullable tag?
137
			switch (readChar()) {
138
				case 'o':
139
			        if ((readChar() == 't') &&
140
							(readChar() == 'N') && (readChar() == 'u') &&
141
							(readChar() == 'l') && (readChar() == 'l')) {
142
						// ensure the tag is properly ended: either followed by a space, a tab, line end or asterisk.
143
						char c = readChar();
144
						if (Character.isWhitespace(c) || c == '*') {
145
				    		this.notNull = true;
146
							this.tagValue = TAG_NOT_NULL_VALUE;
147
						}
148
			        }
149
			        break;
150
				case 'u':
151
			        if ((readChar() == 'l') &&
152
							(readChar() == 'l') && (readChar() == 'a') &&
153
							(readChar() == 'b') && (readChar() == 'l') &&
154
							(readChar() == 'e')) {
155
						// ensure the tag is properly ended: either followed by a space, a tab, line end or asterisk.
156
						char c = readChar();
157
						if (Character.isWhitespace(c) || c == '*') {
158
				    		this.nullable = true;
159
							this.tagValue = TAG_NULLABLE_VALUE;
160
						}
161
			        }
162
			        break;
163
			}	        
164
			break;			
136
	}
165
	}
137
}
166
}
138
167
(-)model/org/eclipse/jdt/internal/core/util/CommentRecorderParser.java (+11 lines)
Lines 13-18 Link Here
13
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
13
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
14
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
14
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
15
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
15
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
16
import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers;
16
import org.eclipse.jdt.internal.compiler.parser.Parser;
17
import org.eclipse.jdt.internal.compiler.parser.Parser;
17
import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
18
import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
18
import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
19
import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
Lines 48-53 Link Here
48
		}
49
		}
49
		boolean deprecated = false;
50
		boolean deprecated = false;
50
		boolean checkDeprecated = false;
51
		boolean checkDeprecated = false;
52
		boolean notNull = false;
53
		boolean nullable = false;
51
		int lastCommentIndex = -1;
54
		int lastCommentIndex = -1;
52
		
55
		
53
		//since jdk1.2 look only in the last java doc comment...
56
		//since jdk1.2 look only in the last java doc comment...
Lines 67-78 Link Here
67
			// do not report problem before last parsed comment while recovering code...
70
			// do not report problem before last parsed comment while recovering code...
68
			this.javadocParser.reportProblems = this.currentElement == null || commentSourceEnd > this.lastJavadocEnd;
71
			this.javadocParser.reportProblems = this.currentElement == null || commentSourceEnd > this.lastJavadocEnd;
69
			deprecated = this.javadocParser.checkDeprecation(lastCommentIndex);
72
			deprecated = this.javadocParser.checkDeprecation(lastCommentIndex);
73
			notNull = this.javadocParser.notNull;
74
			nullable = this.javadocParser.nullable;
70
			this.javadoc = this.javadocParser.docComment;
75
			this.javadoc = this.javadocParser.docComment;
71
			break nextComment;
76
			break nextComment;
72
		}
77
		}
73
		if (deprecated) {
78
		if (deprecated) {
74
			checkAndSetModifiers(ClassFileConstants.AccDeprecated);
79
			checkAndSetModifiers(ClassFileConstants.AccDeprecated);
75
		}
80
		}
81
		if (notNull) {
82
			checkAndSetModifiers(ExtraCompilerModifiers.AccNotNull);
83
		}
84
		if (nullable) { // no else on purpose
85
			checkAndSetModifiers(ExtraCompilerModifiers.AccNullable);
86
		}
76
		// modify the modifier source start to point at the first comment
87
		// modify the modifier source start to point at the first comment
77
		if (lastCommentIndex >= 0 && checkDeprecated) {
88
		if (lastCommentIndex >= 0 && checkDeprecated) {
78
			this.modifiersSourceStart = this.scanner.commentStarts[lastCommentIndex]; 
89
			this.modifiersSourceStart = this.scanner.commentStarts[lastCommentIndex]; 
(-)Eclipse Java Tests Compiler/org/eclipse/jdt/tests/compiler/regression/ConformTest.java (-20 / +24 lines)
Lines 24-35 Link Here
24
	super(name);
24
	super(name);
25
}
25
}
26
public static Test suite() {
26
public static Test suite() {
27
27
	if (false) {
28
	if (false) {
28
	   	TestSuite ts;
29
	   	TestSuite ts;
29
		//some of the tests depend on the order of this suite.
30
		//some of the tests depend on the order of this suite.
30
		ts = new TestSuite();
31
		ts = new TestSuite();
31
		ts.addTest(new ConformTest("test089"));
32
		ts.addTest(new ConformTest("test246"));
32
		return new RegressionTestSetup(ts, COMPLIANCE_1_6);
33
		return new RegressionTestSetup(ts, COMPLIANCE_1_4);
33
	}
34
	}
34
	return setupSuite(testClass());
35
	return setupSuite(testClass());
35
}
36
}
Lines 948-954 Link Here
948
	"SUCCESS");
949
	"SUCCESS");
949
}
950
}
950
public void test067() {
951
public void test067() {
951
	if (this.complianceLevel.compareTo(COMPLIANCE_1_4) >= 0) return; // TODO (philippe) test is failing in 1.4 or 1.5 compliance mode
952
	if (COMPLIANCE_1_4.equals(this.complianceLevel)
953
		|| COMPLIANCE_1_5.equals(this.complianceLevel)) return; // TODO (philippe) test is failing in 1.4 or 1.5 compliance mode
952
	this.runConformTest(new String[] {
954
	this.runConformTest(new String[] {
953
		"p/F.java",
955
		"p/F.java",
954
		"package p;\n" + 
956
		"package p;\n" + 
Lines 3555-3561 Link Here
3555
 */
3557
 */
3556
public void test211() {
3558
public void test211() {
3557
	String expectedResult;
3559
	String expectedResult;
3558
	if (this.complianceLevel.compareTo(COMPLIANCE_1_5) >= 0) {
3560
	if (COMPLIANCE_1_5.equals(this.complianceLevel)) {
3559
		expectedResult = "SUCCESS";
3561
		expectedResult = "SUCCESS";
3560
	} else {
3562
	} else {
3561
		expectedResult = "SUCC<A should be initialized>ESS";
3563
		expectedResult = "SUCC<A should be initialized>ESS";
Lines 6092-6105 Link Here
6092
		new String[] {
6094
		new String[] {
6093
			"X.java",
6095
			"X.java",
6094
			"public class X {\n" + 
6096
			"public class X {\n" + 
6095
			"	void foo (int n) {\n" + 
6097
			"\n" + 
6096
			"   	synchronized (this) {\n" + 
6097
			"       	switch (n) {\n" + 
6098
			"       		case 1:\n" + 
6099
			"       		throw new NullPointerException();\n" + 
6100
			"			}\n" + 
6101
			"		}\n" + 
6102
			"	}\n" + 
6103
			"    public static void main(String args[]) {\n" + 
6098
			"    public static void main(String args[]) {\n" + 
6104
			"    	try {\n" + 
6099
			"    	try {\n" + 
6105
			"	    	new X().foo(1);\n" + 
6100
			"	    	new X().foo(1);\n" + 
Lines 6107-6112 Link Here
6107
			"	        System.out.println(\"SUCCESS\"); \n" + 
6102
			"	        System.out.println(\"SUCCESS\"); \n" + 
6108
			"    	}\n" + 
6103
			"    	}\n" + 
6109
			"    } \n" + 
6104
			"    } \n" + 
6105
			"\n" + 
6106
			"void foo (int n) {\n" + 
6107
			"    synchronized (this) {\n" + 
6108
			"        switch (n) {\n" + 
6109
			"        case 1:\n" + 
6110
			"            throw new NullPointerException();\n" + 
6111
			"        }\n" + 
6112
			"    }\n" + 
6113
			"}\n" + 
6110
			"}\n",
6114
			"}\n",
6111
		},
6115
		},
6112
		"SUCCESS",
6116
		"SUCCESS",
Lines 6117-6123 Link Here
6117
		null); // custom requestor
6121
		null); // custom requestor
6118
	
6122
	
6119
	String expectedOutput =
6123
	String expectedOutput =
6120
		"  // Method descriptor #15 (I)V\n" + 
6124
		"  // Method descriptor #20 (I)V\n" + 
6121
		"  // Stack: 2, Locals: 3\n" + 
6125
		"  // Stack: 2, Locals: 3\n" + 
6122
		"  void foo(int n);\n" + 
6126
		"  void foo(int n);\n" + 
6123
		"     0  aload_0 [this]\n" + 
6127
		"     0  aload_0 [this]\n" + 
Lines 6127-6135 Link Here
6127
		"     4  iload_1 [n]\n" + 
6131
		"     4  iload_1 [n]\n" + 
6128
		"     5  tableswitch default: 32\n" + 
6132
		"     5  tableswitch default: 32\n" + 
6129
		"          case 1: 24\n" + 
6133
		"          case 1: 24\n" + 
6130
		"    24  new java.lang.NullPointerException [16]\n" + 
6134
		"    24  new java.lang.NullPointerException [41]\n" + 
6131
		"    27  dup\n" + 
6135
		"    27  dup\n" + 
6132
		"    28  invokespecial java.lang.NullPointerException() [18]\n" + 
6136
		"    28  invokespecial java.lang.NullPointerException() [43]\n" + 
6133
		"    31  athrow\n" + 
6137
		"    31  athrow\n" + 
6134
		"    32  aload_2\n" + 
6138
		"    32  aload_2\n" + 
6135
		"    33  monitorexit\n" + 
6139
		"    33  monitorexit\n" + 
Lines 6142-6152 Link Here
6142
		"        [pc: 4, pc: 34] -> 37 when : any\n" + 
6146
		"        [pc: 4, pc: 34] -> 37 when : any\n" + 
6143
		"        [pc: 37, pc: 39] -> 37 when : any\n" + 
6147
		"        [pc: 37, pc: 39] -> 37 when : any\n" + 
6144
		"      Line numbers:\n" + 
6148
		"      Line numbers:\n" + 
6145
		"        [pc: 0, line: 3]\n" + 
6149
		"        [pc: 0, line: 12]\n" + 
6146
		"        [pc: 4, line: 4]\n" + 
6150
		"        [pc: 4, line: 13]\n" + 
6147
		"        [pc: 24, line: 6]\n" + 
6151
		"        [pc: 24, line: 15]\n" + 
6148
		"        [pc: 32, line: 3]\n" + 
6152
		"        [pc: 32, line: 12]\n" + 
6149
		"        [pc: 40, line: 9]\n" + 
6153
		"        [pc: 40, line: 18]\n" + 
6150
		"      Local variable table:\n" + 
6154
		"      Local variable table:\n" + 
6151
		"        [pc: 0, pc: 41] local: this index: 0 type: X\n" + 
6155
		"        [pc: 0, pc: 41] local: this index: 0 type: X\n" + 
6152
		"        [pc: 0, pc: 41] local: n index: 1 type: int\n";
6156
		"        [pc: 0, pc: 41] local: n index: 1 type: int\n";
(-)Eclipse Java Tests Compiler/org/eclipse/jdt/tests/compiler/regression/InitializationTest.java (-3 / +13 lines)
Lines 11-19 Link Here
11
public InitializationTest(String name) {
11
public InitializationTest(String name) {
12
	super(name);
12
	super(name);
13
}
13
}
14
public static Test suite() {
14
	// Static initializer to specify tests subset using TESTS_* static variables
15
	return setupSuite(testClass());
15
	// All specified tests which does not belong to the class are skipped...
16
}
16
	// Only the highest compliance level is run; add the VM argument
17
	// -Dcompliance=1.4 (for example) to lower it if needed
18
	static {
19
//		TESTS_NAMES = new String[] { "test011" };
20
//	 	TESTS_NUMBERS = new int[] { 58 };   
21
//		TESTS_RANGE = new int[] { 231, 240 }; 
22
	}
23
	public static Test suite() {
24
		return buildTestSuite(testClass());
25
	}
26
	
17
public void test001() {
27
public void test001() {
18
	this.runConformTest(
28
	this.runConformTest(
19
		new String[] {
29
		new String[] {
(-)Eclipse Java Tests Compiler/org/eclipse/jdt/tests/compiler/regression/InnerClassTest.java (-11 / +3 lines)
Lines 4-22 Link Here
4
import org.eclipse.jdt.core.tests.compiler.regression.*;
4
import org.eclipse.jdt.core.tests.compiler.regression.*;
5
5
6
public class InnerClassTest extends AbstractRegressionTest {
6
public class InnerClassTest extends AbstractRegressionTest {
7
static {
8
	// Names of tests to run: can be "testBugXXXX" or "BugXXXX")
9
//			TESTS_NAMES = new String[] { "Bug58069" };
10
	// Numbers of tests to run: "test<number>" will be run for each number of this array
11
//	TESTS_NUMBERS = new int[] { 183 };
12
	// Range numbers of tests to run: all tests between "test<first>" and "test<last>" will be run for { first, last }
13
//			TESTS_RANGE = new int[] { 85, -1 };
14
}
15
public InnerClassTest(String name) {
7
public InnerClassTest(String name) {
16
	super(name);
8
	super(name);
17
}
9
}
18
public static Test suite() {
10
public static Test suite() {
19
	return buildTestSuite(testClass());
11
	return setupSuite(testClass());
20
}
12
}
21
public void test001() {
13
public void test001() {
22
	this.runConformTest(new String[] {
14
	this.runConformTest(new String[] {
Lines 8827-8833 Link Here
8827
		"  }\n" + 
8819
		"  }\n" + 
8828
		"  public static void main( String args[] ) {\n" + 
8820
		"  public static void main( String args[] ) {\n" + 
8829
		"    Test02 t = new Test02();\n" + 
8821
		"    Test02 t = new Test02();\n" + 
8830
		"    Test02B b = new Test02B( t );  // Doesn\'t work. MUST provide enclosing instance with t.new B().\n" + 
8822
		"    Test02B b = new Test02B( t );  // Dosen\'t work. MUST provide enclosing instance with t.new B().\n" + 
8831
		"    System.out.println( b.varTest02B );\n" + 
8823
		"    System.out.println( b.varTest02B );\n" + 
8832
		"  }\n" + 
8824
		"  }\n" + 
8833
		"}",
8825
		"}",
Lines 8839-8845 Link Here
8839
		"Illegal enclosing instance specification for type Object\n" + 
8831
		"Illegal enclosing instance specification for type Object\n" + 
8840
		"----------\n" + 
8832
		"----------\n" + 
8841
		"2. ERROR in InnerClassTests\\PassingParameters\\Test02.java (at line 30)\n" + 
8833
		"2. ERROR in InnerClassTests\\PassingParameters\\Test02.java (at line 30)\n" + 
8842
		"	Test02B b = new Test02B( t );  // Doesn\'t work. MUST provide enclosing instance with t.new B().\n" + 
8834
		"	Test02B b = new Test02B( t );  // Dosen\'t work. MUST provide enclosing instance with t.new B().\n" + 
8843
		"	            ^^^^^^^^^^^^^^^^\n" + 
8835
		"	            ^^^^^^^^^^^^^^^^\n" + 
8844
		"No enclosing instance of type Test02 is accessible. Must qualify the allocation with an enclosing instance of type Test02 (e.g. x.new A() where x is an instance of Test02).\n" + 
8836
		"No enclosing instance of type Test02 is accessible. Must qualify the allocation with an enclosing instance of type Test02 (e.g. x.new A() where x is an instance of Test02).\n" + 
8845
		"----------\n"
8837
		"----------\n"
(-)Eclipse Java Tests Compiler/org/eclipse/jdt/tests/compiler/regression/InnerEmulationTest.java (-2 / +2 lines)
Lines 2791-2797 Link Here
2791
			"    public static void main(String[] args) {	\n"+
2791
			"    public static void main(String[] args) {	\n"+
2792
			"       System.out.print(\"SUCCESS\"); 	\n"+
2792
			"       System.out.print(\"SUCCESS\"); 	\n"+
2793
			"    }	\n"+
2793
			"    }	\n"+
2794
			"}"
2794
			"}	\n"
2795
		},
2795
		},
2796
		"SUCCESS");
2796
		"SUCCESS");
2797
}
2797
}
Lines 4542-4548 Link Here
4542
		"bar");
4542
		"bar");
4543
	// ensure synthetic access method got generated for enclosing field
4543
	// ensure synthetic access method got generated for enclosing field
4544
	String expectedOutput =
4544
	String expectedOutput =
4545
			"  // Method descriptor #6 ()V\n" + 
4545
		"  // Method descriptor #6 ()V\n" + 
4546
			"  // Stack: 1, Locals: 1\n" + 
4546
			"  // Stack: 1, Locals: 1\n" + 
4547
			"  X$Z();\n" + 
4547
			"  X$Z();\n" + 
4548
			"    0  aload_0 [this]\n" + 
4548
			"    0  aload_0 [this]\n" + 
(-)Eclipse Java Tests Compiler/org/eclipse/jdt/tests/compiler/regression/NegativeTest.java (-9 lines)
Lines 9-23 Link Here
9
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
9
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
10
10
11
public class NegativeTest extends AbstractRegressionTest {
11
public class NegativeTest extends AbstractRegressionTest {
12
// Use this static initializer to specify subset for tests
13
// All specified tests which does not belong to the class are skipped...
14
static {
15
//		TESTS_PREFIX = "testBug95521";
16
//		TESTS_NAMES = new String[] { "testBug83127a" };
17
//		TESTS_NUMBERS = new int[] { 218 };
18
//		TESTS_RANGE = new int[] { 23, -1 };
19
}
20
	
21
public NegativeTest(String name) {
12
public NegativeTest(String name) {
22
	super(name);
13
	super(name);
23
}
14
}
(-)Eclipse Java Tests Compiler/org/eclipse/jdt/tests/compiler/regression/RunPrivateCompilerTests.java (-3 lines)
Lines 40-48 Link Here
40
	if ((possibleComplianceLevels & AbstractCompilerTest.F_1_5) != 0) {
40
	if ((possibleComplianceLevels & AbstractCompilerTest.F_1_5) != 0) {
41
		all.addTest(AbstractCompilerTest.suiteForComplianceLevel(AbstractCompilerTest.COMPLIANCE_1_5, RegressionTestSetup.class, standardTests));
41
		all.addTest(AbstractCompilerTest.suiteForComplianceLevel(AbstractCompilerTest.COMPLIANCE_1_5, RegressionTestSetup.class, standardTests));
42
	}
42
	}
43
	if ((possibleComplianceLevels & AbstractCompilerTest.F_1_6) != 0) {
44
		all.addTest(AbstractCompilerTest.suiteForComplianceLevel(AbstractCompilerTest.COMPLIANCE_1_6, RegressionTestSetup.class, standardTests));
45
	}
46
	return all;
43
	return all;
47
}
44
}
48
}
45
}
(-)src/org/eclipse/jdt/core/tests/compiler/regression/AssignmentTest.java (-748 / +22 lines)
Lines 129-561 Link Here
129
		"The assignment to variable next has no effect\n" + 
129
		"The assignment to variable next has no effect\n" + 
130
		"----------\n");
130
		"----------\n");
131
}
131
}
132
/*
132
133
 * check null/non-null reference diagnosis
133
// final multiple assignment
134
 */
135
public void test003() {
136
	this.runNegativeTest(
137
		new String[] {
138
			"X.java",
139
			"public class X {\n" + 
140
			"	X foo(X x) {\n" + 
141
			"		x.foo(null);\n" + 
142
			"		if (x == null) {\n" + 
143
			"			x.foo(null);\n" + 
144
			"		}\n" + 
145
			"		return this;\n" + 
146
			"	}\n" + 
147
			"}\n",
148
		},
149
		"----------\n" + 
150
		"1. ERROR in X.java (at line 4)\n" + 
151
		"	if (x == null) {\n" + 
152
		"	    ^\n" + 
153
		"The variable x cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
154
		"----------\n" + 
155
		"2. ERROR in X.java (at line 5)\n" + 
156
		"	x.foo(null);\n" + 
157
		"	^\n" + 
158
		"The variable x can only be null; it was either set to null or checked for null when last used\n" + 
159
		"----------\n");
160
}
161
public void test004() {
162
	this.runNegativeTest(
163
		new String[] {
164
			"X.java",
165
			"public class X {\n" + 
166
			"	X foo(X x) {\n" + 
167
			"		x.foo(null); // 0\n" + 
168
			"		if (x != null) { // 1\n" + 
169
			"			if (x == null) { // 2\n" + 
170
			"				x.foo(null); // 3\n" + 
171
			"			} else if (x instanceof X) { // 4\n" + 
172
			"				x.foo(null); // 5 \n" + 
173
			"			} else if (x != null) { // 6\n" + 
174
			"				x.foo(null); // 7\n" + 
175
			"			}\n" + 
176
			"			x.foo(null); // 8\n" + 
177
			"		}\n" + 
178
			"		return this;\n" + 
179
			"	}\n" + 
180
			"}\n",
181
		},
182
		"----------\n" + 
183
		"1. ERROR in X.java (at line 4)\n" + 
184
		"	if (x != null) { // 1\n" + 
185
		"	    ^\n" + 
186
		"The variable x cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
187
		"----------\n" + 
188
		"2. ERROR in X.java (at line 5)\n" + 
189
		"	if (x == null) { // 2\n" + 
190
		"	    ^\n" + 
191
		"The variable x cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
192
		"----------\n" + 
193
		"3. ERROR in X.java (at line 6)\n" + 
194
		"	x.foo(null); // 3\n" + 
195
		"	^\n" + 
196
		"The variable x can only be null; it was either set to null or checked for null when last used\n" + 
197
		"----------\n" + 
198
		"4. ERROR in X.java (at line 9)\n" + 
199
		"	} else if (x != null) { // 6\n" + 
200
		"	           ^\n" + 
201
		"The variable x cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
202
		"----------\n");
203
}
204
public void test005() {
205
	this.runConformTest(
206
		new String[] {
207
			"X.java",
208
			"public class X {\n" + 
209
			"	void foo(Class c) {\n" + 
210
			"		if (c.isArray() ) {\n" + 
211
			"		} else if (c == java.lang.String.class ) {\n" + 
212
			"		}\n" + 
213
			"	}\n" + 
214
			"}\n",
215
		},
216
		"");
217
}
218
public void test006() {
219
	this.runConformTest(
220
		new String[] {
221
			"X.java",
222
			"public class X {\n" + 
223
			"	void foo(X x) {\n" + 
224
			"		if (x == this)\n" + 
225
			"			return;\n" + 
226
			"		x.foo(this);\n" + 
227
			"	}\n" + 
228
			"}\n",
229
		},
230
		"");
231
}
232
public void test007() {
233
	this.runConformTest(
234
		new String[] {
235
			"X.java",
236
			"public class X {\n" + 
237
			"	void foo(X x, X x2) {\n" + 
238
			"		if (x != null)\n" + 
239
			"			return;\n" + 
240
			"		x = x2;\n" + 
241
			"		if (x == null) {\n" + 
242
			"		}\n" + 
243
			"	}\n" + 
244
			"}\n",
245
		},
246
		"");
247
}
248
public void test008() {
249
	this.runConformTest(
250
		new String[] {
251
			"X.java",
252
			"public class X {\n" + 
253
			"	void foo(X x, X x2) {\n" + 
254
			"		if (x != null)\n" + 
255
			"			return;\n" + 
256
			"		try {\n" + 
257
			"			x = x2;\n" + 
258
			"		} catch(Exception e) {}\n" + 
259
			"		if (x == null) {\n" + 
260
			"		}\n" + 
261
			"	}\n" + 
262
			"}\n",
263
		},
264
		"");
265
}
266
// TODO (philippe) reenable once fixed
267
public void _test009() {
268
	this.runNegativeTest(
269
		new String[] {
270
			"X.java",
271
			"import java.io.File;\n" + 
272
			"\n" + 
273
			"public class X {\n" + 
274
			"	boolean check(String name) { return true; }\n" + 
275
			"	Class bar(String name) throws ClassNotFoundException { return null; }\n" + 
276
			"	File baz(String name) { return null; }\n" + 
277
			"	\n" + 
278
			"	public Class foo(String name, boolean resolve) throws ClassNotFoundException {\n" + 
279
			"			\n" + 
280
			"		Class c = bar(name);\n" + 
281
			"		if (c != null)\n" + 
282
			"			return c;\n" + 
283
			"		if (check(name)) {\n" + 
284
			"			try {\n" + 
285
			"				c= bar(name);\n" + 
286
			"				return c;\n" + 
287
			"			} catch (ClassNotFoundException e) {\n" + 
288
			"				// keep searching\n" + 
289
			"				// only path to here left c unassigned from try block, means it was assumed to be null\n" + 
290
			"			}\n" + 
291
			"		}\n" + 
292
			"		if (c == null) {// should complain: c can only be null\n" + 
293
			"			File file= baz(name);\n" + 
294
			"			if (file == null)\n" + 
295
			"				throw new ClassNotFoundException();\n" + 
296
			"		}\n" + 
297
			"		return c;\n" + 
298
			"	}\n" + 
299
			"\n" + 
300
			"}\n",
301
		},
302
		"----------\n" + 
303
		"1. ERROR in X.java (at line 22)\n" + 
304
		"	if (c == null) {// should complain: c can only be null\n" + 
305
		"	    ^\n" + 
306
		"The variable c can only be null; it was either set to null or checked for null when last used\n" + 
307
		"----------\n");
308
}
309
public void test010() {
310
	this.runConformTest(
311
		new String[] {
312
			"X.java",
313
			"public class X {\n" + 
314
			"\n" + 
315
			"	X itself() { return this; }\n" + 
316
			"\n" + 
317
			"	void bar() {\n" + 
318
			"		X itself = this.itself();\n" + 
319
			"		if (this == itself) {\n" + 
320
			"			System.out.println(itself.toString()); //1\n" + 
321
			"		} else {\n" + 
322
			"			System.out.println(itself.toString()); //2\n" + 
323
			"		}\n" + 
324
			"	}\n" + 
325
			"}\n",
326
		},
327
		"");
328
}
329
public void test011() {
330
	this.runNegativeTest(
331
		new String[] {
332
			"X.java",
333
			"public class X {\n" + 
334
			"\n" + 
335
			"	X itself() { return this; }\n" + 
336
			"\n" + 
337
			"	void bar() {\n" + 
338
			"		X itself = this.itself();\n" + 
339
			"		if (this == itself) {\n" + 
340
			"			X other = (X)itself;\n" + 
341
			"			if (other != null) {\n" + 
342
			"			}\n" + 
343
			"			if (other == null) {\n" + 
344
			"			}\n" + 
345
			"		}\n" + 
346
			"	}\n" + 
347
			"}\n",
348
		},
349
		"----------\n" + 
350
		"1. ERROR in X.java (at line 9)\n" + 
351
		"	if (other != null) {\n" + 
352
		"	    ^^^^^\n" + 
353
		"The variable other cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
354
		"----------\n");
355
}
356
public void test012() {
357
	this.runConformTest(
358
		new String[] {
359
			"X.java",
360
			"public class X {\n" + 
361
			"	\n" + 
362
			"	void foo() {\n" + 
363
			"		Object o = null;\n" + 
364
			"		do {\n" + 
365
			"			if (o == null) return;\n" + 
366
			"			o = bar();\n" + 
367
			"		} while (true);\n" + 
368
			"	}\n" + 
369
			"	X bar() { \n" + 
370
			"		return null; \n" + 
371
			"	}\n" + 
372
			"}",
373
		},
374
		"");
375
}
376
public void test013() {
377
	this.runNegativeTest(
378
		new String[] {
379
			"X.java",
380
			"public class X {\n" + 
381
			"	void foo(X x) {\n" + 
382
			"		if (x == this) {\n" + 
383
			"			if (x == null) {\n" + 
384
			"				x.foo(this);\n" + 
385
			"			}\n" + 
386
			"		}\n" + 
387
			"	}\n" + 
388
			"}\n",
389
		},
390
		"----------\n" + 
391
		"1. ERROR in X.java (at line 4)\n" + 
392
		"	if (x == null) {\n" + 
393
		"	    ^\n" + 
394
		"The variable x cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
395
		"----------\n" + 
396
		"2. ERROR in X.java (at line 5)\n" + 
397
		"	x.foo(this);\n" + 
398
		"	^\n" + 
399
		"The variable x can only be null; it was either set to null or checked for null when last used\n" + 
400
		"----------\n");
401
}
402
public void test014() {
403
	this.runConformTest(
404
		new String[] {
405
			"X.java",
406
			"public class X {\n" + 
407
			"	void foo(X x) {\n" + 
408
			"		x = null;\n" + 
409
			"		try {\n" + 
410
			"			x = this;\n" + 
411
			"		} finally {\n" + 
412
			"			if (x != null) {\n" + 
413
			"				x.foo(null);\n" + 
414
			"			}\n" + 
415
			"		}\n" + 
416
			"	}\n" + 
417
			"}\n",
418
		},
419
		"");
420
}
421
public void test015() {
422
	this.runConformTest(
423
		new String[] {
424
			"X.java",
425
			"public class X {\n" + 
426
			"    void foo() {\n" + 
427
			"       Object o = null;\n" + 
428
			"       int i = 1;\n" + 
429
			"       switch (i) {\n" + 
430
			"          case 1:\n" + 
431
			"             o = new Object();\n" + 
432
			"             break;\n" + 
433
			"       }\n" + 
434
			"       if (o != null)\n" + 
435
			"            o.toString();\n" + 
436
			"    }\n" + 
437
			"}\n",
438
		},
439
		"");
440
}
441
public void test016() {
442
	this.runNegativeTest(
443
		new String[] {
444
			"X.java",
445
			"public class X {\n" + 
446
			"	void foo(X x) {\n" + 
447
			"		x = null;\n" + 
448
			"		try {\n" + 
449
			"			x = null;\n" + 
450
			"		} finally {\n" + 
451
			"			if (x != null) {\n" + 
452
			"				x.foo(null);\n" + 
453
			"			}\n" + 
454
			"		}\n" + 
455
			"	}\n" + 
456
			"}\n",
457
		},
458
		"----------\n" + 
459
		"1. ERROR in X.java (at line 5)\n" + 
460
		"	x = null;\n" + 
461
		"	^\n" + 
462
		"The variable x can only be null; it was either set to null or checked for null when last used\n" + 
463
		"----------\n" + 
464
		"2. ERROR in X.java (at line 7)\n" + 
465
		"	if (x != null) {\n" + 
466
		"	    ^\n" + 
467
		"The variable x can only be null; it was either set to null or checked for null when last used\n" + 
468
		"----------\n");
469
}
470
public void test017() {
471
	this.runNegativeTest(
472
		new String[] {
473
			"X.java",
474
			"public class X {\n" + 
475
			"	void foo(X x) {\n" + 
476
			"		x = this;\n" + 
477
			"		try {\n" + 
478
			"			x = null;\n" + 
479
			"		} finally {\n" + 
480
			"			if (x == null) {\n" + 
481
			"				x.foo(null);\n" + 
482
			"			}\n" + 
483
			"		}\n" + 
484
			"	}\n" + 
485
			"}\n",
486
		},
487
		"----------\n" + 
488
		"1. ERROR in X.java (at line 7)\n" + 
489
		"	if (x == null) {\n" + 
490
		"	    ^\n" + 
491
		"The variable x can only be null; it was either set to null or checked for null when last used\n" + 
492
		"----------\n" + 
493
		"2. ERROR in X.java (at line 8)\n" + 
494
		"	x.foo(null);\n" + 
495
		"	^\n" + 
496
		"The variable x can only be null; it was either set to null or checked for null when last used\n" + 
497
		"----------\n");
498
}
499
public void test018() {
500
	this.runNegativeTest(
501
		new String[] {
502
			"X.java",
503
			"public class X {\n" + 
504
			"	\n" + 
505
			"	void foo() {\n" + 
506
			"		Object o = null;\n" + 
507
			"		do {\n" + 
508
			"			if (o != null) return;\n" + 
509
			"			o = null;\n" + 
510
			"		} while (true);\n" + 
511
			"	}\n" + 
512
			"	X bar() { \n" + 
513
			"		return null; \n" + 
514
			"	}\n" + 
515
			"}",
516
		},
517
		"----------\n" + 
518
		"1. ERROR in X.java (at line 6)\r\n" + 
519
		"	if (o != null) return;\r\n" + 
520
		"	    ^\n" + 
521
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
522
		"----------\n" + 
523
		"2. ERROR in X.java (at line 7)\r\n" + 
524
		"	o = null;\r\n" + 
525
		"	^\n" + 
526
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
527
		"----------\n");
528
}
529
public void test019() {
530
	this.runConformTest(
531
		new String[] {
532
			"X.java",
533
			"public class X {\n" + 
534
			"	public static final char[] replaceOnCopy(\n" + 
535
			"		char[] array,\n" + 
536
			"		char toBeReplaced,\n" + 
537
			"		char replacementChar) {\n" + 
538
			"		\n" + 
539
			"		char[] result = null;\n" + 
540
			"		for (int i = 0, length = array.length; i < length; i++) {\n" + 
541
			"			char c = array[i];\n" + 
542
			"			if (c == toBeReplaced) {\n" + 
543
			"				if (result == null) {\n" + 
544
			"					result = new char[length];\n" + 
545
			"					System.arraycopy(array, 0, result, 0, i);\n" + 
546
			"				}\n" + 
547
			"				result[i] = replacementChar;\n" + 
548
			"			} else if (result != null) {\n" + 
549
			"				result[i] = c;\n" + 
550
			"			}\n" + 
551
			"		}\n" + 
552
			"		if (result == null) return array;\n" + 
553
			"		return result;\n" + 
554
			"	}\n" + 
555
			"}\n",
556
		},
557
		"");
558
}
559
public void test020() {
134
public void test020() {
560
	this.runNegativeTest(
135
	this.runNegativeTest(
561
		new String[] {
136
		new String[] {
Lines 582-901 Link Here
582
		"The final local variable v may already have been assigned\n" + 
157
		"The final local variable v may already have been assigned\n" + 
583
		"----------\n");
158
		"----------\n");
584
}
159
}
585
public void test021() {
160
586
	this.runConformTest(
161
// null part has been repeated into NullReferenceTest#test1033
587
		new String[] {
588
			"X.java",
589
			"public class X {\n" + 
590
			"	int kind;\n" + 
591
			"	X parent;\n" + 
592
			"	Object[] foo() { return null; }\n" + 
593
			"	private void findTypeParameters(X scope) {\n" + 
594
			"		Object[] typeParameters = null;\n" + 
595
			"		while (scope != null) {\n" + 
596
			"			typeParameters = null;\n" + 
597
			"			switch (scope.kind) {\n" + 
598
			"				case 0 :\n" + 
599
			"					typeParameters = foo();\n" + 
600
			"					break;\n" + 
601
			"				case 1 :\n" + 
602
			"					typeParameters = foo();\n" + 
603
			"					break;\n" + 
604
			"				case 2 :\n" + 
605
			"					return;\n" + 
606
			"			}\n" + 
607
			"			if(typeParameters != null) {\n" + 
608
			"				foo();\n" + 
609
			"			}\n" + 
610
			"			scope = scope.parent;\n" + 
611
			"		}\n" + 
612
			"	}\n" + 
613
			"}\n",
614
		},
615
		"");
616
}
617
public void test022() {
618
	this.runConformTest(
619
		new String[] {
620
			"X.java",
621
			"public class X {\n" + 
622
			"	\n" + 
623
			"	boolean bool() { return true; }\n" + 
624
			"	void doSomething() {}\n" + 
625
			"	\n" + 
626
			"	void foo() {\n" + 
627
			"		Object progressJob = null;\n" + 
628
			"		while (bool()) {\n" + 
629
			"			if (bool()) {\n" + 
630
			"				if (progressJob != null)\n" + 
631
			"					progressJob = null;\n" + 
632
			"				doSomething();\n" + 
633
			"			}\n" + 
634
			"			try {\n" + 
635
			"				if (progressJob == null) {\n" + 
636
			"					progressJob = new Object();\n" + 
637
			"				}\n" + 
638
			"			} finally {\n" + 
639
			"				doSomething();\n" + 
640
			"			}\n" + 
641
			"		}\n" + 
642
			"	}\n" + 
643
			"}",
644
		},
645
		"");
646
}
647
public void test023() {
648
	this.runNegativeTest(
649
		new String[] {
650
			"X.java",
651
			"public class X {\n" + 
652
			"\n" + 
653
			"	void foo() {\n" + 
654
			"		Object o = new Object();\n" + 
655
			"		while (this != null) {\n" + 
656
			"			try {\n" + 
657
			"				o = null;\n" + 
658
			"				break;\n" + 
659
			"			} finally {\n" + 
660
			"				o = new Object();\n" + 
661
			"			}\n" + 
662
			"		}\n" + 
663
			"		if (o == null) return;\n" + 
664
			"	}\n" + 
665
			"}\n",
666
		},
667
		"----------\n" + 
668
		"1. ERROR in X.java (at line 13)\n" + 
669
		"	if (o == null) return;\n" + 
670
		"	    ^\n" + 
671
		"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
672
		"----------\n");
673
}
674
public void test024() {
675
	this.runNegativeTest(
676
		new String[] {
677
			"X.java",
678
			"public class X {\n" + 
679
			"	\n" + 
680
			"	boolean bool() { return true; }\n" + 
681
			"	void doSomething() {}\n" + 
682
			"	\n" + 
683
			"	void foo() {\n" + 
684
			"		Object progressJob = null;\n" + 
685
			"		while (bool()) {\n" + 
686
			"			if (progressJob != null)\n" + 
687
			"				progressJob = null;\n" + 
688
			"			doSomething();\n" + 
689
			"			try {\n" + 
690
			"				if (progressJob == null) {\n" + 
691
			"					progressJob = new Object();\n" + 
692
			"				}\n" + 
693
			"			} finally {\n" + 
694
			"				doSomething();\n" + 
695
			"			}\n" + 
696
			"		}\n" + 
697
			"	}\n" + 
698
			"}",
699
		},
700
		"----------\n" + 
701
		"1. ERROR in X.java (at line 13)\n" + 
702
		"	if (progressJob == null) {\n" + 
703
		"	    ^^^^^^^^^^^\n" + 
704
		"The variable progressJob can only be null; it was either set to null or checked for null when last used\n" + 
705
		"----------\n");
706
}
707
public void test025() {
708
	this.runNegativeTest(
709
		new String[] {
710
			"X.java",
711
			"public class X {\n" + 
712
			"	\n" + 
713
			"	void foo() {\n" + 
714
			"		Object o;\n" + 
715
			"		try {\n" + 
716
			"			o = null;\n" + 
717
			"		} finally {\n" + 
718
			"			o = new Object();\n" + 
719
			"		}\n" + 
720
			"		if (o == null) return;\n" + 
721
			"	}\n" + 
722
			"}\n",
723
		},
724
		"----------\n" + 
725
		"1. ERROR in X.java (at line 10)\n" + 
726
		"	if (o == null) return;\n" + 
727
		"	    ^\n" + 
728
		"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
729
		"----------\n");
730
}
731
// TODO (philippe) reenable once fixed
732
public void _test026() {
733
	this.runConformTest(
734
		new String[] {
735
			"X.java",
736
			"public class X {\n" + 
737
			"	\n" + 
738
			"	public static void main(String[] args) {\n" + 
739
			"		Object o;\n" + 
740
			"		try {\n" + 
741
			"			o = null;\n" + 
742
			"		} finally {\n" + 
743
			"			if (args == null) o = new Object();\n" + 
744
			"		}\n" + 
745
			"		if (o == null) System.out.println(\"SUCCESS\");\n" + 
746
			"	}\n" + 
747
			"}\n",
748
		},
749
		"SUCCESS");
750
}
751
// TODO (philippe) reenable once fixed
752
public void _test027() {
753
	this.runConformTest(
754
		new String[] {
755
			"X.java",
756
			"public class X {\n" + 
757
			"	boolean b;\n" + 
758
			"	void foo() {\n" + 
759
			"		Object o = null;\n" + 
760
			"		while (b) {\n" + 
761
			"			try {\n" + 
762
			"				o = null;\n" + 
763
			"			} finally {\n" + 
764
			"				if (o == null) \n" + 
765
			"					o = new Object();\n" + 
766
			"			}\n" + 
767
			"		}\n" + 
768
			"		if (o == null) return;\n" + 
769
			"	}\n" + 
770
			"}\n",
771
		},
772
		"");
773
}
774
// TODO (philippe) reenable once fixed
775
public void _test028() {
776
	this.runConformTest(
777
		new String[] {
778
			"X.java",
779
			"public class X {\n" + 
780
			"	boolean b;\n" + 
781
			"	void foo() {\n" + 
782
			"		Object o = null;\n" + 
783
			"		while (b) {\n" + 
784
			"			try {\n" + 
785
			"				o = null;\n" + 
786
			"				break;\n" + 
787
			"			} finally {\n" + 
788
			"				if (o == null) \n" + 
789
			"					o = new Object();\n" + 
790
			"			}\n" + 
791
			"		}\n" + 
792
			"		if (o == null) return;\n" + 
793
			"	}\n" + 
794
			"}\n",
795
		},
796
		"");
797
}
798
public void test029() {
799
	this.runConformTest(
800
		new String[] {
801
			"X.java",
802
			"public class X {\n" + 
803
			"	public static void main(String[] args) {\n" + 
804
			"		Object o = null;\n" + 
805
			"		int i = 0;\n" + 
806
			"		while (i++ < 2) {\n" + 
807
			"			try {\n" + 
808
			"				if (i == 2) return;\n" + 
809
			"				o = null;\n" + 
810
			"			} finally {\n" + 
811
			"				if (i == 2) System.out.println(o);\n" + 
812
			"				if (o == null) \n" + 
813
			"					o = \"SUCCESS\";\n" + 
814
			"			}\n" + 
815
			"		}\n" + 
816
			"		if (o == null) return;\n" + 
817
			"	}\n" + 
818
			"}\n",
819
		},
820
		"SUCCESS");
821
}
822
public void test030() {
823
	this.runNegativeTest(
824
		new String[] {
825
			"X.java",
826
			"public class X {\n" + 
827
			"	\n" + 
828
			"	void foo() {\n" + 
829
			"		Object a = null;\n" + 
830
			"		while (true) {\n" + 
831
			"			a = null;\n" + 
832
			"			if (a == null) {\n" + 
833
			"				System.out.println();\n" + 
834
			"			}\n" + 
835
			"			a = new Object();\n" + 
836
			"			break;\n" + 
837
			"		}\n" + 
838
			"	}\n" + 
839
			"}\n",
840
		},
841
		"----------\n" + 
842
		"1. ERROR in X.java (at line 7)\n" + 
843
		"	if (a == null) {\n" + 
844
		"	    ^\n" + 
845
		"The variable a can only be null; it was either set to null or checked for null when last used\n" + 
846
		"----------\n");
847
}
848
// TODO (philippe) reenable once fixed
849
public void _test031() {
850
	this.runNegativeTest(
851
		new String[] {
852
			"X.java",
853
			"public class X {\n" + 
854
			"	\n" + 
855
			"	void foo() {\n" + 
856
			"		Object a = null;\n" + 
857
			"		while (true) {\n" + 
858
			"			a = null;\n" + 
859
			"			if (a == null) {\n" + 
860
			"				System.out.println();\n" + 
861
			"			}\n" + 
862
			"			a = new Object();\n" + 
863
			"			break;\n" + 
864
			"		}\n" + 
865
			"		if (a == null) {\n" + 
866
			"			System.out.println();\n" + 
867
			"		}\n" + 
868
			"	}\n" + 
869
			"}\n",
870
		},
871
		"----------\n" + 
872
		"1. ERROR in X.java (at line 7)\n" + 
873
		"	if (a == null) {\n" + 
874
		"	    ^\n" + 
875
		"The variable a can only be null; it was either set to null or checked for null when last used\n" + 
876
		"----------\n" + 
877
		"2. ERROR in X.java (at line 13)\n" + 
878
		"	if (a == null) {\n" + 
879
		"	    ^\n" + 
880
		"The variable a cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
881
		"----------\n");
882
}
883
public void test032() {
884
	this.runConformTest(
885
		new String[] {
886
			"X.java",
887
			"public class X {\n" + 
888
			"	void foo() {\n" + 
889
			"		Object o1 = this;\n" + 
890
			"		Object o3;\n" + 
891
			"		while (o1 != null && (o3 = o1) != null) {\n" + 
892
			"			o1 = o3;\n" + 
893
			"		}\n" + 
894
			"	}\n" + 
895
			"}\n",
896
		},
897
		"");
898
}
899
public void test033() {
162
public void test033() {
900
	this.runNegativeTest(
163
	this.runNegativeTest(
901
		new String[] {
164
		new String[] {
Lines 917-933 Link Here
917
			"}\n",
180
			"}\n",
918
		},
181
		},
919
		"----------\n" + 
182
		"----------\n" + 
920
		"1. ERROR in X.java (at line 9)\n" + 
183
		"1. ERROR in X.java (at line 7)\n" + 
184
		"	}while(a!=null);\n" + 
185
		"	       ^\n" + 
186
		"The variable a cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
187
		"----------\n" + 
188
		"2. ERROR in X.java (at line 9)\n" + 
921
		"	if(a!=null)\n" + 
189
		"	if(a!=null)\n" + 
922
		"	   ^\n" + 
190
		"	   ^\n" + 
923
		"The variable a cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
191
		"The variable a can only be null; it was either set to null or checked for null when last used\n" + 
924
		"----------\n" + 
192
		"----------\n" + 
925
		"2. ERROR in X.java (at line 13)\n" + 
193
		"3. ERROR in X.java (at line 13)\n" + 
926
		"	System.out.println(a+b);\n" + 
194
		"	System.out.println(a+b);\n" + 
927
		"	                     ^\n" + 
195
		"	                     ^\n" + 
928
		"The local variable b may not have been initialized\n" + 
196
		"The local variable b may not have been initialized\n" + 
929
		"----------\n");
197
		"----------\n");
930
}
198
}
199
931
//https://bugs.eclipse.org/bugs/show_bug.cgi?id=84215
200
//https://bugs.eclipse.org/bugs/show_bug.cgi?id=84215
932
//TODO (philippe) should move to InitializationTest suite
201
//TODO (philippe) should move to InitializationTest suite
933
public void test034() {
202
public void test034() {
Lines 1293-1299 Link Here
1293
			"			{\n" + 
562
			"			{\n" + 
1294
			"				try\n" + 
563
			"				try\n" + 
1295
			"				{\n" + 
564
			"				{\n" + 
1296
			"					rs.toString();\n" + 
565
			"					rs.toString();\n" +
1297
			"				}\n" + 
566
			"				}\n" + 
1298
			"				catch (Exception ex)\n" + 
567
			"				catch (Exception ex)\n" + 
1299
			"				{\n" + 
568
			"				{\n" + 
Lines 1357-1366 Link Here
1357
			"}\n",
626
			"}\n",
1358
		},
627
		},
1359
		"----------\n" + 
628
		"----------\n" + 
1360
		"1. ERROR in X.java (at line 8)\r\n" + 
629
		"1. ERROR in X.java (at line 7)\n" + 
1361
		"	if (o == null) {\r\n" + 
630
		"	} while (o != null);\n" + 
631
		"	         ^\n" + 
632
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
633
		"----------\n" + 
634
		"2. ERROR in X.java (at line 8)\n" + 
635
		"	if (o == null) {\n" + 
1362
		"	    ^\n" + 
636
		"	    ^\n" + 
1363
		"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
637
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
1364
		"----------\n");
638
		"----------\n");
1365
}
639
}
1366
//https://bugs.eclipse.org/bugs/show_bug.cgi?id=93588
640
//https://bugs.eclipse.org/bugs/show_bug.cgi?id=93588
(-)src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java (+49 lines)
Lines 2530-2535 Link Here
2530
        false);
2530
        false);
2531
}
2531
}
2532
2532
2533
// null ref option
2534
public void test044(){
2535
	this.runConformTest(
2536
		new String[] {
2537
			"X.java",
2538
			"public class X {\n" + 
2539
			"  void foo() {\n" + 
2540
			"    Object o = null;\n" + 
2541
			"    o.toString();\n" + 
2542
			"  }\n" + 
2543
			"}"},
2544
        "\"" + OUTPUT_DIR +  File.separator + "X.java\""
2545
        + " -1.5 -g -preserveAllLocals"
2546
        + " -bootclasspath " + JRE_HOME_DIR + "/lib/rt.jar"
2547
        + " -cp " + JRE_HOME_DIR + "/lib/jce.jar"
2548
        + " -warn:+null"
2549
        + " -proceedOnError -referenceInfo -d \"" + OUTPUT_DIR + "\"",
2550
        "", 
2551
        "----------\n" + 
2552
        "1. WARNING in ---OUTPUT_DIR_PLACEHOLDER---" + File.separator + "X.java\n" + 
2553
		" (at line 4)\n" + 
2554
		"	o.toString();\n" + 
2555
		"	^\n" + 
2556
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
2557
		"----------\n" + 
2558
		"1 problem (1 warning)", true);
2559
}
2560
2561
// null ref option
2562
public void test045(){
2563
	this.runConformTest(
2564
		new String[] {
2565
			"X.java",
2566
			"public class X {\n" + 
2567
			"  void foo() {\n" + 
2568
			"    Object o = null;\n" + 
2569
			"    o.toString();\n" + 
2570
			"  }\n" + 
2571
			"}"},
2572
        "\"" + OUTPUT_DIR +  File.separator + "X.java\""
2573
        + " -1.5 -g -preserveAllLocals"
2574
        + " -bootclasspath " + JRE_HOME_DIR + "/lib/rt.jar"
2575
        + " -cp " + JRE_HOME_DIR + "/lib/jce.jar"
2576
        + " -warn:-null" // contrast with test036
2577
        + " -proceedOnError -referenceInfo -d \"" + OUTPUT_DIR + "\"",
2578
        "", 
2579
        "", true);
2580
}
2581
2533
public static Class testClass() {
2582
public static Class testClass() {
2534
	return BatchCompilerTest.class;
2583
	return BatchCompilerTest.class;
2535
}
2584
}
(-)src/org/eclipse/jdt/core/tests/compiler/regression/NullReferenceTest.java (-2370 / +8834 lines)
Lines 12-2538 Link Here
12
12
13
import java.util.Map;
13
import java.util.Map;
14
14
15
import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
16
import org.eclipse.jdt.internal.compiler.flow.UnconditionalFlowInfo;
15
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
17
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
18
import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
19
import org.eclipse.jdt.internal.core.Assert.AssertionFailedException;
16
20
21
import junit.framework.AssertionFailedError;
17
import junit.framework.Test;
22
import junit.framework.Test;
18
23
19
public class NullReferenceTest extends AbstractRegressionTest {
24
public class NullReferenceTest extends AbstractRegressionTest {
20
25
21
	public NullReferenceTest(String name) {
26
public NullReferenceTest(String name) {
22
		super(name);
27
    super(name);
23
	}
28
}
24
29
25
	// Static initializer to specify tests subset using TESTS_* static variables
30
	// Static initializer to specify tests subset using TESTS_* static variables
26
	// All specified tests which does not belong to the class are skipped...
31
  	// All specified tests which does not belong to the class are skipped...
27
	// Only the highest compliance level is run; add the VM argument
32
  	// Only the highest compliance level is run; add the VM argument
28
	// -Dcompliance=1.4 (for example) to lower it if needed
33
  	// -Dcompliance=1.4 (for example) to lower it if needed
29
	static {
34
  	static {
30
//		TESTS_NAMES = new String[] { "test011" };
35
//    	TESTS_NAMES = new String[] { "test011" };
31
//	 	TESTS_NUMBERS = new int[] { 2 };   
36
//    	TESTS_NUMBERS = new int[] { 729 };   
32
//		TESTS_RANGE = new int[] { 231, 240 }; 
37
//    	TESTS_NUMBERS = new int[] { 2999 };   
33
	}
38
//    	TESTS_RANGE = new int[] { 2050, -1 }; 
34
	public static Test suite() {
39
//  	TESTS_RANGE = new int[] { 1, 2049 }; 
35
		return buildTestSuite(testClass());
40
//  	TESTS_RANGE = new int[] { 449, 451 }; 
36
	}
41
//    	TESTS_RANGE = new int[] { 900, 999 }; 
37
	
42
  	}
38
	public static Class testClass() {
39
		return NullReferenceTest.class;
40
	}
41
43
42
	// Augment problem detection settings
44
public static Test suite() {
43
	protected Map getCompilerOptions() {
45
    return buildTestSuite(testClass());
44
		Map defaultOptions = super.getCompilerOptions();
46
}
45
		defaultOptions.put(CompilerOptions.OPTION_ReportNullReference, CompilerOptions.WARNING);
47
  
46
		defaultOptions.put(CompilerOptions.OPTION_ReportNoEffectAssignment, CompilerOptions.WARNING);
48
public static Class testClass() {
47
		return defaultOptions;
49
    return NullReferenceTest.class;
48
	}
50
}
49
	
51
50
	// null analysis -- simple case for local
52
// Augment problem detection settings
51
	public void test0001_simple_local() {
53
protected Map getCompilerOptions() {
52
		this.runNegativeTest(
54
    Map defaultOptions = super.getCompilerOptions();
53
			new String[] {
55
//    defaultOptions.put(CompilerOptions.OPTION_ReportNullReference, CompilerOptions.WARNING);
54
				"X.java",
56
    defaultOptions.put(CompilerOptions.OPTION_ReportNullReference, CompilerOptions.ERROR);
55
				"public class X {\n" + 
57
//    defaultOptions.put(CompilerOptions.OPTION_ReportNoEffectAssignment, CompilerOptions.WARNING);
56
				"	 void foo() {\n" + 
58
    return defaultOptions;
57
				"		 Object o = null;\n" + 
59
}
58
				"		 o.toString();\n" + 
60
  
59
				"	 }\n" + 
61
// null analysis -- simple case for local
60
				"}\n"},
62
public void test0001_simple_local() {
61
			"----------\n" + 
63
	this.runNegativeTest(
62
			"1. WARNING in X.java (at line 4)\n" + 
64
		new String[] {
63
			"	o.toString();\n" + 
65
			"X.java",
64
			"	^\n" + 
66
			  "public class X {\n" + 
65
			"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
67
			  "  void foo() {\n" + 
66
			"----------\n"
68
			  "    Object o = null;\n" + 
67
		);
69
			  "    o.toString();\n" + 
68
	}
70
			  "  }\n" + 
69
	
71
			  "}\n"},
70
	// null analysis -- simple case for field
72
	    "----------\n" + 
71
	// despite the fact that a separate thread may update the field,
73
	    "1. ERROR in X.java (at line 4)\n" + 
72
	// a comprehensive warning policy could point this case as potentially
74
	    "	o.toString();\n" + 
73
	// harmful -- this is not the current design, thow; it takes a 
75
	    "	^\n" + 
74
	// conservative approach and leaves fields out of the analysis altogether
76
	    "The variable o can only be null; it was either set to null or checked for null when last used\n" + 
75
	// TODO (maxime) reset diagnostic once supported
77
	    "----------\n");
76
	public void test0002_simple_field() {
78
}
77
		this.runNegativeTest(
79
  
78
			new String[] {
80
// null analysis -- simple case for field
79
				"X.java",
81
// the current design leaves fields out of the analysis altogether
80
				"public class X {\n" + 
82
public void test0002_simple_field() {
81
				"  Object o;\n" + 
83
	this.runNegativeTest(
82
				"	 void foo() {\n" + 
84
		new String[] {
83
				"		 o = null;\n" + 
85
			"X.java",
84
				"	 	 o.toString();\n" + 
86
			"public class X {\n" + 
85
				"	 }\n" + 
87
			"  Object o;\n" + 
86
				"}\n"},
88
			"  void foo() {\n" + 
89
			"    o = null;\n" + 
90
			"    o.toString();\n" + 
91
			"  }\n" + 
92
			"}\n"},
93
	""
94
//      "----------\n" + 
95
//      "1. ERROR in X.java (at line 5)\n" + 
96
//      "	o.toString();\n" + 
97
//      "	^\n" + 
98
//      "The field o is likely null; it was either set to null or checked for null when last used\n" + 
99
//      "----------\n"
100
	);
101
}
102
103
// null analysis -- simple case for parameter
104
public void test0003_simple_parameter() {
105
	this.runNegativeTest(
106
		new String[] {
107
			"X.java",
108
			"public class X {\n" + 
109
			"  void foo(Object o) {\n" + 
110
			"    o = null;\n" + 
111
			"    o.toString();\n" + 
112
			"  }\n" + 
113
			"}\n"},
114
		"----------\n" + 
115
		"1. ERROR in X.java (at line 4)\n" + 
116
		"	o.toString();\n" + 
117
		"	^\n" + 
118
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
119
		"----------\n");
120
}
121
122
// null analysis -- final local
123
public void test0004_final_local() {
124
	this.runNegativeTest(
125
		new String[] {
126
			"X.java",
127
			"public class X {\n" + 
128
			"  void foo() {\n" +        
129
			"    final Object o = null;\n" + 
130
			"    o.toString();\n" + 
131
			"  }\n" + 
132
			"}\n"},
133
		"----------\n" + 
134
		"1. ERROR in X.java (at line 4)\n" + 
135
		"	o.toString();\n" + 
136
		"	^\n" + 
137
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
138
		"----------\n");
139
}
140
141
// null analysis -- final local
142
public void test0005_final_local() {
143
	this.runNegativeTest(
144
		new String[] {
145
			"X.java",
146
			"public class X {\n" + 
147
			"  void foo() {\n" +        
148
			"    final Object o;\n" + 
149
			"    o.toString();\n" + 
150
			"  }\n" + 
151
			"}\n"},
152
		"----------\n" + 
153
		"1. ERROR in X.java (at line 4)\n" + 
154
		"	o.toString();\n" + 
155
		"	^\n" + 
156
		"The local variable o may not have been initialized\n" +
157
			// hides the null related message, but complains once, which is good
158
		"----------\n");
159
}
160
161
// null analysis -- final local
162
public void test0006_final_local() {
163
	this.runNegativeTest(
164
		new String[] {
165
			"X.java",
166
			"public class X {\n" + 
167
			"  void foo() {\n" +        
168
			"    final Object o = null;\n" + 
169
			"    if (o != null) { /* */ }\n" + // complain 
170
			"  }\n" + 
171
			"}\n"},
172
		"----------\n" + 
173
		"1. ERROR in X.java (at line 4)\n" + 
174
		"	if (o != null) { /* */ }\n" + 
175
		"	    ^\n" + 
176
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
177
		"----------\n");
178
}
179
 
180
// null analysis -- local with member
181
public void test0007_local_with_member() {
182
	this.runNegativeTest(
183
		new String[] {
184
			"X.java",
185
			"public class X {\n" +
186
			"  Object m;\n" + 
187
			"  void foo() {\n" +        
188
			"    X x = null;\n" + 
189
			"    x.m.toString();\n" + // complain 
190
			"  }\n" + 
191
			"}\n"},
192
		"----------\n" + 
193
		"1. ERROR in X.java (at line 5)\n" + 
194
		"	x.m.toString();\n" + 
195
		"	^^^\n" + 
196
		"The variable x can only be null; it was either set to null or checked for null when last used\n" + 
197
		"----------\n");
198
}
199
200
// null analysis -- local with member
201
// REVIEW le diagnostic montre x.m au lieu de x ; noter que c'est aussi le cas pour
202
// REVIEW      le message "n'a pas été initialisé" ; ouvrir un bug dédié ?
203
// REVIEW      la cause est que QualifiedNameReference est l'ASTNode concerné, et que l'on
204
// REVIEW      n'a pas de support pour en montrer une sous-partie
205
public void test0008_local_with_member() {
206
	this.runNegativeTest(
207
		new String[] {
208
			"X.java",
209
			"public class X {\n" +
210
			"  Object m;\n" + 
211
			"  void foo() {\n" +        
212
			"    X x = null;\n" + 
213
			"    System.out.println(x.m);\n" + // complain 
214
			"  }\n" + 
215
			"}\n"},
216
		"----------\n" + 
217
		"1. ERROR in X.java (at line 5)\n" + 
218
		"	System.out.println(x.m);\n" + 
219
		"	                   ^^^\n" + 
220
		"The variable x can only be null; it was either set to null or checked for null when last used\n" + 
221
		"----------\n");
222
}
223
224
// null analysis -- local with member
225
public void test0009_local_with_member() {
226
	this.runConformTest(
227
		new String[] {
228
			"X.java",
229
			"public class X {\n" +
230
			"  Object m;\n" + 
231
			"  void foo(X x) {\n" +        
232
			"    x.m.toString();\n" + // quiet
233
			"  }\n" + 
234
			"}\n"},
235
		"");
236
}
237
238
// null analysis -- field
239
public void test0010_field_with_method_call() {
240
	this.runConformTest(
241
		new String[] {
242
			"X.java",
243
			"public class X {\n" + 
244
			"  Object o;\n" + 
245
			"  void foo() {\n" + 
246
			"    o = null;\n" + 
247
			"    bar();\n" + // defuses null by side effect
248
			"    o.toString();\n" + 
249
			"  }\n" + 
250
			"  void bar() {\n" + 
251
			"  }\n" + 
252
			"}\n"},
253
		"");
254
}
255
256
// null analysis -- field
257
public void test0011_field_with_method_call() {
258
	this.runConformTest(
259
		new String[] {
260
			"X.java",
261
			"public class X {\n" + 
262
			"  static Object o;\n" + 
263
			"  void foo() {\n" + 
264
			"    o = null;\n" + 
265
			"    bar();\n" + // defuses null by side effect
266
			"    o.toString();\n" + 
267
			"  }\n" + 
268
			"  static void bar() {\n" + 
269
			"  }\n" + 
270
			"}\n"},
271
		"");
272
}
273
274
// null analysis -- field
275
public void test0012_field_with_method_call() {
276
	this.runConformTest(
277
		new String[] {
278
			"X.java",
279
			"public class X {\n" + 
280
			"  Object o;\n" + 
281
			"  void foo() {\n" + 
282
			"    o = null;\n" + 
283
			"    bar();\n" + 
284
			"    o.toString();\n" + 
285
			"  }\n" + 
286
			"  static void bar() {\n" + 
287
			"  }\n" + 
288
			"}\n"},
289
		"" // still ok because the class may hold a pointer to this
290
	);
291
}
292
293
// null analysis -- field
294
public void test0013_field_with_method_call() {
295
	this.runConformTest(
296
		new String[] {
297
			"X.java",
298
			"public class X {\n" + 
299
			"  static Object o;\n" + 
300
			"  void foo() {\n" + 
301
			"    o = null;\n" + 
302
			"    bar();\n" + 
303
			"    o.toString();\n" + 
304
			"  }\n" + 
305
			"  void bar() {\n" + 
306
			"  }\n" + 
307
			"}\n"},
308
		"" // still ok because this may place a static call upon X
309
	);
310
}
311
312
// null analysis -- field
313
public void test0014_field_with_explicit_this_access() {
314
	this.runNegativeTest(
315
		new String[] {
316
			"X.java",
317
			"public class X {\n" + 
318
			"  Object o;\n" + 
319
			"  void foo() {\n" + 
320
			"    o = null;\n" + 
321
			"    this.o.toString();\n" + 
322
			"  }\n" + 
323
			"}\n"},
87
		""
324
		""
88
//			"----------\n" + 
325
//      "----------\n" + 
89
//			"1. WARNING in X.java (at line 5)\n" + 
326
//      "1. ERROR in X.java (at line 5)\n" + 
90
//			"	o.toString();\n" + 
327
//      "	this.o.toString();\n" + 
91
//			"	^\n" + 
328
//      "	^^^^^^\n" + 
92
//			"The field o is likely null; it was either set to null or checked for null when last used\n" + 
329
//      "The field o is likely null; it was either set to null or checked for null when last used\n" + 
93
//			"----------\n"
330
//      "----------\n"
94
		);
331
	);
95
	}
332
}
96
333
97
	// null analysis -- simple case for parameter
334
// null analysis -- field
98
	public void test0003_simple_parameter() {
335
public void test0015_field_with_explicit_this_access() {
99
		this.runNegativeTest(
336
	this.runNegativeTest(
100
			new String[] {
337
		new String[] {
101
				"X.java",
338
			"X.java",
102
				"public class X {\n" + 
339
			"public class X {\n" + 
103
				"	 void foo(Object o) {\n" + 
340
			"  Object o;\n" + 
104
				"		 o = null;\n" + 
341
			"  void foo() {\n" + 
105
				"		 o.toString();\n" + 
342
			"    this.o = null;\n" + 
106
				"	 }\n" + 
343
			"    o.toString();\n" + 
107
				"}\n"},
344
			"  }\n" + 
108
			"----------\n" + 
345
			"}\n"},
109
			"1. WARNING in X.java (at line 4)\n" + 
346
		""
110
			"	o.toString();\n" + 
347
//      "----------\n" + 
111
			"	^\n" + 
348
//      "1. ERROR in X.java (at line 5)\n" + 
112
			"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
349
//      "	o.toString();\n" + 
113
			"----------\n"
350
//      "	^\n" + 
114
		);
351
//      "The field o is likely null; it was either set to null or checked for null when last used\n" + 
115
	}
352
//      "----------\n"
353
	);
354
}
116
355
117
	// null analysis -- field
356
// null analysis -- field
118
	public void test0004_field_with_method_call() {
357
public void test0016_field_of_another_object() {
119
		this.runNegativeTest(
358
	this.runConformTest(
120
			new String[] {
359
		new String[] {
121
				"X.java",
360
			"X.java",
122
				"public class X {\n" + 
361
			"public class X {\n" + 
123
				"	 Object o;\n" + 
362
			"  Object o;\n" + 
124
				"	 void foo() {\n" + 
363
			"  void foo() {\n" + 
125
				"		 o = null;\n" + 
364
			"    X other = new X();\n" + 
126
				"		 bar();\n" + // defuses null by side effect
365
			"    other.o = null;\n" + 
127
				"		 o.toString();\n" + 
366
			"    other.o.toString();\n" + 
128
				"	 }\n" + 
367
			"  }\n" + 
129
				"	 void bar() {\n" + 
368
			"}\n"},
130
				"	 }\n" + 
369
		"");
131
				"}\n"},
370
}
132
			""
133
		);
134
	}
135
371
136
	// null analysis -- field
372
// null analysis -- field
137
	public void test0005_field_with_method_call() {
373
public void test0017_field_of_another_object() {
138
		this.runNegativeTest(
374
	this.runConformTest(
139
			new String[] {
375
		new String[] {
140
				"X.java",
376
			"X.java",
141
				"public class X {\n" + 
377
			"public class X {\n" + 
142
				"	 static Object o;\n" + 
378
			"  Object o;\n" + 
143
				"	 void foo() {\n" + 
379
			"  void foo() {\n" + 
144
				"		 o = null;\n" + 
380
			"    X other = this;\n" + 
145
				"		 bar();\n" + // defuses null by side effect
381
			"    o = null;\n" + 
146
				"		 o.toString();\n" + 
382
			"    other.o.toString();\n" + 
147
				"	 }\n" + 
383
			"  }\n" + 
148
				"	 static void bar() {\n" + 
384
			"}\n"},
149
				"	 }\n" + 
385
		"");
150
				"}\n"},
386
}
151
			""
152
		);
153
	}
154
387
155
	// null analysis -- field
388
// null analysis -- field
156
	public void test0006_field_with_method_call() {
389
public void test0018_field_of_enclosing_object() {
157
		this.runNegativeTest(
390
	this.runNegativeTest(
158
			new String[] {
391
		new String[] {
159
				"X.java",
392
			"X.java",
160
				"public class X {\n" + 
393
			"public class X {\n" + 
161
				"	 Object o;\n" + 
394
			"  Object o;\n" + 
162
				"	 void foo() {\n" + 
395
			"  public class Y {\n" + 
163
				"		 o = null;\n" + 
396
			"    void foo() {\n" + 
164
				"		 bar();\n" + 
397
			"      X.this.o = null;\n" + 
165
				"		 o.toString();\n" + 
398
			"      X.this.o.toString();\n" + // complain
166
				"	 }\n" + 
399
			"    }\n" + 
167
				"	 static void bar() {\n" + 
400
			"  }\n" + 
168
				"	 }\n" + 
401
			"}\n"},
169
				"}\n"},
402
		""
170
			"" // still ok because the class may hold a pointer to this
403
//      "----------\n" + 
171
		);
404
//      "1. ERROR in X.java (at line 6)\n" + 
172
	}
405
//      "	X.this.o.toString();\n" + 
406
//      "	^^^^^^^^\n" + 
407
//      "The field o is likely null; it was either set to null or checked for null when last used\n" + 
408
//      "----------\n"
409
	);
410
}
173
411
174
	// null analysis -- field
412
// null analysis -- fields
175
	public void test0007_field_with_method_call() {
413
// check that fields that are protected against concurrent access
176
		this.runNegativeTest(
414
// behave as locals when no call to further methods can affect them
177
			new String[] {
415
public void test0019_field_synchronized() {
178
				"X.java",
416
	this.runNegativeTest(
179
				"public class X {\n" + 
417
		new String[] {
180
				"	 static Object o;\n" + 
418
			"X.java",
181
				"	 void foo() {\n" + 
419
			"public class X {\n" + 
182
				"		 o = null;\n" + 
420
			"  Object o;\n" + 
183
				"		 bar();\n" + 
421
			"  public synchronized void foo() {\n" +        
184
				"		 o.toString();\n" + 
422
			"    o = null;\n" + 
185
				"	 }\n" + 
423
			"    o.toString();\n" + 
186
				"	 void bar() {\n" + 
424
			"  }\n" + 
187
				"	 }\n" + 
425
			"  void bar() {/* */}\n" +        
188
				"}\n"},
426
			"}\n"},
189
			"" // still ok because this may place a static call upon X
427
		""
190
		);
428
//      "----------\n" + 
191
	}
429
//      "1. ERROR in X.java (at line 5)\n" + 
192
	
430
//      "	o.toString();\n" + 
193
	// null analysis -- field
431
//      "	^\n" + 
194
	// TODO (maxime) reset diagnostic once supported
432
//      "The field o is likely null; it was either set to null or checked for null when last used\n" + 
195
	public void test0008_field_with_explicit_this_access() {
433
//      "----------\n" 
196
		this.runNegativeTest(
434
	);
197
			new String[] {
435
}
198
				"X.java",
199
				"public class X {\n" + 
200
				"	 Object o;\n" + 
201
				"	 void foo() {\n" + 
202
				"		 o = null;\n" + 
203
				"		 this.o.toString();\n" + 
204
				"	 }\n" + 
205
				"}\n"},
206
			""
207
//			"----------\n" + 
208
//			"1. WARNING in X.java (at line 5)\n" + 
209
//			"	this.o.toString();\n" + 
210
//			"	^^^^^^\n" + 
211
//			"The field o is likely null; it was either set to null or checked for null when last used\n" + 
212
//			"----------\n"
213
		);
214
	}
215
436
216
	// null analysis -- field
437
// null analysis -- field
217
	// TODO (maxime) reset diagnostic once supported
438
// check that final fields behave as locals despite calls to further 
218
	public void test0009_field_with_explicit_this_access() {
439
// methods
219
		this.runNegativeTest(
440
public void test0020_final_field() {
220
			new String[] {
441
	this.runNegativeTest(
221
				"X.java",
442
		new String[] {
222
				"public class X {\n" + 
443
			"X.java",
223
				"	 Object o;\n" + 
444
			"public class X {\n" + 
224
				"	 void foo() {\n" + 
445
			"  final Object o = null;\n" + 
225
				"		 this.o = null;\n" + 
446
			"  public synchronized void foo() {\n" +        
226
				"		 o.toString();\n" + 
447
			"    bar();\n" + 
227
				"	 }\n" + 
448
			"    o.toString();\n" + 
228
				"}\n"},
449
			"  }\n" + 
229
			""
450
			"  void bar() {/* */}\n" +        
230
//			"----------\n" + 
451
			"}\n"},
231
//			"1. WARNING in X.java (at line 5)\n" + 
452
		""
232
//			"	o.toString();\n" + 
453
//      "----------\n" + 
233
//			"	^\n" + 
454
//      "1. ERROR in X.java (at line 5)\n" + 
234
//			"The field o is likely null; it was either set to null or checked for null when last used\n" + 
455
//      "	o.toString();\n" + 
235
//			"----------\n"
456
//      "	^\n" + 
236
		);
457
//      "The field o is likely null; it was either set to null or checked for null when last used\n" + 
237
	}
458
//      "----------\n" 
459
	);
460
}
238
461
239
	// null analysis -- field
462
// null analysis -- field
240
	public void test0010_field_of_another_object() {
463
public void test0021_final_field() {
241
		this.runNegativeTest(
464
	this.runNegativeTest(
242
			new String[] {
465
		new String[] {
243
				"X.java",
466
			"X.java",
244
				"public class X {\n" + 
467
			"public class X {\n" + 
245
				"	 Object o;\n" + 
468
			"  final Object o = null;\n" + 
246
				"	 void foo() {\n" + 
469
			"  X () {\n" +        
247
				"	   X other = new X();\n" + 
470
			"    bar();\n" + 
248
				"		 other.o = null;\n" + 
471
			"    o.toString();\n" + 
249
				"		 other.o.toString();\n" + 
472
			"  }\n" + 
250
				"	 }\n" + 
473
			"  void bar() {/* */}\n" +        
251
				"}\n"},
474
			"}\n"},
252
			""
475
		""
253
		);
476
//      "----------\n" + 
254
	}
477
//      "1. ERROR in X.java (at line 5)\n" + 
255
	
478
//      "	o.toString();\n" + 
256
	// null analysis -- field
479
//      "	^\n" + 
257
	public void test0011_field_of_another_object() {
480
//      "The field o is likely null; it was either set to null or checked for null when last used\n" + 
258
		this.runNegativeTest(
481
//      "----------\n" 
259
			new String[] {
482
	);
260
				"X.java",
483
}
261
				"public class X {\n" + 
262
				"	 Object o;\n" + 
263
				"	 void foo() {\n" + 
264
				"	   X other = this;\n" + 
265
				"		 o = null;\n" + 
266
				"		 other.o.toString();\n" + 
267
				"	 }\n" + 
268
				"}\n"},
269
			""
270
		);
271
	}
272
484
273
	// null analysis -- field
485
// null analysis -- field
274
	// TODO (maxime) reset diagnostic once supported
486
public void test0022_final_field() {
275
	public void test0012_field_of_enclosing_object() {
487
	this.runNegativeTest(
276
		this.runNegativeTest(
488
		new String[] {
489
			"X.java",
490
			"public class X {\n" + 
491
			"  final Object o = new Object();\n" + 
492
			"  X () {\n" +        
493
			"    bar();\n" + 
494
			"    if (o == null) { /* empty */ }\n" + 
495
			"  }\n" + 
496
			"  void bar() {/* */}\n" +        
497
			"}\n"},
498
		""
499
//      "----------\n" + 
500
//      "1. ERROR in X.java (at line 5)\n" + 
501
//      "	if (o == null) { /* empty */ }\n" + 
502
//      "	    ^\n" + 
503
//      "The field o is likely non null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
504
//      "----------\n"
505
	);
506
}
507
508
// null analysis -- field
509
public void test0023_field_assignment() {
510
	this.runConformTest(
511
		new String[] {
512
			"X.java",
513
			"public class X {\n" + 
514
			"  Object m;\n" + 
515
			"  void foo(X x) {\n" + 
516
			"    Object o = x.m;\n" + 
517
			"    if (o == null) { /* */ };\n" + 
518
			"  }\n" + 
519
			"}\n"},
520
		"");
521
}
522
523
// null analysis -- field
524
public void test0024_field_cast_assignment() {
525
	this.runConformTest(
526
		new String[] {
527
			"X.java",
528
			"public class X {\n" + 
529
			"  Object m;\n" + 
530
			"  void foo(Object x) {\n" + 
531
			"    Object o = ((X) x).m;\n" + 
532
			"    if (o == null) { /* */ };\n" + 
533
			"  }\n" + 
534
			"}\n"},
535
		"");
536
}
537
538
// null analysis -- parameter
539
public void test0025_parameter() {
540
	this.runConformTest(
541
		new String[] {
542
			"X.java",
543
			"public class X {\n" + 
544
			"  void foo(Object o) {\n" + 
545
			"    o.toString();\n" + // quiet: parameters have unknown value 
546
			"  }\n" + 
547
			"}\n"},
548
		"");
549
}
550
551
// null analysis -- suppress warnings
552
public void test0026_suppress_warnings() {
553
	if (COMPLIANCE_1_5.equals(this.complianceLevel)) {
554
		Map compilerOptions = getCompilerOptions();
555
		compilerOptions.put(CompilerOptions.OPTION_ReportNullReference, CompilerOptions.WARNING);
556
		this.runConformTest(
277
			new String[] {
557
			new String[] {
278
				"X.java",
558
				"X.java",
279
				"public class X {\n" + 
559
				"@SuppressWarnings(\"null\")\n" + 
280
				"	 Object o;\n" + 
560
				"public class X {\n" + 
281
				"  public class Y {\n" + 
561
				"  void foo() {\n" + 
282
				"	   void foo() {\n" + 
562
				"    Object o = null;\n" + 
283
				"		   X.this.o = null;\n" + 
563
				"    o.toString();\n" + 
284
				"		   X.this.o.toString();\n" + // complain
285
				"	   }\n" + 
286
				"  }\n" + 
564
				"  }\n" + 
287
				"}\n"},
565
				"}\n"},
288
			""
566
		    "", null, true, null, compilerOptions, null);
289
//			"----------\n" + 
290
//			"1. WARNING in X.java (at line 6)\n" + 
291
//			"	X.this.o.toString();\n" + 
292
//			"	^^^^^^^^\n" + 
293
//			"The field o is likely null; it was either set to null or checked for null when last used\n" + 
294
//			"----------\n"
295
		);
296
	}
297
	
298
	// null analysis -- fields
299
	// check that fields that are protected against concurrent access
300
	// behave as locals when no call to further methods can affect them
301
	// TODO (maxime) reset diagnostic once supported
302
	public void test0013_field_synchronized() {
303
		this.runNegativeTest(
304
			new String[] {
305
				"X.java",
306
				"public class X {\n" + 
307
				"	 Object o;\n" + 
308
				"  public synchronized void foo() {\n" + 				
309
				"		 o = null;\n" + 
310
				"		 o.toString();\n" + 
311
				"	 }\n" + 
312
				"  void bar() {/* */}\n" + 				
313
				"}\n"},
314
			""
315
//			"----------\n" + 
316
//			"1. WARNING in X.java (at line 5)\n" + 
317
//			" o.toString();\n" + 
318
//			"	^\n" + 
319
//			"The field o is likely null; it was either set to null or checked for null when last used\n" + 
320
//			"----------\n" 
321
		);
322
	}
567
	}
568
}
323
569
324
	// null analysis -- field
570
// null analysis -- embedded comparison
325
	// check that final fields behave as locals despite calls to further 
571
public void test0027_embedded_comparison() {
326
	// methods
572
	this.runNegativeTest(
327
	// TODO (maxime) reset diagnostic once supported
573
		new String[] {
328
	public void test0014_final_field() {
574
			"X.java",
329
		this.runNegativeTest(
575
			"public class X {\n" + 
330
			new String[] {
576
			"  void foo(Object o) {\n" + 
331
				"X.java",
577
			"    boolean b = o != null;\n" + // shades doubts upon o 
332
				"public class X {\n" + 
578
			"    if (b) { /* */ }\n" + 
333
				"	 final Object o = null;\n" + 
579
			"    o.toString();\n" + 		// complain
334
				"  public synchronized void foo() {\n" + 				
580
			"  }\n" + 
335
				"		 bar();\n" + 
581
			"}\n"},
336
				"		 o.toString();\n" + 
582
		"----------\n" + 
337
				"	 }\n" + 
583
		"1. ERROR in X.java (at line 5)\n" + 
338
				"  void bar() {/* */}\n" + 				
584
		"	o.toString();\n" + 
339
				"}\n"},
585
		"	^\n" + 
340
			""
586
		"The variable o may be null\n" + 
341
//			"----------\n" + 
587
		"----------\n");
342
//			"1. WARNING in X.java (at line 5)\n" + 
588
}
343
//			"	o.toString();\n" + 
344
//			"	^\n" + 
345
//			"The field o is likely null; it was either set to null or checked for null when last used\n" + 
346
//			"----------\n" 
347
		);
348
	}
349
589
350
	// null analysis -- field
590
// null analysis -- field
351
	// TODO (maxime) reset diagnostic once supported
591
public void test0028_field_as_initializer() {
352
	public void test0015_final_field() {
592
	this.runConformTest(
353
		this.runNegativeTest(
593
		new String[] {
354
			new String[] {
594
			"X.java",
355
				"X.java",
595
			"public class X {\n" + 
356
				"public class X {\n" + 
596
			"  X f;\n" + 
357
				"	 final Object o = null;\n" + 
597
			"  void foo() {\n" + 
358
				"  X () {\n" + 				
598
			"    X x = f;\n" + 
359
				"		 bar();\n" + 
599
			"    if (x == null) { /* */ }\n" + 
360
				"		 o.toString();\n" + 
600
			"  }\n" + 
361
				"	 }\n" + 
601
			"}\n"},
362
				"  void bar() {/* */}\n" + 				
602
		"");
363
				"}\n"},
603
}
364
			""
365
//			"----------\n" + 
366
//			"1. WARNING in X.java (at line 5)\n" + 
367
//			"	o.toString();\n" + 
368
//			"	^\n" + 
369
//			"The field o is likely null; it was either set to null or checked for null when last used\n" + 
370
//			"----------\n" 
371
		);
372
	}
373
604
374
	// null analysis -- field
605
// null analysis -- field
375
	// TODO (maxime) reset diagnostic once supported
606
public void test0029_field_assignment() {
376
	public void test0016_final_field() {
607
	this.runNegativeTest(
377
		this.runNegativeTest(
608
		new String[] {
378
			new String[] {
609
			"X.java",
379
				"X.java",
610
			"public class X {\n" + 
380
				"public class X {\n" + 
611
			"  Object m;\n" + 
381
				"	 final Object o = new Object();\n" + 
612
			"  void foo() {\n" + 
382
				"  X () {\n" + 				
613
			"    X x = null;\n" + 
383
				"		 bar();\n" + 
614
			"    x.m = new Object();\n" + 
384
				"		 if (o == null) { /* empty */ }\n" + 
615
			"  }\n" + 
385
				"	 }\n" + 
616
			"}\n"},
386
				"  void bar() {/* */}\n" + 				
617
		"----------\n" + 
387
				"}\n"},
618
		"1. ERROR in X.java (at line 5)\n" + 
388
			""
619
		"	x.m = new Object();\n" + 
389
//			"----------\n" + 
620
		"	^^^\n" + 
390
//			"1. WARNING in X.java (at line 5)\n" + 
621
		"The variable x can only be null; it was either set to null or checked for null when last used\n" + 
391
//			"	if (o == null) { /* empty */ }\n" + 
622
		"----------\n");
392
//			"	    ^\n" + 
623
}
393
//			"The field o is likely non null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
394
//			"----------\n"
395
		);
396
	}
397
624
398
	// null analysis -- parameter
625
// null analysis -- conditional expression
399
	public void test0017_parameter() {
626
public void test0030_conditional_expression() {
400
		this.runNegativeTest(
627
	this.runNegativeTest(
401
			new String[] {
628
		new String[] {
402
				"X.java",
629
			"X.java",
403
				"public class X {\n" + 
630
			"public class X {\n" + 
404
				"	 void foo(Object o) {\n" + 
631
			"  void foo() {\n" + 
405
				"		 o.toString();\n" + // quiet: parameters have unknown value 
632
			"    Object o = true ? null : null;\n" + 
406
				"	 }\n" + 
633
			"    o.toString();\n" + 
407
				"}\n"},
634
			"  }\n" + 
408
			""
635
			"}\n"},
409
		);
636
		"----------\n" + 
410
	}
637
		"1. ERROR in X.java (at line 4)\n" + 
638
		"	o.toString();\n" + 
639
		"	^\n" + 
640
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
641
		"----------\n");
642
}
643
644
// null analysis -- conditional expression
645
public void test0031_conditional_expression() {
646
	this.runNegativeTest(
647
		new String[] {
648
			"X.java",
649
			"public class X {\n" + 
650
			"  void foo() {\n" + 
651
			"    Object o = true ? null : new Object();\n" + 
652
			"    o.toString();\n" + 
653
			"  }\n" + 
654
			"}\n"},
655
		"----------\n" + 
656
		"1. ERROR in X.java (at line 4)\n" + 
657
		"	o.toString();\n" + 
658
		"	^\n" + 
659
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
660
		"----------\n");
661
}
662
663
// null analysis -- conditional expression
664
public void test0032_conditional_expression() {
665
	this.runConformTest(
666
		new String[] {
667
			"X.java",
668
			"public class X {\n" + 
669
			"  void foo() {\n" + 
670
			"    Object o = false ? null : new Object();\n" + 
671
			"    o.toString();\n" + 
672
			"  }\n" + 
673
			"}\n"},
674
		"");
675
}
676
677
// null analysis -- conditional expression
678
public void test0033_conditional_expression() {
679
	this.runNegativeTest(
680
		new String[] {
681
			"X.java",
682
			"public class X {\n" + 
683
			"  void foo() {\n" + 
684
			"    Object o = (1 == 1) ? null : new Object();\n" + 
685
			"    o.toString();\n" + 
686
			"  }\n" + 
687
			"}\n"},
688
		"----------\n" + 
689
		"1. ERROR in X.java (at line 4)\n" + 
690
		"	o.toString();\n" + 
691
		"	^\n" + 
692
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
693
		"----------\n");
694
}
411
695
412
	// null analysis -- conditional expression
696
// null analysis -- conditional expression
413
	// TODO (maxime) fix
697
// TODO (maxime) fix - may consider simultaneous computation of expression null status
414
	public void _test0020_conditional_expression() {
698
// this case is one of those which raise the need for the simultaneous calculation of
699
// the null status of an expression and the code analysis of the said expression; this
700
// case is simplistic: we need a value (here, potentially null), that is *not* carried
701
// by the current embodiment of the flow info; other cases are less trivial in which
702
// side effects on variables could introduce errors into after the facts evaluations;
703
// one possible trick would be to add a slot for this
704
// other path: use a tainted unknown expression status; does not seem to cope well 
705
// with o = (o ==  null ? new Object() : o)
706
public void _test0034_conditional_expression() {
707
	this.runNegativeTest(
708
		new String[] {
709
			"X.java",
710
			"public class X {\n" + 
711
			"  boolean b;\n" + 
712
			"  void foo() {\n" + 
713
			"    Object o = b ? null : new Object();\n" + 
714
			"    o.toString();\n" + 
715
			"  }\n" + 
716
			"}\n"},
717
		"----------\n" + 
718
		"1. ERROR in X.java (at line 4)\n" + 
719
		"	o.toString();\n" + 
720
		"	^\n" + 
721
		"The variable o may be null\n" + 
722
		"----------\n");
723
}
724
725
// null analysis -- conditional expression
726
public void test0035_conditional_expression() {
727
	this.runConformTest(
728
		new String[] {
729
			"X.java",
730
			"public class X {\n" + 
731
			"  boolean b;\n" + 
732
			"  void foo() {\n" + 
733
			"    Object o = b ? null : new Object();\n" + 
734
			"    if (o == null) { /* */ }\n" + 
735
			"  }\n" + 
736
			"}\n"},
737
		"");
738
}
739
740
// null analysis -- conditional expression
741
public void test0036_conditional_expression() {
742
	this.runNegativeTest(
743
		new String[] {
744
			"X.java",
745
			"public class X {\n" + 
746
			"  boolean b;\n" + 
747
			"  void foo() {\n" + 
748
			"    Object o = b ? null : null;\n" + 
749
			"    if (o == null) { /* */ }\n" + 
750
			"  }\n" + 
751
			"}\n"},
752
		"----------\n" + 
753
		"1. ERROR in X.java (at line 5)\n" + 
754
		"	if (o == null) { /* */ }\n" + 
755
		"	    ^\n" + 
756
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
757
		"----------\n");
758
}
759
760
// null analysis -- autoboxing
761
public void test0040_autoboxing_compound_assignment() {
762
	if (COMPLIANCE_1_5.equals(this.complianceLevel)) {
415
		this.runNegativeTest(
763
		this.runNegativeTest(
416
			new String[] {
764
			new String[] {
417
				"X.java",
765
				"X.java",
418
				"public class X {\n" + 
766
				"public class X {\n" + 
419
				"	 void foo() {\n" + 
767
				"  void foo() {\n" + 
420
				"		 Object o = true ? null : null;\n" + 
768
				"    Integer i = null;\n" +
421
				"		 o.toString();\n" + 
769
				"    i += 1;\n" + 
422
				"	 }\n" + 
770
				"  }\n" + 
423
				"}\n"},
771
				"}\n"},
424
			"----------\n" + 
772
			"----------\n" + 
425
			"1. WARNING in X.java (at line 4)\n" + 
773
			"1. ERROR in X.java (at line 4)\n" + 
426
			"	o.toString();\n" + 
774
			"	i += 1;\n" + 
427
			"	^\n" + 
775
			"	^\n" + 
428
			"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
776
			"The variable i can only be null; it was either set to null or checked for null when last used\n" + 
429
			"----------\n"
777
			"----------\n");
430
		);
431
	}
778
	}
779
}
432
780
433
	// null analysis -- conditional expression
781
// null analysis -- autoboxing
434
	// TODO (maxime) fix
782
public void test0041_autoboxing_increment_operator() {
435
	public void _test0021_conditional_expression() {
783
	if (COMPLIANCE_1_5.equals(this.complianceLevel)) {
436
		this.runNegativeTest(
784
		this.runNegativeTest(
437
			new String[] {
785
			new String[] {
438
				"X.java",
786
				"X.java",
439
				"public class X {\n" + 
787
				"public class X {\n" + 
440
				"	 void foo() {\n" + 
788
				"  void foo() {\n" + 
441
				"		 Object o = true ? null : new Object();\n" + 
789
				"    Integer i = null;\n" +
442
				"		 o.toString();\n" + 
790
				"    i++;\n" + // complain: this is null
443
				"	 }\n" + 
791
				"    ++i;\n" + // quiet (because previous step guards it)
792
				"  }\n" + 
444
				"}\n"},
793
				"}\n"},
445
			"----------\n" + 
794
			"----------\n" + 
446
			"1. WARNING in X.java (at line 4)\n" + 
795
			"1. ERROR in X.java (at line 4)\n" + 
447
			"	o.toString();\n" + 
796
			"	i++;\n" + 
448
			"	^\n" + 
797
			"	^\n" + 
449
			"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
798
			"The variable i can only be null; it was either set to null or checked for null when last used\n" + 
450
			"----------\n"
799
			"----------\n");
451
		);
452
	}
800
	}
801
}
453
802
454
	// null analysis -- conditional expression
803
// null analysis -- autoboxing
455
	public void test0022_conditional_expression() {
804
public void test0042_autoboxing_literal() {
805
	if (COMPLIANCE_1_5.equals(this.complianceLevel)) {
456
		this.runNegativeTest(
806
		this.runNegativeTest(
457
			new String[] {
807
			new String[] {
458
				"X.java",
808
				"X.java",
459
				"public class X {\n" + 
809
				"public class X {\n" + 
460
				"	 void foo() {\n" + 
810
				"  void foo() {\n" + 
461
				"		 Object o = false ? null : new Object();\n" + 
811
				"    Integer i = 0;\n" +
462
				"		 o.toString();\n" + 
812
				"    if (i == null) {};\n" + // complain: this is non null
463
				"	 }\n" + 
813
				"  }\n" + 
464
				"}\n"},
814
				"}\n"},
465
			""
815
			"----------\n" + 
466
		);
816
			"1. ERROR in X.java (at line 4)\n" + 
817
			"	if (i == null) {};\n" + 
818
			"	    ^\n" + 
819
			"The variable i cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
820
			"----------\n");
467
	}
821
	}
822
}
468
823
469
	// null analysis -- conditional expression
824
// null analysis -- autoboxing
470
	// TODO (maxime) fix
825
public void test0043_autoboxing_literal() {
471
	public void _test0023_conditional_expression() {
826
	if (COMPLIANCE_1_5.equals(this.complianceLevel)) {
472
		this.runNegativeTest(
827
		this.runNegativeTest(
473
			new String[] {
828
			new String[] {
474
				"X.java",
829
				"X.java",
475
				"public class X {\n" + 
830
				"public class X {\n" + 
476
				"	 void foo() {\n" + 
831
				"  void foo() {\n" + 
477
				"		 Object o = (1 == 1) ? null : new Object();\n" + 
832
				"    Integer i = null;\n" +
478
				"		 o.toString();\n" + 
833
				"    System.out.println(i + 4);\n" + // complain: this is null
479
				"	 }\n" + 
834
				"  }\n" + 
480
				"}\n"},
835
				"}\n"},
481
			"----------\n" + 
836
			"----------\n" + 
482
			"1. WARNING in X.java (at line 4)\n" + 
837
			"1. ERROR in X.java (at line 4)\n" + 
483
			"	o.toString();\n" + 
838
			"	System.out.println(i + 4);\n" + 
484
			"	^\n" + 
839
			"	                   ^\n" + 
485
			"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
840
			"The variable i can only be null; it was either set to null or checked for null when last used\n" + 
486
			"----------\n"
841
			"----------\n");
487
		);
488
	}
842
	}
489
	//TODO (maxime) - add case with non constant condition in conditional expression   cond() ? ... : ...
843
}
490
	
844
491
	// null analysis -- autoboxing
845
// null analysis -- autoboxing
492
	// TODO (maxime) fix
846
// origin: AssignmentTest#test020
493
	public void _test0030_autoboxing_compound_assignment() {
847
public void test0044_autoboxing() {
494
		if (COMPLIANCE_1_5.equals(this.complianceLevel)) {
848
	this.runConformTest(
495
			this.runNegativeTest(
849
		new String[] {
496
				new String[] {
850
			"X.java",
497
					"X.java",
851
			"public class X {\n" + 
498
					"public class X {\n" + 
852
			"  void foo() {\n" + 
499
					"	 void foo() {\n" + 
853
			"    int i = 0;\n" +
500
					"		 Integer i = null;\n" +
854
			"    boolean b = i < 10;\n" + 
501
					"    i += 1;\n" + 
855
			"  }\n" + 
502
					"	 }\n" + 
856
			"}\n"},
503
					"}\n"},
504
				"----------\n" + 
505
				"1. WARNING in X.java (at line 4)\n" + 
506
				"	i += 1;\n" + 
507
				"	^\n" + 
508
				"The variable i can only be null; it was either set to null or checked for null when last used\n" + 
509
				"----------\n"
510
			);
511
		}
512
	}
513
514
	// null analysis -- autoboxing
515
	// TODO (maxime) fix
516
	public void _test0031_autoboxing_increment_operator() {
517
		if (COMPLIANCE_1_5.equals(this.complianceLevel)) {
518
			this.runNegativeTest(
519
				new String[] {
520
					"X.java",
521
					"public class X {\n" + 
522
					"	 void foo() {\n" + 
523
					"		 Integer i = null;\n" +
524
					"    i++;\n" + // complain: this is null
525
					"    ++i;\n" + // quiet (because previous step guards it)
526
					"	 }\n" + 
527
					"}\n"},
528
				"----------\n" + 
529
				"1. WARNING in X.java (at line 4)\n" + 
530
				"	i++;\n" + 
531
				"	^\n" + 
532
				"The variable i can only be null; it was either set to null or checked for null when last used\n" + 
533
				"----------\n"
534
			);
535
		}
536
	}
537
538
	// null analysis -- autoboxing
539
	public void test0032_autoboxing_literal() {
540
		if (COMPLIANCE_1_5.equals(this.complianceLevel)) {
541
			this.runNegativeTest(
542
				new String[] {
543
					"X.java",
544
					"public class X {\n" + 
545
					"	 void foo() {\n" + 
546
					"		 Integer i = 0;\n" +
547
					"    if (i == null) {};\n" + // complain: this is non null
548
					"	 }\n" + 
549
					"}\n"},
550
				"----------\n" + 
551
				"1. WARNING in X.java (at line 4)\n" + 
552
				"	if (i == null) {};\n" + 
553
				"	    ^\n" + 
554
				"The variable i cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
555
				"----------\n"
556
			);
557
		}
558
	}
559
560
	// null analysis -- autoboxing
561
	// TODO (maxime) fix
562
	public void _test0033_autoboxing_literal() {
563
		if (COMPLIANCE_1_5.equals(this.complianceLevel)) {
564
			this.runNegativeTest(
565
				new String[] {
566
					"X.java",
567
					"public class X {\n" + 
568
					"	 void foo() {\n" + 
569
					"		 Integer i = null;\n" +
570
					"    System.out.println(i + 4);\n" + // complain: this is null
571
					"	 }\n" + 
572
					"}\n"},
573
				"----------\n" + 
574
				"1. WARNING in X.java (at line 4)\n" + 
575
				"	System.out.println(i + 4);\n" + 
576
				"	                   ^\n" + 
577
				"The variable i can only be null; it was either set to null or checked for null when last used\n" + 
578
				"----------\n"
579
			);
580
		}
581
	}
582
583
	// null analysis -- autoboxing
584
	// origin: AssignmentTest#test020
585
	public void test034_autoboxing() {
586
		this.runNegativeTest(
587
			new String[] {
588
				"X.java",
589
				"public class X {\n" + 
590
				"	 void foo() {\n" + 
591
				"		 int i = 0;\n" +
592
				"    boolean b = i < 10;\n" + 
593
				"	 }\n" + 
594
				"}\n",
595
			},
596
		"");
857
		"");
858
}
859
860
// null analysis -- strings concatenation
861
// JLS 15.18.1: if one of the operands is null, it is replaced by "null"
862
// Note: having the diagnostic could come handing when the initialization path
863
//       is non trivial; to get the diagnostic, simply put in place an
864
//       extraneous call to toString() -- and remove it before releasing.
865
public void test0045_strings_concatenation() {
866
	this.runConformTest(
867
		new String[] {
868
			"X.java",
869
			"public class X {\n" + 
870
			"  String foo(String s1, String s2) {\n" + 
871
			"    if (s1 == null) { /* */ };\n" +
872
			"    return s1 + s2;\n" + 
873
			"  }\n" + 
874
			"}\n"},
875
		"");
876
}
877
878
// null analysis -- strings concatenation
879
public void test0046_strings_concatenation() {
880
	this.runConformTest(
881
		new String[] {
882
			"X.java",
883
			"public class X {\n" + 
884
			"  String foo(String s1, String s2) {\n" + 
885
			"    if (s1 == null) { /* */ };\n" +
886
			"    s1 += s2;\n" + 
887
			"    return s1;\n" + 
888
			"  }\n" + 
889
			"}\n"},
890
		"");
891
}
892
893
// null analysis -- strings concatenation
894
public void test0047_strings_concatenation() {
895
	this.runNegativeTest(
896
		new String[] {
897
			"X.java",
898
			"public class X {\n" + 
899
			"  String foo(String s1) {\n" + 
900
			"    if (s1 == null) { /* */ };\n" +
901
			"    return s1.toString();\n" + 
902
			"  }\n" + 
903
			"}\n"},
904
		"----------\n" + 
905
		"1. ERROR in X.java (at line 4)\n" + 
906
		"	return s1.toString();\n" + 
907
		"	       ^^\n" + 
908
		"The variable s1 may be null\n" + 
909
		"----------\n");
910
}
911
912
// null analysis -- array
913
public void test0050_array() {
914
	this.runConformTest(
915
		new String[] {
916
			"X.java",
917
			"public class X {\n" + 
918
			"  public static void main(String args[]) {\n" + 
919
			"    args = new String[] {\"zero\"};\n" +
920
			"    args[0] = null;\n" +
921
			"    if (args[0] == null) {};\n" + 
922
			     // quiet: we don't keep track of all array elements
923
			"  }\n" + 
924
			"}\n"},
925
		"");
926
}
927
928
// null analysis -- array
929
public void test0051_array() {
930
	this.runNegativeTest(
931
		new String[] {
932
			"X.java",
933
			"public class X {\n" + 
934
			"  public static void main(String args[]) {\n" + 
935
			"    args = null;\n" +
936
			"    args[0].toString();\n" + // complain: args is null
937
			"  }\n" + 
938
			"}\n"},
939
		"----------\n" + 
940
		"1. ERROR in X.java (at line 4)\n" + 
941
		"	args[0].toString();\n" + 
942
		"	^^^^\n" + 
943
		"The variable args can only be null; it was either set to null or checked for null when last used\n" + 
944
		"----------\n");
945
}
946
947
// null analysis -- array
948
public void test0052_array() {
949
	this.runConformTest(
950
		new String[] {
951
			"X.java",
952
			"public class X {\n" + 
953
			"  public void foo(String args[]) {\n" + 
954
			"    String s = args[0];\n" +
955
			"    if (s == null) {};\n" + 
956
			     // quiet: we don't keep track of all array elements
957
			"  }\n" + 
958
			"}\n"},
959
		"");
960
}
961
962
// null analysis -- array
963
public void test0053_array() {
964
	this.runConformTest(
965
		new String[] {
966
			"X.java",
967
			"public class X {\n" + 
968
			"  public void foo(String args[]) {\n" + 
969
			"    for (int i = 0; i < args.length; i++) { /* */}\n" +
970
			"  }\n" + 
971
			"}\n"},
972
		"");
973
}
974
975
// null analysis -- method call
976
public void test0061_method_call_guard() {
977
	this.runNegativeTest(
978
		new String[] {
979
			"X.java",
980
			"public class X {\n" + 
981
			"  void foo(Object o) {\n" + 
982
			"    o.toString();\n" +      // guards o from being null
983
			"    if (o == null) {};\n" + // complain
984
			"  }\n" + 
985
			"}\n"},
986
		"----------\n" + 
987
		"1. ERROR in X.java (at line 4)\n" + 
988
		"	if (o == null) {};\n" + 
989
		"	    ^\n" + 
990
		"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
991
		"----------\n");
992
} 
993
994
// null analysis - method call
995
public void test0062_method_call_isolation() {
996
	this.runNegativeTest(
997
		new String[] {
998
			"X.java",
999
			"public class X {\n" + 
1000
			"  void foo(Object o) {\n" + 
1001
			"    if (bar(o = null)) {\n" + 
1002
			"      if (o == null) {/* empty */}\n" + // complain 
1003
			"    }\n" + 
1004
			"  }\n" + 
1005
			"  boolean bar(Object o) {\n" + 
1006
			"    return true;\n" + 
1007
			"  }\n" + 
1008
			"}\n"},
1009
		"----------\n" + 
1010
		"1. ERROR in X.java (at line 4)\n" + 
1011
		"	if (o == null) {/* empty */}\n" + 
1012
		"	    ^\n" + 
1013
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
1014
		"----------\n");
1015
}   
1016
1017
// null analysis - method call
1018
public void test0063_method_call_isolation() {
1019
	this.runConformTest(
1020
		new String[] {
1021
			"X.java",
1022
			"public class X {\n" + 
1023
			"  void foo(Object o) {\n" + 
1024
			"    if (bar(o == null ? new Object() : o)) {\n" + 
1025
			"      if (o == null) {/* empty */}\n" + // quiet 
1026
			"    }\n" + 
1027
			"  }\n" + 
1028
			"  boolean bar(Object o) {\n" + 
1029
			"    return true;\n" + 
1030
			"  }\n" + 
1031
			"}\n"},
1032
		"");
1033
}   
1034
1035
// null analysis - method call
1036
public void test0064_method_call_isolation() {
1037
	this.runNegativeTest(
1038
		new String[] {
1039
			"X.java",
1040
			"public class X {\n" + 
1041
			"  void foo(Object o) {\n" + 
1042
			"    if (bar(o = new Object())) {\n" + 
1043
			"      if (o == null) {/* empty */}\n" + // complain 
1044
			"    }\n" + 
1045
			"  }\n" + 
1046
			"  boolean bar(Object o) {\n" + 
1047
			"    return true;\n" + 
1048
			"  }\n" + 
1049
			"}\n"},
1050
		"----------\n" + 
1051
		"1. ERROR in X.java (at line 4)\n" + 
1052
		"	if (o == null) {/* empty */}\n" + 
1053
		"	    ^\n" + 
1054
		"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
1055
		"----------\n");
1056
}   
1057
1058
// null analysis - method call
1059
public void test0065_method_call_invocation_target() {
1060
	this.runConformTest(
1061
		new String[] {
1062
			"X.java",
1063
			"public class X {\n" + 
1064
			"  void foo() {\n" + 
1065
			"    Object o = null;\n" + 
1066
			"    (o = new Object()).toString();\n" + // quiet 
1067
			"  }\n" + 
1068
			"}\n"},
1069
		"");
1070
}   
1071
1072
// null analysis - method call
1073
public void test0066_method_call_invocation_target() {
1074
	this.runNegativeTest(
1075
		new String[] {
1076
			"X.java",
1077
			"public class X {\n" + 
1078
			"  void foo() {\n" + 
1079
			"    Object o = new Object();\n" + 
1080
			"    (o = null).toString();\n" + // complain 
1081
			"  }\n" + 
1082
			"}\n"},
1083
		"----------\n" + 
1084
		"1. ERROR in X.java (at line 4)\n" + 
1085
		"	(o = null).toString();\n" + 
1086
		"	^^^^^^^^^^\n" + 
1087
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
1088
		"----------\n");
1089
}   
1090
1091
// null analysis - method call
1092
public void test0067_method_call_invocation_target() {
1093
	this.runNegativeTest(
1094
		new String[] {
1095
			"X.java",
1096
			"public class X {\n" + 
1097
			"  void foo(Object o) {\n" + 
1098
			"    (o = new Object()).toString();\n" + // quiet 
1099
			"    if (o == null)  { /* */ }\n" + // complain 
1100
			"  }\n" + 
1101
			"}\n"},
1102
		"----------\n" + 
1103
		"1. ERROR in X.java (at line 4)\n" + 
1104
		"	if (o == null)  { /* */ }\n" + 
1105
		"	    ^\n" + 
1106
		"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
1107
		"----------\n");
1108
}  
1109
1110
// null analysis - method call
1111
public void test0068_method_call_assignment() {
1112
	this.runConformTest(
1113
		new String[] {
1114
			"X.java",
1115
			"public class X {\n" + 
1116
			"  X bar() {\n" + 
1117
			"    return null;\n" + 
1118
			"  }\n" + 
1119
			"  void foo(X x) {\n" + 
1120
			"    x = x.bar();\n" +  
1121
			"    if (x == null)  { /* */ }\n" + // quiet 
1122
			"  }\n" + 
1123
			"}\n"},
1124
		"");
1125
} 
1126
1127
// null analysis -- type reference
1128
public void test0070_type_reference() {
1129
	this.runNegativeTest(
1130
		new String[] {
1131
			"X.java",
1132
			"public class X {\n" + 
1133
			"  public static void main(String args[]) {\n" + 
1134
			"    Class c = java.lang.Object.class;\n" +
1135
			"    if (c == null) {};\n" +
1136
			"  }\n" + 
1137
			"}\n"},
1138
		"----------\n" + 
1139
		"1. ERROR in X.java (at line 4)\n" + 
1140
		"	if (c == null) {};\n" + 
1141
		"	    ^\n" + 
1142
		"The variable c cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
1143
		"----------\n");
1144
}
1145
1146
public void test0080_shortcut_boolean_expressions() {
1147
	this.runNegativeTest(
1148
		new String[] {
1149
			"X.java",
1150
			"public class X {\n" + 
1151
			"  void foo(Object o1, Object o2) {\n" + 
1152
			"    if (o1 != null && (o2 = o1) != null) { /* */ }\n" + 
1153
			"  }\n" + 
1154
			"}\n"},
1155
		"----------\n" + 
1156
		"1. ERROR in X.java (at line 3)\n" + 
1157
		"	if (o1 != null && (o2 = o1) != null) { /* */ }\n" + 
1158
		"	                  ^^^^^^^^^\n" + 
1159
		"The variable o2 cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
1160
		"----------\n"
1161
	);
1162
}
1163
1164
public void test0081_shortcut_boolean_expressions() {
1165
	this.runNegativeTest(
1166
		new String[] {
1167
			"X.java",
1168
			"public class X {\n" + 
1169
			"  void foo(Object o1, Object o2) {\n" + 
1170
			"    while (o1 != null && (o2 = o1) != null) { /* */ }\n" + 
1171
			"  }\n" + 
1172
			"}\n"},
1173
		"----------\n" + 
1174
		"1. ERROR in X.java (at line 3)\n" + 
1175
		"	while (o1 != null && (o2 = o1) != null) { /* */ }\n" + 
1176
		"	                     ^^^^^^^^^\n" + 
1177
		"The variable o2 cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
1178
		"----------\n"
1179
	);
1180
}
1181
1182
// null analysis - shortcut boolean expression
1183
public void test0082_shortcut_boolean_expression() {
1184
	this.runNegativeTest(
1185
		new String[] {
1186
			"X.java",
1187
			"public class X {\n" + 
1188
			"  void foo(Object o) {\n" + 
1189
			"    if (o == null || o == null) {\n" + 
1190
			"      o = new Object();\n" + 
1191
			"    }\n" + 
1192
			"    if (o == null) { /* */ }\n" + 
1193
			"  }\n" + 
1194
			"}"},
1195
		"----------\n" + 
1196
		"1. ERROR in X.java (at line 3)\n" + 
1197
		"	if (o == null || o == null) {\n" + 
1198
		"	                 ^\n" + 
1199
		"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
1200
		"----------\n" + 
1201
		"2. ERROR in X.java (at line 6)\n" + 
1202
		"	if (o == null) { /* */ }\n" + 
1203
		"	    ^\n" + 
1204
		"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
1205
		"----------\n");
1206
}
1207
1208
// null analysis - shortcut boolean expression
1209
public void test0083_shortcut_boolean_expression() {
1210
	this.runNegativeTest(
1211
		new String[] {
1212
			"X.java",
1213
			"public class X {\n" + 
1214
			"  void foo(Object o) {\n" + 
1215
			"    if (o == null && o == null) {\n" + 
1216
			"      o = new Object();\n" + 
1217
			"    }\n" + 
1218
			"    if (o == null) { /* */ }\n" + 
1219
			"  }\n" + 
1220
			"}"},
1221
		"----------\n" + 
1222
		"1. ERROR in X.java (at line 3)\n" + 
1223
		"	if (o == null && o == null) {\n" + 
1224
		"	                 ^\n" + 
1225
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
1226
		"----------\n" + 
1227
		"2. ERROR in X.java (at line 6)\n" + 
1228
		"	if (o == null) { /* */ }\n" + 
1229
		"	    ^\n" + 
1230
		"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
1231
		"----------\n");
1232
}
1233
1234
// null analysis -- instanceof
1235
// JLS: instanceof returns false if o turns out to be null
1236
public void test0090_instanceof() {
1237
	this.runConformTest(
1238
		new String[] {
1239
			"X.java",
1240
			"class X {\n" + 
1241
			"  boolean dummy;\n" + 
1242
			"  void foo (Object o) {\n" + 
1243
			"	if (dummy) {\n" + 
1244
			"	  o = null;\n" + 
1245
			"	}\n" + 
1246
			"	if (o instanceof X) { /* */ }\n" + 
1247
			"  }\n" + 
1248
			"}"},
1249
		"");
1250
}
1251
1252
// null analysis -- instanceof
1253
public void test0091_instanceof() {
1254
	this.runConformTest(
1255
		new String[] {
1256
			"X.java",
1257
			"class X {\n" + 
1258
			"  boolean dummy;\n" + 
1259
			"  void foo (Object o) {\n" + 
1260
			"	if (dummy) {\n" + 
1261
			"	  o = null;\n" + 
1262
			"	}\n" + 
1263
			"	if (o instanceof X) { /* */ }\n" + 
1264
			"	if (o == null) { /* */ }\n" + 
1265
			"  }\n" + 
1266
			"}"},
1267
		"");
1268
}
1269
1270
// null analysis -- instanceof
1271
// can only be null always yields false
1272
public void test0092_instanceof() {
1273
	this.runNegativeTest(
1274
		new String[] {
1275
			"X.java",
1276
			"class X {\n" + 
1277
			"  boolean dummy;\n" + 
1278
			"  void foo () {\n" + 
1279
			"	Object o = null;\n" + 
1280
			"	if (o instanceof X) { /* */ }\n" + 
1281
			"  }\n" + 
1282
			"}"},
1283
		"----------\n" + 
1284
		"1. ERROR in X.java (at line 5)\n" + 
1285
		"	if (o instanceof X) { /* */ }\n" + 
1286
		"	    ^\n" + 
1287
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
1288
		"----------\n");
1289
}
1290
1291
// null analysis -- instanceof
1292
public void test0093_instanceof() {
1293
	this.runNegativeTest(
1294
		new String[] {
1295
			"X.java",
1296
			"class X {\n" + 
1297
			"  void foo(Object x) {\n" + 
1298
			"    if (x instanceof X) {\n" + 
1299
			"      if (x == null) { /* */ }\n" + // cannot happen 
1300
			"    }\n" + 
1301
			"  }\n" + 
1302
			"}"},
1303
		"----------\n" + 
1304
		"1. ERROR in X.java (at line 4)\n" + 
1305
		"	if (x == null) { /* */ }\n" + 
1306
		"	    ^\n" + 
1307
		"The variable x cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
1308
		"----------\n");
1309
}
1310
1311
// null analysis -- instanceof
1312
public void test0094_instanceof() {
1313
	this.runConformTest(
1314
		new String[] {
1315
			"X.java",
1316
			"class X {\n" + 
1317
			"  void foo(Object x) {\n" + 
1318
			"    if (x instanceof X) {\n" + 
1319
			"      return;\n" + 
1320
			"    }\n" + 
1321
			"    if (x != null) { /* */ }\n" + 
1322
			// cannot decide: could be null of new Object() for example  
1323
			"  }\n" + 
1324
			"}"},
1325
		"");
1326
}
1327
1328
// null analysis -- if/else
1329
// check that obviously unreachable code does not modify the null
1330
// status of a local
1331
// the said code is not marked as unreachable per JLS 14.21 (the rationale
1332
// being the accommodation for the if (constant_flag_evaluating_to_false)
1333
// {code...} volontary code exclusion pattern)
1334
public void test0300_if_else() {
1335
	this.runNegativeTest(
1336
		new String[] {
1337
			"X.java",
1338
			"public class X {\n" + 
1339
			"  public void foo() {\n" +         
1340
			"    Object o = null;\n" + 
1341
			"    if (false) {\n" + 
1342
			"      o = new Object();\n" + // skipped 
1343
			"    }\n" + 
1344
			"    if (true) {\n" + 
1345
			"      //\n" + 
1346
			"    }\n" + 
1347
			"    else {\n" + 
1348
			"      o = new Object();\n" + // skipped
1349
			"    }\n" + 
1350
			"    o.toString();\n" + 
1351
			"  }\n" + 
1352
			"}\n"},
1353
		"----------\n" + 
1354
		"1. ERROR in X.java (at line 13)\n" + 
1355
		"	o.toString();\n" + 
1356
		"	^\n" + 
1357
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
1358
		"----------\n");
1359
}
1360
1361
// null analysis - if/else
1362
public void test0301_if_else() {
1363
	this.runNegativeTest(
1364
		new String[] {
1365
			"X.java",
1366
			"public class X {\n" + 
1367
			"  void foo() {\n" + 
1368
			"    Object o = new Object();\n" + 
1369
			"    if (o != null) {\n" + 
1370
			"    }\n" + 
1371
			"  }\n" + 
1372
			"}\n"},
1373
		"----------\n" + 
1374
		"1. ERROR in X.java (at line 4)\n" + 
1375
		"	if (o != null) {\n" + 
1376
		"	    ^\n" + 
1377
		"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
1378
		"----------\n");
1379
}
1380
1381
// null analysis - if/else
1382
public void test0302_if_else() {
1383
	this.runNegativeTest(
1384
		new String[] {
1385
			"X.java",
1386
			"public class X {\n" + 
1387
			"  void foo(Object o) throws Exception {\n" + 
1388
			"    if (o == null) {\n" + 
1389
			"      throw new Exception();\n" + 
1390
			"    }\n" + 
1391
			"    if (o != null) {\n" + // only get there if o non null
1392
			"    }\n" + 
1393
			"  }\n" + 
1394
			"}\n"},
1395
		"----------\n" + 
1396
		"1. ERROR in X.java (at line 6)\n" + 
1397
		"	if (o != null) {\n" + 
1398
		"	    ^\n" + 
1399
		"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
1400
		"----------\n");
1401
}
1402
1403
// null analysis - if/else
1404
public void test0303_if_else() {
1405
	this.runNegativeTest(
1406
		new String[] {
1407
			"X.java",
1408
			"public class X {\n" + 
1409
			"  void foo(Object o) {\n" + 
1410
			"    if (o == null) {\n" + 
1411
			"      return;\n" + 
1412
			"    }\n" + 
1413
			"    if (o != null) {\n" + 
1414
			"    }\n" + 
1415
			"  }\n" + 
1416
			"}\n"},
1417
		"----------\n" + 
1418
		"1. ERROR in X.java (at line 6)\n" + 
1419
		"	if (o != null) {\n" + 
1420
		"	    ^\n" + 
1421
		"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
1422
		"----------\n");
1423
}
1424
1425
// null analysis - if/else
1426
public void test0304_if_else() {
1427
	this.runNegativeTest(
1428
		new String[] {
1429
			"X.java",
1430
			"public class X {\n" + 
1431
			"  void foo(Object o) {\n" + 
1432
			"    if (o == null) {\n" + 
1433
			"      o.toString();\n" + 
1434
			"    }\n" + 
1435
			"  }\n" + 
1436
			"}\n"},
1437
		"----------\n" + 
1438
		"1. ERROR in X.java (at line 4)\n" + 
1439
		"	o.toString();\n" + 
1440
		"	^\n" + 
1441
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
1442
		"----------\n");
1443
}
1444
1445
// null analysis - if/else
1446
public void test0305_if_else() {
1447
	this.runNegativeTest(
1448
		new String[] {
1449
			"X.java",
1450
			"public class X {\n" + 
1451
			"  void foo(Object o) {\n" + 
1452
			"    if (o == null) {\n" + 
1453
			"      // do nothing\n" + 
1454
			"    }\n" + 
1455
			"    o.toString();\n" + 
1456
			"  }\n" + 
1457
			"}\n"},
1458
		"----------\n" + 
1459
		"1. ERROR in X.java (at line 6)\n" + 
1460
		"	o.toString();\n" + 
1461
		"	^\n" + 
1462
		"The variable o may be null\n" + 
1463
		"----------\n");
1464
}
1465
1466
// null analysis - if/else
1467
public void test0306_if_else() {
1468
	this.runNegativeTest(
1469
		new String[] {
1470
			"X.java",
1471
			"public class X {\n" + 
1472
			"  void foo(Object o) {\n" + 
1473
			"    if (o.toString().equals(\"\")) {\n" + 
1474
			"      if (o == null) {\n" + // complain: could not get here 
1475
			"        // do nothing\n" + 
1476
			"      }\n" + 
1477
			"    }\n" + 
1478
			"  }\n" + 
1479
			"}\n"},
1480
		"----------\n" + 
1481
		"1. ERROR in X.java (at line 4)\n" + 
1482
		"	if (o == null) {\n" + 
1483
		"	    ^\n" + 
1484
		"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
1485
		"----------\n");
1486
}
1487
1488
// null analysis - if/else
1489
public void test0307_if_else() {
1490
	this.runConformTest(
1491
		new String[] {
1492
			"X.java",
1493
			"public class X {\n" + 
1494
			"  void foo(Object o) {\n" + 
1495
			"    if (o ==  null) {\n" + 
1496
			"      System.exit(0);\n" + 
1497
			"    }\n" + 
1498
			"    if (o == null) {\n" + 
1499
			  // quiet 
1500
			  // a direct call to System.exit() can be recognized as such; yet,
1501
			  // a lot of other methods may have the same property (aka calling
1502
			  // System.exit() themselves.)
1503
			"      // do nothing\n" + 
1504
			"    }\n" + 
1505
			"  }\n" + 
1506
			"}\n"},
1507
		"");
1508
}   
1509
1510
// null analysis - if/else
1511
public void test0308_if_else() {
1512
	this.runNegativeTest(
1513
		new String[] {
1514
			"X.java",
1515
			"public class X {\n" + 
1516
			"  boolean b;\n" + 
1517
			"  void foo(Object o) {\n" + 
1518
			"    if (b) {\n" + 
1519
			"      o = null;\n" + 
1520
			"    }\n" + 
1521
			"    o.toString();\n" + // complain
1522
			"  }\n" + 
1523
			"}\n"},
1524
		"----------\n" + 
1525
		"1. ERROR in X.java (at line 7)\n" + 
1526
		"	o.toString();\n" + 
1527
		"	^\n" + 
1528
		"The variable o may be null\n" + 
1529
		"----------\n");
1530
}   
1531
1532
// null analysis - if/else
1533
public void test0309_if_else() {
1534
	this.runNegativeTest(
1535
		new String[] {
1536
			"X.java",
1537
			"public class X {\n" + 
1538
			"  boolean b1, b2;\n" + 
1539
			"  void foo(Object o) {\n" + 
1540
			"    if (b1) {\n" + 
1541
			"      o = null;\n" + 
1542
			"    }\n" + 
1543
			"    if (b2) {\n" + 
1544
			"      o = new Object();\n" + 
1545
			"    }\n" + 
1546
			"    o.toString();\n" + // complain
1547
			"  }\n" + 
1548
			"}\n"},
1549
		"----------\n" + 
1550
		"1. ERROR in X.java (at line 10)\n" + 
1551
		"	o.toString();\n" + 
1552
		"	^\n" + 
1553
		"The variable o may be null\n" + 
1554
		"----------\n");
1555
}   
1556
1557
// null analysis - if/else
1558
public void test0310_if_else() {
1559
	this.runNegativeTest(
1560
		new String[] {
1561
			"X.java",
1562
			"public class X {\n" + 
1563
			"  boolean b1, b2;\n" + 
1564
			"  void foo(Object o) {\n" + 
1565
			"    if (b1) {\n" + 
1566
			"      o = null;\n" + 
1567
			"    }\n" + 
1568
			"    if (b2) {\n" + 
1569
			"      o.toString();\n" + // complain
1570
			"      o.toString();\n" + // silent
1571
			"    }\n" + 
1572
			"    o.toString();\n" + // complain
1573
			"  }\n" + 
1574
			"}\n"},
1575
		"----------\n" + 
1576
		"1. ERROR in X.java (at line 8)\n" + 
1577
		"	o.toString();\n" + 
1578
		"	^\n" + 
1579
		"The variable o may be null\n" + 
1580
		"----------\n" + 
1581
		"2. ERROR in X.java (at line 11)\n" + 
1582
		"	o.toString();\n" + 
1583
		"	^\n" + 
1584
		"The variable o may be null\n" + 
1585
		"----------\n");
1586
}   
1587
1588
// null analysis - if/else
1589
public void test0311_if_else() {
1590
	this.runConformTest(
1591
		new String[] {
1592
			"X.java",
1593
			"public class X {\n" + 
1594
			"  void foo(Object o) {\n" + 
1595
			"    if (o == null)\n" + 
1596
			"      o = new Object();\n" + 
1597
			"    o.toString();\n" + // quiet 
1598
			"  }\n" + 
1599
			"}"	},
1600
		"");
1601
}
1602
1603
// null analysis - if/else
1604
// PMT: exactly the case we talked about; what happens is that the first
1605
// if shade doubts upon o; what we could do is to avoid marking in case
1606
// of error? not sure this is appropriate though, because of inner code
1607
// into the if itself; I believe I somewhat did that on purpose: the latest
1608
// wins; completed with o.toString()...
1609
// basically, the choice is about what we should do in case of error:
1610
// neglect the effect of the error, or propagate this effect; the second
1611
//  tends to produce less repeated errors (I believe) than the first...
1612
// PREMATURE could refine adding a null-dependent reachable mark... not urgent
1613
public void test0312_if_else() {
1614
	this.runNegativeTest(
1615
		new String[] {
1616
			"X.java",
1617
			"public class X {\n" + 
1618
			"\n" + 
1619
			"  void foo() {\n" + 
1620
			"    Object o = new Object();\n" + 
1621
			"    if (o == null) { /* */ }\n" + // complain 
1622
			"    if (o != null) { /* */ }\n" + // quiet
1623
			"    o.toString();\n" + // complain
1624
			"  }\n" + 
1625
			"}\n"},
1626
		"----------\n" + 
1627
		"1. ERROR in X.java (at line 5)\n" + 
1628
		"	if (o == null) { /* */ }\n" + 
1629
		"	    ^\n" + 
1630
		"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
1631
		"----------\n" + 
1632
		"2. ERROR in X.java (at line 7)\n" + 
1633
		"	o.toString();\n" + 
1634
		"	^\n" + 
1635
		"The variable o may be null\n" + 
1636
		"----------\n");
1637
}
1638
 
1639
// null analysis - if/else
1640
public void test0313_if_else() {
1641
	this.runNegativeTest(
1642
		new String[] {
1643
			"X.java",
1644
			"public class X {\n" + 
1645
			"  void foo(Object o) {\n" + 
1646
			"    if (o == null) {\n" + // quiet 
1647
			"      o = new Object();\n" + 
1648
			"    }\n" + 
1649
			"    if (o == null) { /* */ }\n" + 
1650
			// complain: o set to non null iff it was null 
1651
			"  }\n" + 
1652
			"}"},
1653
		"----------\n" + 
1654
		"1. ERROR in X.java (at line 6)\n" + 
1655
		"	if (o == null) { /* */ }\n" + 
1656
		"	    ^\n" + 
1657
		"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
1658
		"----------\n");
1659
}
1660
1661
// null analysis - if/else
1662
public void test0314_if_else() {
1663
	this.runNegativeTest(
1664
		new String[] {
1665
			"X.java",
1666
			"public class X {\n" + 
1667
			"  void foo(Object o) {\n" + 
1668
			"    if (o != null) {\n" + // quiet 
1669
			"      o = null;\n" + 
1670
			"    }\n" + 
1671
			"    if (o == null) { /* */ }\n" + // complain 
1672
			"  }\n" + 
1673
			"}"},
1674
		"----------\n" + 
1675
		"1. ERROR in X.java (at line 6)\n" + 
1676
		"	if (o == null) { /* */ }\n" + 
1677
		"	    ^\n" + 
1678
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
1679
		"----------\n");
1680
}
1681
1682
// null analysis - if/else
1683
public void test0315_if_else() {
1684
	this.runNegativeTest(
1685
		new String[] {
1686
			"X.java",
1687
			"public class X {\n" + 
1688
			"  void foo(Object o) {\n" + 
1689
			"    if (o != null) {\n" + // quiet 
1690
			"      o = null;\n" + 
1691
			"    }\n" + 
1692
			"    o.toString();\n" + // complain 
1693
			"  }\n" + 
1694
			"}"},
1695
		"----------\n" + 
1696
		"1. ERROR in X.java (at line 6)\n" + 
1697
		"	o.toString();\n" + 
1698
		"	^\n" + 
1699
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
1700
		"----------\n");
1701
}
1702
1703
// null analysis - if/else
1704
public void test0316_if_else() {
1705
	this.runNegativeTest(
1706
		new String[] {
1707
			"X.java",
1708
			"public class X {\n" + 
1709
			"  void foo(Object o, boolean b) {\n" + 
1710
			"    if (o == null || b) { /* */ }\n" + // quiet 
1711
			"    else { /* */ }\n" + 
1712
			"    o.toString();\n" + // complain 
1713
			"  }\n" + 
1714
			"}"},
1715
		"----------\n" + 
1716
		"1. ERROR in X.java (at line 5)\n" + 
1717
		"	o.toString();\n" + 
1718
		"	^\n" + 
1719
		"The variable o may be null\n" + 
1720
		"----------\n");
1721
}
1722
1723
// null analysis - if/else
1724
public void test0317_if_else_nested() {
1725
	this.runConformTest(
1726
		new String[] {
1727
			"X.java",
1728
			"public class X {\n" + 
1729
			"  void foo(Object o, boolean b) {\n" + 
1730
			"    if (o != null) {\n" + // quiet 
1731
			"      if (b) {\n" + // quiet 
1732
			"        o = null;\n" + 
1733
			"      }\n" + 
1734
			"    }\n" + 
1735
			"    if (o == null) { /* */ }\n" + // quiet 
1736
			"  }\n" + 
1737
			"}"},
1738
		"");
1739
}
1740
1741
// null analysis - if/else
1742
public void test0318_if_else_nested() {
1743
	this.runConformTest(
1744
		new String[] {
1745
			"X.java",
1746
			"public class X {\n" + 
1747
			"  void foo(Object o, boolean b) {\n" + 
1748
			"    if (o != null) {\n" + // quiet 
1749
			"      if (b) {\n" + // quiet 
1750
			"        o = null;\n" + 
1751
			"      }\n" + 
1752
			"      if (o == null) { /* */ }\n" + // quiet 
1753
			"    }\n" + 
1754
			"  }\n" + 
1755
			"}"},
1756
		"");
1757
}
1758
1759
// null analysis - if/else
1760
// REVIEW we do nothing at this point to diagnose the contents of fake reachable code
1761
public void test0319_if_else_dead_branch() {
1762
	this.runConformTest(
1763
		new String[] {
1764
			"X.java",
1765
			"public class X {\n" + 
1766
			"  void foo(Object o, boolean b) {\n" + 
1767
			"    if (false) {\n" + 
1768
			"      o = null;\n" + 
1769
			"      if (o == null) { /* */ }\n" + 
1770
			"    }\n" + 
1771
			"  }\n" + 
1772
			"}"},
1773
		"");
1774
}
1775
1776
// null analysis - if/else
1777
public void test0320_if_else() {
1778
	this.runNegativeTest(
1779
		new String[] {
1780
			"X.java",
1781
			"public class X {\n" + 
1782
			"  void foo(Object o) {\n" + 
1783
			"    o.toString();\n" + 
1784
			"    if (o == null) { /* */ }\n" + // complain 
1785
			"  }\n" + 
1786
			"}"},
1787
		"----------\n" + 
1788
		"1. ERROR in X.java (at line 4)\n" + 
1789
		"	if (o == null) { /* */ }\n" + 
1790
		"	    ^\n" + 
1791
		"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
1792
		"----------\n");
1793
}
1794
1795
// null analysis - if/else
1796
public void test0321_if_else() {
1797
	this.runConformTest(
1798
		new String[] {
1799
			"X.java",
1800
			"public class X {\n" + 
1801
			"  void foo(Object o, boolean b) {\n" + 
1802
			"    Object other = new Object();\n" + 
1803
			"    if (b) {\n" +
1804
			"      other = o;\n" + 
1805
			"    }\n" + 
1806
			"    if (o != null) { /* */ }\n" + // quiet 
1807
			"  }\n" + 
1808
			"}"},
1809
		"");
1810
}
1811
1812
// null analysis - if/else
1813
public void test0322_if_else() {
1814
	this.runNegativeTest(
1815
		new String[] {
1816
			"X.java",
1817
			"public class X {\n" + 
1818
			"  void foo(Object o, boolean b) {\n" + 
1819
			"    o.toString();\n" + 
1820
			"    if (b) { /* */ }\n" + 
1821
			"    if (o == null) { /* */ }\n" + // complain 
1822
			"  }\n" + 
1823
			"}"},
1824
		"----------\n" + 
1825
		"1. ERROR in X.java (at line 5)\n" + 
1826
		"	if (o == null) { /* */ }\n" + 
1827
		"	    ^\n" + 
1828
		"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
1829
		"----------\n");
1830
}
1831
1832
// null analysis - if/else
1833
public void test0323_if_else() {
1834
	this.runConformTest(
1835
		new String[] {
1836
			"X.java",
1837
			"public class X {\n" + 
1838
			"  void foo(Object o, boolean b) {\n" + 
1839
			"    if (o == null && b) {\n" + 
1840
			"      o = new Object();\n" + 
1841
			"    }\n" + 
1842
			"    if (o == null) { /* */ }\n" + // quiet 
1843
			"  }\n" + 
1844
			"}"},
1845
		"");
1846
}
1847
1848
// null analysis - if/else
1849
public void test0324_if_else_nested() {
1850
	this.runConformTest(
1851
		new String[] {
1852
			"X.java",				
1853
			"class X {\n" + 
1854
			"  void foo (boolean b) {\n" + 
1855
			"    String s = null;\n" + 
1856
			"    if (b) {\n" + 
1857
			"      if (b) {\n" + 
1858
			"        s = \"1\";\n" + 
1859
			"      } \n" + 
1860
			"      else {\n" + 
1861
			"        s = \"2\";\n" + 
1862
			"      }\n" + 
1863
			"    } \n" + 
1864
			"    else if (b) {\n" + 
1865
			"      s = \"3\"; \n" + 
1866
			"    } \n" + 
1867
			"    else {\n" + 
1868
			"      s = \"4\";\n" + 
1869
			"    }\n" + 
1870
			"    s.toString();\n" + 
1871
			"  }\n" + 
1872
			"}"},
1873
		"");
1874
}
1875
1876
// null analysis - if/else
1877
public void test0325_if_else_nested() {
1878
	this.runNegativeTest(
1879
		new String[] {
1880
			"X.java",				
1881
			"class X {\n" + 
1882
			"  void foo (boolean b) {\n" + 
1883
			"    String s = null;\n" + 
1884
			"    if (b) {\n" + 
1885
			"      if (b) {\n" + 
1886
			"        s = \"1\";\n" + 
1887
			"      } \n" + 
1888
			"      else {\n" + 
1889
			"        s = \"2\";\n" + 
1890
			"      }\n" + 
1891
			"    } \n" + 
1892
			"    else if (b) {\n" + 
1893
			"      if (b) {\n" + 
1894
			"        s = \"3\"; \n" + 
1895
			"      }\n" + 
1896
			"    } \n" + 
1897
			"    else {\n" + 
1898
			"      s = \"4\";\n" + 
1899
			"    }\n" + 
1900
			"    s.toString();\n" + 
1901
			"  }\n" + 
1902
			"}"},
1903
		"----------\n" + 
1904
		"1. ERROR in X.java (at line 20)\n" + 
1905
		"	s.toString();\n" + 
1906
		"	^\n" + 
1907
		"The variable s may be null\n" + 
1908
		"----------\n");
1909
}
1910
1911
// null analysis - if/else
1912
// REVIEW limit: we cannot sync on external factors, even if this is a pattern
1913
// REVIEW that is quite used
1914
public void test0326_if_else() {
1915
	this.runNegativeTest(
1916
		new String[] {
1917
			"X.java",				
1918
			"class X {\n" + 
1919
			"  void foo (boolean b) {\n" + 
1920
			"    String s1 = null;\n" + 
1921
			"    if (b) {\n" + 
1922
			"      s1 = \"1\";\n" + 
1923
			"    }\n" + 
1924
			"    s1.toString();\n" + // complain: can't guess if b means anything for s1 init 
1925
			"  }\n" + 
1926
			"}"},
1927
		"----------\n" + 
1928
		"1. ERROR in X.java (at line 7)\n" + 
1929
		"	s1.toString();\n" + 
1930
		"	^^\n" + 
1931
		"The variable s1 may be null\n" + 
1932
		"----------\n");
1933
}
1934
1935
// null analysis - if/else
1936
// REVIEW limit: we cannot sync on external factors, even if this is a pattern
1937
// REVIEW that is quite used
1938
public void test0327_if_else() {
1939
	this.runNegativeTest(
1940
		new String[] {
1941
			"X.java",				
1942
			"class X {\n" + 
1943
			"  void foo (String s1) {\n" + 
1944
			"    String s2 = null;\n" + 
1945
			"    if (s1 == null) {\n" + 
1946
			"      s1 = \"1\";\n" + 
1947
			"      s2 = \"2\";\n" + 
1948
			"    }\n" + 
1949
			"    s1.toString();\n" + // quiet 
1950
			"    s2.toString();\n" + // complain: can't guess whether s2 depends on s1 for init
1951
			"  }\n" + 
1952
			"}"},
1953
		"----------\n" + 
1954
		"1. ERROR in X.java (at line 9)\n" + 
1955
		"	s2.toString();\n" + 
1956
		"	^^\n" + 
1957
		"The variable s2 may be null\n" + 
1958
		"----------\n");
1959
}
1960
1961
// null analysis - if/else
1962
public void test0328_if_else() {
1963
	this.runNegativeTest(
1964
		new String[] {
1965
			"X.java",
1966
			"public class X {\n" + 
1967
			"  void foo(Object o, boolean b) {\n" + 
1968
			"    if (o != null || b) {\n" +
1969
			"      if (b) {\n" +
1970
			"        o = new Object();\n" +
1971
			"      }\n" +
1972
			"    }\n" + // quiet 
1973
			"    else { /* */ }\n" + 
1974
			"    o.toString();\n" + // complain 
1975
			"  }\n" + 
1976
			"}"},
1977
		"----------\n" + 
1978
		"1. ERROR in X.java (at line 9)\n" + 
1979
		"	o.toString();\n" + 
1980
		"	^\n" + 
1981
		"The variable o may be null\n" + 
1982
		"----------\n");
1983
}
1984
1985
// null analysis - if/else
1986
// REVIEW may be surprising within more elaborate code
1987
public void test0329_if_else_nested() {
1988
	this.runNegativeTest(
1989
		new String[] {
1990
			"X.java",
1991
			"public class X {\n" + 
1992
			"  void foo(Object o, boolean b) {\n" + 
1993
			"    if (b) {\n" +
1994
			"      if (o != null) { /* */ }\n" + // shade doubts on o
1995
			"    }\n" +  
1996
			"    o.toString();\n" + // complain 
1997
			"  }\n" + 
1998
			"}"},
1999
		"----------\n" + 
2000
		"1. ERROR in X.java (at line 6)\n" + 
2001
		"	o.toString();\n" + 
2002
		"	^\n" + 
2003
		"The variable o may be null\n" + 
2004
		"----------\n");
2005
}
2006
2007
// null analysis - if/else
2008
public void test0330_if_else_nested() {
2009
	this.runConformTest(
2010
		new String[] {
2011
			"X.java",
2012
			"public class X {\n" + 
2013
			"  void foo(Object o, boolean b) {\n" + 
2014
			"    if (b) {\n" +
2015
			"      if (o == null) {\n" +
2016
			"        o = new Object();\n" +
2017
			"      }\n" +
2018
			"    }\n" +
2019
			"    o.toString();\n" + // quiet 
2020
			"  }\n" + 
2021
			"}"},
2022
		"");
2023
}
2024
2025
// null analysis - if/else
2026
public void test0331_if_else_nested() {
2027
	this.runConformTest(
2028
		new String[] {
2029
			"X.java",
2030
			"public class X {\n" + 
2031
			"  void foo(Object o1, Object o2) {\n" + 
2032
			"    Object o3 = o2;\n" + 
2033
			"    if (o1 != null) {\n" + 
2034
			"      o3.toString(); // guards o3\n" + 
2035
			"    }\n" + 
2036
			"    o1 = o3;\n" + 
2037
			"    if (o1 != null) { /* */ }\n" + 
2038
			"  }\n" + 
2039
			"}"},
2040
		"");
2041
}
2042
2043
// null analysis - if/else
2044
public void test0332_if_else() {
2045
	this.runNegativeTest(
2046
		new String[] {
2047
			"X.java",
2048
			"public class X {\n" + 
2049
			"  void foo(Object o, boolean b) {\n" + 
2050
			"    o = new Object();\n" + 
2051
			"    if (b) {\n" +
2052
			"      o = new Object();\n" + 
2053
			"    }\n" + 
2054
			"    if (o != null) { /* */ }\n" + // complain 
2055
			"  }\n" + 
2056
			"}"},
2057
		"----------\n" + 
2058
		"1. ERROR in X.java (at line 7)\n" + 
2059
		"	if (o != null) { /* */ }\n" + 
2060
		"	    ^\n" + 
2061
		"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
2062
		"----------\n");
2063
}
2064
2065
// null analysis -- while
2066
public void test0401_while() {
2067
	this.runNegativeTest(
2068
		new String[] {
2069
			"X.java",
2070
			"public class X {\n" + 
2071
			"  void foo() {\n" + 
2072
			"    Object o = null;\n" + 
2073
			"    while (o.toString() != null) {/* */}\n" +
2074
			      // complain: NPE
2075
			"  }\n" + 
2076
			"}\n"},
2077
		"----------\n" + 
2078
		"1. ERROR in X.java (at line 4)\n" + 
2079
		"	while (o.toString() != null) {/* */}\n" + 
2080
		"	       ^\n" + 
2081
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
2082
		"----------\n");
2083
}
2084
2085
// null analysis -- while
2086
public void test0402_while() {
2087
	this.runNegativeTest(
2088
		new String[] {
2089
			"X.java",
2090
			"public class X {\n" + 
2091
			"  void foo() {\n" + 
2092
			"    Object o = null;\n" + 
2093
			"    while (o != null) {/* */}\n" + 
2094
			  // complain: get o null first time and forever
2095
			"  }\n" + 
2096
			"}\n"},
2097
		"----------\n" + 
2098
		"1. ERROR in X.java (at line 4)\n" + 
2099
		"	while (o != null) {/* */}\n" + 
2100
		"	       ^\n" + 
2101
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
2102
		"----------\n");
2103
}
2104
2105
// null analysis -- while
2106
public void test0403_while() {
2107
	this.runConformTest(
2108
		new String[] {
2109
			"X.java",
2110
			"public class X {\n" + 
2111
			"  void foo() {\n" + 
2112
			"    Object o = null;\n" + 
2113
			"    while (o == null) {\n" + 
2114
			      // quiet: first iteration is sure to find o null, 
2115
			      // but other iterations may change it 
2116
			"      o = new Object();\n" + 
2117
			"    }\n" + 
2118
			"  }\n" + 
2119
			"}\n"},
2120
		"");
2121
}
2122
2123
// null analysis -- while
2124
public void test0404_while() {
2125
	this.runConformTest(
2126
		new String[] {
2127
			"X.java",
2128
			"public class X {\n" + 
2129
			"  void foo() {\n" + 
2130
			"    Object o = null;\n" + 
2131
			"    while (o == null) {\n" + 
2132
			     // quiet: first iteration is sure to find o null, 
2133
			     // but other iterations may change it 
2134
			"      if (System.currentTimeMillis() > 10L) {\n" + 
2135
			"        o = new Object();\n" + 
2136
			"      }\n" + 
2137
			"    }\n" + 
2138
			"  }\n" + 
2139
			"}\n"},
2140
		"");
2141
}
2142
2143
// null analysis -- while
2144
public void test0405_while() {
2145
	this.runNegativeTest(
2146
		new String[] {
2147
			"X.java",
2148
			"public class X {\n" + 
2149
			"  boolean bar() {\n" + 
2150
			"    return true;\n" + 
2151
			"  }\n" + 
2152
			"  void foo(Object o) {\n" + 
2153
			"    while (bar() && o == null) {\n" + 
2154
			"      o.toString();\n" + // complain: NPE
2155
			"      o = new Object();\n" +
2156
			"    }\n" + 
2157
			"  }\n" + 
2158
			"}\n"},
2159
		"----------\n" + 
2160
		"1. ERROR in X.java (at line 7)\n" + 
2161
		"	o.toString();\n" + 
2162
		"	^\n" + 
2163
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
2164
		"----------\n");
2165
}
2166
2167
// null analysis -- while
2168
public void test0406_while() {
2169
	this.runNegativeTest(
2170
		new String[] {
2171
			"X.java",
2172
			"public class X {\n" + 
2173
			"  boolean dummy;\n" + 
2174
			"  void foo(Object o) {\n" + 
2175
			"    o = null;\n" +
2176
			"    while (dummy || o != null) { /* */ }\n" + // o can only be null 
2177
			"  }\n" + 
2178
			"}\n"},
2179
		"----------\n" + 
2180
		"1. ERROR in X.java (at line 5)\n" + 
2181
		"	while (dummy || o != null) { /* */ }\n" + 
2182
		"	                ^\n" + 
2183
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
2184
		"----------\n");
2185
}
2186
2187
// null analysis -- while
2188
public void test0407_while() {
2189
	this.runNegativeTest(
2190
		new String[] {
2191
			"X.java",
2192
			"public class X {\n" + 
2193
			"  boolean dummy;\n" + 
2194
			"  void foo() {\n" + 
2195
			"    Object o = null;\n" + 
2196
			"    while (dummy) {\n" +
2197
			"      o.toString();\n" +  // complain: NPE on first iteration
2198
			"      o = new Object();\n" +
2199
			"    }\n" +
2200
			"  }\n" + 
2201
			"}\n"},
2202
		"----------\n" + 
2203
		"1. ERROR in X.java (at line 6)\n" + 
2204
		"	o.toString();\n" + 
2205
		"	^\n" + 
2206
		"The variable o may be null\n" + 
2207
		"----------\n");
2208
}
2209
2210
// null analysis -- while
2211
// this test shows that, as long as we do not explore all possible
2212
// paths, we have to take potential initializations into account
2213
// even in branches that could be pruned in the first passes
2214
// first approximation is to stop pruning code conditioned by
2215
// variables
2216
// second approximation could still rely upon variables that are
2217
// never affected by the looping code (unassigned variables)
2218
// complete solution would call for multiple iterations in the
2219
// null analysis
2220
public void test0408_while() {
2221
	this.runConformTest(
2222
		new String[] {
2223
			"X.java",
2224
			"public class X {\n" + 
2225
			"  void foo() {\n" + 
2226
			"    Object o = null,\n" + 
2227
			"           u = new Object(),\n" + 
2228
			"           v = new Object();\n" + 
2229
			"    while (o == null) {\n" +
2230
			"      if (v == null) {\n" +
2231
			"        o = new Object();\n" +
2232
			"      };\n" +
2233
			"      if (u == null) {\n" +
2234
			"        v = null;\n" +
2235
			"      };\n" +
2236
			"      u = null;\n" +
2237
			"    }\n" +
2238
			"  }\n" + 
2239
			"}\n"},
2240
		"");
2241
}
2242
2243
// null analysis -- while
2244
public void test0409_while() {
2245
	this.runNegativeTest(
2246
		new String[] {
2247
			"X.java",
2248
			"public class X {\n" + 
2249
			"  boolean dummy;\n" + 
2250
			"  void foo() {\n" + 
2251
			"    Object o = null;\n" + 
2252
			"    while (dummy || (o = new Object()).equals(o)) {\n" +
2253
			"      o.toString();\n" +
2254
			"    }\n" +
2255
			"  }\n" + 
2256
			"}\n"},
2257
		"----------\n" + 
2258
		"1. ERROR in X.java (at line 6)\n" + 
2259
		"	o.toString();\n" + 
2260
		"	^\n" + 
2261
		"The variable o may be null\n" + 
2262
		"----------\n");
2263
}
2264
2265
// null analysis -- while
2266
public void test0410_while_nested() {
2267
	this.runConformTest(
2268
		new String[] {
2269
			"X.java",
2270
			"public class X {\n" + 
2271
			"  boolean dummy;\n" + 
2272
			"  void foo() {\n" + 
2273
			"    Object o = null;\n" + 
2274
			"    while (dummy) {\n" + 
2275
			"      while (o != null) {\n" + 
2276
			"        o.toString();\n" + 
2277
			"      }\n" + 
2278
			"      if (System.currentTimeMillis() > 10L) {\n" + 
2279
			"        o = new Object();\n" + 
2280
			"      }\n" + 
2281
			"    }\n" + 
2282
			"  }\n" + 
2283
			"}\n"},
2284
		"");
2285
}
2286
2287
// null analysis -- while
2288
public void test0411_while_nested() {
2289
	this.runConformTest(
2290
		new String[] {
2291
			"X.java",
2292
			"public class X {\n" + 
2293
			"  void foo() {\n" + 
2294
			"    Object o = null,\n" + 
2295
			"           u = new Object(),\n" + 
2296
			"           v = new Object();\n" + 
2297
			"    while (o == null) {\n" + 
2298
			"      if (v == null) {\n" +
2299
			"        o = new Object();\n" +
2300
			"      };\n" +
2301
			"      while (o == null) {\n" +
2302
			"        if (u == null) {\n" +
2303
			"          v = null;\n" +
2304
			"        };\n" +
2305
			"        u = null;\n" +
2306
			"      }\n" +
2307
			"    }\n" +
2308
			"  }\n" + 
2309
			"}\n"},
2310
		"");
2311
}
2312
2313
// null analysis -- while
2314
public void test0412_while_if_nested() {
2315
	this.runNegativeTest(
2316
		new String[] {
2317
			"X.java",
2318
			"public class X {\n" + 
2319
			"  boolean dummy, other;\n" + 
2320
			"  void foo() {\n" + 
2321
			"    Object o = null;\n" + 
2322
			"    while (dummy) {\n" +   
2323
			"      if (other) {\n" + 
2324
			"        o.toString();\n" +    
2325
			"      }\n" + 
2326
			"      o = new Object();\n" + 
2327
			"    }\n" + 
2328
			"  }\n" + 
2329
			"}\n"},
2330
		"----------\n" + 
2331
		"1. ERROR in X.java (at line 7)\n" + 
2332
		"	o.toString();\n" + 
2333
		"	^\n" + 
2334
		"The variable o may be null\n" + 
2335
		"----------\n");
2336
}
2337
2338
// null analysis -- while
2339
public void test0413_while_unknown_field() {
2340
	this.runConformTest(
2341
		new String[] {
2342
			"X.java",
2343
			"public class X {\n" + 
2344
			"  Object o;\n" + 
2345
			"  void foo(boolean dummy) {\n" + 
2346
			"    while (dummy) {\n" +
2347
			"      o = null;\n" +
2348
			"    }\n" +
2349
			"    o.toString();\n" +
2350
			"  }\n" + 
2351
			"}\n"},
2352
		"");
2353
}
2354
2355
// null analysis -- while
2356
public void test0414_while_unknown_parameter() {
2357
	this.runNegativeTest(
2358
		new String[] {
2359
			"X.java",
2360
			"public class X {\n" + 
2361
			"  boolean dummy;\n" + 
2362
			"  void foo(Object o) {\n" + 
2363
			"    while (dummy) {\n" +
2364
			"      o = null;\n" + // quiet: first iteration doesn't know
2365
			"    }\n" +
2366
			"    o.toString();\n" + // complain: only get out of the loop with null
2367
			"  }\n" + 
2368
			"}\n"},
2369
		"----------\n" + 
2370
		"1. ERROR in X.java (at line 7)\n" + 
2371
		"	o.toString();\n" + 
2372
		"	^\n" + 
2373
		"The variable o may be null\n" + 
2374
		"----------\n");
2375
}
2376
2377
// null analysis -- while
2378
public void test0415_while_unknown_if_else() {
2379
	this.runConformTest(
2380
		new String[] {
2381
			"X.java",
2382
			"public class X {\n" + 
2383
			"  boolean dummy;\n" + 
2384
			"  void foo() {\n" + 
2385
			"    Object o = null;\n" +
2386
			"    if (dummy) {\n" +
2387
			"      o = new Object();\n" +
2388
			"    }\n" +
2389
			"    while (dummy) {\n" + 
2390
			  // limit of the analysis: we do not correlate if and while conditions
2391
			"      if (o == null) {/* */}\n" + 
2392
			"    }\n" +
2393
			"  }\n" + 
2394
			"}\n"},
2395
		"");
2396
}
2397
2398
// null analysis -- while
2399
public void test0416_while() {
2400
	this.runNegativeTest(
2401
		new String[] {
2402
			"X.java",
2403
			"public class X {\n" + 
2404
			"  boolean dummy;\n" + 
2405
			"  void foo() {\n" + 
2406
			"    Object o = null;\n" + 
2407
			"    while (dummy) {\n" + 
2408
			"      o = new Object();\n" + 
2409
			"    }\n" + 
2410
			"    o.toString();\n" + 
2411
			"  }\n" + 
2412
			"}\n"},
2413
		"----------\n" + 
2414
		"1. ERROR in X.java (at line 8)\n" + 
2415
		"	o.toString();\n" + 
2416
		"	^\n" + 
2417
		"The variable o may be null\n" + 
2418
		"----------\n");
2419
}
2420
2421
// null analysis -- while
2422
public void test0417_while() {
2423
	this.runNegativeTest(
2424
		new String[] {
2425
			"X.java",
2426
			"public class X {\n" + 
2427
			"  boolean dummy;\n" + 
2428
			"  void foo() {\n" + 
2429
			"    Object o = null;\n" + 
2430
			"    while (dummy) { /* */ }\n" + // doesn't affect o
2431
			"    o.toString();\n" + 
2432
			"  }\n" + 
2433
			"}\n"},
2434
		"----------\n" + 
2435
		"1. ERROR in X.java (at line 6)\n" + 
2436
		"	o.toString();\n" + 
2437
		"	^\n" + 
2438
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
2439
		"----------\n");
2440
}
2441
2442
// null analysis -- while
2443
// origin AssignmentTest.testO22
2444
public void test0418_while_try() {
2445
	this.runConformTest(
2446
		new String[] {
2447
			"X.java",
2448
			"public class X {\n" + 
2449
			"  boolean bool() { return true; }\n" + 
2450
			"  void foo() {\n" + 
2451
			"    Object o = null;\n" + 
2452
			"    while (bool()) {\n" + 
2453
			"      try {\n" + 
2454
			"        if (o == null) {\n" + 
2455
			"          o = new Object();\n" + 
2456
			"        }\n" + 
2457
			"      } finally { /* */ }\n" + 
2458
			"    }\n" + 
2459
			"  }\n" + 
2460
			"}"},
2461
		"");
2462
}
2463
2464
// null analysis -- while
2465
public void test0419_while() {
2466
	this.runNegativeTest(
2467
		new String[] {
2468
			"X.java",
2469
			"public class X {\n" + 
2470
			"  boolean bool;\n" + 
2471
			"  void foo(Object o) {\n" + 
2472
			"    while (bool) {\n" + 
2473
			"      o.toString();" + // complain NPE because of second iteration
2474
			"      o = null;\n" + 
2475
			"    }\n" + 
2476
			"  }\n" + 
2477
			"}"},
2478
		"----------\n" + 
2479
		"1. ERROR in X.java (at line 5)\n" + 
2480
		"	o.toString();      o = null;\n" + 
2481
		"	^\n" + 
2482
		"The variable o may be null\n" + 
2483
		"----------\n");
2484
}
2485
2486
// null analysis -- while
2487
public void test0420_while() {
2488
	this.runNegativeTest(
2489
		new String[] {
2490
			"X.java",
2491
			"public class X {\n" + 
2492
			"  boolean bool;\n" + 
2493
			"  void foo(Object compare) {\n" + 
2494
			"    Object o = new Object();\n" + 
2495
			"    while ((o = null) == compare) {\n" + 
2496
			"      if (true) {\n" +
2497
			"        break;\n" + 
2498
			"      }\n" + 
2499
			"    }\n" + 
2500
			"    if (o == null) { /* */ }\n" + // complain can only be null
2501
			"  }\n" + 
2502
			"}"},
2503
		"----------\n" + 
2504
		"1. ERROR in X.java (at line 10)\n" + 
2505
		"	if (o == null) { /* */ }\n" + 
2506
		"	    ^\n" + 
2507
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
2508
		"----------\n");
2509
}
2510
2511
// null analysis -- while
2512
public void test0421_while() {
2513
	this.runConformTest(
2514
		new String[] {
2515
			"X.java",
2516
			"public class X {\n" + 
2517
			"  boolean bool;\n" + 
2518
			"  void foo(Object compare) {\n" + 
2519
			"    Object o = null;\n" + 
2520
			"    while (bool) {\n" + 
2521
			"      o = new Object();\n" +
2522
			"      o.toString();\n" + 
2523
			"    }\n" + 
2524
			"  }\n" + 
2525
			"}"},
2526
		"");
2527
}
2528
2529
// null analysis -- while
2530
public void test0422_while() {
2531
	this.runNegativeTest(
2532
		new String[] {
2533
			"X.java",
2534
			"public class X {\n" + 
2535
			"  boolean bool;\n" + 
2536
			"  void foo() {\n" + 
2537
			"    Object o;\n" + 
2538
			"    while (bool) {\n" + 
2539
			"      o = new Object();\n" +
2540
			"      if (o == null) { /* */ }\n" + 
2541
			"      o = null;\n" +
2542
			"    }\n" + 
2543
			"  }\n" + 
2544
			"}"},
2545
		"----------\n" + 
2546
		"1. ERROR in X.java (at line 7)\n" + 
2547
		"	if (o == null) { /* */ }\n" + 
2548
		"	    ^\n" + 
2549
		"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
2550
		"----------\n");
2551
}
2552
2553
// null analysis -- while
2554
// REVIEW we get one extraneous message that looks a bit strange
2555
public void test0423_while() {
2556
	this.runNegativeTest(
2557
		new String[] {
2558
			"X.java",
2559
			"public class X {\n" + 
2560
			"  boolean bool;\n" + 
2561
			"  void foo() {\n" + 
2562
			"    Object o = null;\n" + 
2563
			"    while (bool) {\n" + 
2564
			"      o = new Object();\n" +
2565
			"      if (o == null) { /* */ }\n" + 
2566
			"      o = null;\n" +
2567
			"    }\n" + 
2568
			"  }\n" + 
2569
			"}"},
2570
		"----------\n" + 
2571
		"1. ERROR in X.java (at line 7)\n" + 
2572
		"	if (o == null) { /* */ }\n" + 
2573
		"	    ^\n" + 
2574
		"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
2575
		"----------\n" + 
2576
		"2. ERROR in X.java (at line 8)\n" + 
2577
		"	o = null;\n" + 
2578
		"	^\n" + 
2579
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
2580
		"----------\n");
2581
}
2582
2583
// null analysis -- while
2584
public void test0424_while_try() {
2585
	this.runConformTest(
2586
		new String[] {
2587
			"X.java",
2588
			"public class X {\n" + 
2589
			"  void foo(boolean b) {\n" + 
2590
			"    Object o = null;\n" + 
2591
			"    while (o == null) {\n" + 
2592
			     // quiet: first iteration is sure to find o null, 
2593
			     // but other iterations may change it 
2594
			"      try { /* */ }\n" + 
2595
			"      finally {\n" + 
2596
			"        if (b) {\n" +
2597
			"          o = new Object();\n" +
2598
			"        }\n" + 
2599
			"      }\n" + 
2600
			"    }\n" + 
2601
			"  }\n" + 
2602
			"}\n"},
2603
		"");
2604
}
2605
2606
// null analysis -- while
2607
public void test0425_while() {
2608
	this.runNegativeTest(
2609
		new String[] {
2610
			"X.java",
2611
			"public class X {\n" + 
2612
			"  boolean dummy;\n" + 
2613
			"  void foo(Object u) {\n" + 
2614
			"    Object o = null;\n" + 
2615
			"    while (dummy) {\n" + 
2616
			"      o = u;\n" + 
2617
			"    }\n" + 
2618
			"    o.toString();\n" + 
2619
			"  }\n" + 
2620
			"}\n"},
2621
		"----------\n" + 
2622
		"1. ERROR in X.java (at line 8)\n" + 
2623
		"	o.toString();\n" + 
2624
		"	^\n" + 
2625
		"The variable o may be null\n" + 
2626
		"----------\n");
2627
}
2628
2629
// null analysis -- while
2630
public void test0426_while() {
2631
	this.runNegativeTest(
2632
		new String[] {
2633
			"X.java",
2634
			"public class X {\n" + 
2635
			"  boolean dummy;\n" + 
2636
			"  void foo(Object o) {\n" + 
2637
			"    o.toString();\n" + 
2638
			"    while (dummy) { /* */ }\n" + 
2639
			"    if (o == null) { /* */ }\n" + // complain 
2640
			"  }\n" + 
2641
			"}\n"},
2642
		"----------\n" + 
2643
		"1. ERROR in X.java (at line 6)\n" + 
2644
		"	if (o == null) { /* */ }\n" + 
2645
		"	    ^\n" + 
2646
		"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
2647
		"----------\n");
2648
}
2649
2650
// null analysis -- while
2651
public void test0427_while_return() {
2652
	this.runNegativeTest(
2653
		new String[] {
2654
			"X.java",
2655
			"public class X {\n" + 
2656
			"  boolean dummy;\n" + 
2657
			"  void foo() {\n" + 
2658
			"    Object o = null;\n" + 
2659
			"    while (dummy) {\n" + 
2660
			"      if (o == null) {\n" +
2661
			"        return;\n" +
2662
			"      }\n" + 
2663
			"    }\n" + 
2664
			"  }\n" + 
2665
			"}\n"},
2666
		"----------\n" + 
2667
		"1. ERROR in X.java (at line 6)\n" + 
2668
		"	if (o == null) {\n" + 
2669
		"	    ^\n" + 
2670
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
2671
		"----------\n");
2672
}
2673
2674
// null analysis - while
2675
public void test0428_while() {
2676
	this.runConformTest(
2677
		new String[] {
2678
			"X.java",
2679
			"public class X {\n" + 
2680
			"  X bar() {\n" + 
2681
			"    return null;\n" + 
2682
			"  }\n" + 
2683
			"  void foo(X x) {\n" + 
2684
			"    x.bar();\n" +  
2685
			"    while (x != null) {\n" +
2686
			"      x = x.bar();\n" +  
2687
			"    }\n" + 
2688
			"  }\n" + 
2689
			"}\n"},
2690
		"");
2691
} 
2692
2693
// null analysis - while
2694
public void test0429_while_nested() {
2695
	this.runConformTest(
2696
		new String[] {
2697
			"X.java",
2698
			"class X {\n" + 
2699
			"  boolean dummy;\n" + 
2700
			"  void foo (X[] xa) {\n" + 
2701
			"	while (dummy) {\n" + 
2702
			"	  xa = null;\n" + 
2703
			"	  if (dummy) {\n" + 
2704
			"	    xa = new X[5];\n" + 
2705
			"	  }\n" + 
2706
			"	  if (xa != null) {\n" + 
2707
			"		int i = 0;\n" + 
2708
			"		while (dummy) {\n" + 
2709
			"		  X x = xa[i++];\n" + 
2710
			"		  x.toString();\n" + 
2711
			"		}\n" + 
2712
			"	  }\n" + 
2713
			"	}\n" + 
2714
			"  }\n" + 
2715
			"}"},
2716
		"");
2717
} 
2718
2719
// null analysis - while
2720
public void test0430_while_for_nested() {
2721
	this.runConformTest(
2722
		new String[] {
2723
			"X.java",
2724
			"class X {\n" + 
2725
			"  boolean dummy;\n" + 
2726
			"  void foo (X[] xa) {\n" + 
2727
			"	while (dummy) {\n" + 
2728
			"	  xa = null;\n" + 
2729
			"	  if (dummy) {\n" + 
2730
			"	    xa = new X[5];\n" + 
2731
			"	  }\n" + 
2732
			"	  if (xa != null) {\n" + 
2733
			"		for (int i = 0; i < xa.length; i++) {\n" + 
2734
			"		  X x = xa[i];\n" + 
2735
			"		  x.toString();\n" + 
2736
			"		}\n" + 
2737
			"	  }\n" + 
2738
			"	}\n" + 
2739
			"  }\n" + 
2740
			"}"},
2741
		"");
2742
} 
2743
2744
// null analysis - while
2745
public void test0431_while() {
2746
	this.runConformTest(
2747
		new String[] {
2748
			"X.java",
2749
			"class X {\n" + 
2750
			"  boolean dummy;\n" + 
2751
			"  void foo (X x) {\n" + 
2752
			"	x = null;\n" + 
2753
			"	while (dummy) {\n" + 
2754
			"	  x = bar();\n" + 
2755
			"	  x.toString();\n" + 
2756
			"	}\n" + 
2757
			"  }\n" + 
2758
			"  X bar() {\n" + 
2759
			"	return null;\n" + 
2760
			"  }\n" + 
2761
			"}"},
2762
		"");
2763
} 
2764
2765
// null analysis - while
2766
public void test0432_while() {
2767
	this.runConformTest(
2768
		new String[] {
2769
			"X.java",
2770
			"class X {\n" + 
2771
			"  boolean dummy;\n" + 
2772
			"  void foo (X x) {\n" + 
2773
			"	while (dummy) {\n" + 
2774
			"	  x = bar();\n" + 
2775
			"	  x.toString();\n" + 
2776
			"	}\n" + 
2777
			"  }\n" + 
2778
			"  X bar() {\n" + 
2779
			"	return null;\n" + 
2780
			"  }\n" + 
2781
			"}"},
2782
		"");
2783
} 
2784
2785
// null analysis - while
2786
public void test0433_while() {
2787
	this.runNegativeTest(
2788
		new String[] {
2789
			"X.java",
2790
			"class X {\n" + 
2791
			"  boolean dummy;\n" + 
2792
			"  void foo (X x) {\n" + 
2793
			"	x = null;\n" +
2794
			"   while (dummy) {\n" + 
2795
			"	  x.toString();\n" + // complain and protect
2796
			"	  x.toString();\n" + // quiet
2797
			"	}\n" + 
2798
			"  }\n" + 
2799
			"}"},
2800
		"----------\n" + 
2801
		"1. ERROR in X.java (at line 6)\n" + 
2802
		"	x.toString();\n" + 
2803
		"	^\n" + 
2804
		"The variable x can only be null; it was either set to null or checked for null when last used\n" + 
2805
		"----------\n");
2806
}
2807
2808
// null analysis - while
2809
// this one shows that we cannot project definitely unknown onto potentially unknown too soon
2810
public void test0434_while_switch_nested() {
2811
	this.runConformTest(
2812
		new String[] {
2813
			"X.java",
2814
			"class X {\n" + 
2815
			"  Object bar() {\n" + 
2816
			"    return new Object();\n" + 
2817
			"  }\n" + 
2818
			"  void foo(boolean b, int selector) {\n" + 
2819
			"    Object o = null;\n" + 
2820
			"    while (b) {\n" + 
2821
			"      switch (selector) {\n" + 
2822
			"      case 0:\n" + 
2823
			"        o = bar();\n" + 
2824
			"        if (o != null) { \n" + 
2825
			"          return;\n" + 
2826
			"        }\n" + 
2827
			"      }\n" + 
2828
			"    }\n" + 
2829
			"  }\n" + 
2830
			"}"},
2831
		"");
2832
} 
2833
2834
// null analysis - while
2835
public void test0435_while_init() {
2836
	this.runConformTest(
2837
		new String[] {
2838
			"X.java",
2839
			"class X {\n" + 
2840
			"  int f1;\n" + 			
2841
			"  X f2;\n" + 			
2842
			"  void foo(X x1, boolean b) {\n" + 
2843
			"    X x2;\n" + 
2844
			"    x2 = x1;\n" + 
2845
			"    while (b) {\n" + 
2846
//			"      if (x2.f1 > 0) { /* */ }\n" + 
2847
			"      if (x2.toString().equals(\"\")) { /* */ }\n" + 
2848
			"      x2 = x2.f2;\n" + 
2849
			"    }\n" + 
2850
			"  }\n" + 
2851
			"}"},
2852
		"");
2853
} 
2854
2855
// null analysis - while
2856
public void test0436_while_init() {
2857
	this.runConformTest(
2858
		new String[] {
2859
			"X.java",
2860
			"class X {\n" + 
2861
			"  int f1;\n" + 			
2862
			"  X f2;\n" + 			
2863
			"  void foo(X x1, boolean b) {\n" + 
2864
			"    X x2 = x1;\n" + 
2865
			"    while (b) {\n" + 
2866
			"      if (x2.f1 > 0) { /* */ }\n" + 
2867
			"      x2 = x2.f2;\n" + 
2868
			"    }\n" + 
2869
			"  }\n" + 
2870
			"}"},
2871
		"");
2872
} 
2873
2874
// null analysis - while
2875
public void test0437_while_exit() {
2876
	this.runConformTest(
2877
		new String[] {
2878
			"X.java",
2879
			"class X {\n" + 
2880
			"  void foo(boolean b) {\n" + 
2881
			"    Object o = null;\n" + 
2882
			"    while (b) {\n" + 
2883
			"      if (b) {\n" + 
2884
			"        o = new Object();\n" + 
2885
			"      }\n" + 
2886
			"      if (o != null) {\n" + 
2887
			"        throw new RuntimeException(); \n" + 
2888
			"      }\n" + 
2889
			"    }\n" + 
2890
			"  }\n" + 
2891
			"}"},
2892
		"");
2893
} 
2894
2895
2896
// null analysis - while
2897
public void test0438_while() {
2898
	this.runNegativeTest(
2899
		new String[] {
2900
			"X.java",
2901
			"class X {\n" + 
2902
			"  void foo(Object o) {\n" + 
2903
			"    while (o == null) { /* */ }\n" + 
2904
			"    o.toString();\n" + // quiet 
2905
			"    if (o != null) { /* */ }\n" + // complain 
2906
			"  }\n" + 
2907
			"}"},
2908
		"----------\n" + 
2909
		"1. ERROR in X.java (at line 5)\n" + 
2910
		"	if (o != null) { /* */ }\n" + 
2911
		"	    ^\n" + 
2912
		"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
2913
		"----------\n");
2914
} 
2915
2916
// null analysis - while
2917
public void test0439_while() {
2918
	this.runNegativeTest(
2919
		new String[] {
2920
			"X.java",
2921
			"class X {\n" + 
2922
			"  void foo(Object o) {\n" + 
2923
			"    while (o == null) {\n" +
2924
			"      o = new Object();\n" +
2925
			"    }\n" + 
2926
			"    o.toString();\n" + // quiet 
2927
			"  }\n" + 
2928
			"}"},
2929
		"");
2930
} 
2931
2932
// null analysis - while
2933
public void test0440_while() {
2934
	this.runNegativeTest(
2935
		new String[] {
2936
			"X.java",
2937
			"class X {\n" + 
2938
			"  void foo(Object o) {\n" + 
2939
			"    while (o == null) {\n" +
2940
			"      o = new Object();\n" +
2941
			"    }\n" + 
2942
			"    if (o != null) { /* */ }\n" + // complain 
2943
			"  }\n" + 
2944
			"}"},
2945
		"----------\n" + 
2946
		"1. ERROR in X.java (at line 6)\n" + 
2947
		"	if (o != null) { /* */ }\n" + 
2948
		"	    ^\n" + 
2949
		"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
2950
		"----------\n");
2951
}
2952
2953
// null analysis - while
2954
public void test0441_while() {
2955
	this.runNegativeTest(
2956
		new String[] {
2957
			"X.java",
2958
			"class X {\n" + 
2959
			"  X bar() {\n" + 
2960
			"    return new X();\n" + 
2961
			"  }\n" + 
2962
			"  void foo(Object o) {\n" + 
2963
			"    while (o == null) {\n" +
2964
			"      o = bar();\n" +
2965
			"    }\n" + 
2966
			"    if (o != null) { /* */ }\n" + // complain 
2967
			"  }\n" + 
2968
			"}"},
2969
		"----------\n" + 
2970
		"1. ERROR in X.java (at line 9)\n" + 
2971
		"	if (o != null) { /* */ }\n" + 
2972
		"	    ^\n" + 
2973
		"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
2974
		"----------\n");
2975
}
2976
2977
// null analysis - while
2978
public void test0442_while() {
2979
	this.runNegativeTest(
2980
		new String[] {
2981
			"X.java",
2982
			"class X {\n" + 
2983
			"  boolean bar() {\n" + 
2984
			"    return true;\n" + 
2985
			"  }\n" + 
2986
			"  void foo(Object o) {\n" + 
2987
			"    while (o == null && bar()) { /* */ }\n" + 
2988
			"    o.toString();\n" + // complain 
2989
			"  }\n" + 
2990
			"}"},
2991
		"----------\n" + 
2992
		"1. ERROR in X.java (at line 7)\n" + 
2993
		"	o.toString();\n" + 
2994
		"	^\n" + 
2995
		"The variable o may be null\n" + 
2996
		"----------\n");
2997
} 
2998
2999
// null analysis - while
3000
public void test0443_while_nested() {
3001
	this.runConformTest(
3002
		new String[] {
3003
			"X.java",
3004
			"class X {\n" + 
3005
			"  void foo() {\n" + 
3006
			"    Object o = null;\n" + 
3007
			"    ext: for (int i = 0; i < 5 ; i++) {\n" + 
3008
			"        if (o != null) {\n" + 
3009
			"          break;\n" + 
3010
			"        }\n" + 
3011
			"        o = new Object();\n" + 
3012
			"        int j = 0;\n" + 
3013
			"        while (j++ < 2) {\n" + 
3014
			"          continue ext;\n" + 
3015
			"        }\n" + 
3016
			"        return;\n" + 
3017
			"    }\n" + 
3018
			"  }\n" + 
3019
			"}"},
3020
		"");
3021
} 
3022
3023
// null analysis - while
3024
public void test0444_while_deeply_nested() {
3025
	this.runConformTest(
3026
		new String[] {
3027
			"X.java",
3028
			"class X {\n" + 
3029
			"  void foo(boolean b) {\n" + 
3030
			"    Object o = null;\n" + 
3031
			"    ext: for (int i = 0; i < 5 ; i++) {\n" + 
3032
			"        if (o != null) {\n" + 
3033
			"          break;\n" + 
3034
			"        }\n" +
3035
			"        do {\n" + 
3036
			"          o = new Object();\n" + 
3037
			"          int j = 0;\n" + 
3038
			"          while (j++ < 2) {\n" + 
3039
			"            continue ext;\n" + 
3040
			"          }\n" + 
3041
			"        } while (b);\n" + 
3042
			"        return;\n" + 
3043
			"    }\n" + 
3044
			"  }\n" + 
3045
			"}"},
3046
		"");
3047
} 
3048
3049
// null analysis - while
3050
public void test0445_while_deeply_nested() {
3051
	this.runNegativeTest(
3052
		new String[] {
3053
			"X.java",
3054
			"class X {\n" + 
3055
			"  void foo(boolean b) {\n" + 
3056
			"    Object o = null;\n" + 
3057
			"    ext: for (int i = 0; i < 5 ; i++) {\n" + 
3058
			"        if (o != null) {\n" + 
3059
			"          break;\n" + 
3060
			"        }\n" +
3061
			"        do {\n" + 
3062
			"          // o = new Object();\n" + 
3063
			"          int j = 0;\n" + 
3064
			"          while (j++ < 2) {\n" + 
3065
			"            continue ext;\n" + 
3066
			"          }\n" + 
3067
			"        } while (b);\n" + 
3068
			"        return;\n" + 
3069
			"    }\n" + 
3070
			"  }\n" + 
3071
			"}"},
3072
		"----------\n" + 
3073
		"1. ERROR in X.java (at line 5)\n" + 
3074
		"	if (o != null) {\n" + 
3075
		"	    ^\n" + 
3076
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
3077
		"----------\n");
3078
} 
3079
3080
// null analysis - while
3081
public void test0446_while() {
3082
	this.runNegativeTest(
3083
		new String[] {
3084
			"X.java",
3085
			"class X {\n" + 
3086
			"  void foo(Object o, boolean b) {\n" + 
3087
			"    while (o == null || b) {\n" +
3088
			"      o = new Object();\n" +
3089
			"    }\n" + 
3090
			"    if (o != null) { /* */ }\n" + // complain 
3091
			"  }\n" + 
3092
			"}"},
3093
		"----------\n" + 
3094
		"1. ERROR in X.java (at line 6)\n" + 
3095
		"	if (o != null) { /* */ }\n" + 
3096
		"	    ^\n" + 
3097
		"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
3098
		"----------\n");
3099
}
3100
3101
// null analysis - while
3102
public void test0447_while() {
3103
	this.runConformTest(
3104
		new String[] {
3105
			"X.java",
3106
			"class X {\n" + 
3107
			"  void foo(Object o, boolean b) {\n" + 
3108
			"    while (o == null & b) {\n" +
3109
			"      o = new Object();\n" +
3110
			"    }\n" + 
3111
			"    if (o != null) { /* */ }\n" + 
3112
			"  }\n" + 
3113
			"}"},
3114
		"");
3115
}
3116
3117
// null analysis - while
3118
public void test0448_while() {
3119
	this.runNegativeTest(
3120
		new String[] {
3121
			"X.java",
3122
			"class X {\n" + 
3123
			"  void foo(boolean b[]) {\n" + 
3124
			"    Object o = null;\n" + 
3125
			"    ext: for (int i = 0; i < 5 ; i++) {\n" + 
3126
			"        if (o != null) {\n" + 
3127
			"          break;\n" + 
3128
			"        }\n" +
3129
			"        while (b[1]) {\n" + 
3130
			"          continue ext;\n" + 
3131
			"        }\n" + 
3132
			"        while (b[2]) {\n" + 
3133
			"          continue ext;\n" + 
3134
			"        }\n" + 
3135
			"        while (b[3]) {\n" + 
3136
			"          continue ext;\n" + 
3137
			"        }\n" + 
3138
			"        while (b[4]) {\n" + 
3139
			"          continue ext;\n" + 
3140
			"        }\n" + 
3141
			"        while (b[5]) {\n" + 
3142
			"          continue ext;\n" + 
3143
			"        }\n" + 
3144
			"        while (b[6]) {\n" + 
3145
			"          continue ext;\n" + 
3146
			"        }\n" + 
3147
			"        return;\n" + 
3148
			"    }\n" + 
3149
			"  }\n" + 
3150
			"}"},
3151
		"----------\n" + 
3152
		"1. ERROR in X.java (at line 5)\n" + 
3153
		"	if (o != null) {\n" + 
3154
		"	    ^\n" + 
3155
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
3156
		"----------\n");
3157
} 
3158
3159
// null analysis - while
3160
// REVIEW this series (up to 451) shows that the merge of the states
3161
// REVIEW potential non null and potential unknown yields damages in
3162
// REVIEW case of nested loops (unested loops still OK because we can
3163
// REVIEW carry the definite non null property)
3164
public void test0449_while_nested() {
3165
	this.runConformTest(
3166
		new String[] {
3167
			"X.java",
3168
			"class X {\n" + 
3169
			"  void foo(Object p, boolean b) {\n" + 
3170
			"    Object o = new Object();\n" + 
3171
			"    while (b) {\n" + 
3172
			"      while (b) {\n" + 
3173
			"        o = p;\n" + // now o is unknown
3174
			"      }\n" + 
3175
			"    }\n" + 
3176
			"    if (o != null) { /* */ }\n" + 
3177
			"  }\n" + 
3178
			"}"},
3179
		"");
3180
} 
3181
3182
// null analysis - while
3183
public void test0450_while() {
3184
	this.runNegativeTest(
3185
		new String[] {
3186
			"X.java",
3187
			"class X {\n" + 
3188
			"  void foo(boolean b) {\n" + 
3189
			"    Object o = new Object();\n" + 
3190
			"    while (b) {\n" + 
3191
			"      o = new Object();\n" + // o still non null
3192
			"    }\n" + 
3193
			"    if (o != null) { /* */ }\n" + 
3194
			"  }\n" + 
3195
			"}"},
3196
		"----------\n" + 
3197
		"1. ERROR in X.java (at line 7)\n" + 
3198
		"	if (o != null) { /* */ }\n" + 
3199
		"	    ^\n" + 
3200
		"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
3201
		"----------\n");
3202
} 
3203
3204
// null analysis - while
3205
public void _test0451_while_nested() {
3206
	this.runNegativeTest(
3207
		new String[] {
3208
			"X.java",
3209
			"class X {\n" + 
3210
			"  void foo(boolean b) {\n" + 
3211
			"    Object o = new Object();\n" + 
3212
			"    while (b) {\n" + 
3213
			"      while (b) {\n" + 
3214
			"        o = new Object();\n" + // o still non null
3215
			"      }\n" + 
3216
			"    }\n" + 
3217
			"    if (o != null) { /* */ }\n" + 
3218
			"  }\n" + 
3219
			"}"},
3220
		"ERR");
3221
} 
3222
3223
// null analysis -- try/finally
3224
public void test0500_try_finally() {
3225
	this.runConformTest(
3226
		new String[] {
3227
			"X.java",
3228
			"public class X {\n" + 
3229
			"  Object m;\n" + 
3230
			"  void foo() {\n" + 
3231
			"    Object o = null;\n" + 
3232
			"    try { /* */ }\n" + 
3233
			"    finally {\n" + 
3234
			"      o = m;\n" + 
3235
			"    }\n" + 
3236
			"    o.toString();\n" + 
3237
			"  }\n" + 
3238
			"}\n"},
3239
		"" // because finally assigns to unknown value
3240
	);
3241
}
3242
3243
// null analysis -- try/finally
3244
public void test0501_try_finally() {
3245
	this.runNegativeTest(
3246
		new String[] {
3247
			"X.java",
3248
			"public class X {\n" + 
3249
			"  void foo() {\n" + 
3250
			"    Object o = new Object();\n" + 
3251
			"    try { /* */ }\n" + 
3252
			"    finally {\n" + 
3253
			"      o = null;\n" + 
3254
			"    }\n" + 
3255
			"    o.toString();\n" + 
3256
			"  }\n" + 
3257
			"}\n"},
3258
		"----------\n" + 
3259
		"1. ERROR in X.java (at line 8)\n" + 
3260
		"	o.toString();\n" + 
3261
		"	^\n" + 
3262
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
3263
		"----------\n" // because finally assigns to null 
3264
	);
3265
}
3266
3267
// null analysis -- try/finally
3268
public void test0502_try_finally() {
3269
	this.runConformTest(
3270
		new String[] {
3271
			"X.java",
3272
			"public class X {\n" + 
3273
			"  void foo() {\n" + 
3274
			"    Object o = null;\n" + 
3275
			"    try {\n" + 
3276
			"      System.out.println();\n" + // might throw a runtime exception 
3277
			"      o = new Object();\n" + 
3278
			"    }\n" + 
3279
			"    finally { /* */ }\n" + 
3280
			"    o.toString();\n" + 
3281
			    // still OK because in case of exception this code is 
3282
			    // not reached
3283
			"  }\n" + 
3284
			"}\n"},
3285
		"");
3286
}
3287
3288
// null analysis -- try/finally
3289
public void test0503_try_finally() {
3290
	this.runNegativeTest(
3291
		new String[] {
3292
			"X.java",
3293
			"public class X {\n" + 
3294
			"  void foo(X x) {\n" + 
3295
			"    x = null;\n" + 
3296
			"    try {\n" + 
3297
			"      x = null;\n" +                // complain, already null
3298
			"    } finally { /* */ }\n" + 
3299
			"  }\n" + 
3300
			"}\n"},
3301
		"----------\n" + 
3302
		"1. ERROR in X.java (at line 5)\n" + 
3303
		"	x = null;\n" + 
3304
		"	^\n" + 
3305
		"The variable x can only be null; it was either set to null or checked for null when last used\n" + 
3306
		"----------\n");
3307
}
3308
3309
// null analysis -- try/finally
3310
public void test0504_try_finally() {
3311
	this.runNegativeTest(
3312
		new String[] {
3313
			"X.java",
3314
			"public class X {\n" + 
3315
			"  void foo(X x) {\n" + 
3316
			"    x = null;\n" + 
3317
			"    try {\n" + 
3318
			"    } finally {\n" + 
3319
			"      if (x != null) { /* */ }\n" + // complain null 
3320
			"    }\n" + 
3321
			"  }\n" + 
3322
			"}\n"},
3323
		"----------\n" + 
3324
		"1. ERROR in X.java (at line 6)\n" + 
3325
		"	if (x != null) { /* */ }\n" + 
3326
		"	    ^\n" + 
3327
		"The variable x can only be null; it was either set to null or checked for null when last used\n" + 
3328
		"----------\n");
3329
}
3330
3331
// null analysis -- try/finally
3332
// origin: AssignmentTest#test017
3333
// The whole issue here is whether or not to detect premature exits. We
3334
// follow JLS's conservative approach, which considers that the try
3335
// block may exit before the assignment is completed.
3336
// Note: conversely, without line 1, we would complain about x not being 
3337
//       initialized (for sure) on line 2.
3338
public void test0505_try_finally() {
3339
	this.runConformTest(
3340
		new String[] {
3341
			"X.java",
3342
			"public class X {\n" + 
3343
			" void foo(X x) {\n" + 
3344
			"   x = this;\n" + // 1
3345
			"   try {\n" + 
3346
			"     x = null;\n" + 
3347
			"   } finally {\n" + 
3348
			"     if (x == null) {/* */}\n" + // 2
3349
			"   }\n" + 
3350
			" }\n" + 
3351
			"}\n"},
3352
		"");
3353
}
3354
3355
// null analysis -- try finally
3356
public void test0506_try_finally() {
3357
	this.runNegativeTest(
3358
		new String[] {
3359
			"X.java",
3360
			"public class X {\n" + 
3361
			"  void foo(Object o) {\n" + 
3362
			"    try { /* */ }\n" + 
3363
			"    finally {\n" + 
3364
			"      o = new Object();\n" +
3365
			"    }\n" + 
3366
			"    if (o == null) { /* */ }\n" + 
3367
			"  }\n" + 
3368
			"}\n"},
3369
		"----------\n" + 
3370
		"1. ERROR in X.java (at line 7)\n" + 
3371
		"	if (o == null) { /* */ }\n" + 
3372
		"	    ^\n" + 
3373
		"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
3374
		"----------\n");
3375
}
3376
3377
// null analysis -- try finally
3378
public void test0507_try_finally() {
3379
	this.runNegativeTest(
3380
		new String[] {
3381
			"X.java",
3382
			"public class X {\n" + 
3383
			"  void foo(Object o, boolean b) {\n" + 
3384
			"    try { /* */ }\n" + 
3385
			"    finally {\n" + 
3386
			"      o.toString();\n" +  // protect
3387
			"    }\n" + 
3388
			"    if (o == null) {\n" + // complain
3389
			"      o = new Object();\n" +
3390
			"    }\n" + 
3391
			"  }\n" + 
3392
			"}\n"},
3393
		"----------\n" + 
3394
		"1. ERROR in X.java (at line 7)\n" + 
3395
		"	if (o == null) {\n" + 
3396
		"	    ^\n" + 
3397
		"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
3398
		"----------\n");
3399
}
3400
3401
// null analysis -- try finally
3402
public void test0508_try_finally() {
3403
	this.runNegativeTest(
3404
		new String[] {
3405
			"X.java",
3406
			"public class X {\n" + 
3407
			"  void foo(Object o) {\n" + 
3408
			"    o = null;" +
3409
			"    try { /* */ }\n" + 
3410
			"    finally {\n" + 
3411
			"      o.toString();\n" +  // complain and protect
3412
			"      o.toString();\n" +  // quiet
3413
			"    }\n" + 
3414
			"    o.toString();\n" +  // quiet
3415
			"  }\n" + 
3416
			"}\n"},
3417
		"----------\n" + 
3418
		"1. ERROR in X.java (at line 5)\n" + 
3419
		"	o.toString();\n" + 
3420
		"	^\n" + 
3421
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
3422
		"----------\n");
3423
}
3424
3425
// null analysis -- try finally
3426
public void test0509_try_finally_embedded() {
3427
	this.runNegativeTest(
3428
		new String[] {
3429
			"X.java",
3430
			"public class X {\n" + 
3431
			"  void foo(Object o1) {\n" + 
3432
			"    Object o2 = null;" +
3433
			"    while (true) {\n" + 
3434
			"      // o2 = o1;\n" + 
3435
			"      try { /* */ }\n" + 
3436
			"      finally {\n" + 
3437
			"        o2.toString();\n" +  // complain and protect
3438
			"        o2.toString();\n" +  // quiet
3439
			"      }\n" + 
3440
			"      o2.toString();\n" +  // quiet
3441
			"    }\n" + 
3442
			"  }\n" + 
3443
			"}\n"},
3444
		"----------\n" + 
3445
		"1. ERROR in X.java (at line 7)\n" + 
3446
		"	o2.toString();\n" + 
3447
		"	^^\n" + 
3448
		"The variable o2 can only be null; it was either set to null or checked for null when last used\n" + 
3449
		"----------\n");
3450
}
3451
3452
// null analysis -- try finally
3453
public void test0510_try_finally() {
3454
	this.runConformTest(
3455
		new String[] {
3456
			"X.java",
3457
			"public class X {\n" + 
3458
			"  void bar() throws Exception {\n" + 
3459
			"    // empty\n" + 
3460
			"  }\n" + 
3461
			"  void foo(Object o, boolean b) throws Exception {\n" + 
3462
			"    try {\n" + 
3463
			"      bar();\n" + 
3464
			"      if (b) {\n" +
3465
			"        o.toString();\n" +
3466
			"      }\n" + 
3467
			"    }\n" + 
3468
			"    finally {\n" + 
3469
			"      if (o != null) {\n" + 
3470
			"          o.toString();\n" + 
3471
			"      }\n" + 
3472
			"    }\n" + 
3473
			"  }\n" + 
3474
			"}\n"},
3475
		"");
3476
}
3477
3478
// null analysis -- try finally
3479
public void test0511_try_finally() {
3480
	this.runConformTest(
3481
		new String[] {
3482
			"X.java",
3483
			"public class X {\n" + 
3484
			"  void foo(Object o1, boolean b) {\n" + 
3485
			"    Object o2 = null;\n" +
3486
			"    if (b) {\n" +
3487
			"      o2 = new Object();\n" +
3488
			"    }\n" + 				// 0011
3489
			"    try { /* */ }\n" + 
3490
			"    finally {\n" + 
3491
			"      o2 = o1;\n" + 		// 1011 
3492
			"    }\n" + 
3493
			"    o2.toString();\n" + 	// 1011 -- quiet
3494
			"  }\n" + 
3495
			"}\n"},
3496
		"");
3497
}
3498
3499
// null analysis -- try/finally
3500
public void test0512_try_finally() {
3501
	this.runNegativeTest(
3502
		new String[] {
3503
			"X.java",
3504
			"public class X {\n" + 
3505
			" void foo(X x) {\n" + 
3506
			"   x = null;\n" +
3507
			"   try {\n" + 
3508
			"     x = new X();\n" + 
3509
			"   } finally {\n" + 
3510
			"     x.toString();\n" +
3511
			"   }\n" + 
3512
			" }\n" + 
3513
			"}\n"},
3514
		"----------\n" + 
3515
		"1. ERROR in X.java (at line 7)\n" + 
3516
		"	x.toString();\n" + 
3517
		"	^\n" + 
3518
		"The variable x may be null\n" + 
3519
		"----------\n");
3520
}
3521
3522
// null analysis -- try/catch
3523
public void test0550_try_catch() {
3524
	this.runConformTest(
3525
		new String[] {
3526
			"X.java",
3527
			"public class X {\n" + 
3528
			"  void foo() {\n" + 
3529
			"    Object o = null;\n" + 
3530
			"    try {\n" + 
3531
			"      System.out.println();\n" +  // might throw a runtime exception 
3532
			"      o = new Object();\n" + 
3533
			"    }\n" + 
3534
			"    catch (Throwable t) {\n" + // catches everything 
3535
			"      return;\n" +             // gets out         
3536
			"    }\n" + 
3537
			"    o.toString();\n" +         // non null  
3538
			"  }\n" + 
3539
			"}\n"},
3540
		"");
3541
}
3542
3543
// null analysis - try/catch
3544
public void test0551_try_catch() {
3545
	this.runNegativeTest(
3546
		new String[] {
3547
			"X.java",
3548
			"public class X {\n" + 
3549
			"  boolean dummy;\n" + 
3550
			"  void foo() {\n" + 
3551
			"    Object o = new Object();\n" + 
3552
			"    try {\n" + 
3553
			"      System.out.println();\n" + 
3554
			"      if (dummy) {\n" + 
3555
			"        o = null;\n" + 
3556
			"        throw new Exception();\n" + 
3557
			"      }\n" + 
3558
			"    }\n" + 
3559
			"    catch (Exception e) {\n" + 
3560
			"      o.toString();\n" + // complain
3561
			"    }\n" + 
3562
			"  }\n" + 
3563
			"}\n"},
3564
		"----------\n" + 
3565
		"1. ERROR in X.java (at line 13)\n" + 
3566
		"	o.toString();\n" + 
3567
		"	^\n" + 
3568
		"The variable o may be null\n" + 
3569
		"----------\n");
3570
}
3571
3572
// null analysis - try/catch
3573
public void test0552_try_catch() {
3574
	this.runConformTest(
3575
		new String[] {
3576
			"X.java",
3577
			"public class X {\n" + 
3578
			"  boolean dummy;\n" + 
3579
			"  void foo() throws Exception {\n" + 
3580
			"    Object o = new Object();\n" + 
3581
			"    try {\n" + 
3582
			"      if (dummy) {\n" + 
3583
			"        o = null;\n" + 
3584
			"        throw new Exception();\n" + 
3585
			"      }\n" + 
3586
			"    }\n" + 
3587
			"    catch (Exception e) {\n" + 
3588
			"    }\n" + 
3589
			"    if (o != null) {\n" +
3590
			  // quiet: get out of try either through normal flow, leaves a new
3591
			  // object, or through Exception, leaves a null 
3592
			"    }\n" + 
3593
			"  }\n" + 
3594
			"}\n"},
3595
		"");
3596
}
3597
3598
// null analysis - try/catch
3599
public void test0553_try_catch() {
3600
	this.runNegativeTest(
3601
		new String[] {
3602
			"X.java",
3603
			"public class X {\n" + 
3604
			"  boolean dummy, other;\n" + 
3605
			"  void foo() {\n" + 
3606
			"    Object o = new Object();\n" + 
3607
			"    try {\n" + 
3608
			"      if (dummy) {\n" + 
3609
			"        if (other) {\n" + 
3610
			"          throw new LocalException();\n" + // may launch new exception
3611
			"        }\n" + 
3612
			"        o = null;\n" + 
3613
			"        throw new LocalException();\n" + // must launch new exception
3614
			"      }\n" + 
3615
			"    }\n" + 
3616
			"    catch (LocalException e) {\n" + 
3617
			"      o.toString();\n" + // complain
3618
			"    }\n" + 
3619
			"  }\n" + 
3620
			"  class LocalException extends Exception {\n" + 
3621
			"    private static final long serialVersionUID = 1L;\n" + 
3622
			"  }\n" + 
3623
			"}\n"},
3624
		"----------\n" + 
3625
		"1. ERROR in X.java (at line 15)\n" + 
3626
		"	o.toString();\n" + 
3627
		"	^\n" + 
3628
		"The variable o may be null\n" + 
3629
		"----------\n");
3630
}
3631
3632
// null analysis - try/catch
3633
public void test0554_try_catch() {
3634
	this.runConformTest(
3635
		new String[] {
3636
			"X.java",
3637
			"public class X {\n" + 
3638
			"  void foo(Object o) throws Exception {\n" + 
3639
			"    try {\n" + 
3640
			"      o = null;\n" + 
3641
			"      throwLocalException();\n" + 
3642
			"      throw new Exception();\n" + 
3643
			"    }\n" + 
3644
			"    catch (LocalException e) {\n" + 
3645
			"    }\n" + 
3646
			"    if (o != null) {\n" +
3647
			  // complain: only way to get out of try and get there is to go
3648
			  // through throwLocalException, after the assignment 
3649
			"    }\n" + 
3650
			"  }\n" + 
3651
			"  class LocalException extends Exception {\n" + 
3652
			"    private static final long serialVersionUID = 1L;\n" + 
3653
			"  }\n" + 
3654
			"  void throwLocalException() throws LocalException {\n" + 
3655
			"    throw new LocalException();\n" + 
3656
			"  }\n" + 
3657
			"}\n"},
3658
		""
3659
		// conservative flow analysis suppresses the warning
3660
//		"----------\n" + 
3661
//		"1. ERROR in X.java (at line 10)\n" + 
3662
//		"	if (o != null) {\n" + 
3663
//		"	    ^\n" + 
3664
//		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
3665
//		"----------\n"
3666
	);
3667
}
3668
3669
// null analysis - try/catch
3670
public void test0555_try_catch() {
3671
	this.runNegativeTest(
3672
		new String[] {
3673
			"X.java",
3674
			"public class X {\n" + 
3675
			"  void foo() {\n" + 
3676
			"    Object o = new Object();\n" + 
3677
			"    try {\n" + 
3678
			"      o = null;\n" + 
3679
			"      throwException();\n" + 
3680
			"    }\n" + 
3681
			"    catch (Exception e) {\n" + 
3682
			"      o.toString();\n" + // complain NPE
3683
			"    }\n" + 
3684
			"  }\n" + 
3685
			"  void throwException() throws Exception {\n" + 
3686
			"    throw new Exception();\n" + 
3687
			"  }\n" + 
3688
			"}\n"},
3689
		"----------\n" + 
3690
		"1. ERROR in X.java (at line 9)\n" + 
3691
		"	o.toString();\n" + 
3692
		"	^\n" + 
3693
		"The variable o may be null\n" + 
3694
		"----------\n");
3695
}
3696
3697
// null analysis - try/catch
3698
public void test0556_try_catch() {
3699
	this.runNegativeTest(
3700
		new String[] {
3701
			"X.java",
3702
			"public class X {\n" + 
3703
			"  void foo() {\n" + 
3704
			"    Object o = new Object();\n" + 
3705
			"    try {\n" + 
3706
			"      o = null;\n" + 
3707
			"      throwException();\n" + 
3708
			"    }\n" + 
3709
			"    catch (Throwable t) {\n" + 
3710
			"      o.toString();\n" + // complain NPE
3711
			"    }\n" + 
3712
			"  }\n" + 
3713
			"  void throwException() throws Exception {\n" + 
3714
			"    throw new Exception();\n" + 
3715
			"  }\n" + 
3716
			"}\n"},
3717
		"----------\n" + 
3718
		"1. ERROR in X.java (at line 9)\n" + 
3719
		"	o.toString();\n" + 
3720
		"	^\n" + 
3721
		"The variable o may be null\n" + 
3722
		"----------\n");
3723
}
3724
3725
// null analysis - try/catch
3726
public void test0557_try_catch() {
3727
	this.runNegativeTest(
3728
		new String[] {
3729
			"X.java",
3730
			"public class X {\n" + 
3731
			"  boolean dummy;\n" + 
3732
			"  void foo() {\n" + 
3733
			"    Object o = new Object();\n" + 
3734
			"    try {\n" + 
3735
			"      if (dummy) {\n" + 
3736
			"        o = null;\n" + 
3737
			"        throw new Exception();\n" + 
3738
			"      }\n" + 
3739
			"    }\n" + 
3740
			"    catch (Exception e) {\n" + 
3741
			"      o.toString();\n" + // complain NPE
3742
			"    }\n" + 
3743
			"  }\n" + 
3744
			"}\n"},
3745
		"----------\n" + 
3746
		"1. ERROR in X.java (at line 12)\n" + 
3747
		"	o.toString();\n" + 
3748
		"	^\n" + 
3749
		"The variable o may be null\n" + 
3750
		"----------\n");
3751
}
3752
3753
// null analysis - try/catch
3754
public void test0558_try_catch() {
3755
	this.runNegativeTest(
3756
		new String[] {
3757
			"X.java",
3758
			"public class X {\n" + 
3759
			"  boolean dummy;\n" + 
3760
			"  void foo() {\n" + 
3761
			"    Object o = new Object();\n" + 
3762
			"    try {\n" + 
3763
			"      if (dummy) {\n" + 
3764
			"        System.out.print(0);\n" + // may thow RuntimeException 
3765
			"        o = null;\n" + 
3766
			"        throw new LocalException();\n" + 
3767
			"      }\n" + 
3768
			"    }\n" + 
3769
			"    catch (LocalException e) {\n" + // doesn't catch RuntimeException
3770
			"      o.toString();\n" + // complain NPE
3771
			"    }\n" + 
3772
			"  }\n" + 
3773
			"  class LocalException extends Exception {\n" + 
3774
			"    private static final long serialVersionUID = 1L;\n" + 
3775
			"  }\n" + 
3776
			"}\n"},
3777
		"----------\n" + 
3778
		"1. ERROR in X.java (at line 13)\n" + 
3779
		"	o.toString();\n" + 
3780
		"	^\n" + 
3781
//		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
3782
		"The variable o may be null\n" +
3783
		// conservative flow analysis softens the error
3784
		"----------\n");
3785
}
3786
3787
// null analysis - try/catch
3788
public void test0559_try_catch() {
3789
	this.runNegativeTest(
3790
		new String[] {
3791
			"X.java",
3792
			"public class X {\n" + 
3793
			"  boolean dummy;\n" + 
3794
			"  void foo() {\n" + 
3795
			"    Object o = new Object();\n" + 
3796
			"    try {\n" + 
3797
			"      if (dummy) {\n" + 
3798
			"        o = null;\n" + 
3799
			"        throw new SubException();\n" + 
3800
			"      }\n" + 
3801
			"    }\n" + 
3802
			"    catch (LocalException e) {\n" + // must catch SubException
3803
			"      o.toString();\n" + // complain NPE
3804
			"    }\n" + 
3805
			"  }\n" + 
3806
			"  class LocalException extends Exception {\n" + 
3807
			"    private static final long serialVersionUID = 1L;\n" + 
3808
			"  }\n" + 
3809
			"  class SubException extends LocalException {\n" + 
3810
			"    private static final long serialVersionUID = 1L;\n" + 
3811
			"  }\n" + 
3812
			"}\n"},
3813
		"----------\n" + 
3814
		"1. ERROR in X.java (at line 12)\n" + 
3815
		"	o.toString();\n" + 
3816
		"	^\n" + 
3817
//		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
3818
		"The variable o may be null\n" +
3819
		// conservative flow analysis softens the error
3820
		"----------\n");
3821
}
3822
3823
// null analysis - try/catch
3824
public void test0560_try_catch() {
3825
	this.runNegativeTest(
3826
		new String[] {
3827
			"X.java",
3828
			"public class X {\n" + 
3829
			"  Class bar(boolean b) throws ClassNotFoundException {\n" + 
3830
			"    if (b) {\n" + 
3831
			"      throw new ClassNotFoundException();\n" + 
3832
			"    }\n" + 
3833
			"    return null;\n" + 
3834
			"  }\n" + 
3835
			"  public Class foo(Class c, boolean b) {\n" + 
3836
			"    if (c != null)\n" + 
3837
			"      return c;\n" + 
3838
			"    if (b) {\n" + 
3839
			"      try {\n" + 
3840
			"        c = bar(b);\n" + 
3841
			"        return c;\n" + 
3842
			"      } catch (ClassNotFoundException e) {\n" + 
3843
			"      // empty\n" + 
3844
			"      }\n" + 
3845
			"    }\n" + 
3846
			"    if (c == null) { // should complain: c can only be null\n" + 
3847
			"    }\n" + 
3848
			"    return c;\n" + 
3849
			"  }\n" + 
3850
			"}\n"},
3851
		"----------\n" + 
3852
		"1. ERROR in X.java (at line 19)\n" + 
3853
		"	if (c == null) { // should complain: c can only be null\n" + 
3854
		"	    ^\n" + 
3855
		"The variable c can only be null; it was either set to null or checked for null when last used\n" + 
3856
		"----------\n");
3857
}
3858
3859
// null analysis -- do while
3860
public void test0601_do_while() {
3861
	this.runNegativeTest(
3862
		new String[] {
3863
			"X.java",
3864
			"public class X {\n" + 
3865
			"  void foo() {\n" + 
3866
			"    Object o = null;\n" + 
3867
			"    do {/* */}\n" +
3868
			"    while (o.toString() != null);\n" +
3869
			      // complain: NPE
3870
			"  }\n" + 
3871
			"}\n"},
3872
		"----------\n" + 
3873
		"1. ERROR in X.java (at line 5)\n" + 
3874
		"	while (o.toString() != null);\n" + 
3875
		"	       ^\n" + 
3876
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
3877
		"----------\n");
3878
}
3879
3880
// null analysis -- do while
3881
public void test0602_do_while() {
3882
	this.runNegativeTest(
3883
		new String[] {
3884
			"X.java",
3885
			"public class X {\n" + 
3886
			"  void foo() {\n" + 
3887
			"    Object o = null;\n" + 
3888
			"    do {/* */}\n" + 
3889
			"    while (o != null);\n" + 
3890
			  // complain: get o null first time and forever
3891
			"  }\n" + 
3892
			"}\n"},
3893
		"----------\n" + 
3894
		"1. ERROR in X.java (at line 5)\n" + 
3895
		"	while (o != null);\n" + 
3896
		"	       ^\n" + 
3897
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
3898
		"----------\n");
3899
}
3900
3901
// null analysis -- do while
3902
public void test0603_do_while() {
3903
	this.runNegativeTest(
3904
		new String[] {
3905
			"X.java",
3906
			"public class X {\n" + 
3907
			"  void foo() {\n" + 
3908
			"    Object o = null;\n" + 
3909
			"    do {\n" + 
3910
			"      o = new Object();\n" + 
3911
			"    }\n" + 
3912
			"    while (o == null);\n" + 
3913
			      // complain: set it to non null before test, for each iteration
3914
			"  }\n" + 
3915
			"}\n"},
3916
		"----------\n" + 
3917
		"1. ERROR in X.java (at line 7)\n" + 
3918
		"	while (o == null);\n" + 
3919
		"	       ^\n" + 
3920
		"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
3921
		"----------\n");
3922
}
3923
3924
// null analysis -- do while
3925
public void test0604_do_while() {
3926
	this.runConformTest(
3927
		new String[] {
3928
			"X.java",
3929
			"public class X {\n" + 
3930
			"  void foo() {\n" + 
3931
			"    Object o = null;\n" + 
3932
			"    do {\n" + 
3933
			"      if (System.currentTimeMillis() > 10L) {\n" + 
3934
			"        o = new Object();\n" + 
3935
			"      }\n" + 
3936
			"    }\n" + 
3937
			"    while (o == null);\n" + 
3938
			"  }\n" + 
3939
			"}\n"},
3940
		"");
3941
}
3942
3943
// null analysis -- do while
3944
public void test0605_do_while() {
3945
	this.runNegativeTest(
3946
		new String[] {
3947
			"X.java",
3948
			"public class X {\n" + 
3949
			"  boolean dummy;\n" + 
3950
			"  void foo(Object o) {\n" + 
3951
			"    o = null;\n" +
3952
			"    do {\n" +
3953
			"      // do nothing\n" +
3954
			"    }\n" + 
3955
			"    while (dummy || o != null);\n" + 
3956
			"  }\n" + 
3957
			"}\n"},
3958
		"----------\n" + 
3959
		"1. ERROR in X.java (at line 8)\n" + 
3960
		"	while (dummy || o != null);\n" + 
3961
		"	                ^\n" + 
3962
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
3963
		"----------\n");
3964
}
3965
3966
// null analysis -- do while
3967
public void test0606_do_while() {
3968
	this.runConformTest(
3969
		new String[] {
3970
			"X.java",
3971
			"public class X {\n" + 
3972
			"  void foo() {\n" + 
3973
			"    Object o = null,\n" + 
3974
			"           u = new Object(),\n" + 
3975
			"           v = new Object();\n" + 
3976
			"    do {\n" +
3977
			"      if (v == null) {\n" +
3978
			"        o = new Object();\n" +
3979
			"      };\n" +
3980
			"      if (u == null) {\n" +
3981
			"        v = null;\n" +
3982
			"      };\n" +
3983
			"      u = null;\n" +
3984
			"    }\n" +
3985
			"    while (o == null);\n" +
3986
			"  }\n" + 
3987
			"}\n"},
3988
		"");
3989
}
3990
3991
// null analysis -- do while
3992
public void test0607_do_while() {
3993
	this.runNegativeTest(
3994
		new String[] {
3995
			"X.java",
3996
			"public class X {\n" + 
3997
			"  boolean dummy;\n" + 
3998
			"  void foo() {\n" + 
3999
			"    Object o = null;\n" + 
4000
			"    do {\n" + 
4001
			"      o.toString();\n" + 
4002
			         // complain: NPE
4003
			"      o = new Object();\n" + 
4004
			"    }\n" + 
4005
			"    while (dummy);\n" + 
4006
			"  }\n" + 
4007
			"}\n"},
4008
		"----------\n" + 
4009
		"1. ERROR in X.java (at line 6)\n" + 
4010
		"	o.toString();\n" + 
4011
		"	^\n" + 
4012
		"The variable o may be null\n" + 
4013
		"----------\n");
4014
}
4015
4016
// null analysis -- do while
4017
public void test0608_do_while() {
4018
	this.runConformTest(
4019
		new String[] {
4020
			"X.java",
4021
			"public class X {\n" + 
4022
			"  boolean dummy;\n" + 
4023
			"  void foo() {\n" + 
4024
			"    Object o = null;\n" + 
4025
			"    do {\n" + 
4026
			"      o = new Object();\n" + 
4027
			"    }\n" + 
4028
			"    while (dummy);\n" + 
4029
			"    o.toString();\n" + 
4030
			"  }\n" + 
4031
			"}\n"},
4032
		"");
4033
}
4034
4035
// null analysis -- do while
4036
public void test0609_do_while() {
4037
	this.runNegativeTest(
4038
		new String[] {
4039
			"X.java",
4040
			"public class X {\n" + 
4041
			"  boolean dummy;\n" + 
4042
			"  void foo() {\n" + 
4043
			"    Object o = null;\n" + 
4044
			"    do { /* */ }\n" + 
4045
			"    while (dummy);\n" + 
4046
			"    o.toString();\n" + 
4047
			"  }\n" + 
4048
			"}\n"},
4049
		"----------\n" + 
4050
		"1. ERROR in X.java (at line 7)\n" + 
4051
		"	o.toString();\n" + 
4052
		"	^\n" + 
4053
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
4054
		"----------\n");
4055
}
4056
4057
// null analysis - do while
4058
public void test0610_do_while() {
4059
	this.runConformTest(
4060
		new String[] {
4061
			"X.java",
4062
			"public class X {\n" + 
4063
			"  X bar() {\n" + 
4064
			"    return null;\n" + 
4065
			"  }\n" + 
4066
			"  void foo(X x) {\n" + 
4067
			"    x.bar();\n" +  
4068
			"    do {\n" +
4069
			"      x = x.bar();\n" +  
4070
			"    } while (x != null);\n" + // quiet 
4071
			"  }\n" + 
4072
			"}\n"},
4073
		"");
4074
} 
4075
4076
// null analysis - do while
4077
public void test0611_do_while() {
4078
	this.runNegativeTest(
4079
		new String[] {
4080
			"X.java",
4081
			"class X {\n" + 
4082
			"  X bar() {\n" + 
4083
			"    return new X();\n" + 
4084
			"  }\n" + 
4085
			"  void foo(Object o) {\n" + 
4086
			"    do {\n" +
4087
			"      o = bar();\n" +
4088
			"    } while (o == null);\n" + 
4089
			"    if (o != null) { /* */ }\n" + // complain 
4090
			"  }\n" + 
4091
			"}"},
4092
		"----------\n" + 
4093
		"1. ERROR in X.java (at line 9)\n" + 
4094
		"	if (o != null) { /* */ }\n" + 
4095
		"	    ^\n" + 
4096
		"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
4097
		"----------\n");
4098
}
4099
4100
// the problem here is that a single pass cannot know for the return
4101
// embedded into the if; prior approach did use the upstream flow 
4102
// info to catch this, but this is inappropriate in many cases (eg
4103
// test0606); may be able to do better if keeping all deep returns
4104
// as we do for labeled continue
4105
// TODO (maxime) https://bugs.eclipse.org/bugs/show_bug.cgi?id=123399
4106
public void _test0612_do_while() {
4107
	this.runNegativeTest(
4108
		new String[] {
4109
			"X.java",
4110
			"public class X {\n" + 
4111
			"  void foo(Object doubt) {\n" + 
4112
			"    Object o = null;\n" + 
4113
			"    do {\n" + 
4114
			"      if (o == null) {\n" +
4115
			"        return;\n" +
4116
			"      }\n" + 
4117
			"      o = doubt;\n" + 
4118
			"    } while (true);\n" + 
4119
			"  }\n" + 
4120
			"}"},
4121
		"----------\n" + 
4122
		"1. ERROR in X.java (at line 6)\n" + 
4123
		"	if (o == null) {\n" + 
4124
		"	    ^\n" + 
4125
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
4126
		"----------\n"
4127
	);
4128
}
4129
4130
// null analysis -- for
4131
public void test0701_for() {
4132
	this.runNegativeTest(
4133
		new String[] {
4134
			"X.java",
4135
			"public class X {\n" + 
4136
			"  void foo() {\n" + 
4137
			"    Object o = null;\n" + 
4138
			"    for (;o.toString() != null;) {/* */}\n" +
4139
			      // complain: NPE
4140
			"  }\n" + 
4141
			"}\n"},
4142
		"----------\n" + 
4143
		"1. ERROR in X.java (at line 4)\n" + 
4144
		"	for (;o.toString() != null;) {/* */}\n" + 
4145
		"	      ^\n" + 
4146
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
4147
		"----------\n");
4148
}
4149
4150
// null analysis -- for
4151
public void test0702_for() {
4152
	this.runNegativeTest(
4153
		new String[] {
4154
			"X.java",
4155
			"public class X {\n" + 
4156
			"  void foo() {\n" + 
4157
			"    Object o = null;\n" + 
4158
			"    for (;o != null;) {/* */}\n" + 
4159
			  // complain: get o null first time and forever
4160
			"  }\n" + 
4161
			"}\n"},
4162
		"----------\n" + 
4163
		"1. ERROR in X.java (at line 4)\n" + 
4164
		"	for (;o != null;) {/* */}\n" + 
4165
		"	      ^\n" + 
4166
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
4167
		"----------\n");
4168
}
4169
4170
// null analysis -- for
4171
public void test0703_for() {
4172
	this.runConformTest(
4173
		new String[] {
4174
			"X.java",
4175
			"public class X {\n" + 
4176
			"  void foo() {\n" + 
4177
			"    Object o = null;\n" + 
4178
			"    for (;o == null;) {\n" + 
4179
			      // quiet: first iteration is sure to find it null, 
4180
			      // but other iterations may change it 
4181
			"      o = new Object();\n" + 
4182
			"    }\n" + 
4183
			"  }\n" + 
4184
			"}\n"},
4185
		"");
4186
}
4187
4188
// null analysis -- for
4189
public void test0704_for() {
4190
	this.runConformTest(
4191
		new String[] {
4192
			"X.java",
4193
			"public class X {\n" + 
4194
			"  void foo() {\n" + 
4195
			"    Object o = null;\n" + 
4196
			"    for (;o == null;) {\n" + 
4197
			     // quiet: first iteration is sure to find it null, 
4198
			     // but other iterations may change it 
4199
			"      if (System.currentTimeMillis() > 10L) {\n" + 
4200
			"        o = new Object();\n" + 
4201
			"      }\n" + 
4202
			"    }\n" + 
4203
			"  }\n" + 
4204
			"}\n"},
4205
		"");
4206
}
4207
4208
// null analysis -- for
4209
public void test0705_for() {
4210
	this.runNegativeTest(
4211
		new String[] {
4212
			"X.java",
4213
			"public class X {\n" + 
4214
			"  boolean bar() {\n" + 
4215
			"    return true;\n" + 
4216
			"  }\n" + 
4217
			"  void foo(Object o) {\n" + 
4218
			"    for (;bar() && o == null;) {\n" + 
4219
			"      o.toString();\n" + // complain: NPE because of condition
4220
			"      o = new Object();\n" +
4221
			"    }\n" + 
4222
			"  }\n" + 
4223
			"}\n"},
4224
		"----------\n" + 
4225
		"1. ERROR in X.java (at line 7)\n" + 
4226
		"	o.toString();\n" + 
4227
		"	^\n" + 
4228
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
4229
		"----------\n");
4230
}
4231
4232
// null analysis -- for
4233
public void test0707_for() {
4234
	this.runConformTest(
4235
		new String[] {
4236
			"X.java",
4237
			"public class X {\n" + 
4238
			"  void foo(Object o) {\n" + 
4239
			"    for (;o == null; o.toString()) {\n" + 
4240
			"      o = new Object();\n" +
4241
			"    }\n" + 
4242
			"  }\n" + 
4243
			"}\n"},
4244
		"");
4245
}
4246
4247
// null analysis -- for
4248
public void test0708_for() {
4249
	this.runNegativeTest(
4250
		new String[] {
4251
			"X.java",
4252
			"public class X {\n" + 
4253
			"  void foo(Object o) {\n" + 
4254
			"    for (;o == null; o.toString()) {\n" + 
4255
			"    }\n" + 
4256
			"  }\n" + 
4257
			"}\n"},
4258
		"----------\n" + 
4259
		"1. ERROR in X.java (at line 3)\n" + 
4260
		"	for (;o == null; o.toString()) {\n" + 
4261
		"	                 ^\n" + 
4262
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
4263
		"----------\n");
4264
}
4265
4266
// null analysis -- for
4267
public void test0709_for() {
4268
	this.runNegativeTest(
4269
		new String[] {
4270
			"X.java",
4271
			"public class X {\n" + 
4272
			"  void foo(Object o) {\n" + 
4273
			"    for (o.toString(); o == null;) { /* */ }\n" + // complain: protected then unchanged
4274
			"  }\n" + 
4275
			"}\n"},
4276
		"----------\n" + 
4277
		"1. ERROR in X.java (at line 3)\n" + 
4278
		"	for (o.toString(); o == null;) { /* */ }\n" + 
4279
		"	                   ^\n" + 
4280
		"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
4281
		"----------\n");
4282
}
4283
4284
// null analysis -- for
4285
public void test0710_for() {
4286
	this.runNegativeTest(
4287
		new String[] {
4288
			"X.java",
4289
			"public class X {\n" + 
4290
			"  boolean bar() {\n" + 
4291
			"    return true;\n" + 
4292
			"  }\n" + 
4293
			"  void foo(Object o) {\n" + 
4294
			"    o = null;\n" + 
4295
			"    for (o.toString(); bar();) {\n" + 
4296
			"    }\n" + 
4297
			"  }\n" + 
4298
			"}\n"},
4299
		"----------\n" + 
4300
		"1. ERROR in X.java (at line 7)\n" + 
4301
		"	for (o.toString(); bar();) {\n" + 
4302
		"	     ^\n" + 
4303
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
4304
		"----------\n");
4305
}
4306
4307
// null analysis -- for
4308
public void test0711_for() {
4309
	if (COMPLIANCE_1_5.equals(this.complianceLevel)) {
4310
		this.runNegativeTest(
4311
			new String[] {
4312
				"X.java",
4313
				"public class X {\n" + 
4314
				"  void foo() {\n" + 
4315
				"    Object t[] = null;\n" + 
4316
				"    for (Object o : t) {/* */}\n" +
4317
				      // complain: NPE
4318
				"  }\n" + 
4319
				"}\n"},
4320
			"----------\n" + 
4321
			"1. ERROR in X.java (at line 4)\n" + 
4322
			"	for (Object o : t) {/* */}\n" + 
4323
			"	                ^\n" + 
4324
			"The variable t can only be null; it was either set to null or checked for null when last used\n" + 
4325
			"----------\n");
4326
	}
4327
}
4328
4329
// null analysis -- for
4330
public void test0712_for() {
4331
	if (COMPLIANCE_1_5.equals(this.complianceLevel)) {
4332
		this.runNegativeTest(
4333
			new String[] {
4334
				"X.java",
4335
				"public class X {\n" + 
4336
				"  void foo() {\n" + 
4337
				"    Iterable i = null;\n" + 
4338
				"    for (Object o : i) {/* */}\n" +
4339
				      // complain: NPE
4340
				"  }\n" + 
4341
				"}\n"},
4342
			"----------\n" + 
4343
			"1. ERROR in X.java (at line 4)\n" + 
4344
			"	for (Object o : i) {/* */}\n" + 
4345
			"	                ^\n" + 
4346
			"The variable i can only be null; it was either set to null or checked for null when last used\n" + 
4347
			"----------\n");
4348
	}
4349
}
4350
4351
// null analysis -- for
4352
public void test0713_for() {
4353
	if (COMPLIANCE_1_5.equals(this.complianceLevel)) {
4354
		this.runConformTest(
4355
			new String[] {
4356
				"X.java",
4357
				"public class X {\n" + 
4358
				"  void foo() {\n" + 
4359
				"    Object t[] = new Object[1];\n" + 
4360
				"    for (Object o : t) {/* */}\n" +
4361
				"  }\n" + 
4362
				"}\n"},
4363
			"");
4364
	}
4365
}
4366
4367
// null analysis -- for
4368
public void test0714_for() {
4369
	if (COMPLIANCE_1_5.equals(this.complianceLevel)) {
4370
		this.runConformTest(
4371
			new String[] {
4372
				"X.java",
4373
				"public class X {\n" + 
4374
				"  void foo() {\n" + 
4375
				"    Iterable i = new java.util.Vector<Object>();\n" + 
4376
				"    for (Object o : i) {/* */}\n" +
4377
				"  }\n" + 
4378
				"}\n"},
4379
			"");
4380
	}
4381
}
4382
4383
// null analysis -- for
4384
public void test0715_for() {
4385
	if (COMPLIANCE_1_5.equals(this.complianceLevel)) {
4386
		this.runNegativeTest(
4387
			new String[] {
4388
				"X.java",
4389
				"public class X {\n" + 
4390
				"  void foo() {\n" + 
4391
				"    Iterable i = new java.util.Vector<Object>();\n" + 
4392
				"    Object flag = null;\n" + 
4393
				"    for (Object o : i) {\n" +
4394
				"      flag = new Object();\n" +
4395
				"    }\n" +
4396
				"    flag.toString();\n" + 
4397
				// complain: cannot know if at least one iteration got executed 
4398
				"  }\n" + 
4399
				"}\n"},
4400
			"----------\n" + 
4401
			"1. ERROR in X.java (at line 8)\n" + 
4402
			"	flag.toString();\n" + 
4403
			"	^^^^\n" + 
4404
			"The variable flag may be null\n" + 
4405
			"----------\n");
4406
	}
4407
}
4408
4409
// null analysis -- for
4410
public void test0716_for() {
4411
	if (COMPLIANCE_1_5.equals(this.complianceLevel)) {
4412
		this.runNegativeTest(
4413
			new String[] {
4414
				"X.java",
4415
				"public class X {\n" + 
4416
				"  void foo() {\n" + 
4417
				"    Iterable i = new java.util.Vector<Object>();\n" + 
4418
				"    Object flag = null;\n" + 
4419
				"    for (Object o : i) { /* */ }\n" +
4420
				"    flag.toString();\n" + 
4421
				"  }\n" + 
4422
				"}\n"},
4423
			"----------\n" + 
4424
			"1. ERROR in X.java (at line 6)\n" + 
4425
			"	flag.toString();\n" + 
4426
			"	^^^^\n" + 
4427
			"The variable flag can only be null; it was either set to null or checked for null when last used\n" + 
4428
			"----------\n");
4429
	}
4430
}
4431
4432
// null analysis -- for
4433
public void test0717_for() {
4434
	if (COMPLIANCE_1_5.equals(this.complianceLevel)) {
4435
		this.runNegativeTest(
4436
			new String[] {
4437
				"X.java",
4438
				"public class X {\n" + 
4439
				"  void foo(boolean dummy) {\n" + 
4440
				"    Object flag = null;\n" + 
4441
				"    for (;dummy;) {\n" +
4442
				"      flag = new Object();\n" +
4443
				"    }\n" +
4444
				"    flag.toString();\n" + 
4445
				"  }\n" + 
4446
				"}\n"},
4447
			"----------\n" + 
4448
			"1. ERROR in X.java (at line 7)\n" + 
4449
			"	flag.toString();\n" + 
4450
			"	^^^^\n" + 
4451
			"The variable flag may be null\n" + 
4452
			"----------\n");
597
	}
4453
	}
4454
}
4455
4456
// null analysis -- for
4457
public void test0718_for() {
4458
	this.runNegativeTest(
4459
		new String[] {
4460
			"X.java",
4461
			"public class X {\n" + 
4462
			"  void foo(boolean dummy) {\n" + 
4463
			"    Object flag = null;\n" + 
4464
			"    for (;dummy;) { /* */ }\n" +
4465
			"    flag.toString();\n" + 
4466
			"  }\n" + 
4467
			"}\n"},
4468
		"----------\n" + 
4469
		"1. ERROR in X.java (at line 5)\n" + 
4470
		"	flag.toString();\n" + 
4471
		"	^^^^\n" + 
4472
		"The variable flag can only be null; it was either set to null or checked for null when last used\n" + 
4473
		"----------\n");
4474
}
4475
4476
// null analysis -- for
4477
// origin: AssignmentTest#test019
4478
public void test0719_for() {
4479
	this.runConformTest(
4480
		new String[] {
4481
			    "X.java",
4482
			    "public class X {\n" + 
4483
			    "  public static final char[] foo(char[] a, char c1, char c2) {\n" + 
4484
			    "   char[] r = null;\n" + 
4485
			    "   for (int i = 0, length = a.length; i < length; i++) {\n" + 
4486
			    "     char c = a[i];\n" + 
4487
			    "     if (c == c1) {\n" + 
4488
			    "       if (r == null) {\n" + 
4489
			    "         r = new char[length];\n" + 
4490
			    "       }\n" + 
4491
			    "       r[i] = c2;\n" + 
4492
			    "     } else if (r != null) {\n" + 
4493
			    "       r[i] = c;\n" + 
4494
			    "     }\n" + 
4495
			    "   }\n" + 
4496
			    "   if (r == null) return a;\n" + 
4497
			    "   return r;\n" + 
4498
			    " }\n" + 
4499
			    "}\n"},
4500
		"");
4501
}
4502
4503
// null analysis -- for
4504
public void test0720_for_continue_break() {
4505
	this.runNegativeTest(
4506
		new String[] {
4507
			"X.java",
4508
			  "public class X {\n" + 
4509
			  "  void foo() {\n" + 
4510
			  "    Object o = new Object();\n" + 
4511
			  "    for (int i = 0; i < 10; i++) {\n" + 
4512
			  "      if (o == null) {\n" + // complain: o cannot be null
4513
			  "        continue;\n" + 
4514
			  "      }\n" + 
4515
			  "      o = null;\n" + 
4516
			  "      break;\n" + 
4517
			  "    }\n" + 
4518
			  "  }\n" + 
4519
			  "}\n"},
4520
		"----------\n" + 
4521
		"1. ERROR in X.java (at line 5)\n" + 
4522
		"	if (o == null) {\n" + 
4523
		"	    ^\n" + 
4524
		"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
4525
		"----------\n");
4526
}
4527
	
4528
// null analysis -- for
4529
public void test0721_for() {
4530
	this.runConformTest(
4531
		new String[] {
4532
			"X.java",
4533
			"public class X {\n" + 
4534
			"  void foo(boolean b) {\n" + 
4535
			"    Object o = null;\n" +
4536
			"    for (; b ? (o = new Object()).equals(o) : false ;) {\n" +
4537
			// contrast this with test0238; here the condition shades doubts
4538
			// upon o being null
4539
			"      /* */\n" +
4540
			"    }\n" + 
4541
			"    if (o == null) { /* */ }\n" + 
4542
			"  }\n" + 
4543
			"}\n"},
4544
		"");
4545
}
4546
	
4547
// null analysis -- for
4548
public void test0722_for_return() {
4549
	this.runNegativeTest(
4550
		new String[] {
4551
			"X.java",
4552
			"public class X {\n" + 
4553
			"  void foo (boolean b) {\n" + 
4554
			"    Object o = null;\n" + 
4555
			"    for (int i = 0; i < 25; i++) {\n" + 
4556
			"      if (b) {\n" + 
4557
			"        if (o == null) {\n" + 
4558
			"          o = new Object();\n" + // cleared by return downstream 
4559
			"        }\n" + 
4560
			"        return;\n" + 
4561
			"      }\n" + 
4562
			"    }\n" + 
4563
			"  }\n" + 
4564
			"}\n"},
4565
		"----------\n" + 
4566
		"1. ERROR in X.java (at line 6)\n" + 
4567
		"	if (o == null) {\n" + 
4568
		"	    ^\n" + 
4569
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
4570
		"----------\n");
4571
}
4572
	
4573
// null analysis -- for
4574
public void test0723_for() {
4575
	this.runConformTest(
4576
		new String[] {
4577
			"X.java",
4578
			"public class X {\n" + 
4579
			"  void foo () {\n" + 
4580
			"    Object o[] = new Object[1];\n" + 
4581
			"    for (int i = 0; i < 1; i++) {\n" + 
4582
			"      if (i < 1) {\n" +
4583
			"        o[i].toString();\n" +
4584
			"      }\n" + 
4585
			"    }\n" + 
4586
			"  }\n" + 
4587
			"}\n"},
4588
		"");
4589
}
4590
4591
// null analysis -- for
4592
public void test0724_for_with_initialization() {
4593
	this.runConformTest(
4594
		new String[] {
4595
			"X.java",
4596
			"public class X {\n" + 
4597
			"  X field;\n" + 
4598
			"  void foo(X x1) {\n" + 
4599
			"    // X x2;\n" + 
4600
			"    outer: for (int i = 0; i < 30; i++) {\n" + 
4601
			"      X x2 = x1;\n" + 
4602
			"      do {\n" + 
4603
			"        if (x2.equals(x1)) {\n" + 
4604
			"          continue outer;\n" + 
4605
			"        }\n" + 
4606
			"        x2 = x2.field;\n" + 
4607
			"      } while (x2 != null);\n" + 
4608
			"    }\n" + 
4609
			"  }\n" + 
4610
			"}\n"},
4611
		"");
4612
}
4613
4614
// null analysis -- for
4615
public void test0725_for_with_assignment() {
4616
	this.runConformTest(
4617
		new String[] {
4618
			"X.java",
4619
			"public class X {\n" + 
4620
			"  X field;\n" + 
4621
			"  void foo(X x1) {\n" + 
4622
			"    X x2;\n" + 
4623
			"    outer: for (int i = 0; i < 30; i++) {\n" + 
4624
			"      x2 = x1;\n" + 
4625
			"      do {\n" + 
4626
			"        if (x2.equals(x1)) {\n" + 
4627
			"          continue outer;\n" + 
4628
			"        }\n" + 
4629
			"        x2 = x2.field;\n" + 
4630
			"      } while (x2 != null);\n" + 
4631
			"    }\n" + 
4632
			"  }\n" + 
4633
			"}\n"},
4634
		"");
4635
}
4636
4637
// null analysis -- for
4638
// contrast this with #311
4639
public void test0726_for() {
4640
	this.runNegativeTest(
4641
		new String[] {
4642
			"X.java",
4643
			"public class X {\n" + 
4644
			"  void foo(X x1) {\n" + 
4645
			"    X x2 = null;\n" + 
4646
			"    for (int i = 0; i < 5; i++) {\n" + 
4647
			"      if (x2 == null) {\n" + 
4648
			"        x2 = x1;\n" + 
4649
			"      }\n" + 
4650
			"      x2.toString();\n" + 
4651
			"    }\n" + 
4652
			"  }\n" +  
4653
			"}\n"},
4654
		"----------\n" + 
4655
		"1. ERROR in X.java (at line 8)\n" + 
4656
		"	x2.toString();\n" + 
4657
		"	^^\n" + 
4658
		"The variable x2 may be null\n" + 
4659
		"----------\n");
4660
}
4661
4662
// null analysis -- for
4663
public void test0727_for() {
4664
	this.runConformTest(
4665
		new String[] {
4666
			"X.java",
4667
			"public class X {\n" + 
4668
			"  void foo() {\n" + 
4669
			"    for (; true;) { /* */ }\n" + 
4670
			"  }\n" + 
4671
			"}\n"},
4672
		"");
4673
}
4674
4675
// null analysis -- for
4676
public void test0728_for() {
4677
	this.runNegativeTest(
4678
		new String[] {
4679
			"X.java",
4680
			"public class X {\n" + 
4681
			"  void foo(X x) {\n" + 
4682
			"    for (; true; x.toString()) { /* */ }\n" + 
4683
			"    if (x == null) { /* */ }\n" + // complain 
4684
			"  }\n" + 
4685
			"}\n"},
4686
		"----------\n" + 
4687
		"1. ERROR in X.java (at line 4)\n" + 
4688
		"	if (x == null) { /* */ }\n" + 
4689
		"	^^^^^^^^^^^^^^^^^^^^^^^^\n" + 
4690
		"Unreachable code\n" + 
4691
		"----------\n");
4692
}
4693
4694
// null analysis -- for
4695
public void test0729_for_try_catch_finally() {
4696
	this.runConformTest(
4697
		new String[] {
4698
			"X.java",
4699
			"import java.io.IOException;\n" + 
4700
			"class X {\n" + 
4701
			"  X f;\n" + 
4702
			"  void bar() throws IOException {\n" + 
4703
			"    throw new IOException();\n" + 
4704
			"  }\n" + 
4705
			"  void foo(boolean b) {\n" + 
4706
			"    for (int i = 0 ; i < 5 ; i++) {\n" + 
4707
			"      X x = this.f;\n" + 
4708
			"      if (x == null) { \n" + 
4709
			"        continue;\n" + 
4710
			"      }\n" + 
4711
			"      if (b) {\n" + 
4712
			"        try {\n" + 
4713
			"          bar();\n" + 
4714
			"        } \n" + 
4715
			"        catch(IOException e) { /* */ }\n" + 
4716
			"        finally {\n" + 
4717
			"          x.toString();\n" + 
4718
			"        }\n" + 
4719
			"      }\n" + 
4720
			"    }\n" + 
4721
			"  }\n" + 
4722
			"}"},
4723
		"");
4724
}
4725
4726
// null analysis - for
4727
public void test0730_for() {
4728
	this.runNegativeTest(
4729
		new String[] {
4730
			"X.java",
4731
			"class X {\n" + 
4732
			"  void foo(Object o) {\n" + 
4733
			"    for ( ; o == null ; ) {\n" +
4734
			"      o = new Object();\n" +
4735
			"    }\n" + 
4736
			"    if (o != null) { /* */ }\n" + // complain 
4737
			"  }\n" + 
4738
			"}"},
4739
		"----------\n" + 
4740
		"1. ERROR in X.java (at line 6)\n" + 
4741
		"	if (o != null) { /* */ }\n" + 
4742
		"	    ^\n" + 
4743
		"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
4744
		"----------\n");
4745
}
4746
4747
// null analysis - for
4748
public void test0731_for() {
4749
	this.runNegativeTest(
4750
		new String[] {
4751
			"X.java",
4752
			"class X {\n" + 
4753
			"  X bar() {\n" + 
4754
			"    return new X();\n" + 
4755
			"  }\n" + 
4756
			"  void foo(Object o) {\n" + 
4757
			"    for ( ; o == null ; ) {\n" +
4758
			"      o = bar();\n" +
4759
			"    }\n" + 
4760
			"    if (o != null) { /* */ }\n" + // complain 
4761
			"  }\n" + 
4762
			"}"},
4763
		"----------\n" + 
4764
		"1. ERROR in X.java (at line 9)\n" + 
4765
		"	if (o != null) { /* */ }\n" + 
4766
		"	    ^\n" + 
4767
		"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
4768
		"----------\n");
4769
}
4770
4771
// null analysis -- switch
4772
public void test0800_switch() {
4773
	this.runConformTest(
4774
		new String[] {
4775
			"X.java",
4776
			"public class X {\n" + 
4777
			" int k;\n" + 
4778
			" void foo() {\n" + 
4779
			"   Object o = null;\n" + 
4780
			"   switch (k) {\n" + 
4781
			"     case 0 :\n" + 
4782
			"       o = new Object();\n" + 
4783
			"       break;\n" + 
4784
			"     case 2 :\n" + 
4785
			"       return;\n" + 
4786
			"   }\n" + 
4787
			"   if(o == null) { /* */ }\n" + // quiet: don't know whether came from 0 or default
4788
			" }\n" + 
4789
			"}\n"},
4790
		"");
4791
}
4792
4793
// null analysis -- switch
4794
public void test0801_switch() {
4795
	this.runNegativeTest(
4796
		new String[] {
4797
			"X.java",
4798
			"public class X {\n" + 
4799
			" int k;\n" + 
4800
			" void foo() {\n" + 
4801
			"   Object o = null;\n" + 
4802
			"   switch (k) {\n" + 
4803
			"     case 0 :\n" + 
4804
			"       o = new Object();\n" + 
4805
			"       break;\n" + 
4806
			"     default :\n" + 
4807
			"       return;\n" + 
4808
			"   }\n" + 
4809
			"   if(o == null) { /* */ }\n" + // complain: only get there through 0, o non null
4810
			" }\n" + 
4811
			"}\n"},
4812
		"----------\n" + 
4813
		"1. ERROR in X.java (at line 12)\n" + 
4814
		"	if(o == null) { /* */ }\n" + 
4815
		"	   ^\n" + 
4816
		"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
4817
		"----------\n");
4818
}
4819
4820
// null analysis -- switch
4821
public void test0802_switch() {
4822
	this.runNegativeTest(
4823
		new String[] {
4824
			"X.java",
4825
			"public class X {\n" + 
4826
			" int k;\n" + 
4827
			" void foo() {\n" + 
4828
			"   Object o = null;\n" + 
4829
			"   switch (k) {\n" + 
4830
			"     case 0 :\n" + 
4831
			"       o.toString();\n" + // complain: o can only be null
4832
			"       break;\n" + 
4833
			"   }\n" + 
4834
			" }\n" + 
4835
			"}\n"},
4836
		"----------\n" + 
4837
		"1. ERROR in X.java (at line 7)\n" + 
4838
		"	o.toString();\n" + 
4839
		"	^\n" + 
4840
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
4841
		"----------\n");
4842
}
4843
4844
// null analysis -- switch
4845
public void test0803_switch() {
4846
	this.runNegativeTest(
4847
		new String[] {
4848
			"X.java",
4849
			"public class X {\n" + 
4850
			" int k;\n" + 
4851
			" void foo() {\n" + 
4852
			"   Object o = null;\n" + 
4853
			"   switch (k) {\n" + 
4854
			"     case 0 :\n" + 
4855
			"       o = new Object();\n" + 
4856
			"     case 1 :\n" + 
4857
			"       o.toString();\n" + // complain: may come through 0 or 1
4858
			"       break;\n" + 
4859
			"   }\n" + 
4860
			" }\n" + 
4861
			"}\n"},
4862
		"----------\n" + 
4863
		"1. ERROR in X.java (at line 9)\n" + 
4864
		"	o.toString();\n" + 
4865
		"	^\n" + 
4866
		"The variable o may be null\n" + 
4867
		"----------\n");
4868
}
4869
4870
// null analysis -- switch
4871
public void test0804_switch() {
4872
	this.runNegativeTest(
4873
		new String[] {
4874
			"X.java",
4875
			"public class X {\n" + 
4876
			"  void foo (Object o, int info) {\n" + 
4877
			"	 o = null;\n" + 
4878
			"	 switch (info) {\n" + 
4879
			"	   case 0 :\n" + 
4880
			"		 o = new Object();\n" + 
4881
			"		 break;\n" + 
4882
			"	   case 1 :\n" + 
4883
			"		 o = new String();\n" + 
4884
			"		 break;\n" + 
4885
			"	   default :\n" + 
4886
			"		 o = new X();\n" + 
4887
			"		 break;\n" + 
4888
			"	 }\n" + 
4889
			"	 if(o != null) { /* */ }\n" + // complain: all branches allocate a new o
4890
			"  }\n" + 
4891
			"}\n"},
4892
		"----------\n" + 
4893
		"1. ERROR in X.java (at line 15)\n" + 
4894
		"	if(o != null) { /* */ }\n" + 
4895
		"	   ^\n" + 
4896
		"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
4897
		"----------\n");
4898
}
4899
4900
// null analysis -- switch
4901
public void test0805_switch() {
4902
	this.runConformTest(
4903
		new String[] {
4904
			"X.java",
4905
			"public class X {\n" + 
4906
			"  void foo(X p) {\n" + 
4907
			"    X x = this;\n" + 
4908
			"    for (int i = 0; i < 5; i++) {\n" + 
4909
			"      switch (i) {\n" + 
4910
			"        case 1:\n" + 
4911
			"          x = p;\n" + 
4912
			"      }\n" + 
4913
			"    }\n" + 
4914
			"    if (x != null) { /* */ }\n" + 
4915
			"  }\n" + 
4916
			"}\n"},
4917
		"");
4918
}
4919
4920
// null analysis -- non null protection tag
4921
public void test0900_non_null_protection_tag() {
4922
	this.runConformTest(
4923
		new String[] {
4924
			"X.java",
4925
			"public class X {\n" + 
4926
			"  void foo(Object o) {\n" + 
4927
			"    boolean b = o != null;\n" + // shades doubts upon o 
4928
			"    o/*NN*/.toString();\n" + 	// protection => do not complain
4929
			"    o.toString();\n" + 		// protected by previous line
4930
			"  }\n" + 
4931
			"}\n"},
4932
		"");
4933
}
4934
4935
// null analysis -- non null protection tag
4936
public void test0901_non_null_protection_tag() {
4937
	this.runConformTest(
4938
		new String[] {
4939
			"X.java",
4940
			"public class X {\n" + 
4941
			"  void foo(Object o, boolean b) {\n" + 
4942
			"    if (b) {\n" +
4943
			"      o = null;\n" +
4944
			"    }\n" + 
4945
			"    o/*NN*/.toString();\n" +
4946
			"    if (b) {\n" +
4947
			"      o = null;\n" +
4948
			"    }\n" + 
4949
			"    o/*\n" +
4950
			"         NN  comment  */.toString();\n" +
4951
			"    if (b) {\n" +
4952
			"      o = null;\n" +
4953
			"    }\n" + 
4954
			"    o/*  NN\n" +
4955
			"               */.toString();\n" +
4956
			"    if (b) {\n" +
4957
			"      o = null;\n" +
4958
			"    }\n" + 
4959
			"    o               //  NN   \n" +
4960
			"      .toString();\n" +
4961
			"  }\n" + 
4962
			"}\n"},
4963
		"");
4964
}
4965
4966
// null analysis -- non null protection tag
4967
public void test0902_non_null_protection_tag() {
4968
	this.runConformTest(
4969
		new String[] {
4970
			"X.java",
4971
			"public class X {\n" + 
4972
			"  void foo(Object o, boolean b) {\n" + 
4973
			"    if (b) {\n" +
4974
			"      o = null;\n" +
4975
			"    }\n" + 
4976
			"    o/*NON-NULL*/.toString();\n" +
4977
			"    if (b) {\n" +
4978
			"      o = null;\n" +
4979
			"    }\n" + 
4980
			"    o/*  NON-NULL   comment */.toString();\n" +
4981
			"    if (b) {\n" +
4982
			"      o = null;\n" +
4983
			"    }\n" + 
4984
			"    o/*  NON-NULL   \n" +
4985
			"               */.toString();\n" +
4986
			"    if (b) {\n" +
4987
			"      o = null;\n" +
4988
			"    }\n" + 
4989
			"    o               //  NON-NULL   \n" +
4990
			"      .toString();\n" +
4991
			"  }\n" + 
4992
			"}\n"},
4993
		"");
4994
}
4995
4996
// null analysis -- non null protection tag
4997
public void test0903_non_null_protection_tag() {
4998
	this.runNegativeTest(
4999
		new String[] {
5000
			"X.java",
5001
			"public class X {\n" + 
5002
			"  void foo(Object o, boolean b) {\n" + 
5003
			"    if (b) {\n" +
5004
			"      o = null;\n" +
5005
			"    }\n" + 
5006
			"    o/*N N*/.toString();\n" +
5007
			"    if (b) {\n" +
5008
			"      o = null;\n" +
5009
			"    }\n" + 
5010
			"    o/*NNa*/.toString();\n" +
5011
			"    if (b) {\n" +
5012
			"      o = null;\n" +
5013
			"    }\n" + 
5014
			"    o/*aNN */.toString();\n" +
5015
			"    if (b) {\n" +
5016
			"      o = null;\n" +
5017
			"    }\n" + 
5018
			"    o/*NON NULL*/.toString();\n" +
5019
			"    if (b) {\n" +
5020
			"      o = null;\n" +
5021
			"    }\n" + 
5022
			"    o/*Non-Null*/.toString();\n" +
5023
			"    if (b) {\n" +
5024
			"      o = null;\n" +
5025
			"    }\n" + 
5026
			"    o/*aNON-NULL */.toString();\n" +
5027
			"  }\n" + 
5028
			"}\n"},
5029
		"----------\n" + 
5030
		"1. ERROR in X.java (at line 6)\n" + 
5031
		"	o/*N N*/.toString();\n" + 
5032
		"	^\n" + 
5033
		"The variable o may be null\n" + 
5034
		"----------\n" + 
5035
		"2. ERROR in X.java (at line 10)\n" + 
5036
		"	o/*NNa*/.toString();\n" + 
5037
		"	^\n" + 
5038
		"The variable o may be null\n" + 
5039
		"----------\n" + 
5040
		"3. ERROR in X.java (at line 14)\n" + 
5041
		"	o/*aNN */.toString();\n" + 
5042
		"	^\n" + 
5043
		"The variable o may be null\n" + 
5044
		"----------\n" + 
5045
		"4. ERROR in X.java (at line 18)\n" + 
5046
		"	o/*NON NULL*/.toString();\n" + 
5047
		"	^\n" + 
5048
		"The variable o may be null\n" + 
5049
		"----------\n" + 
5050
		"5. ERROR in X.java (at line 22)\n" + 
5051
		"	o/*Non-Null*/.toString();\n" + 
5052
		"	^\n" + 
5053
		"The variable o may be null\n" + 
5054
		"----------\n" + 
5055
		"6. ERROR in X.java (at line 26)\n" + 
5056
		"	o/*aNON-NULL */.toString();\n" + 
5057
		"	^\n" + 
5058
		"The variable o may be null\n" + 
5059
		"----------\n");
5060
}
5061
5062
5063
// null analysis -- non null protection tag
5064
public void test0905_non_null_protection_tag() {
5065
	this.runNegativeTest(
5066
		new String[] {
5067
			"X.java",
5068
			"public class X {\n" + 
5069
			"  void foo(Object o) {\n" + 
5070
			"    boolean b = o != null;\n" + // shades doubts upon o 
5071
			"    o.toString();/*NN*/\n" + 	// too late to protect => complain
5072
			"  }\n" + 
5073
			"}\n"},
5074
		"----------\n" + 
5075
		"1. ERROR in X.java (at line 4)\n" + 
5076
		"	o.toString();/*NN*/\n" + 
5077
		"	^\n" + 
5078
		"The variable o may be null\n" + 
5079
		"----------\n");
5080
}
5081
5082
// null analysis -- non null protection tag
5083
public void test0906_non_null_protection_tag() {
5084
	this.runNegativeTest(
5085
		new String[] {
5086
			"X.java",
5087
			"public class X {\n" + 
5088
			"  void foo(Object o) {\n" + 
5089
			"    boolean b = o != null;\n" + // shades doubts upon o 
5090
			"    /*NN*/o.toString();\n" + 	// too soon to protect => complain
5091
			"  }\n" + 
5092
			"}\n"},
5093
		"----------\n" + 
5094
		"1. ERROR in X.java (at line 4)\n" + 
5095
		"	/*NN*/o.toString();\n" + 
5096
		"	      ^\n" + 
5097
		"The variable o may be null\n" + 
5098
		"----------\n");
5099
}
5100
5101
// null analysis -- notNull protection tag
5102
public void _test0900_notNull_protection_tag() {
5103
	this.runNegativeTest(
5104
		new String[] {
5105
			"X.java",
5106
			"public class X {\n" + 
5107
			"  void foo(/** @notNull */ Object o) {\n" + 
5108
			"    boolean b = o != null;\n" + 
5109
			"  }\n" + 
5110
			"}\n"},
5111
		"ERR cannot be null");
5112
}
5113
5114
// null analysis -- notNull protection tag
5115
public void _test0901_notNull_protection_tag() {
5116
	this.runNegativeTest(
5117
		new String[] {
5118
			"X.java",
5119
			"public class X {\n" + 
5120
			"  void foo(Object o) {\n" + 
5121
			"    /** @notNull */ Object l = o;\n" +
5122
			"  }\n" + 
5123
			"}\n"},
5124
		"ERR cannot be null... ou pas ?");
5125
}
5126
5127
// null analysis -- notNull protection tag
5128
public void _test0902_notNull_protection_tag() {
5129
	this.runNegativeTest(
5130
		new String[] {
5131
			"X.java",
5132
			"public class X {\n" + 
5133
			"  void foo(/** @nullable */ Object o) {\n" + 
5134
			"    /** @notNull */ Object l = o;\n" +
5135
			"  }\n" + 
5136
			"}\n"},
5137
		"ERR cannot be null");
5138
}
5139
5140
// null analysis -- notNull protection tag
5141
public void _test0903_notNull_protection_tag() {
5142
	this.runConformTest(
5143
		new String[] {
5144
			"X.java",
5145
			"public class X {\n" + 
5146
			"  Object bar() {\n" + 
5147
			"    return null;\n" +
5148
			"  }\n" + 
5149
			"  void foo() {\n" + 
5150
			"    /** @notNull */ Object l = bar();\n" +
5151
			"  }\n" + 
5152
			"}\n"},
5153
		"");
5154
}
5155
5156
// null analysis -- notNull protection tag
5157
public void _test0904_notNull_protection_tag() {
5158
	this.runNegativeTest(
5159
		new String[] {
5160
			"X.java",
5161
			"public class X {\n" + 
5162
			"  /** @notNull */\n" +
5163
			"  Object bar() {\n" + 
5164
			"    return new Object();\n" +
5165
			"  }\n" + 
5166
			"  void foo() {\n" + 
5167
			"    Object l = bar();\n" +
5168
			"    if (l == null) { /* empty */ }\n" +
5169
			"  }\n" + 
5170
			"}\n"},
5171
		"ERR cannot be null");
5172
}
5173
5174
// null analysis -- notNull protection tag
5175
public void _test0905_notNull_protection_tag() {
5176
	this.runNegativeTest(
5177
		new String[] {
5178
			"X.java",
5179
			"public class X {\n" + 
5180
			"  /** @notNull */\n" +
5181
			"  Object bar() {\n" + 
5182
			"    return null;\n" +
5183
			"  }\n" + 
5184
			"}\n"},
5185
		"ERR cannot be null");
5186
}
5187
5188
// null analysis -- nullable tag
5189
public void _test0950_nullable_tag() {
5190
	this.runConformTest(
5191
		new String[] {
5192
			"X.java",
5193
			"public class X {\n" + 
5194
			"  void foo(/** @nullable */ Object o) {\n" + 
5195
			"    o.toString();\n" +
5196
			"  }\n" + 
5197
			"}\n"},
5198
		"ERR may be null");
5199
}
5200
5201
// null analysis -- nullable tag
5202
public void _test0951_nullable_tag() {
5203
	this.runConformTest(
5204
		new String[] {
5205
			"X.java",
5206
			"public class X {\n" + 
5207
			"  void foo(/** @nullable */ Object o) {\n" + 
5208
			"    Object l = o;\n" +
5209
			"    l.toString();\n" +
5210
			"  }\n" + 
5211
			"}\n"},
5212
		"ERR may be null");
5213
}
5214
5215
// null analysis -- nullable tag
5216
public void _test0952_nullable_tag() {
5217
	this.runConformTest(
5218
		new String[] {
5219
			"X.java",
5220
			"public class X {\n" + 
5221
			"  void foo(boolean b) {\n" + 
5222
			"    /** @nullable */ Object o;\n" +
5223
			"    if (b) {\n" +
5224
			"      o = new Object();\n" +
5225
			"    }\n" +
5226
			"    o.toString();\n" +
5227
			"  }\n" + 
5228
			"}\n"},
5229
		"ERR may be null");
5230
}
5231
5232
// moved from AssignmentTest
5233
public void test1004() {
5234
	this.runNegativeTest(
5235
		new String[] {
5236
			"X.java",
5237
			"public class X {\n" + 
5238
			"  X foo(X x) {\n" + 
5239
			"    x.foo(null); // 0\n" + 
5240
			"    if (x != null) { // 1\n" + 
5241
			"      if (x == null) { // 2\n" + 
5242
			"        x.foo(null); // 3\n" + 
5243
			"      } else if (x instanceof X) { // 4\n" + 
5244
			"        x.foo(null); // 5 \n" + 
5245
			"      } else if (x != null) { // 6\n" + 
5246
			"        x.foo(null); // 7\n" + 
5247
			"      }\n" + 
5248
			"      x.foo(null); // 8\n" + 
5249
			"    }\n" + 
5250
			"    return this;\n" + 
5251
			"  }\n" + 
5252
			"}\n"},
5253
		"----------\n" + 
5254
		"1. ERROR in X.java (at line 4)\n" + 
5255
		"	if (x != null) { // 1\n" + 
5256
		"	    ^\n" + 
5257
		"The variable x cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
5258
		"----------\n" + 
5259
		"2. ERROR in X.java (at line 5)\n" + 
5260
		"	if (x == null) { // 2\n" + 
5261
		"	    ^\n" + 
5262
		"The variable x cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
5263
		"----------\n" + 
5264
		"3. ERROR in X.java (at line 6)\n" + 
5265
		"	x.foo(null); // 3\n" + 
5266
		"	^\n" + 
5267
		"The variable x can only be null; it was either set to null or checked for null when last used\n" + 
5268
		"----------\n" + 
5269
		"4. ERROR in X.java (at line 9)\n" + 
5270
		"	} else if (x != null) { // 6\n" + 
5271
		"	           ^\n" + 
5272
		"The variable x cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
5273
		"----------\n" + 
5274
		"5. ERROR in X.java (at line 12)\n" + 
5275
		"	x.foo(null); // 8\n" + 
5276
		"	^\n" + 
5277
		"The variable x may be null\n" + 
5278
		"----------\n");
5279
}
5280
5281
public void test1005() {
5282
	this.runConformTest(
5283
		new String[] {
5284
			"X.java",
5285
			"public class X {\n" + 
5286
			"  void foo(Class c) {\n" + 
5287
			"    if (c.isArray() ) {\n" + 
5288
			"    } else if (c == java.lang.String.class ) {\n" + 
5289
			"    }\n" + 
5290
			"  }\n" + 
5291
			"}\n"},
5292
		"");
5293
}
5294
5295
public void test1006() {
5296
	this.runConformTest(
5297
		new String[] {
5298
			"X.java",
5299
			"public class X {\n" + 
5300
			"  void foo(X x) {\n" + 
5301
			"    if (x == this)\n" + 
5302
			"     return;\n" + 
5303
			"    x.foo(this);\n" + 
5304
			"  }\n" + 
5305
			"}\n"},
5306
		"");
5307
}
5308
5309
public void test1007() {
5310
	this.runConformTest(
5311
		new String[] {
5312
			"X.java",
5313
			"public class X {\n" + 
5314
			"  void foo(X x, X x2) {\n" + 
5315
			"    if (x != null)\n" + 
5316
			"      return;\n" + 
5317
			"    x = x2;\n" + 
5318
			"    if (x == null) {\n" + 
5319
			"    }\n" + 
5320
			"  }\n" + 
5321
			"}\n"},
5322
		"");
5323
}
5324
5325
public void test1008() {
5326
	this.runConformTest(
5327
		new String[] {
5328
			"X.java",
5329
			"public class X {\n" + 
5330
			"  void foo(X x, X x2) {\n" + 
5331
			"    if (x != null)\n" + 
5332
			"      return;\n" + 
5333
			"    try {\n" + 
5334
			"      x = x2;\n" + 
5335
			"    } catch(Exception e) {}\n" + 
5336
			"    if (x == null) {\n" + 
5337
			"    }\n" + 
5338
			"  }\n" + 
5339
			"}\n"},
5340
		"");
5341
}
5342
5343
// TODO (philippe) reenable once fixed
5344
public void _test1009() {
5345
	this.runNegativeTest(
5346
		new String[] {
5347
			"X.java",
5348
			"import java.io.File;\n" + 
5349
			"\n" + 
5350
			"public class X {\n" + 
5351
			"  boolean check(String name) { return true; }\n" + 
5352
			"  Class bar(String name) throws ClassNotFoundException { return null; }\n" + 
5353
			"  File baz(String name) { return null; }\n" + 
5354
			"  \n" + 
5355
			"  public Class foo(String name, boolean resolve) throws ClassNotFoundException {\n" + 
5356
			"    \n" + 
5357
			"    Class c = bar(name);\n" + 
5358
			"    if (c != null)\n" + 
5359
			"      return c;\n" + 
5360
			"    if (check(name)) {\n" + 
5361
			"      try {\n" + 
5362
			"        c= bar(name);\n" + 
5363
			"          return c;\n" + 
5364
			"      } catch (ClassNotFoundException e) {\n" + 
5365
			"        // keep searching\n" + 
5366
			"        // only path to here left c unassigned from try block, means it was assumed to be null\n" + 
5367
			"      }\n" + 
5368
			"    }\n" + 
5369
			"    if (c == null) {// should complain: c can only be null\n" + 
5370
			"      File file= baz(name);\n" + 
5371
			"      if (file == null)\n" + 
5372
			"        throw new ClassNotFoundException();\n" + 
5373
			"    }\n" + 
5374
			"    return c;\n" + 
5375
			"  }\n" + 
5376
			"\n" + 
5377
			"}\n"},
5378
		"----------\n" + 
5379
		"1. ERROR in X.java (at line 22)\n" + 
5380
		"	if (c == null) {// should complain: c can only be null\n" + 
5381
		"	    ^\n" + 
5382
		"The variable c can only be null; it was either set to null or checked for null when last used\n" + 
5383
		"----------\n");
5384
}
5385
5386
// REVIEW maybe leave this one in AssignmentTest?
5387
public void test1010() {
5388
	this.runConformTest(
5389
		new String[] {
5390
			"X.java",
5391
			"public class X {\n" + 
5392
			"\n" + 
5393
			"  X itself() { return this; }\n" + 
5394
			"\n" + 
5395
			"  void bar() {\n" + 
5396
			"    X itself = this.itself();\n" + 
5397
			"    if (this == itself) {\n" + 
5398
			"      System.out.println(itself.toString()); //1\n" + 
5399
			"    } else {\n" + 
5400
			"      System.out.println(itself.toString()); //2\n" + 
5401
			"    }\n" + 
5402
			"  }\n" + 
5403
			"}\n"},
5404
		"");
5405
}
5406
5407
public void test1011() {
5408
	this.runNegativeTest(
5409
		new String[] {
5410
			"X.java",
5411
			"public class X {\n" + 
5412
			"\n" + 
5413
			"  X itself() { return this; }\n" + 
5414
			"\n" + 
5415
			"  void bar() {\n" + 
5416
			"    X itself = this.itself();\n" + 
5417
			"    if (this == itself) {\n" + 
5418
			"      X other = (X)itself;\n" + 
5419
			"      if (other != null) {\n" + 
5420
			"      }\n" + 
5421
			"      if (other == null) {\n" + 
5422
			"      }\n" + 
5423
			"    }\n" + 
5424
			"  }\n" + 
5425
			"}\n"},
5426
		"----------\n" + 
5427
		"1. ERROR in X.java (at line 9)\n" + 
5428
		"	if (other != null) {\n" + 
5429
		"	    ^^^^^\n" + 
5430
		"The variable other cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
5431
		"----------\n");
5432
}
5433
5434
public void test1012() {
5435
	this.runNegativeTest(
5436
		new String[] {
5437
			"X.java",
5438
			"public class X {\n" + 
5439
			"  \n" + 
5440
			"  void foo() {\n" + 
5441
			"    Object o = null;\n" + 
5442
			"    do {\n" + 
5443
			"      if (o == null) {\n" +
5444
			"        return;\n" +
5445
			"      }\n" + 
5446
			"      // o = bar();\n" + 
5447
			"    } while (true);\n" + 
5448
			"  }\n" + 
5449
			"  X bar() { \n" + 
5450
			"    return null; \n" + 
5451
			"  }\n" + 
5452
			"}"},
5453
		"----------\n" + 
5454
		"1. ERROR in X.java (at line 6)\n" + 
5455
		"	if (o == null) {\n" + 
5456
		"	    ^\n" + 
5457
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
5458
		"----------\n"
5459
	);
5460
}
5461
5462
// REVIEW here we do not catch the dead branch: x cannot equal this then null with no assignment in between
5463
public void test1013() {
5464
	this.runNegativeTest(
5465
		new String[] {
5466
			"X.java",
5467
			"public class X {\n" + 
5468
			"  void foo(X x) {\n" + 
5469
			"    if (x == this) {\n" + 
5470
			"      if (x == null) {\n" + 
5471
			"        x.foo(this);\n" + 
5472
			"      }\n" + 
5473
			"    }\n" + 
5474
			"  }\n" + 
5475
			"}\n"},
5476
		"----------\n" + 
5477
		"1. ERROR in X.java (at line 4)\n" + 
5478
		"	if (x == null) {\n" + 
5479
		"	    ^\n" + 
5480
		"The variable x cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
5481
		"----------\n" + 
5482
		"2. ERROR in X.java (at line 5)\n" + 
5483
		"	x.foo(this);\n" + 
5484
		"	^\n" + 
5485
		"The variable x can only be null; it was either set to null or checked for null when last used\n" + 
5486
		"----------\n");
5487
}
5488
5489
public void test1014() {
5490
	this.runNegativeTest(
5491
		new String[] {
5492
			"X.java",
5493
			"public class X {\n" + 
5494
			"  void foo(X x) {\n" + 
5495
			"    x = null;\n" + 
5496
			"    try {\n" + 
5497
			"      x = this;\n" + 
5498
			"    } finally {\n" + 
5499
			"      x.foo(null);\n" + 
5500
			"    }\n" + 
5501
			"  }\n" + 
5502
			"}\n"},
5503
		"----------\n" + 
5504
		"1. ERROR in X.java (at line 7)\n" + 
5505
		"	x.foo(null);\n" + 
5506
		"	^\n" + 
5507
		"The variable x may be null\n" + 
5508
		"----------\n");
5509
}
5510
5511
public void test1015() {
5512
	this.runConformTest(
5513
		new String[] {
5514
			"X.java",
5515
			"public class X {\n" + 
5516
			"  void foo() {\n" + 
5517
			"    Object o = null;\n" + 
5518
			"    int i = 1;\n" + 
5519
			"    switch (i) {\n" + 
5520
			"      case 1:\n" + 
5521
			"        o = new Object();\n" + 
5522
			"        break;\n" + 
5523
			"    }\n" + 
5524
			"    if (o != null)\n" + 
5525
			"      o.toString();\n" + 
5526
			"  }\n" + 
5527
			"}\n"},
5528
		"");
5529
}
5530
5531
public void test1016() {
5532
	this.runNegativeTest(
5533
		new String[] {
5534
			"X.java",
5535
			"public class X {\n" + 
5536
			"  void foo(X x) {\n" + 
5537
			"    x = null;\n" + 
5538
			"    try {\n" + 
5539
			"      x = null;\n" + 
5540
			"    } finally {\n" + 
5541
			"      if (x != null) {\n" + 
5542
			"        x.foo(null);\n" + 
5543
			"      }\n" + 
5544
			"    }\n" + 
5545
			"  }\n" + 
5546
			"}\n"},
5547
		"----------\n" + 
5548
		"1. ERROR in X.java (at line 5)\n" + 
5549
		"	x = null;\n" + 
5550
		"	^\n" + 
5551
		"The variable x can only be null; it was either set to null or checked for null when last used\n" + 
5552
		"----------\n" + 
5553
		"2. ERROR in X.java (at line 7)\n" + 
5554
		"	if (x != null) {\n" + 
5555
		"	    ^\n" + 
5556
		"The variable x can only be null; it was either set to null or checked for null when last used\n" + 
5557
		"----------\n");
5558
}
598
5559
599
	// null analysis -- array
5560
public void test1017() { 
600
	public void test0041_array() {
5561
	this.runNegativeTest(
601
		this.runNegativeTest(
5562
		new String[] {
602
			new String[] {
5563
			"X.java",
603
				"X.java",
5564
			"public class X {\n" + 
604
				"public class X {\n" + 
5565
			"  void foo(X x) {\n" + 
605
				"	 public static void main(String args[]) {\n" + 
5566
			"    x = this;\n" + 
606
				"		 args[0] = null;\n" +
5567
			"    try {\n" + 
607
				"    if (args[0] == null) {};\n" + 
5568
			"      x = null;\n" + 
608
				     // quiet: we don't keep track of all array elements
5569
			"    } finally {\n" + 
609
				"	 }\n" + 
5570
			"      if (x == null) {\n" + 
610
				"}\n"},
5571
			"        x.foo(null);\n" + 
611
			""
5572
			"      }\n" + 
612
		);
5573
			"    }\n" + 
613
	}
5574
			"  }\n" + 
5575
			"}\n"},
5576
		"----------\n" + 
5577
		"1. ERROR in X.java (at line 8)\n" + 
5578
		"	x.foo(null);\n" + 
5579
		"	^\n" + 
5580
		"The variable x can only be null; it was either set to null or checked for null when last used\n" + 
5581
		"----------\n");
5582
}
614
5583
615
	// null analysis -- array
5584
public void test1018() {
616
	public void test0042_array() {
5585
	this.runNegativeTest(
617
		this.runNegativeTest(
5586
		new String[] {
618
			new String[] {
5587
			"X.java",
619
				"X.java",
5588
			"public class X {\n" + 
620
				"public class X {\n" + 
5589
			"  \n" + 
621
				"	 public static void main(String args[]) {\n" + 
5590
			"  void foo() {\n" + 
622
				"		 args = null;\n" +
5591
			"    Object o = null;\n" + 
623
				"    args[0].toString();\n" + // complain: args is null
5592
			"    do {\n" + 
624
				"	 }\n" + 
5593
			"      if (o != null) return;\n" + 
625
				"}\n"},
5594
			"      o = null;\n" + 
626
			"----------\n" + 
5595
			"    } while (true);\n" + 
627
			"1. WARNING in X.java (at line 4)\n" + 
5596
			"  }\n" + 
628
			"	args[0].toString();\n" + 
5597
			"  X bar() { \n" + 
629
			"	^^^^\n" + 
5598
			"    return null; \n" + 
630
			"The variable args can only be null; it was either set to null or checked for null when last used\n" + 
5599
			"  }\n" + 
631
			"----------\n"
5600
			"}"},
632
		);
5601
		"----------\n" + 
633
	}
5602
		"1. ERROR in X.java (at line 6)\r\n" + 
5603
		"	if (o != null) return;\r\n" + 
5604
		"	    ^\n" + 
5605
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
5606
		"----------\n" + 
5607
		"2. ERROR in X.java (at line 7)\r\n" + 
5608
		"	o = null;\r\n" + 
5609
		"	^\n" + 
5610
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
5611
		"----------\n");
5612
}
634
5613
635
	// null analysis -- type reference
5614
public void test1019() {
636
	public void test0051_type_reference() {
5615
	this.runConformTest(
637
		this.runNegativeTest(
5616
		new String[] {
638
			new String[] {
5617
			"X.java",
639
				"X.java",
5618
			"public class X {\n" + 
640
				"public class X {\n" + 
5619
			"  public static final char[] replaceOnCopy(\n" + 
641
				"	 public static void main(String args[]) {\n" + 
5620
			"      char[] array,\n" + 
642
				"		 Class c = java.lang.Object.class;\n" +
5621
			"      char toBeReplaced,\n" + 
643
				"    if (c == null) {};\n" +
5622
			"      char replacementChar) {\n" + 
644
				"	 }\n" + 
5623
			"      \n" + 
645
				"}\n"},
5624
			"    char[] result = null;\n" + 
646
			"----------\n" + 
5625
			"    for (int i = 0, length = array.length; i < length; i++) {\n" + 
647
			"1. WARNING in X.java (at line 4)\n" + 
5626
			"      char c = array[i];\n" + 
648
			"	if (c == null) {};\n" + 
5627
			"      if (c == toBeReplaced) {\n" + 
649
			"	    ^\n" + 
5628
			"        if (result == null) {\n" + 
650
			"The variable c cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
5629
			"          result = new char[length];\n" + 
651
			"----------\n"
5630
			"          System.arraycopy(array, 0, result, 0, i);\n" + 
652
		);
5631
			"        }\n" + 
653
	}
5632
			"        result[i] = replacementChar;\n" + 
5633
			"      } else if (result != null) {\n" + 
5634
			"        result[i] = c;\n" + 
5635
			"      }\n" + 
5636
			"    }\n" + 
5637
			"    if (result == null) return array;\n" + 
5638
			"    return result;\n" + 
5639
			"  }\n" + 
5640
			"}\n"},
5641
		"");
5642
}
654
5643
655
	// null analysis -- method call
5644
public void test1021() {
656
	public void test0061_method_call_guard() {
5645
	this.runConformTest(
657
		this.runNegativeTest(
5646
		new String[] {
658
			new String[] {
5647
			"X.java",
659
				"X.java",
5648
			"public class X {\n" + 
660
				"public class X {\n" + 
5649
			"  int kind;\n" + 
661
				"	 void foo(Object o) {\n" + 
5650
			"  X parent;\n" + 
662
				"    if (o == null) {};\n" + // quiet: we don't know anything
5651
			"  Object[] foo() { return null; }\n" + 
663
				"    o.toString();\n" +      // guards o from being null
5652
			"  void findTypeParameters(X scope) {\n" + 
664
				"    if (o == null) {};\n" + // complain
5653
			"    Object[] typeParameters = null;\n" + 
665
				"	 }\n" + 
5654
			"    while (scope != null) {\n" + 
666
				"}\n"},
5655
			"      typeParameters = null;\n" + 
667
			"----------\n" + 
5656
			"      switch (scope.kind) {\n" + 
668
			"1. WARNING in X.java (at line 5)\n" + 
5657
			"        case 0 :\n" + 
669
			"	if (o == null) {};\n" + 
5658
			"          typeParameters = foo();\n" + 
670
			"	    ^\n" + 
5659
			"          break;\n" + 
671
			"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
5660
			"        case 1 :\n" + 
672
			"----------\n"
5661
			"          typeParameters = foo();\n" + 
673
		);
5662
			"          break;\n" + 
674
	}	
5663
			"        case 2 :\n" + 
675
	
5664
			"          return;\n" + 
676
	// null analysis - method call
5665
			"      }\n" + 
677
	public void test0062_method_call_isolation() {
5666
			"      if(typeParameters != null) {\n" + 
678
		this.runNegativeTest(
5667
			"        foo();\n" + 
679
			new String[] {
5668
			"      }\n" + 
680
				"X.java",
5669
			"      scope = scope.parent;\n" + 
681
				"public class X {\n" + 
5670
			"    }\n" + 
682
				"	 void foo(Object o) {\n" + 
5671
			"  }\n" + 
683
				"		 if (bar(o = null)) {\n" + 
5672
			"}\n"},
684
				"		   if (o == null) {/* empty */}\n" + // complain 
5673
		"");
685
				"		 }\n" + 
5674
}
686
				"	 }\n" + 
687
				"	 boolean bar(Object o) {\n" + 
688
				"		 return true;\n" + 
689
				"	 }\n" + 
690
				"}\n"},
691
			"----------\n" + 
692
			"1. WARNING in X.java (at line 4)\n" + 
693
			"	if (o == null) {/* empty */}\n" + 
694
			"	    ^\n" + 
695
			"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
696
			"----------\n"
697
		);
698
	}		
699
	
700
	// null analysis - method call
701
	public void test0063_method_call_isolation() {
702
		this.runNegativeTest(
703
			new String[] {
704
				"X.java",
705
				"public class X {\n" + 
706
				"	 void foo(Object o) {\n" + 
707
				"		 if (bar(o == null ? new Object() : o)) {\n" + 
708
				"		   if (o == null) {/* empty */}\n" + // quiet 
709
				"		 }\n" + 
710
				"	 }\n" + 
711
				"	 boolean bar(Object o) {\n" + 
712
				"		 return true;\n" + 
713
				"	 }\n" + 
714
				"}\n"},
715
			""
716
		);
717
	}		
718
	
719
	// null analysis - method call
720
	public void test0064_method_call_isolation() {
721
		this.runNegativeTest(
722
			new String[] {
723
				"X.java",
724
				"public class X {\n" + 
725
				"	 void foo(Object o) {\n" + 
726
				"		 if (bar(o = new Object())) {\n" + 
727
				"		   if (o == null) {/* empty */}\n" + // complain 
728
				"		 }\n" + 
729
				"	 }\n" + 
730
				"	 boolean bar(Object o) {\n" + 
731
				"		 return true;\n" + 
732
				"	 }\n" + 
733
				"}\n"},
734
			"----------\n" + 
735
			"1. WARNING in X.java (at line 4)\n" + 
736
			"	if (o == null) {/* empty */}\n" + 
737
			"	    ^\n" + 
738
			"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
739
			"----------\n"
740
		);
741
	}		
742
5675
743
	// null analysis - method call
5676
public void test1022() {
744
	public void test0065_method_call_invocation_target() {
5677
	this.runConformTest(
745
		this.runNegativeTest(
5678
		new String[] {
746
			new String[] {
5679
			"X.java",
747
				"X.java",
5680
			"public class X {\n" + 
748
				"public class X {\n" + 
5681
			"  boolean bool() { return true; }\n" + 
749
				"	 void foo() {\n" + 
5682
			"  void doSomething() {}\n" + 
750
				"		 Object o = null;\n" + 
5683
			"  \n" + 
751
				"		 (o = new Object()).toString();\n" + // quiet 
5684
			"  void foo() {\n" + 
752
				"	 }\n" + 
5685
			"    Object progressJob = null;\n" + 
753
				"}\n"},
5686
			"    while (bool()) {\n" + 
754
			""
5687
			"      if (bool()) {\n" + 
755
		);
5688
			"        if (progressJob != null)\n" + 
756
	}		
5689
			"          progressJob = null;\n" + 
757
5690
			"        doSomething();\n" + 
758
	// null analysis - method call
5691
			"      }\n" + 
759
	// TODO (maxime) fix
5692
			"      try {\n" + 
760
	public void _test0066_method_call_invocation_target() {
5693
			"        if (progressJob == null) {\n" + 
761
		this.runNegativeTest(
5694
			"          progressJob = new Object();\n" + 
762
			new String[] {
5695
			"        }\n" + 
763
				"X.java",
5696
			"      } finally {\n" + 
764
				"public class X {\n" + 
5697
			"        doSomething();\n" + 
765
				"	 void foo() {\n" + 
5698
			"      }\n" + 
766
				"		 Object o = new Object();\n" + 
5699
			"    }\n" + 
767
				"		 (o = null).toString();\n" + // complain 
5700
			"  }\n" + 
768
				"	 }\n" + 
5701
			"}"},
769
				"}\n"},
5702
		"");
770
			"----------\n" + 
5703
}
771
			"1. WARNING in X.java (at line 4)\n" + 
772
			"	(o = null).toString();\n" + 
773
			"	^^^^^^^^^^\n" + 
774
			"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
775
			"----------\n"
776
		);
777
	}		
778
	
779
	// null analysis -- if/else
780
	// check that obviously unreachable code does not modify the null
781
	// status of a local
782
	// the said code is not marked as unreachable per JLS 14.21 (the rationale
783
	// being the accommodation for the if (constant_flag_evaluating_to_false)
784
	// {code...} volontary code exclusion pattern)
785
	// TODO (maxime) fix
786
	public void _test0100_if_else() {
787
		this.runNegativeTest(
788
			new String[] {
789
				"X.java",
790
				"public class X {\n" + 
791
				"  public void foo() {\n" + 				
792
				"		 Object o = null;\n" + 
793
				"		 if (false) {\n" + 
794
				"			 o = new Object();\n" + // skipped 
795
				"		 }\n" + 
796
				"		 if (true) {\n" + 
797
				"			 //\n" + 
798
				"		 }\n" + 
799
				"		 else {\n" + 
800
				"			 o = new Object();\n" + // skipped
801
				"		 }\n" + 
802
				"		 o.toString();\n" + 
803
				"	 }\n" + 
804
				"}\n"},
805
			"----------\n" + 
806
			"1. WARNING in X.java (at line 13)\n" + 
807
			"	o.toString();\n" + 
808
			"	^\n" + 
809
			"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
810
			"----------\n"  
811
		);
812
	}
813
	
814
	// TODO (maxime) - what about further diagnostics inside fake reachable code ? if (false) { o = null; o.toString(); }
815
	
816
	// null analysis - if/else
817
	public void test0101_if_else() {
818
		this.runNegativeTest(
819
			new String[] {
820
				"X.java",
821
				"public class X {\n" + 
822
				"	 void foo() {\n" + 
823
				"		 Object o = new Object();\n" + 
824
				"		 if (o != null) {\n" + 
825
				"		 }\n" + 
826
				"	 }\n" + 
827
				"}\n"},
828
			"----------\n" + 
829
			"1. WARNING in X.java (at line 4)\n" + 
830
			"	if (o != null) {\n" + 
831
			"	    ^\n" + 
832
			"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
833
			"----------\n"
834
		);
835
	}
836
5704
837
	// null analysis - if/else
5705
public void test1023() {
838
	public void test0102_if_else() {
5706
	this.runNegativeTest(
839
		this.runNegativeTest(
5707
		new String[] {
840
			new String[] {
5708
			"X.java",
841
				"X.java",
5709
			"public class X {\n" + 
842
				"public class X {\n" + 
5710
			"\n" + 
843
				"	 void foo(Object o) throws Exception {\n" + 
5711
			"  void foo() {\n" + 
844
				"		 if (o == null) {\n" + 
5712
			"    Object o = new Object();\n" + 
845
				"			 throw new Exception();\n" + 
5713
			"    while (this != null) {\n" + 
846
				"		 }\n" + 
5714
			"      try {\n" + 
847
				"		 if (o != null) {\n" + // only get there if o non null
5715
			"        o = null;\n" + 
848
				"		 }\n" + 
5716
			"        break;\n" + 
849
				"	 }\n" + 
5717
			"      } finally {\n" + 
850
				"}\n"},
5718
			"        o = new Object();\n" + 
851
			"----------\n" + 
5719
			"      }\n" + 
852
			"1. WARNING in X.java (at line 6)\n" + 
5720
			"    }\n" + 
853
			"	if (o != null) {\n" + 
5721
			"    if (o == null) return;\n" + 
854
			"	    ^\n" + 
5722
			"  }\n" + 
855
			"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
5723
			"}\n"},
856
			"----------\n"
5724
		"----------\n" + 
857
		);
5725
		"1. ERROR in X.java (at line 13)\n" + 
858
	}
5726
		"	if (o == null) return;\n" + 
5727
		"	    ^\n" + 
5728
		"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
5729
		"----------\n");
5730
}
859
5731
860
	// null analysis - if/else
5732
public void test1024() {
861
	public void test0103_if_else() {
5733
	this.runNegativeTest(
862
		this.runNegativeTest(
5734
		new String[] {
863
			new String[] {
5735
			"X.java",
864
				"X.java",
5736
			"public class X {\n" + 
865
				"public class X {\n" + 
5737
			"  \n" + 
866
				"	 void foo(Object o) {\n" + 
5738
			"  boolean bool() { return true; }\n" + 
867
				"		 if (o == null) {\n" + 
5739
			"  void doSomething() {}\n" + 
868
				"			 return;\n" + 
5740
			"  \n" + 
869
				"		 }\n" + 
5741
			"  void foo() {\n" + 
870
				"		 if (o != null) {\n" + 
5742
			"    Object progressJob = null;\n" + 
871
				"		 }\n" + 
5743
			"    while (bool()) {\n" + 
872
				"	 }\n" + 
5744
			"      if (progressJob != null)\n" + 
873
				"}\n"},
5745
			"        progressJob = null;\n" + 
874
			"----------\n" + 
5746
			"      doSomething();\n" + 
875
			"1. WARNING in X.java (at line 6)\n" + 
5747
			"      try {\n" + 
876
			"	if (o != null) {\n" + 
5748
			"        if (progressJob == null) {\n" + 
877
			"	    ^\n" + 
5749
			"          progressJob = new Object();\n" + 
878
			"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
5750
			"        }\n" + 
879
			"----------\n"
5751
			"      } finally {\n" + 
880
		);
5752
			"        doSomething();\n" + 
881
	}
5753
			"      }\n" + 
5754
			"    }\n" + 
5755
			"  }\n" + 
5756
			"}"},
5757
		"----------\n" + 
5758
		"1. ERROR in X.java (at line 13)\n" + 
5759
		"	if (progressJob == null) {\n" + 
5760
		"	    ^^^^^^^^^^^\n" + 
5761
		"The variable progressJob can only be null; it was either set to null or checked for null when last used\n" + 
5762
		"----------\n");
5763
}
882
5764
883
	// null analysis - if/else
5765
public void test1025() {
884
	public void test0104_if_else() {
5766
	this.runNegativeTest(
885
		this.runNegativeTest(
5767
		new String[] {
886
			new String[] {
5768
			"X.java",
887
				"X.java",
5769
			"public class X {\n" + 
888
				"public class X {\n" + 
5770
			"  \n" + 
889
				"	 void foo(Object o) {\n" + 
5771
			"  void foo() {\n" + 
890
				"		 if (o == null) {\n" + 
5772
			"    Object o;\n" + 
891
				"		   o.toString();\n" + 
5773
			"    try {\n" + 
892
				"		 }\n" + 
5774
			"      o = null;\n" + 
893
				"	 }\n" + 
5775
			"    } finally {\n" + 
894
				"}\n"},
5776
			"      o = new Object();\n" + 
895
			"----------\n" + 
5777
			"    }\n" + 
896
			"1. WARNING in X.java (at line 4)\n" + 
5778
			"    if (o == null) return;\n" + 
897
			"	o.toString();\n" + 
5779
			"  }\n" + 
898
			"	^\n" + 
5780
			"}\n"},
899
			"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
5781
		"----------\n" + 
900
			"----------\n"
5782
		"1. ERROR in X.java (at line 10)\n" + 
901
		);
5783
		"	if (o == null) return;\n" + 
902
	}
5784
		"	    ^\n" + 
5785
		"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
5786
		"----------\n");
5787
}
903
5788
904
	// null analysis - if/else
5789
// TODO (philippe) reenable once fixed
905
	public void test0105_if_else() {
5790
public void _test1026() {
906
		this.runNegativeTest(
5791
	this.runConformTest(
907
			new String[] {
5792
		new String[] {
908
				"X.java",
5793
			"X.java",
909
				"public class X {\n" + 
5794
			"public class X {\n" + 
910
				"	 void foo(Object o) {\n" + 
5795
			"  \n" + 
911
				"		 if (o == null) {\n" + 
5796
			"  public static void main(String[] args) {\n" + 
912
				"			 // do nothing\n" + 
5797
			"    Object o;\n" + 
913
				"		 }\n" + 
5798
			"    try {\n" + 
914
				"		 o.toString();\n" + 
5799
			"      o = null;\n" + 
915
				"	 }\n" + 
5800
			"    } finally {\n" + 
916
				"}\n"},
5801
			"      if (args == null) o = new Object();\n" + 
917
			""
5802
			"    }\n" + 
918
		);
5803
			"    if (o == null) System.out.println(\"SUCCESS\");\n" + 
919
	}
5804
			"  }\n" + 
5805
			"}\n"},
5806
		"SUCCESS");
5807
}
920
5808
921
	// null analysis - if/else
5809
// TODO (philippe) reenable once fixed
922
	public void test0106_if_else() {
5810
public void _test1027() {
923
		this.runNegativeTest(
5811
	this.runConformTest(
924
			new String[] {
5812
		new String[] {
925
				"X.java",
5813
			"X.java",
926
				"public class X {\n" + 
5814
			"public class X {\n" + 
927
				"	 void foo(Object o) {\n" + 
5815
			"  boolean b;\n" + 
928
				"		 if (o.toString().equals(\"\")) {\n" + 
5816
			"  void foo() {\n" + 
929
				"		   if (o == null) {\n" + // complain: could not get here 
5817
			"    Object o = null;\n" + 
930
				"			   // do nothing\n" + 
5818
			"    while (b) {\n" + 
931
				"		   }\n" + 
5819
			"      try {\n" + 
932
				"		 }\n" + 
5820
			"        o = null;\n" + 
933
				"	 }\n" + 
5821
			"      } finally {\n" + 
934
				"}\n"},
5822
			"        if (o == null) \n" + 
935
			"----------\n" + 
5823
			"          o = new Object();\n" + 
936
			"1. WARNING in X.java (at line 4)\n" + 
5824
			"        }\n" + 
937
			"	if (o == null) {\n" + 
5825
			"      }\n" + 
938
			"	    ^\n" + 
5826
			"    if (o == null) return;\n" + 
939
			"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
5827
			"  }\n" + 
940
			"----------\n"
5828
			"}\n"},
941
		);
5829
		"");
942
	}
5830
}
5831
5832
// TODO (philippe) reenable once fixed
5833
public void _test1028() {
5834
	this.runConformTest(
5835
		new String[] {
5836
			"X.java",
5837
			"public class X {\n" + 
5838
			"  boolean b;\n" + 
5839
			"  void foo() {\n" + 
5840
			"    Object o = null;\n" + 
5841
			"    while (b) {\n" + 
5842
			"      try {\n" + 
5843
			"        o = null;\n" + 
5844
			"        break;\n" + 
5845
			"      } finally {\n" + 
5846
			"        if (o == null) \n" + 
5847
			"          o = new Object();\n" + 
5848
			"      }\n" + 
5849
			"    }\n" + 
5850
			"    if (o == null) return;\n" + 
5851
			"  }\n" + 
5852
			"}\n"},
5853
		"");
5854
}
5855
5856
public void test1029() {
5857
	this.runConformTest(
5858
		new String[] {
5859
			"X.java",
5860
			"public class X {\n" + 
5861
			"  public static void main(String[] args) {\n" + 
5862
			"    Object o = null;\n" + 
5863
			"    int i = 0;\n" + 
5864
			"    while (i++ < 2) {\n" + 
5865
			"      try {\n" + 
5866
			"        if (i == 2) return;\n" + 
5867
			"        o = null;\n" + 
5868
			"      } finally {\n" + 
5869
			"        if (i == 2) System.out.println(o);\n" + 
5870
			"        o = \"SUCCESS\";\n" + 
5871
			"      }\n" + 
5872
			"    }\n" + 
5873
			"    if (o == null) return;\n" + 
5874
			"  }\n" + 
5875
			"}\n"},
5876
		"SUCCESS");
5877
}
5878
5879
public void test1030() {
5880
	this.runNegativeTest(
5881
		new String[] {
5882
			"X.java",
5883
			"public class X {\n" + 
5884
			"  \n" + 
5885
			"  void foo() {\n" + 
5886
			"    Object a = null;\n" + 
5887
			"    while (true) {\n" + 
5888
			"      a = null;\n" + 
5889
			"      if (a == null) {\n" + 
5890
			"        System.out.println();\n" + 
5891
			"      }\n" + 
5892
			"      a = new Object();\n" + 
5893
			"      break;\n" + 
5894
			"    }\n" + 
5895
			"  }\n" + 
5896
			"}\n"},
5897
		"----------\n" + 
5898
		"1. ERROR in X.java (at line 7)\n" + 
5899
		"	if (a == null) {\n" + 
5900
		"	    ^\n" + 
5901
		"The variable a can only be null; it was either set to null or checked for null when last used\n" + 
5902
		"----------\n");
5903
}
5904
5905
// TODO (philippe) reenable once fixed
5906
public void _test1031() {
5907
	this.runNegativeTest(
5908
		new String[] {
5909
			"X.java",
5910
			"public class X {\n" + 
5911
			"  \n" + 
5912
			"  void foo() {\n" + 
5913
			"    Object a = null;\n" + 
5914
			"    while (true) {\n" + 
5915
			"      a = null;\n" + 
5916
			"      if (a == null) {\n" + 
5917
			"        System.out.println();\n" + 
5918
			"      }\n" + 
5919
			"      a = new Object();\n" + 
5920
			"      break;\n" + 
5921
			"    }\n" + 
5922
			"    if (a == null) {\n" + 
5923
			"      System.out.println();\n" + 
5924
			"    }\n" + 
5925
			"  }\n" + 
5926
			"}\n"},
5927
		"----------\n" + 
5928
		"1. ERROR in X.java (at line 7)\n" + 
5929
		"	if (a == null) {\n" + 
5930
		"	    ^\n" + 
5931
		"The variable a can only be null; it was either set to null or checked for null when last used\n" + 
5932
		"----------\n" + 
5933
		"2. ERROR in X.java (at line 13)\n" + 
5934
		"	if (a == null) {\n" + 
5935
		"	    ^\n" + 
5936
		"The variable a cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
5937
		"----------\n");
5938
}
5939
5940
public void test1032() {
5941
	this.runNegativeTest(
5942
		new String[] {
5943
			"X.java",
5944
			"public class X {\n" + 
5945
			"  void foo() {\n" + 
5946
			"    Object o1 = this;\n" + 
5947
			"    Object o3;\n" + 
5948
			"    while (o1 != null && (o3 = o1) != null) {\n" + 
5949
			"      o1 = o3;\n" + 
5950
			"    }\n" + 
5951
			"  }\n" + 
5952
			"}\n"},
5953
		"----------\n" + 
5954
		"1. ERROR in X.java (at line 5)\n" + 
5955
		"	while (o1 != null && (o3 = o1) != null) {\n" + 
5956
		"	       ^^\n" + 
5957
		"The variable o1 cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
5958
		"----------\n" + 
5959
		"2. ERROR in X.java (at line 5)\n" + 
5960
		"	while (o1 != null && (o3 = o1) != null) {\n" + 
5961
		"	                     ^^^^^^^^^\n" + 
5962
		"The variable o3 cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
5963
		"----------\n");
5964
}
5965
5966
// (simplified to focus on nulls)
5967
public void test1033() {
5968
	this.runNegativeTest(
5969
		new String[] {
5970
			"X.java",
5971
			"public class X {\n" + 
5972
			"  \n" + 
5973
			"  void foo() {\n" + 
5974
			"    String a,b;\n" + 
5975
			"    do{\n" + 
5976
			"      a=\"Hello \";\n" + 
5977
			"    }while(a!=null);\n" + 
5978
			"    if(a!=null)\n" + 
5979
			"      { /* */ }\n" + 
5980
			"  }\n" + 
5981
			"}\n"},
5982
		"----------\n" + 
5983
		"1. ERROR in X.java (at line 7)\n" + 
5984
		"	}while(a!=null);\n" + 
5985
		"	       ^\n" + 
5986
		"The variable a cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
5987
		"----------\n" + 
5988
		"2. ERROR in X.java (at line 8)\n" + 
5989
		"	if(a!=null)\n" + 
5990
		"	   ^\n" + 
5991
		"The variable a can only be null; it was either set to null or checked for null when last used\n" + 
5992
		"----------\n");
5993
}
5994
5995
// from AssignmentTest#test034, simplified
5996
public void test1034() {
5997
	this.runConformTest(
5998
		new String[] {
5999
			"X.java",
6000
			"public final class X \n" + 
6001
			"{\n" + 
6002
			"	void foo()\n" + 
6003
			"	{\n" + 
6004
			"		String rs = null;\n" + 
6005
			"		try\n" + 
6006
			"		{\n" + 
6007
			"			rs = \"\";\n" + 
6008
			"			return;\n" + 
6009
			"		}\n" + 
6010
			"		catch (Exception e)\n" + 
6011
			"		{\n" + 
6012
			"		}\n" + 
6013
			"		finally\n" + 
6014
			"		{\n" + 
6015
			"			if (rs != null)\n" + 
6016
			"			{\n" + 
6017
			"				try\n" + 
6018
			"				{\n" + 
6019
			"					rs.toString();\n" + 
6020
			"				}\n" + 
6021
			"				catch (Exception e)\n" + 
6022
			"				{\n" + 
6023
			"				}\n" + 
6024
			"			}\n" + 
6025
			"		}\n" + 
6026
			"		return;\n" + 
6027
			"	}\n" + 
6028
			"}\n",
6029
		},
6030
		"");
6031
}
6032
6033
public void test1036() {
6034
	this.runNegativeTest(
6035
		new String[] {
6036
			"X.java",
6037
			"public class X {\n" + 
6038
			"\n" + 
6039
			"  void foo() {\n" + 
6040
			"    Object o = new Object();\n" + 
6041
			"    do {\n" + 
6042
			"      o = null;\n" + 
6043
			"    } while (o != null);\n" + 
6044
			"    if (o == null) {\n" + 
6045
			"      // throw new Exception();\n" + 
6046
			"    }\n" + 
6047
			"  }\n" + 
6048
			"}\n"},
6049
		"----------\n" + 
6050
		"1. ERROR in X.java (at line 7)\n" + 
6051
		"	} while (o != null);\n" + 
6052
		"	         ^\n" + 
6053
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
6054
		"----------\n" + 
6055
		"2. ERROR in X.java (at line 8)\n" + 
6056
		"	if (o == null) {\n" + 
6057
		"	    ^\n" + 
6058
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
6059
		"----------\n");
6060
}
6061
6062
// flow info low-level validation
6063
public void test2000_flow_info() {
6064
	this.runNegativeTest(
6065
		new String[] {
6066
			"X.java",
6067
			"public class X {\n" + 
6068
			"\n" + 
6069
			"  void foo() {\n" + 
6070
			"    Object o0 = new Object(), o1 = o0, o2 = o0, o3 = o0, o4 = o0,\n" + 
6071
			"      o5 = o0, o6 = o0, o7 = o0, o8 = o0, o9 = o0,\n" + 
6072
			"      o10 = o0, o11 = o0, o12 = o0, o13 = o0, o14 = o0,\n" + 
6073
			"      o15 = o0, o16 = o0, o17 = o0, o18 = o0, o19 = o0,\n" + 
6074
			"      o20 = o0, o21 = o0, o22 = o0, o23 = o0, o24 = o0,\n" + 
6075
			"      o25 = o0, o26 = o0, o27 = o0, o28 = o0, o29 = o0,\n" + 
6076
			"      o30 = o0, o31 = o0, o32 = o0, o33 = o0, o34 = o0,\n" + 
6077
			"      o35 = o0, o36 = o0, o37 = o0, o38 = o0, o39 = o0,\n" + 
6078
			"      o40 = o0, o41 = o0, o42 = o0, o43 = o0, o44 = o0,\n" + 
6079
			"      o45 = o0, o46 = o0, o47 = o0, o48 = o0, o49 = o0,\n" + 
6080
			"      o50 = o0, o51 = o0, o52 = o0, o53 = o0, o54 = o0,\n" + 
6081
			"      o55 = o0, o56 = o0, o57 = o0, o58 = o0, o59 = o0,\n" + 
6082
			"      o60 = o0, o61 = o0, o62 = o0, o63 = o0, o64 = o0,\n" + 
6083
			"      o65 = o0, o66 = o0, o67 = o0, o68 = o0, o69 = o0;\n" + 
6084
			"    if (o65 == null) { /* */ }\n" + // complain 
6085
			"    if (o65 != null) { /* */ }\n" + // quiet (already reported)
6086
			"  }\n" + 
6087
			"}\n"},
6088
		"----------\n" + 
6089
		"1. ERROR in X.java (at line 18)\n" + 
6090
		"	if (o65 == null) { /* */ }\n" + 
6091
		"	    ^^^\n" + 
6092
		"The variable o65 cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
6093
		"----------\n");
6094
}
6095
6096
public void test2001_flow_info() {
6097
	this.runConformTest(
6098
		new String[] {
6099
			"X.java",
6100
			"public class X {\n" + 
6101
			"\n" + 
6102
			"  void foo(\n" + 
6103
			"    Object o0, Object o1, Object o2, Object o3, Object o4,\n" + 
6104
			"      Object o5, Object o6, Object o7, Object o8, Object o9,\n" + 
6105
			"      Object o10, Object o11, Object o12, Object o13, Object o14,\n" + 
6106
			"      Object o15, Object o16, Object o17, Object o18, Object o19,\n" + 
6107
			"      Object o20, Object o21, Object o22, Object o23, Object o24,\n" + 
6108
			"      Object o25, Object o26, Object o27, Object o28, Object o29,\n" + 
6109
			"      Object o30, Object o31, Object o32, Object o33, Object o34,\n" + 
6110
			"      Object o35, Object o36, Object o37, Object o38, Object o39,\n" + 
6111
			"      Object o40, Object o41, Object o42, Object o43, Object o44,\n" + 
6112
			"      Object o45, Object o46, Object o47, Object o48, Object o49,\n" + 
6113
			"      Object o50, Object o51, Object o52, Object o53, Object o54,\n" + 
6114
			"      Object o55, Object o56, Object o57, Object o58, Object o59,\n" + 
6115
			"      Object o60, Object o61, Object o62, Object o63, Object o64,\n" + 
6116
			"      Object o65, Object o66, Object o67, Object o68, Object o69) {\n" + 
6117
			"    if (o65 == null) { /* */ }\n" + 
6118
			"    if (o65 != null) { /* */ }\n" + 
6119
			"  }\n" + 
6120
			"}\n"},
6121
		"");
6122
}
6123
6124
public void test2002_flow_info() {
6125
	this.runConformTest(
6126
		new String[] {
6127
			"X.java",
6128
			"public class X {\n" + 
6129
			"  Object m0, m1, m2, m3, m4,\n" + 
6130
			"    m5, m6, m7, m8, m9,\n" + 
6131
			"    m10, m11, m12, m13, m14,\n" + 
6132
			"    m15, m16, m17, m18, m19,\n" + 
6133
			"    m20, m21, m22, m23, m24,\n" + 
6134
			"    m25, m26, m27, m28, m29,\n" + 
6135
			"    m30, m31, m32, m33, m34,\n" + 
6136
			"    m35, m36, m37, m38, m39,\n" + 
6137
			"    m40, m41, m42, m43, m44,\n" + 
6138
			"    m45, m46, m47, m48, m49,\n" + 
6139
			"    m50, m51, m52, m53, m54,\n" + 
6140
			"    m55, m56, m57, m58, m59,\n" + 
6141
			"    m60, m61, m62, m63;\n" + 
6142
			"  void foo(Object o) {\n" + 
6143
			"    if (o == null) { /* */ }\n" + 
6144
			"    if (o != null) { /* */ }\n" + 
6145
			"  }\n" + 
6146
			"}\n"},
6147
		"");
6148
}
6149
6150
public void test2003_flow_info() {
6151
	this.runConformTest(
6152
		new String[] {
6153
			"X.java",
6154
			"public class X {\n" + 
6155
			"  Object m0, m1, m2, m3, m4,\n" + 
6156
			"    m5, m6, m7, m8, m9,\n" + 
6157
			"    m10, m11, m12, m13, m14,\n" + 
6158
			"    m15, m16, m17, m18, m19,\n" + 
6159
			"    m20, m21, m22, m23, m24,\n" + 
6160
			"    m25, m26, m27, m28, m29,\n" + 
6161
			"    m30, m31, m32, m33, m34,\n" + 
6162
			"    m35, m36, m37, m38, m39,\n" + 
6163
			"    m40, m41, m42, m43, m44,\n" + 
6164
			"    m45, m46, m47, m48, m49,\n" + 
6165
			"    m50, m51, m52, m53, m54,\n" + 
6166
			"    m55, m56, m57, m58, m59,\n" + 
6167
			"    m60, m61, m62, m63;\n" + 
6168
			"  void foo(Object o) {\n" + 
6169
			"    o.toString();\n" + 
6170
			"  }\n" + 
6171
			"}\n"},
6172
		"");
6173
}
6174
6175
public void test2004_flow_info() {
6176
	this.runNegativeTest(
6177
		new String[] {
6178
			"X.java",
6179
			"public class X {\n" + 
6180
			"  Object m0, m1, m2, m3, m4,\n" + 
6181
			"    m5, m6, m7, m8, m9,\n" + 
6182
			"    m10, m11, m12, m13, m14,\n" + 
6183
			"    m15, m16, m17, m18, m19,\n" + 
6184
			"    m20, m21, m22, m23, m24,\n" + 
6185
			"    m25, m26, m27, m28, m29,\n" + 
6186
			"    m30, m31, m32, m33, m34,\n" + 
6187
			"    m35, m36, m37, m38, m39,\n" + 
6188
			"    m40, m41, m42, m43, m44,\n" + 
6189
			"    m45, m46, m47, m48, m49,\n" + 
6190
			"    m50, m51, m52, m53, m54,\n" + 
6191
			"    m55, m56, m57, m58, m59,\n" + 
6192
			"    m60, m61, m62, m63;\n" + 
6193
			"  void foo() {\n" + 
6194
			"    Object o;\n" + 
6195
			"    if (o == null) { /* */ }\n" + 
6196
			"  }\n" + 
6197
			"}\n"},
6198
		"----------\n" + 
6199
		"1. ERROR in X.java (at line 17)\n" + 
6200
		"	if (o == null) { /* */ }\n" + 
6201
		"	    ^\n" + 
6202
		"The local variable o may not have been initialized\n" + 
6203
		"----------\n");
6204
}
6205
6206
public void test2005_flow_info() {
6207
	this.runConformTest(
6208
		new String[] {
6209
			"X.java",
6210
			"public class X {\n" + 
6211
			"  Object m0, m1, m2, m3, m4,\n" + 
6212
			"    m5, m6, m7, m8, m9,\n" + 
6213
			"    m10, m11, m12, m13, m14,\n" + 
6214
			"    m15, m16, m17, m18, m19,\n" + 
6215
			"    m20, m21, m22, m23, m24,\n" + 
6216
			"    m25, m26, m27, m28, m29,\n" + 
6217
			"    m30, m31, m32, m33, m34,\n" + 
6218
			"    m35, m36, m37, m38, m39,\n" + 
6219
			"    m40, m41, m42, m43, m44,\n" + 
6220
			"    m45, m46, m47, m48, m49,\n" + 
6221
			"    m50, m51, m52, m53, m54,\n" + 
6222
			"    m55, m56, m57, m58, m59,\n" + 
6223
			"    m60, m61, m62, m63;\n" + 
6224
			"  void foo(Object o) {\n" + 
6225
			"    o = null;\n" + 
6226
			"  }\n" + 
6227
			"}\n"},
6228
		"");
6229
}
6230
6231
public void test2006_flow_info() {
6232
	this.runConformTest(
6233
		new String[] {
6234
			"X.java",
6235
			"public class X {\n" + 
6236
			"  Object m0, m1, m2, m3, m4,\n" + 
6237
			"    m5, m6, m7, m8, m9,\n" + 
6238
			"    m10, m11, m12, m13, m14,\n" + 
6239
			"    m15, m16, m17, m18, m19,\n" + 
6240
			"    m20, m21, m22, m23, m24,\n" + 
6241
			"    m25, m26, m27, m28, m29,\n" + 
6242
			"    m30, m31, m32, m33, m34,\n" + 
6243
			"    m35, m36, m37, m38, m39,\n" + 
6244
			"    m40, m41, m42, m43, m44,\n" + 
6245
			"    m45, m46, m47, m48, m49,\n" + 
6246
			"    m50, m51, m52, m53, m54,\n" + 
6247
			"    m55, m56, m57, m58, m59,\n" + 
6248
			"    m60, m61, m62, m63;\n" + 
6249
			"  void foo() {\n" + 
6250
			"    Object o = null;\n" + 
6251
			"  }\n" + 
6252
			"}\n"},
6253
		"");
6254
}
6255
6256
public void test2007_flow_info() {
6257
	this.runConformTest(
6258
		new String[] {
6259
			"X.java",
6260
			"public class X {\n" + 
6261
			"  Object m0, m1, m2, m3, m4,\n" + 
6262
			"    m5, m6, m7, m8, m9,\n" + 
6263
			"    m10, m11, m12, m13, m14,\n" + 
6264
			"    m15, m16, m17, m18, m19,\n" + 
6265
			"    m20, m21, m22, m23, m24,\n" + 
6266
			"    m25, m26, m27, m28, m29,\n" + 
6267
			"    m30, m31, m32, m33, m34,\n" + 
6268
			"    m35, m36, m37, m38, m39,\n" + 
6269
			"    m40, m41, m42, m43, m44,\n" + 
6270
			"    m45, m46, m47, m48, m49,\n" + 
6271
			"    m50, m51, m52, m53, m54,\n" + 
6272
			"    m55, m56, m57, m58, m59,\n" + 
6273
			"    m60, m61, m62, m63;\n" + 
6274
			"  void foo() {\n" + 
6275
			"    Object o[] = null;\n" + 
6276
			"  }\n" + 
6277
			"}\n"},
6278
		"");
6279
}
6280
6281
// null analysis -- flow info
6282
public void test2008_flow_info() {
6283
	this.runConformTest(
6284
		new String[] {
6285
			"X.java",
6286
			"public class X {\n" + 
6287
			"  Object m0, m1, m2, m3, m4,\n" + 
6288
			"    m5, m6, m7, m8, m9,\n" + 
6289
			"    m10, m11, m12, m13, m14,\n" + 
6290
			"    m15, m16, m17, m18, m19,\n" + 
6291
			"    m20, m21, m22, m23, m24,\n" + 
6292
			"    m25, m26, m27, m28, m29,\n" + 
6293
			"    m30, m31, m32, m33, m34,\n" + 
6294
			"    m35, m36, m37, m38, m39,\n" + 
6295
			"    m40, m41, m42, m43, m44,\n" + 
6296
			"    m45, m46, m47, m48, m49,\n" + 
6297
			"    m50, m51, m52, m53, m54,\n" + 
6298
			"    m55, m56, m57, m58, m59,\n" + 
6299
			"    m60, m61, m62, m63;\n" + 
6300
			"  void foo(boolean b) {\n" + 
6301
			"    Object o = null;\n" + 
6302
			"    while (o == null) {\n" + 
6303
			     // quiet: first iteration is sure to find o null, 
6304
			     // but other iterations may change it 
6305
			"      try { /* */ }\n" + 
6306
			"      finally {\n" + 
6307
			"        if (b) {\n" +
6308
			"          o = new Object();\n" +
6309
			"        }\n" + 
6310
			"      }\n" + 
6311
			"    }\n" + 
6312
			"  }\n" + 
6313
			"}\n"},
6314
		"");
6315
}
6316
6317
// null analysis -- flow info
6318
public void test2009_flow_info() {
6319
	this.runNegativeTest(
6320
		new String[] {
6321
			"X.java",
6322
			"public class X {\n" + 
6323
			"  Object m0, m1, m2, m3, m4,\n" + 
6324
			"    m5, m6, m7, m8, m9,\n" + 
6325
			"    m10, m11, m12, m13, m14,\n" + 
6326
			"    m15, m16, m17, m18, m19,\n" + 
6327
			"    m20, m21, m22, m23, m24,\n" + 
6328
			"    m25, m26, m27, m28, m29,\n" + 
6329
			"    m30, m31, m32, m33, m34,\n" + 
6330
			"    m35, m36, m37, m38, m39,\n" + 
6331
			"    m40, m41, m42, m43, m44,\n" + 
6332
			"    m45, m46, m47, m48, m49,\n" + 
6333
			"    m50, m51, m52, m53, m54,\n" + 
6334
			"    m55, m56, m57, m58, m59,\n" + 
6335
			"    m60, m61, m62, m63;\n" + 
6336
			"  void foo(Object o) {\n" + 
6337
			"    try { /* */ }\n" + 
6338
			"    finally {\n" + 
6339
			"      o = new Object();\n" +
6340
			"    }\n" + 
6341
			"    if (o == null) { /* */ }\n" + 
6342
			"  }\n" + 
6343
			"}\n"},
6344
		"----------\n" + 
6345
		"1. ERROR in X.java (at line 20)\n" + 
6346
		"	if (o == null) { /* */ }\n" + 
6347
		"	    ^\n" + 
6348
		"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
6349
		"----------\n");
6350
}
6351
6352
// null analysis -- flow info
6353
public void test2010_flow_info() {
6354
	this.runNegativeTest(
6355
		new String[] {
6356
			"X.java",
6357
			"public class X {\n" + 
6358
			"  Object m00, m01, m02, m03, m04,\n" + 
6359
			"    m05, m06, m07, m08, m09,\n" + 
6360
			"    m10, m11, m12, m13, m14,\n" + 
6361
			"    m15, m16, m17, m18, m19,\n" + 
6362
			"    m20, m21, m22, m23, m24,\n" + 
6363
			"    m25, m26, m27, m28, m29,\n" + 
6364
			"    m30, m31, m32, m33, m34,\n" + 
6365
			"    m35, m36, m37, m38, m39,\n" + 
6366
			"    m40, m41, m42, m43, m44,\n" + 
6367
			"    m45, m46, m47, m48, m49,\n" + 
6368
			"    m50, m51, m52, m53, m54,\n" + 
6369
			"    m55, m56, m57, m58, m59,\n" + 
6370
			"    m60, m61, m62, m63;\n" + 
6371
			"  void foo() {\n" + 
6372
			"    Object o;\n" + 
6373
			"    try { /* */ }\n" + 
6374
			"    finally {\n" + 
6375
			"      o = new Object();\n" +
6376
			"    }\n" + 
6377
			"    if (o == null) { /* */ }\n" + 
6378
			"  }\n" + 
6379
			"}\n"},
6380
		"----------\n" + 
6381
		"1. ERROR in X.java (at line 21)\n" + 
6382
		"	if (o == null) { /* */ }\n" + 
6383
		"	    ^\n" + 
6384
		"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
6385
		"----------\n");
6386
}
6387
6388
// null analysis -- flow info
6389
public void test2011_flow_info() {
6390
	this.runNegativeTest(
6391
		new String[] {
6392
			"X.java",
6393
			"public class X {\n" + 
6394
			"  Object m000, m001, m002, m003, m004, m005, m006, m007, m008, m009,\n" + 
6395
			"    m010, m011, m012, m013, m014, m015, m016, m017, m018, m019,\n" + 
6396
			"    m020, m021, m022, m023, m024, m025, m026, m027, m028, m029,\n" + 
6397
			"    m030, m031, m032, m033, m034, m035, m036, m037, m038, m039,\n" + 
6398
			"    m040, m041, m042, m043, m044, m045, m046, m047, m048, m049,\n" + 
6399
			"    m050, m051, m052, m053, m054, m055, m056, m057, m058, m059,\n" + 
6400
			"    m060, m061, m062, m063;\n" + 
6401
			"  void foo() {\n" + 
6402
			"    Object o000, o001, o002, o003, o004, o005, o006, o007, o008, o009,\n" + 
6403
			"      o010, o011, o012, o013, o014, o015, o016, o017, o018, o019,\n" + 
6404
			"      o020, o021, o022, o023, o024, o025, o026, o027, o028, o029,\n" + 
6405
			"      o030, o031, o032, o033, o034, o035, o036, o037, o038, o039,\n" + 
6406
			"      o040, o041, o042, o043, o044, o045, o046, o047, o048, o049,\n" + 
6407
			"      o050, o051, o052, o053, o054, o055, o056, o057, o058, o059,\n" + 
6408
			"      o060, o061, o062, o063;\n" + 
6409
			"    Object o;\n" + 
6410
			"    try {\n" +
6411
			"      o000 = new Object();\n" +
6412
			"    }\n" + 
6413
			"    finally {\n" + 
6414
			"      o = new Object();\n" +
6415
			"    }\n" + 
6416
			"    if (o == null) { /* */ }\n" + 
6417
			"  }\n" + 
6418
			"}\n"},
6419
		"----------\n" + 
6420
		"1. ERROR in X.java (at line 24)\n" + 
6421
		"	if (o == null) { /* */ }\n" + 
6422
		"	    ^\n" + 
6423
		"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
6424
		"----------\n");
6425
}
6426
6427
// null analysis -- flow info
6428
public void test2012_flow_info() {
6429
	this.runNegativeTest(
6430
		new String[] {
6431
			"X.java",
6432
			"public class X {\n" + 
6433
			"  Object m000, m001, m002, m003, m004, m005, m006, m007, m008, m009,\n" + 
6434
			"    m010, m011, m012, m013, m014, m015, m016, m017, m018, m019,\n" + 
6435
			"    m020, m021, m022, m023, m024, m025, m026, m027, m028, m029,\n" + 
6436
			"    m030, m031, m032, m033, m034, m035, m036, m037, m038, m039,\n" + 
6437
			"    m040, m041, m042, m043, m044, m045, m046, m047, m048, m049,\n" + 
6438
			"    m050, m051, m052, m053, m054, m055, m056, m057, m058, m059,\n" + 
6439
			"    m060, m061, m062, m063;\n" + 
6440
			"  void foo() {\n" + 
6441
			"    Object o000, o001, o002, o003, o004, o005, o006, o007, o008, o009,\n" + 
6442
			"      o010, o011, o012, o013, o014, o015, o016, o017, o018, o019,\n" + 
6443
			"      o020, o021, o022, o023, o024, o025, o026, o027, o028, o029,\n" + 
6444
			"      o030, o031, o032, o033, o034, o035, o036, o037, o038, o039,\n" + 
6445
			"      o040, o041, o042, o043, o044, o045, o046, o047, o048, o049,\n" + 
6446
			"      o050, o051, o052, o053, o054, o055, o056, o057, o058, o059,\n" + 
6447
			"      o060, o061, o062, o063;\n" + 
6448
			"    Object o;\n" + 
6449
			"    try {\n" +
6450
			"      o = new Object();\n" +
6451
			"    }\n" + 
6452
			"    finally {\n" + 
6453
			"      o000 = new Object();\n" +
6454
			"    }\n" + 
6455
			"    if (o == null) { /* */ }\n" + 
6456
			"  }\n" + 
6457
			"}\n"},
6458
		"----------\n" + 
6459
		"1. ERROR in X.java (at line 24)\n" + 
6460
		"	if (o == null) { /* */ }\n" + 
6461
		"	    ^\n" + 
6462
		"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
6463
		"----------\n");
6464
}
6465
6466
// null analysis -- flow info
6467
public void test2013_flow_info() {
6468
	this.runNegativeTest(
6469
		new String[] {
6470
			"X.java",
6471
			"public class X {\n" + 
6472
			"  boolean dummy;\n" + 
6473
			"  Object m000, m001, m002, m003, m004, m005, m006, m007, m008, m009,\n" + 
6474
			"    m010, m011, m012, m013, m014, m015, m016, m017, m018, m019,\n" + 
6475
			"    m020, m021, m022, m023, m024, m025, m026, m027, m028, m029,\n" + 
6476
			"    m030, m031, m032, m033, m034, m035, m036, m037, m038, m039,\n" + 
6477
			"    m040, m041, m042, m043, m044, m045, m046, m047, m048, m049,\n" + 
6478
			"    m050, m051, m052, m053, m054, m055, m056, m057, m058, m059,\n" + 
6479
			"    m060, m061, m062, m063;\n" + 
6480
			"  void foo(Object u) {\n" + 
6481
			"    Object o = null;\n" + 
6482
			"    while (dummy) {\n" + 
6483
			"      o = u;\n" + 
6484
			"    }\n" + 
6485
			"    o.toString();\n" + 
6486
			"  }\n" + 
6487
			"}\n"},
6488
		"----------\n" + 
6489
		"1. ERROR in X.java (at line 15)\n" + 
6490
		"	o.toString();\n" + 
6491
		"	^\n" + 
6492
		"The variable o may be null\n" + 
6493
		"----------\n");
6494
}
6495
6496
// null analysis -- flow info
6497
public void test2014_flow_info() {
6498
	this.runNegativeTest(
6499
		new String[] {
6500
			"X.java",
6501
			"class X {\n" + 
6502
			"  int m000, m001, m002, m003, m004, m005, m006, m007, m008, m009,\n" + 
6503
			"    m010, m011, m012, m013, m014, m015, m016, m017, m018, m019,\n" + 
6504
			"    m020, m021, m022, m023, m024, m025, m026, m027, m028, m029,\n" + 
6505
			"    m030, m031, m032, m033, m034, m035, m036, m037, m038, m039,\n" + 
6506
			"    m040, m041, m042, m043, m044, m045, m046, m047, m048, m049,\n" + 
6507
			"    m050, m051, m052, m053, m054, m055, m056, m057, m058, m059,\n" + 
6508
			"    m060, m061, m062, m063;\n" +
6509
			"  final int m064;\n" + 
6510
			"  X() {\n" + 
6511
			"    m064 = 10;\n" +
6512
			"    class Inner extends X {\n" + 
6513
			"      int m100, m101, m102, m103, m104, m105, m106, m107, m108, m109,\n" + 
6514
			"        m110, m111, m112, m113, m114, m115, m116, m117, m118, m119,\n" + 
6515
			"        m120, m121, m122, m123, m124, m125, m126, m127, m128, m129,\n" + 
6516
			"        m130, m131, m132, m133, m134, m135, m136, m137, m138, m139,\n" + 
6517
			"        m140, m141, m142, m143, m144, m145, m146, m147, m148, m149,\n" + 
6518
			"        m150, m151, m152, m153, m154, m155, m156, m157, m158, m159,\n" + 
6519
			"        m160, m161, m162, m163;\n" +
6520
			"      final int m164;\n" + 
6521
			"      int bar() {\n" + 
6522
			"        return m100 + m101 + m102 + m103 + m104 +\n" + 
6523
			"               m105 + m106 + m107 + m108 + m109 +\n" + 
6524
			"               m110 + m111 + m112 + m113 + m114 +\n" + 
6525
			"               m115 + m116 + m117 + m118 + m119 +\n" + 
6526
			"               m120 + m121 + m122 + m123 + m124 +\n" + 
6527
			"               m125 + m126 + m127 + m128 + m129 +\n" + 
6528
			"               m130 + m131 + m132 + m133 + m134 +\n" + 
6529
			"               m135 + m136 + m137 + m138 + m139 +\n" + 
6530
			"               m140 + m141 + m142 + m143 + m144 +\n" + 
6531
			"               m145 + m146 + m147 + m148 + m149 +\n" + 
6532
			"               m150 + m151 + m152 + m153 + m154 +\n" + 
6533
			"               m155 + m156 + m157 + m158 + m159 +\n" + 
6534
			"               m160 + m161 + m162 + m163 + m164;\n" +
6535
			"      }\n" + 
6536
			"    };\n" + 
6537
			"    System.out.println((new Inner()).bar());\n" +
6538
			"  }\n" + 
6539
			"}\n"},
6540
		"----------\n" + 
6541
		"1. ERROR in X.java (at line 12)\n" + 
6542
		"	class Inner extends X {\n" + 
6543
		"	      ^^^^^\n" + 
6544
		"The blank final field m164 may not have been initialized\n" + 
6545
		"----------\n");
6546
}
6547
6548
// null analysis -- flow info
6549
public void test2015_flow_info() {
6550
	this.runNegativeTest(
6551
		new String[] {
6552
			"X.java",
6553
			"class X {\n" + 
6554
			"  int m000, m001, m002, m003, m004, m005, m006, m007, m008, m009,\n" + 
6555
			"    m010, m011, m012, m013, m014, m015, m016, m017, m018, m019,\n" + 
6556
			"    m020, m021, m022, m023, m024, m025, m026, m027, m028, m029,\n" + 
6557
			"    m030, m031, m032, m033, m034, m035, m036, m037, m038, m039,\n" + 
6558
			"    m040, m041, m042, m043, m044, m045, m046, m047, m048, m049,\n" + 
6559
			"    m050, m051, m052, m053, m054, m055, m056, m057, m058, m059,\n" + 
6560
			"    m060, m061, m062, m063;\n" +
6561
			"  final int m200;\n" + 
6562
			"  int m201, m202, m203, m204, m205, m206, m207, m208, m209,\n" + 
6563
			"    m210, m211, m212, m213, m214, m215, m216, m217, m218, m219,\n" + 
6564
			"    m220, m221, m222, m223, m224, m225, m226, m227, m228, m229,\n" + 
6565
			"    m230, m231, m232, m233, m234, m235, m236, m237, m238, m239,\n" + 
6566
			"    m240, m241, m242, m243, m244, m245, m246, m247, m248, m249,\n" + 
6567
			"    m250, m251, m252, m253, m254, m255, m256, m257, m258, m259,\n" + 
6568
			"    m260, m261, m262, m263;\n" +
6569
			"  int m301, m302, m303, m304, m305, m306, m307, m308, m309,\n" + 
6570
			"    m310, m311, m312, m313, m314, m315, m316, m317, m318, m319,\n" + 
6571
			"    m320, m321, m322, m323, m324, m325, m326, m327, m328, m329,\n" + 
6572
			"    m330, m331, m332, m333, m334, m335, m336, m337, m338, m339,\n" + 
6573
			"    m340, m341, m342, m343, m344, m345, m346, m347, m348, m349,\n" + 
6574
			"    m350, m351, m352, m353, m354, m355, m356, m357, m358, m359,\n" + 
6575
			"    m360, m361, m362, m363;\n" +
6576
			"  X() {\n" + 
6577
			"    m200 = 10;\n" +
6578
			"    class Inner extends X {\n" + 
6579
			"      int m100, m101, m102, m103, m104, m105, m106, m107, m108, m109,\n" + 
6580
			"        m110, m111, m112, m113, m114, m115, m116, m117, m118, m119,\n" + 
6581
			"        m120, m121, m122, m123, m124, m125, m126, m127, m128, m129,\n" + 
6582
			"        m130, m131, m132, m133, m134, m135, m136, m137, m138, m139,\n" + 
6583
			"        m140, m141, m142, m143, m144, m145, m146, m147, m148, m149,\n" + 
6584
			"        m150, m151, m152, m153, m154, m155, m156, m157, m158, m159,\n" + 
6585
			"        m160, m161, m162, m163;\n" +
6586
			"      final int m164;\n" + 
6587
			"      int bar() {\n" + 
6588
			"        return m100 + m101 + m102 + m103 + m104 +\n" + 
6589
			"               m105 + m106 + m107 + m108 + m109 +\n" + 
6590
			"               m110 + m111 + m112 + m113 + m114 +\n" + 
6591
			"               m115 + m116 + m117 + m118 + m119 +\n" + 
6592
			"               m120 + m121 + m122 + m123 + m124 +\n" + 
6593
			"               m125 + m126 + m127 + m128 + m129 +\n" + 
6594
			"               m130 + m131 + m132 + m133 + m134 +\n" + 
6595
			"               m135 + m136 + m137 + m138 + m139 +\n" + 
6596
			"               m140 + m141 + m142 + m143 + m144 +\n" + 
6597
			"               m145 + m146 + m147 + m148 + m149 +\n" + 
6598
			"               m150 + m151 + m152 + m153 + m154 +\n" + 
6599
			"               m155 + m156 + m157 + m158 + m159 +\n" + 
6600
			"               m160 + m161 + m162 + m163 + m164;\n" +
6601
			"      }\n" + 
6602
			"    };\n" + 
6603
			"    System.out.println((new Inner()).bar());\n" +
6604
			"  }\n" + 
6605
			"}\n"},
6606
		"----------\n" + 
6607
		"1. ERROR in X.java (at line 26)\n" + 
6608
		"	class Inner extends X {\n" + 
6609
		"	      ^^^^^\n" + 
6610
		"The blank final field m164 may not have been initialized\n" + 
6611
		"----------\n");
6612
}
6613
6614
// null analysis -- flow info
6615
public void test2016_flow_info() {
6616
	this.runNegativeTest(
6617
		new String[] {
6618
			"X.java",
6619
			"class X {\n" + 
6620
			"  int m000, m001, m002, m003, m004, m005, m006, m007, m008, m009,\n" + 
6621
			"    m010, m011, m012, m013, m014, m015, m016, m017, m018, m019,\n" + 
6622
			"    m020, m021, m022, m023, m024, m025, m026, m027, m028, m029,\n" + 
6623
			"    m030, m031, m032, m033, m034, m035, m036, m037, m038, m039,\n" + 
6624
			"    m040, m041, m042, m043, m044, m045, m046, m047, m048, m049,\n" + 
6625
			"    m050, m051, m052, m053, m054, m055, m056, m057, m058, m059,\n" + 
6626
			"    m060, m061;\n" +
6627
			"  final int m062;\n" + 
6628
			"  {\n" +
6629
			"    int l063, m201 = 0, m202, m203, m204, m205, m206, m207, m208, m209,\n" + 
6630
			"      m210, m211, m212, m213, m214, m215, m216, m217, m218, m219,\n" + 
6631
			"      m220, m221, m222, m223, m224, m225, m226, m227, m228, m229,\n" + 
6632
			"      m230, m231, m232, m233, m234, m235, m236, m237, m238, m239,\n" + 
6633
			"      m240, m241, m242, m243, m244, m245, m246, m247, m248, m249,\n" + 
6634
			"      m250, m251, m252, m253, m254, m255, m256, m257, m258, m259,\n" + 
6635
			"      m260, m261, m262, m263;\n" +
6636
			"    int m301, m302, m303, m304, m305, m306, m307, m308, m309,\n" + 
6637
			"      m310, m311, m312, m313, m314, m315, m316, m317, m318, m319,\n" + 
6638
			"      m320, m321, m322, m323, m324, m325, m326, m327, m328, m329,\n" + 
6639
			"      m330, m331, m332, m333, m334, m335, m336, m337, m338, m339,\n" + 
6640
			"      m340, m341, m342, m343, m344, m345, m346, m347, m348, m349,\n" + 
6641
			"      m350, m351, m352, m353, m354, m355, m356, m357, m358, m359,\n" + 
6642
			"      m360 = 0, m361 = 0, m362 = 0, m363 = 0;\n" +
6643
			"    m062 = m360;\n" +
6644
			"  }\n" +
6645
			"  X() {\n" + 
6646
			"    int l0, l1;\n" +
6647
			"    m000 = l1;\n" +
6648
			"    class Inner extends X {\n" + 
6649
			"      int bar() {\n" + 
6650
			"        return 0;\n" + 
6651
			"      }\n" + 
6652
			"    };\n" + 
6653
			"    System.out.println((new Inner()).bar());\n" +
6654
			"  }\n" + 
6655
			"}\n"},
6656
		"----------\n" + 
6657
		"1. ERROR in X.java (at line 29)\n" + 
6658
		"	m000 = l1;\n" + 
6659
		"	       ^^\n" + 
6660
		"The local variable l1 may not have been initialized\n" + 
6661
		"----------\n");
6662
}
943
6663
944
	// null analysis - if/else
6664
public void test2017_flow_info() {
945
	public void test0107_if_else() {
6665
	this.runConformTest(
946
		this.runNegativeTest(
6666
		new String[] {
947
			new String[] {
6667
			"X.java",
948
				"X.java",
6668
			"public class X {\n" + 
949
				"public class X {\n" + 
6669
			"  boolean dummy;\n" + 
950
				"	 void foo(Object o) {\n" + 
6670
			"  Object m000, m001, m002, m003, m004, m005, m006, m007, m008, m009,\n" + 
951
				"		 if (o ==  null) {\n" + 
6671
			"    m010, m011, m012, m013, m014, m015, m016, m017, m018, m019,\n" + 
952
				"			 System.exit(0);\n" + 
6672
			"    m020, m021, m022, m023, m024, m025, m026, m027, m028, m029,\n" + 
953
				"		 }\n" + 
6673
			"    m030, m031, m032, m033, m034, m035, m036, m037, m038, m039,\n" + 
954
				"		 if (o == null) {\n" + 
6674
			"    m040, m041, m042, m043, m044, m045, m046, m047, m048, m049,\n" + 
955
				  // quiet 
6675
			"    m050, m051, m052, m053, m054, m055, m056, m057, m058, m059,\n" + 
956
				  // a direct call to System.exit() can be recognized as such; yet,
6676
			"    m060, m061, m062, m063;\n" + 
957
				  // a lot of other methods may have the same property (aka calling
6677
			"  void foo(Object u) {\n" + 
958
				  // System.exit() themselves.)
6678
			"    Object o = null;\n" + 
959
				"		   // do nothing\n" + 
6679
			"    while (dummy) {\n" + 
960
				"		 }\n" + 
6680
			"      if (dummy) {\n" + // uncorrelated
961
				"	 }\n" + 
6681
			"        o = u;\n" +
962
				"}\n"},
6682
			"        continue;\n" +
963
			""
6683
			"      }\n" + 
964
		);
6684
			"    }\n" + 
965
	}		
6685
			"    if (o != null) { /* */ }\n" + 
966
6686
			"  }\n" + 
967
	// null analysis -- while
6687
			"}\n"},
968
	// TODO (maxime) fix
6688
		"");
969
	public void _test0111_while() {
6689
}
970
		this.runNegativeTest(
971
			new String[] {
972
				"X.java",
973
				"public class X {\n" + 
974
				"	 void foo() {\n" + 
975
				"		 Object o = null;\n" + 
976
				"		 while (o.toString() != null) {/* */}\n" +
977
				      // complain: NPE
978
				"	 }\n" + 
979
				"}\n"},
980
			"----------\n" + 
981
			"1. WARNING in X.java (at line 4)\n" + 
982
			"	while (o.toString() != null) {/* */}\n" + 
983
			"	       ^\n" + 
984
			"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
985
			"----------\n"  
986
		);
987
	}
988
/* TODO (maxime)
989
 	Object o = new Object();
990
 	while (b) {
991
 		o.toString(); // should signal NPE risk
992
 		if (b2) o = null;
993
 	}
994
 */
995
	
996
/* TODO (maxime)
997
 	Object o = new Object();
998
	if (b2) o = null;
999
	o.toString(); // should barf
1000
 */
1001
	// null analysis -- while
1002
	// TODO (maxime) fix
1003
	public void _test0112_while() {
1004
		this.runNegativeTest(
1005
			new String[] {
1006
				"X.java",
1007
				"public class X {\n" + 
1008
				"	 void foo() {\n" + 
1009
				"		 Object o = null;\n" + 
1010
				"		 while (o != null) {/* */}\n" + 
1011
				  // complain: get o null first time and forever
1012
				"	 }\n" + 
1013
				"}\n"},
1014
			"----------\n" + 
1015
			"1. WARNING in X.java (at line 4)\n" + 
1016
			"	while (o != null) {/* */}\n" + 
1017
			"	       ^\n" + 
1018
			"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
1019
			"----------\n"
1020
		);
1021
	}
1022
6690
1023
	// null analysis -- while
6691
public void test2018_flow_info() {
1024
	public void test0113_while() {
6692
	this.runNegativeTest(
1025
		this.runNegativeTest(
6693
		new String[] {
1026
			new String[] {
6694
			"X.java",
1027
				"X.java",
6695
			"public class X {\n" + 
1028
				"public class X {\n" + 
6696
			"  boolean dummy;\n" + 
1029
				"	 void foo() {\n" + 
6697
			"  Object m000, m001, m002, m003, m004, m005, m006, m007, m008, m009,\n" + 
1030
				"		 Object o = null;\n" + 
6698
			"    m010, m011, m012, m013, m014, m015, m016, m017, m018, m019,\n" + 
1031
				"		 while (o == null) {\n" + 
6699
			"    m020, m021, m022, m023, m024, m025, m026, m027, m028, m029,\n" + 
1032
				      // quiet: first iteration is sure to find o null, 
6700
			"    m030, m031, m032, m033, m034, m035, m036, m037, m038, m039,\n" + 
1033
				      // but other iterations may change it 
6701
			"    m040, m041, m042, m043, m044, m045, m046, m047, m048, m049,\n" + 
1034
				"		   o = new Object();\n" + 
6702
			"    m050, m051, m052, m053, m054, m055, m056, m057, m058, m059,\n" + 
1035
				"		 }\n" + 
6703
			"    m060, m061, m062, m063;\n" + 
1036
				"	 }\n" + 
6704
			"  void foo() {\n" +
1037
				"}\n"},
6705
			"    Object o;\n" + 
1038
			""  
6706
			"    while (dummy) {\n" + 
1039
		);
6707
			"      if (dummy) {\n" + // uncorrelated
1040
	}
6708
			"        o = null;\n" +
6709
			"        continue;\n" +
6710
			"      }\n" + 
6711
			"    }\n" +
6712
			"    o.toString();\n" + 
6713
			"  }\n" + 
6714
			"}\n"},
6715
		"----------\n" + 
6716
		"1. ERROR in X.java (at line 18)\n" + 
6717
		"	o.toString();\n" + 
6718
		"	^\n" + 
6719
		"The local variable o may not have been initialized\n" + 
6720
		"----------\n" + 
6721
		"2. ERROR in X.java (at line 18)\n" + 
6722
		"	o.toString();\n" + 
6723
		"	^\n" + 
6724
		"The variable o may be null\n" + 
6725
		"----------\n");
6726
}
1041
6727
1042
	// null analysis -- while
6728
public void test2019_flow_info() {
1043
	public void test0114_while() {
6729
	this.runNegativeTest(
1044
		this.runNegativeTest(
6730
		new String[] {
1045
			new String[] {
6731
			"X.java",
1046
				"X.java",
6732
			"public class X {\n" + 
1047
				"public class X {\n" + 
6733
			"  boolean dummy;\n" + 
1048
				"	 void foo() {\n" + 
6734
			"  Object m000, m001, m002, m003, m004, m005, m006, m007, m008, m009,\n" + 
1049
				"		 Object o = null;\n" + 
6735
			"    m010, m011, m012, m013, m014, m015, m016, m017, m018, m019,\n" + 
1050
				"		 while (o == null) {\n" + 
6736
			"    m020, m021, m022, m023, m024, m025, m026, m027, m028, m029,\n" + 
1051
				     // quiet: first iteration is sure to find o null, 
6737
			"    m030, m031, m032, m033, m034, m035, m036, m037, m038, m039,\n" + 
1052
				     // but other iterations may change it 
6738
			"    m040, m041, m042, m043, m044, m045, m046, m047, m048, m049,\n" + 
1053
				"		   if (System.currentTimeMillis() > 10L) {\n" + 
6739
			"    m050, m051, m052, m053, m054, m055, m056, m057, m058, m059,\n" + 
1054
				"		     o = new Object();\n" + 
6740
			"    m060, m061, m062, m063;\n" + 
1055
				"		   }\n" + 
6741
			"  void foo() {\n" +
1056
				"		 }\n" + 
6742
			"    Object o;\n" + 
1057
				"	 }\n" + 
6743
			"    while (dummy) {\n" + 
1058
				"}\n"},
6744
			"      if (dummy) {\n" + // uncorrelated
1059
			""  
6745
			"        continue;\n" +
1060
		);
6746
			"      }\n" + 
1061
	}
6747
			"      o = null;\n" +
6748
			"    }\n" +
6749
			"    o.toString();\n" + 
6750
			"  }\n" + 
6751
			"}\n"},
6752
		"----------\n" + 
6753
		"1. ERROR in X.java (at line 18)\n" + 
6754
		"	o.toString();\n" + 
6755
		"	^\n" + 
6756
		"The local variable o may not have been initialized\n" + 
6757
		"----------\n" + 
6758
		"2. ERROR in X.java (at line 18)\n" + 
6759
		"	o.toString();\n" + 
6760
		"	^\n" + 
6761
		"The variable o may be null\n" + 
6762
		"----------\n");
6763
}
1062
6764
1063
	// null analysis -- while
6765
public void test2020_flow_info() {
1064
	// TODO (maxime) fix
6766
	this.runNegativeTest(
1065
	public void _test0115_while() {
6767
		new String[] {
1066
		this.runNegativeTest(
6768
			"X.java",
1067
			new String[] {
6769
			"public class X {\n" + 
1068
				"X.java",
6770
			"  boolean dummy;\n" + 
1069
				"public class X {\n" + 
6771
			"  Object m000, m001, m002, m003, m004, m005, m006, m007, m008, m009,\n" + 
1070
				"	 boolean bar() {\n" + 
6772
			"    m010, m011, m012, m013, m014, m015, m016, m017, m018, m019,\n" + 
1071
				"		 return true;\n" + 
6773
			"    m020, m021, m022, m023, m024, m025, m026, m027, m028, m029,\n" + 
1072
				"	 }\n" + 
6774
			"    m030, m031, m032, m033, m034, m035, m036, m037, m038, m039,\n" + 
1073
				"	 void foo(Object o) {\n" + 
6775
			"    m040, m041, m042, m043, m044, m045, m046, m047, m048, m049,\n" + 
1074
				"		 while (bar() && o == null) {\n" + 
6776
			"    m050, m051, m052, m053, m054, m055, m056, m057, m058, m059,\n" + 
1075
				"		   o.toString();\n" + // complain: NPE
6777
			"    m060, m061, m062, m063;\n" + 
1076
				"		   o = new Object();\n" +
6778
			"  int m200, m201, m202, m203, m204, m205, m206, m207, m208, m209,\n" + 
1077
				"		 }\n" + 
6779
			"    m210, m211, m212, m213, m214, m215, m216, m217, m218, m219,\n" + 
1078
				"	 }\n" + 
6780
			"    m220, m221, m222, m223, m224, m225, m226, m227, m228, m229,\n" + 
1079
				"}\n"},
6781
			"    m230, m231, m232, m233, m234, m235, m236, m237, m238, m239,\n" + 
1080
			"----------\n" + 
6782
			"    m240, m241, m242, m243, m244, m245, m246, m247, m248, m249,\n" + 
1081
			"1. WARNING in X.java (at line 7)\n" + 
6783
			"    m250, m251, m252, m253, m254, m255, m256, m257, m258, m259,\n" + 
1082
			"	o.toString();\n" + 
6784
			"    m260, m261;\n" +
1083
			"	^\n" + 
6785
			"  void foo() {\n" +
1084
			"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
6786
			"    Object o0, o1;\n" + 
1085
			"----------\n"
6787
			"    while (dummy) {\n" +
1086
		);
6788
			"      o0 = new Object();\n" + 
1087
	}
6789
			"      if (dummy) {\n" + // uncorrelated
6790
			"        o1 = null;\n" +
6791
			"        continue;\n" +
6792
			"      }\n" + 
6793
			"    }\n" +
6794
			"    o1.toString();\n" + 
6795
			"  }\n" + 
6796
			"}\n"},
6797
		"----------\n" + 
6798
		"1. ERROR in X.java (at line 26)\n" + 
6799
		"	o1.toString();\n" + 
6800
		"	^^\n" + 
6801
		"The local variable o1 may not have been initialized\n" + 
6802
		"----------\n" + 
6803
		"2. ERROR in X.java (at line 26)\n" + 
6804
		"	o1.toString();\n" + 
6805
		"	^^\n" + 
6806
		"The variable o1 may be null\n" + 
6807
		"----------\n");
6808
}
1088
6809
1089
	// null analysis -- while
6810
// Technical tests -- only available with patched sources
1090
	// TODO (maxime) fix
6811
static final boolean 
1091
	public void _test0116_while() {
6812
	printTablesAsNames = false, 
1092
		this.runNegativeTest(
6813
	printTablesAsCodes = false, 
1093
			new String[] {
6814
	printTruthMaps = false;
1094
				"X.java",
6815
static final int
1095
				"public class X {\n" + 
6816
	combinationTestsloopsNb = 1; // define to 10000s to measure performances
1096
				"	 boolean dummy;\n" + 
6817
1097
				"	 void foo(Object o) {\n" + 
6818
1098
				"	   o = null;\n" +
6819
public void test2050_markAsComparedEqualToNonNull() {
1099
				"		 while (dummy || o != null) { /* */ }\n" + // o can only be null 
6820
	long [][][] testData = {
1100
				"	 }\n" + 
6821
		{{0,0,0,0},{1,1,0,0}},
1101
				"}\n"},
6822
		{{0,0,0,1},{1,1,0,1}},
1102
			"----------\n" + 
6823
		{{0,0,1,0},{1,1,0,0}},
1103
			"1. WARNING in X.java (at line 5)\n" + 
6824
		{{0,0,1,1},{1,1,0,1}},
1104
			"	while (dummy || o != null) {\n" + 
6825
		{{0,1,0,0},{1,1,0,0}},
1105
			"	                    ^\n" + 
6826
		{{0,1,0,1},{1,1,0,1}},
1106
			"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
6827
		{{0,1,1,0},{1,1,0,0}},
1107
			"----------\n"
6828
		{{0,1,1,1},{1,1,0,1}},
1108
		);
6829
		{{1,0,0,0},{1,1,0,0}},
6830
		{{1,0,0,1},{1,0,0,1}},
6831
		{{1,0,1,0},{1,1,0,0}},
6832
		{{1,0,1,1},{1,1,0,1}},
6833
		{{1,1,0,0},{1,1,0,0}},
6834
		{{1,1,0,1},{1,1,0,1}},
6835
		{{1,1,1,0},{1,1,0,0}},
6836
		{{1,1,1,1},{1,1,0,1}},
6837
	};
6838
	int failures = 0;
6839
	LocalVariableBinding local = new TestLocalVariableBinding(0);
6840
	for (int i = 0; i < testData.length; i++) {
6841
		UnconditionalFlowInfoTestHarness 
6842
			result = UnconditionalFlowInfoTestHarness.
6843
				testUnconditionalFlowInfo(testData[i][0]);
6844
		result.markAsComparedEqualToNonNull(local);
6845
		if (!(result.testEquals(UnconditionalFlowInfoTestHarness.
6846
				testUnconditionalFlowInfo(testData[i][1])))) {
6847
			if (failures == 0) {
6848
				System.out.println("markAsComparedEqualToNonNull failures: ");
6849
			}
6850
			failures++;
6851
			System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
6852
				',' + result.testString() + 
6853
				"}, // instead of: " + testStringValueOf(testData[i][1]));
6854
		}
1109
	}
6855
	}
1110
6856
	local = new TestLocalVariableBinding(64);
1111
	// null analysis -- while
6857
	for (int i = 0; i < testData.length; i++) {
1112
	// TODO (maxime) fix
6858
		UnconditionalFlowInfoTestHarness 
1113
	public void _test0117_while() {
6859
			result = UnconditionalFlowInfoTestHarness.
1114
		this.runNegativeTest(
6860
				testUnconditionalFlowInfo(testData[i][0], 64),
1115
			new String[] {
6861
			expected = UnconditionalFlowInfoTestHarness.
1116
				"X.java",
6862
				testUnconditionalFlowInfo(testData[i][1], 64);
1117
				"public class X {\n" + 
6863
		result.markAsComparedEqualToNonNull(local);
1118
				"	 boolean dummy;\n" + 
6864
		if (!(result.testEquals(expected))) {
1119
				"	 void foo() {\n" + 
6865
			if (failures == 0) {
1120
				"		 Object o = null;\n" + 
6866
				System.out.println("markAsComparedEqualToNonNull failures: ");
1121
				"		 while (dummy) {\n" +
6867
			}
1122
				"		   o.toString();\n" +  // complain: NPE on first iteration
6868
			failures++;
1123
				"		   o = new Object();\n" +
6869
			System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
1124
				"		 }\n" +
6870
				',' + result.testString() + 
1125
				"	 }\n" + 
6871
				"}, //  (64) instead of: " + testStringValueOf(testData[i][1]));
1126
				"}\n"},
6872
		}
1127
			"----------\n" + 
6873
		if (testData[i][0][0] == 0 &&
1128
			"1. WARNING in X.java (at line 6)\n" + 
6874
				testData[i][0][1] == 0 &&
1129
			"	o.toString();\n" + 
6875
				testData[i][0][2] == 0 &&				
1130
			"	^\n" + 
6876
				testData[i][0][3] == 0) {
1131
			"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
6877
			result = UnconditionalFlowInfoTestHarness.
1132
			"----------\n"  
6878
				testUnconditionalFlowInfo(testData[i][1]);
1133
		);
6879
			result.markAsComparedEqualToNonNull(local);
6880
			if (!result.testEquals(expected, 64)) {
6881
				if (failures == 0) {
6882
					System.out.println("markAsComparedEqualToNonNull failures: ");
6883
				}
6884
				failures++;
6885
				System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
6886
						',' + result.testString() + 
6887
						"}, //  (zero 64) instead of: " + testStringValueOf(testData[i][1]));
6888
			}
6889
		}
1134
	}
6890
	}
1135
6891
	local = new TestLocalVariableBinding(128);
1136
	// TODO (maxime) should nuance error message: The variable o may be null...
6892
	for (int i = 0; i < testData.length; i++) {
1137
	
6893
		if (testData[i][0][0] == 0 &&
1138
	// null analysis -- while
6894
				testData[i][0][1] == 0 &&
1139
	// this test shows that, as long as we do not explore all possible
6895
				testData[i][0][2] == 0 &&				
1140
	// paths, we have to take potential initializations into account
6896
				testData[i][0][3] == 0) {
1141
	// even in branches that could be pruned in the first passes
6897
			UnconditionalFlowInfoTestHarness 
1142
	// first approximation is to stop pruning code conditioned by
6898
				result = UnconditionalFlowInfoTestHarness.
1143
	// variables
6899
					testUnconditionalFlowInfo(testData[i][1], 64),
1144
	// second approximation could still rely upon variables that are
6900
				expected = UnconditionalFlowInfoTestHarness.
1145
	// never affected by the looping code (unassigned variables)
6901
					testUnconditionalFlowInfo(testData[i][1], 128);
1146
	// complete solution would call for multiple iterations in the
6902
			result.markAsComparedEqualToNonNull(local);
1147
	// null analysis
6903
			if (!result.testEquals(expected, 128)) {
1148
	// TODO (maxime) fix
6904
				if (failures == 0) {
1149
	public void _test0118_while() {
6905
					System.out.println("markAsComparedEqualToNonNull failures: ");
1150
		this.runNegativeTest(
6906
				}
1151
			new String[] {
6907
				failures++;
1152
				"X.java",
6908
				System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
1153
				"public class X {\n" + 
6909
						',' + result.testString() + 
1154
				"	 void foo() {\n" + 
6910
						"}, //  (zero 128) instead of: " + testStringValueOf(testData[i][1]));
1155
				"		 Object o = null,\n" + 
6911
			}
1156
				"		        u = new Object(),\n" + 
6912
		}
1157
				"		        v = new Object();\n" + 
1158
				"		 while (o == null) {\n" +
1159
				"		   if (v == null) {\n" +
1160
				"		     o = new Object();\n" +
1161
				"		   };\n" +
1162
				"		   if (u == null) {\n" +
1163
				"		     v = null;\n" +
1164
				"		   };\n" +
1165
				"		   u = null;\n" +
1166
				"		 }\n" +
1167
				"	 }\n" + 
1168
				"}\n"},
1169
			""  
1170
		);
1171
	}
6913
	}
1172
6914
	if (printTablesAsNames) {
1173
	// null analysis -- while
6915
		System.out.println("RECAP TABLE FOR MARK COMPARED NON NULL");
1174
	public void test0119_while() {
6916
		for (int i = 0; i < testData.length; i++) {
1175
		this.runNegativeTest(
6917
			System.out.println(testSymbolicValueOf(testData[i][0]) + " -> " +
1176
			new String[] {
6918
				testSymbolicValueOf(testData[i][1]));
1177
				"X.java",
6919
		}	
1178
				"public class X {\n" + 
6920
	}
1179
				"	 boolean dummy;\n" + 
6921
	if (printTablesAsCodes) {
1180
				"	 void foo() {\n" + 
6922
		System.out.println("RECAP TABLE FOR MARK COMPARED NON NULL");
1181
				"		 Object o = null;\n" + 
6923
		for (int i = 0; i < testData.length; i++) {
1182
				"		 while (dummy || (o = new Object()).equals(o)) {\n" +
6924
			System.out.println(testCodedValueOf(testData[i][0]) + " " +
1183
				"		   o.toString();\n" +
6925
				testCodedValueOf(testData[i][1]));
1184
				"		 }\n" +
6926
		}
1185
				"	 }\n" + 
1186
				"}\n"},
1187
			""  
1188
		);
1189
	}
6927
	}
6928
	assertTrue("nb of failures: " + failures, failures == 0);
6929
}
1190
6930
1191
	// null analysis -- while
6931
public void test2051_markAsComparedEqualToNull() {
1192
	public void test0120_while_nested() {
6932
	long [][][] testData = {
1193
		this.runNegativeTest(
6933
		{{0,0,0,0},{0,1,0,0}},
1194
			new String[] {
6934
		{{0,0,0,1},{0,1,0,0}},
1195
				"X.java",
6935
		{{0,0,1,0},{0,1,1,0}},
1196
				"public class X {\n" + 
6936
		{{0,0,1,1},{0,1,1,0}},
1197
				"	 boolean dummy;\n" + 
6937
		{{0,1,0,0},{0,1,0,0}},
1198
				"	 void foo() {\n" + 
6938
		{{0,1,0,1},{0,1,0,0}},
1199
				"		 Object o = null;\n" + 
6939
		{{0,1,1,0},{0,1,1,0}},
1200
				"		 while (dummy) {\n" + 
6940
		{{0,1,1,1},{0,1,1,0}},
1201
				"		   while (o != null) {\n" + 
6941
		{{1,0,0,0},{0,1,0,0}},
1202
				"		     o.toString();\n" + 
6942
		{{1,0,0,1},{0,1,0,0}},
1203
				"		   }\n" + 
6943
		{{1,0,1,0},{1,0,1,0}},
1204
				"		   if (System.currentTimeMillis() > 10L) {\n" + 
6944
		{{1,0,1,1},{0,1,0,0}},
1205
				"		     o = new Object();\n" + 
6945
		{{1,1,0,0},{0,1,0,0}},
1206
				"		   }\n" + 
6946
		{{1,1,0,1},{0,1,0,0}},
1207
				"		 }\n" + 
6947
		{{1,1,1,0},{0,1,1,0}},
1208
				"	 }\n" + 
6948
		{{1,1,1,1},{0,1,1,0}},
1209
				"}\n"},
6949
	};
1210
			""  
6950
	int failures = 0;
1211
		);
6951
	LocalVariableBinding local = new TestLocalVariableBinding(0);
6952
	for (int i = 0; i < testData.length; i++) {
6953
		UnconditionalFlowInfoTestHarness 
6954
			result = UnconditionalFlowInfoTestHarness.
6955
				testUnconditionalFlowInfo(testData[i][0]);
6956
		result.markAsComparedEqualToNull(local);
6957
		if (!(result.testEquals(UnconditionalFlowInfoTestHarness.
6958
				testUnconditionalFlowInfo(testData[i][1])))) {
6959
			if (failures == 0) {
6960
				System.out.println("markAsComparedEqualToNull failures: ");
6961
			}
6962
			failures++;
6963
			System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
6964
				',' + result.testString() + 
6965
				"}, // instead of: " + testStringValueOf(testData[i][1]));
6966
		}
1212
	}
6967
	}
1213
6968
	local = new TestLocalVariableBinding(64);
1214
	// null analysis -- while
6969
	for (int i = 0; i < testData.length; i++) {
1215
	// TODO (maxime) fix
6970
		UnconditionalFlowInfoTestHarness 
1216
	public void _test0121_while_nested() {
6971
			result = UnconditionalFlowInfoTestHarness.
1217
		this.runNegativeTest(
6972
				testUnconditionalFlowInfo(testData[i][0], 64),
1218
			new String[] {
6973
			expected = UnconditionalFlowInfoTestHarness.
1219
				"X.java",
6974
				testUnconditionalFlowInfo(testData[i][1], 64);
1220
				"public class X {\n" + 
6975
		result.markAsComparedEqualToNull(local);
1221
				"	 void foo() {\n" + 
6976
		if (!(result.testEquals(expected))) {
1222
				"		 Object o = null,\n" + 
6977
			if (failures == 0) {
1223
				"		        u = new Object(),\n" + 
6978
				System.out.println("markAsComparedEqualToNull failures: ");
1224
				"		        v = new Object();\n" + 
6979
			}
1225
				"	   while (o == null) {\n" + 
6980
			failures++;
1226
				"		   if (v == null) {\n" +
6981
			System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
1227
				"		     o = new Object();\n" +
6982
				',' + result.testString() + 
1228
				"		   };\n" +
6983
				"}, // (64) instead of: " + testStringValueOf(testData[i][1]));
1229
				"		   while (o == null) {\n" +
6984
		}
1230
				"		     if (u == null) {\n" +
6985
		if (testData[i][0][0] == 0 &&
1231
				"		       v = null;\n" +
6986
				testData[i][0][1] == 0 &&
1232
				"		     };\n" +
6987
				testData[i][0][2] == 0 &&				
1233
				"  		   u = null;\n" +
6988
				testData[i][0][3] == 0) {
1234
				"		   }\n" +
6989
			result = UnconditionalFlowInfoTestHarness.
1235
				"		 }\n" +
6990
				testUnconditionalFlowInfo(testData[i][1]);
1236
				"	 }\n" + 
6991
			result.markAsComparedEqualToNull(local);
1237
				"}\n"},
6992
			if (!result.testEquals(expected, 64)) {
1238
			""  
6993
				if (failures == 0) {
1239
		);
6994
					System.out.println("markAsComparedEqualToNull failures: ");
6995
				}
6996
				failures++;
6997
				System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
6998
						',' + result.testString() + 
6999
						"}, //  (zero 64) instead of: " + testStringValueOf(testData[i][1]));
7000
			}
7001
		}		
7002
	}
7003
	local = new TestLocalVariableBinding(128);
7004
	for (int i = 0; i < testData.length; i++) {
7005
		if (testData[i][0][0] == 0 &&
7006
				testData[i][0][1] == 0 &&
7007
				testData[i][0][2] == 0 &&				
7008
				testData[i][0][3] == 0) {
7009
			UnconditionalFlowInfoTestHarness 
7010
				result = UnconditionalFlowInfoTestHarness.
7011
					testUnconditionalFlowInfo(testData[i][1], 64),
7012
				expected = UnconditionalFlowInfoTestHarness.
7013
					testUnconditionalFlowInfo(testData[i][1], 128);
7014
			result.markAsComparedEqualToNull(local);
7015
			if (!result.testEquals(expected, 128)) {
7016
				if (failures == 0) {
7017
					System.out.println("markAsComparedEqualToNull failures: ");
7018
				}
7019
				failures++;
7020
				System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
7021
						',' + result.testString() + 
7022
						"}, //  (zero 128) instead of: " + testStringValueOf(testData[i][1]));
7023
			}
7024
		}
7025
	}	
7026
	if (printTablesAsNames) {
7027
		System.out.println("RECAP TABLE FOR MARK COMPARED NULL");
7028
		for (int i = 0; i < testData.length; i++) {
7029
			System.out.println(testSymbolicValueOf(testData[i][0]) + " -> " +
7030
				testSymbolicValueOf(testData[i][1]));
7031
		}	
7032
	}
7033
	if (printTablesAsCodes) {
7034
		System.out.println("RECAP TABLE FOR MARK COMPARED NULL");
7035
		for (int i = 0; i < testData.length; i++) {
7036
			System.out.println(testCodedValueOf(testData[i][0]) + " " +
7037
				testCodedValueOf(testData[i][1]));
7038
		}
1240
	}
7039
	}
7040
	assertTrue("nb of failures: " + failures, failures == 0);
7041
}
1241
7042
1242
	// null analysis -- while
7043
public void test2052_markAsDefinitelyNonNull() {
1243
	public void test0122_while_if_nested() {
7044
	long [][][] testData = {
1244
		this.runNegativeTest(
7045
		{{0,0,0,0},{1,0,0,1}},
1245
			new String[] {
7046
		{{0,0,0,1},{1,0,0,1}},
1246
				"X.java",
7047
		{{0,0,1,0},{1,0,0,1}},
1247
				"public class X {\n" + 
7048
		{{0,0,1,1},{1,0,0,1}},
1248
				"	 boolean dummy, other;\n" + 
7049
		{{0,1,0,0},{1,0,0,1}},
1249
				"	 void foo() {\n" + 
7050
		{{0,1,0,1},{1,0,0,1}},
1250
				"		 Object o = null;\n" + 
7051
		{{0,1,1,0},{1,0,0,1}},
1251
				"		 while (dummy) {\n" +   
7052
		{{0,1,1,1},{1,0,0,1}},
1252
				"		   if (other) {\n" + 
7053
		{{1,0,0,0},{1,0,0,1}},
1253
				"		     o.toString();\n" +    
7054
		{{1,0,0,1},{1,0,0,1}},
1254
				"		   }\n" + 
7055
		{{1,0,1,0},{1,0,0,1}},
1255
				"		   o = new Object();\n" + 
7056
		{{1,0,1,1},{1,0,0,1}},
1256
				"		 }\n" + 
7057
		{{1,1,0,0},{1,0,0,1}},
1257
				"	 }\n" + 
7058
		{{1,1,0,1},{1,0,0,1}},
1258
				"}\n"},
7059
		{{1,1,1,0},{1,0,0,1}},
1259
			""  
7060
		{{1,1,1,1},{1,0,0,1}},
1260
		);
7061
	};
7062
	int failures = 0;
7063
	LocalVariableBinding local = new TestLocalVariableBinding(0);
7064
	for (int i = 0; i < testData.length; i++) {
7065
		UnconditionalFlowInfoTestHarness 
7066
			result = UnconditionalFlowInfoTestHarness.
7067
				testUnconditionalFlowInfo(testData[i][0]);
7068
		result.markAsDefinitelyNonNull(local);
7069
		if (!(result.testEquals(UnconditionalFlowInfoTestHarness.
7070
				testUnconditionalFlowInfo(testData[i][1])))) {
7071
			if (failures == 0) {
7072
				System.out.println("markAsDefinitelyNonNull failures: ");
7073
			}
7074
			failures++;
7075
			System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
7076
				',' + result.testString() + 
7077
				"}, // instead of: " + testStringValueOf(testData[i][1]));
7078
		}
1261
	}
7079
	}
1262
7080
	local = new TestLocalVariableBinding(64);
1263
	// null analysis -- while
7081
	for (int i = 0; i < testData.length; i++) {
1264
	public void test0123_while_unknown_field() {
7082
		UnconditionalFlowInfoTestHarness 
1265
		this.runNegativeTest(
7083
			result = UnconditionalFlowInfoTestHarness.
1266
			new String[] {
7084
				testUnconditionalFlowInfo(testData[i][0], 64);
1267
				"X.java",
7085
		result.markAsDefinitelyNonNull(local);
1268
				"public class X {\n" + 
7086
		if (!(result.testEquals(UnconditionalFlowInfoTestHarness.
1269
				"	 Object o;\n" + 
7087
				testUnconditionalFlowInfo(testData[i][1], 64)))) {
1270
				"	 void foo(boolean dummy) {\n" + 
7088
			if (failures == 0) {
1271
				"		 while (dummy) {\n" +
7089
				System.out.println("markAsDefinitelyNonNull failures: ");
1272
				"		   o = null;\n" +
7090
			}
1273
				"		 }\n" +
7091
			failures++;
1274
				"		 o.toString();\n" +
7092
			System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
1275
				"	 }\n" + 
7093
				',' + result.testString() + 
1276
				"}\n"},
7094
				"}, // (64) instead of: " + testStringValueOf(testData[i][1]));
1277
			""  
7095
		}
1278
		);
1279
	}
7096
	}
1280
7097
	if (printTablesAsNames) {
1281
	// null analysis -- while
7098
		System.out.println("RECAP TABLE FOR MARK DEFINITELY NON NULL");
1282
	public void test0124_while_unknown_parameter() {
7099
		for (int i = 0; i < testData.length; i++) {
1283
		this.runNegativeTest(
7100
			System.out.println(testSymbolicValueOf(testData[i][0]) + " -> " +
1284
			new String[] {
7101
				testSymbolicValueOf(testData[i][1]));
1285
				"X.java",
7102
		}	
1286
				"public class X {\n" + 
7103
	}
1287
				"	 boolean dummy;\n" + 
7104
	if (printTablesAsCodes) {
1288
				"	 void foo(Object o) {\n" + 
7105
		System.out.println("RECAP TABLE FOR MARK DEFINITELY NON NULL");
1289
				"		 while (dummy) {\n" +
7106
		for (int i = 0; i < testData.length; i++) {
1290
				"		   o = null;\n" +
7107
			System.out.println(testCodedValueOf(testData[i][0]) + " " +
1291
				"		 }\n" +
7108
				testCodedValueOf(testData[i][1]));
1292
				"		 o.toString();\n" +
7109
		}
1293
				"	 }\n" + 
1294
				"}\n"},
1295
			""  
1296
		);
1297
	}
7110
	}
7111
	assertTrue("nb of failures: " + failures, failures == 0);
7112
}
1298
7113
1299
	// null analysis -- while
7114
public void test2053_markAsDefinitelyNull() {
1300
	public void test0125_while_unknown_if_else() {
7115
	long [][][] testData = {
1301
		this.runNegativeTest(
7116
		{{0,0,0,0},{1,0,1,0}},
1302
			new String[] {
7117
		{{0,0,0,1},{1,0,1,0}},
1303
				"X.java",
7118
		{{0,0,1,0},{1,0,1,0}},
1304
				"public class X {\n" + 
7119
		{{0,0,1,1},{1,0,1,0}},
1305
				"	 boolean dummy;\n" + 
7120
		{{0,1,0,0},{1,0,1,0}},
1306
				"	 void foo() {\n" + 
7121
		{{0,1,0,1},{1,0,1,0}},
1307
				"		 Object o = null;\n" +
7122
		{{0,1,1,0},{1,0,1,0}},
1308
				"		 if (dummy) {\n" +
7123
		{{0,1,1,1},{1,0,1,0}},
1309
				"		   o = new Object();\n" +
7124
		{{1,0,0,0},{1,0,1,0}},
1310
				"		 }\n" +
7125
		{{1,0,0,1},{1,0,1,0}},
1311
				"		 while (dummy) {\n" + 
7126
		{{1,0,1,0},{1,0,1,0}},
1312
					// limit of the analysis: we do not correlate if and while conditions
7127
		{{1,0,1,1},{1,0,1,0}},
1313
				"		   if (o == null) {/* */}\n" + 
7128
		{{1,1,0,0},{1,0,1,0}},
1314
				"		 }\n" +
7129
		{{1,1,0,1},{1,0,1,0}},
1315
				"	 }\n" + 
7130
		{{1,1,1,0},{1,0,1,0}},
1316
				"}\n"},
7131
		{{1,1,1,1},{1,0,1,0}},
1317
			""  
7132
	};
1318
		);
7133
	int failures = 0;
7134
	LocalVariableBinding local = new TestLocalVariableBinding(0);
7135
	for (int i = 0; i < testData.length; i++) {
7136
		UnconditionalFlowInfoTestHarness 
7137
			result = UnconditionalFlowInfoTestHarness.
7138
				testUnconditionalFlowInfo(testData[i][0]);
7139
		result.markAsDefinitelyNull(local);
7140
		if (!(result.testEquals(UnconditionalFlowInfoTestHarness.
7141
				testUnconditionalFlowInfo(testData[i][1])))) {
7142
			if (failures == 0) {
7143
				System.out.println("markAsDefinitelyNull failures: ");
7144
			}
7145
			failures++;
7146
			System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
7147
				',' + result.testString() + 
7148
				"}, // instead of: " + testStringValueOf(testData[i][1]));
7149
		}
7150
	}
7151
	local = new TestLocalVariableBinding(64);
7152
	for (int i = 0; i < testData.length; i++) {
7153
		UnconditionalFlowInfoTestHarness 
7154
			result = UnconditionalFlowInfoTestHarness.
7155
				testUnconditionalFlowInfo(testData[i][0], 64);
7156
		result.markAsDefinitelyNull(local);
7157
		if (!(result.testEquals(UnconditionalFlowInfoTestHarness.
7158
				testUnconditionalFlowInfo(testData[i][1], 64)))) {
7159
			if (failures == 0) {
7160
				System.out.println("markAsDefinitelyNull failures: ");
7161
			}
7162
			failures++;
7163
			System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
7164
				',' + result.testString() + 
7165
				"}, // (64) instead of: " + testStringValueOf(testData[i][1]));
7166
		}
7167
	}
7168
	if (printTablesAsNames) {
7169
		System.out.println("RECAP TABLE FOR MARK DEFINITELY NULL");
7170
		for (int i = 0; i < testData.length; i++) {
7171
			System.out.println(testSymbolicValueOf(testData[i][0]) + " -> " +
7172
				testSymbolicValueOf(testData[i][1]));
7173
		}	
7174
	}
7175
	if (printTablesAsCodes) {
7176
		System.out.println("RECAP TABLE FOR MARK DEFINITELY NULL");
7177
		for (int i = 0; i < testData.length; i++) {
7178
			System.out.println(testCodedValueOf(testData[i][0]) + " " +
7179
				testCodedValueOf(testData[i][1]));
7180
		}
1319
	}
7181
	}
7182
	assertTrue("nb of failures: " + failures, failures == 0);
7183
}
1320
7184
1321
	// null analysis -- while
7185
public void test2054_markAsDefinitelyUnknown() {
1322
	public void test0126_while() {
7186
	long [][][] testData = {
1323
		this.runNegativeTest(
7187
		{{0,0,0,0},{1,0,1,1}},
1324
			new String[] {
7188
		{{0,0,0,1},{1,0,1,1}},
1325
				"X.java",
7189
		{{0,0,1,0},{1,0,1,1}},
1326
				"public class X {\n" + 
7190
		{{0,0,1,1},{1,0,1,1}},
1327
				"	 boolean dummy;\n" + 
7191
		{{0,1,0,0},{1,0,1,1}},
1328
				"	 void foo() {\n" + 
7192
		{{0,1,0,1},{1,0,1,1}},
1329
				"		 Object o = null;\n" + 
7193
		{{0,1,1,0},{1,0,1,1}},
1330
				"		 while (dummy) {\n" + 
7194
		{{0,1,1,1},{1,0,1,1}},
1331
				"		   o = new Object();\n" + 
7195
		{{1,0,0,0},{1,0,1,1}},
1332
				"		 }\n" + 
7196
		{{1,0,0,1},{1,0,1,1}},
1333
				"		 o.toString();\n" + 
7197
		{{1,0,1,0},{1,0,1,1}},
1334
				"	 }\n" + 
7198
		{{1,0,1,1},{1,0,1,1}},
1335
				"}\n"},
7199
		{{1,1,0,0},{1,0,1,1}},
1336
			""  
7200
		{{1,1,0,1},{1,0,1,1}},
1337
		);
7201
		{{1,1,1,0},{1,0,1,1}},
7202
		{{1,1,1,1},{1,0,1,1}},
7203
	};
7204
	int failures = 0;
7205
	LocalVariableBinding local = new TestLocalVariableBinding(0);
7206
	for (int i = 0; i < testData.length; i++) {
7207
		UnconditionalFlowInfoTestHarness 
7208
			result = UnconditionalFlowInfoTestHarness.
7209
				testUnconditionalFlowInfo(testData[i][0]);
7210
		result.markAsDefinitelyUnknown(local);
7211
		if (!(result.testEquals(UnconditionalFlowInfoTestHarness.
7212
				testUnconditionalFlowInfo(testData[i][1])))) {
7213
			if (failures == 0) {
7214
				System.out.println("markAsDefinitelyUnknown failures: ");
7215
			}
7216
			failures++;
7217
			System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
7218
				',' + result.testString() + 
7219
				"}, // instead of: " + testStringValueOf(testData[i][1]));
7220
		}
1338
	}
7221
	}
1339
	
7222
	local = new TestLocalVariableBinding(64);
1340
	// null analysis -- while
7223
	for (int i = 0; i < testData.length; i++) {
1341
	// TODO (maxime) fix
7224
		UnconditionalFlowInfoTestHarness 
1342
	public void _test0127_while() {
7225
			result = UnconditionalFlowInfoTestHarness.
1343
		this.runNegativeTest(
7226
				testUnconditionalFlowInfo(testData[i][0], 64);
1344
			new String[] {
7227
		result.markAsDefinitelyUnknown(local);
1345
				"X.java",
7228
		if (!(result.testEquals(UnconditionalFlowInfoTestHarness.
1346
				"public class X {\n" + 
7229
				testUnconditionalFlowInfo(testData[i][1], 64)))) {
1347
				"	 boolean dummy;\n" + 
7230
			if (failures == 0) {
1348
				"	 void foo() {\n" + 
7231
				System.out.println("markAsDefinitelyUnknown failures: ");
1349
				"		 Object o = null;\n" + 
7232
			}
1350
				"		 while (dummy) { /* */ }\n" + // doesn't affect o
7233
			failures++;
1351
				"		 o.toString();\n" + 
7234
			System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
1352
				"	 }\n" + 
7235
				',' + result.testString() + 
1353
				"}\n"},
7236
				"}, // (64) instead of: " + testStringValueOf(testData[i][1]));
1354
			"----------\n" + 
7237
		}
1355
			"1. WARNING in X.java (at line 6)\n" + 
1356
			"	o.toString();\n" + 
1357
			"	^\n" + 
1358
			"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
1359
			"----------\n" 
1360
		);
1361
	}
7238
	}
1362
	
7239
	if (printTablesAsNames) {
1363
	// null analysis -- while
7240
		System.out.println("RECAP TABLE FOR MARK DEFINITELY UNKNOWN");
1364
	// origin AssignmentTest.testO22
7241
		for (int i = 0; i < testData.length; i++) {
1365
	public void test0128_while_try() {
7242
			System.out.println(testSymbolicValueOf(testData[i][0]) + " -> " +
1366
		this.runNegativeTest(
7243
				testSymbolicValueOf(testData[i][1]));
1367
			new String[] {
7244
		}	
1368
				"X.java",
7245
	}
1369
				"public class X {\n" + 
7246
	if (printTablesAsCodes) {
1370
				"	 boolean bool() { return true; }\n" + 
7247
		System.out.println("RECAP TABLE FOR MARK DEFINITELY UNKNOWN");
1371
				"	 void foo() {\n" + 
7248
		for (int i = 0; i < testData.length; i++) {
1372
				"		 Object o = null;\n" + 
7249
			System.out.println(testCodedValueOf(testData[i][0]) + " " +
1373
				"		 while (bool()) {\n" + 
7250
				testCodedValueOf(testData[i][1]));
1374
				"			 try {\n" + 
7251
		}
1375
				"				 if (o == null) {\n" + 
1376
				"					 o = new Object();\n" + 
1377
				"				 }\n" + 
1378
				"			 } finally { /* */ }\n" + 
1379
				"		 }\n" + 
1380
				"	 }\n" + 
1381
				"}",
1382
			},
1383
		"");
1384
	}
7252
	}
7253
	assertTrue("nb of failures: " + failures, failures == 0);
7254
}
1385
7255
1386
	// null analysis -- try/finally
7256
public void test2055_addInitializationsFrom() {
1387
	// TODO (maxime) fix
7257
	long [][][] testData = {
1388
	public void _test0150_try_finally() {
7258
		{{0,0,0,0},{0,0,0,0},{0,0,0,0}},
1389
		this.runNegativeTest(
7259
		{{0,0,0,0},{0,0,0,1},{0,0,0,1}},
1390
			new String[] {
7260
		{{0,0,0,0},{0,0,1,0},{0,0,1,0}},
1391
				"X.java",
7261
		{{0,0,0,0},{0,0,1,1},{0,0,1,1}},
1392
				"public class X {\n" + 
7262
		{{0,0,0,0},{0,1,0,0},{0,1,0,0}},
1393
				"	 Object m;\n" + 
7263
		{{0,0,0,0},{0,1,1,0},{0,1,1,0}},
1394
				"	 void foo() {\n" + 
7264
		{{0,0,0,0},{1,0,0,1},{1,0,0,1}},
1395
				"		 Object o = null;\n" + 
7265
		{{0,0,0,0},{1,0,1,0},{1,0,1,0}},
1396
				"		 try { /* */ }\n" + 
7266
		{{0,0,0,0},{1,0,1,1},{1,0,1,1}},
1397
				"		 finally {\n" + 
7267
		{{0,0,0,0},{1,1,0,0},{1,1,0,0}},
1398
				"		   o = m;\n" + 
7268
		{{0,0,0,0},{1,1,0,1},{1,1,0,1}},
1399
				"		 }\n" + 
7269
		{{0,0,0,1},{0,0,0,0},{0,0,0,1}},
1400
				"		 o.toString();\n" + 
7270
		{{0,0,0,1},{0,0,0,1},{0,0,0,1}},
1401
				"	 }\n" + 
7271
		{{0,0,0,1},{0,0,1,0},{0,0,1,1}},
1402
				"}\n"},
7272
		{{0,0,0,1},{0,0,1,1},{0,0,1,1}},
1403
			"" // because finally assigns to unknown value
7273
		{{0,0,0,1},{0,1,0,0},{0,1,0,0}},
1404
		);
7274
		{{0,0,0,1},{0,1,1,0},{0,1,0,0}},
7275
		{{0,0,0,1},{1,0,0,1},{1,0,0,1}},
7276
		{{0,0,0,1},{1,0,1,0},{1,0,1,0}},
7277
		{{0,0,0,1},{1,0,1,1},{1,0,1,1}},
7278
		{{0,0,0,1},{1,1,0,0},{1,1,0,1}},
7279
		{{0,0,0,1},{1,1,0,1},{1,1,0,1}},
7280
		{{0,0,1,0},{0,0,0,0},{0,0,1,0}},
7281
		{{0,0,1,0},{0,0,0,1},{0,0,1,1}},
7282
		{{0,0,1,0},{0,0,1,0},{0,0,1,0}},
7283
		{{0,0,1,0},{0,0,1,1},{0,0,1,1}},
7284
		{{0,0,1,0},{0,1,0,0},{0,1,1,0}},
7285
		{{0,0,1,0},{0,1,1,0},{0,1,1,0}},
7286
		{{0,0,1,0},{1,0,0,1},{1,0,0,1}},
7287
		{{0,0,1,0},{1,0,1,0},{1,0,1,0}},
7288
		{{0,0,1,0},{1,0,1,1},{1,0,1,1}},
7289
		{{0,0,1,0},{1,1,0,0},{1,1,0,0}},
7290
		{{0,0,1,0},{1,1,0,1},{1,1,0,1}},
7291
		{{0,0,1,1},{0,0,0,0},{0,0,1,1}},
7292
		{{0,0,1,1},{0,0,0,1},{0,0,1,1}},
7293
		{{0,0,1,1},{0,0,1,0},{0,0,1,1}},
7294
		{{0,0,1,1},{0,0,1,1},{0,0,1,1}},
7295
		{{0,0,1,1},{0,1,0,0},{0,1,1,0}},
7296
		{{0,0,1,1},{0,1,1,0},{0,1,1,0}},
7297
		{{0,0,1,1},{1,0,0,1},{1,0,0,1}},
7298
		{{0,0,1,1},{1,0,1,0},{1,0,1,0}},
7299
		{{0,0,1,1},{1,0,1,1},{1,0,1,1}},
7300
		{{0,0,1,1},{1,1,0,0},{1,1,0,1}},
7301
		{{0,0,1,1},{1,1,0,1},{1,1,0,1}},
7302
		{{0,1,0,0},{0,0,0,0},{0,1,0,0}},
7303
		{{0,1,0,0},{0,0,0,1},{0,0,0,1}},
7304
		{{0,1,0,0},{0,0,1,0},{0,1,1,0}},
7305
		{{0,1,0,0},{0,0,1,1},{0,0,1,1}},
7306
		{{0,1,0,0},{0,1,0,0},{0,1,0,0}},
7307
		{{0,1,0,0},{0,1,1,0},{0,1,1,0}},
7308
		{{0,1,0,0},{1,0,0,1},{1,0,0,1}},
7309
		{{0,1,0,0},{1,0,1,0},{1,0,1,0}},
7310
		{{0,1,0,0},{1,0,1,1},{1,0,1,1}},
7311
		{{0,1,0,0},{1,1,0,0},{1,1,0,0}},
7312
		{{0,1,0,0},{1,1,0,1},{1,1,0,1}},
7313
		{{0,1,1,0},{0,0,0,0},{0,1,1,0}},
7314
		{{0,1,1,0},{0,0,0,1},{0,0,1,1}},
7315
		{{0,1,1,0},{0,0,1,0},{0,1,1,0}},
7316
		{{0,1,1,0},{0,0,1,1},{0,0,1,1}},
7317
		{{0,1,1,0},{0,1,0,0},{0,1,1,0}},
7318
		{{0,1,1,0},{0,1,1,0},{0,1,1,0}},
7319
		{{0,1,1,0},{1,0,0,1},{1,0,0,1}},
7320
		{{0,1,1,0},{1,0,1,0},{1,0,1,0}},
7321
		{{0,1,1,0},{1,0,1,1},{1,0,1,1}},
7322
		{{0,1,1,0},{1,1,0,0},{1,1,0,0}},
7323
		{{0,1,1,0},{1,1,0,1},{1,1,0,1}},
7324
		{{1,0,0,1},{0,0,0,0},{1,0,0,1}},
7325
		{{1,0,0,1},{0,0,0,1},{1,0,0,1}},
7326
		{{1,0,0,1},{0,0,1,0},{0,0,1,1}},
7327
		{{1,0,0,1},{0,0,1,1},{0,0,1,1}},
7328
		{{1,0,0,1},{0,1,0,0},{0,1,0,0}},
7329
		{{1,0,0,1},{0,1,1,0},{0,1,1,0}},
7330
		{{1,0,0,1},{1,0,0,1},{1,0,0,1}},
7331
		{{1,0,0,1},{1,0,1,0},{1,0,1,0}},
7332
		{{1,0,0,1},{1,0,1,1},{1,0,1,1}},
7333
		{{1,0,0,1},{1,1,0,0},{1,1,0,1}},
7334
		{{1,0,0,1},{1,1,0,1},{1,1,0,1}},
7335
		{{1,0,1,0},{0,0,0,0},{1,0,1,0}},
7336
		{{1,0,1,0},{0,0,0,1},{0,0,1,1}},
7337
		{{1,0,1,0},{0,0,1,0},{1,0,1,0}},
7338
		{{1,0,1,0},{0,0,1,1},{0,0,1,1}},
7339
		{{1,0,1,0},{0,1,0,0},{1,0,1,0}},
7340
		{{1,0,1,0},{0,1,1,0},{1,0,1,0}},
7341
		{{1,0,1,0},{1,0,0,1},{1,0,0,1}},
7342
		{{1,0,1,0},{1,0,1,0},{1,0,1,0}},
7343
		{{1,0,1,0},{1,0,1,1},{1,0,1,1}},
7344
		{{1,0,1,0},{1,1,0,0},{1,1,0,0}},
7345
		{{1,0,1,0},{1,1,0,1},{1,1,0,1}},
7346
		{{1,0,1,1},{0,0,0,0},{1,0,1,1}},
7347
		{{1,0,1,1},{0,0,0,1},{1,0,1,1}},
7348
		{{1,0,1,1},{0,0,1,0},{0,0,1,1}},
7349
		{{1,0,1,1},{0,0,1,1},{0,0,1,1}},
7350
		{{1,0,1,1},{0,1,0,0},{0,1,0,0}},
7351
		{{1,0,1,1},{0,1,1,0},{0,1,1,0}},
7352
		{{1,0,1,1},{1,0,0,1},{1,0,0,1}},
7353
		{{1,0,1,1},{1,0,1,0},{1,0,1,0}},
7354
		{{1,0,1,1},{1,0,1,1},{1,0,1,1}},
7355
		{{1,0,1,1},{1,1,0,0},{1,1,0,1}},
7356
		{{1,0,1,1},{1,1,0,1},{1,1,0,1}},
7357
		{{1,1,0,0},{0,0,0,0},{1,1,0,0}},
7358
		{{1,1,0,0},{0,0,0,1},{1,1,0,1}},
7359
		{{1,1,0,0},{0,0,1,0},{0,0,1,0}},
7360
		{{1,1,0,0},{0,0,1,1},{0,0,1,1}},
7361
		{{1,1,0,0},{0,1,0,0},{0,1,0,0}},
7362
		{{1,1,0,0},{0,1,1,0},{0,1,1,0}},
7363
		{{1,1,0,0},{1,0,0,1},{1,0,0,1}},
7364
		{{1,1,0,0},{1,0,1,0},{1,0,1,0}},
7365
		{{1,1,0,0},{1,0,1,1},{1,0,1,1}},
7366
		{{1,1,0,0},{1,1,0,0},{1,1,0,0}},
7367
		{{1,1,0,0},{1,1,0,1},{1,1,0,1}},
7368
		{{1,1,0,1},{0,0,0,0},{1,1,0,1}},
7369
		{{1,1,0,1},{0,0,0,1},{0,0,0,1}},
7370
		{{1,1,0,1},{0,0,1,0},{0,0,1,1}},
7371
		{{1,1,0,1},{0,0,1,1},{0,0,1,1}},
7372
		{{1,1,0,1},{0,1,0,0},{0,1,0,0}},
7373
		{{1,1,0,1},{0,1,1,0},{0,1,1,0}},
7374
		{{1,1,0,1},{1,0,0,1},{1,0,0,1}},
7375
		{{1,1,0,1},{1,0,1,0},{1,0,1,0}},
7376
		{{1,1,0,1},{1,0,1,1},{1,0,1,1}},
7377
		{{1,1,0,1},{1,1,0,0},{1,1,0,1}},
7378
		{{1,1,0,1},{1,1,0,1},{1,1,0,1}},
7379
	};
7380
	int failures = 0;
7381
	long start;
7382
	if (combinationTestsloopsNb > 1) {
7383
		start = System.currentTimeMillis();
7384
	}
7385
	String header = "addInitializationsFrom failures: "; //$NON-NLS-1$
7386
	for (int l = 0; l < combinationTestsloopsNb ; l++) {
7387
		for (int i = 0; i < testData.length; i++) {
7388
			UnconditionalFlowInfoTestHarness result;
7389
			if (!(result = (UnconditionalFlowInfoTestHarness)(
7390
					UnconditionalFlowInfoTestHarness.
7391
						testUnconditionalFlowInfo(testData[i][0])).
7392
						addInitializationsFrom(
7393
								UnconditionalFlowInfoTestHarness.
7394
								testUnconditionalFlowInfo(testData[i][1]))).
7395
					testEquals(UnconditionalFlowInfoTestHarness.
7396
								testUnconditionalFlowInfo(testData[i][2]))) {
7397
				if (failures == 0) {
7398
					System.out.println(header);
7399
				}
7400
				failures++;
7401
				System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
7402
					',' + testStringValueOf(testData[i][1]) +
7403
					',' + result.testString() + 
7404
					"}, // instead of: " + testStringValueOf(testData[i][2]));
7405
			}
7406
		}
1405
	}
7407
	}
1406
7408
	if (combinationTestsloopsNb > 1) {
1407
	// null analysis -- try/finally
7409
		System.out.println("addInitial...\t\t" + combinationTestsloopsNb + "\t" + 
1408
	public void test0151_try_finally() {
7410
				(System.currentTimeMillis() - start));
1409
		this.runNegativeTest(
7411
	}
1410
			new String[] {
7412
	// PREMATURE optimize test (extraneous allocations and copies)
1411
				"X.java",
7413
	// PREMATURE optimize test (extraneous iterations - undup)
1412
				"public class X {\n" + 
7414
	UnconditionalFlowInfoTestHarness 
1413
				"	 void foo() {\n" + 
7415
		zero = UnconditionalFlowInfoTestHarness.
1414
				"		 Object o = new Object();\n" + 
7416
				testUnconditionalFlowInfo(new long[] {0,0,0,0}),
1415
				"		 try { /* */ }\n" + 
7417
		left0, left1, right1, left2, right2, 
1416
				"		 finally {\n" + 
7418
		expected0, expected1, expected2, result;
1417
				"			 o = null;\n" + 
7419
	for (int i = 0; i < testData.length; i++) {
1418
				"		 }\n" + 
7420
			left0 = UnconditionalFlowInfoTestHarness.
1419
				"		 o.toString();\n" + 
7421
					testUnconditionalFlowInfo(testData[i][0]);
1420
				"	 }\n" + 
7422
			left1 = UnconditionalFlowInfoTestHarness.
1421
				"}\n"},
7423
					testUnconditionalFlowInfo(testData[i][0], 64);
1422
			"----------\n" + 
7424
			left2 = UnconditionalFlowInfoTestHarness.
1423
			"1. WARNING in X.java (at line 8)\n" + 
7425
				testUnconditionalFlowInfo(testData[i][0], 128);
1424
			"	o.toString();\n" + 
7426
			right1 = UnconditionalFlowInfoTestHarness.
1425
			"	^\n" + 
7427
					testUnconditionalFlowInfo(testData[i][1], 64);
1426
			"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
7428
			right2 = UnconditionalFlowInfoTestHarness.
1427
			"----------\n" // because finally assigns to null 
7429
					testUnconditionalFlowInfo(testData[i][1], 128);
1428
		);
7430
			expected0 = UnconditionalFlowInfoTestHarness.
7431
					testUnconditionalFlowInfo(testData[i][2]);
7432
			expected1 = UnconditionalFlowInfoTestHarness.
7433
					testUnconditionalFlowInfo(testData[i][2], 64);
7434
			expected2 = UnconditionalFlowInfoTestHarness.
7435
				testUnconditionalFlowInfo(testData[i][2], 128);
7436
		if (!(result = (UnconditionalFlowInfoTestHarness) 
7437
				left1.copy().addInitializationsFrom(right1)).
7438
					testEquals(expected1)) {
7439
			if (failures == 0) {
7440
				System.out.println(header);
7441
			}
7442
			failures++;
7443
			System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
7444
				',' + testStringValueOf(testData[i][1]) +
7445
				',' + result.testString() + 
7446
				"}, // (64, 64) - instead of: " + testStringValueOf(testData[i][2]));
7447
		}
7448
		if ((testData[i][0][0] | testData[i][0][1] | 
7449
				testData[i][0][2] | testData[i][0][3]) == 0) {
7450
			if (!(result = (UnconditionalFlowInfoTestHarness) 
7451
					zero.copy().addInitializationsFrom(right1)).
7452
						testEquals(expected1)) {
7453
				if (failures == 0) {
7454
					System.out.println(header);
7455
				}
7456
				failures++;
7457
				System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
7458
					',' + testStringValueOf(testData[i][1]) +
7459
					',' + result.testString() + 
7460
					"}, // (zero, 64) - instead of: " + testStringValueOf(testData[i][2]));
7461
			}
7462
			if (!(result = (UnconditionalFlowInfoTestHarness) right2.copy().
7463
					addInitializationsFrom(right1)).
7464
						testEquals(expected1, 64)) {
7465
				if (failures == 0) {
7466
					System.out.println(header);
7467
				}
7468
				failures++;
7469
				System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
7470
					',' + testStringValueOf(testData[i][1]) +
7471
					',' + result.testString() + 
7472
					"}, // (zero 128, 64) - instead of: " + testStringValueOf(testData[i][2]));
7473
			}
7474
			if (!(result = (UnconditionalFlowInfoTestHarness) 
7475
					 zero.copy().addInitializationsFrom(right2)).
7476
						testEquals(expected2, 128)) {
7477
				if (failures == 0) {
7478
					System.out.println(header);
7479
				}
7480
				failures++;
7481
				System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
7482
					',' + testStringValueOf(testData[i][1]) +
7483
					',' + result.testString(128) + 
7484
					"}, // (zero, 128) - instead of: " + testStringValueOf(testData[i][2]));
7485
			}
7486
			if (!(result = (UnconditionalFlowInfoTestHarness) 
7487
					 right1.copy().addInitializationsFrom(right2)).
7488
						testEquals(expected2, 128)) {
7489
				if (failures == 0) {
7490
					System.out.println(header);
7491
				}
7492
				failures++;
7493
				System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
7494
					',' + testStringValueOf(testData[i][1]) +
7495
					',' + result.testString(128) + 
7496
					"}, // (zero 64, 128) - instead of: " + testStringValueOf(testData[i][2]));
7497
			}
7498
		}
7499
		if ((testData[i][1][0] | testData[i][1][1] | 
7500
				testData[i][1][2] | testData[i][1][3]) == 0) {
7501
			if (!(result = (UnconditionalFlowInfoTestHarness) 
7502
					left0.copy().addInitializationsFrom(left2)).
7503
						testEquals(expected0, 0)) {
7504
				if (failures == 0) {
7505
					System.out.println(header);
7506
				}
7507
				failures++;
7508
				System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
7509
					',' + testStringValueOf(testData[i][1]) +
7510
					',' + result.testString() + 
7511
					"}, // (1, zero 128) - instead of: " + testStringValueOf(testData[i][2]));
7512
			}
7513
			if (!(result = (UnconditionalFlowInfoTestHarness) 
7514
					left1.copy().addInitializationsFrom(zero)).
7515
						testEquals(expected1)) {
7516
				if (failures == 0) {
7517
					System.out.println(header);
7518
				}
7519
				failures++;
7520
				System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
7521
					',' + testStringValueOf(testData[i][1]) +
7522
					',' + result.testString() + 
7523
					"}, // (64, zero) - instead of: " + testStringValueOf(testData[i][2]));
7524
			}
7525
			if (!(result = (UnconditionalFlowInfoTestHarness) 
7526
					left1.copy().addInitializationsFrom(left2)).
7527
						testEquals(expected1, 64)) {
7528
				if (failures == 0) {
7529
					System.out.println(header);
7530
				}
7531
				failures++;
7532
				System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
7533
					',' + testStringValueOf(testData[i][1]) +
7534
					',' + result.testString() + 
7535
					"}, // (64, zero 128) - instead of: " + testStringValueOf(testData[i][2]));
7536
			}
7537
			if (!(result = (UnconditionalFlowInfoTestHarness) 
7538
					left2.copy().addInitializationsFrom(zero)).
7539
						testEquals(expected2, 128)) {
7540
				if (failures == 0) {
7541
					System.out.println(header);
7542
				}
7543
				failures++;
7544
				System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
7545
					',' + testStringValueOf(testData[i][1]) +
7546
					',' + result.testString() + 
7547
					"}, // (128, zero) - instead of: " + testStringValueOf(testData[i][2]));
7548
			}
7549
			if (!(result = (UnconditionalFlowInfoTestHarness) 
7550
					left2.addInitializationsFrom(left1)).
7551
						testEquals(expected2, 128)) {
7552
				if (failures == 0) {
7553
					System.out.println(header);
7554
				}
7555
				failures++;
7556
				System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
7557
					',' + testStringValueOf(testData[i][1]) +
7558
					',' + result.testString() + 
7559
					"}, // (128, zero 64) - instead of: " + testStringValueOf(testData[i][2]));
7560
			}
7561
		}
1429
	}
7562
	}
1430
7563
	if (printTablesAsNames) {
1431
	// null analysis -- try/finally
7564
		System.out.println("RECAP TABLE FOR ADD");
1432
	public void test0152_try_finally() {
7565
		for (int i = 0; i < testData.length; i++) {
1433
		this.runNegativeTest(
7566
			System.out.println(testSymbolicValueOf(testData[i][0]) + " + " +
1434
			new String[] {
7567
				testSymbolicValueOf(testData[i][1]) + " -> " +
1435
				"X.java",
7568
				testSymbolicValueOf(testData[i][2]));
1436
				"public class X {\n" + 
7569
		}	
1437
				"	 void foo() {\n" + 
7570
	}
1438
				"		 Object o = null;\n" + 
7571
	if (printTablesAsCodes) {
1439
				"		 try {\n" + 
7572
		System.out.println("RECAP TABLE FOR ADD");
1440
				"		   System.out.println();\n" + // might throw a runtime exception 
7573
		for (int i = 0; i < testData.length; i++) {
1441
				"			 o = new Object();\n" + 
7574
			System.out.println(testCodedValueOf(testData[i][0]) + " " +
1442
				"		 }\n" + 
7575
				testCodedValueOf(testData[i][1]) + " " +
1443
				"		 finally { /* */ }\n" + 
7576
				testCodedValueOf(testData[i][2]));
1444
				"		 o.toString();\n" + 
7577
		}
1445
						// still OK because in case of exception this code is 
1446
						// not reached
1447
				"	 }\n" + 
1448
				"}\n"},
1449
			""
1450
		);
1451
	}
7578
	}
7579
	if (printTruthMaps) {
7580
		for (int i = 0; i < 4; i++) {
7581
			System.out.println("======================================================");
7582
			System.out.println("Truth map for addInitializationsFrom null bit " + (i + 1));
7583
			System.out.println();
7584
			printTruthMap(testData, i);
7585
		}
7586
	}	
7587
	assertTrue("nb of failures: " + failures, failures == 0);
7588
}
1452
7589
1453
	// null analysis -- try/finally
7590
public void test2056_addPotentialInitializationsFrom() {
1454
	public void test0153_try_finally() {
7591
	long [][][] testData = {
1455
		this.runNegativeTest(
7592
		{{0,0,0,0},{0,0,0,0},{0,0,0,0}},
1456
			new String[] {
7593
		{{0,0,0,0},{0,0,0,1},{0,0,0,1}},
1457
				"X.java",
7594
		{{0,0,0,0},{0,0,1,0},{0,0,1,0}},
1458
				"public class X {\n" + 
7595
		{{0,0,0,0},{0,0,1,1},{0,0,1,1}},
1459
				"	 void foo(X x) {\n" + 
7596
		{{0,0,0,0},{0,1,0,0},{0,0,0,0}},
1460
				"		 x = null;\n" + 
7597
		{{0,0,0,0},{0,1,1,0},{0,0,1,0}},
1461
				"		 try {\n" + 
7598
		{{0,0,0,0},{1,0,0,1},{0,0,0,1}},
1462
				"			 x = null;\n" +                // complain, already null
7599
		{{0,0,0,0},{1,0,1,0},{0,0,1,0}},
1463
				"		 } finally { /* */ }\n" + 
7600
		{{0,0,0,0},{1,0,1,1},{0,0,0,1}},
1464
				"	 }\n" + 
7601
		{{0,0,0,0},{1,1,0,0},{0,0,0,0}},
1465
				"}\n",
7602
		{{0,0,0,0},{1,1,0,1},{0,0,0,1}},
1466
			},
7603
		{{0,0,0,1},{0,0,0,0},{0,0,0,1}},
1467
		"----------\n" + 
7604
		{{0,0,0,1},{0,0,0,1},{0,0,0,1}},
1468
		"1. WARNING in X.java (at line 5)\n" + 
7605
		{{0,0,0,1},{0,0,1,0},{0,0,1,1}},
1469
		"	x = null;\n" + 
7606
		{{0,0,0,1},{0,0,1,1},{0,0,1,1}},
1470
		"	^\n" + 
7607
		{{0,0,0,1},{0,1,0,0},{0,0,0,1}},
1471
		"The variable x can only be null; it was either set to null or checked for null when last used\n" + 
7608
		{{0,0,0,1},{0,1,1,0},{0,0,1,1}},
1472
		"----------\n");
7609
		{{0,0,0,1},{1,0,0,1},{0,0,0,1}},
7610
		{{0,0,0,1},{1,0,1,0},{0,0,1,1}},
7611
		{{0,0,0,1},{1,0,1,1},{0,0,0,1}},
7612
		{{0,0,0,1},{1,1,0,0},{0,0,0,1}},
7613
		{{0,0,0,1},{1,1,0,1},{0,0,0,1}},
7614
		{{0,0,1,0},{0,0,0,0},{0,0,1,0}},
7615
		{{0,0,1,0},{0,0,0,1},{0,0,1,1}},
7616
		{{0,0,1,0},{0,0,1,0},{0,0,1,0}},
7617
		{{0,0,1,0},{0,0,1,1},{0,0,1,1}},
7618
		{{0,0,1,0},{0,1,0,0},{0,0,1,0}},
7619
		{{0,0,1,0},{0,1,1,0},{0,0,1,0}},
7620
		{{0,0,1,0},{1,0,0,1},{0,0,1,1}},
7621
		{{0,0,1,0},{1,0,1,0},{0,0,1,0}},
7622
		{{0,0,1,0},{1,0,1,1},{0,0,1,1}},
7623
		{{0,0,1,0},{1,1,0,0},{0,0,1,0}},
7624
		{{0,0,1,0},{1,1,0,1},{0,0,1,1}},
7625
		{{0,0,1,1},{0,0,0,0},{0,0,1,1}},
7626
		{{0,0,1,1},{0,0,0,1},{0,0,1,1}},
7627
		{{0,0,1,1},{0,0,1,0},{0,0,1,1}},
7628
		{{0,0,1,1},{0,0,1,1},{0,0,1,1}},
7629
		{{0,0,1,1},{0,1,0,0},{0,0,1,1}},
7630
		{{0,0,1,1},{0,1,1,0},{0,0,1,1}},
7631
		{{0,0,1,1},{1,0,0,1},{0,0,1,1}},
7632
		{{0,0,1,1},{1,0,1,0},{0,0,1,1}},
7633
		{{0,0,1,1},{1,0,1,1},{0,0,1,1}},
7634
		{{0,0,1,1},{1,1,0,0},{0,0,1,1}},
7635
		{{0,0,1,1},{1,1,0,1},{0,0,1,1}},
7636
		{{0,1,0,0},{0,0,0,0},{0,1,0,0}},
7637
		{{0,1,0,0},{0,0,0,1},{0,0,0,1}},
7638
		{{0,1,0,0},{0,0,1,0},{0,1,1,0}},
7639
		{{0,1,0,0},{0,0,1,1},{0,0,1,1}},
7640
		{{0,1,0,0},{0,1,0,0},{0,1,0,0}},
7641
		{{0,1,0,0},{0,1,1,0},{0,1,1,0}},
7642
		{{0,1,0,0},{1,0,0,1},{0,0,0,1}},
7643
		{{0,1,0,0},{1,0,1,0},{0,1,1,0}},
7644
		{{0,1,0,0},{1,0,1,1},{0,0,0,1}},
7645
		{{0,1,0,0},{1,1,0,0},{0,1,0,0}},
7646
		{{0,1,0,0},{1,1,0,1},{0,0,0,1}},
7647
		{{0,1,1,0},{0,0,0,0},{0,1,1,0}},
7648
		{{0,1,1,0},{0,0,0,1},{0,0,1,1}},
7649
		{{0,1,1,0},{0,0,1,0},{0,1,1,0}},
7650
		{{0,1,1,0},{0,0,1,1},{0,0,1,1}},
7651
		{{0,1,1,0},{0,1,0,0},{0,1,1,0}},
7652
		{{0,1,1,0},{0,1,1,0},{0,1,1,0}},
7653
		{{0,1,1,0},{1,0,0,1},{0,0,1,1}},
7654
		{{0,1,1,0},{1,0,1,0},{0,1,1,0}},
7655
		{{0,1,1,0},{1,0,1,1},{0,0,1,1}},
7656
		{{0,1,1,0},{1,1,0,0},{0,1,1,0}},
7657
		{{0,1,1,0},{1,1,0,1},{0,0,1,1}},
7658
		{{1,0,0,1},{0,0,0,0},{1,0,0,1}},
7659
		{{1,0,0,1},{0,0,0,1},{1,0,1,1}},
7660
		{{1,0,0,1},{0,0,1,0},{0,0,1,1}},
7661
		{{1,0,0,1},{0,0,1,1},{0,0,1,1}},
7662
		{{1,0,0,1},{0,1,0,0},{1,0,0,1}},
7663
		{{1,0,0,1},{0,1,1,0},{0,0,1,1}},
7664
		{{1,0,0,1},{1,0,0,1},{1,0,0,1}},
7665
		{{1,0,0,1},{1,0,1,0},{0,0,1,1}},
7666
		{{1,0,0,1},{1,0,1,1},{1,0,1,1}},
7667
		{{1,0,0,1},{1,1,0,0},{1,0,0,1}},
7668
		{{1,0,0,1},{1,1,0,1},{1,0,0,1}},
7669
		{{1,0,1,0},{0,0,0,0},{1,0,1,0}},
7670
		{{1,0,1,0},{0,0,0,1},{0,0,1,1}},
7671
		{{1,0,1,0},{0,0,1,0},{1,0,1,0}},
7672
		{{1,0,1,0},{0,0,1,1},{0,0,1,1}},
7673
		{{1,0,1,0},{0,1,0,0},{1,0,1,0}},
7674
		{{1,0,1,0},{0,1,1,0},{1,0,1,0}},
7675
		{{1,0,1,0},{1,0,0,1},{0,0,1,1}},
7676
		{{1,0,1,0},{1,0,1,0},{1,0,1,0}},
7677
		{{1,0,1,0},{1,0,1,1},{0,0,1,1}},
7678
		{{1,0,1,0},{1,1,0,0},{1,0,1,0}},
7679
		{{1,0,1,0},{1,1,0,1},{0,0,1,1}},
7680
		{{1,0,1,1},{0,0,0,0},{1,0,1,1}},
7681
		{{1,0,1,1},{0,0,0,1},{1,0,1,1}},
7682
		{{1,0,1,1},{0,0,1,0},{0,0,1,1}},
7683
		{{1,0,1,1},{0,0,1,1},{0,0,1,1}},
7684
		{{1,0,1,1},{0,1,0,0},{1,0,1,1}},
7685
		{{1,0,1,1},{0,1,1,0},{0,0,1,1}},
7686
		{{1,0,1,1},{1,0,0,1},{1,0,1,1}},
7687
		{{1,0,1,1},{1,0,1,0},{0,0,1,1}},
7688
		{{1,0,1,1},{1,0,1,1},{1,0,1,1}},
7689
		{{1,0,1,1},{1,1,0,0},{1,0,1,1}},
7690
		{{1,0,1,1},{1,1,0,1},{1,0,1,1}},
7691
		{{1,1,0,0},{0,0,0,0},{1,1,0,0}},
7692
		{{1,1,0,0},{0,0,0,1},{0,0,0,1}},
7693
		{{1,1,0,0},{0,0,1,0},{0,0,1,0}},
7694
		{{1,1,0,0},{0,0,1,1},{0,0,1,1}},
7695
		{{1,1,0,0},{0,1,0,0},{1,1,0,0}},
7696
		{{1,1,0,0},{0,1,1,0},{0,0,1,0}},
7697
		{{1,1,0,0},{1,0,0,1},{0,0,0,1}},
7698
		{{1,1,0,0},{1,0,1,0},{0,0,1,0}},
7699
		{{1,1,0,0},{1,0,1,1},{0,0,0,1}},
7700
		{{1,1,0,0},{1,1,0,0},{1,1,0,0}},
7701
		{{1,1,0,0},{1,1,0,1},{1,1,0,1}},
7702
		{{1,1,0,1},{0,0,0,0},{1,1,0,1}},
7703
		{{1,1,0,1},{0,0,0,1},{0,0,0,1}},
7704
		{{1,1,0,1},{0,0,1,0},{0,0,1,1}},
7705
		{{1,1,0,1},{0,0,1,1},{0,0,1,1}},
7706
		{{1,1,0,1},{0,1,0,0},{1,1,0,1}},
7707
		{{1,1,0,1},{0,1,1,0},{0,0,1,1}},
7708
		{{1,1,0,1},{1,0,0,1},{0,0,0,1}},
7709
		{{1,1,0,1},{1,0,1,0},{0,0,1,1}},
7710
		{{1,1,0,1},{1,0,1,1},{0,0,0,1}},
7711
		{{1,1,0,1},{1,1,0,0},{1,1,0,1}},
7712
		{{1,1,0,1},{1,1,0,1},{1,1,0,1}},
7713
	};
7714
	int failures = 0;
7715
	long start;
7716
	if (combinationTestsloopsNb > 1) {
7717
		start = System.currentTimeMillis();
7718
	}
7719
	String header = "addPotentialInitializationsFrom failures: "; //$NON-NLS-1$
7720
	for (int l = 0; l < combinationTestsloopsNb ; l++) {
7721
		for (int i = 0; i < testData.length; i++) {
7722
			UnconditionalFlowInfoTestHarness result;
7723
			if (!(result = (UnconditionalFlowInfoTestHarness)(
7724
					UnconditionalFlowInfoTestHarness.
7725
						testUnconditionalFlowInfo(testData[i][0])).
7726
							addPotentialInitializationsFrom(
7727
								UnconditionalFlowInfoTestHarness.
7728
									testUnconditionalFlowInfo(testData[i][1]))).
7729
					testEquals(UnconditionalFlowInfoTestHarness.
7730
						testUnconditionalFlowInfo(testData[i][2]))) {
7731
				if (failures == 0) {
7732
					System.out.println(header);
7733
				}
7734
				failures++;
7735
				System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
7736
					',' + testStringValueOf(testData[i][1]) +
7737
					',' + result.testString() + 
7738
					"}, // instead of: " + testStringValueOf(testData[i][2]));
7739
			}
7740
			if (combinationTestsloopsNb < 2 && 
7741
					!(result = (UnconditionalFlowInfoTestHarness)(
7742
							UnconditionalFlowInfoTestHarness.
7743
							testUnconditionalFlowInfo(testData[i][0])).
7744
								addPotentialNullInfoFrom(
7745
										UnconditionalFlowInfoTestHarness.
7746
											testUnconditionalFlowInfo(testData[i][1], 128))).
7747
					testEquals(UnconditionalFlowInfoTestHarness.
7748
						testUnconditionalFlowInfo(testData[14][0], 65), 64)) {
7749
				if (failures == 0) {
7750
					System.out.println(header);
7751
				}
7752
				failures++;
7753
				System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
7754
					',' + testStringValueOf(testData[i][1]) +
7755
					',' + result.testString(64) + 
7756
					"}, // bit 64 only, instead of: {0,0,0,0}");
7757
			}
7758
		}
1473
	}
7759
	}
1474
	
7760
	if (combinationTestsloopsNb > 1) {
1475
	// null analysis -- try/finally
7761
		System.out.println("addPotential...\t" + combinationTestsloopsNb + "\t" + 
1476
	public void test0154_try_finally() {
7762
				(System.currentTimeMillis() - start));
1477
		this.runNegativeTest(
7763
	}
1478
			new String[] {
7764
	UnconditionalFlowInfoTestHarness 
1479
				"X.java",
7765
		zero = UnconditionalFlowInfoTestHarness.
1480
				"public class X {\n" + 
7766
				testUnconditionalFlowInfo(new long[] {0,0,0,0}),
1481
				"	 void foo(X x) {\n" + 
7767
		left0, left1, right1, left2, right2, 
1482
				"		 x = null;\n" + 
7768
		expected0, expected1, expected2, result;
1483
				"		 try {\n" + 
7769
	for (int i = 0; i < testData.length; i++) {
1484
				"			 x = null;\n" +           
7770
			left0 = UnconditionalFlowInfoTestHarness.
1485
				"		 } finally {\n" + 
7771
						testUnconditionalFlowInfo(testData[i][0]);
1486
				"			 if (x != null) { /* */ }\n" + // complain, null in both paths 
7772
			left1 = UnconditionalFlowInfoTestHarness.
1487
				"		 }\n" + 
7773
						testUnconditionalFlowInfo(testData[i][0], 64);
1488
				"	 }\n" + 
7774
			left2 = UnconditionalFlowInfoTestHarness.
1489
				"}\n",
7775
						testUnconditionalFlowInfo(testData[i][0], 128);
1490
			},
7776
			right1 = UnconditionalFlowInfoTestHarness.
1491
		"----------\n" + 
7777
						testUnconditionalFlowInfo(testData[i][1], 64);
1492
		"1. WARNING in X.java (at line 5)\n" + 
7778
			right2 = UnconditionalFlowInfoTestHarness.
1493
		"	x = null;\n" + 
7779
						testUnconditionalFlowInfo(testData[i][1], 128);
1494
		"	^\n" + 
7780
			expected0 = UnconditionalFlowInfoTestHarness.
1495
		"The variable x can only be null; it was either set to null or checked for null when last used\n" + 
7781
							testUnconditionalFlowInfo(testData[i][2]);
1496
		"----------\n" + 
7782
			expected1 = UnconditionalFlowInfoTestHarness.
1497
		"2. WARNING in X.java (at line 7)\n" + 
7783
							testUnconditionalFlowInfo(testData[i][2], 64);
1498
		"	if (x != null) { /* */ }\n" + 
7784
			expected2 = UnconditionalFlowInfoTestHarness.
1499
		"	    ^\n" + 
7785
							testUnconditionalFlowInfo(testData[i][2], 128);
1500
		"The variable x can only be null; it was either set to null or checked for null when last used\n" + 
7786
		if (!(result = (UnconditionalFlowInfoTestHarness) 
1501
		"----------\n");
7787
				left1.copy().addPotentialInitializationsFrom(right1)).
7788
					testEquals(expected1)) {
7789
			if (failures == 0) {
7790
				System.out.println(header);
7791
			}
7792
			failures++;
7793
			System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
7794
				',' + testStringValueOf(testData[i][1]) +
7795
				',' + result.testString() + 
7796
				"}, // (64, 64) - instead of: " + testStringValueOf(testData[i][2]));
7797
		}
7798
		if (testData[i][0][0] + testData[i][0][1] + 
7799
				testData[i][0][2] + testData[i][0][3] == 0) {
7800
			if (!(result = (UnconditionalFlowInfoTestHarness)
7801
					zero.copy().addPotentialInitializationsFrom(right1)).
7802
						testEquals(expected1)) {
7803
				if (failures == 0) {
7804
					System.out.println(header);
7805
				}
7806
				failures++;
7807
				System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
7808
					',' + testStringValueOf(testData[i][1]) +
7809
					',' + result.testString() + 
7810
					"}, // (zero, 64) - instead of: " + testStringValueOf(testData[i][2]));
7811
			}
7812
			if (!(result = (UnconditionalFlowInfoTestHarness) 
7813
					right2.copy().addPotentialInitializationsFrom(right1)).
7814
						testEquals(expected1, 64)) {
7815
				if (failures == 0) {
7816
					System.out.println(header);
7817
				}
7818
				failures++;
7819
				System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
7820
					',' + testStringValueOf(testData[i][1]) +
7821
					',' + result.testString() + 
7822
					"}, // (zero 128, 64) - instead of: " + testStringValueOf(testData[i][2]));
7823
			}
7824
			if (!(result = (UnconditionalFlowInfoTestHarness)
7825
					(UnconditionalFlowInfoTestHarness.
7826
							testUnconditionalFlowInfo(new long[] {0,0,0,0}, 64)).
7827
								// make just in time to get the needed structure
7828
								addPotentialNullInfoFrom(right2)).
7829
									testEquals(expected2, 128)) {
7830
				if (failures == 0) {
7831
					System.out.println(header);
7832
				}
7833
				failures++;
7834
				System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
7835
					',' + testStringValueOf(testData[i][1]) +
7836
					',' + result.testString() + 
7837
					"}, // (zero extra, 128) null only - instead of: " + testStringValueOf(testData[i][2]));
7838
			}
7839
			if (!(result = (UnconditionalFlowInfoTestHarness) 
7840
					((UnconditionalFlowInfo)right2.copy()).
7841
						addPotentialNullInfoFrom(right1)).
7842
							testEquals(expected1, 64)) {
7843
				if (failures == 0) {
7844
					System.out.println(header);
7845
				}
7846
				failures++;
7847
				System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
7848
					',' + testStringValueOf(testData[i][1]) +
7849
					',' + result.testString() + 
7850
					"}, // (zero 128, 64) null only - instead of: " + testStringValueOf(testData[i][2]));
7851
			}
7852
			if (!(result = (UnconditionalFlowInfoTestHarness) 
7853
					 ((UnconditionalFlowInfo)zero.copy()).
7854
					 	addPotentialNullInfoFrom(right2)).
7855
					 		testEquals(expected2, 128)) {
7856
				if (failures == 0) {
7857
					System.out.println(header);
7858
				}
7859
				failures++;
7860
				System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
7861
					',' + testStringValueOf(testData[i][1]) +
7862
					',' + result.testString(128) + 
7863
					"}, // (zero, 128) null only - instead of: " + testStringValueOf(testData[i][2]));
7864
			}
7865
			if (!(result = (UnconditionalFlowInfoTestHarness) 
7866
					 ((UnconditionalFlowInfo)right1.copy()).
7867
					 	addPotentialNullInfoFrom(right2)).
7868
					 		testEquals(expected2, 128)) {
7869
				if (failures == 0) {
7870
					System.out.println(header);
7871
				}
7872
				failures++;
7873
				System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
7874
					',' + testStringValueOf(testData[i][1]) +
7875
					',' + result.testString(128) + 
7876
					"}, // (zero 64, 128) null only - instead of: " + testStringValueOf(testData[i][2]));
7877
			}		}
7878
		if (testData[i][1][0] + testData[i][1][1] + 
7879
				testData[i][1][2] + testData[i][1][3] == 0) {
7880
			if (!(result = (UnconditionalFlowInfoTestHarness) 
7881
					((UnconditionalFlowInfoTestHarness)left0.copy()).
7882
						addPotentialNullInfoFrom(left2)).
7883
							testEquals(expected0, 1)) {
7884
				if (failures == 0) {
7885
					System.out.println(header);
7886
				}
7887
				failures++;
7888
				System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
7889
					',' + testStringValueOf(testData[i][1]) +
7890
					',' + result.testString() + 
7891
					"}, // (1, zero 128) null only - instead of: " + testStringValueOf(testData[i][2]));
7892
			}
7893
			if (!(result = (UnconditionalFlowInfoTestHarness)
7894
					left1.copy().addPotentialInitializationsFrom(zero)).
7895
						testEquals(expected1)) {
7896
				if (failures == 0) {
7897
					System.out.println(header);
7898
				}
7899
				failures++;
7900
				System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
7901
					',' + testStringValueOf(testData[i][1]) +
7902
					',' + result.testString() + 
7903
					"}, // (64, zero) - instead of: " + testStringValueOf(testData[i][2]));
7904
			}
7905
			if (!(result = (UnconditionalFlowInfoTestHarness)
7906
					left1.copy().addPotentialInitializationsFrom(left2)).
7907
						testEquals(expected1, 64)) {
7908
				if (failures == 0) {
7909
					System.out.println(header);
7910
				}
7911
				failures++;
7912
				System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
7913
					',' + testStringValueOf(testData[i][1]) +
7914
					',' + result.testString() + 
7915
					"}, // (64, zero 128) - instead of: " + testStringValueOf(testData[i][2]));
7916
			}
7917
			if (!(result = (UnconditionalFlowInfoTestHarness) 
7918
					((UnconditionalFlowInfo)left1.copy()).
7919
						addPotentialNullInfoFrom(left2)).
7920
							testEquals(expected1, 64)) {
7921
				if (failures == 0) {
7922
					System.out.println(header);
7923
				}
7924
				failures++;
7925
				System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
7926
					',' + testStringValueOf(testData[i][1]) +
7927
					',' + result.testString() + 
7928
					"}, // (64, zero 128) null only - instead of: " + testStringValueOf(testData[i][2]));
7929
			}
7930
			if (!(result = (UnconditionalFlowInfoTestHarness) 
7931
					((UnconditionalFlowInfo)left2.copy()).
7932
						addPotentialNullInfoFrom(zero)).
7933
							testEquals(expected2, 128)) {
7934
				if (failures == 0) {
7935
					System.out.println(header);
7936
				}
7937
				failures++;
7938
				System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
7939
					',' + testStringValueOf(testData[i][1]) +
7940
					',' + result.testString() + 
7941
					"}, // (128, zero) null only - instead of: " + testStringValueOf(testData[i][2]));
7942
			}
7943
			if (!(result = (UnconditionalFlowInfoTestHarness) 
7944
					left2.addPotentialNullInfoFrom(left1)).
7945
						testEquals(expected2, 128)) {
7946
				if (failures == 0) {
7947
					System.out.println(header);
7948
				}
7949
				failures++;
7950
				System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
7951
					',' + testStringValueOf(testData[i][1]) +
7952
					',' + result.testString() + 
7953
					"}, // (128, zero 64) null only - instead of: " + testStringValueOf(testData[i][2]));
7954
			}
7955
		}
1502
	}
7956
	}
1503
	
7957
	if (printTablesAsNames) {
1504
	// null analysis -- try/finally
7958
		System.out.println("RECAP TABLE FOR ADD POTENTIAL");
1505
	// origin: AssignmentTest#test017
7959
		for (int i = 0; i < testData.length; i++) {
1506
	// REVIEW design choice
7960
			System.out.println(testSymbolicValueOf(testData[i][0]) + " + " +
1507
	// See also test0174. The whole issue here is whether or not to detect
7961
				testSymbolicValueOf(testData[i][1]) + " -> " +
1508
	// premature exits. We follow JLS's conservative approach, which considers
7962
				testSymbolicValueOf(testData[i][2]));
1509
	// that the try block may exit before the assignment is completed.
7963
		}
1510
	// TODO (maxime) fix
1511
	public void _test0155_try_finally() {
1512
		this.runNegativeTest(
1513
			new String[] {
1514
				"X.java",
1515
				"public class X {\n" + 
1516
				"	void foo(X x) {\n" + 
1517
				"		x = this;\n" + 
1518
				"		try {\n" + 
1519
				"			x = null;\n" + 
1520
				"		} finally {\n" + 
1521
				"			if (x == null) {/* */}\n" + 
1522
				"		}\n" + 
1523
				"	}\n" + 
1524
				"}\n",
1525
			},
1526
		""
1527
		);
1528
	}
7964
	}
1529
7965
	if (printTablesAsCodes) {
1530
	// null analysis -- try/catch
7966
		System.out.println("RECAP TABLE FOR ADD POTENTIAL");
1531
	public void test0170_try_catch() {
7967
		for (int i = 0; i < testData.length; i++) {
1532
		this.runNegativeTest(
7968
			System.out.println(testCodedValueOf(testData[i][0]) + " " +
1533
			new String[] {
7969
				testCodedValueOf(testData[i][1]) + " " +
1534
				"X.java",
7970
				testCodedValueOf(testData[i][2]));
1535
				"public class X {\n" + 
7971
		}
1536
				"	 void foo() {\n" + 
1537
				"		 Object o = null;\n" + 
1538
				"		 try {\n" + 
1539
				"		   System.out.println();\n" +  // might throw a runtime exception 
1540
				"			 o = new Object();\n" + 
1541
				"		 }\n" + 
1542
				"		 catch (Throwable t) {\n" + // catches everything 
1543
				"		   return;\n" +             // gets out					
1544
				"	   }\n" + 
1545
				"		 o.toString();\n" +         // can't tell if o is null or not  
1546
				"	 }\n" + 
1547
				"}\n"},
1548
			""  
1549
		);
1550
	}
7972
	}
7973
	if (printTruthMaps) {
7974
		for (int i = 0; i < 4; i++) {
7975
			System.out.println("======================================================");
7976
			System.out.println("Truth map for addPotentialInitializationsFrom null bit " + (i + 1));
7977
			System.out.println();
7978
		}
7979
	}	
7980
	assertTrue("nb of failures: " + failures, failures == 0);
7981
}
1551
7982
1552
	// null analysis - try/catch
7983
public void test2057_mergedWith() {
1553
	public void test0171_try_catch() {
7984
	long [][][] testData = {
1554
		this.runNegativeTest(
7985
		{{0,0,0,0},{0,0,0,0},{0,0,0,0}},
1555
			new String[] {
7986
		{{0,0,0,0},{0,0,0,1},{0,0,0,1}},
1556
				"X.java",
7987
		{{0,0,0,0},{0,0,1,0},{0,0,1,0}},
1557
				"public class X {\n" + 
7988
		{{0,0,0,0},{0,0,1,1},{0,0,1,1}},
1558
				"	 boolean dummy;\n" + 
7989
		{{0,0,0,0},{0,1,0,0},{0,0,1,0}},
1559
				"	 void foo() {\n" + 
7990
		{{0,0,0,0},{0,1,1,0},{0,0,1,0}},
1560
				"		 Object o = new Object();\n" + 
7991
		{{0,0,0,0},{1,0,0,1},{0,0,0,1}},
1561
				"		 try {\n" + 
7992
		{{0,0,0,0},{1,0,1,0},{0,0,1,0}},
1562
				"			 System.out.println();\n" + 
7993
		{{0,0,0,0},{1,0,1,1},{0,0,0,1}},
1563
				"			 if (dummy) {\n" + 
7994
		{{0,0,0,0},{1,1,0,0},{0,0,0,0}},
1564
				"			   o = null;\n" + 
7995
		{{0,0,0,0},{1,1,0,1},{0,0,0,1}},
1565
				"			   throw new Exception();\n" + 
7996
		{{0,0,0,1},{0,0,0,0},{0,0,0,1}},
1566
				"			 }\n" + 
7997
		{{0,0,0,1},{0,0,0,1},{0,0,0,1}},
1567
				"		 }\n" + 
7998
		{{0,0,0,1},{0,0,1,0},{0,0,1,1}},
1568
				"		 catch (Exception e) {\n" + 
7999
		{{0,0,0,1},{0,0,1,1},{0,0,1,1}},
1569
				"			 o.toString();\n" +
8000
		{{0,0,0,1},{0,1,0,0},{0,0,1,1}},
1570
				 	// quiet: println may throw a RuntimeException
8001
		{{0,0,0,1},{0,1,1,0},{0,0,1,1}},
1571
				"		 }\n" + 
8002
		{{0,0,0,1},{1,0,0,1},{0,0,0,1}},
1572
				"	 }\n" + 
8003
		{{0,0,0,1},{1,0,1,0},{0,0,1,1}},
1573
				"}\n"},
8004
		{{0,0,0,1},{1,0,1,1},{0,0,0,1}},
1574
			""
8005
		{{0,0,0,1},{1,1,0,0},{0,0,0,1}},
1575
		);
8006
		{{0,0,0,1},{1,1,0,1},{0,0,0,1}},
8007
		{{0,0,1,0},{0,0,0,0},{0,0,1,0}},
8008
		{{0,0,1,0},{0,0,0,1},{0,0,1,1}},
8009
		{{0,0,1,0},{0,0,1,0},{0,0,1,0}},
8010
		{{0,0,1,0},{0,0,1,1},{0,0,1,1}},
8011
		{{0,0,1,0},{0,1,0,0},{0,0,1,0}},
8012
		{{0,0,1,0},{0,1,1,0},{0,0,1,0}},
8013
		{{0,0,1,0},{1,0,0,1},{0,0,1,1}},
8014
		{{0,0,1,0},{1,0,1,0},{0,0,1,0}},
8015
		{{0,0,1,0},{1,0,1,1},{0,0,1,1}},
8016
		{{0,0,1,0},{1,1,0,0},{0,0,1,0}},
8017
		{{0,0,1,0},{1,1,0,1},{0,0,1,1}},
8018
		{{0,0,1,1},{0,0,0,0},{0,0,1,1}},
8019
		{{0,0,1,1},{0,0,0,1},{0,0,1,1}},
8020
		{{0,0,1,1},{0,0,1,0},{0,0,1,1}},
8021
		{{0,0,1,1},{0,0,1,1},{0,0,1,1}},
8022
		{{0,0,1,1},{0,1,0,0},{0,0,1,1}},
8023
		{{0,0,1,1},{0,1,1,0},{0,0,1,1}},
8024
		{{0,0,1,1},{1,0,0,1},{0,0,1,1}},
8025
		{{0,0,1,1},{1,0,1,0},{0,0,1,1}},
8026
		{{0,0,1,1},{1,0,1,1},{0,0,1,1}},
8027
		{{0,0,1,1},{1,1,0,0},{0,0,1,1}},
8028
		{{0,0,1,1},{1,1,0,1},{0,0,1,1}},
8029
		{{0,1,0,0},{0,0,0,0},{0,0,1,0}},
8030
		{{0,1,0,0},{0,0,0,1},{0,0,1,1}},
8031
		{{0,1,0,0},{0,0,1,0},{0,0,1,0}},
8032
		{{0,1,0,0},{0,0,1,1},{0,0,1,1}},
8033
		{{0,1,0,0},{0,1,0,0},{0,1,0,0}},
8034
		{{0,1,0,0},{0,1,1,0},{0,1,1,0}},
8035
		{{0,1,0,0},{1,0,0,1},{0,0,1,1}},
8036
		{{0,1,0,0},{1,0,1,0},{0,1,1,0}},
8037
		{{0,1,0,0},{1,0,1,1},{0,0,1,1}},
8038
		{{0,1,0,0},{1,1,0,0},{0,0,1,0}},
8039
		{{0,1,0,0},{1,1,0,1},{0,0,1,1}},
8040
		{{0,1,1,0},{0,0,0,0},{0,0,1,0}},
8041
		{{0,1,1,0},{0,0,0,1},{0,0,1,1}},
8042
		{{0,1,1,0},{0,0,1,0},{0,0,1,0}},
8043
		{{0,1,1,0},{0,0,1,1},{0,0,1,1}},
8044
		{{0,1,1,0},{0,1,0,0},{0,1,1,0}},
8045
		{{0,1,1,0},{0,1,1,0},{0,1,1,0}},
8046
		{{0,1,1,0},{1,0,0,1},{0,0,1,1}},
8047
		{{0,1,1,0},{1,0,1,0},{0,1,1,0}},
8048
		{{0,1,1,0},{1,0,1,1},{0,0,1,1}},
8049
		{{0,1,1,0},{1,1,0,0},{0,0,1,0}},
8050
		{{0,1,1,0},{1,1,0,1},{0,0,1,1}},
8051
		{{1,0,0,1},{0,0,0,0},{0,0,0,1}},
8052
		{{1,0,0,1},{0,0,0,1},{0,0,0,1}},
8053
		{{1,0,0,1},{0,0,1,0},{0,0,1,1}},
8054
		{{1,0,0,1},{0,0,1,1},{0,0,1,1}},
8055
		{{1,0,0,1},{0,1,0,0},{0,0,1,1}},
8056
		{{1,0,0,1},{0,1,1,0},{0,0,1,1}},
8057
		{{1,0,0,1},{1,0,0,1},{1,0,0,1}},
8058
		{{1,0,0,1},{1,0,1,0},{0,0,1,1}},
8059
		{{1,0,0,1},{1,0,1,1},{1,0,1,1}},
8060
		{{1,0,0,1},{1,1,0,0},{1,1,0,1}},
8061
		{{1,0,0,1},{1,1,0,1},{1,1,0,1}},
8062
		{{1,0,1,0},{0,0,0,0},{0,0,1,0}},
8063
		{{1,0,1,0},{0,0,0,1},{0,0,1,1}},
8064
		{{1,0,1,0},{0,0,1,0},{0,0,1,0}},
8065
		{{1,0,1,0},{0,0,1,1},{0,0,1,1}},
8066
		{{1,0,1,0},{0,1,0,0},{0,1,1,0}},
8067
		{{1,0,1,0},{0,1,1,0},{0,1,1,0}},
8068
		{{1,0,1,0},{1,0,0,1},{0,0,1,1}},
8069
		{{1,0,1,0},{1,0,1,0},{1,0,1,0}},
8070
		{{1,0,1,0},{1,0,1,1},{0,0,1,1}},
8071
		{{1,0,1,0},{1,1,0,0},{0,0,1,0}},
8072
		{{1,0,1,0},{1,1,0,1},{0,0,1,1}},
8073
		{{1,0,1,1},{0,0,0,0},{0,0,0,1}},
8074
		{{1,0,1,1},{0,0,0,1},{0,0,0,1}},
8075
		{{1,0,1,1},{0,0,1,0},{0,0,1,1}},
8076
		{{1,0,1,1},{0,0,1,1},{0,0,1,1}},
8077
		{{1,0,1,1},{0,1,0,0},{0,0,1,1}},
8078
		{{1,0,1,1},{0,1,1,0},{0,0,1,1}},
8079
		{{1,0,1,1},{1,0,0,1},{1,0,1,1}},
8080
		{{1,0,1,1},{1,0,1,0},{0,0,1,1}},
8081
		{{1,0,1,1},{1,0,1,1},{1,0,1,1}},
8082
		{{1,0,1,1},{1,1,0,0},{0,0,0,1}},
8083
		{{1,0,1,1},{1,1,0,1},{0,0,0,1}},
8084
		{{1,1,0,0},{0,0,0,0},{0,0,0,0}},
8085
		{{1,1,0,0},{0,0,0,1},{0,0,0,1}},
8086
		{{1,1,0,0},{0,0,1,0},{0,0,1,0}},
8087
		{{1,1,0,0},{0,0,1,1},{0,0,1,1}},
8088
		{{1,1,0,0},{0,1,0,0},{0,0,1,0}},
8089
		{{1,1,0,0},{0,1,1,0},{0,0,1,0}},
8090
		{{1,1,0,0},{1,0,0,1},{1,1,0,1}},
8091
		{{1,1,0,0},{1,0,1,0},{0,0,1,0}},
8092
		{{1,1,0,0},{1,0,1,1},{0,0,0,1}},
8093
		{{1,1,0,0},{1,1,0,0},{1,1,0,0}},
8094
		{{1,1,0,0},{1,1,0,1},{1,1,0,1}},
8095
		{{1,1,0,1},{0,0,0,0},{0,0,0,1}},
8096
		{{1,1,0,1},{0,0,0,1},{0,0,0,1}},
8097
		{{1,1,0,1},{0,0,1,0},{0,0,1,1}},
8098
		{{1,1,0,1},{0,0,1,1},{0,0,1,1}},
8099
		{{1,1,0,1},{0,1,0,0},{0,0,1,1}},
8100
		{{1,1,0,1},{0,1,1,0},{0,0,1,1}},
8101
		{{1,1,0,1},{1,0,0,1},{1,1,0,1}},
8102
		{{1,1,0,1},{1,0,1,0},{0,0,1,1}},
8103
		{{1,1,0,1},{1,0,1,1},{0,0,0,1}},
8104
		{{1,1,0,1},{1,1,0,0},{1,1,0,1}},
8105
		{{1,1,0,1},{1,1,0,1},{1,1,0,1}}
8106
	};
8107
	int failures = 0;
8108
	long start;
8109
	if (combinationTestsloopsNb > 1) {
8110
		start = System.currentTimeMillis();
8111
	}
8112
	String header = "mergedWith failures: ";
8113
	for (int l = 0; l < combinationTestsloopsNb ; l++) {
8114
		for (int i = 0; i < testData.length; i++) {
8115
			UnconditionalFlowInfoTestHarness result;
8116
			if (!(result = (UnconditionalFlowInfoTestHarness)
8117
					UnconditionalFlowInfoTestHarness.
8118
						testUnconditionalFlowInfo(testData[i][0]).
8119
							mergedWith(
8120
								UnconditionalFlowInfoTestHarness.
8121
									testUnconditionalFlowInfo(testData[i][1]))).
8122
					testEquals(UnconditionalFlowInfoTestHarness.
8123
						testUnconditionalFlowInfo(testData[i][2]))) {
8124
				if (failures == 0) {
8125
					System.out.println(header);
8126
				}
8127
				failures++;
8128
				System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
8129
					',' + testStringValueOf(testData[i][1]) +
8130
					',' + result.testString() + 
8131
					"}, // instead of: " + testStringValueOf(testData[i][2]));
8132
			}
8133
		}
1576
	}
8134
	}
1577
8135
	if (combinationTestsloopsNb > 1) {
1578
	// null analysis - try/catch
8136
		System.out.println("mergedWith\t\t\t" + combinationTestsloopsNb + "\t" + 
1579
	public void test0172_try_catch() {
8137
				(System.currentTimeMillis() - start));
1580
		this.runNegativeTest(
8138
	}
1581
			new String[] {
8139
	UnconditionalFlowInfoTestHarness 
1582
				"X.java",
8140
		zero = UnconditionalFlowInfoTestHarness.
1583
				"public class X {\n" + 
8141
				testUnconditionalFlowInfo(new long[] {0,0,0,0}),
1584
				"	 boolean dummy;\n" + 
8142
		left1, right1, left2, right2, 
1585
				"	 void foo() throws Exception {\n" + 
8143
		expected1, expected2, result;
1586
				"		 Object o = new Object();\n" + 
8144
	for (int i = 0; i < testData.length; i++) {
1587
				"		 try {\n" + 
8145
		left1 = UnconditionalFlowInfoTestHarness.
1588
				"			 if (dummy) {\n" + 
8146
				testUnconditionalFlowInfo(testData[i][0], 64);
1589
				"			   o = null;\n" + 
8147
		left2 = UnconditionalFlowInfoTestHarness.
1590
				"			   throw new Exception();\n" + 
8148
			testUnconditionalFlowInfo(testData[i][0], 128);
1591
				"			 }\n" + 
8149
		right1 = UnconditionalFlowInfoTestHarness.
1592
				"		 }\n" + 
8150
				testUnconditionalFlowInfo(testData[i][1], 64);
1593
				"		 catch (Exception e) {\n" + 
8151
		right2 = UnconditionalFlowInfoTestHarness.
1594
				"		 }\n" + 
8152
				testUnconditionalFlowInfo(testData[i][1], 128);
1595
				"		 if (o != null) {\n" +
8153
		expected1 = UnconditionalFlowInfoTestHarness.
1596
				  // quiet: get out of try either through normal flow, leaves a new
8154
				testUnconditionalFlowInfo(testData[i][2], 64);
1597
				  // object, or through Exception, leaves a null 
8155
		expected2 = UnconditionalFlowInfoTestHarness.
1598
				"		 }\n" + 
8156
			testUnconditionalFlowInfo(testData[i][2], 128);
1599
				"	 }\n" + 
8157
		if (!(result = (UnconditionalFlowInfoTestHarness) 
1600
				"}\n"},
8158
				left1.copy().mergedWith(right1)).testEquals(expected1)) {
1601
			""
8159
			if (failures == 0) {
1602
		);
8160
				System.out.println(header);
8161
			}
8162
			failures++;
8163
			System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
8164
				',' + testStringValueOf(testData[i][1]) +
8165
				',' + result.testString() + 
8166
				"}, // (64, 64) - instead of: " + testStringValueOf(testData[i][2]));
8167
		}
8168
		if (testData[i][0][0] + testData[i][0][1] + 
8169
				testData[i][0][2] + testData[i][0][3] == 0) {
8170
			if (!(result = (UnconditionalFlowInfoTestHarness) 
8171
					zero.copy().mergedWith(right1)).testEquals(expected1)) {
8172
				if (failures == 0) {
8173
					System.out.println(header);
8174
				}
8175
				failures++;
8176
				System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
8177
					',' + testStringValueOf(testData[i][1]) +
8178
					',' + result.testString() + 
8179
					"}, // (zero, 64) - instead of: " + testStringValueOf(testData[i][2]));
8180
			}
8181
			if (!(result = (UnconditionalFlowInfoTestHarness)
8182
					right2.copy().mergedWith(right1)).
8183
						testEquals(expected1, 64)) {
8184
				if (failures == 0) {
8185
					System.out.println(header);
8186
				}
8187
				failures++;
8188
				System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
8189
					',' + testStringValueOf(testData[i][1]) +
8190
					',' + result.testString() + 
8191
					"}, // (zero 128, 64) - instead of: " + testStringValueOf(testData[i][2]));
8192
			}
8193
			if (!(result = (UnconditionalFlowInfoTestHarness)
8194
					zero.copy().mergedWith(right2)).
8195
						testEquals(expected2, 128)) {
8196
				if (failures == 0) {
8197
					System.out.println(header);
8198
				}
8199
				failures++;
8200
				System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
8201
					',' + testStringValueOf(testData[i][1]) +
8202
					',' + result.testString() + 
8203
					"}, // (zero, 128) - instead of: " + testStringValueOf(testData[i][2]));
8204
			}
8205
			if (!(result = (UnconditionalFlowInfoTestHarness)
8206
					right1.copy().mergedWith(right2)).
8207
						testEquals(expected2, 128)) {
8208
				if (failures == 0) {
8209
					System.out.println(header);
8210
				}
8211
				failures++;
8212
				System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
8213
					',' + testStringValueOf(testData[i][1]) +
8214
					',' + result.testString() + 
8215
					"}, // (zero 64, 128) - instead of: " + testStringValueOf(testData[i][2]));
8216
			}
8217
		}
8218
		if (testData[i][1][0] + testData[i][1][1] + 
8219
				testData[i][1][2] + testData[i][1][3] == 0) {
8220
			if (!(result = (UnconditionalFlowInfoTestHarness) 
8221
					left1.copy().mergedWith(zero)).testEquals(expected1)) {
8222
				if (failures == 0) {
8223
					System.out.println(header);
8224
				}
8225
				failures++;
8226
				System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
8227
					',' + testStringValueOf(testData[i][1]) +
8228
					',' + result.testString() + 
8229
					"}, // (64, zero) - instead of: " + testStringValueOf(testData[i][2]));
8230
			}
8231
			if (!(result = (UnconditionalFlowInfoTestHarness)
8232
					left1.mergedWith(left2)).
8233
						testEquals(expected1, 64)) {
8234
				if (failures == 0) {
8235
					System.out.println(header);
8236
				}
8237
				failures++;
8238
				System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
8239
					',' + testStringValueOf(testData[i][1]) +
8240
					',' + result.testString() + 
8241
					"}, // (64, zero 128) - instead of: " + testStringValueOf(testData[i][2]));
8242
			}
8243
			if (!(result = (UnconditionalFlowInfoTestHarness) 
8244
					left2.copy().mergedWith(zero)).
8245
						testEquals(expected2, 128)) {
8246
				if (failures == 0) {
8247
					System.out.println(header);
8248
				}
8249
				failures++;
8250
				System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
8251
					',' + testStringValueOf(testData[i][1]) +
8252
					',' + result.testString() + 
8253
					"}, // (128, zero) - instead of: " + testStringValueOf(testData[i][2]));
8254
			}
8255
			if (!(result = (UnconditionalFlowInfoTestHarness) 
8256
					left2.mergedWith(left1)).
8257
						testEquals(expected2, 128)) {
8258
				if (failures == 0) {
8259
					System.out.println(header);
8260
				}
8261
				failures++;
8262
				System.out.println("\t\t{" + testStringValueOf(testData[i][0]) + 
8263
					',' + testStringValueOf(testData[i][1]) +
8264
					',' + result.testString() + 
8265
					"}, // (128, zero 64) - instead of: " + testStringValueOf(testData[i][2]));
8266
			}
8267
		}
8268
	}
8269
	if (printTablesAsNames) {
8270
		System.out.println("RECAP TABLE FOR MERGE");
8271
		for (int i = 0; i < testData.length; i++) {
8272
			System.out.println(testSymbolicValueOf(testData[i][0]) + " + " +
8273
				testSymbolicValueOf(testData[i][1]) + " -> " +
8274
				testSymbolicValueOf(testData[i][2]));
8275
		}
8276
		
1603
	}
8277
	}
1604
8278
	if (printTablesAsCodes) {
1605
	// null analysis - try/catch
8279
		System.out.println("RECAP TABLE FOR MERGE");
1606
	public void test0173_try_catch() {
8280
		for (int i = 0; i < testData.length; i++) {
1607
		this.runNegativeTest(
8281
			System.out.println(testCodedValueOf(testData[i][0]) + " " +
1608
			new String[] {
8282
				testCodedValueOf(testData[i][1]) + " " +
1609
				"X.java",
8283
				testCodedValueOf(testData[i][2]));
1610
				"public class X {\n" + 
8284
		}
1611
				"	 boolean dummy, other;\n" + 
1612
				"	 void foo() {\n" + 
1613
				"		 Object o = new Object();\n" + 
1614
				"		 try {\n" + 
1615
				"			 if (dummy) {\n" + 
1616
				"			   if (other) {\n" + 
1617
				"			     throw new LocalException();\n" + // may launch new exception
1618
				"			   }\n" + 
1619
				"			   o = null;\n" + 
1620
				"			   throw new LocalException();\n" + // must launch new exception
1621
				"			 }\n" + 
1622
				"		 }\n" + 
1623
				"		 catch (LocalException e) {\n" + 
1624
				"			 o.toString();\n" +
1625
				 	// quiet: don't know the exact state when exception is launched
1626
				"		 }\n" + 
1627
				"	 }\n" + 
1628
				"	 class LocalException extends Exception {\n" + 
1629
				"		 private static final long serialVersionUID = 1L;\n" + 
1630
				"	 }\n" + 
1631
				"}\n"},
1632
			""
1633
		);
1634
	}
8285
	}
1635
8286
	if (printTruthMaps) {
1636
	// null analysis - try/catch
8287
		for (int i = 0; i < 4; i++) {
1637
	// REVIEW the following series of try catch tests all relate to the finer
8288
			System.out.println("======================================================");
1638
	//        analysis of possible exception paths; such analysis
8289
			System.out.println("Truth map for mergedWith null bit " + (i + 1));
1639
	//        calls for a supplementary context for each condition
8290
			System.out.println();
1640
	//        (so as to sort out certain paths from hypothetical
8291
		}
1641
	//        ones), which is due to be expensive.
1642
	// TODO (maxime) fix
1643
	public void _test0174_try_catch() {
1644
		this.runNegativeTest(
1645
			new String[] {
1646
				"X.java",
1647
				"public class X {\n" + 
1648
				"	 void foo(Object o) throws Exception {\n" + 
1649
				"		 try {\n" + 
1650
				"		   o = null;\n" + 
1651
				"		   throwLocalException();\n" + 
1652
				"		   throw new Exception();\n" + 
1653
				"		 }\n" + 
1654
				"		 catch (LocalException e) {\n" + 
1655
				"		 }\n" + 
1656
				"		 if (o != null) {\n" +
1657
				 	// complain: only way to get out of try and get there is to go
1658
					// through throwLocalException, after the assignment 
1659
				"		 }\n" + 
1660
				"	 }\n" + 
1661
				"	 class LocalException extends Exception {\n" + 
1662
				"		 private static final long serialVersionUID = 1L;\n" + 
1663
				"	 }\n" + 
1664
				"	 void throwLocalException() throws LocalException {\n" + 
1665
				"		 throw new LocalException();\n" + 
1666
				"	 }\n" + 
1667
				"}\n"},
1668
			"WARN"
1669
		);
1670
	}
8292
	}
8293
	assertTrue("nb of failures: " + failures, failures == 0);
8294
}
1671
8295
1672
	// null analysis - try/catch
8296
// Use for coverage tests only. Needs specific instrumentation of code,
1673
	// TODO (maxime) fix
8297
// that is controled by UnconditionalFlowInfo#coverageTestFlag.
1674
	public void _test0175_try_catch() {
8298
// Note: coverage tests tend to fill the console with messages, and the
1675
		this.runNegativeTest(
8299
//       instrumented code is slower, so never release code with active
1676
			new String[] {
8300
//       coverage tests.
1677
				"X.java",
8301
private static int coveragePointsNb = 46;
1678
				"public class X {\n" + 
8302
1679
				"	 void foo() {\n" + 
8303
// Coverage by state transition tables methods.
1680
				"	   Object o = new Object();\n" + 
8304
public void test2998_coverage() {
1681
				"		 try {\n" + 
8305
	if (UnconditionalFlowInfo.coverageTestFlag) {
1682
				"		   o = null;\n" + 
8306
		// sanity check: need to be sure that the tests execute properly when not
1683
				"		   throwException();\n" + 
8307
		// trying to check coverage
1684
				"		 }\n" + 
8308
		UnconditionalFlowInfo.coverageTestId = 0;
1685
				"		 catch (Exception e) {\n" + 
8309
		test0053_array();
1686
				"			 o.toString();\n" +
8310
		test0070_type_reference();
1687
				  // complain: know o is null despite the lack of a definite assignment
8311
		test2050_markAsComparedEqualToNonNull();
1688
				"		 }\n" + 
8312
		test2051_markAsComparedEqualToNull();
1689
				"	 }\n" + 
8313
		test2052_markAsDefinitelyNonNull();
1690
				"	 void throwException() throws Exception {\n" + 
8314
		test2053_markAsDefinitelyNull();
1691
				"		 throw new Exception();\n" + 
8315
		test2054_markAsDefinitelyUnknown();
1692
				"	 }\n" + 
8316
		test2055_addInitializationsFrom();
1693
				"}\n"},
8317
		test2056_addPotentialInitializationsFrom();
1694
			"WARN"
8318
		test2057_mergedWith();
1695
		);
8319
		// coverage check
8320
		int failuresNb = 0;
8321
		for (int i = 1; i <= coveragePointsNb; i++) {
8322
			try {
8323
				UnconditionalFlowInfo.coverageTestId = i;
8324
				test0053_array();
8325
				test0070_type_reference();
8326
				test2050_markAsComparedEqualToNonNull();
8327
				test2051_markAsComparedEqualToNull();
8328
				test2052_markAsDefinitelyNonNull();
8329
				test2053_markAsDefinitelyNull();
8330
				test2054_markAsDefinitelyUnknown();
8331
				test2055_addInitializationsFrom();
8332
				test2056_addPotentialInitializationsFrom();
8333
				test2057_mergedWith();
8334
			}
8335
			catch (AssertionFailedError e) {
8336
				continue;
8337
			}
8338
			catch (AssertionFailedException e) {
8339
				continue;
8340
			}
8341
			failuresNb++;
8342
			System.out.println("Missing coverage point: " + i);
8343
		}
8344
		UnconditionalFlowInfo.coverageTestId = 0; // reset for other tests
8345
		assertEquals(failuresNb + " missing coverage point(s)", failuresNb, 0);
1696
	}
8346
	}
8347
}
1697
8348
1698
	// null analysis - try/catch
8349
// Coverage by code samples.
1699
	// TODO (maxime) fix
8350
public void test2999_coverage() {
1700
	public void _test0176_try_catch() {
8351
	if (UnconditionalFlowInfo.coverageTestFlag) {
1701
		this.runNegativeTest(
8352
		// sanity check: need to be sure that the tests execute properly when not
1702
			new String[] {
8353
		// trying to check coverage
1703
				"X.java",
8354
		UnconditionalFlowInfo.coverageTestId = 0;
1704
				"public class X {\n" + 
8355
		test0001_simple_local();
1705
				"	 void foo() {\n" + 
8356
		test0053_array();
1706
				"		 Object o = new Object();\n" + 
8357
		test0070_type_reference();
1707
				"		 try {\n" + 
8358
		test0327_if_else();
1708
				"		   o = null;\n" + 
8359
		test0401_while();
1709
				"		   throwException();\n" + 
8360
		test0420_while();
1710
				"		 }\n" + 
8361
		test0509_try_finally_embedded();
1711
				"		 catch (Throwable t) {\n" + 
8362
		test2000_flow_info();
1712
				"			 o.toString();\n" +
8363
		test2004_flow_info();
1713
				  // complain: know o is null despite the lack of a definite assignment
8364
		test2008_flow_info();
1714
				"		 }\n" + 
8365
		test2011_flow_info();
1715
				"	 }\n" + 
8366
		test2013_flow_info();
1716
				"  void throwException() throws Exception {\n" + 
8367
		test2018_flow_info();
1717
				"		 throw new Exception();\n" + 
8368
		test2019_flow_info();
1718
				"	 }\n" + 
8369
		test2020_flow_info();
1719
				"}\n"},
8370
		// coverage check
1720
			"WARN"
8371
		int failuresNb = 0;
1721
		);
8372
		for (int i = 1; i <= coveragePointsNb; i++) {
8373
			if (i > 4 && i < 15 ||
8374
				i > 15 && i < 19 ||
8375
				i == 22 ||
8376
				i == 23 ||
8377
				i == 27 ||
8378
				i == 28 ||
8379
				i == 30 ||
8380
				i == 33 ||
8381
				i == 34 ||
8382
				i == 38 ||
8383
				i >= 43
8384
				) { // TODO (maxime) complete coverage tests
8385
				continue;
8386
			}
8387
			try {
8388
				UnconditionalFlowInfo.coverageTestId = i;
8389
				test0001_simple_local();
8390
				test0053_array();
8391
				test0070_type_reference();
8392
				test0327_if_else();
8393
				test0401_while();
8394
				test0420_while();
8395
				test0509_try_finally_embedded();
8396
				test2000_flow_info();
8397
				test2004_flow_info();
8398
				test2008_flow_info();
8399
				test2011_flow_info();
8400
				test2013_flow_info();
8401
				test2018_flow_info();
8402
				test2019_flow_info();
8403
				test2020_flow_info();
8404
			}
8405
			catch (AssertionFailedError e) {
8406
				continue;
8407
			}
8408
			catch (AssertionFailedException e) {
8409
				continue;
8410
			}
8411
			failuresNb++;
8412
			System.out.println("Missing coverage point: " + i);
8413
		}
8414
		UnconditionalFlowInfo.coverageTestId = 0; // reset for other tests
8415
		assertEquals(failuresNb + " missing coverage point(s)", failuresNb, 0);
1722
	}
8416
	}
8417
}
1723
8418
1724
	// null analysis - try/catch
8419
// only works for info coded on bit 0 - least significant
1725
	// TODO (maxime) fix
8420
String testCodedValueOf(long[] data) {
1726
	public void _test0177_try_catch() {
8421
	StringBuffer result = new StringBuffer(4);
1727
		this.runNegativeTest(
8422
	for (int i = 0; i < data.length; i++) {
1728
			new String[] {
8423
		result.append(data[i] == 0 ? '0' : '1');
1729
				"X.java",
1730
				"public class X {\n" + 
1731
				"	 boolean dummy;\n" + 
1732
				"	 void foo() {\n" + 
1733
				"		 Object o = new Object();\n" + 
1734
				"		 try {\n" + 
1735
				"			 if (dummy) {\n" + 
1736
				"			   o = null;\n" + 
1737
				"			   throw new Exception();\n" + 
1738
				"			 }\n" + 
1739
				"		 }\n" + 
1740
				"		 catch (Exception e) {\n" + 
1741
				"			 o.toString();\n" +
1742
				 	// complain: know o is null despite the lack of definite assignment
1743
				"		 }\n" + 
1744
				"	 }\n" + 
1745
				"}\n"},
1746
			"WARN"
1747
		);
1748
	}
8424
	}
8425
	return result.toString();
8426
}
1749
8427
1750
	// null analysis - try/catch
8428
String testStringValueOf(long[] data) {
1751
	// TODO (maxime) fix
8429
	StringBuffer result = new StringBuffer(9);
1752
	public void _test0178_try_catch() {
8430
	result.append('{');
1753
		this.runNegativeTest(
8431
	for (int j = 0; j < 4; j++) {
1754
			new String[] {
8432
		if (j > 0) {
1755
				"X.java",
8433
			result.append(',');
1756
				"public class X {\n" + 
8434
		}
1757
				"	 boolean dummy;\n" + 
8435
		result.append(data[j]);
1758
				"	 void foo() {\n" + 
1759
				"		 Object o = new Object();\n" + 
1760
				"		 try {\n" + 
1761
				"			 if (dummy) {\n" + 
1762
				"			   System.out.print(0);\n" + // may thow RuntimeException 
1763
				"			   o = null;\n" + 
1764
				"			   throw new LocalException();\n" + 
1765
				"			 }\n" + 
1766
				"		 }\n" + 
1767
				"		 catch (LocalException e) {\n" + // doesn't catch RuntimeException
1768
				"			 o.toString();\n" +
1769
				 	// complain: know o is null despite the lack of definite assignment
1770
				"		 }\n" + 
1771
				"	 }\n" + 
1772
				"	 class LocalException extends Exception {\n" + 
1773
				"		 private static final long serialVersionUID = 1L;\n" + 
1774
				"	 }\n" + 
1775
				"}\n"},
1776
			"WARN"
1777
		);
1778
	}
8436
	}
8437
	result.append('}');
8438
	return result.toString();
8439
}
1779
8440
1780
	// null analysis - try/catch
8441
String testStringValueOf(long[][] data) {
1781
	// TODO (maxime) fix
8442
	StringBuffer result = new StringBuffer(25);
1782
	public void _test0179_try_catch() {
8443
	result.append('{');
1783
		this.runNegativeTest(
8444
	for (int i = 0; i < 3; i++) {
1784
			new String[] {
8445
		if (i > 0) {
1785
				"X.java",
8446
			result.append(',');
1786
				"public class X {\n" + 
8447
		}
1787
				"	 boolean dummy;\n" + 
8448
		result.append('{');
1788
				"	 void foo() {\n" + 
8449
		for (int j = 0; j < 4; j++) {
1789
				"		 Object o = new Object();\n" + 
8450
			if (j > 0) {
1790
				"		 try {\n" + 
8451
				result.append(',');
1791
				"			 if (dummy) {\n" + 
8452
			}
1792
				"			   o = null;\n" + 
8453
			result.append(data[i][j]);
1793
				"			   throw new SubException();\n" + 
8454
		}
1794
				"			 }\n" + 
8455
		result.append('}');
1795
				"		 }\n" + 
1796
				"		 catch (LocalException e) {\n" + // must catch SubException
1797
				"			 o.toString();\n" +
1798
				 	// complain: know o is null despite the lack of definite assignment
1799
				"		 }\n" + 
1800
				"	 }\n" + 
1801
				"	 class LocalException extends Exception {\n" + 
1802
				"		 private static final long serialVersionUID = 1L;\n" + 
1803
				"	 }\n" + 
1804
				"	 class SubException extends LocalException {\n" + 
1805
				"		 private static final long serialVersionUID = 1L;\n" + 
1806
				"	 }\n" + 
1807
				"}\n"},
1808
			"WARN"
1809
		);
1810
	}
1811
	
1812
	// null analysis -- do while
1813
	// TODO (maxime) fix
1814
	public void _test0201_do_while() {
1815
		this.runNegativeTest(
1816
			new String[] {
1817
				"X.java",
1818
				"public class X {\n" + 
1819
				"	 void foo() {\n" + 
1820
				"		 Object o = null;\n" + 
1821
				"		 do {/* */}\n" +
1822
				"		 while (o.toString() != null);\n" +
1823
				      // complain: NPE
1824
				"	 }\n" + 
1825
				"}\n"},
1826
			"----------\n" + 
1827
			"1. WARNING in X.java (at line 5)\n" + 
1828
			"	while (o.toString() != null);\n" + 
1829
			"	       ^\n" + 
1830
			"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
1831
			"----------\n"
1832
		);
1833
	}
8456
	}
8457
	result.append('}');
8458
	return result.toString();
8459
}
1834
8460
1835
	// null analysis -- do while
8461
// only works for info coded on bit 0 - least significant
1836
	// TODO (maxime) fix
8462
String testSymbolicValueOf(long[] data) {
1837
	public void _test0202_do_while() {
8463
	if (data[0] == 0) {
1838
		this.runNegativeTest(
8464
		if (data[1] == 0) {
1839
			new String[] {
8465
			if (data[2] == 0) {
1840
				"X.java",
8466
				if (data[3] == 0) {
1841
				"public class X {\n" + 
8467
					return "start                 "; //$NON-NLS1$
1842
				"	 void foo() {\n" + 
8468
				}
1843
				"		 Object o = null;\n" + 
8469
				else {
1844
				"		 do {/* */}\n" + 
8470
					return "pot. nn/unknown       "; //$NON-NLS1$
1845
				"		 while (o != null);\n" + 
8471
				}
1846
				  // complain: get o null first time and forever
8472
			}
1847
				"	 }\n" + 
8473
			else {
1848
				"}\n"},
8474
				if (data[3] == 0) {
1849
			"----------\n" + 
8475
					return "pot. null             "; //$NON-NLS1$
1850
			"1. WARNING in X.java (at line 5)\n" + 
8476
				}
1851
			"	while (o != null);\n" + 
8477
				else {
1852
			"	       ^\n" + 
8478
					return "pot. n/nn/unkn.       "; //$NON-NLS1$
1853
			"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
8479
				}
1854
			"----------\n"
8480
			}
1855
		);
8481
		}
8482
		else {
8483
			if (data[2] == 0) {
8484
				if (data[3] == 0) {
8485
					return "prot. null            "; //$NON-NLS1$
8486
				}
8487
				else {
8488
					return "0101                  "; //$NON-NLS1$
8489
				}
8490
			}
8491
			else {
8492
				if (data[3] == 0) {
8493
					return "prot. null + pot. null"; //$NON-NLS1$
8494
				}
8495
				else {
8496
					return "0111                  "; //$NON-NLS1$
8497
				}
8498
			}
8499
		}
1856
	}
8500
	}
1857
8501
	else {
1858
	// null analysis -- do while
8502
		if (data[1] == 0) {
1859
	// TODO (maxime) fix
8503
			if (data[2] == 0) {
1860
	public void _test0203_do_while() {
8504
				if (data[3] == 0) {
1861
		this.runNegativeTest(
8505
					return "1000                  "; //$NON-NLS1$
1862
			new String[] {
8506
				}
1863
				"X.java",
8507
				else {
1864
				"public class X {\n" + 
8508
					return "assigned non null     "; //$NON-NLS1$
1865
				"	 void foo() {\n" + 
8509
				}
1866
				"		 Object o = null;\n" + 
8510
			}
1867
				"		 do {\n" + 
8511
			else {
1868
				"		   o = new Object();\n" + 
8512
				if (data[3] == 0) {
1869
				"		 }\n" + 
8513
					return "assigned null         "; //$NON-NLS1$
1870
				"		 while (o == null);\n" + 
8514
				}
1871
				      // complain: set it to non null before test, for each iteration
8515
				else {
1872
				"	 }\n" + 
8516
					return "assigned unknown      "; //$NON-NLS1$
1873
				"}\n"},
8517
				}
1874
			"----------\n" + 
8518
			}
1875
			"1. WARNING in X.java (at line 7)\n" + 
8519
		}
1876
			"	while (o == null);\n" + 
8520
		else {
1877
			"	       ^\n" + 
8521
			if (data[2] == 0) {
1878
			"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
8522
				if (data[3] == 0) {
1879
			"----------\n"
8523
					return "protected non null    "; //$NON-NLS1$
1880
		);
8524
				}
8525
				else {
8526
					return "prot. nn + pot. nn/unknown"; //$NON-NLS1$
8527
				}
8528
			}
8529
			else {
8530
				if (data[3] == 0) {
8531
					return "1110                  "; //$NON-NLS1$
8532
				}
8533
				else {
8534
					return "1111                  "; //$NON-NLS1$
8535
				}
8536
			}
8537
		}
1881
	}
8538
	}
8539
}
1882
8540
1883
	// null analysis -- do while
8541
private void printTruthMap(long data[][][], int bit) {
1884
	public void test0204_do_while() {
8542
	final int dimension = 16;
1885
		this.runNegativeTest(
8543
	printTruthMapHeader();
1886
			new String[] {
8544
	char truthValues[][] = new char[dimension][dimension];
1887
				"X.java",
8545
	int row, column;
1888
				"public class X {\n" + 
8546
	for (row = 0; row < dimension; row++) {
1889
				"	 void foo() {\n" + 
8547
		for (column = 0; column < dimension; column++) {
1890
				"		 Object o = null;\n" + 
8548
			truthValues[row][column] = '.';
1891
				"		 do {\n" + 
8549
		}
1892
				"		   if (System.currentTimeMillis() > 10L) {\n" + 
1893
				"		     o = new Object();\n" + 
1894
				"		   }\n" + 
1895
				"		 }\n" + 
1896
				"		 while (o == null);\n" + 
1897
				"	 }\n" + 
1898
				"}\n"},
1899
			""  
1900
		);
1901
	}
8550
	}
1902
8551
	String rows[] = {
1903
	// null analysis -- do while
8552
		"0000",
1904
	// TODO (maxime) fix
8553
		"0001",
1905
	public void _test0205_do_while() {
8554
		"0011",
1906
		this.runNegativeTest(
8555
		"0111",
1907
			new String[] {
8556
		"1111",
1908
				"X.java",
8557
		"1110",
1909
				"public class X {\n" + 
8558
		"1100",
1910
				"	 boolean dummy;\n" + 
8559
		"1000",
1911
				"	 void foo(Object o) {\n" + 
8560
		"1010",
1912
				"	   o = null;\n" +
8561
		"1011",
1913
				"		 do {\n" +
8562
		"1001",
1914
				"		   // do nothing\n" +
8563
		"1101",
1915
				"		 }\n" + 
8564
		"0101",
1916
				"		 while (dummy || o != null);\n" + 
8565
		"0100",
1917
				"	 }\n" + 
8566
		"0110",
1918
				"}\n"},
8567
		"0010"
1919
			"----------\n" + 
8568
	};
1920
			"1. WARNING in X.java (at line 8)\n" + 
8569
	if (false) { // checking row names
1921
			"	while (dummy || o != null);\n" + 
8570
		for (row = 0; row < dimension; row++) {
1922
			"	                    ^\n" + 
8571
			long [] state = new long [4];
1923
			"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
8572
			for (int i = 0; i < 4; i++) {
1924
			"----------\n"
8573
				state[i] = rows[row].charAt(i) - '0';
1925
		);
8574
			}
8575
			System.out.println(row + " " + rows[row] + " " + rankForState(state));
8576
		}
1926
	}
8577
	}
1927
8578
	for (int i = 0; i < data.length; i++) {
1928
	// null analysis -- do while
8579
		truthValues[rankForState(data[i][0])][rankForState(data[i][1])] =
1929
	// TODO (maxime) fix
8580
			(char) ('0' + data[i][2][bit]);
1930
	public void _test0206_do_while() {
8581
	}
1931
		this.runNegativeTest(
8582
	for (row = 0; row < dimension; row++) {
1932
			new String[] {
8583
		StringBuffer line = new StringBuffer(120);
1933
				"X.java",
8584
		line.append(rows[row]);
1934
				"public class X {\n" + 
8585
		line.append(" | ");
1935
				"	 void foo() {\n" + 
8586
		for (column = 0; column < dimension; column++) {
1936
				"		 Object o = null,\n" + 
8587
			line.append(truthValues[row][column]);
1937
				"		        u = new Object(),\n" + 
8588
			line.append(' ');
1938
				"		        v = new Object();\n" + 
8589
		}
1939
				"		 do {\n" +
8590
		System.out.println(line);
1940
				"		   if (v == null) {\n" +
1941
				"		     o = new Object();\n" +
1942
				"		   };\n" +
1943
				"		   if (u == null) {\n" +
1944
				"		     v = null;\n" +
1945
				"		   };\n" +
1946
				"		   u = null;\n" +
1947
				"		 }\n" +
1948
				"		 while (o == null);\n" +
1949
				"	 }\n" + 
1950
				"}\n"},
1951
			""  
1952
		);
1953
	}
8591
	}
8592
}
1954
8593
1955
	// null analysis -- do while
8594
private void printTruthMapHeader() {
1956
	// TODO (maxime) fix
8595
	System.out.println("       0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0");
1957
	public void _test0207_do_while() {
8596
	System.out.println("       0 0 0 1 1 1 1 0 0 0 0 1 1 1 1 0");
1958
		this.runNegativeTest(
8597
	System.out.println("       0 0 1 1 1 1 0 0 1 1 0 0 0 0 1 1");
1959
			new String[] {
8598
	System.out.println("       0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0");
1960
				"X.java",
8599
	System.out.println("      --------------------------------");
1961
				"public class X {\n" + 
8600
}
1962
				"	 boolean dummy;\n" + 
1963
				"	 void foo() {\n" + 
1964
				"		 Object o = null;\n" + 
1965
				"		 do {\n" + 
1966
				"		   o.toString();\n" + 
1967
				      	 // complain: NPE on first iteration 
1968
				"		   o = new Object();\n" + 
1969
				"		 }\n" + 
1970
				"		 while (dummy);\n" + 
1971
				"	 }\n" + 
1972
				"}\n"},
1973
			"WARN"  
1974
		);
1975
	}
1976
8601
1977
	// null analysis -- do while
8602
private int rankForState(long [] state) {
1978
	// TODO (maxime) fix
8603
	if (state[0] == 0) {
1979
	public void _test0208_do_while() {
8604
		if (state[1] == 0) {
1980
		this.runNegativeTest(
8605
			if (state[2] == 0) {
1981
			new String[] {
8606
				if (state[3] == 0) {
1982
				"X.java",
8607
					return 0; 	// 0000
1983
				"public class X {\n" + 
8608
				}
1984
				"	 boolean dummy;\n" + 
8609
				else {
1985
				"	 void foo() {\n" + 
8610
					return 1; 	// 0001
1986
				"		 Object o = null;\n" + 
8611
				}
1987
				"		 do {\n" + 
8612
			}
1988
				"		   o = new Object();\n" + 
8613
			else {
1989
				"		 }\n" + 
8614
				if (state[3] == 0) {
1990
				"		 while (dummy);\n" + 
8615
					return 15;	// 0010
1991
				"		 o.toString();\n" + 
8616
				}
1992
				"	 }\n" + 
8617
				else {
1993
				"}\n"},
8618
					return 2;	// 0011
1994
			""  
8619
				}
1995
		);
8620
			}
8621
		}
8622
		else {
8623
			if (state[2] == 0) {
8624
				if (state[3] == 0) {
8625
					return 13;	// 0100
8626
				}
8627
				else {
8628
					return 12;	// 0101
8629
				}
8630
			}
8631
			else {
8632
				if (state[3] == 0) {
8633
					return 14;	// 0110
8634
				}
8635
				else {
8636
					return 3;	// 0111
8637
				}
8638
			}
8639
		}
1996
	}
8640
	}
1997
	
8641
	else {
1998
	// null analysis -- do while
8642
		if (state[1] == 0) {
1999
	public void test0209_do_while() {
8643
			if (state[2] == 0) {
2000
		this.runNegativeTest(
8644
				if (state[3] == 0) {
2001
			new String[] {
8645
					return 7;	// 1000
2002
				"X.java",
8646
				}
2003
				"public class X {\n" + 
8647
				else {
2004
				"	 boolean dummy;\n" + 
8648
					return 10;	// 1001
2005
				"	 void foo() {\n" + 
8649
				}
2006
				"		 Object o = null;\n" + 
8650
			}
2007
				"		 do { /* */ }\n" + 
8651
			else {
2008
				"		 while (dummy);\n" + 
8652
				if (state[3] == 0) {
2009
				"		 o.toString();\n" + 
8653
					return 8;	// 1010
2010
				"	 }\n" + 
8654
				}
2011
				"}\n"},
8655
				else {
2012
			"----------\n" + 
8656
					return 9;	// 1011
2013
			"1. WARNING in X.java (at line 7)\n" + 
8657
				}
2014
			"	o.toString();\n" + 
8658
			}
2015
			"	^\n" + 
8659
		}
2016
			"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
8660
		else {
2017
			"----------\n"
8661
			if (state[2] == 0) {
2018
		);
8662
				if (state[3] == 0) {
8663
					return 6;	// 1100
8664
				}
8665
				else {
8666
					return 11;	// 1101
8667
				}
8668
			}
8669
			else {
8670
				if (state[3] == 0) {
8671
					return 5;	// 1110
8672
				}
8673
				else {
8674
					return 4;	// 1111
8675
				}
8676
			}
8677
		}
2019
	}
8678
	}
8679
}
8680
}
2020
8681
2021
	// null analysis -- for
8682
class TestLocalVariableBinding extends LocalVariableBinding {
2022
	// TODO (maxime) fix
8683
	final static char [] testName = {'t', 'e', 's', 't'};
2023
	public void _test0221_for() {
8684
	TestLocalVariableBinding(int id) {
2024
		this.runNegativeTest(
8685
		super(testName, null, 0, false);
2025
			new String[] {
8686
		this.id = id;
2026
				"X.java",
2027
				"public class X {\n" + 
2028
				"	 void foo() {\n" + 
2029
				"		 Object o = null;\n" + 
2030
				"		 for (;o.toString() != null;) {/* */}\n" +
2031
				      // complain: NPE
2032
				"	 }\n" + 
2033
				"}\n"},
2034
			"----------\n" + 
2035
			"1. WARNING in X.java (at line 4)\n" + 
2036
			"	for (;o.toString() != null;) {/* */}\n" + 
2037
			"	      ^\n" + 
2038
			"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
2039
			"----------\n"
2040
		);
2041
	}
8687
	}
8688
}
2042
8689
2043
	// null analysis -- for
8690
/**
2044
	// TODO (maxime) fix
8691
 * A class meant to augment 
2045
	public void _test0222_for() {
8692
 * @link{org.eclipse.jdt.internal.compiler.flow.UnconditionalFlowInfo} with
2046
		this.runNegativeTest(
8693
 * capabilities in the test domain. It especially provides factories to build
2047
			new String[] {
8694
 * fake flow info instances for use in state transition tables validation.
2048
				"X.java",
8695
 */
2049
				"public class X {\n" + 
8696
class UnconditionalFlowInfoTestHarness extends UnconditionalFlowInfo {
2050
				"	 void foo() {\n" + 
8697
	private int testPosition;
2051
				"		 Object o = null;\n" + 
8698
	
2052
				"		 for (;o != null;) {/* */}\n" + 
8699
/**
2053
				  // complain: get o null first time and forever
8700
 * Return a fake unconditional flow info which bit fields represent the given
2054
				"	 }\n" + 
8701
 * null bits for a local variable of id 0 within a class that would have no
2055
				"}\n"},
8702
 * field.
2056
			"----------\n" + 
8703
 * @param nullBits the bits that must be set, given in the same order as the
2057
			"1. WARNING in X.java (at line 4)\n" + 
8704
 *        nullAssignment* fields in UnconditionalFlowInfo definition; use 0
2058
			"	for (;o != null;) {/* */}\n" + 
8705
 *        for a bit that is not set, 1 else
2059
			"	      ^\n" + 
8706
 * @return a fake unconditional flow info which bit fields represent the
2060
			"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
8707
 *         null bits given in parameter
2061
			"----------\n"
8708
 */
2062
		);
8709
public static UnconditionalFlowInfoTestHarness testUnconditionalFlowInfo(
2063
	}
8710
		long [] nullBits) {
8711
	return testUnconditionalFlowInfo(nullBits, 0);
8712
}
2064
8713
2065
	// null analysis -- for
8714
public FlowInfo copy() {
2066
	public void test0223_for() {
8715
	UnconditionalFlowInfoTestHarness copy = 
2067
		this.runNegativeTest(
8716
		new UnconditionalFlowInfoTestHarness();
2068
			new String[] {
8717
	copy.testPosition = this.testPosition;
2069
				"X.java",
8718
	copy.definiteInits = this.definiteInits;
2070
				"public class X {\n" + 
8719
	copy.potentialInits = this.potentialInits;
2071
				"	 void foo() {\n" + 
8720
	boolean hasNullInfo = (this.tagBits & NULL_FLAG_MASK) != 0;
2072
				"		 Object o = null;\n" + 
8721
	if (hasNullInfo) { 
2073
				"		 for (;o == null;) {\n" + 
8722
		copy.nullAssignmentStatusBit1 = this.nullAssignmentStatusBit1;
2074
				      // quiet: first iteration is sure to find it null, 
8723
		copy.nullAssignmentStatusBit2 = this.nullAssignmentStatusBit2;
2075
				      // but other iterations may change it 
8724
		copy.nullAssignmentValueBit1 = this.nullAssignmentValueBit1;
2076
				"		   o = new Object();\n" + 
8725
		copy.nullAssignmentValueBit2 = this.nullAssignmentValueBit2;
2077
				"		 }\n" + 
8726
	}
2078
				"	 }\n" + 
8727
	copy.tagBits = this.tagBits;
2079
				"}\n"},
8728
	copy.maxFieldCount = this.maxFieldCount;
2080
			""  
8729
	if (this.extra != null) {
2081
		);
8730
		int length;
8731
        copy.extra = new long[extraLength][];
8732
		System.arraycopy(this.extra[0], 0, 
8733
			(copy.extra[0] = new long[length = extra[0].length]), 0, length);
8734
		System.arraycopy(this.extra[1], 0, 
8735
			(copy.extra[1] = new long[length]), 0, length);
8736
		if (hasNullInfo) {
8737
            for (int j = 0; j < extraLength; j++) {
8738
			    System.arraycopy(this.extra[j], 0, 
8739
				    (copy.extra[j] = new long[length]), 0, length);
8740
            }
8741
		}
8742
		else {
8743
            for (int j = 0; j < extraLength; j++) {
8744
			    copy.extra[j] = new long[length];
8745
            }
8746
		}
2082
	}
8747
	}
8748
	return copy;
8749
}
2083
8750
2084
	// null analysis -- for
8751
/**
2085
	public void test0224_for() {
8752
 * Return a fake unconditional flow info which bit fields represent the given
2086
		this.runNegativeTest(
8753
 * null bits for a local variable of id position within a class that would have 
2087
			new String[] {
8754
 * no field.
2088
				"X.java",
8755
 * @param nullBits the bits that must be set, given in the same order as the
2089
				"public class X {\n" + 
8756
 *        nullAssignment* fields in UnconditionalFlowInfo definition; use 0
2090
				"	 void foo() {\n" + 
8757
 *        for a bit that is not set, 1 else
2091
				"		 Object o = null;\n" + 
8758
 * @param position the position of the variable within the bit fields; use
2092
				"		 for (;o == null;) {\n" + 
8759
 *        various values to test different parts of the bit fields, within
2093
				     // quiet: first iteration is sure to find it null, 
8760
 *        or beyond BitCacheSize
2094
				     // but other iterations may change it 
8761
 * @return a fake unconditional flow info which bit fields represent the
2095
				"		   if (System.currentTimeMillis() > 10L) {\n" + 
8762
 *         null bits given in parameter
2096
				"		     o = new Object();\n" + 
8763
 */
2097
				"		   }\n" + 
8764
public static UnconditionalFlowInfoTestHarness testUnconditionalFlowInfo(
2098
				"		 }\n" + 
8765
		long [] nullBits, int position) {
2099
				"	 }\n" + 
8766
 	UnconditionalFlowInfoTestHarness result = 
2100
				"}\n"},
8767
 		new UnconditionalFlowInfoTestHarness();
2101
			""  
8768
	result.testPosition = position;
2102
		);
8769
	if (position < BitCacheSize) {
8770
		result.nullAssignmentStatusBit1 = nullBits[0] << position;
8771
		result.nullAssignmentStatusBit2 = nullBits[1] << position;
8772
		result.nullAssignmentValueBit1 = nullBits[2] << position;
8773
		result.nullAssignmentValueBit2 = nullBits[3] << position;
8774
	} 
8775
 	else {
8776
		int vectorIndex = (position / BitCacheSize) - 1,
8777
			length = vectorIndex + 1;
8778
        position %= BitCacheSize;
8779
        result.extra = new long[extraLength][];
8780
		result.extra[0] = new long[length];
8781
		result.extra[1] = new long[length];
8782
        for (int j = 2; j < extraLength; j++) {
8783
		    result.extra[j] = new long[length];
8784
		    result.extra[j][vectorIndex] = nullBits[j - 2] << 
8785
		        position;
8786
        }
2103
	}
8787
	}
2104
8788
	if ((nullBits[0] | nullBits[1] | nullBits[2] | nullBits[3]) != 0) {
2105
	// null analysis -- for
8789
		result.tagBits |= NULL_FLAG_MASK;
2106
	// TODO (maxime) fix
2107
	public void _test0225_for() {
2108
		this.runNegativeTest(
2109
			new String[] {
2110
				"X.java",
2111
				"public class X {\n" + 
2112
				"	 boolean bar() {\n" + 
2113
				"		 return true;\n" + 
2114
				"	 }\n" + 
2115
				"	 void foo(Object o) {\n" + 
2116
				"		 for (;bar() && o == null;) {\n" + 
2117
				"		   o.toString();\n" + // complain: NPE because of condition
2118
				"		   o = new Object();\n" +
2119
				"		 }\n" + 
2120
				"	 }\n" + 
2121
				"}\n"},
2122
			"----------\n" + 
2123
			"1. WARNING in X.java (at line 7)\n" + 
2124
			"	o.toString();\n" + 
2125
			"	^\n" + 
2126
			"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
2127
			"----------\n"
2128
		);
2129
	}
8790
	}
8791
	result.maxFieldCount = 0;
8792
	return result;
8793
}
2130
8794
2131
	// null analysis -- for
8795
/**
2132
	public void test0227_for() {
8796
 * Return a fake unconditional flow info which bit fields represent the given
2133
		this.runNegativeTest(
8797
 * null bits for a pair of local variables of id position and position +
2134
			new String[] {
8798
 * extra * BitCacheSize within a class that would have no field.
2135
				"X.java",
8799
 * @param nullBits the bits that must be set, given in the same order as the
2136
				"public class X {\n" + 
8800
 *        nullAssignment* fields in UnconditionalFlowInfo definition; use 0
2137
				"	 void foo(Object o) {\n" + 
8801
 *        for a bit that is not set, 1 else
2138
				"		 for (;o == null; o.toString()) {\n" + 
8802
 * @param position the position of the variable within the bit fields; use
2139
				"		   o = new Object();\n" +
8803
 *        various values to test different parts of the bit fields, within
2140
				"		 }\n" + 
8804
 *        or beyond BitCacheSize
2141
				"	 }\n" + 
8805
 * @param extra the length of the allocated extra bit fields, if position is 
2142
				"}\n"},
8806
 *        beyond BitCacheSize; unused otherwise; make sure it is big enough to
2143
			""
8807
 *        match position (that is, extra > position - BitCacheSize)
2144
		);
8808
 * @return a fake unconditional flow info which bit fields represent the
8809
 *         null bits given in parameter
8810
 */
8811
public static UnconditionalFlowInfoTestHarness testUnconditionalFlowInfo(
8812
		long [] nullBits, int position, int extra) {
8813
 	UnconditionalFlowInfoTestHarness result = 
8814
 		new UnconditionalFlowInfoTestHarness();
8815
	result.testPosition = position;
8816
	if (position < BitCacheSize) {
8817
		result.nullAssignmentStatusBit1 = nullBits[0] << position;
8818
		result.nullAssignmentStatusBit2 = nullBits[1] << position;
8819
		result.nullAssignmentValueBit1 = nullBits[2] << position;
8820
		result.nullAssignmentValueBit2 = nullBits[3] << position;
8821
	} 
8822
 	else {
8823
		int vectorIndex = (position / BitCacheSize) - 1,
8824
			length = extra / BitCacheSize;
8825
		position %= BitCacheSize;
8826
        result.extra = new long[extraLength][];
8827
		result.extra[0] = new long[length];
8828
		result.extra[1] = new long[length];
8829
        for (int j = 2; j < extraLength; j++) {
8830
		    result.extra[j] = new long[length];
8831
		    result.extra[j] [vectorIndex]= nullBits[j - 2] << position;
8832
        }
8833
	}
8834
	if (nullBits[1] != 0 || nullBits[3] != 0 || nullBits[0] != 0 || nullBits[2] != 0 ) {
8835
		// cascade better than nullBits[0] | nullBits[1] | nullBits[2] | nullBits[3]
8836
		// by 10%+
8837
		// TODO (maxime) run stats to determine which is the better order
8838
		result.tagBits |= NULL_FLAG_MASK;
2145
	}
8839
	}
8840
	result.maxFieldCount = 0;
8841
	return result;
8842
}
2146
8843
2147
	// null analysis -- for
8844
/**
2148
	// TODO (maxime) fix
8845
 * Return true iff this flow info can be considered as equal to the one passed
2149
	public void _test0228_for() {
8846
 * in parameter.
2150
		this.runNegativeTest(
8847
 * @param other the flow info to compare to
2151
			new String[] {
8848
 * @return true iff this flow info compares equal to other
2152
				"X.java",
8849
 */
2153
				"public class X {\n" + 
8850
public boolean testEquals(UnconditionalFlowInfo other) {
2154
				"	 void foo(Object o) {\n" + 
8851
	if (this.tagBits != other.tagBits) {
2155
				"		 for (;o == null; o.toString()) {\n" + 
8852
		return false;
2156
				"		 }\n" + 
8853
	}
2157
				"	 }\n" + 
8854
	if (this.nullAssignmentStatusBit1 != other.nullAssignmentStatusBit1 ||
2158
				"}\n"},
8855
		this.nullAssignmentStatusBit2 != other.nullAssignmentStatusBit2 ||
2159
			"----------\n" + 
8856
		this.nullAssignmentValueBit1 != other.nullAssignmentValueBit1 ||
2160
			"1. WARNING in X.java (at line 3)\n" + 
8857
		this.nullAssignmentValueBit2 != other.nullAssignmentValueBit2) {
2161
			"	for (;o == null; o.toString()) {\n" + 
8858
		return false;
2162
			"	                 ^\n" + 
8859
	}
2163
			"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
8860
	int left = this.extra == null ? 0 : this.extra[0].length,
2164
			"----------\n"
8861
			right = other.extra == null ? 0 : other.extra[0].length,
2165
		);
8862
			both = 0, i;
2166
	}
8863
	if (left > right) {
2167
	
8864
		both = right;
2168
	// null analysis -- for
8865
	}
2169
	// TODO (maxime) fix
8866
	else {
2170
	public void _test0229_for() {
8867
		both = left;
2171
		this.runNegativeTest(
8868
	}
2172
			new String[] {
8869
	for (i = 0; i < both ; i++) {
2173
				"X.java",
8870
		if (this.extra[2][i] != 
2174
				"public class X {\n" + 
8871
				other.extra[2][i] ||
2175
				"	 void foo(Object o) {\n" + 
8872
			this.extra[3][i] != 
2176
				"		 for (o.toString(); o == null;) { /* */ }\n" + // complain: protected then unchanged
8873
				other.extra[3][i] ||
2177
				"	 }\n" + 
8874
			this.extra[4][i] != 
2178
				"}\n"},
8875
				other.extra[4][i] ||
2179
			"----------\n" + 
8876
			this.extra[5][i] != 
2180
			"1. WARNING in X.java (at line 3)\n" + 
8877
				other.extra[5][i]) {
2181
			"	for (o.toString(); o == null;) { /* */ }\n" + 
8878
			return false;
2182
			"	                   ^\n" + 
8879
		}
2183
			"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
2184
			"----------\n"
2185
		);
2186
	}
2187
	
2188
	// null analysis -- for
2189
	public void test0230_for() {
2190
		this.runNegativeTest(
2191
			new String[] {
2192
				"X.java",
2193
				"public class X {\n" + 
2194
				"	 boolean bar() {\n" + 
2195
				"		 return true;\n" + 
2196
				"	 }\n" + 
2197
				"	 void foo(Object o) {\n" + 
2198
				"	   o = null;\n" + 
2199
				"		 for (o.toString(); bar();) {\n" + 
2200
				"		 }\n" + 
2201
				"	 }\n" + 
2202
				"}\n"},
2203
			"----------\n" + 
2204
			"1. WARNING in X.java (at line 7)\n" + 
2205
			"	for (o.toString(); bar();) {\n" + 
2206
			"	     ^\n" + 
2207
			"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
2208
			"----------\n"
2209
		);
2210
	}
8880
	}
2211
	
8881
	for (; i < left; i++) {
2212
	// null analysis -- for
8882
		if (this.extra[2][i] != 0 ||
2213
	// TODO (maxime) fix
8883
				this.extra[3][i] != 0 ||
2214
	public void _test0231_for() {
8884
				this.extra[4][i] != 0 ||
2215
		if (COMPLIANCE_1_5.equals(this.complianceLevel)) {
8885
				this.extra[5][i] != 0) {
2216
			this.runNegativeTest(
8886
			return false;
2217
				new String[] {
2218
					"X.java",
2219
					"public class X {\n" + 
2220
					"	 void foo() {\n" + 
2221
					"		 Object t[] = null;\n" + 
2222
					"		 for (Object o : t) {/* */}\n" +
2223
					      // complain: NPE
2224
					"	 }\n" + 
2225
					"}\n"},
2226
				"----------\n" + 
2227
				"1. WARNING in X.java (at line 4)\n" + 
2228
				"	for (Object o : t) {/* */}\n" + 
2229
				"	                ^\n" + 
2230
				"The variable t can only be null; it was either set to null or checked for null when last used\n" + 
2231
				"----------\n"
2232
			);
2233
		}
2234
	}
2235
2236
	// null analysis -- for
2237
	// TODO (maxime) fix
2238
	public void _test0232_for() {
2239
		if (COMPLIANCE_1_5.equals(this.complianceLevel)) {
2240
			this.runNegativeTest(
2241
				new String[] {
2242
					"X.java",
2243
					"public class X {\n" + 
2244
					"	 void foo() {\n" + 
2245
					"		 Iterable i = null;\n" + 
2246
					"		 for (Object o : i) {/* */}\n" +
2247
					      // complain: NPE
2248
					"	 }\n" + 
2249
					"}\n"},
2250
				"----------\n" + 
2251
				"1. WARNING in X.java (at line 4)\n" + 
2252
				"	for (Object o : i) {/* */}\n" + 
2253
				"	                ^\n" + 
2254
				"The variable i can only be null; it was either set to null or checked for null when last used\n" + 
2255
				"----------\n"
2256
			);
2257
		}
2258
	}
2259
2260
	// null analysis -- for
2261
	public void test0233_for() {
2262
		if (COMPLIANCE_1_5.equals(this.complianceLevel)) {
2263
			this.runNegativeTest(
2264
				new String[] {
2265
					"X.java",
2266
					"public class X {\n" + 
2267
					"	 void foo() {\n" + 
2268
					"		 Object t[] = new Object[1];\n" + 
2269
					"		 for (Object o : t) {/* */}\n" +
2270
					"	 }\n" + 
2271
					"}\n"},
2272
				""
2273
			);
2274
		}
2275
	}
2276
2277
	// null analysis -- for
2278
	public void test0234_for() {
2279
		if (COMPLIANCE_1_5.equals(this.complianceLevel)) {
2280
			this.runNegativeTest(
2281
				new String[] {
2282
					"X.java",
2283
					"public class X {\n" + 
2284
					"	 void foo() {\n" + 
2285
					"		 Iterable i = new java.util.Vector<Object>();\n" + 
2286
					"		 for (Object o : i) {/* */}\n" +
2287
					"	 }\n" + 
2288
					"}\n"},
2289
				""
2290
			);
2291
		}
2292
	}
2293
2294
	// null analysis -- for
2295
	public void test0235_for() {
2296
		if (COMPLIANCE_1_5.equals(this.complianceLevel)) {
2297
			this.runNegativeTest(
2298
				new String[] {
2299
					"X.java",
2300
					"public class X {\n" + 
2301
					"	 void foo() {\n" + 
2302
					"		 Iterable i = new java.util.Vector<Object>();\n" + 
2303
					"		 Object flag = null;\n" + 
2304
					"		 for (Object o : i) {\n" +
2305
					"		   flag = new Object();\n" +
2306
					"		 }\n" +
2307
					"		 flag.toString();\n" + 
2308
					"	 }\n" + 
2309
					"}\n"},
2310
				""
2311
			);
2312
		}
8887
		}
2313
	}
8888
	}
2314
	
8889
	for (; i < right; i++) {
2315
	// null analysis -- for
8890
		if (other.extra[2][i] != 0 ||
2316
	// TODO (maxime) fix
8891
				other.extra[3][i] != 0 ||
2317
	public void _test0236_for() {
8892
				other.extra[4][i] != 0 ||
2318
		if (COMPLIANCE_1_5.equals(this.complianceLevel)) {
8893
				other.extra[5][i] != 0) {
2319
			this.runNegativeTest(
8894
			return false;
2320
				new String[] {
2321
					"X.java",
2322
					"public class X {\n" + 
2323
					"	 void foo() {\n" + 
2324
					"		 Iterable i = new java.util.Vector<Object>();\n" + 
2325
					"		 Object flag = null;\n" + 
2326
					"		 for (Object o : i) { /* */ }\n" +
2327
					"		 flag.toString();\n" + 
2328
					"	 }\n" + 
2329
					"}\n"},
2330
				"----------\n" + 
2331
				"1. WARNING in X.java (at line 6)\n" + 
2332
				"	flag.toString();\n" + 
2333
				"	^^^^\n" + 
2334
				"The variable flag can only be null; it was either set to null or checked for null when last used\n" + 
2335
				"----------\n"
2336
			);
2337
		}
8895
		}
2338
	}
8896
	}
8897
	return true;
8898
}
2339
8899
2340
	// null analysis -- for
8900
/**
2341
	public void test0237_for() {
8901
 * Return true iff this flow info can be considered as equal to the one passed
2342
		if (COMPLIANCE_1_5.equals(this.complianceLevel)) {
8902
 * in parameter in respect with a single local variable which id would be
2343
			this.runNegativeTest(
8903
 * position in a class with no field.
2344
				new String[] {
8904
 * @param other the flow info to compare to
2345
					"X.java",
8905
 * @param position the position of the local to consider
2346
					"public class X {\n" + 
8906
 * @return true iff this flow info compares equal to other for a given local
2347
					"	 void foo(boolean dummy) {\n" + 
8907
 */
2348
					"		 Object flag = null;\n" + 
8908
public boolean testEquals(UnconditionalFlowInfo other, int position) {
2349
					"		 for (;dummy;) {\n" +
8909
	int vectorIndex = position / BitCacheSize - 1;
2350
					"		   flag = new Object();\n" +
8910
	if ((this.tagBits & other.tagBits & NULL_FLAG_MASK) == 0) {
2351
					"		 }\n" +
8911
		return true;
2352
					"		 flag.toString();\n" + 
8912
	}
2353
					"	 }\n" + 
8913
	long mask;
2354
					"}\n"},
8914
	if (vectorIndex < 0) {
2355
				""
8915
		return ((this.nullAssignmentStatusBit1 & (mask = (1L << position))) ^
2356
			);
8916
				(other.nullAssignmentStatusBit1 & mask)) == 0 &&
8917
				((this.nullAssignmentStatusBit2 & mask) ^
8918
				(other.nullAssignmentStatusBit2 & mask)) == 0 &&
8919
				((this.nullAssignmentValueBit1 & mask) ^
8920
				(other.nullAssignmentValueBit1 & mask)) == 0 &&
8921
				((this.nullAssignmentValueBit2 & mask) ^
8922
				(other.nullAssignmentValueBit2 & mask)) == 0;
8923
	}
8924
	else {
8925
		int left = this.extra == null ?
8926
				0 :
8927
				this.extra[0].length;
8928
		int right = other.extra == null ?
8929
				0 :
8930
				other.extra[0].length;
8931
		int both = left < right ? left : right;
8932
		if (vectorIndex < both) {
8933
			return ((this.extra[2][vectorIndex] & 
8934
					(mask = (1L << (position % BitCacheSize)))) ^
8935
				(other.extra[2][vectorIndex] & mask)) == 0 &&
8936
				((this.extra[3][vectorIndex] & mask) ^
8937
				(other.extra[3][vectorIndex] & mask)) == 0 &&
8938
				((this.extra[4][vectorIndex] & mask) ^
8939
				(other.extra[4][vectorIndex] & mask)) == 0 &&
8940
				((this.extra[5][vectorIndex] & mask) ^
8941
				(other.extra[5][vectorIndex] & mask)) == 0;
2357
		}
8942
		}
2358
	}
8943
		if (vectorIndex < left) {
2359
	
8944
			return ((this.extra[2][vectorIndex] |
2360
	// null analysis -- for
8945
					this.extra[3][vectorIndex] |
2361
	// TODO (maxime) fix
8946
					this.extra[4][vectorIndex] |
2362
	public void _test0238_for() {
8947
					this.extra[5][vectorIndex]) &
2363
		if (COMPLIANCE_1_5.equals(this.complianceLevel)) {
8948
					(1L << (position % BitCacheSize))) == 0;
2364
			this.runNegativeTest(
2365
				new String[] {
2366
					"X.java",
2367
					"public class X {\n" + 
2368
					"	 void foo(boolean dummy) {\n" + 
2369
					"		 Object flag = null;\n" + 
2370
					"		 for (;dummy;) { /* */ }\n" +
2371
					"		 flag.toString();\n" + 
2372
					"	 }\n" + 
2373
					"}\n"},
2374
				"----------\n" + 
2375
				"1. WARNING in X.java (at line 5)\n" + 
2376
				"	flag.toString();\n" + 
2377
				"	^^^^\n" + 
2378
				"The variable flag can only be null; it was either set to null or checked for null when last used\n" + 
2379
				"----------\n"
2380
			);
2381
		}
8949
		}
8950
		return ((other.extra[2][vectorIndex] |
8951
				other.extra[3][vectorIndex] |
8952
				other.extra[4][vectorIndex] |
8953
				other.extra[5][vectorIndex]) &
8954
				(1L << (position % BitCacheSize))) == 0;
2382
	}
8955
	}
2383
	
8956
}
2384
	// null analysis -- for
2385
	// origin: AssignmentTest#test019
2386
	public void test0239_for() {
2387
		this.runNegativeTest(
2388
			new String[] {
2389
				"X.java",
2390
				"public class X {\n" + 
2391
				"	 public static final char[] foo(char[] a, char c1, char c2) {\n" + 
2392
				"		char[] r = null;\n" + 
2393
				"		for (int i = 0, length = a.length; i < length; i++) {\n" + 
2394
				"			char c = a[i];\n" + 
2395
				"			if (c == c1) {\n" + 
2396
				"				if (r == null) {\n" + 
2397
				"					r = new char[length];\n" + 
2398
				"				}\n" + 
2399
				"				r[i] = c2;\n" + 
2400
				"			} else if (r != null) {\n" + 
2401
				"				r[i] = c;\n" + 
2402
				"			}\n" + 
2403
				"		}\n" + 
2404
				"		if (r == null) return a;\n" + 
2405
				"		return r;\n" + 
2406
				"	}\n" + 
2407
				"}\n",
2408
			},
2409
		"");
2410
	}
2411
8957
2412
	// null analysis -- for
8958
/**
2413
	public void test0240_for_continue_break() {
8959
 * Return a string suitable for use as a representation of this flow info
2414
		this.runNegativeTest(
8960
 * within test series.
2415
			new String[] {
8961
 * @return a string suitable for use as a representation of this flow info
2416
				"X.java",
8962
 */
2417
				"public class X {\n" + 
8963
public String testString() {
2418
				"	 void foo() {\n" + 
8964
	if (this == DEAD_END) {
2419
				"	   Object o = new Object();\n" + 
8965
		return "FlowInfo.DEAD_END"; //$NON-NLS-1$
2420
				"		 for (int i = 0; i < 10; i++) {\n" + 
2421
				"		   if (o == null) {\n" + // complain: o cannot be null
2422
				"		     continue;\n" + 
2423
				"		   }\n" + 
2424
				"		   o = null;\n" + 
2425
				"		   break;\n" + 
2426
				"		 }\n" + 
2427
				"	 }\n" + 
2428
				"}\n",
2429
			},
2430
		"----------\n" + 
2431
		"1. WARNING in X.java (at line 5)\n" + 
2432
		"	if (o == null) {\n" + 
2433
		"	    ^\n" + 
2434
		"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
2435
		"----------\n");
2436
	}
2437
		
2438
	// null analysis -- switch
2439
	public void test0300_switch() {
2440
		this.runNegativeTest(
2441
			new String[] {
2442
				"X.java",
2443
				"public class X {\n" + 
2444
				"	int k;\n" + 
2445
				"	void foo() {\n" + 
2446
				"		Object o = null;\n" + 
2447
				"		switch (k) {\n" + 
2448
				"			case 0 :\n" + 
2449
				"				o = new Object();\n" + 
2450
				"				break;\n" + 
2451
				"			case 2 :\n" + 
2452
				"				return;\n" + 
2453
				"		}\n" + 
2454
				"		if(o == null) { /* */	}\n" + // quiet: don't know whether came from 0 or default
2455
				"	}\n" + 
2456
				"}\n"},
2457
			""
2458
		);
2459
	}
8966
	}
8967
	return testString(this.testPosition);
8968
}
2460
8969
2461
	// null analysis -- switch
8970
/**
2462
	public void test0301_switch() {
8971
 * Return a string suitable for use as a representation of this flow info
2463
		this.runNegativeTest(
8972
 * within test series.
2464
			new String[] {
8973
 * @param position a position to consider instead of this flow info default
2465
				"X.java",
8974
 *                 test position
2466
				"public class X {\n" + 
8975
 * @return a string suitable for use as a representation of this flow info
2467
				"	int k;\n" + 
8976
 */
2468
				"	void foo() {\n" + 
8977
public String testString(int position) {
2469
				"		Object o = null;\n" + 
8978
	if (this == DEAD_END) {
2470
				"		switch (k) {\n" + 
8979
		return "FlowInfo.DEAD_END"; //$NON-NLS-1$
2471
				"			case 0 :\n" + 
8980
	}
2472
				"				o = new Object();\n" + 
8981
	if (position < BitCacheSize) {
2473
				"				break;\n" + 
8982
		return "{" + (this.nullAssignmentStatusBit1 >> position) //$NON-NLS-1$
2474
				"			default :\n" + 
8983
					+ "," + (this.nullAssignmentStatusBit2 >> position) //$NON-NLS-1$
2475
				"				return;\n" + 
8984
					+ "," + (this.nullAssignmentValueBit1 >> position) //$NON-NLS-1$
2476
				"		}\n" + 
8985
					+ "," + (this.nullAssignmentValueBit2 >> position) //$NON-NLS-1$
2477
				"		if(o == null) { /* */	}\n" + // complain: only get there through 0, o non null
8986
					+ "}"; //$NON-NLS-1$
2478
				"	}\n" + 
8987
	}
2479
				"}\n"},
8988
	else {
2480
			"----------\n" + 
8989
		int vectorIndex = position / BitCacheSize - 1,
2481
			"1. WARNING in X.java (at line 12)\n" + 
8990
			shift = position % BitCacheSize;
2482
			"	if(o == null) { /* */	}\n" + 
8991
			return "{" + (this.extra[2][vectorIndex] //$NON-NLS-1$
2483
			"	   ^\n" + 
8992
			               >> shift) 
2484
			"The variable o cannot be null; it was either set to a non-null value or assumed to be non-null when last used\n" + 
8993
						+ "," + (this.extra[3][vectorIndex] //$NON-NLS-1$
2485
			"----------\n"
8994
						   >> shift)
2486
		);
8995
						+ "," + (this.extra[4][vectorIndex] //$NON-NLS-1$
2487
	}
8996
						   >> shift)
2488
	
8997
						+ "," + (this.extra[5][vectorIndex] //$NON-NLS-1$
2489
	// null analysis -- switch
8998
						   >> shift)
2490
	public void test0302_switch() {
8999
						+ "}"; //$NON-NLS-1$
2491
		this.runNegativeTest(
2492
			new String[] {
2493
				"X.java",
2494
				"public class X {\n" + 
2495
				"	int k;\n" + 
2496
				"	void foo() {\n" + 
2497
				"		Object o = null;\n" + 
2498
				"		switch (k) {\n" + 
2499
				"			case 0 :\n" + 
2500
				"				o.toString();\n" + // complain: o can only be null
2501
				"				break;\n" + 
2502
				"		}\n" + 
2503
				"	}\n" + 
2504
				"}\n"},
2505
			"----------\n" + 
2506
			"1. WARNING in X.java (at line 7)\n" + 
2507
			"	o.toString();\n" + 
2508
			"	^\n" + 
2509
			"The variable o can only be null; it was either set to null or checked for null when last used\n" + 
2510
			"----------\n"
2511
		);
2512
	}
2513
	
2514
	// null analysis -- switch
2515
	public void test0303_switch() {
2516
		this.runNegativeTest(
2517
			new String[] {
2518
				"X.java",
2519
				"public class X {\n" + 
2520
				"	int k;\n" + 
2521
				"	void foo() {\n" + 
2522
				"		Object o = null;\n" + 
2523
				"		switch (k) {\n" + 
2524
				"			case 0 :\n" + 
2525
				"			  o = new Object();\n" + 
2526
				"			case 1 :\n" + 
2527
				"				o.toString();\n" + // quiet: may come through 0 or 1
2528
				"				break;\n" + 
2529
				"		}\n" + 
2530
				"	}\n" + 
2531
				"}\n",
2532
			},
2533
		"");
2534
	}
9000
	}
2535
	
9001
}
2536
	// flow info low-level validation
2537
	// TODO (maxime) try to cover with source level tests instead of intrusive code
2538
}
9002
}
(-)src/org/eclipse/jdt/core/tests/compiler/regression/TestAll.java (+1 lines)
Lines 54-59 Link Here
54
	standardTests.add(CharOperationTest.class);
54
	standardTests.add(CharOperationTest.class);
55
	standardTests.add(RuntimeTests.class);
55
	standardTests.add(RuntimeTests.class);
56
	standardTests.add(DebugAttributeTest.class);
56
	standardTests.add(DebugAttributeTest.class);
57
	standardTests.add(NullReferenceTest.class);
57
	
58
	
58
	// add all javadoc tests
59
	// add all javadoc tests
59
	for (int i=0, l=JavadocTest.ALL_CLASSES.size(); i<l; i++) {
60
	for (int i=0, l=JavadocTest.ALL_CLASSES.size(); i<l; i++) {

Return to bug 110030