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 |
} |