Move virtual dispatch resolution from CallExpr to CallNode and generalise it very slightly.

This commit is contained in:
Max Schaefer
2020-02-05 13:49:54 +00:00
parent 253a394ae0
commit cf0e38b22c
2 changed files with 24 additions and 15 deletions

View File

@@ -476,18 +476,8 @@ class CallExpr extends CallOrConversionExpr {
* interface type.
*/
FuncDef getACallee() {
result = getTarget().(DeclaredFunction).getFuncDecl()
or
exists(SelectorExpr sel, InterfaceType declaredRecv, Type actualRecv |
sel = getCalleeExpr().stripParens() and
declaredRecv = sel.getBase().getType().getUnderlyingType() and
actualRecv.implements(declaredRecv)
|
result = actualRecv
.(PointerType)
.getBaseType()
.(NamedType)
.getMethodDecl(sel.getSelector().getName())
exists(DataFlow::CallNode call | call.asExpr() = this |
result = call.getACallee()
)
}

View File

@@ -264,8 +264,27 @@ class CallNode extends ExprNode {
/** Gets the declared target of this call */
Function getTarget() { result = expr.getTarget() }
/** Get the definition of a possible target of this call. See `CallExpr.getACallee`. */
FuncDef getACallee() { result = expr.getACallee() }
/**
* Gets the definition of a possible target of this call.
*
* For non-virtual calls, there is at most one possible call target (but there may be none if the
* target has no declaration).
*
* For virtual calls, we look up possible targets in all types that implement the receiver
* interface type.
*/
FuncDef getACallee() {
result = getTarget().(DeclaredFunction).getFuncDecl()
or
exists(DataFlow::Node calleeSource | calleeSource.getASuccessor*() = getCalleeNode() |
exists(Method m, InterfaceType declaredRecv, Type actualRecv |
calleeSource = m.getARead() and
declaredRecv = m.getReceiverType().(NamedType).getBaseType() and
actualRecv.implements(declaredRecv) and
result = actualRecv.getMethod(m.getName()).(DeclaredFunction).getFuncDecl()
)
)
}
/** Gets the name of the function or method being called, if it can be determined. */
string getCalleeName() { result = expr.getTarget().getName() or result = expr.getCalleeName() }
@@ -328,7 +347,7 @@ class MethodCallNode extends CallNode {
override Method getTarget() { result = expr.getTarget() }
override MethodDecl getACallee() { result = expr.getACallee() }
override MethodDecl getACallee() { result = super.getACallee() }
}
/** A representation of a receiver initialization. */