@@ -204,38 +204,42 @@ private predicate exactType(TypeFlowNode n, RefType t) {
204
204
205
205
/**
206
206
* Holds if `n` occurs in a position where type information might be discarded;
207
- * `t ` is the potentially boxed type of `n`, `t1 ` is the erasure of `t `, and
208
- * `t2` is the erased type of the implicit or explicit cast .
207
+ * `t1 ` is the type of `n`, `t1e ` is the erasure of `t1 `, `t2` is the type of
208
+ * the implicit or explicit cast, and `t2e` is the erasure of `t2` .
209
209
*/
210
- pragma [ noinline]
211
- private predicate upcastCand ( TypeFlowNode n , RefType t , RefType t1 , RefType t2 ) {
212
- t = boxIfNeeded ( n .getType ( ) ) and
213
- t .getErasure ( ) = t1 and
214
- (
215
- exists ( Variable v | v .getAnAssignedValue ( ) = n .asExpr ( ) and t2 = v .getType ( ) .getErasure ( ) )
216
- or
217
- exists ( CastingExpr c | c .getExpr ( ) = n .asExpr ( ) and t2 = c .getType ( ) .getErasure ( ) )
218
- or
219
- exists ( ReturnStmt ret |
220
- ret .getResult ( ) = n .asExpr ( ) and t2 = ret .getEnclosingCallable ( ) .getReturnType ( ) .getErasure ( )
221
- )
222
- or
223
- exists ( MethodAccess ma | viableImpl_v1 ( ma ) = n .asMethod ( ) and t2 = ma .getType ( ) .getErasure ( ) )
224
- or
225
- exists ( Parameter p | privateParamArg ( p , n .asExpr ( ) ) and t2 = p .getType ( ) .getErasure ( ) )
226
- or
227
- exists ( ChooseExpr cond |
228
- cond .getAResultExpr ( ) = n .asExpr ( ) and
229
- t2 = cond .getType ( ) .getErasure ( )
210
+ pragma [ nomagic]
211
+ private predicate upcastCand ( TypeFlowNode n , RefType t1 , RefType t1e , RefType t2 , RefType t2e ) {
212
+ exists ( TypeFlowNode next | step ( n , next ) or joinStep ( n , next ) |
213
+ n .getType ( ) = t1 and
214
+ next .getType ( ) = t2 and
215
+ t1 .getErasure ( ) = t1e and
216
+ t2 .getErasure ( ) = t2e and
217
+ t1 != t2
218
+ )
219
+ }
220
+
221
+ /** Holds if `t` is a raw type or parameterised type with unrestricted type arguments. */
222
+ private predicate unbound ( RefType t ) {
223
+ t instanceof RawType
224
+ or
225
+ exists ( ParameterizedType pt | pt = t |
226
+ forex ( RefType arg | arg = pt .getATypeArgument ( ) |
227
+ arg .( Wildcard ) .isUnconstrained ( )
228
+ or
229
+ arg .( BoundedType ) .getUpperBoundType ( ) instanceof TypeObject and
230
+ not arg .( Wildcard ) .hasLowerBound ( )
230
231
)
231
232
)
232
233
}
233
234
234
235
/** Holds if `n` occurs in a position where type information is discarded. */
235
- private predicate upcast ( TypeFlowNode n , RefType t ) {
236
- exists ( RefType t1 , RefType t2 |
237
- upcastCand ( n , t , t1 , t2 ) and
238
- t1 .getASourceSupertype + ( ) = t2
236
+ private predicate upcast ( TypeFlowNode n , RefType t1 ) {
237
+ exists ( RefType t1e , RefType t2 , RefType t2e | upcastCand ( n , t1 , t1e , t2 , t2e ) |
238
+ t1e .getASourceSupertype + ( ) = t2e
239
+ or
240
+ t1e = t2e and
241
+ unbound ( t2 ) and
242
+ not unbound ( t1 )
239
243
)
240
244
}
241
245
0 commit comments