Java: Autoformat semmle.code.java.dispatch.

This commit is contained in:
Anders Schack-Mulligen
2018-10-11 15:03:51 +02:00
parent 89828b8284
commit 291fb11c48
3 changed files with 146 additions and 91 deletions

View File

@@ -9,12 +9,11 @@ private import semmle.code.java.Maps
/**
* Gets a viable dispatch target for `ma`. This is the input dispatch relation.
*/
private Method viableImpl_inp(MethodAccess ma) {
result = viableImpl_v2(ma)
}
private Method viableImpl_inp(MethodAccess ma) { result = viableImpl_v2(ma) }
private Callable dispatchCand(Call c) {
c instanceof ConstructorCall and result = c.getCallee().getSourceDeclaration() or
c instanceof ConstructorCall and result = c.getCallee().getSourceDeclaration()
or
result = viableImpl_inp(c)
}
@@ -97,18 +96,23 @@ private predicate dispatchOrigin(ClassInstanceExpr cie, MethodAccess ma, Method
/** Holds if `t` is a type that is relevant for dispatch flow. */
private predicate relevant(RefType t) {
exists(ClassInstanceExpr cie | dispatchOrigin(cie, _, _) and t = cie.getConstructedType().getSourceDeclaration()) or
relevant(t.getErasure()) or
exists(RefType r | relevant(r) and t = r.getASourceSupertype()) or
relevant(t.(Array).getComponentType()) or
t instanceof MapType or
exists(ClassInstanceExpr cie |
dispatchOrigin(cie, _, _) and t = cie.getConstructedType().getSourceDeclaration()
)
or
relevant(t.getErasure())
or
exists(RefType r | relevant(r) and t = r.getASourceSupertype())
or
relevant(t.(Array).getComponentType())
or
t instanceof MapType
or
t instanceof CollectionType
}
/** A node with a type that is relevant for dispatch flow. */
private class RelevantNode extends Node {
RelevantNode() { relevant(this.getType()) }
}
private class RelevantNode extends Node { RelevantNode() { relevant(this.getType()) } }
/**
* Holds if `p` is the `i`th parameter of a viable dispatch target of `call`.
@@ -141,7 +145,8 @@ private predicate callFlowStepCand(RelevantNode n1, RelevantNode n2) {
ret.getEnclosingCallable() = m and
ret.getResult() = n1.asExpr() and
m = dispatchCand(n2.asExpr())
) or
)
or
viableArgParamCand(n1, n2)
}
@@ -151,47 +156,66 @@ private predicate callFlowStepCand(RelevantNode n1, RelevantNode n2) {
*/
private predicate flowStep(RelevantNode n1, RelevantNode n2) {
exists(BaseSsaVariable v, BaseSsaVariable def |
def.(BaseSsaUpdate).getDefiningExpr().(VariableAssign).getSource() = n1.asExpr() or
def.(BaseSsaImplicitInit).isParameterDefinition(n1.asParameter()) or
def.(BaseSsaUpdate).getDefiningExpr().(VariableAssign).getSource() = n1.asExpr()
or
def.(BaseSsaImplicitInit).isParameterDefinition(n1.asParameter())
or
exists(EnhancedForStmt for |
for.getVariable() = def.(BaseSsaUpdate).getDefiningExpr() and
for.getExpr() = n1.asExpr() and
n1.getType() instanceof Array
)
|
|
v.getAnUltimateDefinition() = def and
v.getAUse() = n2.asExpr()
) or
exists(Callable c |
n1.(InstanceParameterNode).getCallable() = c
|
exists(InstanceAccess ia | ia = n2.asExpr() and ia.getEnclosingCallable() = c and ia.isOwnInstanceAccess()) or
)
or
exists(Callable c | n1.(InstanceParameterNode).getCallable() = c |
exists(InstanceAccess ia |
ia = n2.asExpr() and ia.getEnclosingCallable() = c and ia.isOwnInstanceAccess()
)
or
n2.(ImplicitInstanceAccess).getInstanceAccess().(OwnInstanceAccess).getEnclosingCallable() = c
) or
)
or
exists(Field f |
f.getAnAssignedValue() = n1.asExpr() and
n2.asExpr().(FieldRead).getField() = f
) or
)
or
exists(EnumType enum, Method getValue |
enum.getAnEnumConstant().getAnAssignedValue() = n1.asExpr() and
getValue.getDeclaringType() = enum and
(getValue.hasName("values") or getValue.hasName("valueOf")) and
n2.asExpr().(MethodAccess).getMethod() = getValue
) or
n2.asExpr().(ParExpr).getExpr() = n1.asExpr() or
n2.asExpr().(CastExpr).getExpr() = n1.asExpr() or
n2.asExpr().(ConditionalExpr).getTrueExpr() = n1.asExpr() or
n2.asExpr().(ConditionalExpr).getFalseExpr() = n1.asExpr() or
n2.asExpr().(AssignExpr).getSource() = n1.asExpr() or
n2.asExpr().(ArrayInit).getAnInit() = n1.asExpr() or
n2.asExpr().(ArrayCreationExpr).getInit() = n1.asExpr() or
n2.asExpr().(ArrayAccess).getArray() = n1.asExpr() or
exists(Argument arg | n1.asExpr() = arg and arg.isVararg() and n2.(ImplicitVarargsArray).getCall() = arg.getCall()) or
)
or
n2.asExpr().(ParExpr).getExpr() = n1.asExpr()
or
n2.asExpr().(CastExpr).getExpr() = n1.asExpr()
or
n2.asExpr().(ConditionalExpr).getTrueExpr() = n1.asExpr()
or
n2.asExpr().(ConditionalExpr).getFalseExpr() = n1.asExpr()
or
n2.asExpr().(AssignExpr).getSource() = n1.asExpr()
or
n2.asExpr().(ArrayInit).getAnInit() = n1.asExpr()
or
n2.asExpr().(ArrayCreationExpr).getInit() = n1.asExpr()
or
n2.asExpr().(ArrayAccess).getArray() = n1.asExpr()
or
exists(Argument arg |
n1.asExpr() = arg and arg.isVararg() and n2.(ImplicitVarargsArray).getCall() = arg.getCall()
)
or
exists(AssignExpr a, Variable v |
a.getSource() = n1.asExpr() and
a.getDest().(ArrayAccess).getArray() = v.getAnAccess() and
n2.asExpr() = v.getAnAccess().(RValue)
) or
)
or
exists(Variable v, MethodAccess put, MethodAccess get |
put.getArgument(1) = n1.asExpr() and
put.getMethod().(MapMethod).hasName("put") and
@@ -199,17 +223,19 @@ private predicate flowStep(RelevantNode n1, RelevantNode n2) {
get.getQualifier() = v.getAnAccess() and
get.getMethod().(MapMethod).hasName("get") and
n2.asExpr() = get
) or
)
or
exists(Variable v, MethodAccess add |
add.getAnArgument() = n1.asExpr() and
add.getMethod().(CollectionMethod).hasName("add") and
add.getQualifier() = v.getAnAccess()
|
|
exists(MethodAccess get |
get.getQualifier() = v.getAnAccess() and
get.getMethod().(CollectionMethod).hasName("get") and
n2.asExpr() = get
) or
)
or
exists(EnhancedForStmt for, BaseSsaVariable ssa, BaseSsaVariable def |
for.getVariable() = def.(BaseSsaUpdate).getDefiningExpr() and
for.getExpr() = v.getAnAccess() and
@@ -223,7 +249,8 @@ private predicate flowStep(RelevantNode n1, RelevantNode n2) {
* Holds if `n` is forward-reachable from a relevant `ClassInstanceExpr`.
*/
private predicate nodeCandFwd(Node n) {
dispatchOrigin(n.asExpr(), _, _) or
dispatchOrigin(n.asExpr(), _, _)
or
exists(Node mid | nodeCandFwd(mid) | flowStep(mid, n) or callFlowStepCand(mid, n))
}
@@ -236,7 +263,8 @@ private predicate nodeCand(Node n) {
dispatchOrigin(_, ma, _) and
n = getInstanceArgument(ma) and
nodeCandFwd(n)
) or
)
or
exists(Node mid | nodeCand(mid) | flowStep(n, mid) or callFlowStepCand(n, mid)) and
nodeCandFwd(n)
}

View File

@@ -24,12 +24,11 @@ Callable exactCallable(Call c) {
c instanceof ConstructorCall and result = c.getCallee()
}
private predicate implCount(MethodAccess m, int c) {
strictcount(viableImpl(m)) = c
}
private predicate implCount(MethodAccess m, int c) { strictcount(viableImpl(m)) = c }
Callable viableCallable(Call c) {
result = viableImpl(c) or
result = viableImpl(c)
or
c instanceof ConstructorCall and result = c.getCallee().getSourceDeclaration()
}
@@ -38,11 +37,11 @@ class CalledMethod extends Method {
CalledMethod() { exists(MethodAccess ma | ma.getMethod() = this) }
}
cached private module Dispatch {
cached
private module Dispatch {
/** Gets a viable implementation of the method called in the given method access. */
cached Method viableImpl(MethodAccess ma) {
result = DispatchFlow::viableImpl_out(ma)
}
cached
Method viableImpl(MethodAccess ma) { result = DispatchFlow::viableImpl_out(ma) }
private predicate qualType(VirtualMethodAccess ma, RefType t, boolean exact) {
exprTypeFlow(ma.getQualifier(), t, exact)
@@ -53,13 +52,14 @@ cached private module Dispatch {
*
* Gets a viable implementation of the method called in the given method access.
*/
cached Method viableImpl_v2(MethodAccess ma) {
cached
Method viableImpl_v2(MethodAccess ma) {
result = viableImpl_v1(ma) and
(
exists(Method def, RefType t, boolean exact |
qualType(ma, t, exact) and
def = ma.getMethod()
|
|
exact = true and result = exactMethodImpl(def, t.getSourceDeclaration())
or
exact = false and
@@ -67,7 +67,8 @@ cached private module Dispatch {
result = viableMethodImpl(def, t.getSourceDeclaration(), t2) and
not Unification_v2::failsUnification(t, t2)
)
) or
)
or
not qualType(ma, _, _)
)
}
@@ -84,12 +85,14 @@ cached private module Dispatch {
}
private predicate unificationTargets(Type t1, Type t2) {
exists(GenericType g | unificationTargetLeft(t1, g) and unificationTargetRight(t2, g)) or
exists(GenericType g | unificationTargetLeft(t1, g) and unificationTargetRight(t2, g))
or
exists(Array a1, Array a2 |
unificationTargets(a1, a2) and
t1 = a1.getComponentType() and
t2 = a2.getComponentType()
) or
)
or
exists(ParameterizedType pt1, ParameterizedType pt2, int pos |
unificationTargets(pt1, pt2) and
not pt1.getSourceDeclaration() != pt2.getSourceDeclaration() and
@@ -99,7 +102,9 @@ cached private module Dispatch {
}
pragma[noinline]
private predicate typeArgsOfUnificationTargets(ParameterizedType t1, ParameterizedType t2, int pos, RefType arg1, RefType arg2) {
private predicate typeArgsOfUnificationTargets(
ParameterizedType t1, ParameterizedType t2, int pos, RefType arg1, RefType arg2
) {
unificationTargets(t1, t2) and
arg1 = t1.getTypeArgument(pos) and
arg2 = t2.getTypeArgument(pos)
@@ -111,14 +116,21 @@ cached private module Dispatch {
exists(RefType arg1, RefType arg2 |
typeArgsOfUnificationTargets(t1, t2, _, arg1, arg2) and
failsUnification(arg1, arg2)
) or
failsUnification(t1.(Array).getComponentType(), t2.(Array).getComponentType()) or
)
or
failsUnification(t1.(Array).getComponentType(), t2.(Array).getComponentType())
or
not (
t1 instanceof Array and t2 instanceof Array or
t1.(PrimitiveType) = t2.(PrimitiveType) or
t1.(Class).getSourceDeclaration() = t2.(Class).getSourceDeclaration() or
t1.(Interface).getSourceDeclaration() = t2.(Interface).getSourceDeclaration() or
t1 instanceof BoundedType and t2 instanceof RefType or
t1 instanceof Array and t2 instanceof Array
or
t1.(PrimitiveType) = t2.(PrimitiveType)
or
t1.(Class).getSourceDeclaration() = t2.(Class).getSourceDeclaration()
or
t1.(Interface).getSourceDeclaration() = t2.(Interface).getSourceDeclaration()
or
t1 instanceof BoundedType and t2 instanceof RefType
or
t1 instanceof RefType and t2 instanceof BoundedType
)
)
@@ -156,11 +168,12 @@ cached private module Dispatch {
*/
private Method viableImpl_v1_cand(MethodAccess source) {
not result.isAbstract() and
if source instanceof VirtualMethodAccess then
if source instanceof VirtualMethodAccess
then
exists(CalledMethod def, RefType t, boolean exact |
source.getMethod() = def and
hasQualifierType(source, t, exact)
|
|
exact = true and result = exactMethodImpl(def, t.getSourceDeclaration())
or
exact = false and
@@ -169,8 +182,7 @@ cached private module Dispatch {
not Unification_v1::failsUnification(t, t2)
)
)
else
result = source.getMethod().getSourceDeclaration()
else result = source.getMethod().getSourceDeclaration()
}
private module Unification_v1 {
@@ -185,12 +197,14 @@ cached private module Dispatch {
}
private predicate unificationTargets(Type t1, Type t2) {
exists(GenericType g | unificationTargetLeft(t1, g) and unificationTargetRight(t2, g)) or
exists(GenericType g | unificationTargetLeft(t1, g) and unificationTargetRight(t2, g))
or
exists(Array a1, Array a2 |
unificationTargets(a1, a2) and
t1 = a1.getComponentType() and
t2 = a2.getComponentType()
) or
)
or
exists(ParameterizedType pt1, ParameterizedType pt2, int pos |
unificationTargets(pt1, pt2) and
not pt1.getSourceDeclaration() != pt2.getSourceDeclaration() and
@@ -200,7 +214,9 @@ cached private module Dispatch {
}
pragma[noinline]
private predicate typeArgsOfUnificationTargets(ParameterizedType t1, ParameterizedType t2, int pos, RefType arg1, RefType arg2) {
private predicate typeArgsOfUnificationTargets(
ParameterizedType t1, ParameterizedType t2, int pos, RefType arg1, RefType arg2
) {
unificationTargets(t1, t2) and
arg1 = t1.getTypeArgument(pos) and
arg2 = t2.getTypeArgument(pos)
@@ -212,14 +228,21 @@ cached private module Dispatch {
exists(RefType arg1, RefType arg2 |
typeArgsOfUnificationTargets(t1, t2, _, arg1, arg2) and
failsUnification(arg1, arg2)
) or
failsUnification(t1.(Array).getComponentType(), t2.(Array).getComponentType()) or
)
or
failsUnification(t1.(Array).getComponentType(), t2.(Array).getComponentType())
or
not (
t1 instanceof Array and t2 instanceof Array or
t1.(PrimitiveType) = t2.(PrimitiveType) or
t1.(Class).getSourceDeclaration() = t2.(Class).getSourceDeclaration() or
t1.(Interface).getSourceDeclaration() = t2.(Interface).getSourceDeclaration() or
t1 instanceof BoundedType and t2 instanceof RefType or
t1 instanceof Array and t2 instanceof Array
or
t1.(PrimitiveType) = t2.(PrimitiveType)
or
t1.(Class).getSourceDeclaration() = t2.(Class).getSourceDeclaration()
or
t1.(Interface).getSourceDeclaration() = t2.(Interface).getSourceDeclaration()
or
t1 instanceof BoundedType and t2 instanceof RefType
or
t1 instanceof RefType and t2 instanceof BoundedType
)
)
@@ -227,7 +250,8 @@ cached private module Dispatch {
}
private RefType getPreciseType(Expr e) {
result = e.(FunctionalExpr).getConstructedType() or
result = e.(FunctionalExpr).getConstructedType()
or
not e instanceof FunctionalExpr and result = e.getType()
}
@@ -237,20 +261,25 @@ cached private module Dispatch {
// and take the type of the assigned value.
exists(RefType srctype | srctype = getPreciseType(src) |
exists(BoundedType bd | bd = srctype |
t = bd.getAnUltimateUpperBoundType() or
t = bd.getAnUltimateUpperBoundType()
or
not exists(bd.getAnUltimateUpperBoundType()) and t = ma.getMethod().getDeclaringType()
) or
)
or
t = srctype and not srctype instanceof BoundedType
) and
// If we have a class instance expression, then we know the exact type.
// This is an important improvement in precision.
if src instanceof ClassInstanceExpr then exact = true else exact = false
) or
)
or
// If the call has no qualifier then it's an implicit `this` qualifier,
// so start from the caller's declaring type or enclosing type.
not exists(ma.getQualifier()) and exact = false and
not exists(ma.getQualifier()) and
exact = false and
(
ma.isOwnMethodAccess() and t = ma.getEnclosingCallable().getDeclaringType() or
ma.isOwnMethodAccess() and t = ma.getEnclosingCallable().getDeclaringType()
or
ma.isEnclosingMethodAccess(t)
)
}
@@ -274,9 +303,7 @@ cached private module Dispatch {
pragma[noinline]
private predicate hasSrcMethod(SrcRefType t, Method impl) {
exists(Method m |
t.hasMethod(m, _, _) and impl = m.getSourceDeclaration()
)
exists(Method m | t.hasMethod(m, _, _) and impl = m.getSourceDeclaration())
}
private predicate hasViableSubtype(RefType t, SrcRefType sub) {
@@ -284,7 +311,6 @@ cached private module Dispatch {
not sub instanceof Interface and
not sub.isAbstract()
}
}
import Dispatch
@@ -294,7 +320,7 @@ private Expr variableTrackStep(Expr use) {
use.getType() instanceof RefType and
not result instanceof NullLiteral and
not v.(LocalVariableDecl).getDeclExpr().hasImplicitInit()
|
|
not v instanceof Parameter and
result = v.getAnAssignedValue()
or
@@ -314,6 +340,7 @@ private Expr variableTrackPath(Expr use) {
* Gets an expression by tracking `use` backwards through variable assignments.
*/
Expr variableTrack(Expr use) {
result = variableTrackPath(use) or
result = variableTrackPath(use)
or
not exists(variableTrackPath(use)) and result = use
}

View File

@@ -29,9 +29,7 @@ class FunctionalInterface extends Interface {
}
/** Gets the single method of this interface. */
Method getRunMethod() {
getAPotentialRunMethod(this).getSourceDeclaration() = result
}
Method getRunMethod() { getAPotentialRunMethod(this).getSourceDeclaration() = result }
}
/**
@@ -41,7 +39,8 @@ class FunctionalInterface extends Interface {
private predicate runner(Method m, int n, Method runmethod) {
m.getParameterType(n).(RefType).getSourceDeclaration().(FunctionalInterface).getRunMethod() = runmethod and
(
m.isNative() or
m.isNative()
or
exists(Parameter p, MethodAccess ma, int j |
p = m.getParameter(n) and
ma.getEnclosingCallable() = m and
@@ -63,7 +62,8 @@ private Expr getRunnerArgument(MethodAccess ma, Method runmethod) {
result = ma.getArgument(param)
)
or
getRunnerArgument(ma, runmethod).(CastExpr).getExpr() = result or
getRunnerArgument(ma, runmethod).(CastExpr).getExpr() = result
or
getRunnerArgument(ma, runmethod).(VarAccess).getVariable().getAnAssignedValue() = result
}