Skip to content

Commit bd6acc0

Browse files
committed
Java: Refactor upcastCand, and track type flow for upcasts to unbound generics.
1 parent fc415b3 commit bd6acc0

File tree

1 file changed

+30
-26
lines changed

1 file changed

+30
-26
lines changed

java/ql/lib/semmle/code/java/dataflow/TypeFlow.qll

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -204,38 +204,42 @@ private predicate exactType(TypeFlowNode n, RefType t) {
204204

205205
/**
206206
* 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`.
209209
*/
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()
230231
)
231232
)
232233
}
233234

234235
/** 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)
239243
)
240244
}
241245

0 commit comments

Comments
 (0)