11private import rust
22private import codeql.rust.controlflow.ControlFlowGraph
3- private import codeql.rust.elements.internal.generated.ParentChild
3+ private import codeql.rust.elements.internal.generated.ParentChild as ParentChild
44private import codeql.rust.elements.internal.PathImpl:: Impl as PathImpl
55private import codeql.rust.elements.internal.PathExprBaseImpl:: Impl as PathExprBaseImpl
66private import codeql.rust.elements.internal.FormatTemplateVariableAccessImpl:: Impl as FormatTemplateVariableAccessImpl
@@ -36,9 +36,37 @@ module Impl {
3636 ClosureBodyScope ( ) { this = any ( ClosureExpr ce ) .getBody ( ) }
3737 }
3838
39- class IfExprScope extends VariableScope , IfExpr { }
39+ /**
40+ * A scope for conditions, which may introduce variables using `let`
41+ * expressions, which are available only in the `then` branch or
42+ * loop body.
43+ */
44+ class ConditionScope extends VariableScope , Expr {
45+ private AstNode parent ;
46+ private AstNode body ;
47+
48+ ConditionScope ( ) {
49+ parent =
50+ any ( IfExpr ie |
51+ this = ie .getCondition ( ) and
52+ body = ie .getThen ( )
53+ )
54+ or
55+ parent =
56+ any ( WhileExpr we |
57+ this = we .getCondition ( ) and
58+ body = we .getLoopBody ( )
59+ )
60+ }
4061
41- class WhileExprScope extends VariableScope , WhileExpr { }
62+ /** Gets the parent of this condition. */
63+ AstNode getParent ( ) { result = parent }
64+
65+ /**
66+ * Gets the body in which variables introduced in this scope are available.
67+ */
68+ AstNode getBody ( ) { result = body }
69+ }
4270
4371 private Pat getAPatAncestor ( Pat p ) {
4472 ( p instanceof IdentPat or p instanceof OrPat ) and
@@ -203,45 +231,38 @@ module Impl {
203231 string getName ( ) { result = name_ }
204232 }
205233
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-
220234 pragma [ nomagic]
221- private Element getImmediateChildAdj ( Element e , int preOrd , int index , int postOrd ) {
222- result = getImmediateChild ( e , index ) and
235+ private Element getImmediateChildAdj ( Element e , int preOrd , int index ) {
236+ result = ParentChild :: getImmediateChild ( e , index ) and
223237 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
238+ not exists ( ConditionScope cs |
239+ e = cs .getParent ( ) and
240+ result = cs .getBody ( )
241+ )
231242 or
232- result = getLoopBody ( e ) and
233- index = 0 and
243+ result = e .( ConditionScope ) .getBody ( ) and
234244 preOrd = 1 and
235- postOrd = 0
245+ index = 0
236246 }
237247
248+ /**
249+ * An adjusted version of `ParentChild::getImmediateChild`, which makes the following
250+ * two adjustments:
251+ *
252+ * 1. For conditions like `if cond body`, instead of letting `body` be the second child
253+ * of `if`, we make it the last child of `cond`. This ensures that variables
254+ * introduced in the `cond` scope are available in `body`.
255+ *
256+ * 2. A similar adjustment is made for `while` loops: the body of the loop is made a
257+ * child of the loop condition instead of the loop itself.
258+ */
238259 pragma [ nomagic]
239260 private Element getImmediateChildAdj ( Element e , int index ) {
240261 result =
241- rank [ index + 1 ] ( Element res , int i , int preOrd , int postOrd |
242- res = getImmediateChildAdj ( e , preOrd , i , postOrd )
262+ rank [ index + 1 ] ( Element res , int preOrd , int i |
263+ res = getImmediateChildAdj ( e , preOrd , i )
243264 |
244- res order by preOrd , i , postOrd
265+ res order by preOrd , i
245266 )
246267 }
247268
@@ -252,7 +273,7 @@ module Impl {
252273 n instanceof Pat or
253274 n instanceof VariableAccessCand or
254275 n instanceof LetStmt or
255- n instanceof LetExpr or
276+ n = any ( LetExpr le ) . getScrutinee ( ) or
256277 n instanceof VariableScope
257278 ) and
258279 exists ( AstNode n0 |
@@ -298,7 +319,7 @@ module Impl {
298319 this instanceof VariableScope or
299320 this instanceof VariableAccessCand or
300321 this instanceof LetStmt or
301- this instanceof LetExpr or
322+ this = any ( LetExpr le ) . getScrutinee ( ) or
302323 getImmediateChildAdj ( this , _) instanceof RelevantElement
303324 }
304325
@@ -410,12 +431,13 @@ module Impl {
410431 ord = getLastPreOrderNumbering ( scope , let ) + 1
411432 )
412433 or
413- exists ( LetExpr let |
434+ exists ( LetExpr let , Expr scrutinee |
414435 let .getPat ( ) = pat and
415- scope = getEnclosingScope ( let ) and
416- // for `let` expressions, variables are bound _after_ the statement, i.e.
436+ scrutinee = let .getScrutinee ( ) and
437+ scope = getEnclosingScope ( scrutinee ) and
438+ // for `let` expressions, variables are bound _after_ the expression, i.e.
417439 // not in the RHS
418- ord = getLastPreOrderNumbering ( scope , let ) + 1
440+ ord = getLastPreOrderNumbering ( scope , scrutinee ) + 1
419441 )
420442 or
421443 exists ( ForExpr fe |
0 commit comments