@@ -35,12 +35,17 @@ module Ast implements AstSig<Location> {
3535 not e .fromSource ( )
3636 }
3737
38+ private AstNode adjustedGetChild ( AstNode n , int index ) { deferScope ( n , index , result ) }
39+
3840 AstNode getChild ( AstNode n , int index ) {
3941 result .getParent ( ) = n and
4042 result .getParentIndex ( ) = index and
4143 not n instanceof Callable and
4244 not skipControlFlow ( n ) and
43- not skipControlFlow ( result )
45+ not skipControlFlow ( result ) and
46+ not adjustedGetChild ( _, _) = result
47+ or
48+ adjustedGetChild ( n , index ) = result
4449 or
4550 n .( FunctionExpr ) .getCaptureDeclaration ( index ) = result
4651 or
@@ -76,7 +81,56 @@ module Ast implements AstSig<Location> {
7681
7782 class Expr = U:: Expr ;
7883
79- class BlockStmt = U:: Block ;
84+ /**
85+ * Holds if `s` is the `n`th statement in the constructed `try` block of
86+ * `defer`.
87+ *
88+ * For example, the following `defer` statements
89+ * ```
90+ * {
91+ * s1
92+ * defer { s5 }
93+ * s2
94+ * defer { s4 }
95+ * s3
96+ * }
97+ * ```
98+ * are transformed into these `try`-`finally` blocks:
99+ * ```
100+ * {
101+ * s1
102+ * try {
103+ * s2
104+ * try {
105+ * s3
106+ * } finally {
107+ * s4
108+ * }
109+ * } finally {
110+ * s5
111+ * }
112+ * }
113+ * ```
114+ */
115+ private predicate deferScope ( U:: DeferStmt defer , int n , Stmt s ) {
116+ exists ( U:: Block block , int deferIdx | block .getStmt ( deferIdx ) = defer |
117+ block .getStmt ( deferIdx + 1 ) = s and n = 0
118+ or
119+ exists ( Stmt mid |
120+ deferScope ( defer , n - 1 , mid ) and
121+ not mid instanceof U:: DeferStmt and
122+ block .getStmt ( deferIdx + 1 + n ) = s
123+ )
124+ )
125+ }
126+
127+ class BlockStmt extends Stmt instanceof U:: Block {
128+ Stmt getStmt ( int n ) { result = super .getStmt ( n ) and not deferScope ( _, _, result ) }
129+
130+ Stmt getLastStmt ( ) {
131+ exists ( int i | result = this .getStmt ( i ) and not exists ( this .getStmt ( i + 1 ) ) )
132+ }
133+ }
80134
81135 class ExprStmt extends Stmt {
82136 ExprStmt ( ) { none ( ) }
@@ -127,13 +181,13 @@ module Ast implements AstSig<Location> {
127181 class ForEachStmt extends LoopStmt instanceof U:: ForEachStmt {
128182 override Stmt getBody ( ) { result = U:: ForEachStmt .super .getBody ( ) }
129183
130- // TODO support foreach guard
131- //
132184 Expr getVariable ( ) { result = super .getPattern ( ) }
133185
134186 Expr getCollection ( ) { result = super .getIterable ( ) }
135187 }
136188
189+ AstNode getLoopGuard ( ForEachStmt foreachstmt ) { result = foreachstmt .( U:: ForEachStmt ) .getGuard ( ) }
190+
137191 class BreakStmt = U:: BreakExpr ;
138192
139193 class ContinueStmt = U:: ContinueExpr ;
@@ -152,12 +206,18 @@ module Ast implements AstSig<Location> {
152206 Expr getExpr ( ) { result = super .getValue ( ) }
153207 }
154208
155- class TryStmt extends U:: TryExpr {
156- AstNode getBody ( int index ) { index = 0 and result = super .getBody ( ) }
209+ class TryStmt extends Stmt {
210+ TryStmt ( ) { this instanceof U:: TryExpr or this instanceof U:: DeferStmt }
211+
212+ AstNode getBody ( int index ) {
213+ index = 0 and result = this .( U:: TryExpr ) .getBody ( )
214+ or
215+ deferScope ( this , index , result )
216+ }
157217
158- CatchClause getCatch ( int index ) { result = super .getCatchClause ( index ) }
218+ CatchClause getCatch ( int index ) { result = this . ( U :: TryExpr ) .getCatchClause ( index ) }
159219
160- Stmt getFinally ( ) { none ( ) }
220+ Stmt getFinally ( ) { result = this . ( U :: DeferStmt ) . getBody ( ) }
161221 }
162222
163223 class CatchClause extends U:: CatchClause {
0 commit comments