@@ -36,6 +36,10 @@ module Impl {
3636 ClosureBodyScope ( ) { this = any ( ClosureExpr ce ) .getBody ( ) }
3737 }
3838
39+ class IfExprScope extends VariableScope , IfExpr { }
40+
41+ class WhileExprScope extends VariableScope , WhileExpr { }
42+
3943 private Pat getAPatAncestor ( Pat p ) {
4044 ( p instanceof IdentPat or p instanceof OrPat ) and
4145 exists ( Pat p0 | result = p0 .getParentPat ( ) |
@@ -152,8 +156,14 @@ module Impl {
152156 /** Gets the `let` statement that introduces this variable, if any. */
153157 LetStmt getLetStmt ( ) { this .getPat ( ) = result .getPat ( ) }
154158
159+ /** Gets the `let` expression that introduces this variable, if any. */
160+ LetExpr getLetExpr ( ) { this .getPat ( ) = result .getPat ( ) }
161+
155162 /** Gets the initial value of this variable, if any. */
156- Expr getInitializer ( ) { result = this .getLetStmt ( ) .getInitializer ( ) }
163+ Expr getInitializer ( ) {
164+ result = this .getLetStmt ( ) .getInitializer ( ) or
165+ result = this .getLetExpr ( ) .getScrutinee ( )
166+ }
157167
158168 /** Holds if this variable is captured. */
159169 predicate isCaptured ( ) { this .getAnAccess ( ) .isCapture ( ) }
@@ -193,15 +203,60 @@ module Impl {
193203 string getName ( ) { result = name_ }
194204 }
195205
206+ private AstNode getElseBranch (
207+ AstNode elseParentParent , int index , AstNode elseParent , int elseIndex
208+ ) {
209+ elseParent = getImmediateChild ( elseParentParent , index ) and
210+ result = getImmediateChild ( elseParent , elseIndex ) and
211+ (
212+ result = elseParent .( LetStmt ) .getLetElse ( )
213+ or
214+ result = elseParent .( IfExpr ) .getElse ( )
215+ )
216+ }
217+
218+ private AstNode getLoopBody ( LoopingExpr loop ) { result = loop .getLoopBody ( ) }
219+
220+ pragma [ nomagic]
221+ private Element getImmediateChildAdj ( Element e , int preOrd , int index , int postOrd ) {
222+ result = getImmediateChild ( e , index ) and
223+ preOrd = 0 and
224+ postOrd = 0 and
225+ not result = getElseBranch ( _, _, e , index ) and
226+ not result = getLoopBody ( e )
227+ or
228+ result = getElseBranch ( e , index , _, _) and
229+ preOrd = 0 and
230+ postOrd = - 1
231+ or
232+ result = getLoopBody ( e ) and
233+ index = 0 and
234+ preOrd = 1 and
235+ postOrd = 0
236+ }
237+
238+ pragma [ nomagic]
239+ private Element getImmediateChildAdj ( Element e , int index ) {
240+ result =
241+ rank [ index + 1 ] ( Element res , int i , int preOrd , int postOrd |
242+ res = getImmediateChildAdj ( e , preOrd , i , postOrd )
243+ |
244+ res order by preOrd , i , postOrd
245+ )
246+ }
247+
248+ private Element getImmediateParentAdj ( Element e ) { e = getImmediateChildAdj ( result , _) }
249+
196250 private AstNode getAnAncestorInVariableScope ( AstNode n ) {
197251 (
198252 n instanceof Pat or
199253 n instanceof VariableAccessCand or
200254 n instanceof LetStmt or
255+ n instanceof LetExpr or
201256 n instanceof VariableScope
202257 ) and
203258 exists ( AstNode n0 |
204- result = getImmediateParent ( n0 ) or
259+ result = getImmediateParentAdj ( n0 ) or
205260 result = n0 .( FormatTemplateVariableAccess ) .getArgument ( ) .getParent ( ) .getParent ( )
206261 |
207262 n0 = n
@@ -243,31 +298,32 @@ module Impl {
243298 this instanceof VariableScope or
244299 this instanceof VariableAccessCand or
245300 this instanceof LetStmt or
246- getImmediateChild ( this , _) instanceof RelevantElement
301+ this instanceof LetExpr or
302+ getImmediateChildAdj ( this , _) instanceof RelevantElement
247303 }
248304
249305 pragma [ nomagic]
250- private RelevantElement getChild ( int index ) { result = getImmediateChild ( this , index ) }
306+ private RelevantElement getChild ( int index ) { result = getImmediateChildAdj ( this , index ) }
251307
252308 pragma [ nomagic]
253- private RelevantElement getImmediateChildMin ( int index ) {
309+ private RelevantElement getImmediateChildAdjMin ( int index ) {
254310 // A child may have multiple positions for different accessors,
255311 // so always use the first
256312 result = this .getChild ( index ) and
257313 index = min ( int i | result = this .getChild ( i ) | i )
258314 }
259315
260316 pragma [ nomagic]
261- RelevantElement getImmediateChild ( int index ) {
317+ RelevantElement getImmediateChildAdj ( int index ) {
262318 result =
263- rank [ index + 1 ] ( Element res , int i | res = this .getImmediateChildMin ( i ) | res order by i )
319+ rank [ index + 1 ] ( Element res , int i | res = this .getImmediateChildAdjMin ( i ) | res order by i )
264320 }
265321
266322 pragma [ nomagic]
267323 RelevantElement getImmediateLastChild ( ) {
268324 exists ( int last |
269- result = this .getImmediateChild ( last ) and
270- not exists ( this .getImmediateChild ( last + 1 ) )
325+ result = this .getImmediateChildAdj ( last ) and
326+ not exists ( this .getImmediateChildAdj ( last + 1 ) )
271327 )
272328 }
273329 }
@@ -288,13 +344,13 @@ module Impl {
288344 |
289345 // first child of a previously numbered node
290346 result = getPreOrderNumbering ( scope , parent ) + 1 and
291- n = parent .getImmediateChild ( 0 )
347+ n = parent .getImmediateChildAdj ( 0 )
292348 or
293349 // non-first child of a previously numbered node
294350 exists ( RelevantElement child , int i |
295351 result = getLastPreOrderNumbering ( scope , child ) + 1 and
296- child = parent .getImmediateChild ( i ) and
297- n = parent .getImmediateChild ( i + 1 )
352+ child = parent .getImmediateChildAdj ( i ) and
353+ n = parent .getImmediateChildAdj ( i + 1 )
298354 )
299355 )
300356 }
@@ -309,7 +365,7 @@ module Impl {
309365 result = getPreOrderNumbering ( scope , leaf ) and
310366 leaf != scope and
311367 (
312- not exists ( leaf .getImmediateChild ( _) )
368+ not exists ( leaf .getImmediateChildAdj ( _) )
313369 or
314370 leaf instanceof VariableScope
315371 )
@@ -331,7 +387,7 @@ module Impl {
331387 /**
332388 * Holds if `v` is named `name` and is declared inside variable scope
333389 * `scope`. The pre-order numbering of the binding site of `v`, amongst
334- * all nodes nester under `scope`, is `ord`.
390+ * all nodes nested under `scope`, is `ord`.
335391 */
336392 private predicate variableDeclInScope ( Variable v , VariableScope scope , string name , int ord ) {
337393 name = v .getText ( ) and
@@ -354,25 +410,19 @@ module Impl {
354410 ord = getLastPreOrderNumbering ( scope , let ) + 1
355411 )
356412 or
357- exists ( IfExpr ie , LetExpr let |
413+ exists ( LetExpr let |
358414 let .getPat ( ) = pat and
359- ie .getCondition ( ) = let and
360- scope = ie .getThen ( ) and
361- ord = getPreOrderNumbering ( scope , scope )
415+ scope = getEnclosingScope ( let ) and
416+ // for `let` expressions, variables are bound _after_ the statement, i.e.
417+ // not in the RHS
418+ ord = getLastPreOrderNumbering ( scope , let ) + 1
362419 )
363420 or
364421 exists ( ForExpr fe |
365422 fe .getPat ( ) = pat and
366423 scope = fe .getLoopBody ( ) and
367424 ord = getPreOrderNumbering ( scope , scope )
368425 )
369- or
370- exists ( WhileExpr we , LetExpr let |
371- let .getPat ( ) = pat and
372- we .getCondition ( ) = let and
373- scope = we .getLoopBody ( ) and
374- ord = getPreOrderNumbering ( scope , scope )
375- )
376426 )
377427 )
378428 }
@@ -612,7 +662,7 @@ module Impl {
612662 or
613663 exists ( Expr mid |
614664 assignmentExprDescendant ( mid ) and
615- getImmediateParent ( e ) = mid and
665+ getImmediateParentAdj ( e ) = mid and
616666 not mid instanceof DerefExpr and
617667 not mid instanceof FieldExpr and
618668 not mid instanceof IndexExpr
0 commit comments