Python: use comprehension function argument

For a comprehension `[x for x in l]
- `l` is now a legal argument (in DataFlowPublic)
- `l` is the argument of the comprehension function (in DataFlowDispatch)
- the parameter of the comprehension function is being read rather than `l` (in IterableUnpacking)
Thus the read that used to cross callable boundaries is now split into a arg-param edge and a read from that param.
This commit is contained in:
Rasmus Lerchedahl Petersen
2024-09-27 09:44:39 +02:00
parent fc2dc28f87
commit 294092b671
3 changed files with 8 additions and 2 deletions

View File

@@ -1491,7 +1491,10 @@ class ComprehensionCall extends ExtractedDataFlowCall, TComprehensionCall {
override DataFlowCallable getCallable() { result.(DataFlowFunction).getScope() = target }
override ArgumentNode getArgument(ArgumentPosition apos) { none() }
override ArgumentNode getArgument(ArgumentPosition apos) {
result.asExpr() = c.getIterable() and
apos.isPositional(0)
}
override Location getLocation() { result = c.getLocation() }
}

View File

@@ -350,6 +350,9 @@ class ExtractedArgumentNode extends ArgumentNode {
or
// and self arguments
this.asCfgNode() = any(CallNode c).getFunction().(AttrNode).getObject()
or
// for comprehensions, we allow the synthetic `iterable` argument
this.asExpr() = any(Comp c).getIterable()
}
final override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {

View File

@@ -187,7 +187,7 @@ class ForTarget extends ControlFlowNode {
)
or
exists(Comp comp |
source = comp.getIterable() and
source = comp.getFunction().getArg(0) and
this.getNode() = comp.getNthInnerLoop(0).getTarget()
)
}