Skip to content

Commit 052a008

Browse files
committed
Swift: Content-based dataflow through case let
1 parent 5c79563 commit 052a008

File tree

4 files changed

+92
-7
lines changed

4 files changed

+92
-7
lines changed

swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,8 @@ private module Cached {
201201
cached
202202
newtype TContent =
203203
TFieldContent(FieldDecl f) or
204-
TTupleContent(int index) { exists(any(TupleExpr te).getElement(index)) }
204+
TTupleContent(int index) { exists(any(TupleExpr te).getElement(index)) } or
205+
TEnumContent(ParamDecl f) { exists(EnumElementDecl d | d.getAParam() = f) }
205206
}
206207

207208
/**
@@ -558,6 +559,13 @@ predicate storeStep(Node node1, ContentSet c, Node node2) {
558559
c.isSingleton(any(Content::TupleContent tc | tc.getIndex() = tuple.getIndex()))
559560
)
560561
or
562+
// creation of an enum `.variant(v1, v2)`
563+
exists(EnumElementExpr enum, int pos |
564+
node1.asExpr() = enum.getArgument(pos).getExpr() and
565+
node2.asExpr() = enum and
566+
c.isSingleton(any(Content::EnumContent ec | ec.getField() = enum.getElement().getParam(pos)))
567+
)
568+
or
561569
FlowSummaryImpl::Private::Steps::summaryStoreStep(node1, c, node2)
562570
}
563571

@@ -578,6 +586,20 @@ predicate readStep(Node node1, ContentSet c, Node node2) {
578586
node2.asExpr() = tuple and
579587
c.isSingleton(any(Content::TupleContent tc | tc.getIndex() = tuple.getIndex()))
580588
)
589+
or
590+
// read of an enum member via `case let .variant(v1, v2)` pattern matching
591+
exists(Expr enumExpr, ParamDecl enumField, VarDecl boundVar |
592+
node1.asExpr() = enumExpr and
593+
node2.asDefinition().getSourceVariable() = boundVar and
594+
c.isSingleton(any(Content::EnumContent ec | ec.getField() = enumField))
595+
|
596+
exists(EnumElementPattern enumPat, NamedPattern namePat, int idx |
597+
enumPat.getMatchingExpr() = enumExpr and
598+
enumPat.getElement().getParam(idx) = enumField and
599+
namePat.getIdentityPreservingEnclosingPattern*() = enumPat.getSubPattern(idx) and
600+
namePat.getVarDecl() = boundVar
601+
)
602+
)
581603
}
582604

583605
/**

swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPublic.qll

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,20 @@ module Content {
171171

172172
override string toString() { result = "Tuple element at index " + index.toString() }
173173
}
174+
175+
/** A field of an enum element. */
176+
class EnumContent extends Content, TEnumContent {
177+
private ParamDecl f;
178+
179+
EnumContent() { this = TEnumContent(f) }
180+
181+
/** Gets the declaration of the enum field. */
182+
ParamDecl getField() { result = f }
183+
184+
override string toString() {
185+
exists(EnumElementDecl d, int pos | d.getParam(pos) = f | result = d.toString() + ":" + pos)
186+
}
187+
}
174188
}
175189

176190
/**

swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,26 @@ edges
145145
| test.swift:357:15:357:15 | t1 [Tuple element at index 1] : | test.swift:357:15:357:18 | .1 |
146146
| test.swift:360:15:360:15 | t2 [Tuple element at index 0] : | test.swift:360:15:360:18 | .0 |
147147
| test.swift:361:15:361:15 | t2 [Tuple element at index 1] : | test.swift:361:15:361:18 | .1 |
148+
| test.swift:398:9:398:27 | call to ... [mySingle:0] : | test.swift:400:12:400:12 | a [mySingle:0] : |
149+
| test.swift:398:9:398:27 | call to ... [mySingle:0] : | test.swift:412:32:412:32 | a [mySingle:0] : |
150+
| test.swift:398:19:398:26 | call to source() : | test.swift:398:9:398:27 | call to ... [mySingle:0] : |
151+
| test.swift:400:12:400:12 | a [mySingle:0] : | test.swift:403:10:403:25 | SSA def(a) : |
152+
| test.swift:403:10:403:25 | SSA def(a) : | test.swift:404:19:404:19 | a |
153+
| test.swift:412:13:412:28 | SSA def(x) : | test.swift:413:19:413:19 | x |
154+
| test.swift:412:32:412:32 | a [mySingle:0] : | test.swift:412:13:412:28 | SSA def(x) : |
155+
| test.swift:420:9:420:34 | call to ... [myPair:1] : | test.swift:422:12:422:12 | a [myPair:1] : |
156+
| test.swift:420:9:420:34 | call to ... [myPair:1] : | test.swift:437:37:437:37 | a [myPair:1] : |
157+
| test.swift:420:9:420:34 | call to ... [myPair:1] : | test.swift:471:13:471:13 | a [myPair:1] : |
158+
| test.swift:420:26:420:33 | call to source() : | test.swift:420:9:420:34 | call to ... [myPair:1] : |
159+
| test.swift:422:12:422:12 | a [myPair:1] : | test.swift:427:10:427:30 | SSA def(b) : |
160+
| test.swift:427:10:427:30 | SSA def(b) : | test.swift:429:19:429:19 | b |
161+
| test.swift:437:13:437:33 | SSA def(y) : | test.swift:439:19:439:19 | y |
162+
| test.swift:437:37:437:37 | a [myPair:1] : | test.swift:437:13:437:33 | SSA def(y) : |
163+
| test.swift:463:13:463:39 | SSA def(x) : | test.swift:464:19:464:19 | x |
164+
| test.swift:463:43:463:62 | call to ... [myPair:0] : | test.swift:463:13:463:39 | SSA def(x) : |
165+
| test.swift:463:51:463:58 | call to source() : | test.swift:463:43:463:62 | call to ... [myPair:0] : |
166+
| test.swift:471:13:471:13 | a [myPair:1] : | test.swift:472:14:472:55 | SSA def(b) : |
167+
| test.swift:472:14:472:55 | SSA def(b) : | test.swift:474:19:474:19 | b |
148168
| test.swift:486:13:486:28 | call to optionalSource() : | test.swift:489:19:489:19 | a |
149169
| test.swift:509:9:509:9 | self [x] : | file://:0:0:0:0 | self [x] : |
150170
| test.swift:509:9:509:9 | value : | file://:0:0:0:0 | value : |
@@ -334,6 +354,29 @@ nodes
334354
| test.swift:360:15:360:18 | .0 | semmle.label | .0 |
335355
| test.swift:361:15:361:15 | t2 [Tuple element at index 1] : | semmle.label | t2 [Tuple element at index 1] : |
336356
| test.swift:361:15:361:18 | .1 | semmle.label | .1 |
357+
| test.swift:398:9:398:27 | call to ... [mySingle:0] : | semmle.label | call to ... [mySingle:0] : |
358+
| test.swift:398:19:398:26 | call to source() : | semmle.label | call to source() : |
359+
| test.swift:400:12:400:12 | a [mySingle:0] : | semmle.label | a [mySingle:0] : |
360+
| test.swift:403:10:403:25 | SSA def(a) : | semmle.label | SSA def(a) : |
361+
| test.swift:404:19:404:19 | a | semmle.label | a |
362+
| test.swift:412:13:412:28 | SSA def(x) : | semmle.label | SSA def(x) : |
363+
| test.swift:412:32:412:32 | a [mySingle:0] : | semmle.label | a [mySingle:0] : |
364+
| test.swift:413:19:413:19 | x | semmle.label | x |
365+
| test.swift:420:9:420:34 | call to ... [myPair:1] : | semmle.label | call to ... [myPair:1] : |
366+
| test.swift:420:26:420:33 | call to source() : | semmle.label | call to source() : |
367+
| test.swift:422:12:422:12 | a [myPair:1] : | semmle.label | a [myPair:1] : |
368+
| test.swift:427:10:427:30 | SSA def(b) : | semmle.label | SSA def(b) : |
369+
| test.swift:429:19:429:19 | b | semmle.label | b |
370+
| test.swift:437:13:437:33 | SSA def(y) : | semmle.label | SSA def(y) : |
371+
| test.swift:437:37:437:37 | a [myPair:1] : | semmle.label | a [myPair:1] : |
372+
| test.swift:439:19:439:19 | y | semmle.label | y |
373+
| test.swift:463:13:463:39 | SSA def(x) : | semmle.label | SSA def(x) : |
374+
| test.swift:463:43:463:62 | call to ... [myPair:0] : | semmle.label | call to ... [myPair:0] : |
375+
| test.swift:463:51:463:58 | call to source() : | semmle.label | call to source() : |
376+
| test.swift:464:19:464:19 | x | semmle.label | x |
377+
| test.swift:471:13:471:13 | a [myPair:1] : | semmle.label | a [myPair:1] : |
378+
| test.swift:472:14:472:55 | SSA def(b) : | semmle.label | SSA def(b) : |
379+
| test.swift:474:19:474:19 | b | semmle.label | b |
337380
| test.swift:486:13:486:28 | call to optionalSource() : | semmle.label | call to optionalSource() : |
338381
| test.swift:489:19:489:19 | a | semmle.label | a |
339382
| test.swift:509:9:509:9 | self [x] : | semmle.label | self [x] : |
@@ -448,6 +491,12 @@ subpaths
448491
| test.swift:357:15:357:18 | .1 | test.swift:351:31:351:38 | call to source() : | test.swift:357:15:357:18 | .1 | result |
449492
| test.swift:360:15:360:18 | .0 | test.swift:351:18:351:25 | call to source() : | test.swift:360:15:360:18 | .0 | result |
450493
| test.swift:361:15:361:18 | .1 | test.swift:351:31:351:38 | call to source() : | test.swift:361:15:361:18 | .1 | result |
494+
| test.swift:404:19:404:19 | a | test.swift:398:19:398:26 | call to source() : | test.swift:404:19:404:19 | a | result |
495+
| test.swift:413:19:413:19 | x | test.swift:398:19:398:26 | call to source() : | test.swift:413:19:413:19 | x | result |
496+
| test.swift:429:19:429:19 | b | test.swift:420:26:420:33 | call to source() : | test.swift:429:19:429:19 | b | result |
497+
| test.swift:439:19:439:19 | y | test.swift:420:26:420:33 | call to source() : | test.swift:439:19:439:19 | y | result |
498+
| test.swift:464:19:464:19 | x | test.swift:463:51:463:58 | call to source() : | test.swift:464:19:464:19 | x | result |
499+
| test.swift:474:19:474:19 | b | test.swift:420:26:420:33 | call to source() : | test.swift:474:19:474:19 | b | result |
451500
| test.swift:489:19:489:19 | a | test.swift:259:12:259:19 | call to source() : | test.swift:489:19:489:19 | a | result |
452501
| test.swift:520:15:520:15 | z1 | test.swift:259:12:259:19 | call to source() : | test.swift:520:15:520:15 | z1 | result |
453502
| test.swift:526:13:526:21 | call to +(_:) | test.swift:526:14:526:21 | call to source() : | test.swift:526:13:526:21 | call to +(_:) | result |

swift/ql/test/library-tests/dataflow/dataflow/test.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,7 @@ func testEnums() {
401401
case .myNone:
402402
()
403403
case .mySingle(let a):
404-
sink(arg: a) // $ MISSING: flow=398
404+
sink(arg: a) // $ flow=398
405405
case .myPair(let a, let b):
406406
sink(arg: a)
407407
sink(arg: b)
@@ -410,7 +410,7 @@ func testEnums() {
410410
}
411411

412412
if case .mySingle(let x) = a {
413-
sink(arg: x) // $ MISSING: flow=398
413+
sink(arg: x) // $ flow=398
414414
}
415415
if case .myPair(let x, let y) = a {
416416
sink(arg: x)
@@ -426,7 +426,7 @@ func testEnums() {
426426
sink(arg: a)
427427
case .myPair(let a, let b):
428428
sink(arg: a)
429-
sink(arg: b) // $ MISSING: flow=420
429+
sink(arg: b) // $ flow=420
430430
case let .myCons(a, _):
431431
sink(arg: a)
432432
}
@@ -436,7 +436,7 @@ func testEnums() {
436436
}
437437
if case .myPair(let x, let y) = a {
438438
sink(arg: x)
439-
sink(arg: y) // $ MISSING: flow=420
439+
sink(arg: y) // $ flow=420
440440
}
441441

442442
let b: MyEnum = .myCons(42, a)
@@ -461,7 +461,7 @@ func testEnums() {
461461
sink(arg: x)
462462
}
463463
if case MyEnum.myPair(let x, let y) = .myPair(source(), 0) {
464-
sink(arg: x) // $ MISSING: flow=463
464+
sink(arg: x) // $ flow=463
465465
sink(arg: y)
466466
}
467467
if case let .myCons(_, .myPair(_, c)) = b {
@@ -471,7 +471,7 @@ func testEnums() {
471471
switch (a, b) {
472472
case let (.myPair(a, b), .myCons(c, .myPair(d, e))):
473473
sink(arg: a)
474-
sink(arg: b) // $ MISSING: flow=420
474+
sink(arg: b) // $ flow=420
475475
sink(arg: c)
476476
sink(arg: d)
477477
sink(arg: e) // $ MISSING: flow=420

0 commit comments

Comments
 (0)