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

Collapse All | Expand All

(-)codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnBranchStatementLabel.java (-2 / +1 lines)
Lines 28-35 Link Here
28
		this.possibleLabels = possibleLabels;
28
		this.possibleLabels = possibleLabels;
29
	}
29
	}
30
30
31
	public FlowInfo analyseCode(BlockScope currentScope,
31
	public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
32
			FlowContext flowContext, FlowInfo flowInfo) {
33
		// Is never called
32
		// Is never called
34
		return null;
33
		return null;
35
	}
34
	}
(-)compiler/org/eclipse/jdt/internal/compiler/ast/AND_AND_Expression.java (-5 / +5 lines)
Lines 27-33 Link Here
27
		super(left, right, operator);
27
		super(left, right, operator);
28
	}
28
	}
29
29
30
	public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
30
	public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
31
31
32
		Constant cst = this.left.optimizedBooleanConstant();
32
		Constant cst = this.left.optimizedBooleanConstant();
33
		boolean isLeftOptimizedTrue = cst != Constant.NotAConstant && cst.booleanValue() == true;
33
		boolean isLeftOptimizedTrue = cst != Constant.NotAConstant && cst.booleanValue() == true;
Lines 38-52 Link Here
38
			// need to be careful of scenario:
38
			// need to be careful of scenario:
39
			//  (x && y) && !z, if passing the left info to the right, it would
39
			//  (x && y) && !z, if passing the left info to the right, it would
40
			// be swapped by the !
40
			// be swapped by the !
41
			FlowInfo mergedInfo = this.left.analyseCode(currentScope, flowContext, flowInfo)
41
			FlowInfo mergedInfo = this.left.analyseCode(currentScope, flowContext, flowInfo, false) // subject to optimization
42
					.unconditionalInits();
42
					.unconditionalInits();
43
			mergedInfo = this.right.analyseCode(currentScope, flowContext, mergedInfo);
43
			mergedInfo = this.right.analyseCode(currentScope, flowContext, mergedInfo, valueRequired);
44
			this.mergedInitStateIndex = currentScope.methodScope()
44
			this.mergedInitStateIndex = currentScope.methodScope()
45
					.recordInitializationStates(mergedInfo);
45
					.recordInitializationStates(mergedInfo);
46
			return mergedInfo;
46
			return mergedInfo;
47
		}
47
		}
48
48
49
		FlowInfo leftInfo = this.left.analyseCode(currentScope, flowContext, flowInfo);
49
		FlowInfo leftInfo = this.left.analyseCode(currentScope, flowContext, flowInfo, valueRequired);
50
		// need to be careful of scenario:
50
		// need to be careful of scenario:
51
		//  (x && y) && !z, if passing the left info to the right, it would be
51
		//  (x && y) && !z, if passing the left info to the right, it would be
52
		// swapped by the !
52
		// swapped by the !
Lines 60-66 Link Here
60
				rightInfo.setReachMode(FlowInfo.UNREACHABLE);
60
				rightInfo.setReachMode(FlowInfo.UNREACHABLE);
61
			}
61
			}
62
		}
62
		}
63
		rightInfo = this.right.analyseCode(currentScope, flowContext, rightInfo);
63
		rightInfo = this.right.analyseCode(currentScope, flowContext, rightInfo, !isLeftOptimizedFalse); // unused if left is false
64
		if ((this.left.implicitConversion & TypeIds.UNBOXING) != 0) {
64
		if ((this.left.implicitConversion & TypeIds.UNBOXING) != 0) {
65
			this.left.checkNPE(currentScope, flowContext, flowInfo);
65
			this.left.checkNPE(currentScope, flowContext, flowInfo);
66
		}
66
		}
(-)compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java (-1 / +2 lines)
Lines 156-161 Link Here
156
	// for references on lhs of assignment
156
	// for references on lhs of assignment
157
	public static final int IsStrictlyAssigned = Bit14; // set only for true assignments, as opposed to compound ones
157
	public static final int IsStrictlyAssigned = Bit14; // set only for true assignments, as opposed to compound ones
158
	public static final int IsCompoundAssigned = Bit17; // set only for compound assignments, as opposed to other ones
158
	public static final int IsCompoundAssigned = Bit17; // set only for compound assignments, as opposed to other ones
159
	public static final int IsInsideCondition = Bit21; // for name/field reference inside a condition 
159
160
160
	// for explicit constructor call
161
	// for explicit constructor call
161
	public static final int DiscardEnclosingInstance = Bit14; // used for codegen
162
	public static final int DiscardEnclosingInstance = Bit14; // used for codegen
Lines 364-370 Link Here
364
				&& field.isOrEnclosedByPrivateType() 
365
				&& field.isOrEnclosedByPrivateType() 
365
				&& !scope.isDefinedInField(field)) 				// ignore cases where field is used from inside itself 
366
				&& !scope.isDefinedInField(field)) 				// ignore cases where field is used from inside itself 
366
		{		
367
		{		
367
			if (((filteredBits & IsCompoundAssigned) != 0))
368
			if (((filteredBits & (IsCompoundAssigned|IsInsideCondition)) != 0))
368
				// used, but usage may not be relevant
369
				// used, but usage may not be relevant
369
				field.original().compoundUseFlag++;
370
				field.original().compoundUseFlag++;
370
			else
371
			else
(-)compiler/org/eclipse/jdt/internal/compiler/ast/AbstractVariableDeclaration.java (-1 / +1 lines)
Lines 36-42 Link Here
36
36
37
	public TypeReference type;
37
	public TypeReference type;
38
38
39
	public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
39
	public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
40
		return flowInfo;
40
		return flowInfo;
41
	}
41
	}
42
42
(-)compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java (-2 / +4 lines)
Lines 30-36 Link Here
30
	public TypeBinding[] genericTypeArguments;
30
	public TypeBinding[] genericTypeArguments;
31
	public FieldDeclaration enumConstant; // for enum constant initializations
31
	public FieldDeclaration enumConstant; // for enum constant initializations
32
32
33
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
33
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
34
	// constructor may have side effect => require values from all child nodes
35
34
	// check captured variables are initialized in current context (26134)
36
	// check captured variables are initialized in current context (26134)
35
	checkCapturedLocalInitializationIfNecessary((ReferenceBinding)this.binding.declaringClass.erasure(), currentScope, flowInfo);
37
	checkCapturedLocalInitializationIfNecessary((ReferenceBinding)this.binding.declaringClass.erasure(), currentScope, flowInfo);
36
38
Lines 39-45 Link Here
39
		for (int i = 0, count = this.arguments.length; i < count; i++) {
41
		for (int i = 0, count = this.arguments.length; i < count; i++) {
40
			flowInfo =
42
			flowInfo =
41
				this.arguments[i]
43
				this.arguments[i]
42
					.analyseCode(currentScope, flowContext, flowInfo)
44
					.analyseCode(currentScope, flowContext, flowInfo, true)
43
					.unconditionalInits();
45
					.unconditionalInits();
44
			if ((this.arguments[i].implicitConversion & TypeIds.UNBOXING) != 0) {
46
			if ((this.arguments[i].implicitConversion & TypeIds.UNBOXING) != 0) {
45
				this.arguments[i].checkNPE(currentScope, flowContext, flowInfo);
47
				this.arguments[i].checkNPE(currentScope, flowContext, flowInfo);
(-)compiler/org/eclipse/jdt/internal/compiler/ast/ArrayAllocationExpression.java (-3 / +5 lines)
Lines 26-43 Link Here
26
	public Expression[] dimensions;
26
	public Expression[] dimensions;
27
	public ArrayInitializer initializer;
27
	public ArrayInitializer initializer;
28
28
29
	public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
29
	public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
30
		// allocation itself has no side effect => may optimize all child nodes
31
30
		for (int i = 0, max = this.dimensions.length; i < max; i++) {
32
		for (int i = 0, max = this.dimensions.length; i < max; i++) {
31
			Expression dim;
33
			Expression dim;
32
			if ((dim = this.dimensions[i]) != null) {
34
			if ((dim = this.dimensions[i]) != null) {
33
				flowInfo = dim.analyseCode(currentScope, flowContext, flowInfo);
35
				flowInfo = dim.analyseCode(currentScope, flowContext, flowInfo, valueRequired);
34
				if ((dim.implicitConversion & TypeIds.UNBOXING) != 0) {
36
				if ((dim.implicitConversion & TypeIds.UNBOXING) != 0) {
35
					dim.checkNPE(currentScope, flowContext, flowInfo);
37
					dim.checkNPE(currentScope, flowContext, flowInfo);
36
				}
38
				}
37
			}
39
			}
38
		}
40
		}
39
		if (this.initializer != null) {
41
		if (this.initializer != null) {
40
			return this.initializer.analyseCode(currentScope, flowContext, flowInfo);
42
			return this.initializer.analyseCode(currentScope, flowContext, flowInfo, valueRequired);
41
		}
43
		}
42
		return flowInfo;
44
		return flowInfo;
43
	}
45
	}
(-)compiler/org/eclipse/jdt/internal/compiler/ast/ArrayInitializer.java (-2 / +3 lines)
Lines 29-39 Link Here
29
		super();
29
		super();
30
	}
30
	}
31
31
32
	public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
32
	public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
33
		// initializer itself has no side effect => may optimize all child nodes
33
34
34
		if (this.expressions != null) {
35
		if (this.expressions != null) {
35
			for (int i = 0, max = this.expressions.length; i < max; i++) {
36
			for (int i = 0, max = this.expressions.length; i < max; i++) {
36
				flowInfo = this.expressions[i].analyseCode(currentScope, flowContext, flowInfo).unconditionalInits();
37
				flowInfo = this.expressions[i].analyseCode(currentScope, flowContext, flowInfo, valueRequired).unconditionalInits();
37
			}
38
			}
38
		}
39
		}
39
		return flowInfo;
40
		return flowInfo;
(-)compiler/org/eclipse/jdt/internal/compiler/ast/ArrayReference.java (-7 / +9 lines)
Lines 31-53 Link Here
31
	this.sourceStart = rec.sourceStart;
31
	this.sourceStart = rec.sourceStart;
32
}
32
}
33
33
34
public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean compoundAssignment) {
34
public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean compoundAssignment, boolean valueRequired) {
35
	// array assignment has a side effect => require values from all child nodes
36
	
35
	// TODO (maxime) optimization: unconditionalInits is applied to all existing calls
37
	// TODO (maxime) optimization: unconditionalInits is applied to all existing calls
36
	if (assignment.expression == null) {
38
	if (assignment.expression == null) {
37
		return analyseCode(currentScope, flowContext, flowInfo);
39
		return analyseCode(currentScope, flowContext, flowInfo, true);
38
	}
40
	}
39
	return assignment
41
	return assignment
40
		.expression
42
		.expression
41
		.analyseCode(
43
		.analyseCode(
42
			currentScope,
44
			currentScope,
43
			flowContext,
45
			flowContext,
44
			analyseCode(currentScope, flowContext, flowInfo).unconditionalInits());
46
			analyseCode(currentScope, flowContext, flowInfo, true).unconditionalInits(), true);
45
}
47
}
46
48
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
47
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
49
	// reference itself has no side effect => may optimize all child nodes
48
	this.receiver.checkNPE(currentScope, flowContext, flowInfo);
50
	this.receiver.checkNPE(currentScope, flowContext, flowInfo);
49
	flowInfo = this.receiver.analyseCode(currentScope, flowContext, flowInfo);
51
	flowInfo = this.receiver.analyseCode(currentScope, flowContext, flowInfo, valueRequired);
50
	return this.position.analyseCode(currentScope, flowContext, flowInfo);
52
	return this.position.analyseCode(currentScope, flowContext, flowInfo, valueRequired);
51
}
53
}
52
54
53
public void generateAssignment(BlockScope currentScope, CodeStream codeStream, Assignment assignment, boolean valueRequired) {
55
public void generateAssignment(BlockScope currentScope, CodeStream codeStream, Assignment assignment, boolean valueRequired) {
(-)compiler/org/eclipse/jdt/internal/compiler/ast/AssertStatement.java (-3 / +4 lines)
Lines 40-46 Link Here
40
	this.sourceEnd = assertExpression.sourceEnd;
40
	this.sourceEnd = assertExpression.sourceEnd;
41
}
41
}
42
42
43
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
43
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
44
	// assert may have side effect (throwing) => require values from all child nodes
44
	this.preAssertInitStateIndex = currentScope.methodScope().recordInitializationStates(flowInfo);
45
	this.preAssertInitStateIndex = currentScope.methodScope().recordInitializationStates(flowInfo);
45
46
46
	Constant cst = this.assertExpression.optimizedBooleanConstant();
47
	Constant cst = this.assertExpression.optimizedBooleanConstant();
Lines 51-57 Link Here
51
	boolean isOptimizedFalseAssertion = cst != Constant.NotAConstant && cst.booleanValue() == false;
52
	boolean isOptimizedFalseAssertion = cst != Constant.NotAConstant && cst.booleanValue() == false;
52
	
53
	
53
	flowContext.tagBits |= FlowContext.HIDE_NULL_COMPARISON_WARNING;
54
	flowContext.tagBits |= FlowContext.HIDE_NULL_COMPARISON_WARNING;
54
	FlowInfo conditionFlowInfo = this.assertExpression.analyseCode(currentScope, flowContext, flowInfo.copy());
55
	FlowInfo conditionFlowInfo = this.assertExpression.analyseCode(currentScope, flowContext, flowInfo.copy(), true);
55
	flowContext.tagBits &= ~FlowContext.HIDE_NULL_COMPARISON_WARNING;
56
	flowContext.tagBits &= ~FlowContext.HIDE_NULL_COMPARISON_WARNING;
56
	UnconditionalFlowInfo assertWhenTrueInfo = conditionFlowInfo.initsWhenTrue().unconditionalInits();
57
	UnconditionalFlowInfo assertWhenTrueInfo = conditionFlowInfo.initsWhenTrue().unconditionalInits();
57
	FlowInfo assertInfo = conditionFlowInfo.initsWhenFalse();
58
	FlowInfo assertInfo = conditionFlowInfo.initsWhenFalse();
Lines 61-67 Link Here
61
62
62
	if (this.exceptionArgument != null) {
63
	if (this.exceptionArgument != null) {
63
		// only gets evaluated when escaping - results are not taken into account
64
		// only gets evaluated when escaping - results are not taken into account
64
		FlowInfo exceptionInfo = this.exceptionArgument.analyseCode(currentScope, flowContext, assertInfo.copy());
65
		FlowInfo exceptionInfo = this.exceptionArgument.analyseCode(currentScope, flowContext, assertInfo.copy(), true);
65
66
66
		if (isOptimizedTrueAssertion){
67
		if (isOptimizedTrueAssertion){
67
			currentScope.problemReporter().fakeReachable(this.exceptionArgument);
68
			currentScope.problemReporter().fakeReachable(this.exceptionArgument);
(-)compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java (-2 / +2 lines)
Lines 34-40 Link Here
34
	this.sourceEnd = sourceEnd;
34
	this.sourceEnd = sourceEnd;
35
}
35
}
36
36
37
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
37
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
38
	// record setting a variable: various scenarii are possible, setting an array reference,
38
	// record setting a variable: various scenarii are possible, setting an array reference,
39
// a field reference, a blank final field reference, a field of an enclosing instance or
39
// a field reference, a blank final field reference, a field of an enclosing instance or
40
// just a local variable.
40
// just a local variable.
Lines 50-56 Link Here
50
		}
50
		}
51
	}
51
	}
52
	flowInfo = ((Reference) this.lhs)
52
	flowInfo = ((Reference) this.lhs)
53
		.analyseAssignment(currentScope, flowContext, flowInfo, this, false)
53
		.analyseAssignment(currentScope, flowContext, flowInfo, this, false, valueRequired)
54
		.unconditionalInits();
54
		.unconditionalInits();
55
	if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) {
55
	if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) {
56
		flowInfo.markNullStatus(local, nullStatus);
56
		flowInfo.markNullStatus(local, nullStatus);
(-)compiler/org/eclipse/jdt/internal/compiler/ast/BinaryExpression.java (-4 / +4 lines)
Lines 56-73 Link Here
56
	this.sourceStart = expression.sourceStart;
56
	this.sourceStart = expression.sourceStart;
57
	this.sourceEnd = expression.sourceEnd;
57
	this.sourceEnd = expression.sourceEnd;
58
}
58
}
59
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
59
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
60
	// keep implementation in sync with CombinedBinaryExpression#analyseCode
60
	// keep implementation in sync with CombinedBinaryExpression#analyseCode
61
	if (this.resolvedType.id == TypeIds.T_JavaLangString) {
61
	if (this.resolvedType.id == TypeIds.T_JavaLangString) {
62
		return this.right.analyseCode(
62
		return this.right.analyseCode(
63
							currentScope, flowContext,
63
							currentScope, flowContext,
64
							this.left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits())
64
							this.left.analyseCode(currentScope, flowContext, flowInfo, valueRequired).unconditionalInits(), valueRequired)
65
						.unconditionalInits();
65
						.unconditionalInits();
66
	} else {
66
	} else {
67
		this.left.checkNPE(currentScope, flowContext, flowInfo);
67
		this.left.checkNPE(currentScope, flowContext, flowInfo);
68
		flowInfo = this.left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits();
68
		flowInfo = this.left.analyseCode(currentScope, flowContext, flowInfo, valueRequired).unconditionalInits();
69
		this.right.checkNPE(currentScope, flowContext, flowInfo);
69
		this.right.checkNPE(currentScope, flowContext, flowInfo);
70
		return this.right.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits();
70
		return this.right.analyseCode(currentScope, flowContext, flowInfo, valueRequired).unconditionalInits();
71
	}
71
	}
72
}
72
}
73
73
(-)compiler/org/eclipse/jdt/internal/compiler/ast/Block.java (-2 / +2 lines)
Lines 26-39 Link Here
26
	this.explicitDeclarations = explicitDeclarations;
26
	this.explicitDeclarations = explicitDeclarations;
27
}
27
}
28
28
29
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
29
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
30
	// empty block
30
	// empty block
31
	if (this.statements == null)	return flowInfo;
31
	if (this.statements == null)	return flowInfo;
32
	int complaintLevel = (flowInfo.reachMode() & FlowInfo.UNREACHABLE) != 0 ? Statement.COMPLAINED_FAKE_REACHABLE : Statement.NOT_COMPLAINED;
32
	int complaintLevel = (flowInfo.reachMode() & FlowInfo.UNREACHABLE) != 0 ? Statement.COMPLAINED_FAKE_REACHABLE : Statement.NOT_COMPLAINED;
33
	for (int i = 0, max = this.statements.length; i < max; i++) {
33
	for (int i = 0, max = this.statements.length; i < max; i++) {
34
		Statement stat = this.statements[i];
34
		Statement stat = this.statements[i];
35
		if ((complaintLevel = stat.complainIfUnreachable(flowInfo, this.scope, complaintLevel)) < Statement.COMPLAINED_UNREACHABLE) {
35
		if ((complaintLevel = stat.complainIfUnreachable(flowInfo, this.scope, complaintLevel)) < Statement.COMPLAINED_UNREACHABLE) {
36
			flowInfo = stat.analyseCode(this.scope, flowContext, flowInfo);
36
			flowInfo = stat.analyseCode(this.scope, flowContext, flowInfo, false);
37
		}
37
		}
38
	}
38
	}
39
	return flowInfo;
39
	return flowInfo;
(-)compiler/org/eclipse/jdt/internal/compiler/ast/BreakStatement.java (-1 / +1 lines)
Lines 20-26 Link Here
20
	super(label, sourceStart, e);
20
	super(label, sourceStart, e);
21
}
21
}
22
22
23
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
23
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
24
24
25
	// here requires to generate a sequence of finally blocks invocations depending corresponding
25
	// here requires to generate a sequence of finally blocks invocations depending corresponding
26
	// to each of the traversed try statements, so that execution will terminate properly.
26
	// to each of the traversed try statements, so that execution will terminate properly.
(-)compiler/org/eclipse/jdt/internal/compiler/ast/CaseStatement.java (-5 / +2 lines)
Lines 35-51 Link Here
35
	this.sourceStart = sourceStart;
35
	this.sourceStart = sourceStart;
36
}
36
}
37
37
38
public FlowInfo analyseCode(
38
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
39
	BlockScope currentScope,
40
	FlowContext flowContext,
41
	FlowInfo flowInfo) {
42
39
43
	if (this.constantExpression != null) {
40
	if (this.constantExpression != null) {
44
		if (this.constantExpression.constant == Constant.NotAConstant
41
		if (this.constantExpression.constant == Constant.NotAConstant
45
				&& !this.constantExpression.resolvedType.isEnum()) {
42
				&& !this.constantExpression.resolvedType.isEnum()) {
46
			currentScope.problemReporter().caseExpressionMustBeConstant(this.constantExpression);
43
			currentScope.problemReporter().caseExpressionMustBeConstant(this.constantExpression);
47
		}
44
		}
48
		this.constantExpression.analyseCode(currentScope, flowContext, flowInfo);
45
		this.constantExpression.analyseCode(currentScope, flowContext, flowInfo, true); // nothing to optimize here
49
	}
46
	}
50
	return flowInfo;
47
	return flowInfo;
51
}
48
}
(-)compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java (-3 / +5 lines)
Lines 47-57 Link Here
47
	type.bits |= ASTNode.IgnoreRawTypeCheck; // no need to worry about raw type usage
47
	type.bits |= ASTNode.IgnoreRawTypeCheck; // no need to worry about raw type usage
48
}
48
}
49
49
50
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
50
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
51
	boolean isUnboxing = (this.expression.implicitConversion & TypeIds.UNBOXING) != 0;
52
	boolean canThrow = isUnboxing || (this.bits & ASTNode.UnnecessaryCast) == 0;
51
	FlowInfo result = this.expression
53
	FlowInfo result = this.expression
52
		.analyseCode(currentScope, flowContext, flowInfo)
54
		.analyseCode(currentScope, flowContext, flowInfo, valueRequired||canThrow) // may optimize if no side effect by throwing (NPE or CCE)
53
		.unconditionalInits();
55
		.unconditionalInits();
54
	if ((this.expression.implicitConversion & TypeIds.UNBOXING) != 0) {
56
	if (isUnboxing) {
55
		this.expression.checkNPE(currentScope, flowContext, flowInfo);
57
		this.expression.checkNPE(currentScope, flowContext, flowInfo);
56
	}
58
	}
57
	return result;
59
	return result;
(-)compiler/org/eclipse/jdt/internal/compiler/ast/ClassLiteralAccess.java (-4 / +1 lines)
Lines 30-39 Link Here
30
		this.sourceEnd = sourceEnd;
30
		this.sourceEnd = sourceEnd;
31
	}
31
	}
32
32
33
	public FlowInfo analyseCode(
33
	public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
34
		BlockScope currentScope,
35
		FlowContext flowContext,
36
		FlowInfo flowInfo) {
37
34
38
		// if reachable, request the addition of a synthetic field for caching the class descriptor
35
		// if reachable, request the addition of a synthetic field for caching the class descriptor
39
		SourceTypeBinding sourceType = currentScope.outerMostClassScope().enclosingSourceType();
36
		SourceTypeBinding sourceType = currentScope.outerMostClassScope().enclosingSourceType();
(-)compiler/org/eclipse/jdt/internal/compiler/ast/CombinedBinaryExpression.java (-5 / +5 lines)
Lines 116-132 Link Here
116
}
116
}
117
117
118
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext,
118
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext,
119
		FlowInfo flowInfo) {
119
		FlowInfo flowInfo, boolean valueRequired) {
120
	// keep implementation in sync with BinaryExpression#analyseCode
120
	// keep implementation in sync with BinaryExpression#analyseCode
121
	if (this.referencesTable == null) {
121
	if (this.referencesTable == null) {
122
		return super.analyseCode(currentScope, flowContext, flowInfo);
122
		return super.analyseCode(currentScope, flowContext, flowInfo, valueRequired);
123
	}
123
	}
124
	BinaryExpression cursor;
124
	BinaryExpression cursor;
125
	if ((cursor = this.referencesTable[0]).resolvedType.id !=
125
	if ((cursor = this.referencesTable[0]).resolvedType.id !=
126
			TypeIds.T_JavaLangString) {
126
			TypeIds.T_JavaLangString) {
127
		cursor.left.checkNPE(currentScope, flowContext, flowInfo);
127
		cursor.left.checkNPE(currentScope, flowContext, flowInfo);
128
	}
128
	}
129
	flowInfo = cursor.left.analyseCode(currentScope, flowContext, flowInfo).
129
	flowInfo = cursor.left.analyseCode(currentScope, flowContext, flowInfo, valueRequired).
130
		unconditionalInits();
130
		unconditionalInits();
131
	for (int i = 0, end = this.arity; i < end; i ++) {
131
	for (int i = 0, end = this.arity; i < end; i ++) {
132
		if ((cursor = this.referencesTable[i]).resolvedType.id !=
132
		if ((cursor = this.referencesTable[i]).resolvedType.id !=
Lines 134-146 Link Here
134
			cursor.right.checkNPE(currentScope, flowContext, flowInfo);
134
			cursor.right.checkNPE(currentScope, flowContext, flowInfo);
135
		}
135
		}
136
		flowInfo = cursor.right.
136
		flowInfo = cursor.right.
137
			analyseCode(currentScope, flowContext, flowInfo).
137
			analyseCode(currentScope, flowContext, flowInfo, valueRequired).
138
				unconditionalInits();
138
				unconditionalInits();
139
	}
139
	}
140
	if (this.resolvedType.id != TypeIds.T_JavaLangString) {
140
	if (this.resolvedType.id != TypeIds.T_JavaLangString) {
141
		this.right.checkNPE(currentScope, flowContext, flowInfo);
141
		this.right.checkNPE(currentScope, flowContext, flowInfo);
142
	}
142
	}
143
	return this.right.analyseCode(currentScope, flowContext, flowInfo).
143
	return this.right.analyseCode(currentScope, flowContext, flowInfo, valueRequired).
144
		unconditionalInits();
144
		unconditionalInits();
145
}
145
}
146
146
(-)compiler/org/eclipse/jdt/internal/compiler/ast/CompoundAssignment.java (-9 / +9 lines)
Lines 34-49 Link Here
34
		this.operator = operator ;
34
		this.operator = operator ;
35
	}
35
	}
36
36
37
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext,
37
	public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext,
38
		FlowInfo flowInfo) {
38
			FlowInfo flowInfo, boolean valueRequired) {
39
	// record setting a variable: various scenarii are possible, setting an array reference,
39
		// record setting a variable: various scenarii are possible, setting an array reference,
40
	// a field reference, a blank final field reference, a field of an enclosing instance or
40
		// a field reference, a blank final field reference, a field of an enclosing instance or
41
	// just a local variable.
41
		// just a local variable.
42
	if (this.resolvedType.id != T_JavaLangString) {
42
		if (this.resolvedType.id != T_JavaLangString) {
43
		this.lhs.checkNPE(currentScope, flowContext, flowInfo);
43
			this.lhs.checkNPE(currentScope, flowContext, flowInfo);
44
		}
45
		return  ((Reference) this.lhs).analyseAssignment(currentScope, flowContext, flowInfo, this, true, valueRequired).unconditionalInits();
44
	}
46
	}
45
	return  ((Reference) this.lhs).analyseAssignment(currentScope, flowContext, flowInfo, this, true).unconditionalInits();
46
}
47
47
48
	public boolean checkCastCompatibility() {
48
	public boolean checkCastCompatibility() {
49
		return true;
49
		return true;
(-)compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java (-6 / +5 lines)
Lines 40-55 Link Here
40
		this.sourceStart = condition.sourceStart;
40
		this.sourceStart = condition.sourceStart;
41
		this.sourceEnd = valueIfFalse.sourceEnd;
41
		this.sourceEnd = valueIfFalse.sourceEnd;
42
	}
42
	}
43
43
	public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext,
44
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext,
44
			FlowInfo flowInfo, boolean valueRequired) {
45
			FlowInfo flowInfo) {
46
		int initialComplaintLevel = (flowInfo.reachMode() & FlowInfo.UNREACHABLE) != 0 ? Statement.COMPLAINED_FAKE_REACHABLE : Statement.NOT_COMPLAINED;
45
		int initialComplaintLevel = (flowInfo.reachMode() & FlowInfo.UNREACHABLE) != 0 ? Statement.COMPLAINED_FAKE_REACHABLE : Statement.NOT_COMPLAINED;
47
		Constant cst = this.condition.optimizedBooleanConstant();
46
		Constant cst = this.condition.optimizedBooleanConstant();
48
		boolean isConditionOptimizedTrue = cst != Constant.NotAConstant && cst.booleanValue() == true;
47
		boolean isConditionOptimizedTrue = cst != Constant.NotAConstant && cst.booleanValue() == true;
49
		boolean isConditionOptimizedFalse = cst != Constant.NotAConstant && cst.booleanValue() == false;
48
		boolean isConditionOptimizedFalse = cst != Constant.NotAConstant && cst.booleanValue() == false;
50
49
51
		int mode = flowInfo.reachMode();
50
		int mode = flowInfo.reachMode();
52
		flowInfo = this.condition.analyseCode(currentScope, flowContext, flowInfo, cst == Constant.NotAConstant);
51
		flowInfo = this.condition.analyseCode(currentScope, flowContext, flowInfo, valueRequired && (cst == Constant.NotAConstant));
53
52
54
		// process the if-true part
53
		// process the if-true part
55
		FlowInfo trueFlowInfo = flowInfo.initsWhenTrue().copy();
54
		FlowInfo trueFlowInfo = flowInfo.initsWhenTrue().copy();
Lines 62-68 Link Here
62
			}
61
			}
63
		}
62
		}
64
		this.trueInitStateIndex = currentScope.methodScope().recordInitializationStates(trueFlowInfo);
63
		this.trueInitStateIndex = currentScope.methodScope().recordInitializationStates(trueFlowInfo);
65
		trueFlowInfo = this.valueIfTrue.analyseCode(currentScope, flowContext, trueFlowInfo);
64
		trueFlowInfo = this.valueIfTrue.analyseCode(currentScope, flowContext, trueFlowInfo, valueRequired);
66
65
67
		// process the if-false part
66
		// process the if-false part
68
		FlowInfo falseFlowInfo = flowInfo.initsWhenFalse().copy();
67
		FlowInfo falseFlowInfo = flowInfo.initsWhenFalse().copy();
Lines 75-81 Link Here
75
			}
74
			}
76
		}
75
		}
77
		this.falseInitStateIndex = currentScope.methodScope().recordInitializationStates(falseFlowInfo);
76
		this.falseInitStateIndex = currentScope.methodScope().recordInitializationStates(falseFlowInfo);
78
		falseFlowInfo = this.valueIfFalse.analyseCode(currentScope, flowContext, falseFlowInfo);
77
		falseFlowInfo = this.valueIfFalse.analyseCode(currentScope, flowContext, falseFlowInfo, valueRequired);
79
78
80
		// merge if-true & if-false initializations
79
		// merge if-true & if-false initializations
81
		FlowInfo mergedInfo;
80
		FlowInfo mergedInfo;
(-)compiler/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java (-2 / +2 lines)
Lines 139-145 Link Here
139
					}
139
					}
140
				}
140
				}
141
			}
141
			}
142
			flowInfo = this.constructorCall.analyseCode(this.scope, constructorContext, flowInfo);
142
			flowInfo = this.constructorCall.analyseCode(this.scope, constructorContext, flowInfo, false); // called as a statement
143
		}
143
		}
144
144
145
		// reuse the reachMode from non static field info
145
		// reuse the reachMode from non static field info
Lines 151-157 Link Here
151
			for (int i = 0, count = this.statements.length; i < count; i++) {
151
			for (int i = 0, count = this.statements.length; i < count; i++) {
152
				Statement stat = this.statements[i];
152
				Statement stat = this.statements[i];
153
				if ((complaintLevel = stat.complainIfUnreachable(flowInfo, this.scope, complaintLevel)) < Statement.COMPLAINED_UNREACHABLE) {
153
				if ((complaintLevel = stat.complainIfUnreachable(flowInfo, this.scope, complaintLevel)) < Statement.COMPLAINED_UNREACHABLE) {
154
					flowInfo = stat.analyseCode(this.scope, constructorContext, flowInfo);
154
					flowInfo = stat.analyseCode(this.scope, constructorContext, flowInfo, false); // ignore any values produced by statements
155
				}
155
				}
156
			}
156
			}
157
		}
157
		}
(-)compiler/org/eclipse/jdt/internal/compiler/ast/ContinueStatement.java (-1 / +1 lines)
Lines 20-26 Link Here
20
	super(label, sourceStart, sourceEnd);
20
	super(label, sourceStart, sourceEnd);
21
}
21
}
22
22
23
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
23
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
24
24
25
	// here requires to generate a sequence of finally blocks invocations depending corresponding
25
	// here requires to generate a sequence of finally blocks invocations depending corresponding
26
	// to each of the traversed try statements, so that execution will terminate properly.
26
	// to each of the traversed try statements, so that execution will terminate properly.
(-)compiler/org/eclipse/jdt/internal/compiler/ast/DoStatement.java (-4 / +12 lines)
Lines 38-44 Link Here
38
	if (action instanceof EmptyStatement) action.bits |= ASTNode.IsUsefulEmptyStatement;
38
	if (action instanceof EmptyStatement) action.bits |= ASTNode.IsUsefulEmptyStatement;
39
}
39
}
40
40
41
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
41
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
42
		
42
	this.breakLabel = new BranchLabel();
43
	this.breakLabel = new BranchLabel();
43
	this.continueLabel = new BranchLabel();
44
	this.continueLabel = new BranchLabel();
44
	LoopingFlowContext loopingContext =
45
	LoopingFlowContext loopingContext =
Lines 66-72 Link Here
66
	// or catch blocks
67
	// or catch blocks
67
	if ((this.action != null) && !this.action.isEmptyBlock()) {
68
	if ((this.action != null) && !this.action.isEmptyBlock()) {
68
		actionInfo = this.action.
69
		actionInfo = this.action.
69
			analyseCode(currentScope, loopingContext, actionInfo).
70
			analyseCode(currentScope, loopingContext, actionInfo, false). // statements, values are ignored
70
			unconditionalInits();
71
			unconditionalInits();
71
72
72
		// code generation can be optimized when no need to continue in the loop
73
		// code generation can be optimized when no need to continue in the loop
Lines 100-106 Link Here
100
					null, currentScope)),
101
					null, currentScope)),
101
			(this.action == null
102
			(this.action == null
102
				? actionInfo
103
				? actionInfo
103
				: (actionInfo.mergedWith(loopingContext.initsOnContinue))).copy());
104
				: (actionInfo.mergedWith(loopingContext.initsOnContinue))).copy(),
105
			!isConditionOptimizedFalse); // subject to optimization if constant false
104
	this.preConditionInitStateIndex = currentScope.methodScope().recordInitializationStates(actionInfo);
106
	this.preConditionInitStateIndex = currentScope.methodScope().recordInitializationStates(actionInfo);
105
	if (!isConditionOptimizedFalse && this.continueLabel != null) {
107
	if (!isConditionOptimizedFalse && this.continueLabel != null) {
106
		loopingContext.complainOnDeferredFinalChecks(currentScope, condInfo);
108
		loopingContext.complainOnDeferredFinalChecks(currentScope, condInfo);
Lines 206-212 Link Here
206
}
208
}
207
209
208
public void resolve(BlockScope scope) {
210
public void resolve(BlockScope scope) {
209
	TypeBinding type = this.condition.resolveTypeExpecting(scope, TypeBinding.BOOLEAN);
211
	TypeBinding type = null;
212
	try {
213
		scope.isInsideCondition = true;
214
		type = this.condition.resolveTypeExpecting(scope, TypeBinding.BOOLEAN);
215
	} finally {
216
		scope.isInsideCondition = false;
217
	}
210
	this.condition.computeConversion(scope, type, type);
218
	this.condition.computeConversion(scope, type, type);
211
	if (this.action != null)
219
	if (this.action != null)
212
		this.action.resolve(scope);
220
		this.action.resolve(scope);
(-)compiler/org/eclipse/jdt/internal/compiler/ast/EmptyStatement.java (-1 / +1 lines)
Lines 24-30 Link Here
24
		this.sourceEnd = endPosition;
24
		this.sourceEnd = endPosition;
25
	}
25
	}
26
26
27
	public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
27
	public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
28
		return flowInfo;
28
		return flowInfo;
29
	}
29
	}
30
30
(-)compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java (-13 / +17 lines)
Lines 69-123 Link Here
69
		// does not preclude the variable from being null in an enclosing scope
69
		// does not preclude the variable from being null in an enclosing scope
70
	}
70
	}
71
71
72
	public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
72
	public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) 
73
	{
73
		FlowInfo result;
74
		FlowInfo result;
74
		if (((this.bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL) {
75
		if (((this.bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL) {
75
			if ((this.left.constant != Constant.NotAConstant) && (this.left.constant.typeID() == T_boolean)) {
76
			if ((this.left.constant != Constant.NotAConstant) && (this.left.constant.typeID() == T_boolean)) {
76
				if (this.left.constant.booleanValue()) { //  true == anything
77
				if (this.left.constant.booleanValue()) { //  true == anything
77
					//  this is equivalent to the right argument inits
78
					//  this is equivalent to the right argument inits
78
					result = this.right.analyseCode(currentScope, flowContext, flowInfo);
79
					result = this.right.analyseCode(currentScope, flowContext, flowInfo, valueRequired);
79
				} else { // false == anything
80
				} else { // false == anything
80
					//  this is equivalent to the right argument inits negated
81
					//  this is equivalent to the right argument inits negated
81
					result = this.right.analyseCode(currentScope, flowContext, flowInfo).asNegatedCondition();
82
					result = this.right.analyseCode(currentScope, flowContext, flowInfo, valueRequired).asNegatedCondition();
82
				}
83
				}
83
			}
84
			}
84
			else if ((this.right.constant != Constant.NotAConstant) && (this.right.constant.typeID() == T_boolean)) {
85
			else if ((this.right.constant != Constant.NotAConstant) && (this.right.constant.typeID() == T_boolean)) {
85
				if (this.right.constant.booleanValue()) { //  anything == true
86
				if (this.right.constant.booleanValue()) { //  anything == true
86
					//  this is equivalent to the left argument inits
87
					//  this is equivalent to the left argument inits
87
					result = this.left.analyseCode(currentScope, flowContext, flowInfo);
88
					result = this.left.analyseCode(currentScope, flowContext, flowInfo, valueRequired);
88
				} else { // anything == false
89
				} else { // anything == false
89
					//  this is equivalent to the right argument inits negated
90
					//  this is equivalent to the right argument inits negated
90
					result = this.left.analyseCode(currentScope, flowContext, flowInfo).asNegatedCondition();
91
					result = this.left.analyseCode(currentScope, flowContext, flowInfo, valueRequired).asNegatedCondition();
91
				}
92
				}
92
			}
93
			}
93
			else {
94
			else {
94
				result = this.right.analyseCode(
95
				result = this.right.analyseCode(
95
					currentScope, flowContext,
96
						currentScope, flowContext,
96
					this.left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits()).unconditionalInits();
97
						this.left.analyseCode(currentScope, flowContext, flowInfo, valueRequired).unconditionalInits(),
98
						valueRequired).
99
					unconditionalInits();
97
			}
100
			}
98
		} else { //NOT_EQUAL :
101
		} else { //NOT_EQUAL :
99
			if ((this.left.constant != Constant.NotAConstant) && (this.left.constant.typeID() == T_boolean)) {
102
			if ((this.left.constant != Constant.NotAConstant) && (this.left.constant.typeID() == T_boolean)) {
100
				if (!this.left.constant.booleanValue()) { //  false != anything
103
				if (!this.left.constant.booleanValue()) { //  false != anything
101
					//  this is equivalent to the right argument inits
104
					//  this is equivalent to the right argument inits
102
					result = this.right.analyseCode(currentScope, flowContext, flowInfo);
105
					result = this.right.analyseCode(currentScope, flowContext, flowInfo, valueRequired);
103
				} else { // true != anything
106
				} else { // true != anything
104
					//  this is equivalent to the right argument inits negated
107
					//  this is equivalent to the right argument inits negated
105
					result = this.right.analyseCode(currentScope, flowContext, flowInfo).asNegatedCondition();
108
					result = this.right.analyseCode(currentScope, flowContext, flowInfo, valueRequired).asNegatedCondition();
106
				}
109
				}
107
			}
110
			}
108
			else if ((this.right.constant != Constant.NotAConstant) && (this.right.constant.typeID() == T_boolean)) {
111
			else if ((this.right.constant != Constant.NotAConstant) && (this.right.constant.typeID() == T_boolean)) {
109
				if (!this.right.constant.booleanValue()) { //  anything != false
112
				if (!this.right.constant.booleanValue()) { //  anything != false
110
					//  this is equivalent to the right argument inits
113
					//  this is equivalent to the right argument inits
111
					result = this.left.analyseCode(currentScope, flowContext, flowInfo);
114
					result = this.left.analyseCode(currentScope, flowContext, flowInfo, valueRequired);
112
				} else { // anything != true
115
				} else { // anything != true
113
					//  this is equivalent to the right argument inits negated
116
					//  this is equivalent to the right argument inits negated
114
					result = this.left.analyseCode(currentScope, flowContext, flowInfo).asNegatedCondition();
117
					result = this.left.analyseCode(currentScope, flowContext, flowInfo, valueRequired).asNegatedCondition();
115
				}
118
				}
116
			}
119
			}
117
			else {
120
			else {
118
				result = this.right.analyseCode(
121
				result = this.right.analyseCode(
119
					currentScope, flowContext,
122
						currentScope, flowContext,
120
					this.left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits()).
123
						this.left.analyseCode(currentScope, flowContext, flowInfo, valueRequired).unconditionalInits(), 
124
						valueRequired).
121
					/* unneeded since we flatten it: asNegatedCondition(). */
125
					/* unneeded since we flatten it: asNegatedCondition(). */
122
					unconditionalInits();
126
					unconditionalInits();
123
			}
127
			}
(-)compiler/org/eclipse/jdt/internal/compiler/ast/ExplicitConstructorCall.java (-3 / +5 lines)
Lines 57-63 Link Here
57
		this.accessMode = accessMode;
57
		this.accessMode = accessMode;
58
	}
58
	}
59
59
60
	public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
60
	public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
61
		// called constructor may have side effect => require values from all child nodes
62
61
		// must verify that exceptions potentially thrown by this expression are caught in the method.
63
		// must verify that exceptions potentially thrown by this expression are caught in the method.
62
64
63
		try {
65
		try {
Lines 67-73 Link Here
67
			if (this.qualification != null) {
69
			if (this.qualification != null) {
68
				flowInfo =
70
				flowInfo =
69
					this.qualification
71
					this.qualification
70
						.analyseCode(currentScope, flowContext, flowInfo)
72
						.analyseCode(currentScope, flowContext, flowInfo, true)
71
						.unconditionalInits();
73
						.unconditionalInits();
72
			}
74
			}
73
			// process arguments
75
			// process arguments
Lines 75-81 Link Here
75
				for (int i = 0, max = this.arguments.length; i < max; i++) {
77
				for (int i = 0, max = this.arguments.length; i < max; i++) {
76
					flowInfo =
78
					flowInfo =
77
						this.arguments[i]
79
						this.arguments[i]
78
							.analyseCode(currentScope, flowContext, flowInfo)
80
							.analyseCode(currentScope, flowContext, flowInfo, true)
79
							.unconditionalInits();
81
							.unconditionalInits();
80
					if ((this.arguments[i].implicitConversion & TypeIds.UNBOXING) != 0) {
82
					if ((this.arguments[i].implicitConversion & TypeIds.UNBOXING) != 0) {
81
						this.arguments[i].checkNPE(currentScope, flowContext, flowInfo);
83
						this.arguments[i].checkNPE(currentScope, flowContext, flowInfo);
(-)compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java (-5 / +1 lines)
Lines 207-216 Link Here
207
	super();
207
	super();
208
}
208
}
209
209
210
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
211
	return flowInfo;
212
}
213
214
/**
210
/**
215
 * More sophisticated for of the flow analysis used for analyzing expressions, and be able to optimize out
211
 * More sophisticated for of the flow analysis used for analyzing expressions, and be able to optimize out
216
 * portions of expressions where no actual value is required.
212
 * portions of expressions where no actual value is required.
Lines 222-228 Link Here
222
 * @return The state of initialization after the analysis of the current expression
218
 * @return The state of initialization after the analysis of the current expression
223
 */
219
 */
224
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
220
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
225
	return analyseCode(currentScope, flowContext, flowInfo);
221
	return flowInfo;
226
}
222
}
227
223
228
/**
224
/**
(-)compiler/org/eclipse/jdt/internal/compiler/ast/FieldDeclaration.java (-1 / +1 lines)
Lines 71-77 Link Here
71
	if (this.initialization != null) {
71
	if (this.initialization != null) {
72
		flowInfo =
72
		flowInfo =
73
			this.initialization
73
			this.initialization
74
				.analyseCode(initializationScope, flowContext, flowInfo)
74
				.analyseCode(initializationScope, flowContext, flowInfo, true) // side effect => require values
75
				.unconditionalInits();
75
				.unconditionalInits();
76
		flowInfo.markAsDefinitelyAssigned(this.binding);
76
		flowInfo.markAsDefinitelyAssigned(this.binding);
77
	}
77
	}
(-)compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java (-10 / +13 lines)
Lines 59-65 Link Here
59
59
60
}
60
}
61
61
62
public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound) {
62
public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound, boolean valueRequired) {
63
	// generally, the assignment side effect requires all values from child nodes
64
	// - only the receiver of static field access can be optimized out
65
	// assigning to a field doesn't necessarily mark the field as used, only if the value of the assignment itself is used
66
	
63
	// compound assignment extra work
67
	// compound assignment extra work
64
	if (isCompound) { // check the variable part is initialized if blank final
68
	if (isCompound) { // check the variable part is initialized if blank final
65
		if (this.binding.isBlankFinal()
69
		if (this.binding.isBlankFinal()
Lines 72-77 Link Here
72
			}
76
			}
73
		}
77
		}
74
		manageSyntheticAccessIfNecessary(currentScope, flowInfo, true /*read-access*/);
78
		manageSyntheticAccessIfNecessary(currentScope, flowInfo, true /*read-access*/);
79
		// https://bugs.eclipse.org/bugs/show_bug.cgi?id=328830
80
		reportOnlyUselesslyReadPrivateField(currentScope, this.binding, valueRequired);
75
	}
81
	}
76
	flowInfo =
82
	flowInfo =
77
		this.receiver
83
		this.receiver
Lines 81-87 Link Here
81
		flowInfo =
87
		flowInfo =
82
			assignment
88
			assignment
83
				.expression
89
				.expression
84
				.analyseCode(currentScope, flowContext, flowInfo)
90
				.analyseCode(currentScope, flowContext, flowInfo, true)
85
				.unconditionalInits();
91
				.unconditionalInits();
86
	}
92
	}
87
	manageSyntheticAccessIfNecessary(currentScope, flowInfo, false /*write-access*/);
93
	manageSyntheticAccessIfNecessary(currentScope, flowInfo, false /*write-access*/);
Lines 111-122 Link Here
111
	return flowInfo;
117
	return flowInfo;
112
}
118
}
113
119
114
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
115
	return analyseCode(currentScope, flowContext, flowInfo, true);
116
}
117
118
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
120
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
119
	boolean nonStatic = !this.binding.isStatic();
121
	boolean nonStatic = !this.binding.isStatic();
122
	// https://bugs.eclipse.org/bugs/show_bug.cgi?id=328830
123
	reportOnlyUselesslyReadPrivateField(currentScope, this.binding, valueRequired);
120
	this.receiver.analyseCode(currentScope, flowContext, flowInfo, nonStatic);
124
	this.receiver.analyseCode(currentScope, flowContext, flowInfo, nonStatic);
121
	if (nonStatic) {
125
	if (nonStatic) {
122
		this.receiver.checkNPE(currentScope, flowContext, flowInfo);
126
		this.receiver.checkNPE(currentScope, flowContext, flowInfo);
Lines 291-298 Link Here
291
295
292
public void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) {
296
public void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) {
293
	boolean isStatic;
297
	boolean isStatic;
294
	// check if compound assignment is the only usage of a private field
295
	reportOnlyUselesslyReadPrivateField(currentScope, this.binding, valueRequired);
296
	FieldBinding codegenBinding = this.binding.original();
298
	FieldBinding codegenBinding = this.binding.original();
297
	this.receiver.generateCode(currentScope, codeStream, !(isStatic = codegenBinding.isStatic()));
299
	this.receiver.generateCode(currentScope, codeStream, !(isStatic = codegenBinding.isStatic()));
298
	if (isStatic) {
300
	if (isStatic) {
Lines 340-347 Link Here
340
342
341
public void generatePostIncrement(BlockScope currentScope, CodeStream codeStream, CompoundAssignment postIncrement, boolean valueRequired) {
343
public void generatePostIncrement(BlockScope currentScope, CodeStream codeStream, CompoundAssignment postIncrement, boolean valueRequired) {
342
	boolean isStatic;
344
	boolean isStatic;
343
	// check if postIncrement is the only usage of a private field
344
	reportOnlyUselesslyReadPrivateField(currentScope, this.binding, valueRequired);
345
	FieldBinding codegenBinding = this.binding.original();
345
	FieldBinding codegenBinding = this.binding.original();
346
	this.receiver.generateCode(currentScope, codeStream, !(isStatic = codegenBinding.isStatic()));
346
	this.receiver.generateCode(currentScope, codeStream, !(isStatic = codegenBinding.isStatic()));
347
	if (isStatic) {
347
	if (isStatic) {
Lines 523-528 Link Here
523
	// constants are propaged when the field is final
523
	// constants are propaged when the field is final
524
	// and initialized with a (compile time) constant
524
	// and initialized with a (compile time) constant
525
525
526
	if (scope.isInsideCondition)
527
		this.bits |= ASTNode.IsInsideCondition;
528
526
	//always ignore receiver cast, since may affect constant pool reference
529
	//always ignore receiver cast, since may affect constant pool reference
527
	boolean receiverCast = false;
530
	boolean receiverCast = false;
528
	if (this.receiver instanceof CastExpression) {
531
	if (this.receiver instanceof CastExpression) {
(-)compiler/org/eclipse/jdt/internal/compiler/ast/ForStatement.java (-6 / +13 lines)
Lines 59-65 Link Here
59
		}
59
		}
60
	}
60
	}
61
61
62
	public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
62
	public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
63
		this.breakLabel = new BranchLabel();
63
		this.breakLabel = new BranchLabel();
64
		this.continueLabel = new BranchLabel();
64
		this.continueLabel = new BranchLabel();
65
		int initialComplaintLevel = (flowInfo.reachMode() & FlowInfo.UNREACHABLE) != 0 ? Statement.COMPLAINED_FAKE_REACHABLE : Statement.NOT_COMPLAINED;
65
		int initialComplaintLevel = (flowInfo.reachMode() & FlowInfo.UNREACHABLE) != 0 ? Statement.COMPLAINED_FAKE_REACHABLE : Statement.NOT_COMPLAINED;
Lines 67-73 Link Here
67
		// process the initializations
67
		// process the initializations
68
		if (this.initializations != null) {
68
		if (this.initializations != null) {
69
			for (int i = 0, count = this.initializations.length; i < count; i++) {
69
			for (int i = 0, count = this.initializations.length; i < count; i++) {
70
				flowInfo = this.initializations[i].analyseCode(this.scope, flowContext, flowInfo);
70
				flowInfo = this.initializations[i].analyseCode(this.scope, flowContext, flowInfo, false);
71
			}
71
			}
72
		}
72
		}
73
		this.preCondInitStateIndex =
73
		this.preCondInitStateIndex =
Lines 92-98 Link Here
92
						(condLoopContext =
92
						(condLoopContext =
93
							new LoopingFlowContext(flowContext, flowInfo, this, null,
93
							new LoopingFlowContext(flowContext, flowInfo, this, null,
94
								null, this.scope)),
94
								null, this.scope)),
95
						condInfo);
95
						condInfo,
96
						!isConditionOptimizedFalse);
96
				if ((this.condition.implicitConversion & TypeIds.UNBOXING) != 0) {
97
				if ((this.condition.implicitConversion & TypeIds.UNBOXING) != 0) {
97
					this.condition.checkNPE(currentScope, flowContext, flowInfo);
98
					this.condition.checkNPE(currentScope, flowContext, flowInfo);
98
				}
99
				}
Lines 139-145 Link Here
139
					}
140
					}
140
				}
141
				}
141
			if (this.action.complainIfUnreachable(actionInfo, this.scope, initialComplaintLevel) < Statement.COMPLAINED_UNREACHABLE) {
142
			if (this.action.complainIfUnreachable(actionInfo, this.scope, initialComplaintLevel) < Statement.COMPLAINED_UNREACHABLE) {
142
				actionInfo = this.action.analyseCode(this.scope, loopingContext, actionInfo).unconditionalInits();
143
				actionInfo = this.action.analyseCode(this.scope, loopingContext, actionInfo, false).unconditionalInits();
143
			}
144
			}
144
145
145
			// code generation can be optimized when no need to continue in the loop
146
			// code generation can be optimized when no need to continue in the loop
Lines 172-178 Link Here
172
					currentScope.methodScope().recordInitializationStates(incrementInfo);
173
					currentScope.methodScope().recordInitializationStates(incrementInfo);
173
				for (int i = 0, count = this.increments.length; i < count; i++) {
174
				for (int i = 0, count = this.increments.length; i < count; i++) {
174
					incrementInfo = this.increments[i].
175
					incrementInfo = this.increments[i].
175
						analyseCode(this.scope, incrementContext, incrementInfo);
176
						analyseCode(this.scope, incrementContext, incrementInfo, false);
176
				}
177
				}
177
				incrementContext.complainOnDeferredFinalChecks(this.scope,
178
				incrementContext.complainOnDeferredFinalChecks(this.scope,
178
						actionInfo = incrementInfo.unconditionalInits());
179
						actionInfo = incrementInfo.unconditionalInits());
Lines 377-383 Link Here
377
			for (int i = 0, length = this.initializations.length; i < length; i++)
378
			for (int i = 0, length = this.initializations.length; i < length; i++)
378
				this.initializations[i].resolve(this.scope);
379
				this.initializations[i].resolve(this.scope);
379
		if (this.condition != null) {
380
		if (this.condition != null) {
380
			TypeBinding type = this.condition.resolveTypeExpecting(this.scope, TypeBinding.BOOLEAN);
381
			TypeBinding type = null;
382
			try {
383
				upperScope.isInsideCondition = true;
384
				type = this.condition.resolveTypeExpecting(this.scope, TypeBinding.BOOLEAN);
385
			} finally  {
386
				upperScope.isInsideCondition = false;
387
			}
381
			this.condition.computeConversion(this.scope, type, type);
388
			this.condition.computeConversion(this.scope, type, type);
382
		}
389
		}
383
		if (this.increments != null)
390
		if (this.increments != null)
(-)compiler/org/eclipse/jdt/internal/compiler/ast/ForeachStatement.java (-4 / +4 lines)
Lines 72-78 Link Here
72
		this.kind = -1;
72
		this.kind = -1;
73
	}
73
	}
74
74
75
	public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
75
	public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
76
		// initialize break and continue labels
76
		// initialize break and continue labels
77
		this.breakLabel = new BranchLabel();
77
		this.breakLabel = new BranchLabel();
78
		this.continueLabel = new BranchLabel();
78
		this.continueLabel = new BranchLabel();
Lines 80-87 Link Here
80
80
81
		// process the element variable and collection
81
		// process the element variable and collection
82
		this.collection.checkNPE(currentScope, flowContext, flowInfo);
82
		this.collection.checkNPE(currentScope, flowContext, flowInfo);
83
		flowInfo = this.elementVariable.analyseCode(this.scope, flowContext, flowInfo);		
83
		flowInfo = this.elementVariable.analyseCode(this.scope, flowContext, flowInfo, false); // analyse as a statement -> ignore value		
84
		FlowInfo condInfo = this.collection.analyseCode(this.scope, flowContext, flowInfo.copy());
84
		FlowInfo condInfo = this.collection.analyseCode(this.scope, flowContext, flowInfo.copy(), true); // collection value is required
85
85
86
		// element variable will be assigned when iterating
86
		// element variable will be assigned when iterating
87
		condInfo.markAsDefinitelyAssigned(this.elementVariable.binding);
87
		condInfo.markAsDefinitelyAssigned(this.elementVariable.binding);
Lines 100-106 Link Here
100
				&& currentScope.compilerOptions().complianceLevel <= ClassFileConstants.JDK1_3))) {
100
				&& currentScope.compilerOptions().complianceLevel <= ClassFileConstants.JDK1_3))) {
101
101
102
			if (this.action.complainIfUnreachable(actionInfo, this.scope, initialComplaintLevel) < Statement.COMPLAINED_UNREACHABLE) {
102
			if (this.action.complainIfUnreachable(actionInfo, this.scope, initialComplaintLevel) < Statement.COMPLAINED_UNREACHABLE) {
103
				actionInfo = this.action.analyseCode(this.scope, loopingContext, actionInfo).unconditionalCopy();
103
				actionInfo = this.action.analyseCode(this.scope, loopingContext, actionInfo, false).unconditionalCopy(); // statement values are ignored
104
			}
104
			}
105
105
106
			// code generation can be optimized when no need to continue in the loop
106
			// code generation can be optimized when no need to continue in the loop
(-)compiler/org/eclipse/jdt/internal/compiler/ast/IfStatement.java (-8 / +34 lines)
Lines 52-68 Link Here
52
	this.sourceEnd = sourceEnd;
52
	this.sourceEnd = sourceEnd;
53
}
53
}
54
54
55
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
55
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
56
	// process the condition
56
	// process the condition
57
	FlowInfo conditionFlowInfo = this.condition.analyseCode(currentScope, flowContext, flowInfo);
57
	Constant cst = this.condition.optimizedBooleanConstant();
58
	
59
	boolean isConditionOptimizedTrue = cst != Constant.NotAConstant && cst.booleanValue() == true;
60
	boolean isConditionOptimizedFalse = cst != Constant.NotAConstant && cst.booleanValue() == false;
61
	boolean hasThenPart = this.thenStatement != null && !this.thenStatement.isEmptyBlock();
62
	boolean hasElsePart = this.elseStatement != null && !this.elseStatement.isEmptyBlock();
63
64
	boolean conditionValueRequired = true;
65
	if (hasThenPart) {
66
		// will generate boolean condition only if needed
67
		if (isConditionOptimizedTrue)
68
			conditionValueRequired = false;
69
	} else if (hasElsePart) {
70
		// will generate boolean condition only if needed
71
		if (isConditionOptimizedFalse)
72
			conditionValueRequired = false;
73
	} else {
74
		conditionValueRequired = false;
75
	}
76
77
	FlowInfo conditionFlowInfo = this.condition.analyseCode(currentScope, flowContext, flowInfo, conditionValueRequired);
58
	int initialComplaintLevel = (flowInfo.reachMode() & FlowInfo.UNREACHABLE) != 0 ? Statement.COMPLAINED_FAKE_REACHABLE : Statement.NOT_COMPLAINED;
78
	int initialComplaintLevel = (flowInfo.reachMode() & FlowInfo.UNREACHABLE) != 0 ? Statement.COMPLAINED_FAKE_REACHABLE : Statement.NOT_COMPLAINED;
59
79
60
	Constant cst = this.condition.optimizedBooleanConstant();
61
	if ((this.condition.implicitConversion & TypeIds.UNBOXING) != 0) {
80
	if ((this.condition.implicitConversion & TypeIds.UNBOXING) != 0) {
62
		this.condition.checkNPE(currentScope, flowContext, flowInfo);
81
		this.condition.checkNPE(currentScope, flowContext, flowInfo);
63
	}
82
	}
64
	boolean isConditionOptimizedTrue = cst != Constant.NotAConstant && cst.booleanValue() == true;
83
65
	boolean isConditionOptimizedFalse = cst != Constant.NotAConstant && cst.booleanValue() == false;
84
66
85
67
	// process the THEN part
86
	// process the THEN part
68
	FlowInfo thenFlowInfo = conditionFlowInfo.safeInitsWhenTrue();
87
	FlowInfo thenFlowInfo = conditionFlowInfo.safeInitsWhenTrue();
Lines 84-89 Link Here
84
		// No need if the whole if-else construct itself lies in unreachable code
103
		// No need if the whole if-else construct itself lies in unreachable code
85
		this.bits |= ASTNode.IsElseStatementUnreachable;
104
		this.bits |= ASTNode.IsElseStatementUnreachable;
86
	}
105
	}
106
	
87
	if (this.thenStatement != null) {
107
	if (this.thenStatement != null) {
88
		// Save info for code gen
108
		// Save info for code gen
89
		this.thenInitStateIndex = currentScope.methodScope().recordInitializationStates(thenFlowInfo);
109
		this.thenInitStateIndex = currentScope.methodScope().recordInitializationStates(thenFlowInfo);
Lines 96-102 Link Here
96
				this.bits &= ~ASTNode.IsThenStatementUnreachable;
116
				this.bits &= ~ASTNode.IsThenStatementUnreachable;
97
			}
117
			}
98
		}
118
		}
99
		thenFlowInfo = this.thenStatement.analyseCode(currentScope, flowContext, thenFlowInfo);
119
		thenFlowInfo = this.thenStatement.analyseCode(currentScope, flowContext, thenFlowInfo, false); // analyse as statement, ignore value
100
	}
120
	}
101
	// code gen: optimizing the jump around the ELSE part
121
	// code gen: optimizing the jump around the ELSE part
102
	if ((thenFlowInfo.tagBits & FlowInfo.UNREACHABLE) != 0) {
122
	if ((thenFlowInfo.tagBits & FlowInfo.UNREACHABLE) != 0) {
Lines 122-128 Link Here
122
				this.bits &= ~ASTNode.IsElseStatementUnreachable;
142
				this.bits &= ~ASTNode.IsElseStatementUnreachable;
123
			}
143
			}
124
		}
144
		}
125
		elseFlowInfo = this.elseStatement.analyseCode(currentScope, flowContext, elseFlowInfo);
145
		elseFlowInfo = this.elseStatement.analyseCode(currentScope, flowContext, elseFlowInfo, false); // analyse as statement, ignore value
126
	}
146
	}
127
	// merge THEN & ELSE initializations
147
	// merge THEN & ELSE initializations
128
	FlowInfo mergedInfo = FlowInfo.mergedOptimizedBranchesIfElse(
148
	FlowInfo mergedInfo = FlowInfo.mergedOptimizedBranchesIfElse(
Lines 260-266 Link Here
260
}
280
}
261
281
262
public void resolve(BlockScope scope) {
282
public void resolve(BlockScope scope) {
263
	TypeBinding type = this.condition.resolveTypeExpecting(scope, TypeBinding.BOOLEAN);
283
	TypeBinding type = null;
284
	try {
285
		scope.isInsideCondition = true;
286
		type = this.condition.resolveTypeExpecting(scope, TypeBinding.BOOLEAN);
287
	} finally {
288
		scope.isInsideCondition = false;
289
	}
264
	this.condition.computeConversion(scope, type, type);
290
	this.condition.computeConversion(scope, type, type);
265
	if (this.thenStatement != null)
291
	if (this.thenStatement != null)
266
		this.thenStatement.resolve(scope);
292
		this.thenStatement.resolve(scope);
(-)compiler/org/eclipse/jdt/internal/compiler/ast/Initializer.java (-5 / +2 lines)
Lines 33-45 Link Here
33
		}
33
		}
34
	}
34
	}
35
35
36
	public FlowInfo analyseCode(
36
	public FlowInfo analyseCode(MethodScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
37
		MethodScope currentScope,
38
		FlowContext flowContext,
39
		FlowInfo flowInfo) {
40
37
41
		if (this.block != null) {
38
		if (this.block != null) {
42
			return this.block.analyseCode(currentScope, flowContext, flowInfo);
39
			return this.block.analyseCode(currentScope, flowContext, flowInfo, false); // statements, ignore value
43
		}
40
		}
44
		return flowInfo;
41
		return flowInfo;
45
	}
42
	}
(-)compiler/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java (-3 / +3 lines)
Lines 30-39 Link Here
30
	this.sourceEnd = type.sourceEnd;
30
	this.sourceEnd = type.sourceEnd;
31
}
31
}
32
32
33
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
33
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
34
	LocalVariableBinding local = this.expression.localVariableBinding();
34
	LocalVariableBinding local = this.expression.localVariableBinding();
35
	if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) {
35
	if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) {
36
		flowInfo = this.expression.analyseCode(currentScope, flowContext, flowInfo).
36
		flowInfo = this.expression.analyseCode(currentScope, flowContext, flowInfo, valueRequired).
37
			unconditionalInits();
37
			unconditionalInits();
38
		FlowInfo initsWhenTrue = flowInfo.copy();
38
		FlowInfo initsWhenTrue = flowInfo.copy();
39
		initsWhenTrue.markAsComparedEqualToNonNull(local);
39
		initsWhenTrue.markAsComparedEqualToNonNull(local);
Lines 45-51 Link Here
45
		// no impact upon enclosing try context
45
		// no impact upon enclosing try context
46
		return FlowInfo.conditional(initsWhenTrue, flowInfo.copy());
46
		return FlowInfo.conditional(initsWhenTrue, flowInfo.copy());
47
	}
47
	}
48
	return this.expression.analyseCode(currentScope, flowContext, flowInfo).
48
	return this.expression.analyseCode(currentScope, flowContext, flowInfo, valueRequired).
49
			unconditionalInits();
49
			unconditionalInits();
50
}
50
}
51
51
(-)compiler/org/eclipse/jdt/internal/compiler/ast/LabeledStatement.java (-5 / +3 lines)
Lines 39-48 Link Here
39
		this.sourceEnd = sourceEnd;
39
		this.sourceEnd = sourceEnd;
40
	}
40
	}
41
41
42
	public FlowInfo analyseCode(
42
	public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
43
		BlockScope currentScope,
44
		FlowContext flowContext,
45
		FlowInfo flowInfo) {
46
43
47
		// need to stack a context to store explicit label, answer inits in case of normal completion merged
44
		// need to stack a context to store explicit label, answer inits in case of normal completion merged
48
		// with those relative to the exit path from break statement occurring inside the labeled statement.
45
		// with those relative to the exit path from break statement occurring inside the labeled statement.
Lines 60-66 Link Here
60
						this.label,
57
						this.label,
61
						(this.targetLabel = new BranchLabel()),
58
						(this.targetLabel = new BranchLabel()),
62
						currentScope)),
59
						currentScope)),
63
				flowInfo);
60
				flowInfo,
61
				false);	// statement, value ignored
64
			boolean reinjectNullInfo = (statementInfo.tagBits & FlowInfo.UNREACHABLE) != 0 &&
62
			boolean reinjectNullInfo = (statementInfo.tagBits & FlowInfo.UNREACHABLE) != 0 &&
65
				(labelContext.initsOnBreak.tagBits & FlowInfo.UNREACHABLE) == 0;
63
				(labelContext.initsOnBreak.tagBits & FlowInfo.UNREACHABLE) == 0;
66
			mergedInfo = statementInfo.mergedWith(labelContext.initsOnBreak);
64
			mergedInfo = statementInfo.mergedWith(labelContext.initsOnBreak);
(-)compiler/org/eclipse/jdt/internal/compiler/ast/Literal.java (-10 lines)
Lines 10-17 Link Here
10
 *******************************************************************************/
10
 *******************************************************************************/
11
package org.eclipse.jdt.internal.compiler.ast;
11
package org.eclipse.jdt.internal.compiler.ast;
12
12
13
import org.eclipse.jdt.internal.compiler.flow.FlowContext;
14
import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
15
import org.eclipse.jdt.internal.compiler.impl.*;
13
import org.eclipse.jdt.internal.compiler.impl.*;
16
import org.eclipse.jdt.internal.compiler.lookup.*;
14
import org.eclipse.jdt.internal.compiler.lookup.*;
17
15
Lines 23-36 Link Here
23
		this.sourceEnd = e;
21
		this.sourceEnd = e;
24
	}
22
	}
25
23
26
	public FlowInfo analyseCode(
27
		BlockScope currentScope,
28
		FlowContext flowContext,
29
		FlowInfo flowInfo) {
30
31
		return flowInfo;
32
	}
33
34
	public abstract void computeConstant();
24
	public abstract void computeConstant();
35
25
36
	public abstract TypeBinding literalType(BlockScope scope);
26
	public abstract TypeBinding literalType(BlockScope scope);
(-)compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java (-27 / +27 lines)
Lines 34-68 Link Here
34
		this.declarationEnd = sourceEnd;
34
		this.declarationEnd = sourceEnd;
35
	}
35
	}
36
36
37
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
37
	public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
38
	// record variable initialization if any
38
		// record variable initialization if any
39
	if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) {
39
		if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) {
40
		this.bits |= ASTNode.IsLocalDeclarationReachable; // only set if actually reached
40
			this.bits |= ASTNode.IsLocalDeclarationReachable; // only set if actually reached
41
	}
41
		}
42
	if (this.initialization == null) {
42
		if (this.initialization == null) {
43
			return flowInfo;
44
		}
45
		if ((this.initialization.implicitConversion & TypeIds.UNBOXING) != 0) {
46
			this.initialization.checkNPE(currentScope, flowContext, flowInfo);
47
		}
48
		int nullStatus = this.initialization.nullStatus(flowInfo);
49
		flowInfo =
50
			this.initialization
51
				.analyseCode(currentScope, flowContext, flowInfo, true) // at this point we must assume that the local is used, thus the side effect requires the value
52
				.unconditionalInits();
53
		if (!flowInfo.isDefinitelyAssigned(this.binding)){// for local variable debug attributes
54
			this.bits |= FirstAssignmentToLocal;
55
		} else {
56
			this.bits &= ~FirstAssignmentToLocal;  // int i = (i = 0);
57
		}
58
		flowInfo.markAsDefinitelyAssigned(this.binding);
59
		if ((this.binding.type.tagBits & TagBits.IsBaseType) == 0) {
60
			flowInfo.markNullStatus(this.binding, nullStatus);
61
			// no need to inform enclosing try block since its locals won't get
62
			// known by the finally block
63
		}
43
		return flowInfo;
64
		return flowInfo;
44
	}
65
	}
45
	if ((this.initialization.implicitConversion & TypeIds.UNBOXING) != 0) {
46
		this.initialization.checkNPE(currentScope, flowContext, flowInfo);
47
	}
48
	int nullStatus = this.initialization.nullStatus(flowInfo);
49
	flowInfo =
50
		this.initialization
51
			.analyseCode(currentScope, flowContext, flowInfo)
52
			.unconditionalInits();
53
	if (!flowInfo.isDefinitelyAssigned(this.binding)){// for local variable debug attributes
54
		this.bits |= FirstAssignmentToLocal;
55
	} else {
56
		this.bits &= ~FirstAssignmentToLocal;  // int i = (i = 0);
57
	}
58
	flowInfo.markAsDefinitelyAssigned(this.binding);
59
	if ((this.binding.type.tagBits & TagBits.IsBaseType) == 0) {
60
		flowInfo.markNullStatus(this.binding, nullStatus);
61
		// no need to inform enclosing try block since its locals won't get
62
		// known by the finally block
63
	}
64
	return flowInfo;
65
}
66
66
67
	public void checkModifiers() {
67
	public void checkModifiers() {
68
68
(-)compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java (-2 / +4 lines)
Lines 56-62 Link Here
56
	public TypeReference[] typeArguments;
56
	public TypeReference[] typeArguments;
57
	public TypeBinding[] genericTypeArguments;
57
	public TypeBinding[] genericTypeArguments;
58
58
59
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
59
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
60
	// method execution may have side effect => require values from all child nodes
61
	// - exception: receiver of call to static method 
60
	boolean nonStatic = !this.binding.isStatic();
62
	boolean nonStatic = !this.binding.isStatic();
61
	flowInfo = this.receiver.analyseCode(currentScope, flowContext, flowInfo, nonStatic).unconditionalInits();
63
	flowInfo = this.receiver.analyseCode(currentScope, flowContext, flowInfo, nonStatic).unconditionalInits();
62
	if (nonStatic) {
64
	if (nonStatic) {
Lines 69-75 Link Here
69
			if ((this.arguments[i].implicitConversion & TypeIds.UNBOXING) != 0) {
71
			if ((this.arguments[i].implicitConversion & TypeIds.UNBOXING) != 0) {
70
				this.arguments[i].checkNPE(currentScope, flowContext, flowInfo);
72
				this.arguments[i].checkNPE(currentScope, flowContext, flowInfo);
71
			}
73
			}
72
			flowInfo = this.arguments[i].analyseCode(currentScope, flowContext, flowInfo).unconditionalInits();
74
			flowInfo = this.arguments[i].analyseCode(currentScope, flowContext, flowInfo, true).unconditionalInits();
73
		}
75
		}
74
	}
76
	}
75
	ReferenceBinding[] thrownExceptions;
77
	ReferenceBinding[] thrownExceptions;
(-)compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java (-1 / +1 lines)
Lines 86-92 Link Here
86
				for (int i = 0, count = this.statements.length; i < count; i++) {
86
				for (int i = 0, count = this.statements.length; i < count; i++) {
87
					Statement stat = this.statements[i];
87
					Statement stat = this.statements[i];
88
					if ((complaintLevel = stat.complainIfUnreachable(flowInfo, this.scope, complaintLevel)) < Statement.COMPLAINED_UNREACHABLE) {
88
					if ((complaintLevel = stat.complainIfUnreachable(flowInfo, this.scope, complaintLevel)) < Statement.COMPLAINED_UNREACHABLE) {
89
						flowInfo = stat.analyseCode(this.scope, methodContext, flowInfo);
89
						flowInfo = stat.analyseCode(this.scope, methodContext, flowInfo, false);
90
					}
90
					}
91
				}
91
				}
92
			}
92
			}
(-)compiler/org/eclipse/jdt/internal/compiler/ast/OR_OR_Expression.java (-5 / +6 lines)
Lines 30-36 Link Here
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
		boolean valueRequired) {
34
35
35
		Constant cst = this.left.optimizedBooleanConstant();
36
		Constant cst = this.left.optimizedBooleanConstant();
36
		boolean isLeftOptimizedTrue = cst != Constant.NotAConstant && cst.booleanValue() == true;
37
		boolean isLeftOptimizedTrue = cst != Constant.NotAConstant && cst.booleanValue() == true;
Lines 40-53 Link Here
40
			// FALSE || anything
41
			// FALSE || anything
41
			 // need to be careful of scenario:
42
			 // need to be careful of scenario:
42
			//		(x || y) || !z, if passing the left info to the right, it would be swapped by the !
43
			//		(x || y) || !z, if passing the left info to the right, it would be swapped by the !
43
			FlowInfo mergedInfo = this.left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits();
44
			FlowInfo mergedInfo = this.left.analyseCode(currentScope, flowContext, flowInfo, false).unconditionalInits(); // subject to optimization
44
			mergedInfo = this.right.analyseCode(currentScope, flowContext, mergedInfo);
45
			mergedInfo = this.right.analyseCode(currentScope, flowContext, mergedInfo, valueRequired);
45
			this.mergedInitStateIndex =
46
			this.mergedInitStateIndex =
46
				currentScope.methodScope().recordInitializationStates(mergedInfo);
47
				currentScope.methodScope().recordInitializationStates(mergedInfo);
47
			return mergedInfo;
48
			return mergedInfo;
48
		}
49
		}
49
50
50
		FlowInfo leftInfo = this.left.analyseCode(currentScope, flowContext, flowInfo);
51
		FlowInfo leftInfo = this.left.analyseCode(currentScope, flowContext, flowInfo, valueRequired);
51
52
52
		 // need to be careful of scenario:
53
		 // need to be careful of scenario:
53
		//		(x || y) || !z, if passing the left info to the right, it would be swapped by the !
54
		//		(x || y) || !z, if passing the left info to the right, it would be swapped by the !
Lines 62-68 Link Here
62
				rightInfo.setReachMode(FlowInfo.UNREACHABLE);
63
				rightInfo.setReachMode(FlowInfo.UNREACHABLE);
63
			}
64
			}
64
		}
65
		}
65
		rightInfo = this.right.analyseCode(currentScope, flowContext, rightInfo);
66
		rightInfo = this.right.analyseCode(currentScope, flowContext, rightInfo, !isLeftOptimizedTrue); // unused if left is true
66
		if ((this.left.implicitConversion & TypeIds.UNBOXING) != 0) {
67
		if ((this.left.implicitConversion & TypeIds.UNBOXING) != 0) {
67
			this.left.checkNPE(currentScope, flowContext, flowInfo);
68
			this.left.checkNPE(currentScope, flowContext, flowInfo);
68
		}
69
		}
(-)compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java (-4 / +6 lines)
Lines 54-63 Link Here
54
		anonymousType.allocation = this;
54
		anonymousType.allocation = this;
55
	}
55
	}
56
56
57
	public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
57
	public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
58
		// constructor may have side effect => thus require values from all child nodes
59
		
58
		// analyse the enclosing instance
60
		// analyse the enclosing instance
59
		if (this.enclosingInstance != null) {
61
		if (this.enclosingInstance != null) {
60
			flowInfo = this.enclosingInstance.analyseCode(currentScope, flowContext, flowInfo);
62
			flowInfo = this.enclosingInstance.analyseCode(currentScope, flowContext, flowInfo, true);
61
		}
63
		}
62
64
63
		// check captured variables are initialized in current context (26134)
65
		// check captured variables are initialized in current context (26134)
Lines 71-77 Link Here
71
		// process arguments
73
		// process arguments
72
		if (this.arguments != null) {
74
		if (this.arguments != null) {
73
			for (int i = 0, count = this.arguments.length; i < count; i++) {
75
			for (int i = 0, count = this.arguments.length; i < count; i++) {
74
				flowInfo = this.arguments[i].analyseCode(currentScope, flowContext, flowInfo);
76
				flowInfo = this.arguments[i].analyseCode(currentScope, flowContext, flowInfo, true);
75
				if ((this.arguments[i].implicitConversion & TypeIds.UNBOXING) != 0) {
77
				if ((this.arguments[i].implicitConversion & TypeIds.UNBOXING) != 0) {
76
					this.arguments[i].checkNPE(currentScope, flowContext, flowInfo);
78
					this.arguments[i].checkNPE(currentScope, flowContext, flowInfo);
77
				}
79
				}
Lines 80-86 Link Here
80
82
81
		// analyse the anonymous nested type
83
		// analyse the anonymous nested type
82
		if (this.anonymousType != null) {
84
		if (this.anonymousType != null) {
83
			flowInfo = this.anonymousType.analyseCode(currentScope, flowContext, flowInfo);
85
			flowInfo = this.anonymousType.analyseCode(currentScope, flowContext, flowInfo, false); // not a value
84
		}
86
		}
85
87
86
		// record some dependency information for exception types
88
		// record some dependency information for exception types
(-)compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java (-9 / +14 lines)
Lines 60-66 Link Here
60
	this.sourceEnd = sourceEnd;
60
	this.sourceEnd = sourceEnd;
61
}
61
}
62
62
63
public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound) {
63
public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound, boolean valueRequired) {
64
	// determine the rank until which we now we do not need any actual value for the field access
64
	// determine the rank until which we now we do not need any actual value for the field access
65
	int otherBindingsCount = this.otherBindings == null ? 0 : this.otherBindings.length;
65
	int otherBindingsCount = this.otherBindings == null ? 0 : this.otherBindings.length;
66
	boolean needValue = otherBindingsCount == 0 || !this.otherBindings[0].isStatic();
66
	boolean needValue = otherBindingsCount == 0 || !this.otherBindings[0].isStatic();
Lines 116-121 Link Here
116
	}
116
	}
117
117
118
	if (isCompound) {
118
	if (isCompound) {
119
		// https://bugs.eclipse.org/bugs/show_bug.cgi?id=328830
120
		reportOnlyUselesslyReadPrivateField(currentScope, lastFieldBinding, valueRequired);
119
		if (otherBindingsCount == 0
121
		if (otherBindingsCount == 0
120
				&& lastFieldBinding.isBlankFinal()
122
				&& lastFieldBinding.isBlankFinal()
121
				&& currentScope.needBlankFinalFieldInitializationCheck(lastFieldBinding)) {
123
				&& currentScope.needBlankFinalFieldInitializationCheck(lastFieldBinding)) {
Lines 131-137 Link Here
131
		flowInfo =
133
		flowInfo =
132
			assignment
134
			assignment
133
				.expression
135
				.expression
134
				.analyseCode(currentScope, flowContext, flowInfo)
136
				.analyseCode(currentScope, flowContext, flowInfo, true) // assignment side effect => require value
135
				.unconditionalInits();
137
				.unconditionalInits();
136
	}
138
	}
137
139
Lines 161-176 Link Here
161
	return flowInfo;
163
	return flowInfo;
162
}
164
}
163
165
164
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
165
	return analyseCode(currentScope, flowContext, flowInfo, true);
166
}
167
168
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
166
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
169
	// determine the rank until which we now we do not need any actual value for the field access
167
	// determine the rank until which we now we do not need any actual value for the field access
170
	int otherBindingsCount = this.otherBindings == null ? 0 : this.otherBindings.length;
168
	int otherBindingsCount = this.otherBindings == null ? 0 : this.otherBindings.length;
171
169
172
	boolean needValue = otherBindingsCount == 0 ? valueRequired : !this.otherBindings[0].isStatic();
170
	boolean needValue = otherBindingsCount == 0 ? valueRequired : !this.otherBindings[0].isStatic();
173
	boolean complyTo14 = currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4;
171
	boolean complyTo14 = currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4;
172
	FieldBinding lastFieldBinding = null;
174
	switch (this.bits & ASTNode.RestrictiveFlagMASK) {
173
	switch (this.bits & ASTNode.RestrictiveFlagMASK) {
175
		case Binding.FIELD : // reading a field
174
		case Binding.FIELD : // reading a field
176
			if (needValue || complyTo14) {
175
			if (needValue || complyTo14) {
Lines 186-191 Link Here
186
						currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this);
185
						currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this);
187
					}
186
					}
188
				}
187
				}
188
				lastFieldBinding = fieldBinding;
189
			}
189
			}
190
			break;
190
			break;
191
		case Binding.LOCAL : // reading a local variable
191
		case Binding.LOCAL : // reading a local variable
Lines 213-219 Link Here
213
				manageSyntheticAccessIfNecessary(currentScope, this.otherBindings[i], i + 1, flowInfo);
213
				manageSyntheticAccessIfNecessary(currentScope, this.otherBindings[i], i + 1, flowInfo);
214
			}
214
			}
215
		}
215
		}
216
		lastFieldBinding = this.otherBindings[otherBindingsCount-1];
216
	}
217
	}
218
	if (lastFieldBinding != null)
219
		// https://bugs.eclipse.org/bugs/show_bug.cgi?id=328830
220
		reportOnlyUselesslyReadPrivateField(currentScope, lastFieldBinding, valueRequired);
217
	return flowInfo;
221
	return flowInfo;
218
}
222
}
219
223
Lines 382-388 Link Here
382
public void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) {
386
public void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) {
383
	FieldBinding lastFieldBinding = generateReadSequence(currentScope, codeStream);
387
	FieldBinding lastFieldBinding = generateReadSequence(currentScope, codeStream);
384
	// check if compound assignment is the only usage of a private field
388
	// check if compound assignment is the only usage of a private field
385
	reportOnlyUselesslyReadPrivateField(currentScope, lastFieldBinding, valueRequired);
386
	boolean isFirst = lastFieldBinding == this.binding
389
	boolean isFirst = lastFieldBinding == this.binding
387
		&& (this.indexOfFirstFieldBinding == 1 || lastFieldBinding.declaringClass == currentScope.enclosingReceiverType())
390
		&& (this.indexOfFirstFieldBinding == 1 || lastFieldBinding.declaringClass == currentScope.enclosingReceiverType())
388
		&& this.otherBindings == null; // could be dup: next.next.next
391
		&& this.otherBindings == null; // could be dup: next.next.next
Lines 434-441 Link Here
434
437
435
public void generatePostIncrement(BlockScope currentScope, CodeStream codeStream, CompoundAssignment postIncrement, boolean valueRequired) {
438
public void generatePostIncrement(BlockScope currentScope, CodeStream codeStream, CompoundAssignment postIncrement, boolean valueRequired) {
436
	FieldBinding lastFieldBinding = generateReadSequence(currentScope, codeStream);
439
	FieldBinding lastFieldBinding = generateReadSequence(currentScope, codeStream);
437
	// check if this post increment is the only usage of a private field
438
	reportOnlyUselesslyReadPrivateField(currentScope, lastFieldBinding, valueRequired);
439
	boolean isFirst = lastFieldBinding == this.binding
440
	boolean isFirst = lastFieldBinding == this.binding
440
		&& (this.indexOfFirstFieldBinding == 1 || lastFieldBinding.declaringClass == currentScope.enclosingReceiverType())
441
		&& (this.indexOfFirstFieldBinding == 1 || lastFieldBinding.declaringClass == currentScope.enclosingReceiverType())
441
		&& this.otherBindings == null; // could be dup: next.next.next
442
		&& this.otherBindings == null; // could be dup: next.next.next
Lines 919-924 Link Here
919
	// field and/or local are done before type lookups
920
	// field and/or local are done before type lookups
920
	// the only available value for the restrictiveFlag BEFORE
921
	// the only available value for the restrictiveFlag BEFORE
921
	// the TC is Flag_Type Flag_LocalField and Flag_TypeLocalField
922
	// the TC is Flag_Type Flag_LocalField and Flag_TypeLocalField
923
924
	if (scope.isInsideCondition)
925
		this.bits |= ASTNode.IsInsideCondition;
926
922
	this.actualReceiverType = scope.enclosingReceiverType();
927
	this.actualReceiverType = scope.enclosingReceiverType();
923
	this.constant = Constant.NotAConstant;
928
	this.constant = Constant.NotAConstant;
924
	if ((this.binding = scope.getBinding(this.tokens, this.bits & ASTNode.RestrictiveFlagMASK, this, true /*resolve*/)).isValidBinding()) {
929
	if ((this.binding = scope.getBinding(this.tokens, this.bits & ASTNode.RestrictiveFlagMASK, this, true /*resolve*/)).isValidBinding()) {
(-)compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedThisReference.java (-20 / +5 lines)
Lines 11-20 Link Here
11
package org.eclipse.jdt.internal.compiler.ast;
11
package org.eclipse.jdt.internal.compiler.ast;
12
12
13
import org.eclipse.jdt.internal.compiler.ASTVisitor;
13
import org.eclipse.jdt.internal.compiler.ASTVisitor;
14
import org.eclipse.jdt.internal.compiler.codegen.*;
14
import org.eclipse.jdt.internal.compiler.codegen.CodeStream;
15
import org.eclipse.jdt.internal.compiler.flow.*;
16
import org.eclipse.jdt.internal.compiler.impl.Constant;
15
import org.eclipse.jdt.internal.compiler.impl.Constant;
17
import org.eclipse.jdt.internal.compiler.lookup.*;
16
import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
17
import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
18
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
19
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
18
20
19
public class QualifiedThisReference extends ThisReference {
21
public class QualifiedThisReference extends ThisReference {
20
22
Lines 28-50 Link Here
28
		this.sourceStart = name.sourceStart;
30
		this.sourceStart = name.sourceStart;
29
	}
31
	}
30
32
31
	public FlowInfo analyseCode(
32
		BlockScope currentScope,
33
		FlowContext flowContext,
34
		FlowInfo flowInfo) {
35
36
		return flowInfo;
37
	}
38
39
	public FlowInfo analyseCode(
40
		BlockScope currentScope,
41
		FlowContext flowContext,
42
		FlowInfo flowInfo,
43
		boolean valueRequired) {
44
45
		return flowInfo;
46
	}
47
48
	/**
33
	/**
49
	 * Code generation for QualifiedThisReference
34
	 * Code generation for QualifiedThisReference
50
	 *
35
	 *
(-)compiler/org/eclipse/jdt/internal/compiler/ast/Reference.java (-52 / +1 lines)
Lines 18-26 Link Here
18
import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
18
import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
19
import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers;
19
import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers;
20
import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
20
import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
21
import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
22
import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
21
import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
23
import org.eclipse.jdt.internal.compiler.lookup.MethodScope;
24
import org.eclipse.jdt.internal.compiler.lookup.Scope;
22
import org.eclipse.jdt.internal.compiler.lookup.Scope;
25
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
23
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
26
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
24
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
Lines 32-42 Link Here
32
public Reference() {
30
public Reference() {
33
	super();
31
	super();
34
}
32
}
35
public abstract FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound);
33
public abstract FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound, boolean valueRequired);
36
37
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
38
	return flowInfo;
39
}
40
34
41
public FieldBinding fieldBinding() {
35
public FieldBinding fieldBinding() {
42
	//this method should be sent one FIELD-tagged references
36
	//this method should be sent one FIELD-tagged references
Lines 114-162 Link Here
114
		}
108
		}
115
	}
109
	}
116
}
110
}
117
/* report a local/arg that is only read from a 'special operator',
118
 * i.e., in a postIncrement expression or a compound assignment,
119
 * where the information is never flowing out off the local/arg. */
120
static void reportOnlyUselesslyReadLocal(BlockScope currentScope, LocalVariableBinding localBinding, boolean valueRequired) {
121
	if (localBinding.declaration == null)
122
		return;  // secret local
123
	if ((localBinding.declaration.bits & ASTNode.IsLocalDeclarationReachable) == 0)
124
		return;  // declaration is unreachable
125
	if (localBinding.useFlag >= LocalVariableBinding.USED)
126
		return;  // we're only interested in cases with only compound access (negative count)
127
128
	if (valueRequired) {
129
		// access is relevant
130
		localBinding.useFlag = LocalVariableBinding.USED;
131
		return;
132
	} else {
133
		localBinding.useFlag++;
134
		if (localBinding.useFlag != LocalVariableBinding.UNUSED) // have all negative counts been consumed?
135
			return; // still waiting to see more usages of this kind
136
	}
137
	// at this point we know we have something to report
138
	if (localBinding.declaration instanceof Argument) {
139
		// check compiler options to report against unused arguments
140
		MethodScope methodScope = currentScope.methodScope();
141
		if (methodScope != null) {
142
			MethodBinding method = ((AbstractMethodDeclaration)methodScope.referenceContext()).binding;
143
			
144
			boolean shouldReport = !method.isMain();
145
			if (method.isImplementing()) {
146
				shouldReport &= currentScope.compilerOptions().reportUnusedParameterWhenImplementingAbstract;
147
			} else if (method.isOverriding()) {
148
				shouldReport &= currentScope.compilerOptions().reportUnusedParameterWhenOverridingConcrete;
149
			}
150
			
151
			if (shouldReport) {
152
				// report the case of an argument that is unread except through a special operator
153
				currentScope.problemReporter().unusedArgument(localBinding.declaration);
154
			}
155
		}
156
	} else {
157
		// report the case of a local variable that is unread except for a special operator
158
		currentScope.problemReporter().unusedLocalVariable(localBinding.declaration);
159
	}
160
	localBinding.useFlag = LocalVariableBinding.USED; // don't report again
161
}
162
}
111
}
(-)compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java (-2 / +2 lines)
Lines 30-42 Link Here
30
	this.expression = expression ;
30
	this.expression = expression ;
31
}
31
}
32
32
33
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {	// here requires to generate a sequence of finally blocks invocations depending corresponding
33
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {	// here requires to generate a sequence of finally blocks invocations depending corresponding
34
	// to each of the traversed try statements, so that execution will terminate properly.
34
	// to each of the traversed try statements, so that execution will terminate properly.
35
35
36
	// lookup the label, this should answer the returnContext
36
	// lookup the label, this should answer the returnContext
37
37
38
	if (this.expression != null) {
38
	if (this.expression != null) {
39
		flowInfo = this.expression.analyseCode(currentScope, flowContext, flowInfo);
39
		flowInfo = this.expression.analyseCode(currentScope, flowContext, flowInfo, true);
40
		if ((this.expression.implicitConversion & TypeIds.UNBOXING) != 0) {
40
		if ((this.expression.implicitConversion & TypeIds.UNBOXING) != 0) {
41
			this.expression.checkNPE(currentScope, flowContext, flowInfo);
41
			this.expression.checkNPE(currentScope, flowContext, flowInfo);
42
		}
42
		}
(-)compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java (-38 / +34 lines)
Lines 57-63 Link Here
57
	this.sourceEnd = (int) pos;
57
	this.sourceEnd = (int) pos;
58
}
58
}
59
59
60
public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound) {
60
public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound, boolean valueRequired) {
61
	boolean isReachable = (flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0;
61
	boolean isReachable = (flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0;
62
	// compound assignment extra work
62
	// compound assignment extra work
63
	if (isCompound) { // check the variable part is initialized if blank final
63
	if (isCompound) { // check the variable part is initialized if blank final
Lines 72-77 Link Here
72
					}
72
					}
73
				}
73
				}
74
				manageSyntheticAccessIfNecessary(currentScope, flowInfo, true /*read-access*/);
74
				manageSyntheticAccessIfNecessary(currentScope, flowInfo, true /*read-access*/);
75
				// https://bugs.eclipse.org/bugs/show_bug.cgi?id=328830
76
				reportOnlyUselesslyReadPrivateField(currentScope, fieldBinding, valueRequired);
75
				break;
77
				break;
76
			case Binding.LOCAL : // reading a local variable
78
			case Binding.LOCAL : // reading a local variable
77
				// check if assigning a final blank field
79
				// check if assigning a final blank field
Lines 80-100 Link Here
80
					currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
82
					currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
81
					// we could improve error msg here telling "cannot use compound assignment on final local variable"
83
					// we could improve error msg here telling "cannot use compound assignment on final local variable"
82
				}
84
				}
83
				if (localBinding.useFlag != LocalVariableBinding.USED) {
85
				if (isReachable) {
84
					// https://bugs.eclipse.org/bugs/show_bug.cgi?id=185682
86
					// https://bugs.eclipse.org/bugs/show_bug.cgi?id=185682
85
					// access from compound assignment does not prevent "unused" warning, unless unboxing is involved:
87
					// https://bugs.eclipse.org/bugs/show_bug.cgi?id=328830
86
					if (isReachable && (this.implicitConversion & TypeIds.UNBOXING) != 0) {
88
					// access from compound assignment does not prevent "unused" warning / optimization
89
					if ((this.implicitConversion & TypeIds.UNBOXING) != 0	// cannot optimize if unboxing is involved 
90
							|| valueRequired) 								// cannot optimize if value is required
91
					{
87
						localBinding.useFlag = LocalVariableBinding.USED;
92
						localBinding.useFlag = LocalVariableBinding.USED;
88
					} else {
89
						// use values < 0 to count the number of compound uses:
90
						if (localBinding.useFlag <= LocalVariableBinding.UNUSED)
91
							localBinding.useFlag--;
92
					}
93
					}
94
				} else if (localBinding.useFlag == LocalVariableBinding.UNUSED) {
95
					localBinding.useFlag = LocalVariableBinding.FAKE_USED;
93
				}
96
				}
94
		}
97
		}
95
	}
98
	}
96
	if (assignment.expression != null) {
99
	if (assignment.expression != null) {
97
		flowInfo = assignment.expression.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits();
100
		flowInfo = assignment.expression.analyseCode(currentScope, flowContext, flowInfo, true).unconditionalInits();
98
	}
101
	}
99
	switch (this.bits & ASTNode.RestrictiveFlagMASK) {
102
	switch (this.bits & ASTNode.RestrictiveFlagMASK) {
100
		case Binding.FIELD : // assigning to a field
103
		case Binding.FIELD : // assigning to a field
Lines 146-155 Link Here
146
	return flowInfo;
149
	return flowInfo;
147
}
150
}
148
151
149
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
150
	return analyseCode(currentScope, flowContext, flowInfo, true);
151
}
152
153
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
152
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
154
	switch (this.bits & ASTNode.RestrictiveFlagMASK) {
153
	switch (this.bits & ASTNode.RestrictiveFlagMASK) {
155
		case Binding.FIELD : // reading a field
154
		case Binding.FIELD : // reading a field
Lines 158-163 Link Here
158
			}
157
			}
159
			// check if reading a final blank field
158
			// check if reading a final blank field
160
			FieldBinding fieldBinding = (FieldBinding) this.binding;
159
			FieldBinding fieldBinding = (FieldBinding) this.binding;
160
			// https://bugs.eclipse.org/bugs/show_bug.cgi?id=328830
161
			reportOnlyUselesslyReadPrivateField(currentScope, fieldBinding.original(), valueRequired);
161
			if (fieldBinding.isBlankFinal() && currentScope.needBlankFinalFieldInitializationCheck(fieldBinding)) {
162
			if (fieldBinding.isBlankFinal() && currentScope.needBlankFinalFieldInitializationCheck(fieldBinding)) {
162
				FlowInfo fieldInits = flowContext.getInitsForFinalBlankInitializationCheck(fieldBinding.declaringClass.original(), flowInfo);
163
				FlowInfo fieldInits = flowContext.getInitsForFinalBlankInitializationCheck(fieldBinding.declaringClass.original(), flowInfo);
163
				if (!fieldInits.isDefinitelyAssigned(fieldBinding)) {
164
				if (!fieldInits.isDefinitelyAssigned(fieldBinding)) {
Lines 171-177 Link Here
171
				currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
172
				currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
172
			}
173
			}
173
			if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) {
174
			if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) {
174
				localBinding.useFlag = LocalVariableBinding.USED;
175
				// check possibility for optimization (https://bugs.eclipse.org/328830):
176
				if ((this.implicitConversion & TypeIds.UNBOXING) != 0	// cannot optimize if unboxing is involved 
177
						|| valueRequired) 								// cannot optimize if value is required
178
				{
179
					localBinding.useFlag = LocalVariableBinding.USED;
180
				}
175
			} else if (localBinding.useFlag == LocalVariableBinding.UNUSED) {
181
			} else if (localBinding.useFlag == LocalVariableBinding.UNUSED) {
176
				localBinding.useFlag = LocalVariableBinding.FAKE_USED;
182
				localBinding.useFlag = LocalVariableBinding.FAKE_USED;
177
			}
183
			}
Lines 427-433 Link Here
427
					if (valueRequired) {
433
					if (valueRequired) {
428
						// restart code gen
434
						// restart code gen
429
						localBinding.useFlag = LocalVariableBinding.USED;
435
						localBinding.useFlag = LocalVariableBinding.USED;
430
						throw new AbortMethod(CodeStream.RESTART_CODE_GEN_FOR_UNUSED_LOCALS_MODE, null);
436
						//throw new AbortMethod(CodeStream.RESTART_CODE_GEN_FOR_UNUSED_LOCALS_MODE, null);
437
						currentScope.problemReporter().abortDueToInternalError("Unexpected unresolved local");
431
					}
438
					}
432
					codeStream.recordPositionsFrom(pc, this.sourceStart);
439
					codeStream.recordPositionsFrom(pc, this.sourceStart);
433
					return;
440
					return;
Lines 479-495 Link Here
479
 * are optimized in one access: e.g "a = a + 1" optimized into "a++".
486
 * are optimized in one access: e.g "a = a + 1" optimized into "a++".
480
 */
487
 */
481
public void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) {
488
public void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) {
482
	// https://bugs.eclipse.org/bugs/show_bug.cgi?id=185682
483
	switch (this.bits & ASTNode.RestrictiveFlagMASK) {
484
		case Binding.LOCAL:
485
			LocalVariableBinding localBinding = (LocalVariableBinding) this.binding;
486
			// check if compound assignment is the only usage of this local
487
			Reference.reportOnlyUselesslyReadLocal(currentScope, localBinding, valueRequired);
488
			break;
489
		case Binding.FIELD:
490
			// check if compound assignment is the only usage of a private field
491
			reportOnlyUselesslyReadPrivateField(currentScope, (FieldBinding)this.binding, valueRequired);
492
	}
493
	this.generateCompoundAssignment(
489
	this.generateCompoundAssignment(
494
		currentScope,
490
		currentScope,
495
		codeStream,
491
		codeStream,
Lines 538-548 Link Here
538
			Constant assignConstant;
534
			Constant assignConstant;
539
			switch (localBinding.type.id) {
535
			switch (localBinding.type.id) {
540
				case T_JavaLangString :
536
				case T_JavaLangString :
541
					codeStream.generateStringConcatenationAppend(currentScope, this, expression);
537
					if (valueRequired || localBinding.useFlag > LocalVariableBinding.UNUSED) {
542
					if (valueRequired) {
538
						codeStream.generateStringConcatenationAppend(currentScope, this, expression);
543
						codeStream.dup();
539
						if (valueRequired) {
540
							codeStream.dup();
541
						}
542
						codeStream.store(localBinding, false);
544
					}
543
					}
545
					codeStream.store(localBinding, false);
546
					return;
544
					return;
547
				case T_int :
545
				case T_int :
548
					assignConstant = expression.constant;
546
					assignConstant = expression.constant;
Lines 554-560 Link Here
554
							 * - the constant can have potential side-effect
552
							 * - the constant can have potential side-effect
555
							 */
553
							 */
556
							localBinding.useFlag = LocalVariableBinding.USED;
554
							localBinding.useFlag = LocalVariableBinding.USED;
557
							throw new AbortMethod(CodeStream.RESTART_CODE_GEN_FOR_UNUSED_LOCALS_MODE, null);
555
//							throw new AbortMethod(CodeStream.RESTART_CODE_GEN_FOR_UNUSED_LOCALS_MODE, null);
556
							currentScope.problemReporter().abortDueToInternalError("Unexpected unresolved local");
558
						} else if (assignConstant == Constant.NotAConstant) {
557
						} else if (assignConstant == Constant.NotAConstant) {
559
							// we only need to generate the value of the expression's constant if it is not a constant expression
558
							// we only need to generate the value of the expression's constant if it is not a constant expression
560
							expression.generateCode(currentScope, codeStream, false);
559
							expression.generateCode(currentScope, codeStream, false);
Lines 660-668 Link Here
660
	switch (this.bits & ASTNode.RestrictiveFlagMASK) {
659
	switch (this.bits & ASTNode.RestrictiveFlagMASK) {
661
		case Binding.FIELD : // assigning to a field
660
		case Binding.FIELD : // assigning to a field
662
			FieldBinding fieldBinding = (FieldBinding)this.binding;
661
			FieldBinding fieldBinding = (FieldBinding)this.binding;
663
			// https://bugs.eclipse.org/bugs/show_bug.cgi?id=185682
664
			// check if postIncrement is the only usage of a private field
665
			reportOnlyUselesslyReadPrivateField(currentScope, fieldBinding, valueRequired);
666
			FieldBinding codegenField = fieldBinding.original();
662
			FieldBinding codegenField = fieldBinding.original();
667
			if (codegenField.isStatic()) {
663
			if (codegenField.isStatic()) {
668
				if ((this.syntheticAccessors == null) || (this.syntheticAccessors[SingleNameReference.READ] == null)) {
664
				if ((this.syntheticAccessors == null) || (this.syntheticAccessors[SingleNameReference.READ] == null)) {
Lines 726-739 Link Here
726
			return;
722
			return;
727
		case Binding.LOCAL : // assigning to a local variable
723
		case Binding.LOCAL : // assigning to a local variable
728
			LocalVariableBinding localBinding = (LocalVariableBinding) this.binding;
724
			LocalVariableBinding localBinding = (LocalVariableBinding) this.binding;
729
			// https://bugs.eclipse.org/bugs/show_bug.cgi?id=185682
730
			// check if postIncrement is the only usage of this local
731
			Reference.reportOnlyUselesslyReadLocal(currentScope, localBinding, valueRequired);
732
			if (localBinding.resolvedPosition == -1) {
725
			if (localBinding.resolvedPosition == -1) {
733
				if (valueRequired) {
726
				if (valueRequired) {
734
					// restart code gen
727
					// restart code gen
735
					localBinding.useFlag = LocalVariableBinding.USED;
728
					localBinding.useFlag = LocalVariableBinding.USED;
736
					throw new AbortMethod(CodeStream.RESTART_CODE_GEN_FOR_UNUSED_LOCALS_MODE, null);
729
//					throw new AbortMethod(CodeStream.RESTART_CODE_GEN_FOR_UNUSED_LOCALS_MODE, null);
730
					currentScope.problemReporter().abortDueToInternalError("Unexpected unresolved local");
737
				}
731
				}
738
				return;
732
				return;
739
			}
733
			}
Lines 914-919 Link Here
914
}
908
}
915
909
916
public TypeBinding resolveType(BlockScope scope) {
910
public TypeBinding resolveType(BlockScope scope) {
911
	if (scope.isInsideCondition)
912
		this.bits |= ASTNode.IsInsideCondition;
917
	// for code gen, harm the restrictiveFlag
913
	// for code gen, harm the restrictiveFlag
918
914
919
	if (this.actualReceiverType != null) {
915
	if (this.actualReceiverType != null) {
(-)compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java (-1 / +1 lines)
Lines 48-54 Link Here
48
//		}
48
//		}
49
		return false;
49
		return false;
50
	}
50
	}
51
public abstract FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo);
51
public abstract FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired);
52
52
53
	public static final int NOT_COMPLAINED = 0;
53
	public static final int NOT_COMPLAINED = 0;
54
	public static final int COMPLAINED_FAKE_REACHABLE = 1;
54
	public static final int COMPLAINED_FAKE_REACHABLE = 1;
(-)compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java (-5 / +16 lines)
Lines 45-53 Link Here
45
	int preSwitchInitStateIndex = -1;
45
	int preSwitchInitStateIndex = -1;
46
	int mergedInitStateIndex = -1;
46
	int mergedInitStateIndex = -1;
47
47
48
	public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
48
	public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
49
		try {
49
		try {
50
			flowInfo = this.expression.analyseCode(currentScope, flowContext, flowInfo);
50
			boolean expressionValueRequired = this.caseCount != 0 || 					// case-less: subject to optimization
51
								((this.expression.constant == Constant.NotAConstant) 	// constant branching ...
52
										&& (this.expression.implicitConversion & TypeIds.UNBOXING) != 0); // ... which cannot throw NPE?
53
			flowInfo = this.expression.analyseCode(currentScope, flowContext, flowInfo, expressionValueRequired);
51
			if ((this.expression.implicitConversion & TypeIds.UNBOXING) != 0) {
54
			if ((this.expression.implicitConversion & TypeIds.UNBOXING) != 0) {
52
				this.expression.checkNPE(currentScope, flowContext, flowInfo);
55
				this.expression.checkNPE(currentScope, flowContext, flowInfo);
53
			}
56
			}
Lines 89-95 Link Here
89
						fallThroughState = FALLTHROUGH; // reset below if needed
92
						fallThroughState = FALLTHROUGH; // reset below if needed
90
					}
93
					}
91
					if ((complaintLevel = statement.complainIfUnreachable(caseInits, this.scope, complaintLevel)) < Statement.COMPLAINED_UNREACHABLE) {
94
					if ((complaintLevel = statement.complainIfUnreachable(caseInits, this.scope, complaintLevel)) < Statement.COMPLAINED_UNREACHABLE) {
92
						caseInits = statement.analyseCode(this.scope, switchContext, caseInits);
95
						caseInits = statement.analyseCode(this.scope, switchContext, caseInits, false); // analyse as statement => ignore value
93
						if (caseInits == FlowInfo.DEAD_END) {
96
						if (caseInits == FlowInfo.DEAD_END) {
94
							fallThroughState = ESCAPING;
97
							fallThroughState = ESCAPING;
95
						}
98
						}
Lines 162-168 Link Here
162
					codeStream.pop();
165
					codeStream.pop();
163
				}
166
				}
164
			} else {
167
			} else {
165
				valueRequired = this.expression.constant == Constant.NotAConstant || hasCases;
168
				valueRequired = hasCases || 
169
								((this.expression.constant == Constant.NotAConstant) 
170
									&& (this.expression.implicitConversion & TypeIds.UNBOXING) != 0);
166
				// generate expression
171
				// generate expression
167
				this.expression.generateCode(currentScope, codeStream, valueRequired);
172
				this.expression.generateCode(currentScope, codeStream, valueRequired);
168
			}
173
			}
Lines 267-273 Link Here
267
	public void resolve(BlockScope upperScope) {
272
	public void resolve(BlockScope upperScope) {
268
		try {
273
		try {
269
			boolean isEnumSwitch = false;
274
			boolean isEnumSwitch = false;
270
			TypeBinding expressionType = this.expression.resolveType(upperScope);
275
			TypeBinding expressionType = null;
276
			try {
277
				upperScope.isInsideCondition = true;
278
				expressionType = this.expression.resolveType(upperScope);
279
			} finally  {
280
				upperScope.isInsideCondition = false;
281
			}
271
			if (expressionType != null) {
282
			if (expressionType != null) {
272
				this.expression.computeConversion(upperScope, expressionType, expressionType);
283
				this.expression.computeConversion(upperScope, expressionType, expressionType);
273
				checkType: {
284
				checkType: {
(-)compiler/org/eclipse/jdt/internal/compiler/ast/SynchronizedStatement.java (-6 / +3 lines)
Lines 40-50 Link Here
40
	this.sourceEnd = e;
40
	this.sourceEnd = e;
41
	this.sourceStart = s;
41
	this.sourceStart = s;
42
}
42
}
43
43
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
44
public FlowInfo analyseCode(
45
	BlockScope currentScope,
46
	FlowContext flowContext,
47
	FlowInfo flowInfo) {
48
44
49
	this.preSynchronizedInitStateIndex =
45
	this.preSynchronizedInitStateIndex =
50
		currentScope.methodScope().recordInitializationStates(flowInfo);
46
		currentScope.methodScope().recordInitializationStates(flowInfo);
Lines 58-64 Link Here
58
		this.block.analyseCode(
54
		this.block.analyseCode(
59
			this.scope,
55
			this.scope,
60
			new InsideSubRoutineFlowContext(flowContext, this),
56
			new InsideSubRoutineFlowContext(flowContext, this),
61
			this.expression.analyseCode(this.scope, flowContext, flowInfo));
57
			this.expression.analyseCode(this.scope, flowContext, flowInfo, true), // require expression value 
58
			false); 															  // ignore value of statements
62
59
63
	this.mergedSynchronizedInitStateIndex =
60
	this.mergedSynchronizedInitStateIndex =
64
		currentScope.methodScope().recordInitializationStates(flowInfo);
61
		currentScope.methodScope().recordInitializationStates(flowInfo);
(-)compiler/org/eclipse/jdt/internal/compiler/ast/ThisReference.java (-1 / +1 lines)
Lines 35-41 Link Here
35
	/*
35
	/*
36
	 * @see Reference#analyseAssignment(...)
36
	 * @see Reference#analyseAssignment(...)
37
	 */
37
	 */
38
	public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound) {
38
	public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound, boolean valueRequired) {
39
39
40
		return flowInfo; // this cannot be assigned
40
		return flowInfo; // this cannot be assigned
41
	}
41
	}
(-)compiler/org/eclipse/jdt/internal/compiler/ast/ThrowStatement.java (-2 / +2 lines)
Lines 30-37 Link Here
30
	this.sourceEnd = sourceEnd;
30
	this.sourceEnd = sourceEnd;
31
}
31
}
32
32
33
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
33
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
34
	this.exception.analyseCode(currentScope, flowContext, flowInfo);
34
	this.exception.analyseCode(currentScope, flowContext, flowInfo, true); // cannot optimize
35
	this.exception.checkNPE(currentScope, flowContext, flowInfo);
35
	this.exception.checkNPE(currentScope, flowContext, flowInfo);
36
	// need to check that exception thrown is actually caught somewhere
36
	// need to check that exception thrown is actually caught somewhere
37
	flowContext.checkExceptionHandlers(this.exceptionType, this, flowInfo, currentScope);
37
	flowContext.checkExceptionHandlers(this.exceptionType, this, flowInfo, currentScope);
(-)compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java (-14 / +9 lines)
Lines 61-68 Link Here
61
	int naturalExitMergeInitStateIndex = -1;
61
	int naturalExitMergeInitStateIndex = -1;
62
	int[] catchExitInitStateIndexes;
62
	int[] catchExitInitStateIndexes;
63
63
64
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
65
64
65
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
66
	// 
67
	
66
	// Consider the try block and catch block so as to compute the intersection of initializations and
68
	// Consider the try block and catch block so as to compute the intersection of initializations and
67
	// the minimum exit relative depth amongst all of them. Then consider the subroutine, and append its
69
	// the minimum exit relative depth amongst all of them. Then consider the subroutine, and append its
68
	// initialization to the try/catch ones, if the subroutine completes normally. If the subroutine does not
70
	// initialization to the try/catch ones, if the subroutine completes normally. If the subroutine does not
Lines 99-105 Link Here
99
		if (this.tryBlock.isEmptyBlock()) {
101
		if (this.tryBlock.isEmptyBlock()) {
100
			tryInfo = flowInfo;
102
			tryInfo = flowInfo;
101
		} else {
103
		} else {
102
			tryInfo = this.tryBlock.analyseCode(currentScope, handlingContext, flowInfo.copy());
104
			tryInfo = this.tryBlock.analyseCode(currentScope, handlingContext, flowInfo.copy(), false); // statements, ignore values
103
			if ((tryInfo.tagBits & FlowInfo.UNREACHABLE) != 0)
105
			if ((tryInfo.tagBits & FlowInfo.UNREACHABLE) != 0)
104
				this.bits |= ASTNode.IsTryBlockExiting;
106
				this.bits |= ASTNode.IsTryBlockExiting;
105
		}
107
		}
Lines 151-161 Link Here
151
				if (this.tryBlock.statements == null) {
153
				if (this.tryBlock.statements == null) {
152
					catchInfo.setReachMode(FlowInfo.UNREACHABLE);
154
					catchInfo.setReachMode(FlowInfo.UNREACHABLE);
153
				}
155
				}
154
				catchInfo =
156
				catchInfo = this.catchBlocks[i].analyseCode(currentScope, flowContext, catchInfo, false); // statements, ignore values
155
					this.catchBlocks[i].analyseCode(
156
						currentScope,
157
						flowContext,
158
						catchInfo);
159
				this.catchExitInitStateIndexes[i] = currentScope.methodScope().recordInitializationStates(catchInfo);
157
				this.catchExitInitStateIndexes[i] = currentScope.methodScope().recordInitializationStates(catchInfo);
160
				this.catchExits[i] =
158
				this.catchExits[i] =
161
					(catchInfo.tagBits & FlowInfo.UNREACHABLE) != 0;
159
					(catchInfo.tagBits & FlowInfo.UNREACHABLE) != 0;
Lines 183-189 Link Here
183
				.analyseCode(
181
				.analyseCode(
184
					currentScope,
182
					currentScope,
185
					finallyContext = new FinallyFlowContext(flowContext, this.finallyBlock),
183
					finallyContext = new FinallyFlowContext(flowContext, this.finallyBlock),
186
					flowInfo.nullInfoLessUnconditionalCopy())
184
					flowInfo.nullInfoLessUnconditionalCopy(),
185
				 	false)  // statements, ignore values
187
				.unconditionalInits();
186
				.unconditionalInits();
188
		if (subInfo == FlowInfo.DEAD_END) {
187
		if (subInfo == FlowInfo.DEAD_END) {
189
			this.bits |= ASTNode.IsSubRoutineEscaping;
188
			this.bits |= ASTNode.IsSubRoutineEscaping;
Lines 208-214 Link Here
208
		if (this.tryBlock.isEmptyBlock()) {
207
		if (this.tryBlock.isEmptyBlock()) {
209
			tryInfo = flowInfo;
208
			tryInfo = flowInfo;
210
		} else {
209
		} else {
211
			tryInfo = this.tryBlock.analyseCode(currentScope, handlingContext, flowInfo.copy());
210
			tryInfo = this.tryBlock.analyseCode(currentScope, handlingContext, flowInfo.copy(), false); // statements, ignore values
212
			if ((tryInfo.tagBits & FlowInfo.UNREACHABLE) != 0)
211
			if ((tryInfo.tagBits & FlowInfo.UNREACHABLE) != 0)
213
				this.bits |= ASTNode.IsTryBlockExiting;
212
				this.bits |= ASTNode.IsTryBlockExiting;
214
		}
213
		}
Lines 260-270 Link Here
260
				if (this.tryBlock.statements == null) {
259
				if (this.tryBlock.statements == null) {
261
					catchInfo.setReachMode(FlowInfo.UNREACHABLE);
260
					catchInfo.setReachMode(FlowInfo.UNREACHABLE);
262
				}
261
				}
263
				catchInfo =
262
				catchInfo =	this.catchBlocks[i].analyseCode(currentScope, insideSubContext, catchInfo, false);  // statements, ignore values
264
					this.catchBlocks[i].analyseCode(
265
						currentScope,
266
						insideSubContext,
267
						catchInfo);
268
				this.catchExitInitStateIndexes[i] = currentScope.methodScope().recordInitializationStates(catchInfo);
263
				this.catchExitInitStateIndexes[i] = currentScope.methodScope().recordInitializationStates(catchInfo);
269
				this.catchExits[i] =
264
				this.catchExits[i] =
270
					(catchInfo.tagBits & FlowInfo.UNREACHABLE) != 0;
265
					(catchInfo.tagBits & FlowInfo.UNREACHABLE) != 0;
(-)compiler/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java (-1 / +1 lines)
Lines 187-193 Link Here
187
 *	Flow analysis for a local innertype
187
 *	Flow analysis for a local innertype
188
 *
188
 *
189
 */
189
 */
190
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
190
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
191
	if (this.ignoreFurtherInvestigation)
191
	if (this.ignoreFurtherInvestigation)
192
		return flowInfo;
192
		return flowInfo;
193
	try {
193
	try {
(-)compiler/org/eclipse/jdt/internal/compiler/ast/TypeReference.java (-5 lines)
Lines 11-18 Link Here
11
package org.eclipse.jdt.internal.compiler.ast;
11
package org.eclipse.jdt.internal.compiler.ast;
12
12
13
import org.eclipse.jdt.internal.compiler.ASTVisitor;
13
import org.eclipse.jdt.internal.compiler.ASTVisitor;
14
import org.eclipse.jdt.internal.compiler.flow.FlowContext;
15
import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
16
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
14
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
17
import org.eclipse.jdt.internal.compiler.impl.Constant;
15
import org.eclipse.jdt.internal.compiler.impl.Constant;
18
import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
16
import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
Lines 82-90 Link Here
82
public void aboutToResolve(Scope scope) {
80
public void aboutToResolve(Scope scope) {
83
	// default implementation: do nothing
81
	// default implementation: do nothing
84
}
82
}
85
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
86
	return flowInfo;
87
}
88
public void checkBounds(Scope scope) {
83
public void checkBounds(Scope scope) {
89
	// only parameterized type references have bounds
84
	// only parameterized type references have bounds
90
}
85
}
(-)compiler/org/eclipse/jdt/internal/compiler/ast/UnaryExpression.java (-14 / +13 lines)
Lines 26-46 Link Here
26
		this.expression = expression;
26
		this.expression = expression;
27
		this.bits |= operator << OperatorSHIFT; // encode operator
27
		this.bits |= operator << OperatorSHIFT; // encode operator
28
	}
28
	}
29
29
	public FlowInfo analyseCode(
30
public FlowInfo analyseCode(
30
			BlockScope currentScope,
31
		BlockScope currentScope,
31
			FlowContext flowContext,
32
		FlowContext flowContext,
32
			FlowInfo flowInfo, boolean valueRequired) {
33
		FlowInfo flowInfo) {
33
		this.expression.checkNPE(currentScope, flowContext, flowInfo);
34
	this.expression.checkNPE(currentScope, flowContext, flowInfo);
34
		if (((this.bits & OperatorMASK) >> OperatorSHIFT) == NOT) {
35
	if (((this.bits & OperatorMASK) >> OperatorSHIFT) == NOT) {
35
			return this.expression.
36
		return this.expression.
36
				analyseCode(currentScope, flowContext, flowInfo, valueRequired).
37
			analyseCode(currentScope, flowContext, flowInfo).
37
				asNegatedCondition();
38
			asNegatedCondition();
38
		} else {
39
	} else {
39
			return this.expression.
40
		return this.expression.
40
				analyseCode(currentScope, flowContext, flowInfo, valueRequired);
41
			analyseCode(currentScope, flowContext, flowInfo);
41
		}
42
	}
42
	}
43
}
44
43
45
	public Constant optimizedBooleanConstant() {
44
	public Constant optimizedBooleanConstant() {
46
45
(-)compiler/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java (-5 / +11 lines)
Lines 37-43 Link Here
37
		this.sourceEnd = e;
37
		this.sourceEnd = e;
38
	}
38
	}
39
39
40
	public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
40
	public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
41
41
42
		this.breakLabel = new BranchLabel();
42
		this.breakLabel = new BranchLabel();
43
		this.continueLabel = new BranchLabel();
43
		this.continueLabel = new BranchLabel();
Lines 63-69 Link Here
63
				(condLoopContext =
63
				(condLoopContext =
64
					new LoopingFlowContext(flowContext, flowInfo, this, null,
64
					new LoopingFlowContext(flowContext, flowInfo, this, null,
65
						null, currentScope)),
65
						null, currentScope)),
66
				condInfo);
66
				condInfo,
67
				!isConditionOptimizedFalse); // may optimize condition value if never entering the loop
67
		if ((this.condition.implicitConversion & TypeIds.UNBOXING) != 0) {
68
		if ((this.condition.implicitConversion & TypeIds.UNBOXING) != 0) {
68
			this.condition.checkNPE(currentScope, flowContext, flowInfo);
69
			this.condition.checkNPE(currentScope, flowContext, flowInfo);
69
		}
70
		}
Lines 114-120 Link Here
114
					condInfo.initsWhenTrue());
115
					condInfo.initsWhenTrue());
115
116
116
			if (this.action.complainIfUnreachable(actionInfo, currentScope, initialComplaintLevel) < Statement.COMPLAINED_UNREACHABLE) {
117
			if (this.action.complainIfUnreachable(actionInfo, currentScope, initialComplaintLevel) < Statement.COMPLAINED_UNREACHABLE) {
117
				actionInfo = this.action.analyseCode(currentScope, loopingContext, actionInfo);
118
				actionInfo = this.action.analyseCode(currentScope, loopingContext, actionInfo, false); // statements, ignore values
118
			}
119
			}
119
120
120
			// code generation can be optimized when no need to continue in the loop
121
			// code generation can be optimized when no need to continue in the loop
Lines 254-261 Link Here
254
	}
255
	}
255
256
256
	public void resolve(BlockScope scope) {
257
	public void resolve(BlockScope scope) {
257
258
		TypeBinding type = null;
258
		TypeBinding type = this.condition.resolveTypeExpecting(scope, TypeBinding.BOOLEAN);
259
		try {
260
			scope.isInsideCondition = true;
261
			type = this.condition.resolveTypeExpecting(scope, TypeBinding.BOOLEAN);
262
		} finally  {
263
			scope.isInsideCondition = false;
264
		}
259
		this.condition.computeConversion(scope, type, type);
265
		this.condition.computeConversion(scope, type, type);
260
		if (this.action != null)
266
		if (this.action != null)
261
			this.action.resolve(scope);
267
			this.action.resolve(scope);
(-)compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java (+2 lines)
Lines 35-40 Link Here
35
	// record the current case statement being processed (for entire switch case block).
35
	// record the current case statement being processed (for entire switch case block).
36
	public CaseStatement enclosingCase; // from 1.4 on, local types should not be accessed across switch case blocks (52221)
36
	public CaseStatement enclosingCase; // from 1.4 on, local types should not be accessed across switch case blocks (52221)
37
37
38
	public boolean isInsideCondition = false;
39
38
	public final static VariableBinding[] EmulationPathToImplicitThis = {};
40
	public final static VariableBinding[] EmulationPathToImplicitThis = {};
39
	public final static VariableBinding[] NoEnclosingInstanceInConstructorCall = {};
41
	public final static VariableBinding[] NoEnclosingInstanceInConstructorCall = {};
40
42
(-)compiler/org/eclipse/jdt/internal/compiler/lookup/LocalVariableBinding.java (-1 / +1 lines)
Lines 27-33 Link Here
27
	public static final int UNUSED = 0;
27
	public static final int UNUSED = 0;
28
	public static final int USED = 1;
28
	public static final int USED = 1;
29
	public static final int FAKE_USED = 2;
29
	public static final int FAKE_USED = 2;
30
	public int useFlag; // for flow analysis (default is UNUSED), values < 0 indicate the number of compound uses (postIncrement or compoundAssignment)
30
	public int useFlag; // for flow analysis (default is UNUSED)
31
31
32
	public BlockScope declaringScope; // back-pointer to its declaring scope
32
	public BlockScope declaringScope; // back-pointer to its declaring scope
33
	public LocalDeclaration declaration; // for source-positions
33
	public LocalDeclaration declaration; // for source-positions
(-)eval/org/eclipse/jdt/internal/eval/CodeSnippetReturnStatement.java (-2 / +2 lines)
Lines 35-42 Link Here
35
	super(expr, s, e);
35
	super(expr, s, e);
36
}
36
}
37
37
38
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
38
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
39
	FlowInfo info = super.analyseCode(currentScope, flowContext, flowInfo);
39
	FlowInfo info = super.analyseCode(currentScope, flowContext, flowInfo, valueRequired);
40
	// we need to remove this optimization in order to prevent the inlining of the return bytecode
40
	// we need to remove this optimization in order to prevent the inlining of the return bytecode
41
	// 1GH0AU7: ITPJCORE:ALL - Eval - VerifyError in scrapbook page
41
	// 1GH0AU7: ITPJCORE:ALL - Eval - VerifyError in scrapbook page
42
	this.expression.bits &= ~IsReturnedValue;
42
	this.expression.bits &= ~IsReturnedValue;
(-)src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java (-8 / +19 lines)
Lines 5950-5962 Link Here
5950
  + " -warn:+null"
5950
  + " -warn:+null"
5951
  + " -proceedOnError -referenceInfo -d \"" + OUTPUT_DIR + "\"",
5951
  + " -proceedOnError -referenceInfo -d \"" + OUTPUT_DIR + "\"",
5952
  "",
5952
  "",
5953
  "----------\n" +
5953
  "----------\n" + 
5954
  "1. WARNING in ---OUTPUT_DIR_PLACEHOLDER---/X.java (at line 4)\n" +
5954
  "1. WARNING in ---OUTPUT_DIR_PLACEHOLDER---/X.java (at line 3)\n" + 
5955
  "	if (o == null) {}\n" +
5955
  "	Object o = null;\n" + 
5956
  "	    ^\n" +
5956
  "	       ^\n" + 
5957
  "Redundant null check: The variable o can only be null at this location\n" +
5957
  "The value of the local variable o is not used\n" + 
5958
  "----------\n" +
5958
  "----------\n" + 
5959
  "1 problem (1 warning)",
5959
  "2. WARNING in ---OUTPUT_DIR_PLACEHOLDER---/X.java (at line 4)\n" + 
5960
  "	if (o == null) {}\n" + 
5961
  "	    ^\n" + 
5962
  "Redundant null check: The variable o can only be null at this location\n" + 
5963
  "----------\n" + 
5964
  "2 problems (2 warnings)",
5960
  true);
5965
  true);
5961
}
5966
}
5962
// null ref option
5967
// null ref option
Lines 5979-5985 Link Here
5979
+ " -warn:+nullDereference"
5984
+ " -warn:+nullDereference"
5980
+ " -proceedOnError -referenceInfo -d \"" + OUTPUT_DIR + "\"",
5985
+ " -proceedOnError -referenceInfo -d \"" + OUTPUT_DIR + "\"",
5981
"",
5986
"",
5982
"",
5987
"----------\n" + 
5988
"1. WARNING in ---OUTPUT_DIR_PLACEHOLDER---/X.java (at line 3)\n" + 
5989
"	Object o = null;\n" + 
5990
"	       ^\n" + 
5991
"The value of the local variable o is not used\n" + 
5992
"----------\n" + 
5993
"1 problem (1 warning)",
5983
true);
5994
true);
5984
}
5995
}
5985
//https://bugs.eclipse.org/bugs/show_bug.cgi?id=190493
5996
//https://bugs.eclipse.org/bugs/show_bug.cgi?id=190493
(-)src/org/eclipse/jdt/core/tests/compiler/regression/FlowAnalysisTest.java (-2 / +7 lines)
Lines 1836-1847 Link Here
1836
		"	      ^^^^^\n" + 
1836
		"	      ^^^^^\n" + 
1837
		"The type Local is never used locally\n" + 
1837
		"The type Local is never used locally\n" + 
1838
		"----------\n" + 
1838
		"----------\n" + 
1839
		"3. WARNING in X.java (at line 7)\n" + 
1839
		"3. WARNING in X.java (at line 5)\n" + 
1840
		"	int i = 12;\n" + 
1841
		"	    ^\n" + 
1842
		"The value of the field Local.i is not used\n" + 
1843
		"----------\n" + 
1844
		"4. WARNING in X.java (at line 7)\n" + 
1840
		"	void method() {\n" + 
1845
		"	void method() {\n" + 
1841
		"	     ^^^^^^^^\n" + 
1846
		"	     ^^^^^^^^\n" + 
1842
		"The method method() from the type Local is never used locally\n" + 
1847
		"The method method() from the type Local is never used locally\n" + 
1843
		"----------\n" + 
1848
		"----------\n" + 
1844
		"4. ERROR in X.java (at line 11)\n" + 
1849
		"5. ERROR in X.java (at line 11)\n" + 
1845
		"	return;\n" + 
1850
		"	return;\n" + 
1846
		"	^^^^^^^\n" + 
1851
		"	^^^^^^^\n" + 
1847
		"Unreachable code\n" + 
1852
		"Unreachable code\n" + 
(-)src/org/eclipse/jdt/core/tests/compiler/regression/ForeachStatementTest.java (-2 / +24 lines)
Lines 38-44 Link Here
38
// Static initializer to specify tests subset using TESTS_* static variables
38
// Static initializer to specify tests subset using TESTS_* static variables
39
// All specified tests which do not belong to the class are skipped...
39
// All specified tests which do not belong to the class are skipped...
40
static {
40
static {
41
//	TESTS_NAMES = new String[] { "test000" };
41
//	TESTS_NAMES = new String[] { "test026" };
42
//	TESTS_NUMBERS = new int[] { 50, 51, 52, 53 };
42
//	TESTS_NUMBERS = new int[] { 50, 51, 52, 53 };
43
//	TESTS_RANGE = new int[] { 34, 38 };
43
//	TESTS_RANGE = new int[] { 34, 38 };
44
}
44
}
Lines 1245-1251 Link Here
1245
			"    void test() {\n" +
1245
			"    void test() {\n" +
1246
			"        for (Object object : array) {\n" +
1246
			"        for (Object object : array) {\n" +
1247
			"            String str = object.toString();\n" +
1247
			"            String str = object.toString();\n" +
1248
			"            str += \"\";\n" + // force 'str' to be preserved during codegen
1248
			"            str += \"\";\n" + // try force 'str' to be preserved during codegen (can still be optimized out)
1249
			"        }\n" +
1250
			"    }\n" +
1251
			"    public static void main(String[] args) {\n" +
1252
			"        new X().test();\n" +
1253
			"		System.out.println(\"SUCCESS\");\n" +
1254
			"    }\n" +
1255
			"}\n",
1256
		},
1257
		"SUCCESS");
1258
}
1259
// 68440 - verify error due to local variable invalid slot sharing
1260
public void test026a() {
1261
	this.runConformTest(
1262
		new String[] {
1263
			"X.java",
1264
			"public class X {\n" +
1265
			"    Object[] array = {\n" +
1266
			"    };\n" +
1267
			"    void test() {\n" +
1268
			"        for (Object object : array) {\n" +
1269
			"            String str = object.toString();\n" +
1270
			"            System.out.print(str);\n" + // really force 'str' to be preserved during codegen
1249
			"        }\n" +
1271
			"        }\n" +
1250
			"    }\n" +
1272
			"    }\n" +
1251
			"    public static void main(String[] args) {\n" +
1273
			"    public static void main(String[] args) {\n" +
(-)src/org/eclipse/jdt/core/tests/compiler/regression/ProgrammingProblemsTest.java (-3 / +982 lines)
Lines 36-43 Link Here
36
  	// Only the highest compliance level is run; add the VM argument
36
  	// Only the highest compliance level is run; add the VM argument
37
  	// -Dcompliance=1.4 (for example) to lower it if needed
37
  	// -Dcompliance=1.4 (for example) to lower it if needed
38
  	static {
38
  	static {
39
//    	TESTS_NAMES = new String[] { "test0055" };
39
//    	TESTS_NAMES = new String[] { "test0059" };
40
//		TESTS_NUMBERS = new int[] { 56 };
40
//		TESTS_NUMBERS = new int[] { 70 };
41
//  	TESTS_RANGE = new int[] { 1, -1 };
41
//  	TESTS_RANGE = new int[] { 1, -1 };
42
  	}
42
  	}
43
43
Lines 2279-2282 Link Here
2279
		customOptions,
2279
		customOptions,
2280
		null);
2280
		null);
2281
}
2281
}
2282
}
2282
// https://bugs.eclipse.org/328830  -  Variable should be marked unused when it can be optimized out
2283
// SingleNameReference, local, postIncr, emptyThen
2284
public void test0058()  throws Exception {
2285
	Map customOptions = getCompilerOptions();
2286
	customOptions.put(CompilerOptions.OPTION_ReportUnusedLocal, CompilerOptions.ERROR);	
2287
	this.runNegativeTest(
2288
		new String[] {
2289
			"X.java",
2290
			"public class X {\n" +
2291
			"	public void method() {\n" +
2292
			"		int a=10;\n" +
2293
			" 		if(a++ > 10) {\n" + // not counted as relevant use since bug 185682
2294
			"		}\n" +   
2295
			"    }\n" +
2296
			"}\n"
2297
		},
2298
		"----------\n" + 
2299
		"1. ERROR in X.java (at line 3)\n" + 
2300
		"	int a=10;\n" + 
2301
		"	    ^\n" + 
2302
		"The value of the local variable a is not used\n" + 
2303
		"----------\n",
2304
		null/*classLibraries*/,
2305
		true/*shouldFlushOutputDirectory*/,
2306
		customOptions);
2307
}
2308
// https://bugs.eclipse.org/328830  -  Variable should be marked unused when it can be optimized out
2309
// SingleNameReference, field, postIncr, emptyThenWithElse
2310
public void test0059()  throws Exception {
2311
	Map customOptions = getCompilerOptions();
2312
	customOptions.put(CompilerOptions.OPTION_ReportUnusedPrivateMember, CompilerOptions.ERROR);	
2313
	customOptions.put(CompilerOptions.OPTION_ReportDeadCode, CompilerOptions.IGNORE);	
2314
	this.runNegativeTest(
2315
		new String[] {
2316
			"X.java",
2317
			"public class X {\n" +
2318
			"	private int a=10;\n" +
2319
			"	public void method() {\n" +
2320
			" 		if(true || (a++ > 10 && false)) {\n" + // not counted as relevant use since bug 185682
2321
			"			System.out.println(\"OK\");\n" +   
2322
			"		} else {\n" +   
2323
			"			System.out.println(\"NOK\");\n" +   
2324
			"		}\n" +   
2325
			"   }\n" +
2326
			"}\n"
2327
		},
2328
		"----------\n" + 
2329
		"1. ERROR in X.java (at line 2)\n" + 
2330
		"	private int a=10;\n" + 
2331
		"	            ^\n" + 
2332
		"The value of the field X.a is not used\n" + 
2333
		"----------\n",
2334
		null/*classLibraries*/,
2335
		true/*shouldFlushOutputDirectory*/,
2336
		customOptions);
2337
}
2338
// https://bugs.eclipse.org/328830  -  Variable should be marked unused when it can be optimized out
2339
// FieldReference, field, postIncr, optimizableCondition
2340
public void test0060()  throws Exception {
2341
	Map customOptions = getCompilerOptions();
2342
	customOptions.put(CompilerOptions.OPTION_ReportUnusedPrivateMember, CompilerOptions.ERROR);	
2343
	customOptions.put(CompilerOptions.OPTION_ReportDeadCode, CompilerOptions.IGNORE);	
2344
	this.runNegativeTest(
2345
		new String[] {
2346
			"X.java",
2347
			"public class X {\n" +
2348
			"	private int a=10;\n" +
2349
			"	public void method() {\n" +
2350
			" 		if(this.a++ > 10 || true) {\n" + // not counted as relevant use since bug 185682
2351
			"			System.out.println(\"OK\");\n" +
2352
			"		}\n" +   
2353
			"   }\n" +
2354
			"}\n"
2355
		},
2356
		"----------\n" + 
2357
		"1. ERROR in X.java (at line 2)\n" + 
2358
		"	private int a=10;\n" + 
2359
		"	            ^\n" + 
2360
		"The value of the field X.a is not used\n" + 
2361
		"----------\n",
2362
		null/*classLibraries*/,
2363
		true/*shouldFlushOutputDirectory*/,
2364
		customOptions);
2365
}
2366
2367
// https://bugs.eclipse.org/328830  -  Variable should be marked unused when it can be optimized out
2368
// SingleNameReference, local, simpleRead, emptyThen
2369
public void test0061()  throws Exception {
2370
	Map customOptions = getCompilerOptions();
2371
	customOptions.put(CompilerOptions.OPTION_ReportUnusedLocal, CompilerOptions.ERROR);	
2372
	this.runNegativeTest(
2373
		new String[] {
2374
			"X.java",
2375
			"public class X {\n" +
2376
			"	public void method() {\n" +
2377
			"		int a=10;\n" +
2378
			" 		if(a > 10) {\n" +
2379
			"		}\n" +   
2380
			"    }\n" +
2381
			"}\n"
2382
		},
2383
		"----------\n" + 
2384
		"1. ERROR in X.java (at line 3)\n" + 
2385
		"	int a=10;\n" + 
2386
		"	    ^\n" + 
2387
		"The value of the local variable a is not used\n" + 
2388
		"----------\n",
2389
		null/*classLibraries*/,
2390
		true/*shouldFlushOutputDirectory*/,
2391
		customOptions);
2392
}
2393
// https://bugs.eclipse.org/328830  -  Variable should be marked unused when it can be optimized out
2394
// SingleNameReference, field, simpleRead, emptyThenWithElse
2395
public void test0062()  throws Exception {
2396
	Map customOptions = getCompilerOptions();
2397
	customOptions.put(CompilerOptions.OPTION_ReportUnusedPrivateMember, CompilerOptions.ERROR);	
2398
	customOptions.put(CompilerOptions.OPTION_ReportDeadCode, CompilerOptions.IGNORE);	
2399
	this.runNegativeTest(
2400
		new String[] {
2401
			"X.java",
2402
			"public class X {\n" +
2403
			"	private int a=10;\n" +
2404
			"	public void method() {\n" +
2405
			" 		if(a > 10 && false) {\n" +
2406
			"		} else {\n" +   
2407
			"			System.out.println(\"OK\");\n" +   
2408
			"		}\n" +   
2409
			"   }\n" +
2410
			"}\n"
2411
		},
2412
		"----------\n" + 
2413
		"1. ERROR in X.java (at line 2)\n" + 
2414
		"	private int a=10;\n" + 
2415
		"	            ^\n" + 
2416
		"The value of the field X.a is not used\n" + 
2417
		"----------\n",
2418
		null/*classLibraries*/,
2419
		true/*shouldFlushOutputDirectory*/,
2420
		customOptions);
2421
}
2422
// https://bugs.eclipse.org/328830  -  Variable should be marked unused when it can be optimized out
2423
// FieldReference+QualifiedNameReference, field, simpleRead, optimizableCondition
2424
public void test0063()  throws Exception {
2425
	Map customOptions = getCompilerOptions();
2426
	customOptions.put(CompilerOptions.OPTION_ReportUnusedPrivateMember, CompilerOptions.ERROR);	
2427
	customOptions.put(CompilerOptions.OPTION_ReportDeadCode, CompilerOptions.IGNORE);	
2428
	this.runNegativeTest(
2429
		new String[] {
2430
			"X.java",
2431
			"public class X {\n" +
2432
			"	private int a=10;\n" +
2433
			"	public void method(X other) {\n" +
2434
			" 		if(this.a < 3 || true) {\n" +
2435
			"			System.out.println(\"OK\");\n" +
2436
			"		}\n" +   
2437
			" 		if(other.a > 10 || true) {\n" +
2438
			"			System.out.println(\"OK\");\n" +
2439
			"		}\n" +   
2440
			"   }\n" +
2441
			"}\n"
2442
		},
2443
		"----------\n" + 
2444
		"1. ERROR in X.java (at line 2)\n" + 
2445
		"	private int a=10;\n" + 
2446
		"	            ^\n" + 
2447
		"The value of the field X.a is not used\n" + 
2448
		"----------\n",
2449
		null/*classLibraries*/,
2450
		true/*shouldFlushOutputDirectory*/,
2451
		customOptions);
2452
}
2453
// https://bugs.eclipse.org/328830  -  Variable should be marked unused when it can be optimized out
2454
// FieldReference+QualifiedNameReference, field, postIncr, optimizableCondition, exprOfForWhileDoSwitch
2455
public void test0064()  throws Exception {
2456
	Map customOptions = getCompilerOptions();
2457
	customOptions.put(CompilerOptions.OPTION_ReportUnusedPrivateMember, CompilerOptions.ERROR);	
2458
	customOptions.put(CompilerOptions.OPTION_ReportDeadCode, CompilerOptions.IGNORE);	
2459
	this.runNegativeTest(
2460
		new String[] {
2461
			"X.java",
2462
			"public class X {\n" +
2463
			" 	private int a=10;\n" +
2464
			"	public void method(X other) {\n" +
2465
			" 		for(;other.a++ > 10 && false;) {\n" +
2466
			" 		}\n" +
2467
			" 		while (true || this.a++>10) {\n" +
2468
			" 		}\n" +
2469
			" 		do {\n" +
2470
			" 		} while (this.a++>10 && false);\n" +
2471
			" 		switch(a++) {\n" +
2472
			" 		}\n" +
2473
			"   }\n" +
2474
			"}\n"
2475
		},
2476
		"----------\n" + 
2477
		"1. ERROR in X.java (at line 2)\n" + 
2478
		"	private int a=10;\n" + 
2479
		"	            ^\n" + 
2480
		"The value of the field X.a is not used\n" + 
2481
		"----------\n",
2482
		null/*classLibraries*/,
2483
		true/*shouldFlushOutputDirectory*/,
2484
		customOptions);
2485
}
2486
// https://bugs.eclipse.org/328830  -  Variable should be marked unused when it can be optimized out
2487
// SingleNameReference, argument, simpleRead, optimizableCondition, exprOfForWhileDoSwitch
2488
public void test0065()  throws Exception {
2489
	Map customOptions = getCompilerOptions();
2490
	customOptions.put(CompilerOptions.OPTION_ReportUnusedParameter, CompilerOptions.ERROR);	
2491
	customOptions.put(CompilerOptions.OPTION_ReportDeadCode, CompilerOptions.IGNORE);	
2492
	this.runNegativeTest(
2493
		new String[] {
2494
			"X.java",
2495
			"public class X {\n" +
2496
			"	public void method(int a) {\n" +
2497
			" 		for(;a > 10 && false;) {\n" +
2498
			" 		}\n" +
2499
			" 		while (a>10 && false) {\n" +
2500
			" 		}\n" +
2501
			" 		do {\n" +
2502
			" 		} while (a>10 && false);\n" +
2503
			" 		switch(a) {\n" +
2504
			" 		}\n" +   
2505
			"   }\n" +
2506
			"}\n"
2507
		},
2508
		"----------\n" + 
2509
		"1. ERROR in X.java (at line 2)\n" + 
2510
		"	public void method(int a) {\n" + 
2511
		"	                       ^\n" + 
2512
		"The value of the parameter a is not used\n" + 
2513
		"----------\n",
2514
		null/*classLibraries*/,
2515
		true/*shouldFlushOutputDirectory*/,
2516
		customOptions);
2517
}
2518
// https://bugs.eclipse.org/328830  -  Variable should be marked unused when it can be optimized out
2519
// SimpleNameReference, localOfEnclosing, simpleRead, valueNeeded signaled by AbortMethod
2520
public void test0066() throws Exception {
2521
	Map customOptions = getCompilerOptions();
2522
	customOptions.put(CompilerOptions.OPTION_ReportUnusedLocal, CompilerOptions.ERROR);
2523
	this.runConformTest(
2524
		new String[] {
2525
			"X.java",
2526
			"class X {\n" + 
2527
			"    int bar() { return 23; }\n" +
2528
			"    void foo() {\n" + 
2529
			"        final int i=bar();\n" +
2530
			"        new Runnable() {\n" +
2531
			"            public void run() {\n" +
2532
			"                if (i>3) { System.out.print(4); }\n" + 	// value is used
2533
			"            }\n" + 
2534
			"        }.run();\n" + 
2535
			"    }\n" + 
2536
			"}"
2537
		},
2538
		"",
2539
		null/*classLibraries*/,
2540
		true/*shouldFlushOutputDirectory*/,
2541
		null,
2542
		customOptions,
2543
		null);
2544
	String expectedOutput =
2545
			"  // Method descriptor #6 ()V\n" + 
2546
			"  // Stack: 4, Locals: 2\n" + 
2547
			"  void foo();\n" + 
2548
			"     0  aload_0 [this]\n" + 
2549
			"     1  invokevirtual X.bar() : int [17]\n" + 
2550
			"     4  istore_1 [i]\n" + 
2551
			"     5  new X$1 [19]\n" + 
2552
			"     8  dup\n" + 
2553
			"     9  aload_0 [this]\n" + 
2554
			"    10  iload_1 [i]\n" + 
2555
			"    11  invokespecial X$1(X, int) [21]\n" + 
2556
			"    14  invokevirtual X$1.run() : void [24]\n" + 
2557
			"    17  return\n" + 
2558
			"      Line numbers:\n" + 
2559
			"        [pc: 0, line: 4]\n" + 
2560
			"        [pc: 5, line: 5]\n" + 
2561
			"        [pc: 14, line: 9]\n" + 
2562
			"        [pc: 17, line: 10]\n" + 
2563
			"      Local variable table:\n" + 
2564
			"        [pc: 0, pc: 18] local: this index: 0 type: X\n" + 
2565
			"        [pc: 5, pc: 18] local: i index: 1 type: int\n";
2566
	checkDisassembledClassFile(OUTPUT_DIR + File.separator + "X.class", "X", expectedOutput);
2567
}
2568
// https://bugs.eclipse.org/328830  -  Variable should be marked unused when it can be optimized out
2569
// SimpleNameReference, localOfEnclosing, simpleRead, emptyThen
2570
public void test0067() throws Exception {
2571
	Map customOptions = getCompilerOptions();
2572
	customOptions.put(CompilerOptions.OPTION_ReportUnusedLocal, CompilerOptions.WARNING);
2573
	this.runNegativeTest(
2574
		new String[] {
2575
			"X.java",
2576
			"class X {\n" + 
2577
			"    int bar() { return 23; }\n" +
2578
			"    void foo() {\n" + 
2579
			"        final int i=bar();\n" +
2580
			"        new Runnable() {\n" +
2581
			"            public void run() {\n" +
2582
			"                if (i>3) { }\n" + 	// value is optimized out
2583
			"            }\n" + 
2584
			"        }.run();\n" + 
2585
			"    }\n" + 
2586
			"}"
2587
		},
2588
		"----------\n" + 
2589
		"1. WARNING in X.java (at line 4)\n" + 
2590
		"	final int i=bar();\n" + 
2591
		"	          ^\n" + 
2592
		"The value of the local variable i is not used\n" + 
2593
		"----------\n",
2594
		null/*classLibraries*/,
2595
		true/*shouldFlushOutputDirectory*/,
2596
		customOptions);
2597
	String expectedOutput =
2598
			"  // Method descriptor #6 ()V\n" + 
2599
			"  // Stack: 3, Locals: 1\n" + 
2600
			"  void foo();\n" + 
2601
			"     0  aload_0 [this]\n" + 
2602
			"     1  invokevirtual X.bar() : int [17]\n" + 
2603
			"     4  pop\n" + 
2604
			"     5  new X$1 [19]\n" + 
2605
			"     8  dup\n" + 
2606
			"     9  aload_0 [this]\n" + 
2607
			"    10  invokespecial X$1(X) [21]\n" + 
2608
			"    13  invokevirtual X$1.run() : void [24]\n" + 
2609
			"    16  return\n" + 
2610
			"      Line numbers:\n" + 
2611
			"        [pc: 0, line: 4]\n" + 
2612
			"        [pc: 5, line: 5]\n" + 
2613
			"        [pc: 13, line: 9]\n" + 
2614
			"        [pc: 16, line: 10]\n" + 
2615
			"      Local variable table:\n" + 
2616
			"        [pc: 0, pc: 17] local: this index: 0 type: X\n";
2617
	checkDisassembledClassFile(OUTPUT_DIR + File.separator + "X.class", "X", expectedOutput);
2618
}
2619
// https://bugs.eclipse.org/328830  -  Variable should be marked unused when it can be optimized out
2620
// SingleNameReference, local, assignmentAsExpression, emptyThen
2621
public void test0068()  throws Exception {
2622
	Map customOptions = getCompilerOptions();
2623
	customOptions.put(CompilerOptions.OPTION_ReportUnusedLocal, CompilerOptions.WARNING);	
2624
	this.runNegativeTest(
2625
			new String[] {
2626
				"X.java",
2627
				"public class X {\n" +
2628
				"	public void method() {\n" +
2629
				"		int a=10;\n" +
2630
				"		int b;\n" +
2631
				" 		if((b=a) > 10) {\n" +
2632
				"		}\n" +   
2633
				"    }\n" +
2634
				"}\n"
2635
			},
2636
			"----------\n" + 
2637
			"1. WARNING in X.java (at line 4)\n" + 
2638
			"	int b;\n" + 
2639
			"	    ^\n" + 
2640
			"The value of the local variable b is not used\n" + 
2641
			"----------\n",
2642
			null/*classLibraries*/,
2643
			true/*shouldFlushOutputDirectory*/,
2644
			customOptions);
2645
	String expectedOutput =
2646
			"  // Method descriptor #6 ()V\n" + 
2647
			"  // Stack: 1, Locals: 2\n" + 
2648
			"  public void method();\n" + 
2649
			"    0  bipush 10\n" + 
2650
			"    2  istore_1 [a]\n" + 
2651
			"    3  iload_1 [a]\n" + 
2652
			"    4  pop\n" + 
2653
			"    5  return\n" + 
2654
			"      Line numbers:\n" + 
2655
			"        [pc: 0, line: 3]\n" + 
2656
			"        [pc: 3, line: 5]\n" + 
2657
			"        [pc: 5, line: 7]\n" + 
2658
			"      Local variable table:\n" + 
2659
			"        [pc: 0, pc: 6] local: this index: 0 type: X\n" + 
2660
			"        [pc: 3, pc: 6] local: a index: 1 type: int\n"; // b has been optimized out
2661
	checkDisassembledClassFile(OUTPUT_DIR + File.separator + "X.class", "X", expectedOutput);
2662
}
2663
// https://bugs.eclipse.org/328830  -  Variable should be marked unused when it can be optimized out
2664
// SimpleNameReference, localOfEnclosing, simpleRead, valueNeeded from local type
2665
public void test0069() throws Exception {
2666
	Map customOptions = getCompilerOptions();
2667
	customOptions.put(CompilerOptions.OPTION_ReportUnusedLocal, CompilerOptions.IGNORE);
2668
	this.runConformTest(
2669
			new String[] {
2670
					"X.java",
2671
					"public class X {\n" + 
2672
					"    int bar() { return 23; }\n" +
2673
					"    void foo() {\n" + 
2674
					"        final int i=bar();\n" +
2675
					"        new Runnable() {\n" +
2676
					"            public void run() {\n" +
2677
					"                if (i>3) {}\n" + 	// value is not used
2678
					"                System.out.print(4);\n" +
2679
					"            }\n" + 
2680
					"        }.run();\n" + 
2681
					"    }\n" + 
2682
					"	public static void main(String[] args) {\n" +
2683
					"		new  X().foo();\n" +
2684
					"	}\n" +
2685
					"}"
2686
			},
2687
			"4",
2688
			null/*classLibraries*/,
2689
			true/*shouldFlushOutputDirectory*/,
2690
			null,
2691
			customOptions,
2692
			null);
2693
	String expectedOutput =
2694
			"  // Method descriptor #6 ()V\n" + 
2695
			"  // Stack: 3, Locals: 1\n" + 
2696
			"  void foo();\n" + 
2697
			"     0  aload_0 [this]\n" + 
2698
			"     1  invokevirtual X.bar() : int [17]\n" + 
2699
			"     4  pop\n" + 
2700
			"     5  new X$1 [19]\n" + 
2701
			"     8  dup\n" + 
2702
			"     9  aload_0 [this]\n" + 
2703
			"    10  invokespecial X$1(X) [21]\n" + 
2704
			"    13  invokevirtual X$1.run() : void [24]\n" + 
2705
			"    16  return\n" + 
2706
			"      Line numbers:\n" + 
2707
			"        [pc: 0, line: 4]\n" + 
2708
			"        [pc: 5, line: 5]\n" + 
2709
			"        [pc: 13, line: 10]\n" + 
2710
			"        [pc: 16, line: 11]\n" + 
2711
			"      Local variable table:\n" + 
2712
			"        [pc: 0, pc: 17] local: this index: 0 type: X\n";
2713
	checkDisassembledClassFile(OUTPUT_DIR + File.separator + "X.class", "X", expectedOutput);
2714
	if (this.complianceLevel < ClassFileConstants.JDK1_4) {
2715
		expectedOutput =
2716
			"  // Method descriptor #11 (LX;)V\n" + 
2717
			"  // Stack: 2, Locals: 2\n" + 
2718
			"  X$1(X arg0);\n" + 
2719
			"     0  aload_0 [this]\n" + 
2720
			"     1  invokespecial java.lang.Object() [13]\n" + 
2721
			"     4  aload_0 [this]\n" + 
2722
			"     5  aload_1 [arg0]\n" + 
2723
			"     6  putfield X$1.this$0 : X [16]\n" + 
2724
			"     9  return\n" + 
2725
			"      Line numbers:\n" + 
2726
			"        [pc: 0, line: 5]\n" + 
2727
			"        [pc: 4, line: 1]\n" + 
2728
			"      Local variable table:\n" + 
2729
			"        [pc: 0, pc: 10] local: this index: 0 type: new X(){}\n";
2730
	} else if (this.complianceLevel < ClassFileConstants.JDK1_5) {
2731
		expectedOutput =
2732
			"  // Method descriptor #11 (LX;)V\n" + 
2733
			"  // Stack: 2, Locals: 2\n" + 
2734
			"  X$1(X arg0);\n" + 
2735
			"     0  aload_0 [this]\n" + 
2736
			"     1  aload_1 [arg0]\n" + 
2737
			"     2  putfield X$1.this$0 : X [13]\n" + 
2738
			"     5  aload_0 [this]\n" + 
2739
			"     6  invokespecial java.lang.Object() [15]\n" + 
2740
			"     9  return\n" + 
2741
			"      Line numbers:\n" + 
2742
			"        [pc: 0, line: 1]\n" + 
2743
			"        [pc: 5, line: 5]\n" + 
2744
			"      Local variable table:\n" + 
2745
			"        [pc: 0, pc: 10] local: this index: 0 type: new X(){}\n";
2746
	} else {
2747
		expectedOutput =
2748
			"  // Method descriptor #10 (LX;)V\n" + 
2749
			"  // Stack: 2, Locals: 2\n" + 
2750
			"  X$1(X arg0);\n" + 
2751
			"     0  aload_0 [this]\n" + 
2752
			"     1  aload_1 [arg0]\n" + 
2753
			"     2  putfield X$1.this$0 : X [12]\n" + 
2754
			"     5  aload_0 [this]\n" + 
2755
			"     6  invokespecial java.lang.Object() [14]\n" + 
2756
			"     9  return\n" + 
2757
			"      Line numbers:\n" + 
2758
			"        [pc: 0, line: 1]\n" + 
2759
			"        [pc: 5, line: 5]\n" + 
2760
			"      Local variable table:\n" + 
2761
			"        [pc: 0, pc: 10] local: this index: 0 type: new X(){}\n";
2762
	}
2763
	checkDisassembledClassFile(OUTPUT_DIR + File.separator + "X$1.class", "X$1", expectedOutput);
2764
}
2765
// https://bugs.eclipse.org/328830  -  Variable should be marked unused when it can be optimized out
2766
// SimpleNameReference, localOfEnclosing, simpleRead, valueNeeded from local type
2767
public void test0070() throws Exception {
2768
	Map customOptions = getCompilerOptions();
2769
	customOptions.put(CompilerOptions.OPTION_ReportUnusedLocal, CompilerOptions.IGNORE);
2770
	this.runConformTest(
2771
			new String[] {
2772
				"X.java",
2773
				"public class X {\n" + 
2774
				"    int bar() { return 23; }\n" +
2775
				"    public X() {\n" + 
2776
				"        final int i=bar();\n" +
2777
				"        new Runnable() {\n" +
2778
				"            public void run() {\n" +
2779
				"                if (i>3) {}\n" + 	// value is not used
2780
				"                System.out.print(4);\n" +
2781
				"            }\n" + 
2782
				"        }.run();\n" + 
2783
				"    }\n" + 
2784
				"	public static void main(String[] args) {\n" +
2785
				"		new  X();\n" +
2786
				"	}\n" +
2787
				"}"
2788
		},
2789
		"4",
2790
		null/*classLibraries*/,
2791
		true/*shouldFlushOutputDirectory*/,
2792
		null,
2793
		customOptions,
2794
		null);
2795
	String expectedOutput =
2796
			"  // Method descriptor #13 ()V\n" + 
2797
			"  // Stack: 3, Locals: 1\n" + 
2798
			"  public X();\n" + 
2799
			"     0  aload_0 [this]\n" + 
2800
			"     1  invokespecial java.lang.Object() [14]\n" + 
2801
			"     4  aload_0 [this]\n" + 
2802
			"     5  invokevirtual X.bar() : int [16]\n" + 
2803
			"     8  pop\n" + 
2804
			"     9  new X$1 [18]\n" + 
2805
			"    12  dup\n" + 
2806
			"    13  aload_0 [this]\n" + 
2807
			"    14  invokespecial X$1(X) [20]\n" + 
2808
			"    17  invokevirtual X$1.run() : void [23]\n" + 
2809
			"    20  return\n" + 
2810
			"      Line numbers:\n" + 
2811
			"        [pc: 0, line: 3]\n" + 
2812
			"        [pc: 4, line: 4]\n" + 
2813
			"        [pc: 9, line: 5]\n" + 
2814
			"        [pc: 17, line: 10]\n" + 
2815
			"        [pc: 20, line: 11]\n" + 
2816
			"      Local variable table:\n" + 
2817
			"        [pc: 0, pc: 21] local: this index: 0 type: X\n";
2818
	checkDisassembledClassFile(OUTPUT_DIR + File.separator + "X.class", "X", expectedOutput);
2819
	if (this.complianceLevel < ClassFileConstants.JDK1_4) {
2820
		expectedOutput =
2821
			"  // Method descriptor #11 (LX;)V\n" + 
2822
			"  // Stack: 2, Locals: 2\n" + 
2823
			"  X$1(X arg0);\n" + 
2824
			"     0  aload_0 [this]\n" + 
2825
			"     1  invokespecial java.lang.Object() [13]\n" + 
2826
			"     4  aload_0 [this]\n" + 
2827
			"     5  aload_1 [arg0]\n" + 
2828
			"     6  putfield X$1.this$0 : X [16]\n" + 
2829
			"     9  return\n" + 
2830
			"      Line numbers:\n" + 
2831
			"        [pc: 0, line: 5]\n" + 
2832
			"        [pc: 4, line: 1]\n" + 
2833
			"      Local variable table:\n" + 
2834
			"        [pc: 0, pc: 10] local: this index: 0 type: new X(){}\n";
2835
	} else if (this.complianceLevel < ClassFileConstants.JDK1_5) {
2836
		expectedOutput =
2837
			"  // Method descriptor #11 (LX;)V\n" + 
2838
			"  // Stack: 2, Locals: 2\n" + 
2839
			"  X$1(X arg0);\n" + 
2840
			"     0  aload_0 [this]\n" + 
2841
			"     1  aload_1 [arg0]\n" + 
2842
			"     2  putfield X$1.this$0 : X [13]\n" + 
2843
			"     5  aload_0 [this]\n" + 
2844
			"     6  invokespecial java.lang.Object() [15]\n" + 
2845
			"     9  return\n" + 
2846
			"      Line numbers:\n" + 
2847
			"        [pc: 0, line: 1]\n" + 
2848
			"        [pc: 5, line: 5]\n" + 
2849
			"      Local variable table:\n" + 
2850
			"        [pc: 0, pc: 10] local: this index: 0 type: new X(){}\n";
2851
	} else {
2852
		expectedOutput =
2853
			"  // Method descriptor #10 (LX;)V\n" + 
2854
			"  // Stack: 2, Locals: 2\n" + 
2855
			"  X$1(X arg0);\n" + 
2856
			"     0  aload_0 [this]\n" + 
2857
			"     1  aload_1 [arg0]\n" + 
2858
			"     2  putfield X$1.this$0 : X [12]\n" + 
2859
			"     5  aload_0 [this]\n" + 
2860
			"     6  invokespecial java.lang.Object() [14]\n" + 
2861
			"     9  return\n" + 
2862
			"      Line numbers:\n" + 
2863
			"        [pc: 0, line: 1]\n" + 
2864
			"        [pc: 5, line: 5]\n" + 
2865
			"      Local variable table:\n" + 
2866
			"        [pc: 0, pc: 10] local: this index: 0 type: new X(){}\n";
2867
	}
2868
	checkDisassembledClassFile(OUTPUT_DIR + File.separator + "X$1.class", "X$1", expectedOutput);
2869
}
2870
// https://bugs.eclipse.org/328830  -  Variable should be marked unused when it can be optimized out
2871
// SimpleNameReference, localOfEnclosing, simpleRead, valueNeeded from local type
2872
public void test0071() throws Exception {
2873
	Map customOptions = getCompilerOptions();
2874
	customOptions.put(CompilerOptions.OPTION_ReportUnusedLocal, CompilerOptions.ERROR);
2875
	this.runConformTest(
2876
		new String[] {
2877
			"X.java",
2878
			"public class X {\n" + 
2879
			"    int bar() { return 23; }\n" +
2880
			"    X() {\n" + 
2881
			"        final int i=bar();\n" +
2882
			"        new Runnable() {\n" +
2883
			"            public void run() {\n" +
2884
			"                if (i>3) { System.out.print(4); }\n" + 	// value is used
2885
			"            }\n" + 
2886
			"        }.run();\n" + 
2887
			"    }\n" + 
2888
			"	public static void main(String[] args) {\n" +
2889
			"		new  X();\n" +
2890
			"	}\n" +
2891
			"}"
2892
		},
2893
		"4",
2894
		null/*classLibraries*/,
2895
		true/*shouldFlushOutputDirectory*/,
2896
		null,
2897
		customOptions,
2898
		null);
2899
	String expectedOutput =
2900
		"  // Method descriptor #13 ()V\n" + 
2901
		"  // Stack: 4, Locals: 2\n" + 
2902
		"  X();\n" + 
2903
		"     0  aload_0 [this]\n" + 
2904
		"     1  invokespecial java.lang.Object() [14]\n" + 
2905
		"     4  aload_0 [this]\n" + 
2906
		"     5  invokevirtual X.bar() : int [16]\n" + 
2907
		"     8  istore_1 [i]\n" + 
2908
		"     9  new X$1 [18]\n" + 
2909
		"    12  dup\n" + 
2910
		"    13  aload_0 [this]\n" + 
2911
		"    14  iload_1 [i]\n" + 
2912
		"    15  invokespecial X$1(X, int) [20]\n" + 
2913
		"    18  invokevirtual X$1.run() : void [23]\n" + 
2914
		"    21  return\n" + 
2915
		"      Line numbers:\n" + 
2916
		"        [pc: 0, line: 3]\n" + 
2917
		"        [pc: 4, line: 4]\n" + 
2918
		"        [pc: 9, line: 5]\n" + 
2919
		"        [pc: 18, line: 9]\n" + 
2920
		"        [pc: 21, line: 10]\n" + 
2921
		"      Local variable table:\n" + 
2922
		"        [pc: 0, pc: 22] local: this index: 0 type: X\n" + 
2923
		"        [pc: 9, pc: 22] local: i index: 1 type: int\n";
2924
	checkDisassembledClassFile(OUTPUT_DIR + File.separator + "X.class", "X", expectedOutput);
2925
	if (this.complianceLevel < ClassFileConstants.JDK1_4) {
2926
		expectedOutput =
2927
				"  // Method descriptor #13 (LX;I)V\n" + 
2928
				"  // Stack: 2, Locals: 3\n" + 
2929
				"  X$1(X arg0, int arg1);\n" + 
2930
				"     0  aload_0 [this]\n" + 
2931
				"     1  invokespecial java.lang.Object() [15]\n" + 
2932
				"     4  aload_0 [this]\n" + 
2933
				"     5  aload_1 [arg0]\n" + 
2934
				"     6  putfield X$1.this$0 : X [18]\n" + 
2935
				"     9  aload_0 [this]\n" + 
2936
				"    10  iload_2 [arg1]\n" + 
2937
				"    11  putfield X$1.val$i : int [20]\n" + 
2938
				"    14  return\n" + 
2939
				"      Line numbers:\n" + 
2940
				"        [pc: 0, line: 5]\n" + 
2941
				"        [pc: 4, line: 1]\n" + 
2942
				"      Local variable table:\n" + 
2943
				"        [pc: 0, pc: 15] local: this index: 0 type: new X(){}\n";
2944
	} else if (this.complianceLevel < ClassFileConstants.JDK1_5) {
2945
		expectedOutput =
2946
				"  // Method descriptor #13 (LX;I)V\n" + 
2947
				"  // Stack: 2, Locals: 3\n" + 
2948
				"  X$1(X arg0, int arg1);\n" + 
2949
				"     0  aload_0 [this]\n" + 
2950
				"     1  aload_1 [arg0]\n" + 
2951
				"     2  putfield X$1.this$0 : X [15]\n" + 
2952
				"     5  aload_0 [this]\n" + 
2953
				"     6  iload_2 [arg1]\n" + 
2954
				"     7  putfield X$1.val$i : int [17]\n" + 
2955
				"    10  aload_0 [this]\n" + 
2956
				"    11  invokespecial java.lang.Object() [19]\n" + 
2957
				"    14  return\n" + 
2958
				"      Line numbers:\n" + 
2959
				"        [pc: 0, line: 1]\n" + 
2960
				"        [pc: 10, line: 5]\n" + 
2961
				"      Local variable table:\n" + 
2962
				"        [pc: 0, pc: 15] local: this index: 0 type: new X(){}\n";
2963
	} else {
2964
		expectedOutput =
2965
				"  // Method descriptor #12 (LX;I)V\n" + 
2966
				"  // Stack: 2, Locals: 3\n" + 
2967
				"  X$1(X arg0, int arg1);\n" + 
2968
				"     0  aload_0 [this]\n" + 
2969
				"     1  aload_1 [arg0]\n" + 
2970
				"     2  putfield X$1.this$0 : X [14]\n" + 
2971
				"     5  aload_0 [this]\n" + 
2972
				"     6  iload_2 [arg1]\n" + 
2973
				"     7  putfield X$1.val$i : int [16]\n" + 
2974
				"    10  aload_0 [this]\n" + 
2975
				"    11  invokespecial java.lang.Object() [18]\n" + 
2976
				"    14  return\n" + 
2977
				"      Line numbers:\n" + 
2978
				"        [pc: 0, line: 1]\n" + 
2979
				"        [pc: 10, line: 5]\n" + 
2980
				"      Local variable table:\n" + 
2981
				"        [pc: 0, pc: 15] local: this index: 0 type: new X(){}\n";
2982
	}
2983
	checkDisassembledClassFile(OUTPUT_DIR + File.separator + "X$1.class", "X$1", expectedOutput);
2984
}
2985
// https://bugs.eclipse.org/328830  -  Variable should be marked unused when it can be optimized out
2986
// SimpleNameReference, localOfEnclosing, simpleRead, valueNeeded from local type
2987
public void test0072() throws Exception {
2988
	Map customOptions = getCompilerOptions();
2989
	customOptions.put(CompilerOptions.OPTION_ReportUnusedLocal, CompilerOptions.ERROR);
2990
	this.runConformTest(
2991
		new String[] {
2992
			"X.java",
2993
			"public class X {\n" + 
2994
			"    int bar() { return 23; }\n" +
2995
			"    X() {\n" + 
2996
			"        final int i=bar();\n" +
2997
			"        new Runnable() {\n" +
2998
			"            {\n" +
2999
			"                if (i>3) { System.out.print(4); }\n" + 	// value is used
3000
			"            }\n" + 
3001
			"            public void run() {\n" +
3002
			"            }\n" + 
3003
			"        }.run();\n" + 
3004
			"    }\n" + 
3005
			"	public static void main(String[] args) {\n" +
3006
			"		new  X();\n" +
3007
			"	}\n" +
3008
			"}"
3009
		},
3010
		"4",
3011
		null/*classLibraries*/,
3012
		true/*shouldFlushOutputDirectory*/,
3013
		null,
3014
		customOptions,
3015
		null);
3016
	String expectedOutput =
3017
		"  // Method descriptor #13 ()V\n" + 
3018
		"  // Stack: 4, Locals: 2\n" + 
3019
		"  X();\n" + 
3020
		"     0  aload_0 [this]\n" + 
3021
		"     1  invokespecial java.lang.Object() [14]\n" + 
3022
		"     4  aload_0 [this]\n" + 
3023
		"     5  invokevirtual X.bar() : int [16]\n" + 
3024
		"     8  istore_1 [i]\n" + 
3025
		"     9  new X$1 [18]\n" + 
3026
		"    12  dup\n" + 
3027
		"    13  aload_0 [this]\n" + 
3028
		"    14  iload_1 [i]\n" + 
3029
		"    15  invokespecial X$1(X, int) [20]\n" + 
3030
		"    18  invokevirtual X$1.run() : void [23]\n" + 
3031
		"    21  return\n" + 
3032
		"      Line numbers:\n" + 
3033
		"        [pc: 0, line: 3]\n" + 
3034
		"        [pc: 4, line: 4]\n" + 
3035
		"        [pc: 9, line: 5]\n" + 
3036
		"        [pc: 18, line: 11]\n" + 
3037
		"        [pc: 21, line: 12]\n" + 
3038
		"      Local variable table:\n" + 
3039
		"        [pc: 0, pc: 22] local: this index: 0 type: X\n" + 
3040
		"        [pc: 9, pc: 22] local: i index: 1 type: int\n";
3041
	checkDisassembledClassFile(OUTPUT_DIR + File.separator + "X.class", "X", expectedOutput);
3042
	if (this.complianceLevel < ClassFileConstants.JDK1_4) {
3043
		expectedOutput =
3044
			"  // Method descriptor #11 (LX;I)V\n" + 
3045
			"  // Stack: 2, Locals: 3\n" + 
3046
			"  X$1(X arg0, int arg1);\n" + 
3047
			"     0  aload_0 [this]\n" + 
3048
			"     1  invokespecial java.lang.Object() [13]\n" + 
3049
			"     4  aload_0 [this]\n" + 
3050
			"     5  aload_1 [arg0]\n" + 
3051
			"     6  putfield X$1.this$0 : X [16]\n" + 
3052
			"     9  iload_2 [arg1]\n" + 
3053
			"    10  iconst_3\n" + 
3054
			"    11  if_icmple 21\n" + 
3055
			"    14  getstatic java.lang.System.out : java.io.PrintStream [18]\n" + 
3056
			"    17  iconst_4\n" + 
3057
			"    18  invokevirtual java.io.PrintStream.print(int) : void [24]\n" + 
3058
			"    21  return\n" + 
3059
			"      Line numbers:\n" + 
3060
			"        [pc: 0, line: 5]\n" + 
3061
			"        [pc: 9, line: 7]\n" + 
3062
			"        [pc: 21, line: 1]\n" + 
3063
			"      Local variable table:\n" + 
3064
			"        [pc: 0, pc: 22] local: this index: 0 type: new X(){}\n";
3065
	} else if (this.complianceLevel < ClassFileConstants.JDK1_5) {
3066
		expectedOutput =
3067
			"  // Method descriptor #11 (LX;I)V\n" + 
3068
			"  // Stack: 2, Locals: 3\n" + 
3069
			"  X$1(X arg0, int arg1);\n" + 
3070
			"     0  aload_0 [this]\n" + 
3071
			"     1  aload_1 [arg0]\n" + 
3072
			"     2  putfield X$1.this$0 : X [13]\n" + 
3073
			"     5  aload_0 [this]\n" + 
3074
			"     6  invokespecial java.lang.Object() [15]\n" + 
3075
			"     9  iload_2 [arg1]\n" + 
3076
			"    10  iconst_3\n" + 
3077
			"    11  if_icmple 21\n" + 
3078
			"    14  getstatic java.lang.System.out : java.io.PrintStream [18]\n" + 
3079
			"    17  iconst_4\n" + 
3080
			"    18  invokevirtual java.io.PrintStream.print(int) : void [24]\n" + 
3081
			"    21  return\n" + 
3082
			"      Line numbers:\n" + 
3083
			"        [pc: 0, line: 1]\n" + 
3084
			"        [pc: 5, line: 5]\n" + 
3085
			"        [pc: 9, line: 7]\n" + 
3086
			"      Local variable table:\n" + 
3087
			"        [pc: 0, pc: 22] local: this index: 0 type: new X(){}\n";
3088
	} else {
3089
		expectedOutput =
3090
			"  // Method descriptor #10 (LX;I)V\n" + 
3091
			"  // Stack: 2, Locals: 3\n" + 
3092
			"  X$1(X arg0, int arg1);\n" + 
3093
			"     0  aload_0 [this]\n" + 
3094
			"     1  aload_1 [arg0]\n" + 
3095
			"     2  putfield X$1.this$0 : X [12]\n" + 
3096
			"     5  aload_0 [this]\n" + 
3097
			"     6  invokespecial java.lang.Object() [14]\n" + 
3098
			"     9  iload_2 [arg1]\n" + 
3099
			"    10  iconst_3\n" + 
3100
			"    11  if_icmple 21\n" + 
3101
			"    14  getstatic java.lang.System.out : java.io.PrintStream [17]\n" + 
3102
			"    17  iconst_4\n" + 
3103
			"    18  invokevirtual java.io.PrintStream.print(int) : void [23]\n" + 
3104
			"    21  return\n" + 
3105
			"      Line numbers:\n" + 
3106
			"        [pc: 0, line: 1]\n" + 
3107
			"        [pc: 5, line: 5]\n" + 
3108
			"        [pc: 9, line: 7]\n" + 
3109
			"      Local variable table:\n" + 
3110
			"        [pc: 0, pc: 22] local: this index: 0 type: new X(){}\n";
3111
	}
3112
	checkDisassembledClassFile(OUTPUT_DIR + File.separator + "X$1.class", "X$1", expectedOutput);
3113
}
3114
// https://bugs.eclipse.org/328830  -  Variable should be marked unused when it can be optimized out
3115
// SimpleNameReference, localOfEnclosing, simpleRead, valueNeeded from local type
3116
public void test0073() throws Exception {
3117
	Map customOptions = getCompilerOptions();
3118
	customOptions.put(CompilerOptions.OPTION_ReportUnusedLocal, CompilerOptions.IGNORE);
3119
	this.runConformTest(
3120
		new String[] {
3121
			"X.java",
3122
			"public class X {\n" + 
3123
			"    int bar() { return 23; }\n" +
3124
			"    X() {\n" + 
3125
			"        final int i=bar();\n" +
3126
			"        new Runnable() {\n" +
3127
			"            {\n" +
3128
			"                if (i>3) {}\n" + 	// value is not used
3129
			"                System.out.print(4);\n" +
3130
			"            }\n" + 
3131
			"            public void run() {\n" +
3132
			"            }\n" + 
3133
			"        }.run();\n" + 
3134
			"    }\n" + 
3135
			"	public static void main(String[] args) {\n" +
3136
			"		new  X();\n" +
3137
			"	}\n" +
3138
			"}"
3139
		},
3140
		"4",
3141
		null/*classLibraries*/,
3142
		true/*shouldFlushOutputDirectory*/,
3143
		null,
3144
		customOptions,
3145
		null);
3146
	String expectedOutput =
3147
		"  // Method descriptor #13 ()V\n" + 
3148
		"  // Stack: 3, Locals: 1\n" + 
3149
		"  X();\n" + 
3150
		"     0  aload_0 [this]\n" + 
3151
		"     1  invokespecial java.lang.Object() [14]\n" + 
3152
		"     4  aload_0 [this]\n" + 
3153
		"     5  invokevirtual X.bar() : int [16]\n" + 
3154
		"     8  pop\n" + 
3155
		"     9  new X$1 [18]\n" + 
3156
		"    12  dup\n" + 
3157
		"    13  aload_0 [this]\n" + 
3158
		"    14  invokespecial X$1(X) [20]\n" + 
3159
		"    17  invokevirtual X$1.run() : void [23]\n" + 
3160
		"    20  return\n" + 
3161
		"      Line numbers:\n" + 
3162
		"        [pc: 0, line: 3]\n" + 
3163
		"        [pc: 4, line: 4]\n" + 
3164
		"        [pc: 9, line: 5]\n" + 
3165
		"        [pc: 17, line: 12]\n" + 
3166
		"        [pc: 20, line: 13]\n" + 
3167
		"      Local variable table:\n" + 
3168
		"        [pc: 0, pc: 21] local: this index: 0 type: X\n";
3169
	checkDisassembledClassFile(OUTPUT_DIR + File.separator + "X.class", "X", expectedOutput);
3170
	if (this.complianceLevel < ClassFileConstants.JDK1_4) {
3171
		expectedOutput =
3172
			"  // Method descriptor #11 (LX;)V\n" + 
3173
			"  // Stack: 2, Locals: 2\n" + 
3174
			"  X$1(X arg0);\n" + 
3175
			"     0  aload_0 [this]\n" + 
3176
			"     1  invokespecial java.lang.Object() [13]\n" + 
3177
			"     4  aload_0 [this]\n" + 
3178
			"     5  aload_1 [arg0]\n" + 
3179
			"     6  putfield X$1.this$0 : X [16]\n" + 
3180
			"     9  getstatic java.lang.System.out : java.io.PrintStream [18]\n" + 
3181
			"    12  iconst_4\n" + 
3182
			"    13  invokevirtual java.io.PrintStream.print(int) : void [24]\n" + 
3183
			"    16  return\n" + 
3184
			"      Line numbers:\n" + 
3185
			"        [pc: 0, line: 5]\n" + 
3186
			"        [pc: 9, line: 8]\n" + 
3187
			"        [pc: 16, line: 1]\n" + 
3188
			"      Local variable table:\n" + 
3189
			"        [pc: 0, pc: 17] local: this index: 0 type: new X(){}\n";
3190
	} else if (this.complianceLevel < ClassFileConstants.JDK1_5) {
3191
		expectedOutput =
3192
			"  // Method descriptor #11 (LX;)V\n" + 
3193
			"  // Stack: 2, Locals: 2\n" + 
3194
			"  X$1(X arg0);\n" + 
3195
			"     0  aload_0 [this]\n" + 
3196
			"     1  aload_1 [arg0]\n" + 
3197
			"     2  putfield X$1.this$0 : X [13]\n" + 
3198
			"     5  aload_0 [this]\n" + 
3199
			"     6  invokespecial java.lang.Object() [15]\n" + 
3200
			"     9  getstatic java.lang.System.out : java.io.PrintStream [18]\n" + 
3201
			"    12  iconst_4\n" + 
3202
			"    13  invokevirtual java.io.PrintStream.print(int) : void [24]\n" + 
3203
			"    16  return\n" + 
3204
			"      Line numbers:\n" + 
3205
			"        [pc: 0, line: 1]\n" + 
3206
			"        [pc: 5, line: 5]\n" + 
3207
			"        [pc: 9, line: 8]\n" + 
3208
			"      Local variable table:\n" + 
3209
			"        [pc: 0, pc: 17] local: this index: 0 type: new X(){}\n";
3210
	} else {
3211
		expectedOutput =
3212
			"  // Method descriptor #10 (LX;)V\n" + 
3213
			"  // Stack: 2, Locals: 2\n" + 
3214
			"  X$1(X arg0);\n" + 
3215
			"     0  aload_0 [this]\n" + 
3216
			"     1  aload_1 [arg0]\n" + 
3217
			"     2  putfield X$1.this$0 : X [12]\n" + 
3218
			"     5  aload_0 [this]\n" + 
3219
			"     6  invokespecial java.lang.Object() [14]\n" + 
3220
			"     9  getstatic java.lang.System.out : java.io.PrintStream [17]\n" + 
3221
			"    12  iconst_4\n" + 
3222
			"    13  invokevirtual java.io.PrintStream.print(int) : void [23]\n" + 
3223
			"    16  return\n" + 
3224
			"      Line numbers:\n" + 
3225
			"        [pc: 0, line: 1]\n" + 
3226
			"        [pc: 5, line: 5]\n" + 
3227
			"        [pc: 9, line: 8]\n" + 
3228
			"      Local variable table:\n" + 
3229
			"        [pc: 0, pc: 17] local: this index: 0 type: new X(){}\n";
3230
	}
3231
	checkDisassembledClassFile(OUTPUT_DIR + File.separator + "X$1.class", "X$1", expectedOutput);
3232
}
3233
// https://bugs.eclipse.org/328830  -  Variable should be marked unused when it can be optimized out
3234
// white box against an intermediate patch: testing that double analysis of a condition may harm
3235
public void test0074() throws Exception {
3236
	Map customOptions = getCompilerOptions();
3237
	customOptions.put(CompilerOptions.OPTION_ReportUnusedLocal, CompilerOptions.WARNING);	
3238
	this.runNegativeTest(
3239
			new String[] {
3240
				"X.java",
3241
				"public class X {\n" +
3242
				"	public void method() {\n" +
3243
				"		int a=10;\n" +
3244
				"		final int b;\n" +
3245
				" 		if((b=a) > 10) {\n" +
3246
				"           System.out.print(3);\n" +
3247
				"		}\n" +   
3248
				"    }\n" +
3249
				"}\n"
3250
			},
3251
			"----------\n" + 
3252
			"1. WARNING in X.java (at line 4)\n" + 
3253
			"	final int b;\n" + 
3254
			"	          ^\n" + 
3255
			"The value of the local variable b is not used\n" + 
3256
			"----------\n",
3257
			null/*classLibraries*/,
3258
			true/*shouldFlushOutputDirectory*/,
3259
			customOptions);	
3260
}
3261
}

Return to bug 328830