View | Details | Raw Unified | Return to bug 223685
Collapse All | Expand All

(-)src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java (-12 / +2 lines)
Lines 20380-20391 Link Here
20380
		"	      ^^^^^^^^^^^^^\n" + 
20380
		"	      ^^^^^^^^^^^^^\n" + 
20381
		"Type safety: Unchecked cast from Integer to S\n" + 
20381
		"Type safety: Unchecked cast from Integer to S\n" + 
20382
		"----------\n" + 
20382
		"----------\n" + 
20383
		"2. WARNING in X.java (at line 3)\n" + 
20383
		"2. ERROR in X.java (at line 5)\n" + 
20384
		"	S a = (S)(Integer)3;\n" + 
20385
		"	         ^^^^^^^^^^\n" + 
20386
		"Unnecessary cast from int to Integer\n" + 
20387
		"----------\n" + 
20388
		"3. ERROR in X.java (at line 5)\n" + 
20389
		"	Zork z;\n" + 
20384
		"	Zork z;\n" + 
20390
		"	^^^^\n" + 
20385
		"	^^^^\n" + 
20391
		"Zork cannot be resolved to a type\n" + 
20386
		"Zork cannot be resolved to a type\n" + 
Lines 20409-20420 Link Here
20409
		"	      ^^^^^^^^^^^^^\n" + 
20404
		"	      ^^^^^^^^^^^^^\n" + 
20410
		"Cannot cast from Integer to S\n" + 
20405
		"Cannot cast from Integer to S\n" + 
20411
		"----------\n" + 
20406
		"----------\n" + 
20412
		"2. WARNING in X.java (at line 3)\n" + 
20407
		"2. ERROR in X.java (at line 5)\n" + 
20413
		"	S a = (S)(Integer)3; // this should fail\n" + 
20414
		"	         ^^^^^^^^^^\n" + 
20415
		"Unnecessary cast from int to Integer\n" + 
20416
		"----------\n" + 
20417
		"3. ERROR in X.java (at line 5)\n" + 
20418
		"	Zork z;\n" + 
20408
		"	Zork z;\n" + 
20419
		"	^^^^\n" + 
20409
		"	^^^^\n" + 
20420
		"Zork cannot be resolved to a type\n" + 
20410
		"Zork cannot be resolved to a type\n" + 
(-)src/org/eclipse/jdt/core/tests/compiler/regression/AutoBoxingTest.java (+67 lines)
Lines 4429-4432 Link Here
4429
		},
4429
		},
4430
		"SUCCESS");
4430
		"SUCCESS");
4431
}
4431
}
4432
//https://bugs.eclipse.org/bugs/show_bug.cgi?id=223685
4433
public void test153() {
4434
	this.runNegativeTest(
4435
		new String[] {
4436
			"X.java",
4437
			"public class X {\n" + 
4438
			"	void foo() {\n" + 
4439
			"		Integer a = 0;\n" + 
4440
			"		char b = (char)((int)a);\n" + 
4441
			"		char c = (char)(a + 1);\n" + 
4442
			"		char d = (char)(a);\n" + 
4443
			"		int e = (int) a;\n" + 
4444
			"		Integer f = (Integer) e;\n" + 
4445
			"	}\n" + 
4446
			"	void bar() {\n" + 
4447
			"		X x = (X) null;\n" + 
4448
			"	}\n" + 
4449
			"}\n",
4450
		},
4451
		"----------\n" + 
4452
		"1. WARNING in X.java (at line 3)\n" + 
4453
		"	Integer a = 0;\n" + 
4454
		"	            ^\n" + 
4455
		"The expression of type int is boxed into Integer\n" + 
4456
		"----------\n" + 
4457
		"2. WARNING in X.java (at line 4)\n" + 
4458
		"	char b = (char)((int)a);\n" + 
4459
		"	                     ^\n" + 
4460
		"The expression of type Integer is unboxed into int\n" + 
4461
		"----------\n" + 
4462
		"3. WARNING in X.java (at line 5)\n" + 
4463
		"	char c = (char)(a + 1);\n" + 
4464
		"	                ^\n" + 
4465
		"The expression of type Integer is unboxed into int\n" + 
4466
		"----------\n" + 
4467
		"4. ERROR in X.java (at line 6)\n" + 
4468
		"	char d = (char)(a);\n" + 
4469
		"	         ^^^^^^^^^\n" + 
4470
		"Cannot cast from Integer to char\n" + 
4471
		"----------\n" + 
4472
		"5. WARNING in X.java (at line 7)\n" + 
4473
		"	int e = (int) a;\n" + 
4474
		"	        ^^^^^^^\n" + 
4475
		"Unnecessary cast from Integer to int\n" + 
4476
		"----------\n" + 
4477
		"6. WARNING in X.java (at line 7)\n" + 
4478
		"	int e = (int) a;\n" + 
4479
		"	              ^\n" + 
4480
		"The expression of type Integer is unboxed into int\n" + 
4481
		"----------\n" + 
4482
		"7. WARNING in X.java (at line 8)\n" + 
4483
		"	Integer f = (Integer) e;\n" + 
4484
		"	            ^^^^^^^^^^^\n" + 
4485
		"Unnecessary cast from int to Integer\n" + 
4486
		"----------\n" + 
4487
		"8. WARNING in X.java (at line 8)\n" + 
4488
		"	Integer f = (Integer) e;\n" + 
4489
		"	                      ^\n" + 
4490
		"The expression of type int is boxed into Integer\n" + 
4491
		"----------\n" + 
4492
		"9. WARNING in X.java (at line 11)\n" + 
4493
		"	X x = (X) null;\n" + 
4494
		"	      ^^^^^^^^\n" + 
4495
		"Unnecessary cast from null to X\n" + 
4496
		"----------\n");
4497
}
4498
4432
}
4499
}
(-)compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java (-474 / +501 lines)
Lines 12-21 Link Here
12
package org.eclipse.jdt.internal.compiler.ast;
12
package org.eclipse.jdt.internal.compiler.ast;
13
13
14
import org.eclipse.jdt.internal.compiler.ASTVisitor;
14
import org.eclipse.jdt.internal.compiler.ASTVisitor;
15
import org.eclipse.jdt.internal.compiler.impl.*;
15
import org.eclipse.jdt.internal.compiler.codegen.CodeStream;
16
import org.eclipse.jdt.internal.compiler.codegen.*;
16
import org.eclipse.jdt.internal.compiler.flow.FlowContext;
17
import org.eclipse.jdt.internal.compiler.flow.*;
17
import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
18
import org.eclipse.jdt.internal.compiler.lookup.*;
18
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
19
import org.eclipse.jdt.internal.compiler.impl.Constant;
20
import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
21
import org.eclipse.jdt.internal.compiler.lookup.Binding;
22
import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
23
import org.eclipse.jdt.internal.compiler.lookup.InvocationSite;
24
import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
25
import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
26
import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
27
import org.eclipse.jdt.internal.compiler.lookup.ParameterizedGenericMethodBinding;
28
import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding;
29
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
30
import org.eclipse.jdt.internal.compiler.lookup.Scope;
31
import org.eclipse.jdt.internal.compiler.lookup.TagBits;
32
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
33
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
19
import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
34
import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
20
35
21
public class CastExpression extends Expression {
36
public class CastExpression extends Expression {
Lines 24-109 Link Here
24
	public Expression type;
39
	public Expression type;
25
	public TypeBinding expectedType; // when assignment conversion to a given expected type: String s = (String) t;
40
	public TypeBinding expectedType; // when assignment conversion to a given expected type: String s = (String) t;
26
	
41
	
27
	//expression.implicitConversion holds the cast for baseType casting 
42
//expression.implicitConversion holds the cast for baseType casting 
28
	public CastExpression(Expression expression, Expression type) {
43
public CastExpression(Expression expression, Expression type) {
29
		this.expression = expression;
44
	this.expression = expression;
30
		this.type = type;
45
	this.type = type;
31
		type.bits |= IgnoreRawTypeCheck; // no need to worry about raw type usage
46
	type.bits |= ASTNode.IgnoreRawTypeCheck; // no need to worry about raw type usage
32
	}
47
}
33
48
34
	public FlowInfo analyseCode(
49
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
35
		BlockScope currentScope,
50
	return this.expression
36
		FlowContext flowContext,
51
		.analyseCode(currentScope, flowContext, flowInfo)
37
		FlowInfo flowInfo) {
52
		.unconditionalInits();
38
53
}
39
		return expression
54
40
			.analyseCode(currentScope, flowContext, flowInfo)
55
/**
41
			.unconditionalInits();
56
 * Complain if assigned expression is cast, but not actually used as such, e.g. Object o = (List) object;
42
	}
57
 */
43
58
public static void checkNeedForAssignedCast(BlockScope scope, TypeBinding expectedType, CastExpression rhs) {
44
	/**
59
	if (scope.compilerOptions().getSeverity(CompilerOptions.UnnecessaryTypeCheck) == ProblemSeverities.Ignore) return;
45
	 * Complain if assigned expression is cast, but not actually used as such, e.g. Object o = (List) object;
60
46
	 */
61
	TypeBinding castedExpressionType = rhs.expression.resolvedType;
47
	public static void checkNeedForAssignedCast(BlockScope scope, TypeBinding expectedType, CastExpression rhs) {
62
	//	int i = (byte) n; // cast still had side effect
48
	
63
	// double d = (float) n; // cast to float is unnecessary
49
		if (scope.compilerOptions().getSeverity(CompilerOptions.UnnecessaryTypeCheck) == ProblemSeverities.Ignore) return;
64
	if (castedExpressionType == null || rhs.resolvedType.isBaseType()) return; 
50
	
65
	//if (castedExpressionType.id == T_null) return; // tolerate null expression cast
51
		TypeBinding castedExpressionType = rhs.expression.resolvedType;
66
	if (castedExpressionType.isCompatibleWith(expectedType)) {
52
		//	int i = (byte) n; // cast still had side effect
67
		scope.problemReporter().unnecessaryCast(rhs); 
53
		// double d = (float) n; // cast to float is unnecessary
54
		if (castedExpressionType == null || rhs.resolvedType.isBaseType()) return; 
55
		//if (castedExpressionType.id == T_null) return; // tolerate null expression cast
56
		if (castedExpressionType.isCompatibleWith(expectedType)) {
57
			scope.problemReporter().unnecessaryCast(rhs); 
58
		}
59
	}
68
	}
60
	
69
}
61
	/**
70
62
	 * Casting an enclosing instance will considered as useful if removing it would actually bind to a different type
71
63
	 */
72
/**
64
	public static void checkNeedForEnclosingInstanceCast(BlockScope scope, Expression enclosingInstance, TypeBinding enclosingInstanceType, TypeBinding memberType) {
73
 * Complain if cast expression is cast, but not actually needed, int i = (int)(Integer) 12;   
65
	
74
 * Note that this (int) cast is however needed:   Integer i = 0;  char c = (char)((int) i);
66
		if (scope.compilerOptions().getSeverity(CompilerOptions.UnnecessaryTypeCheck) == ProblemSeverities.Ignore) return;
75
 */
67
		
76
public static void checkNeedForCastCast(BlockScope scope, CastExpression enclosingCast) {
68
		TypeBinding castedExpressionType = ((CastExpression)enclosingInstance).expression.resolvedType;
77
	if (scope.compilerOptions().getSeverity(CompilerOptions.UnnecessaryTypeCheck) == ProblemSeverities.Ignore) return;
69
		if (castedExpressionType == null) return; // cannot do better
78
70
		// obvious identity cast
79
	CastExpression nestedCast = (CastExpression) enclosingCast.expression;
71
		if (castedExpressionType == enclosingInstanceType) { 
80
	if ((nestedCast.bits & ASTNode.UnnecessaryCast) == 0) return;
81
	// check if could cast directly to enclosing cast type, without intermediate type cast
82
	CastExpression alternateCast = new CastExpression(null, enclosingCast.type);
83
	if (!alternateCast.checkCastTypesCompatibility(scope, enclosingCast.resolvedType, nestedCast.expression.resolvedType, nestedCast.expression)) {
84
		return;
85
	}
86
	scope.problemReporter().unnecessaryCast(nestedCast); 
87
}
88
89
90
/**
91
 * Casting an enclosing instance will considered as useful if removing it would actually bind to a different type
92
 */
93
public static void checkNeedForEnclosingInstanceCast(BlockScope scope, Expression enclosingInstance, TypeBinding enclosingInstanceType, TypeBinding memberType) {
94
	if (scope.compilerOptions().getSeverity(CompilerOptions.UnnecessaryTypeCheck) == ProblemSeverities.Ignore) return;
95
	
96
	TypeBinding castedExpressionType = ((CastExpression)enclosingInstance).expression.resolvedType;
97
	if (castedExpressionType == null) return; // cannot do better
98
	// obvious identity cast
99
	if (castedExpressionType == enclosingInstanceType) { 
100
		scope.problemReporter().unnecessaryCast((CastExpression)enclosingInstance);
101
	} else if (castedExpressionType == TypeBinding.NULL){
102
		return; // tolerate null enclosing instance cast
103
	} else {
104
		TypeBinding alternateEnclosingInstanceType = castedExpressionType; 
105
		if (castedExpressionType.isBaseType() || castedExpressionType.isArrayType()) return; // error case
106
		if (memberType == scope.getMemberType(memberType.sourceName(), (ReferenceBinding) alternateEnclosingInstanceType)) {
72
			scope.problemReporter().unnecessaryCast((CastExpression)enclosingInstance);
107
			scope.problemReporter().unnecessaryCast((CastExpression)enclosingInstance);
73
		} else if (castedExpressionType == TypeBinding.NULL){
74
			return; // tolerate null enclosing instance cast
75
		} else {
76
			TypeBinding alternateEnclosingInstanceType = castedExpressionType; 
77
			if (castedExpressionType.isBaseType() || castedExpressionType.isArrayType()) return; // error case
78
			if (memberType == scope.getMemberType(memberType.sourceName(), (ReferenceBinding) alternateEnclosingInstanceType)) {
79
				scope.problemReporter().unnecessaryCast((CastExpression)enclosingInstance);
80
			}
81
		}
108
		}
82
	}
109
	}
110
}
83
111
84
	/**
112
/**
85
	 * Only complain for identity cast, since other type of casts may be useful: e.g.  ~((~(long) 0) << 32)  is different from: ~((~0) << 32) 
113
 * Only complain for identity cast, since other type of casts may be useful: e.g.  ~((~(long) 0) << 32)  is different from: ~((~0) << 32) 
86
	 */
114
 */
87
	public static void checkNeedForArgumentCast(BlockScope scope, int operator, int operatorSignature, Expression expression, int expressionTypeId) {
115
public static void checkNeedForArgumentCast(BlockScope scope, int operator, int operatorSignature, Expression expression, int expressionTypeId) {
88
	
116
	if (scope.compilerOptions().getSeverity(CompilerOptions.UnnecessaryTypeCheck) == ProblemSeverities.Ignore) return;
89
		if (scope.compilerOptions().getSeverity(CompilerOptions.UnnecessaryTypeCheck) == ProblemSeverities.Ignore) return;
117
90
	
118
	// check need for left operand cast
91
		// check need for left operand cast
119
	int alternateLeftTypeId = expressionTypeId;
92
		int alternateLeftTypeId = expressionTypeId;
120
	if ((expression.bits & ASTNode.UnnecessaryCast) == 0 && expression.resolvedType.isBaseType()) {
93
		if ((expression.bits & UnnecessaryCast) == 0 && expression.resolvedType.isBaseType()) {
121
		// narrowing conversion on base type may change value, thus necessary
94
			// narrowing conversion on base type may change value, thus necessary
122
		return;
123
	} else  {
124
		TypeBinding alternateLeftType = ((CastExpression)expression).expression.resolvedType;
125
		if (alternateLeftType == null) return; // cannot do better
126
		if ((alternateLeftTypeId = alternateLeftType.id) == expressionTypeId) { // obvious identity cast
127
			scope.problemReporter().unnecessaryCast((CastExpression)expression); 
128
			return;
129
		} else if (alternateLeftTypeId == TypeIds.T_null) {
130
			alternateLeftTypeId = expressionTypeId;  // tolerate null argument cast
95
			return;
131
			return;
96
		} else  {
97
			TypeBinding alternateLeftType = ((CastExpression)expression).expression.resolvedType;
98
			if (alternateLeftType == null) return; // cannot do better
99
			if ((alternateLeftTypeId = alternateLeftType.id) == expressionTypeId) { // obvious identity cast
100
				scope.problemReporter().unnecessaryCast((CastExpression)expression); 
101
				return;
102
			} else if (alternateLeftTypeId == T_null) {
103
				alternateLeftTypeId = expressionTypeId;  // tolerate null argument cast
104
				return;
105
			}
106
		}
132
		}
133
	}
107
/*		tolerate widening cast in unary expressions, as may be used when combined in binary expressions (41680)
134
/*		tolerate widening cast in unary expressions, as may be used when combined in binary expressions (41680)
108
		int alternateOperatorSignature = OperatorExpression.OperatorSignatures[operator][(alternateLeftTypeId << 4) + alternateLeftTypeId];
135
		int alternateOperatorSignature = OperatorExpression.OperatorSignatures[operator][(alternateLeftTypeId << 4) + alternateLeftTypeId];
109
		// (cast)  left   Op (cast)  right --> result
136
		// (cast)  left   Op (cast)  right --> result
Lines 114-558 Link Here
114
			scope.problemReporter().unnecessaryCastForArgument((CastExpression)expression,  TypeBinding.wellKnownType(scope, expression.implicitConversion >> 4)); 
141
			scope.problemReporter().unnecessaryCastForArgument((CastExpression)expression,  TypeBinding.wellKnownType(scope, expression.implicitConversion >> 4)); 
115
		}
142
		}
116
*/		
143
*/		
117
	}
144
}
118
		
119
	/**
120
	 * Cast expressions will considered as useful if removing them all would actually bind to a different method
121
	 * (no fine grain analysis on per casted argument basis, simply separate widening cast from narrowing ones)
122
	 */
123
	public static void checkNeedForArgumentCasts(BlockScope scope, Expression receiver, TypeBinding receiverType, MethodBinding binding, Expression[] arguments, TypeBinding[] argumentTypes, final InvocationSite invocationSite) {
124
	
145
	
125
		if (scope.compilerOptions().getSeverity(CompilerOptions.UnnecessaryTypeCheck) == ProblemSeverities.Ignore) return;
146
/**
126
		
147
 * Cast expressions will considered as useful if removing them all would actually bind to a different method
127
		int length = argumentTypes.length;
148
 * (no fine grain analysis on per casted argument basis, simply separate widening cast from narrowing ones)
128
149
 */
129
		// iterate over arguments, and retrieve original argument types (before cast)
150
public static void checkNeedForArgumentCasts(BlockScope scope, Expression receiver, TypeBinding receiverType, MethodBinding binding, Expression[] arguments, TypeBinding[] argumentTypes, final InvocationSite invocationSite) {
130
		TypeBinding[] rawArgumentTypes = argumentTypes;
151
	if (scope.compilerOptions().getSeverity(CompilerOptions.UnnecessaryTypeCheck) == ProblemSeverities.Ignore) return;
131
		for (int i = 0; i < length; i++) {
152
	
132
			Expression argument = arguments[i];
153
	int length = argumentTypes.length;
133
			if (argument instanceof CastExpression) {
154
134
 				// narrowing conversion on base type may change value, thus necessary
155
	// iterate over arguments, and retrieve original argument types (before cast)
135
				if ((argument.bits & UnnecessaryCast) == 0 && argument.resolvedType.isBaseType()) {
156
	TypeBinding[] rawArgumentTypes = argumentTypes;
136
					continue;
157
	for (int i = 0; i < length; i++) {
137
				}		
158
		Expression argument = arguments[i];
138
				TypeBinding castedExpressionType = ((CastExpression)argument).expression.resolvedType;
159
		if (argument instanceof CastExpression) {
139
				if (castedExpressionType == null) return; // cannot do better
160
			// narrowing conversion on base type may change value, thus necessary
140
				// obvious identity cast
161
			if ((argument.bits & ASTNode.UnnecessaryCast) == 0 && argument.resolvedType.isBaseType()) {
141
				if (castedExpressionType == argumentTypes[i]) { 
162
				continue;
142
					scope.problemReporter().unnecessaryCast((CastExpression)argument);
163
			}		
143
				} else if (castedExpressionType == TypeBinding.NULL){
164
			TypeBinding castedExpressionType = ((CastExpression)argument).expression.resolvedType;
144
					continue; // tolerate null argument cast
165
			if (castedExpressionType == null) return; // cannot do better
145
				} else if ((argument.implicitConversion & BOXING) != 0) {
166
			// obvious identity cast
146
					continue; // boxing has a side effect: (int) char   is not boxed as simple char
167
			if (castedExpressionType == argumentTypes[i]) { 
147
				} else {
168
				scope.problemReporter().unnecessaryCast((CastExpression)argument);
148
					if (rawArgumentTypes == argumentTypes) {
169
			} else if (castedExpressionType == TypeBinding.NULL){
149
						System.arraycopy(rawArgumentTypes, 0, rawArgumentTypes = new TypeBinding[length], 0, length);
170
				continue; // tolerate null argument cast
150
					}
171
			} else if ((argument.implicitConversion & TypeIds.BOXING) != 0) {
151
					// retain original argument type
172
				continue; // boxing has a side effect: (int) char   is not boxed as simple char
152
					rawArgumentTypes[i] = castedExpressionType; 
173
			} else {
174
				if (rawArgumentTypes == argumentTypes) {
175
					System.arraycopy(rawArgumentTypes, 0, rawArgumentTypes = new TypeBinding[length], 0, length);
153
				}
176
				}
154
			}				
177
				// retain original argument type
155
		}
178
				rawArgumentTypes[i] = castedExpressionType; 
156
		// perform alternate lookup with original types
179
			}
157
		if (rawArgumentTypes != argumentTypes) {
180
		}				
158
			checkAlternateBinding(scope, receiver, receiverType, binding, arguments, argumentTypes, rawArgumentTypes, invocationSite);
159
		}
160
	}
181
	}
182
	// perform alternate lookup with original types
183
	if (rawArgumentTypes != argumentTypes) {
184
		checkAlternateBinding(scope, receiver, receiverType, binding, arguments, argumentTypes, rawArgumentTypes, invocationSite);
185
	}
186
}
161
187
162
	/**
188
/**
163
	 * Check binary operator casted arguments 
189
 * Check binary operator casted arguments 
164
	 */
190
 */
165
	public static void checkNeedForArgumentCasts(BlockScope scope, int operator, int operatorSignature, Expression left, int leftTypeId, boolean leftIsCast, Expression right, int rightTypeId, boolean rightIsCast) {
191
public static void checkNeedForArgumentCasts(BlockScope scope, int operator, int operatorSignature, Expression left, int leftTypeId, boolean leftIsCast, Expression right, int rightTypeId, boolean rightIsCast) {
166
192
	if (scope.compilerOptions().getSeverity(CompilerOptions.UnnecessaryTypeCheck) == ProblemSeverities.Ignore) return;
167
		if (scope.compilerOptions().getSeverity(CompilerOptions.UnnecessaryTypeCheck) == ProblemSeverities.Ignore) return;
193
168
194
	// check need for left operand cast
169
		// check need for left operand cast
195
	int alternateLeftTypeId = leftTypeId;
170
		int alternateLeftTypeId = leftTypeId;
196
	if (leftIsCast) {
171
		if (leftIsCast) {
197
		if ((left.bits & ASTNode.UnnecessaryCast) == 0 && left.resolvedType.isBaseType()) {
172
			if ((left.bits & UnnecessaryCast) == 0 && left.resolvedType.isBaseType()) {
198
			// narrowing conversion on base type may change value, thus necessary
173
 				// narrowing conversion on base type may change value, thus necessary
199
			leftIsCast = false;
174
 				leftIsCast = false;
200
		} else  {
175
			} else  {
201
			TypeBinding alternateLeftType = ((CastExpression)left).expression.resolvedType;
176
				TypeBinding alternateLeftType = ((CastExpression)left).expression.resolvedType;
202
			if (alternateLeftType == null) return; // cannot do better
177
				if (alternateLeftType == null) return; // cannot do better
203
			if ((alternateLeftTypeId = alternateLeftType.id) == leftTypeId) { // obvious identity cast
178
				if ((alternateLeftTypeId = alternateLeftType.id) == leftTypeId) { // obvious identity cast
204
				scope.problemReporter().unnecessaryCast((CastExpression)left); 
179
					scope.problemReporter().unnecessaryCast((CastExpression)left); 
205
				leftIsCast = false;
180
					leftIsCast = false;
206
			} else if (alternateLeftTypeId == TypeIds.T_null) {
181
				} else if (alternateLeftTypeId == T_null) {
207
				alternateLeftTypeId = leftTypeId;  // tolerate null argument cast
182
					alternateLeftTypeId = leftTypeId;  // tolerate null argument cast
208
				leftIsCast = false;
183
					leftIsCast = false;
184
				}
185
			}
209
			}
186
		}
210
		}
187
		// check need for right operand cast
211
	}
188
		int alternateRightTypeId = rightTypeId;
212
	// check need for right operand cast
189
		if (rightIsCast) {
213
	int alternateRightTypeId = rightTypeId;
190
			if ((right.bits & UnnecessaryCast) == 0 && right.resolvedType.isBaseType()) {
214
	if (rightIsCast) {
191
 				// narrowing conversion on base type may change value, thus necessary
215
		if ((right.bits & ASTNode.UnnecessaryCast) == 0 && right.resolvedType.isBaseType()) {
192
 				rightIsCast = false;
216
			// narrowing conversion on base type may change value, thus necessary
217
			rightIsCast = false;
218
		} else {
219
			TypeBinding alternateRightType = ((CastExpression)right).expression.resolvedType;
220
			if (alternateRightType == null) return; // cannot do better
221
			if ((alternateRightTypeId = alternateRightType.id) == rightTypeId) { // obvious identity cast
222
				scope.problemReporter().unnecessaryCast((CastExpression)right); 
223
				rightIsCast = false;
224
			} else if (alternateRightTypeId == TypeIds.T_null) {
225
				alternateRightTypeId = rightTypeId;  // tolerate null argument cast
226
				rightIsCast = false;
227
			}
228
		}	
229
	}
230
	if (leftIsCast || rightIsCast) {
231
		if (alternateLeftTypeId > 15 || alternateRightTypeId > 15) { // must convert String + Object || Object + String
232
			if (alternateLeftTypeId == TypeIds.T_JavaLangString) {
233
				alternateRightTypeId = TypeIds.T_JavaLangObject;
234
			} else if (alternateRightTypeId == TypeIds.T_JavaLangString) {
235
				alternateLeftTypeId = TypeIds.T_JavaLangObject;
193
			} else {
236
			} else {
194
				TypeBinding alternateRightType = ((CastExpression)right).expression.resolvedType;
237
				return; // invalid operator
195
				if (alternateRightType == null) return; // cannot do better
196
				if ((alternateRightTypeId = alternateRightType.id) == rightTypeId) { // obvious identity cast
197
					scope.problemReporter().unnecessaryCast((CastExpression)right); 
198
					rightIsCast = false;
199
				} else if (alternateRightTypeId == T_null) {
200
					alternateRightTypeId = rightTypeId;  // tolerate null argument cast
201
					rightIsCast = false;
202
				}
203
			}	
204
		}
205
		if (leftIsCast || rightIsCast) {
206
			if (alternateLeftTypeId > 15 || alternateRightTypeId > 15) { // must convert String + Object || Object + String
207
				if (alternateLeftTypeId == T_JavaLangString) {
208
					alternateRightTypeId = T_JavaLangObject;
209
				} else if (alternateRightTypeId == T_JavaLangString) {
210
					alternateLeftTypeId = T_JavaLangObject;
211
				} else {
212
					return; // invalid operator
213
				}
214
			}
215
			int alternateOperatorSignature = OperatorExpression.OperatorSignatures[operator][(alternateLeftTypeId << 4) + alternateRightTypeId];
216
			// (cast)  left   Op (cast)  right --> result
217
			//  1111   0000       1111   0000     1111
218
			//  <<16   <<12       <<8    <<4       <<0
219
			final int CompareMASK = (0xF<<16) + (0xF<<8) + 0xF; // mask hiding compile-time types
220
			if ((operatorSignature & CompareMASK) == (alternateOperatorSignature & CompareMASK)) { // same promotions and result
221
				if (leftIsCast) scope.problemReporter().unnecessaryCast((CastExpression)left); 
222
				if (rightIsCast) scope.problemReporter().unnecessaryCast((CastExpression)right);
223
			}
238
			}
224
		}
239
		}
240
		int alternateOperatorSignature = OperatorExpression.OperatorSignatures[operator][(alternateLeftTypeId << 4) + alternateRightTypeId];
241
		// (cast)  left   Op (cast)  right --> result
242
		//  1111   0000       1111   0000     1111
243
		//  <<16   <<12       <<8    <<4       <<0
244
		final int CompareMASK = (0xF<<16) + (0xF<<8) + 0xF; // mask hiding compile-time types
245
		if ((operatorSignature & CompareMASK) == (alternateOperatorSignature & CompareMASK)) { // same promotions and result
246
			if (leftIsCast) scope.problemReporter().unnecessaryCast((CastExpression)left); 
247
			if (rightIsCast) scope.problemReporter().unnecessaryCast((CastExpression)right);
248
		}
225
	}
249
	}
250
}
226
251
227
	private static void checkAlternateBinding(BlockScope scope, Expression receiver, TypeBinding receiverType, MethodBinding binding, Expression[] arguments, TypeBinding[] originalArgumentTypes, TypeBinding[] alternateArgumentTypes, final InvocationSite invocationSite) {
252
private static void checkAlternateBinding(BlockScope scope, Expression receiver, TypeBinding receiverType, MethodBinding binding, Expression[] arguments, TypeBinding[] originalArgumentTypes, TypeBinding[] alternateArgumentTypes, final InvocationSite invocationSite) {
228
253
		InvocationSite fakeInvocationSite = new InvocationSite(){	
229
			InvocationSite fakeInvocationSite = new InvocationSite(){	
254
			public TypeBinding[] genericTypeArguments() { return null; }
230
				public TypeBinding[] genericTypeArguments() { return null; }
255
			public boolean isSuperAccess(){ return invocationSite.isSuperAccess(); }
231
				public boolean isSuperAccess(){ return invocationSite.isSuperAccess(); }
256
			public boolean isTypeAccess() { return invocationSite.isTypeAccess(); }
232
				public boolean isTypeAccess() { return invocationSite.isTypeAccess(); }
257
			public void setActualReceiverType(ReferenceBinding actualReceiverType) { /* ignore */}
233
				public void setActualReceiverType(ReferenceBinding actualReceiverType) { /* ignore */}
258
			public void setDepth(int depth) { /* ignore */}
234
				public void setDepth(int depth) { /* ignore */}
259
			public void setFieldIndex(int depth){ /* ignore */}
235
				public void setFieldIndex(int depth){ /* ignore */}
260
			public int sourceStart() { return 0; }
236
				public int sourceStart() { return 0; }
261
			public int sourceEnd() { return 0; }
237
				public int sourceEnd() { return 0; }
262
		};	
238
			};	
263
		MethodBinding bindingIfNoCast;
239
			MethodBinding bindingIfNoCast;
264
		if (binding.isConstructor()) {
240
			if (binding.isConstructor()) {
265
			bindingIfNoCast = scope.getConstructor((ReferenceBinding)receiverType, alternateArgumentTypes, fakeInvocationSite);
241
				bindingIfNoCast = scope.getConstructor((ReferenceBinding)receiverType, alternateArgumentTypes, fakeInvocationSite);
266
		} else {
242
			} else {
267
			bindingIfNoCast = receiver.isImplicitThis()
243
				bindingIfNoCast = receiver.isImplicitThis()
268
				? scope.getImplicitMethod(binding.selector, alternateArgumentTypes, fakeInvocationSite)
244
					? scope.getImplicitMethod(binding.selector, alternateArgumentTypes, fakeInvocationSite)
269
				: scope.getMethod(receiverType, binding.selector, alternateArgumentTypes, fakeInvocationSite); 	
245
					: scope.getMethod(receiverType, binding.selector, alternateArgumentTypes, fakeInvocationSite); 	
270
		}
246
			}
271
		if (bindingIfNoCast == binding) {
247
			if (bindingIfNoCast == binding) {
272
			int argumentLength = originalArgumentTypes.length;
248
				int argumentLength = originalArgumentTypes.length;
273
			if (binding.isVarargs()) {
249
				if (binding.isVarargs()) {
274
				int paramLength = binding.parameters.length;
250
					int paramLength = binding.parameters.length;
275
				if (paramLength == argumentLength) {
251
					if (paramLength == argumentLength) {
276
					int varargsIndex = paramLength - 1;
252
						int varargsIndex = paramLength - 1;
277
					ArrayBinding varargsType = (ArrayBinding) binding.parameters[varargsIndex];
253
						ArrayBinding varargsType = (ArrayBinding) binding.parameters[varargsIndex];
278
					TypeBinding lastArgType = alternateArgumentTypes[varargsIndex];
254
						TypeBinding lastArgType = alternateArgumentTypes[varargsIndex];
279
					// originalType may be compatible already, but cast mandated
255
						// originalType may be compatible already, but cast mandated
280
					// to clarify between varargs/non-varargs call
256
						// to clarify between varargs/non-varargs call
281
					if (varargsType.dimensions != lastArgType.dimensions()) {
257
						if (varargsType.dimensions != lastArgType.dimensions()) {
282
						return;
258
							return;
259
						}
260
						if (lastArgType.isCompatibleWith(varargsType.elementsType())
261
								&& lastArgType.isCompatibleWith(varargsType)) {
262
							return;
263
						}
264
					}
283
					}
265
				}
284
					if (lastArgType.isCompatibleWith(varargsType.elementsType())
266
				for (int i = 0; i < argumentLength; i++) {
285
							&& lastArgType.isCompatibleWith(varargsType)) {
267
					if (originalArgumentTypes[i] != alternateArgumentTypes[i]) {
286
						return;
268
						scope.problemReporter().unnecessaryCast((CastExpression)arguments[i]);
269
					}
287
					}
270
				}
288
				}
271
			}	
289
			}
290
			for (int i = 0; i < argumentLength; i++) {
291
				if (originalArgumentTypes[i] != alternateArgumentTypes[i]) {
292
					scope.problemReporter().unnecessaryCast((CastExpression)arguments[i]);
293
				}
294
			}
295
		}	
296
}
297
298
public boolean checkUnsafeCast(Scope scope, TypeBinding castType, TypeBinding expressionType, TypeBinding match, boolean isNarrowing) {
299
	if (match == castType) {
300
		if (!isNarrowing && match == this.resolvedType.leafComponentType()) { // do not tag as unnecessary when recursing through upper bounds
301
			tagAsUnnecessaryCast(scope, castType);
302
		}
303
		return true;
272
	}
304
	}
273
	
305
	if (match != null) {
274
	public boolean checkUnsafeCast(Scope scope, TypeBinding castType, TypeBinding expressionType, TypeBinding match, boolean isNarrowing) {
306
		if (isNarrowing
275
 		if (match == castType) {
307
				? match.isProvablyDistinct(expressionType)
276
			if (!isNarrowing && match == this.resolvedType.leafComponentType()) { // do not tag as unnecessary when recursing through upper bounds
308
				: castType.isProvablyDistinct(match)) {
277
				tagAsUnnecessaryCast(scope, castType);
309
			return false;
278
			}
310
		}
279
			return true;
311
	}
280
		}
312
	switch (castType.kind()) {
281
		if (match != null) {
313
		case Binding.PARAMETERIZED_TYPE :
282
			if (isNarrowing
314
			if (castType.isBoundParameterizedType()) {
283
					? match.isProvablyDistinct(expressionType)
315
				if (match == null) { // unrelated types
284
					: castType.isProvablyDistinct(match)) {
316
					this.bits |= ASTNode.UnsafeCast;
285
				return false;
317
					return true;
286
			}
318
				}
287
		}
319
				switch (match.kind()) {
288
		switch (castType.kind()) {
320
					case Binding.PARAMETERIZED_TYPE :
289
			case Binding.PARAMETERIZED_TYPE :
321
						if (isNarrowing) {
290
				if (castType.isBoundParameterizedType()) {
322
							// [JLS 5.5] T <: S
291
					if (match == null) { // unrelated types
323
							if (expressionType.isRawType() || !expressionType.isEquivalentTo(match)) {
292
						this.bits |= UnsafeCast;
324
								this.bits |= ASTNode.UnsafeCast;
293
						return true;
294
					}
295
					switch (match.kind()) {
296
						case Binding.PARAMETERIZED_TYPE :
297
							if (isNarrowing) {
298
								// [JLS 5.5] T <: S
299
								if (expressionType.isRawType() || !expressionType.isEquivalentTo(match)) {
300
									this.bits |= UnsafeCast;
301
									return true;
302
								}
303
								// [JLS 5.5] S has no subtype X != T, such that |X| == |T|
304
								TypeBinding genericCastType = castType.erasure(); // jump to generic type
305
								TypeBinding genericMatch = genericCastType.findSuperTypeOriginatingFrom(expressionType);
306
								if (genericMatch == match) {
307
									this.bits |= UnsafeCast;
308
								} else {
309
									// if I2<T,U> extends I1<T>, then cast from I1<T> to I2<T,U> is unchecked
310
									ParameterizedTypeBinding paramCastType = (ParameterizedTypeBinding) castType;
311
									ParameterizedTypeBinding paramMatch = (ParameterizedTypeBinding) match;
312
									// easy case if less parameters on match
313
									TypeBinding[] castArguments = paramCastType.arguments;
314
									int length = castArguments.length;
315
									if (length > paramMatch.arguments.length) {
316
										this.bits |= UnsafeCast;
317
									} else if ((paramCastType.tagBits & (TagBits.HasDirectWildcard|TagBits.HasTypeVariable)) != 0) {
318
										// verify alternate cast type, substituting different type arguments
319
										LookupEnvironment environment = scope.environment();
320
										nextAlternateArgument: for (int i = 0; i < length; i++) {
321
											switch (castArguments[i].kind()) {
322
												case Binding.WILDCARD_TYPE :
323
												case Binding.TYPE_PARAMETER :
324
													break; // check substituting with other
325
												default:
326
													continue nextAlternateArgument; // no alternative possible
327
											}
328
											TypeBinding[] alternateArguments;
329
											// need to clone for each iteration to avoid env paramtype cache interference
330
											System.arraycopy(paramCastType.arguments, 0, alternateArguments = new TypeBinding[length], 0, length);
331
											alternateArguments[i] = scope.getJavaLangObject();
332
											ParameterizedTypeBinding alternateCastType = environment.createParameterizedType((ReferenceBinding)genericCastType, alternateArguments, castType.enclosingType());
333
											if (alternateCastType.findSuperTypeOriginatingFrom(expressionType) == match) {
334
												this.bits |= UnsafeCast;
335
												break;
336
											}
337
										}
338
									}
339
								}
340
								return true;
325
								return true;
326
							}
327
							// [JLS 5.5] S has no subtype X != T, such that |X| == |T|
328
							TypeBinding genericCastType = castType.erasure(); // jump to generic type
329
							TypeBinding genericMatch = genericCastType.findSuperTypeOriginatingFrom(expressionType);
330
							if (genericMatch == match) {
331
								this.bits |= ASTNode.UnsafeCast;
341
							} else {
332
							} else {
342
								// [JLS 5.5] T >: S
333
								// if I2<T,U> extends I1<T>, then cast from I1<T> to I2<T,U> is unchecked
343
								if (!match.isEquivalentTo(castType)) {
334
								ParameterizedTypeBinding paramCastType = (ParameterizedTypeBinding) castType;
344
									this.bits |= UnsafeCast;
335
								ParameterizedTypeBinding paramMatch = (ParameterizedTypeBinding) match;
345
									return true;
336
								// easy case if less parameters on match
337
								TypeBinding[] castArguments = paramCastType.arguments;
338
								int length = castArguments.length;
339
								if (length > paramMatch.arguments.length) {
340
									this.bits |= ASTNode.UnsafeCast;
341
								} else if ((paramCastType.tagBits & (TagBits.HasDirectWildcard|TagBits.HasTypeVariable)) != 0) {
342
									// verify alternate cast type, substituting different type arguments
343
									LookupEnvironment environment = scope.environment();
344
									nextAlternateArgument: for (int i = 0; i < length; i++) {
345
										switch (castArguments[i].kind()) {
346
											case Binding.WILDCARD_TYPE :
347
											case Binding.TYPE_PARAMETER :
348
												break; // check substituting with other
349
											default:
350
												continue nextAlternateArgument; // no alternative possible
351
										}
352
										TypeBinding[] alternateArguments;
353
										// need to clone for each iteration to avoid env paramtype cache interference
354
										System.arraycopy(paramCastType.arguments, 0, alternateArguments = new TypeBinding[length], 0, length);
355
										alternateArguments[i] = scope.getJavaLangObject();
356
										ParameterizedTypeBinding alternateCastType = environment.createParameterizedType((ReferenceBinding)genericCastType, alternateArguments, castType.enclosingType());
357
										if (alternateCastType.findSuperTypeOriginatingFrom(expressionType) == match) {
358
											this.bits |= ASTNode.UnsafeCast;
359
											break;
360
										}
361
									}
346
								}
362
								}
347
							}
363
							}
348
							break;
349
						case Binding.RAW_TYPE :
350
							this.bits |= UnsafeCast; // upcast since castType is known to be bound paramType
351
							return true;
364
							return true;
352
						default :
365
						} else {
353
							if (isNarrowing){
366
							// [JLS 5.5] T >: S
354
								// match is not parameterized or raw, then any other subtype of match will erase  to |T|
367
							if (!match.isEquivalentTo(castType)) {
355
								this.bits |= UnsafeCast;
368
								this.bits |= ASTNode.UnsafeCast;
356
								return true;
369
								return true;
357
							}
370
							}
358
							break;
371
						}
359
					}
372
						break;
360
				}
373
					case Binding.RAW_TYPE :
361
				break;
374
						this.bits |= ASTNode.UnsafeCast; // upcast since castType is known to be bound paramType
362
			case Binding.ARRAY_TYPE :
375
						return true;
363
				TypeBinding leafType = castType.leafComponentType();
376
					default :
364
				if (isNarrowing && (leafType.isBoundParameterizedType() || leafType.isTypeVariable())) {
377
						if (isNarrowing){
365
					this.bits |= UnsafeCast;
378
							// match is not parameterized or raw, then any other subtype of match will erase  to |T|
366
					return true;
379
							this.bits |= ASTNode.UnsafeCast;
367
				}
380
							return true;
368
				break;
381
						}
369
			case Binding.TYPE_PARAMETER :
382
						break;
370
				this.bits |= UnsafeCast;
371
				return true;				
372
		}
373
		if (!isNarrowing && match == this.resolvedType.leafComponentType()) { // do not tag as unnecessary when recursing through upper bounds
374
			tagAsUnnecessaryCast(scope, castType);
375
		}
376
		return true;
377
	}	
378
	
379
	/**
380
	 * Cast expression code generation
381
	 *
382
	 * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
383
	 * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
384
	 * @param valueRequired boolean
385
	 */
386
	public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
387
	
388
		int pc = codeStream.position;
389
		boolean needRuntimeCheckcast = (this.bits & GenerateCheckcast) != 0;
390
		if (constant != Constant.NotAConstant) {
391
			if (valueRequired || needRuntimeCheckcast) { // Added for: 1F1W9IG: IVJCOM:WINNT - Compiler omits casting check
392
				codeStream.generateConstant(constant, implicitConversion);
393
				if (needRuntimeCheckcast) {
394
					codeStream.checkcast(this.resolvedType);
395
				}
396
				if (!valueRequired) {
397
					// the resolveType cannot be double or long
398
					codeStream.pop();
399
				}
383
				}
400
			}
384
			}
401
			codeStream.recordPositionsFrom(pc, this.sourceStart);
385
			break;
402
			return;
386
		case Binding.ARRAY_TYPE :
403
		}
387
			TypeBinding leafType = castType.leafComponentType();
404
		expression.generateCode(currentScope, codeStream, valueRequired || needRuntimeCheckcast);
388
			if (isNarrowing && (leafType.isBoundParameterizedType() || leafType.isTypeVariable())) {
405
		if (needRuntimeCheckcast && this.expression.postConversionType(currentScope) != this.resolvedType.erasure()) { // no need to issue a checkcast if already done as genericCast
389
				this.bits |= ASTNode.UnsafeCast;
406
			codeStream.checkcast(this.resolvedType);
390
				return true;
407
		}
391
			}
408
		if (valueRequired) {
392
			break;
409
			codeStream.generateImplicitConversion(implicitConversion);
393
		case Binding.TYPE_PARAMETER :
410
		} else if (needRuntimeCheckcast) {
394
			this.bits |= ASTNode.UnsafeCast;
411
			codeStream.pop();
395
			return true;				
396
	}
397
	if (!isNarrowing && match == this.resolvedType.leafComponentType()) { // do not tag as unnecessary when recursing through upper bounds
398
		tagAsUnnecessaryCast(scope, castType);
399
	}
400
	return true;
401
}	
402
403
/**
404
 * Cast expression code generation
405
 *
406
 * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
407
 * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
408
 * @param valueRequired boolean
409
 */
410
public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
411
	int pc = codeStream.position;
412
	boolean needRuntimeCheckcast = (this.bits & ASTNode.GenerateCheckcast) != 0;
413
	if (this.constant != Constant.NotAConstant) {
414
		if (valueRequired || needRuntimeCheckcast) { // Added for: 1F1W9IG: IVJCOM:WINNT - Compiler omits casting check
415
			codeStream.generateConstant(this.constant, this.implicitConversion);
416
			if (needRuntimeCheckcast) {
417
				codeStream.checkcast(this.resolvedType);
418
			}
419
			if (!valueRequired) {
420
				// the resolveType cannot be double or long
421
				codeStream.pop();
422
			}
412
		}
423
		}
413
		codeStream.recordPositionsFrom(pc, this.sourceStart);
424
		codeStream.recordPositionsFrom(pc, this.sourceStart);
425
		return;
414
	}
426
	}
415
427
	this.expression.generateCode(currentScope, codeStream, valueRequired || needRuntimeCheckcast);
416
	public Expression innermostCastedExpression(){ 
428
	if (needRuntimeCheckcast && this.expression.postConversionType(currentScope) != this.resolvedType.erasure()) { // no need to issue a checkcast if already done as genericCast
417
		Expression current = this.expression;
429
		codeStream.checkcast(this.resolvedType);
418
		while (current instanceof CastExpression) {
430
	}
419
			current = ((CastExpression) current).expression;
431
	if (valueRequired) {
420
		}
432
		codeStream.generateImplicitConversion(this.implicitConversion);
421
		return current;
433
	} else if (needRuntimeCheckcast) {
434
		codeStream.pop();
422
	}
435
	}
436
	codeStream.recordPositionsFrom(pc, this.sourceStart);
437
}
423
438
424
	/**
439
public Expression innermostCastedExpression(){ 
425
	 * @see org.eclipse.jdt.internal.compiler.ast.Expression#localVariableBinding()
440
	Expression current = this.expression;
426
	 */
441
	while (current instanceof CastExpression) {
427
	public LocalVariableBinding localVariableBinding() {
442
		current = ((CastExpression) current).expression;
428
		return this.expression.localVariableBinding();
429
	}
443
	}
430
	
444
	return current;
431
	public int nullStatus(FlowInfo flowInfo) {
445
}
432
		return this.expression.nullStatus(flowInfo);
446
433
	}
447
/**
434
	
448
 * @see org.eclipse.jdt.internal.compiler.ast.Expression#localVariableBinding()
435
	/**
449
 */
436
	 * @see org.eclipse.jdt.internal.compiler.ast.Expression#optimizedBooleanConstant()
450
public LocalVariableBinding localVariableBinding() {
437
	 */
451
	return this.expression.localVariableBinding();
438
	public Constant optimizedBooleanConstant() {
452
}
439
		switch(this.resolvedType.id) {
453
440
			case T_boolean :
454
public int nullStatus(FlowInfo flowInfo) {
441
			case T_JavaLangBoolean :
455
	return this.expression.nullStatus(flowInfo);
442
				return this.expression.optimizedBooleanConstant();
456
}
443
		}
457
444
		return Constant.NotAConstant;
458
/**
459
 * @see org.eclipse.jdt.internal.compiler.ast.Expression#optimizedBooleanConstant()
460
 */
461
public Constant optimizedBooleanConstant() {
462
	switch(this.resolvedType.id) {
463
		case T_boolean :
464
		case T_JavaLangBoolean :
465
			return this.expression.optimizedBooleanConstant();
445
	}
466
	}
446
	
467
	return Constant.NotAConstant;
447
	public StringBuffer printExpression(int indent, StringBuffer output) {
468
}
448
469
449
		output.append('(');
470
public StringBuffer printExpression(int indent, StringBuffer output) {
450
		type.print(0, output).append(") "); //$NON-NLS-1$
471
	output.append('(');
451
		return expression.printExpression(0, output);
472
	this.type.print(0, output).append(") "); //$NON-NLS-1$
452
	}
473
	return this.expression.printExpression(0, output);
453
474
}
454
	public TypeBinding resolveType(BlockScope scope) {
475
455
		// compute a new constant if the cast is effective
476
public TypeBinding resolveType(BlockScope scope) {
456
477
	// compute a new constant if the cast is effective
457
		// due to the fact an expression may start with ( and that a cast can also start with (
478
458
		// the field is an expression....it can be a TypeReference OR a NameReference Or
479
	// due to the fact an expression may start with ( and that a cast can also start with (
459
		// any kind of Expression <-- this last one is invalid.......
480
	// the field is an expression....it can be a TypeReference OR a NameReference Or
460
481
	// any kind of Expression <-- this last one is invalid.......
461
		constant = Constant.NotAConstant;
482
462
		implicitConversion = T_undefined;
483
	this.constant = Constant.NotAConstant;
463
484
	this.implicitConversion = TypeIds.T_undefined;
464
		if ((type instanceof TypeReference) || (type instanceof NameReference)
485
465
				&& ((type.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT) == 0) { // no extra parenthesis around type: ((A))exp
486
	if ((this.type instanceof TypeReference) || (this.type instanceof NameReference)
466
487
			&& ((this.type.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT) == 0) { // no extra parenthesis around type: ((A))exp
467
			TypeBinding castType = this.resolvedType = type.resolveType(scope);
488
468
			//expression.setExpectedType(this.resolvedType); // needed in case of generic method invocation			
489
		boolean exprContainCast = false;
469
			TypeBinding expressionType = expression.resolveType(scope);
490
		
470
			if (castType != null) {
491
		TypeBinding castType = this.resolvedType = this.type.resolveType(scope);
471
				if (expressionType != null) {
492
		//expression.setExpectedType(this.resolvedType); // needed in case of generic method invocation			
472
					boolean isLegal = checkCastTypesCompatibility(scope, castType, expressionType, this.expression);
493
		if (this.expression instanceof CastExpression) {
473
					if (isLegal) {
494
			this.expression.bits |= ASTNode.DisableUnnecessaryCastCheck;
474
						this.expression.computeConversion(scope, castType, expressionType);
495
			exprContainCast = true;
475
						if ((this.bits & UnsafeCast) != 0) { // unsafe cast
496
		}
476
							scope.problemReporter().unsafeCast(this, scope);
497
		TypeBinding expressionType = this.expression.resolveType(scope);
477
						} else {
498
		if (castType != null) {
478
							if (castType.isRawType() && scope.compilerOptions().getSeverity(CompilerOptions.RawTypeReference) != ProblemSeverities.Ignore){
499
			if (expressionType != null) {
479
								scope.problemReporter().rawTypeReference(this.type, castType);			
500
				boolean isLegal = checkCastTypesCompatibility(scope, castType, expressionType, this.expression);
480
							}
501
				if (isLegal) {
481
							if ((this.bits & (UnnecessaryCast|DisableUnnecessaryCastCheck)) == UnnecessaryCast) { // unnecessary cast 
502
					this.expression.computeConversion(scope, castType, expressionType);
482
								if (!isIndirectlyUsed()) // used for generic type inference or boxing ?
503
					if ((this.bits & ASTNode.UnsafeCast) != 0) { // unsafe cast
483
									scope.problemReporter().unnecessaryCast(this);
504
						scope.problemReporter().unsafeCast(this, scope);
484
							}
505
					} else {
506
						if (castType.isRawType() && scope.compilerOptions().getSeverity(CompilerOptions.RawTypeReference) != ProblemSeverities.Ignore){
507
							scope.problemReporter().rawTypeReference(this.type, castType);			
485
						}
508
						}
486
					} else { // illegal cast
509
						if ((this.bits & (ASTNode.UnnecessaryCast|ASTNode.DisableUnnecessaryCastCheck)) == ASTNode.UnnecessaryCast) { // unnecessary cast 
487
						if ((castType.tagBits & TagBits.HasMissingType) == 0) { // no complaint if secondary error
510
							if (!isIndirectlyUsed()) // used for generic type inference or boxing ?
488
							scope.problemReporter().typeCastError(this, castType, expressionType);
511
								scope.problemReporter().unnecessaryCast(this);
489
						}
512
						}
490
						this.bits |= DisableUnnecessaryCastCheck; // disable further secondary diagnosis
491
					}
513
					}
514
				} else { // illegal cast
515
					if ((castType.tagBits & TagBits.HasMissingType) == 0) { // no complaint if secondary error
516
						scope.problemReporter().typeCastError(this, castType, expressionType);
517
					}
518
					this.bits |= ASTNode.DisableUnnecessaryCastCheck; // disable further secondary diagnosis
492
				}
519
				}
493
				this.resolvedType = castType.capture(scope, this.sourceEnd);
494
			}
520
			}
495
			return this.resolvedType;
521
			this.resolvedType = castType.capture(scope, this.sourceEnd);
496
		} else { // expression as a cast
522
			if (exprContainCast) {
497
			TypeBinding expressionType = expression.resolveType(scope);
523
				checkNeedForCastCast(scope, this);
498
			if (expressionType == null) return null;
499
			scope.problemReporter().invalidTypeReference(type);
500
			return null;
501
		}
502
	}
503
	
504
	/**
505
	 * @see org.eclipse.jdt.internal.compiler.ast.Expression#setExpectedType(org.eclipse.jdt.internal.compiler.lookup.TypeBinding)
506
	 */
507
	public void setExpectedType(TypeBinding expectedType) {
508
		this.expectedType = expectedType;
509
	}
510
511
	/**
512
	 * Determines whether apparent unnecessary cast wasn't actually used to
513
	 * perform return type inference of generic method invocation or boxing.
514
	 */
515
	private boolean isIndirectlyUsed() {
516
		if (this.expression instanceof MessageSend) {
517
			MethodBinding method = ((MessageSend)this.expression).binding;
518
			if (method instanceof ParameterizedGenericMethodBinding
519
						&& ((ParameterizedGenericMethodBinding)method).inferredReturnType) {
520
				if (this.expectedType == null) 
521
					return true;
522
				if (this.resolvedType != this.expectedType)
523
					return true;
524
			}
524
			}
525
		}
525
		}
526
		if (this.expectedType != null && this.resolvedType.isBaseType() && !this.resolvedType.isCompatibleWith(this.expectedType)) {
526
		return this.resolvedType;
527
			// boxing: Short s = (short) _byte
527
	} else { // expression as a cast
528
			return true;
528
		TypeBinding expressionType = this.expression.resolveType(scope);
529
		}
529
		if (expressionType == null) return null;
530
		return false;
530
		scope.problemReporter().invalidTypeReference(this.type);
531
		return null;
531
	}
532
	}
533
}
532
534
533
	/**
535
/**
534
	 * @see org.eclipse.jdt.internal.compiler.ast.Expression#tagAsNeedCheckCast()
536
 * @see org.eclipse.jdt.internal.compiler.ast.Expression#setExpectedType(org.eclipse.jdt.internal.compiler.lookup.TypeBinding)
535
	 */
537
 */
536
	public void tagAsNeedCheckCast() {
538
public void setExpectedType(TypeBinding expectedType) {
537
		this.bits |= GenerateCheckcast;
539
	this.expectedType = expectedType;
540
}
541
542
/**
543
 * Determines whether apparent unnecessary cast wasn't actually used to
544
 * perform return type inference of generic method invocation or boxing.
545
 */
546
private boolean isIndirectlyUsed() {
547
	if (this.expression instanceof MessageSend) {
548
		MethodBinding method = ((MessageSend)this.expression).binding;
549
		if (method instanceof ParameterizedGenericMethodBinding
550
					&& ((ParameterizedGenericMethodBinding)method).inferredReturnType) {
551
			if (this.expectedType == null) 
552
				return true;
553
			if (this.resolvedType != this.expectedType)
554
				return true;
555
		}
538
	}
556
	}
539
	
557
	if (this.expectedType != null && this.resolvedType.isBaseType() && !this.resolvedType.isCompatibleWith(this.expectedType)) {
540
	/**
558
		// boxing: Short s = (short) _byte
541
	 * @see org.eclipse.jdt.internal.compiler.ast.Expression#tagAsUnnecessaryCast(Scope, TypeBinding)
559
		return true;
542
	 */
543
	public void tagAsUnnecessaryCast(Scope scope, TypeBinding castType) {
544
		if (this.expression.resolvedType == null) return; // cannot do better if expression is not bound
545
		this.bits |= UnnecessaryCast;
546
	}
560
	}
547
	
561
	return false;
548
	public void traverse(
562
}
549
		ASTVisitor visitor,
563
550
		BlockScope blockScope) {
564
/**
551
565
 * @see org.eclipse.jdt.internal.compiler.ast.Expression#tagAsNeedCheckCast()
552
		if (visitor.visit(this, blockScope)) {
566
 */
553
			type.traverse(visitor, blockScope);
567
public void tagAsNeedCheckCast() {
554
			expression.traverse(visitor, blockScope);
568
	this.bits |= ASTNode.GenerateCheckcast;
555
		}
569
}
556
		visitor.endVisit(this, blockScope);
570
571
/**
572
 * @see org.eclipse.jdt.internal.compiler.ast.Expression#tagAsUnnecessaryCast(Scope, TypeBinding)
573
 */
574
public void tagAsUnnecessaryCast(Scope scope, TypeBinding castType) {
575
	this.bits |= ASTNode.UnnecessaryCast;
576
}
577
578
public void traverse(ASTVisitor visitor, BlockScope blockScope) {
579
	if (visitor.visit(this, blockScope)) {
580
		this.type.traverse(visitor, blockScope);
581
		this.expression.traverse(visitor, blockScope);
557
	}
582
	}
583
	visitor.endVisit(this, blockScope);
584
}
558
}
585
}

Return to bug 223685