Skip to content

Commit 3028b80

Browse files
committed
Swift: Control-flow through interpolated strings.
1 parent 34de400 commit 3028b80

File tree

2 files changed

+256
-6
lines changed

2 files changed

+256
-6
lines changed

swift/ql/lib/codeql/swift/controlflow/internal/ControlFlowGraphImpl.qll

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,21 +96,31 @@ module Stmts {
9696

9797
override predicate propagatesAbnormal(ControlFlowElement node) { none() }
9898

99+
private predicate isBodyOfTapExpr() { any(TapExpr tap).getBody() = ast }
100+
101+
// Note: If the brace statement is the body of a `TapExpr`, the first element is the variable
102+
// declaration (see https://github.com/apple/swift/blob/main/include/swift/AST/Expr.h#L848)
103+
// that's initialized by the `Tapxpr`. In `TapExprTre` we've already visited this declaration,
104+
// along with its initializer. So we skip the first element here.
105+
private AstNode getFirstElement() {
106+
if this.isBodyOfTapExpr() then result = ast.getElement(1) else result = ast.getFirstElement()
107+
}
108+
99109
override predicate first(ControlFlowElement first) {
100110
this.firstInner(first)
101111
or
102-
not exists(ast.getFirstElement()) and first.asAstNode() = ast
112+
not exists(this.getFirstElement()) and first.asAstNode() = ast
103113
}
104114

105115
override predicate last(ControlFlowElement last, Completion c) {
106116
this.lastInner(last, c)
107117
or
108-
not exists(ast.getFirstElement()) and
118+
not exists(this.getFirstElement()) and
109119
last.asAstNode() = ast and
110120
c instanceof SimpleCompletion
111121
}
112122

113-
predicate firstInner(ControlFlowElement first) { astFirst(ast.getFirstElement(), first) }
123+
predicate firstInner(ControlFlowElement first) { astFirst(this.getFirstElement(), first) }
114124

115125
/** Gets the body of the i'th `defer` statement. */
116126
private BraceStmt getDeferStmtBody(int i) {
@@ -1334,10 +1344,34 @@ module Exprs {
13341344
override InterpolatedStringLiteralExpr ast;
13351345

13361346
final override ControlFlowElement getChildElement(int i) {
1337-
none() // TODO
1347+
i = 0 and
1348+
result.asAstNode() = ast.getAppendingExpr().getFullyConverted()
1349+
}
1350+
}
1351+
1352+
private class TapExprTree extends AstStandardPostOrderTree {
1353+
override TapExpr ast;
1354+
1355+
final override ControlFlowElement getChildElement(int i) {
1356+
i = 0 and
1357+
result.asAstNode() = ast.getVar()
1358+
or
1359+
i = 1 and
1360+
result.asAstNode() = ast.getSubExpr().getFullyConverted()
1361+
or
1362+
// Note: The CFG for the body will skip the first element in the
1363+
// body because it's guarenteed to be the variable declaration
1364+
// that we've already visited at i = 0. See the explanation
1365+
// in `BraceStmtTree` for why this is necessary.
1366+
i = 2 and
1367+
result.asAstNode() = ast.getBody()
13381368
}
13391369
}
13401370

1371+
private class OpaqueValueExprTree extends AstLeafTree {
1372+
override OpaqueValueExpr ast;
1373+
}
1374+
13411375
module DeclRefExprs {
13421376
class DeclRefExprLValueTree extends AstLeafTree {
13431377
override DeclRefExpr ast;

swift/ql/test/library-tests/controlflow/graph/Cfg.expected

Lines changed: 218 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,6 @@ cfg.swift:
324324
#-----| -> error
325325

326326
# 40| print(_:separator:terminator:)
327-
#-----| -> "..."
328327

329328
# 40| call to print(_:separator:terminator:)
330329
#-----| -> 0
@@ -341,12 +340,64 @@ cfg.swift:
341340
# 40| (Any) ...
342341
#-----| -> [...]
343342

343+
# 40| OpaqueValueExpr
344+
345+
# 40| TapExpr
346+
#-----| -> "..."
347+
348+
# 40| Unknown error
349+
#-----| -> call to ...
350+
344351
# 40| [...]
345352
#-----| -> default separator
346353

347354
# 40| [...]
348355
#-----| -> [...]
349356

357+
# 40| call to ...
358+
#-----| -> appendInterpolation(_:)
359+
360+
# 40| $interpolation
361+
#-----| -> &...
362+
363+
# 40| &...
364+
#-----| -> call to appendLiteral(_:)
365+
366+
# 40| call to appendLiteral(_:)
367+
#-----| -> Unknown error
368+
369+
# 40| $interpolation
370+
#-----| -> &...
371+
372+
# 40| &...
373+
#-----| -> call to appendInterpolation(_:)
374+
375+
# 40| appendInterpolation(_:)
376+
#-----| -> $interpolation
377+
378+
# 40| call to appendInterpolation(_:)
379+
#-----| -> error
380+
381+
# 40| call to ...
382+
383+
# 40| error
384+
#-----| -> call to ...
385+
386+
# 40|
387+
#-----| -> call to ...
388+
389+
# 40| $interpolation
390+
#-----| -> &...
391+
392+
# 40| &...
393+
#-----| -> call to appendLiteral(_:)
394+
395+
# 40| call to ...
396+
#-----| -> TapExpr
397+
398+
# 40| call to appendLiteral(_:)
399+
#-----| ->
400+
350401
# 42| return ...
351402
#-----| return -> exit tryCatch(x:) (normal)
352403

@@ -2817,14 +2868,179 @@ cfg.swift:
28172868
#-----| -> y
28182869

28192870
# 262| y
2820-
#-----| -> "..."
28212871

28222872
# 263| return ...
28232873
#-----| return -> exit interpolatedString(x:y:) (normal)
28242874

2875+
# 263|
2876+
#-----| -> call to ...
2877+
28252878
# 263| "..."
28262879
#-----| -> return ...
28272880

2881+
# 263| OpaqueValueExpr
2882+
2883+
# 263| TapExpr
2884+
#-----| -> "..."
2885+
2886+
# 263| call to ...
2887+
#-----| -> appendInterpolation(_:)
2888+
2889+
# 263| $interpolation
2890+
#-----| -> &...
2891+
2892+
# 263| &...
2893+
#-----| -> call to appendLiteral(_:)
2894+
2895+
# 263| call to appendLiteral(_:)
2896+
#-----| ->
2897+
2898+
# 263| $interpolation
2899+
#-----| -> &...
2900+
2901+
# 263| &...
2902+
#-----| -> call to appendInterpolation(_:)
2903+
2904+
# 263| appendInterpolation(_:)
2905+
#-----| -> $interpolation
2906+
2907+
# 263| call to appendInterpolation(_:)
2908+
#-----| -> x
2909+
2910+
# 263| call to ...
2911+
2912+
# 263| x
2913+
#-----| -> call to ...
2914+
2915+
# 263| +
2916+
#-----| -> call to ...
2917+
2918+
# 263| $interpolation
2919+
#-----| -> &...
2920+
2921+
# 263| &...
2922+
#-----| -> call to appendLiteral(_:)
2923+
2924+
# 263| call to ...
2925+
#-----| -> appendInterpolation(_:)
2926+
2927+
# 263| call to appendLiteral(_:)
2928+
#-----| -> +
2929+
2930+
# 263| $interpolation
2931+
#-----| -> &...
2932+
2933+
# 263| &...
2934+
#-----| -> call to appendInterpolation(_:)
2935+
2936+
# 263| appendInterpolation(_:)
2937+
#-----| -> $interpolation
2938+
2939+
# 263| call to appendInterpolation(_:)
2940+
#-----| -> y
2941+
2942+
# 263| call to ...
2943+
2944+
# 263| y
2945+
#-----| -> call to ...
2946+
2947+
# 263| is equal to
2948+
#-----| -> call to ...
2949+
2950+
# 263| $interpolation
2951+
#-----| -> &...
2952+
2953+
# 263| &...
2954+
#-----| -> call to appendLiteral(_:)
2955+
2956+
# 263| call to ...
2957+
#-----| -> appendInterpolation(_:)
2958+
2959+
# 263| call to appendLiteral(_:)
2960+
#-----| -> is equal to
2961+
2962+
# 263| $interpolation
2963+
#-----| -> &...
2964+
2965+
# 263| &...
2966+
#-----| -> call to appendInterpolation(_:)
2967+
2968+
# 263| appendInterpolation(_:)
2969+
#-----| -> $interpolation
2970+
2971+
# 263| call to appendInterpolation(_:)
2972+
#-----| -> +(_:_:)
2973+
2974+
# 263| call to ...
2975+
2976+
# 263| x
2977+
#-----| -> y
2978+
2979+
# 263| ... call to +(_:_:) ...
2980+
#-----| -> call to ...
2981+
2982+
# 263| +(_:_:)
2983+
#-----| -> Int.Type
2984+
2985+
# 263| Int.Type
2986+
#-----| -> call to +(_:_:)
2987+
2988+
# 263| call to +(_:_:)
2989+
#-----| -> x
2990+
2991+
# 263| y
2992+
#-----| -> ... call to +(_:_:) ...
2993+
2994+
# 263| and here is a zero:
2995+
#-----| -> call to ...
2996+
2997+
# 263| $interpolation
2998+
#-----| -> &...
2999+
3000+
# 263| &...
3001+
#-----| -> call to appendLiteral(_:)
3002+
3003+
# 263| call to ...
3004+
#-----| -> appendInterpolation(_:)
3005+
3006+
# 263| call to appendLiteral(_:)
3007+
#-----| -> and here is a zero:
3008+
3009+
# 263| $interpolation
3010+
#-----| -> &...
3011+
3012+
# 263| &...
3013+
#-----| -> call to appendInterpolation(_:)
3014+
3015+
# 263| appendInterpolation(_:)
3016+
#-----| -> $interpolation
3017+
3018+
# 263| call to appendInterpolation(_:)
3019+
#-----| -> returnZero()
3020+
3021+
# 263| call to ...
3022+
3023+
# 263| returnZero()
3024+
#-----| -> call to returnZero()
3025+
3026+
# 263| call to returnZero()
3027+
#-----| -> call to ...
3028+
3029+
# 263|
3030+
#-----| -> call to ...
3031+
3032+
# 263| $interpolation
3033+
#-----| -> &...
3034+
3035+
# 263| &...
3036+
#-----| -> call to appendLiteral(_:)
3037+
3038+
# 263| call to ...
3039+
#-----| -> TapExpr
3040+
3041+
# 263| call to appendLiteral(_:)
3042+
#-----| ->
3043+
28283044
# 266| enter testSubscriptExpr()
28293045
#-----| -> testSubscriptExpr()
28303046

0 commit comments

Comments
 (0)