Skip to content

Commit 6b01f02

Browse files
committed
Java: Deduplicate unification code as a parameterised module.
1 parent 4df2e5d commit 6b01f02

File tree

4 files changed

+106
-244
lines changed

4 files changed

+106
-244
lines changed

java/ql/lib/semmle/code/java/dataflow/internal/DataFlowDispatch.qll

Lines changed: 6 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ private import DataFlowUtil
44
private import semmle.code.java.dataflow.InstanceAccess
55
private import semmle.code.java.dataflow.FlowSummary
66
private import semmle.code.java.dispatch.VirtualDispatch as VirtualDispatch
7+
private import semmle.code.java.dispatch.Unification
78

89
private module DispatchImpl {
910
/** Gets a viable implementation of the target of the given `Call`. */
@@ -115,74 +116,20 @@ private module DispatchImpl {
115116
exact = false and
116117
exists(RefType t2 |
117118
result.asCallable() = VirtualDispatch::viableMethodImpl(def, t.getSourceDeclaration(), t2) and
118-
not failsUnification(t, t2)
119+
not Unification::failsUnification(t, t2)
119120
)
120121
or
121122
result.asSummarizedCallable() = def
122123
)
123124
}
124125

125-
pragma[noinline]
126-
private predicate unificationTargetLeft(ParameterizedType t1, GenericType g) {
127-
contextArgHasType(_, _, t1, _) and t1.getGenericType() = g
128-
}
129-
130-
pragma[noinline]
131-
private predicate unificationTargetRight(ParameterizedType t2, GenericType g) {
132-
exists(VirtualDispatch::viableMethodImpl(_, _, t2)) and t2.getGenericType() = g
133-
}
134-
135-
private predicate unificationTargets(Type t1, Type t2) {
136-
exists(GenericType g | unificationTargetLeft(t1, g) and unificationTargetRight(t2, g))
137-
or
138-
exists(Array a1, Array a2 |
139-
unificationTargets(a1, a2) and
140-
t1 = a1.getComponentType() and
141-
t2 = a2.getComponentType()
142-
)
143-
or
144-
exists(ParameterizedType pt1, ParameterizedType pt2, int pos |
145-
unificationTargets(pt1, pt2) and
146-
not pt1.getSourceDeclaration() != pt2.getSourceDeclaration() and
147-
t1 = pt1.getTypeArgument(pos) and
148-
t2 = pt2.getTypeArgument(pos)
149-
)
150-
}
126+
private predicate unificationTargetLeft(ParameterizedType t1) { contextArgHasType(_, _, t1, _) }
151127

152-
pragma[noinline]
153-
private predicate typeArgsOfUnificationTargets(
154-
ParameterizedType t1, ParameterizedType t2, int pos, RefType arg1, RefType arg2
155-
) {
156-
unificationTargets(t1, t2) and
157-
arg1 = t1.getTypeArgument(pos) and
158-
arg2 = t2.getTypeArgument(pos)
128+
private predicate unificationTargetRight(ParameterizedType t2) {
129+
exists(VirtualDispatch::viableMethodImpl(_, _, t2))
159130
}
160131

161-
private predicate failsUnification(Type t1, Type t2) {
162-
unificationTargets(t1, t2) and
163-
(
164-
exists(RefType arg1, RefType arg2 |
165-
typeArgsOfUnificationTargets(t1, t2, _, arg1, arg2) and
166-
failsUnification(arg1, arg2)
167-
)
168-
or
169-
failsUnification(t1.(Array).getComponentType(), t2.(Array).getComponentType())
170-
or
171-
not (
172-
t1 instanceof Array and t2 instanceof Array
173-
or
174-
t1.(PrimitiveType) = t2.(PrimitiveType)
175-
or
176-
t1.(Class).getSourceDeclaration() = t2.(Class).getSourceDeclaration()
177-
or
178-
t1.(Interface).getSourceDeclaration() = t2.(Interface).getSourceDeclaration()
179-
or
180-
t1 instanceof BoundedType and t2 instanceof RefType
181-
or
182-
t1 instanceof RefType and t2 instanceof BoundedType
183-
)
184-
)
185-
}
132+
private module Unification = MkUnification<unificationTargetLeft/1, unificationTargetRight/1>;
186133

187134
private int parameterPosition() { result in [-1, any(Parameter p).getPosition()] }
188135

java/ql/lib/semmle/code/java/dispatch/ObjFlow.qll

Lines changed: 6 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ private import semmle.code.java.dataflow.internal.DataFlowUtil
1515
private import semmle.code.java.dataflow.internal.DataFlowPrivate
1616
private import semmle.code.java.dataflow.internal.ContainerFlow
1717
private import semmle.code.java.dataflow.InstanceAccess
18+
private import semmle.code.java.dispatch.Unification
1819

1920
/**
2021
* Gets a viable dispatch target for `ma`. This is the input dispatch relation.
@@ -266,67 +267,10 @@ Method viableImpl_out(MethodAccess ma) {
266267
)
267268
}
268269

269-
private module Unification {
270-
pragma[noinline]
271-
private predicate unificationTargetLeft(ParameterizedType t1, GenericType g) {
272-
objectToStringQualType(_, t1) and t1.getGenericType() = g
273-
}
270+
private predicate unificationTargetLeft(ParameterizedType t1) { objectToStringQualType(_, t1) }
274271

275-
pragma[noinline]
276-
private predicate unificationTargetRight(ParameterizedType t2, GenericType g) {
277-
exists(viableMethodImpl(_, _, t2)) and t2.getGenericType() = g
278-
}
279-
280-
private predicate unificationTargets(Type t1, Type t2) {
281-
exists(GenericType g | unificationTargetLeft(t1, g) and unificationTargetRight(t2, g))
282-
or
283-
exists(Array a1, Array a2 |
284-
unificationTargets(a1, a2) and
285-
t1 = a1.getComponentType() and
286-
t2 = a2.getComponentType()
287-
)
288-
or
289-
exists(ParameterizedType pt1, ParameterizedType pt2, int pos |
290-
unificationTargets(pt1, pt2) and
291-
not pt1.getSourceDeclaration() != pt2.getSourceDeclaration() and
292-
t1 = pt1.getTypeArgument(pos) and
293-
t2 = pt2.getTypeArgument(pos)
294-
)
295-
}
296-
297-
pragma[noinline]
298-
private predicate typeArgsOfUnificationTargets(
299-
ParameterizedType t1, ParameterizedType t2, int pos, RefType arg1, RefType arg2
300-
) {
301-
unificationTargets(t1, t2) and
302-
arg1 = t1.getTypeArgument(pos) and
303-
arg2 = t2.getTypeArgument(pos)
304-
}
305-
306-
pragma[nomagic]
307-
predicate failsUnification(Type t1, Type t2) {
308-
unificationTargets(t1, t2) and
309-
(
310-
exists(RefType arg1, RefType arg2 |
311-
typeArgsOfUnificationTargets(t1, t2, _, arg1, arg2) and
312-
failsUnification(arg1, arg2)
313-
)
314-
or
315-
failsUnification(t1.(Array).getComponentType(), t2.(Array).getComponentType())
316-
or
317-
not (
318-
t1 instanceof Array and t2 instanceof Array
319-
or
320-
t1.(PrimitiveType) = t2.(PrimitiveType)
321-
or
322-
t1.(Class).getSourceDeclaration() = t2.(Class).getSourceDeclaration()
323-
or
324-
t1.(Interface).getSourceDeclaration() = t2.(Interface).getSourceDeclaration()
325-
or
326-
t1 instanceof BoundedType and t2 instanceof RefType
327-
or
328-
t1 instanceof RefType and t2 instanceof BoundedType
329-
)
330-
)
331-
}
272+
private predicate unificationTargetRight(ParameterizedType t2) {
273+
exists(viableMethodImpl(_, _, t2))
332274
}
275+
276+
private module Unification = MkUnification<unificationTargetLeft/1, unificationTargetRight/1>;
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/**
2+
* Provides a module to check whether two `ParameterizedType`s are unifiable.
3+
*/
4+
5+
import java
6+
7+
/** Holds if `t` is a relevant type to consider for unification. */
8+
signature predicate unificationTarget(ParameterizedType t);
9+
10+
/**
11+
* Given two sets of parameterised types to consider for unification, returns
12+
* the set of pairs that are not unifiable.
13+
*/
14+
module MkUnification<unificationTarget/1 targetLeft, unificationTarget/1 targetRight> {
15+
pragma[noinline]
16+
private predicate unificationTargetLeft(ParameterizedType t1, GenericType g) {
17+
targetLeft(t1) and t1.getGenericType() = g
18+
}
19+
20+
pragma[noinline]
21+
private predicate unificationTargetRight(ParameterizedType t2, GenericType g) {
22+
targetRight(t2) and t2.getGenericType() = g
23+
}
24+
25+
private predicate unificationTargets(Type t1, Type t2) {
26+
exists(GenericType g | unificationTargetLeft(t1, g) and unificationTargetRight(t2, g))
27+
or
28+
exists(Array a1, Array a2 |
29+
unificationTargets(a1, a2) and
30+
t1 = a1.getComponentType() and
31+
t2 = a2.getComponentType()
32+
)
33+
or
34+
exists(ParameterizedType pt1, ParameterizedType pt2, int pos |
35+
unificationTargets(pt1, pt2) and
36+
not pt1.getSourceDeclaration() != pt2.getSourceDeclaration() and
37+
t1 = pt1.getTypeArgument(pos) and
38+
t2 = pt2.getTypeArgument(pos)
39+
)
40+
}
41+
42+
pragma[noinline]
43+
private predicate typeArgsOfUnificationTargets(
44+
ParameterizedType t1, ParameterizedType t2, int pos, RefType arg1, RefType arg2
45+
) {
46+
unificationTargets(t1, t2) and
47+
arg1 = t1.getTypeArgument(pos) and
48+
arg2 = t2.getTypeArgument(pos)
49+
}
50+
51+
/**
52+
* Holds if `t1` and `t2` are not unifiable.
53+
*
54+
* Restricted to only consider pairs of types such that `targetLeft(t1)`,
55+
* `targetRight(t2)`, and that both are parameterised instances of the same
56+
* generic type.
57+
*/
58+
pragma[nomagic]
59+
predicate failsUnification(Type t1, Type t2) {
60+
unificationTargets(t1, t2) and
61+
(
62+
exists(RefType arg1, RefType arg2 |
63+
typeArgsOfUnificationTargets(t1, t2, _, arg1, arg2) and
64+
failsUnification(arg1, arg2)
65+
)
66+
or
67+
failsUnification(t1.(Array).getComponentType(), t2.(Array).getComponentType())
68+
or
69+
not (
70+
t1 instanceof Array and t2 instanceof Array
71+
or
72+
t1.(PrimitiveType) = t2.(PrimitiveType)
73+
or
74+
t1.(Class).getSourceDeclaration() = t2.(Class).getSourceDeclaration()
75+
or
76+
t1.(Interface).getSourceDeclaration() = t2.(Interface).getSourceDeclaration()
77+
or
78+
t1 instanceof BoundedType and t2 instanceof RefType
79+
or
80+
t1 instanceof RefType and t2 instanceof BoundedType
81+
)
82+
)
83+
}
84+
}

0 commit comments

Comments
 (0)