@@ -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 `TapExpr`. In `TapExprTree` 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,38 @@ 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+ /** Control-flow for a `TapExpr`. See the QLDoc for `TapExpr` for the semantics of a `TapExpr`. */
1353+ private class TapExprTree extends AstStandardPostOrderTree {
1354+ override TapExpr ast ;
1355+
1356+ final override ControlFlowElement getChildElement ( int i ) {
1357+ // We first visit the local variable declaration.
1358+ i = 0 and
1359+ result .asAstNode ( ) = ast .getVar ( )
1360+ or
1361+ // Then we visit the expression that gives the local variable its initial value.
1362+ i = 1 and
1363+ result .asAstNode ( ) = ast .getSubExpr ( ) .getFullyConverted ( )
1364+ or
1365+ // And finally, we visit the body that potentially mutates the local variable.
1366+ // Note that the CFG for the body will skip the first element in the
1367+ // body because it's guarenteed to be the variable declaration
1368+ // that we've already visited at i = 0. See the explanation
1369+ // in `BraceStmtTree` for why this is necessary.
1370+ i = 2 and
1371+ result .asAstNode ( ) = ast .getBody ( )
13381372 }
13391373 }
13401374
1375+ private class OpaqueValueExprTree extends AstLeafTree {
1376+ override OpaqueValueExpr ast ;
1377+ }
1378+
13411379 module DeclRefExprs {
13421380 class DeclRefExprLValueTree extends AstLeafTree {
13431381 override DeclRefExpr ast ;
0 commit comments