Skip to content

Commit e91581e

Browse files
committed
Python: Experiments with nested comprhensions
1 parent e1343c7 commit e91581e

File tree

3 files changed

+213
-60
lines changed

3 files changed

+213
-60
lines changed

python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -435,16 +435,26 @@ predicate comprehensionReadStep(CfgNode nodeFrom, Content c, EssaNode nodeTo) {
435435
// nodeFrom is `l`, cfg node
436436
// nodeTo is `x`, essa var
437437
// c denotes element of list or set
438-
exists(For f, Comp comp |
439-
f = getCompFor(comp) and
440-
nodeFrom.getNode().getNode() = getCompIter(comp) and
441-
nodeTo.getVar().getDefinition().(AssignmentDefinition).getDefiningNode().getNode() =
442-
f.getTarget() and
443-
(
444-
c instanceof ListElementContent
445-
or
446-
c instanceof SetElementContent
438+
exists(Comp comp |
439+
// outermost for
440+
exists(For f |
441+
f = getCompFor(comp) and
442+
nodeFrom.getNode().getNode() = getCompIter(comp) and
443+
nodeTo.getVar().getDefinition().(AssignmentDefinition).getDefiningNode().getNode() =
444+
f.getTarget()
445+
)
446+
or
447+
// an inner for
448+
exists(int n |
449+
nodeFrom.getNode().getNode() = comp.getNthInnerLoop(n + 1).getIter() and
450+
nodeTo.getVar().getDefinition().(AssignmentDefinition).getDefiningNode().getNode() =
451+
comp.getNthInnerLoop(n).getTarget()
447452
)
453+
) and
454+
(
455+
c instanceof ListElementContent
456+
or
457+
c instanceof SetElementContent
448458
)
449459
}
450460

python/ql/src/semmle/python/Comprehensions.qll

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,15 @@ import python
44
abstract class Comp extends Expr {
55
abstract Function getFunction();
66

7+
/** Gets the iterable of this set comprehension. */
8+
abstract Expr getIterable();
9+
710
/** Gets the iteration variable for the nth innermost generator of this list comprehension */
811
Variable getIterationVariable(int n) {
912
result.getAnAccess() = this.getNthInnerLoop(n).getTarget()
1013
}
1114

12-
private For getNthInnerLoop(int n) {
15+
For getNthInnerLoop(int n) {
1316
n = 0 and result = this.getFunction().getStmt(0)
1417
or
1518
result = this.getNthInnerLoop(n - 1).getStmt(0)
@@ -62,6 +65,8 @@ class ListComp extends ListComp_, Comp {
6265

6366
override Function getFunction() { result = ListComp_.super.getFunction() }
6467

68+
override Expr getIterable() { result = ListComp_.super.getIterable() }
69+
6570
override string toString() { result = ListComp_.super.toString() }
6671

6772
override Expr getElt() { result = Comp.super.getElt() }
@@ -79,6 +84,8 @@ class SetComp extends SetComp_, Comp {
7984
override predicate hasSideEffects() { any() }
8085

8186
override Function getFunction() { result = SetComp_.super.getFunction() }
87+
88+
override Expr getIterable() { result = SetComp_.super.getIterable() }
8289
}
8390

8491
/** A dictionary comprehension, such as `{ k:v for k, v in enumerate("0123456789") }` */
@@ -93,6 +100,8 @@ class DictComp extends DictComp_, Comp {
93100
override predicate hasSideEffects() { any() }
94101

95102
override Function getFunction() { result = DictComp_.super.getFunction() }
103+
104+
override Expr getIterable() { result = DictComp_.super.getIterable() }
96105
}
97106

98107
/** A generator expression, such as `(var for var in iterable)` */
@@ -107,4 +116,6 @@ class GeneratorExp extends GeneratorExp_, Comp {
107116
override predicate hasSideEffects() { any() }
108117

109118
override Function getFunction() { result = GeneratorExp_.super.getFunction() }
119+
120+
override Expr getIterable() { result = GeneratorExp_.super.getIterable() }
110121
}

0 commit comments

Comments
 (0)