diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index b869bdda521..d4af28d4e26 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -1302,9 +1302,7 @@ predicate getCallArg(CallNode call, Function target, CallType type, Node arg, Ar // // call_func(my_obj.some_method) // ``` - exists(CfgNode cfgNode | cfgNode.getNode() = call | - cfgNode.getEnclosingCallable() = arg.getEnclosingCallable() - ) + exists(CfgNode cfgNode | cfgNode.getNode() = call | sameEnclosingCallable(cfgNode, arg)) or // cls argument for classmethod calls -- see note above about bound methods type instanceof CallTypeClassMethod and @@ -1312,9 +1310,7 @@ predicate getCallArg(CallNode call, Function target, CallType type, Node arg, Ar resolveMethodCall(call, target, type, arg) and (arg = classTracker(_) or arg = clsArgumentTracker(_)) and // dataflow lib has requirement that arguments and calls are in same enclosing callable. - exists(CfgNode cfgNode | cfgNode.getNode() = call | - cfgNode.getEnclosingCallable() = arg.getEnclosingCallable() - ) + exists(CfgNode cfgNode | cfgNode.getNode() = call | sameEnclosingCallable(cfgNode, arg)) or // normal arguments for method calls ( @@ -1365,6 +1361,16 @@ predicate getCallArg(CallNode call, Function target, CallType type, Node arg, Ar ) } +/** + * join-order helper for getCallArg, since otherwise we would do cartesian product of + * the enclosing callables + */ +bindingset[node1, node2] +pragma[inline_late] +private predicate sameEnclosingCallable(Node node1, Node node2) { + node1.getEnclosingCallable() = node2.getEnclosingCallable() +} + // ============================================================================= // DataFlowCall // =============================================================================