Python points-to: restore getArgumentForCall() API method.

This commit is contained in:
Mark Shannon
2019-04-15 10:21:26 +01:00
parent 90bbfd3b16
commit 9d40a6cd8c
5 changed files with 53 additions and 11 deletions

View File

@@ -53,6 +53,7 @@ abstract class CallableObjectInternal extends ObjectInternal {
override int length() { none() }
abstract predicate neverReturns();
}
@@ -151,6 +152,11 @@ class PythonFunctionObjectInternal extends CallableObjectInternal, TPythonFuncti
override predicate neverReturns() {
InterProceduralPointsTo::neverReturns(this.getScope())
}
override predicate functionAndOffset(CallableObjectInternal function, int offset) {
function = this and offset = 0
}
}
@@ -262,6 +268,10 @@ class BuiltinFunctionObjectInternal extends CallableObjectInternal, TBuiltinFunc
this = Module::named("sys").attr("exit")
}
override predicate functionAndOffset(CallableObjectInternal function, int offset) {
function = this and offset = 0
}
}
@@ -347,6 +357,10 @@ class BuiltinMethodObjectInternal extends CallableObjectInternal, TBuiltinMethod
override predicate neverReturns() { none() }
override predicate functionAndOffset(CallableObjectInternal function, int offset) {
function = this and offset = 0
}
}
class BoundMethodObjectInternal extends CallableObjectInternal, TBoundMethod {
@@ -422,6 +436,10 @@ class BoundMethodObjectInternal extends CallableObjectInternal, TBoundMethod {
this.getFunction().neverReturns()
}
override predicate functionAndOffset(CallableObjectInternal function, int offset) {
function = this.getFunction() and offset = 1
}
}

View File

@@ -122,6 +122,10 @@ class PythonClassObjectInternal extends ClassObjectInternal, TPythonClassObject
override boolean isComparable() { result = true }
override predicate functionAndOffset(CallableObjectInternal function, int offset) {
this.lookup("__init__", function, _) and offset = 1
}
}
class BuiltinClassObjectInternal extends ClassObjectInternal, TBuiltinClassObject {

View File

@@ -118,17 +118,35 @@ class CallableValue extends Value {
result = this.(CallableObjectInternal).getParameterByName(name)
}
ControlFlowNode getArgumentForCall(CallNode call, NameNode param) {
this.getACall() = call and
(
exists(int n | call.getArg(n) = result and param = this.getParameter(n))
ControlFlowNode getArgumentForCall(CallNode call, int n) {
exists(ObjectInternal called, int offset |
PointsToInternal::pointsTo(call.getFunction(), _, called, _) and
called.functionAndOffset(this, offset)
|
call.getArg(n-offset) = result
or
exists(string name | call.getArgByName(name) = result and param = this.getParameterByName(name))
exists(string name | call.getArgByName(name) = result and this.(PythonFunctionObjectInternal).getScope().getArg(n+offset).getName() = name)
or
called instanceof BoundMethodObjectInternal and
offset = 1 and n = 0 and result = call.getFunction().(AttrNode).getObject()
)
or
exists(BoundMethodObjectInternal bm |
result = getArgumentForCall(call, param) and
this = bm.getFunction()
}
ControlFlowNode getNamedArgumentForCall(CallNode call, string name) {
exists(CallableObjectInternal called, int offset |
PointsToInternal::pointsTo(call.getFunction(), _, called, _) and
called.functionAndOffset(this, offset)
|
exists(int n |
call.getArg(n) = result and
this.(PythonFunctionObjectInternal).getScope().getArg(n+offset).getName() = name
)
or
call.getArgByName(name) = result and
exists(this.(PythonFunctionObjectInternal).getScope().getArgByName(name))
or
called instanceof BoundMethodObjectInternal and
offset = 1 and name = "self" and result = call.getFunction().(AttrNode).getObject()
)
}

View File

@@ -103,6 +103,8 @@ class ObjectInternal extends TObject {
*/
abstract int length();
predicate functionAndOffset(CallableObjectInternal function, int offset) { none() }
}

View File

@@ -71,14 +71,14 @@ abstract class FunctionObject extends Object {
This predicate will correctly handle `x.y()`, treating `x` as the zeroth argument.
*/
ControlFlowNode getArgumentForCall(CallNode call, int n) {
result = theCallable().getArgumentForCall(call, this.getFunction().getArg(n).asName().getAFlowNode())
result = theCallable().getArgumentForCall(call, n)
}
/** Gets the `ControlFlowNode` that will be passed as the named argument to `this` when called at `call`.
This predicate will correctly handle `x.y()`, treating `x` as the self argument.
*/
ControlFlowNode getNamedArgumentForCall(CallNode call, string name) {
result = theCallable().getArgumentForCall(call, this.getFunction().getArgByName(name).asName().getAFlowNode())
result = theCallable().getNamedArgumentForCall(call, name)
}
/** Whether this function never returns. This is an approximation.