Python: remove NonLibraryNormalCall

it is not necessary to distinguish these calls,
so we remove the class from the hierarchy.
This commit is contained in:
Rasmus Lerchedahl Petersen
2022-09-11 22:25:29 +02:00
parent 895f5480c2
commit fa2da2f3ec
3 changed files with 27 additions and 41 deletions

View File

@@ -103,10 +103,10 @@ module ArgumentPassing {
* Used to limit the size of predicates.
*/
predicate connects(CallNode call, CallableValue callable) {
exists(NonLibraryNormalCall c, NonLibraryDataFlowCallable k |
exists(NormalCall c, NonLibraryDataFlowCallable k |
call = c.getNode() and
callable = k.getCallableValue() and
k = c.getNonLibraryCallable()
k = c.getCallable()
)
}
@@ -511,31 +511,20 @@ class NormalCall extends DataFlowSourceCall, TNormalCall {
abstract override Node getArg(int n);
override ControlFlowNode getNode() { result = call }
override CallNode getNode() { result = call }
abstract override DataFlowCallable getCallable();
override DataFlowCallable getEnclosingCallable() { result.getScope() = call.getNode().getScope() }
}
/** A (non-special) call that does not go to a library callable. */
abstract class NonLibraryNormalCall extends NormalCall {
abstract Node getNonLibraryArg(int n);
final override Node getArg(int n) { result = this.getNonLibraryArg(n) }
abstract DataFlowCallable getNonLibraryCallable();
final override DataFlowCallable getCallable() { result = this.getNonLibraryCallable() }
}
/**
* A call to a function.
* This excludes calls to bound methods, classes, and special methods.
* Bound method calls and class calls insert an argument for the explicit
* `self` parameter, and special method calls have special argument passing.
*/
class FunctionCall extends NonLibraryNormalCall {
class FunctionCall extends NormalCall {
NonLibraryDataFlowCallable callable;
FunctionCall() {
@@ -543,15 +532,13 @@ class FunctionCall extends NonLibraryNormalCall {
call = callable.getACall()
}
override Node getNonLibraryArg(int n) {
result = getArg(call, TNoShift(), callable.getCallableValue(), n)
}
override Node getArg(int n) { result = getArg(call, TNoShift(), callable.getCallableValue(), n) }
override DataFlowCallable getNonLibraryCallable() { result = callable }
override DataFlowCallable getCallable() { result = callable }
}
/** A call to a lambda. */
class LambdaCall extends NonLibraryNormalCall {
class LambdaCall extends NormalCall {
NonLibraryDataFlowCallable callable;
LambdaCall() {
@@ -559,33 +546,29 @@ class LambdaCall extends NonLibraryNormalCall {
callable = TLambda(any(Function f))
}
override Node getNonLibraryArg(int n) {
result = getArg(call, TNoShift(), callable.getCallableValue(), n)
}
override Node getArg(int n) { result = getArg(call, TNoShift(), callable.getCallableValue(), n) }
override DataFlowCallable getNonLibraryCallable() { result = callable }
override DataFlowCallable getCallable() { result = callable }
}
/**
* Represents a call to a bound method call.
* The node representing the instance is inserted as argument to the `self` parameter.
*/
class MethodCall extends NonLibraryNormalCall {
class MethodCall extends NormalCall {
FunctionValue bm;
MethodCall() { call = bm.getAMethodCall() }
private CallableValue getCallableValue() { result = bm }
override Node getNonLibraryArg(int n) {
override Node getArg(int n) {
n > 0 and result = getArg(call, TShiftOneUp(), this.getCallableValue(), n)
or
n = 0 and result = TCfgNode(call.getFunction().(AttrNode).getObject())
}
override DataFlowCallable getNonLibraryCallable() {
result = TCallableValue(this.getCallableValue())
}
override DataFlowCallable getCallable() { result = TCallableValue(this.getCallableValue()) }
}
/**
@@ -594,7 +577,7 @@ class MethodCall extends NonLibraryNormalCall {
* That makes the call node be the post-update node holding the value of the object
* after the constructor has run.
*/
class ClassCall extends NonLibraryNormalCall {
class ClassCall extends NormalCall {
ClassValue c;
ClassCall() {
@@ -604,15 +587,13 @@ class ClassCall extends NonLibraryNormalCall {
private CallableValue getCallableValue() { c.getScope().getInitMethod() = result.getScope() }
override Node getNonLibraryArg(int n) {
override Node getArg(int n) {
n > 0 and result = getArg(call, TShiftOneUp(), this.getCallableValue(), n)
or
n = 0 and result = TSyntheticPreUpdateNode(TCfgNode(call))
}
override DataFlowCallable getNonLibraryCallable() {
result = TCallableValue(this.getCallableValue())
}
override DataFlowCallable getCallable() { result = TCallableValue(this.getCallableValue()) }
}
/** A call to a special method. */

View File

@@ -137,15 +137,15 @@ module SyntheticPostUpdateNode {
* and should not have an extra node synthesised.
*/
Node argumentPreUpdateNode() {
result = any(FunctionCall c).getNonLibraryArg(_)
result = any(FunctionCall c).getArg(_)
or
// Avoid argument 0 of method calls as those have read post-update nodes.
exists(MethodCall c, int n | n > 0 | result = c.getNonLibraryArg(n))
exists(MethodCall c, int n | n > 0 | result = c.getArg(n))
or
result = any(SpecialCall c).getArg(_)
or
// Avoid argument 0 of class calls as those have non-synthetic post-update nodes.
exists(ClassCall c, int n | n > 0 | result = c.getNonLibraryArg(n))
exists(ClassCall c, int n | n > 0 | result = c.getArg(n))
or
// any argument of any call that we have not been able to resolve
exists(CallNode call | not resolvedCall(call) |

View File

@@ -11,15 +11,20 @@
* These are identified by strings and has predicates for finding calls to them.
*
* Having both extracted and non-extracted callables means that we now have three types of calls:
* - Extracted calls to extracted callables, either `NonLibraryNormalCall` or `SpecialCall`. These are handled by standard data flow.
* - Extracted calls to non-extracted callables, `LibraryCall`. These are handled by summaries.
* - Extracted calls to extracted callables, either `NormalCall` or `SpecialCall`. These are handled by standard data flow.
* - Extracted calls to non-extracted callables, `LibraryCall`. These are handled by loking up the relevant summary when the
* global data flwo graph is connected up via `getViableCallable`.
* - Non-extracted calls, `SummaryCall`. These are synthesised by the flow summary framework.
*
* The first two can be referred to as `DataFlowSourceCall`. They have been split up for the benefit of call resolutiuon.
* The first two can be referred to as `DataFlowSourceCall`. In fact, `LibraryCall` is a subclass of `NormalCall`, where
* `getCallable` is set to `none()`. The member predicate `DataFlowSourceCall::getCallable` is _not_ the mechanism for
* call resolution in global data flow. That mechanism is `getViableCallable`.
* Resolving a call to a non-extracted callable goes via `LibraryCallable::getACall`, which may involve type tracking.
* To avoid that type tracking becomes mutualy recursive with data flow, type tracking must use a call graph not including summaries.
* Type tracking sees the callgraph given by `DataFlowSourceCall::getACallable`.
*
* We do not support summaries of special methods.
* We do not support summaries of special methods via the special methods framework,
* the summary would have to identify the call.
*/
private import python