Skip to content

Commit 27437db

Browse files
committed
Cfg: Rework test.
1 parent c1c7f92 commit 27437db

3 files changed

Lines changed: 81 additions & 55 deletions

File tree

shared/controlflow/codeql/controlflow/test/TestCfg.qll

Lines changed: 79 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -85,21 +85,59 @@ module Make<LocationSig Location, CfgSig<Location> Cfg, InputSig<Cfg::AstNode, C
8585
{
8686
private import Cfg
8787

88-
/** Holds if `n` from `bb` starts at the given line. */
89-
private predicate node(int line, ControlFlowNode n, BasicBlock bb) {
90-
n.injects(_) and
91-
n.getLocation().getStartLine() = line and
92-
n.getBasicBlock() = bb
88+
/**
89+
* Gets the rank of `n` within `bb` restricted to nodes that are canonical
90+
* representatives of AST nodes.
91+
*/
92+
private int bbRank(ControlFlowNode n, BasicBlock bb) {
93+
n =
94+
rank[result](ControlFlowNode n0, int i | n0.injects(_) and bb.getNode(i) = n0 | n0 order by i)
9395
}
9496

95-
/** Gets the rank of `n` within the slice of `bb` at the given line. */
96-
private int sliceRank(int line, ControlFlowNode n, BasicBlock bb) {
97-
n =
98-
rank[result](ControlFlowNode n0, int i |
99-
node(line, n0, bb) and n0 = bb.getNode(i)
100-
|
101-
n0 order by i
102-
)
97+
/** Gets the start line of `n`. */
98+
private int getLine(ControlFlowNode n) { n.getLocation().getStartLine() = result }
99+
100+
/** Holds if `n` is the first node of a slice of `bb` at the given line. */
101+
private predicate sliceStart(int line, ControlFlowNode n, BasicBlock bb) {
102+
line = getLine(n) and
103+
1 = bbRank(n, bb)
104+
or
105+
exists(ControlFlowNode n0 |
106+
line = getLine(n) and
107+
bbRank(n0, bb) + 1 = bbRank(n, bb) and
108+
getLine(n0) != line
109+
)
110+
}
111+
112+
private newtype TSlice =
113+
TMkSlice(int line, ControlFlowNode n, BasicBlock bb) { sliceStart(line, n, bb) }
114+
115+
/** A slice of a basic block at a specific line. */
116+
private class Slice extends TSlice {
117+
private int line;
118+
private ControlFlowNode start;
119+
private BasicBlock bb;
120+
121+
Slice() { this = TMkSlice(line, start, bb) }
122+
123+
string toString() { result = start.toString() }
124+
125+
int getLine() { result = line }
126+
127+
ControlFlowNode getNode(int i) {
128+
i = 0 and result = start
129+
or
130+
bbRank(this.getNode(i - 1), bb) + 1 = bbRank(result, bb) and
131+
not sliceStart(_, result, bb)
132+
}
133+
134+
ControlFlowNode getLast() {
135+
exists(int i | result = this.getNode(i) and not exists(this.getNode(i + 1)))
136+
}
137+
138+
predicate step(ControlFlowNode n1, ControlFlowNode n2) {
139+
exists(int i | n1 = this.getNode(i) and n2 = this.getNode(i + 1))
140+
}
103141
}
104142

105143
/**
@@ -125,10 +163,10 @@ module Make<LocationSig Location, CfgSig<Location> Cfg, InputSig<Cfg::AstNode, C
125163
* the other. The direction in the AST is given by `dir`.
126164
*/
127165
private predicate astUpDownStep(ControlFlowNode n1, ControlFlowNode n2, Dir dir) {
128-
exists(int line, BasicBlock bb, AstNode a1, AstNode a2 |
166+
exists(AstNode a1, AstNode a2 |
129167
n1.injects(a1) and
130168
n2.injects(a2) and
131-
sliceRank(line, n1, bb) + 1 = sliceRank(line, n2, bb)
169+
any(Slice s).step(n1, n2)
132170
|
133171
if Input::getParent+(a1) = a2
134172
then dir = Up()
@@ -151,14 +189,12 @@ module Make<LocationSig Location, CfgSig<Location> Cfg, InputSig<Cfg::AstNode, C
151189
private predicate oneline(Location l) { l.getStartLine() = l.getEndLine() }
152190

153191
/**
154-
* Holds if `n1` steps to `n2` within a basic block line slice of `bb` at
155-
* `line` and that the step in locations is given by `dir`. Some identical
156-
* locations may be further resolved by peeking at the AST structure.
192+
* Holds if `n1` steps to `n2` within a basic block line slice `slice` and
193+
* that the step in locations is given by `dir`. Some identical locations may
194+
* be further resolved by peeking at the AST structure.
157195
*/
158-
private predicate singleLineBlockStep(
159-
BasicBlock bb, int line, ControlFlowNode n1, ControlFlowNode n2, Dir dir
160-
) {
161-
sliceRank(line, n1, bb) + 1 = sliceRank(line, n2, bb) and
196+
private predicate singleLineBlockStep(Slice slice, ControlFlowNode n1, ControlFlowNode n2, Dir dir) {
197+
slice.step(n1, n2) and
162198
exists(Location l1, Location l2 | n1.getLocation() = l1 and n2.getLocation() = l2 |
163199
if oneline(l1) and l1.getEndColumn() < l2.getStartColumn()
164200
then dir = Right()
@@ -186,28 +222,26 @@ module Make<LocationSig Location, CfgSig<Location> Cfg, InputSig<Cfg::AstNode, C
186222
}
187223

188224
/**
189-
* Holds if the `line` slice of the basic block `bb` is simple left-to-right
190-
* evaluation order.
225+
* Holds if the slice `slice` is simple left-to-right evaluation order.
191226
*
192227
* Both pre-order and post-order traversal is allowed and allowed to be
193228
* mixed. `Up` indicates the last part of a post-order traversal, and `Down`
194229
* indicates the first part of a pre-order traversal, so an `Up` step
195230
* followed by a `Down` step is inconsistent with simple left-to-right
196231
* evaluation order.
197232
*/
198-
private predicate simpleLeftToRightBlock(int line, BasicBlock bb) {
199-
node(line, _, bb) and
200-
forall(ControlFlowNode n1, ControlFlowNode n2 | singleLineBlockStep(bb, line, n1, n2, _) |
201-
exists(Dir dir | singleLineBlockStep(bb, line, n1, n2, dir) |
233+
private predicate simpleLeftToRightBlock(Slice slice) {
234+
forall(ControlFlowNode n1, ControlFlowNode n2 | singleLineBlockStep(slice, n1, n2, _) |
235+
exists(Dir dir | singleLineBlockStep(slice, n1, n2, dir) |
202236
dir != Other() and
203237
dir != Id() and
204-
(dir = Up() implies not singleLineBlockStep(bb, line, n2, _, Down()))
238+
(dir = Up() implies not singleLineBlockStep(slice, n2, _, Down()))
205239
)
206240
)
207241
}
208242

209243
private string outgoingArrow(ControlFlowNode n) {
210-
exists(Dir dir | singleLineBlockStep(_, _, n, _, dir) |
244+
exists(Dir dir | singleLineBlockStep(_, n, _, dir) |
211245
dir = Down() and result = " -V "
212246
or
213247
dir = Up() and result = " -^ "
@@ -222,23 +256,24 @@ module Make<LocationSig Location, CfgSig<Location> Cfg, InputSig<Cfg::AstNode, C
222256

223257
module BlockSlices {
224258
/**
225-
* Holds if `blockSlice` is a string representation of the `line` slice of a
259+
* Holds if `blockSlice` is a string representation of a `line` slice of a
226260
* basic block. `first` is the first node in the slice.
227261
*/
228262
query predicate blockSlice(int line, ControlFlowNode first, string blockSlice) {
229-
exists(BasicBlock bb |
230-
1 = sliceRank(line, first, bb) and
263+
exists(Slice slice |
264+
first = slice.getNode(0) and
265+
line = slice.getLine() and
231266
blockSlice =
232267
"'" +
233-
strictconcat(ControlFlowNode n, int r, int i, string s |
234-
r = sliceRank(line, n, bb) and
268+
strictconcat(ControlFlowNode n, int i, int j, string s |
269+
slice.getNode(i) = n and
235270
(
236-
i = 0 and s = n.toString()
271+
j = 0 and s = n.toString()
237272
or
238-
i = 1 and s = outgoingArrow(n)
273+
j = 1 and s = outgoingArrow(n)
239274
)
240275
|
241-
s order by r, i
276+
s order by i, j
242277
) + "'"
243278
)
244279
}
@@ -262,22 +297,13 @@ module Make<LocationSig Location, CfgSig<Location> Cfg, InputSig<Cfg::AstNode, C
262297
* `first` is the first node in the slice.
263298
*/
264299
query predicate nonSimple(ControlFlowNode1line first, string blockSlice) {
265-
exists(int line, BasicBlock bb |
266-
BlockSlices::blockSlice(line, first, blockSlice) and
267-
bb = first.getBasicBlock() and
268-
not simpleLeftToRightBlock(line, bb)
300+
exists(Slice slice |
301+
BlockSlices::blockSlice(_, first, blockSlice) and
302+
slice.getNode(0) = first and
303+
not simpleLeftToRightBlock(slice)
269304
)
270305
}
271306

272-
/**
273-
* Gets the rank of `n` within `bb` restricted to nodes that are canonical
274-
* representatives of AST nodes.
275-
*/
276-
private int bbRank(ControlFlowNode n, BasicBlock bb) {
277-
n =
278-
rank[result](ControlFlowNode n0, int i | n0.injects(_) and bb.getNode(i) = n0 | n0 order by i)
279-
}
280-
281307
/**
282308
* Holds if some AST node on `line` has a corresponding CFG node within the
283309
* callable `c`.
@@ -303,9 +329,8 @@ module Make<LocationSig Location, CfgSig<Location> Cfg, InputSig<Cfg::AstNode, C
303329
int line, ControlFlowNode n1, ControlFlowNode n2, int lineDelta
304330
) {
305331
line = n1.getLocation().getStartLine() and
306-
exists(int last, BasicBlock bb |
307-
last = sliceRank(line, n1, bb) and
308-
not last + 1 = sliceRank(line, _, bb) and
332+
exists(BasicBlock bb |
333+
n1 = any(Slice slice).getLast() and
309334
bbRank(n1, bb) + 1 = bbRank(n2, bb)
310335
) and
311336
lineDelta = n2.getLocation().getStartLine() - n1.getLocation().getStartLine() and

unified/ql/test/library-tests/controlflow/cfg.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
bbContinues
2+
| cfg.swift:62:6:62:6 | y | 'y goto Block(-1)' |
23
| cfg.swift:147:5:147:5 | Block | 'Block goto true(+3)' |
34
| cfg.swift:525:78:525:78 | Block | 'Block goto Task(+2)' |
45
| cfg.swift:526:9:526:20 | continuation | 'continuation goto Block(-1)' |

unified/ql/test/library-tests/controlflow/cfg.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ func createClosure2(x : Int) -> (_ : Int) -> Int { // $ noCfg
5959

6060
func createClosure3(x : Int) -> (_ : Int) -> Int { // $ noCfg
6161
return {
62-
(y) -> Int in x + y
62+
(y) -> Int in x + y // $ bbContinues='y goto Block(-1)'
6363
}
6464
}
6565

0 commit comments

Comments
 (0)