1
1
private import rust
2
2
private 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
4
4
private import codeql.rust.elements.internal.PathImpl:: Impl as PathImpl
5
5
private import codeql.rust.elements.internal.PathExprBaseImpl:: Impl as PathExprBaseImpl
6
6
private import codeql.rust.elements.internal.FormatTemplateVariableAccessImpl:: Impl as FormatTemplateVariableAccessImpl
@@ -36,6 +36,38 @@ module Impl {
36
36
ClosureBodyScope ( ) { this = any ( ClosureExpr ce ) .getBody ( ) }
37
37
}
38
38
39
+ /**
40
+ * A scope for conditions, which may introduce variables using `let` expressions.
41
+ *
42
+ * Such variables are only available in the body guarded by the condition.
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
+ }
61
+
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
+ }
70
+
39
71
private Pat getAPatAncestor ( Pat p ) {
40
72
( p instanceof IdentPat or p instanceof OrPat ) and
41
73
exists ( Pat p0 | result = p0 .getParentPat ( ) |
@@ -152,8 +184,14 @@ module Impl {
152
184
/** Gets the `let` statement that introduces this variable, if any. */
153
185
LetStmt getLetStmt ( ) { this .getPat ( ) = result .getPat ( ) }
154
186
187
+ /** Gets the `let` expression that introduces this variable, if any. */
188
+ LetExpr getLetExpr ( ) { this .getPat ( ) = result .getPat ( ) }
189
+
155
190
/** Gets the initial value of this variable, if any. */
156
- Expr getInitializer ( ) { result = this .getLetStmt ( ) .getInitializer ( ) }
191
+ Expr getInitializer ( ) {
192
+ result = this .getLetStmt ( ) .getInitializer ( ) or
193
+ result = this .getLetExpr ( ) .getScrutinee ( )
194
+ }
157
195
158
196
/** Holds if this variable is captured. */
159
197
predicate isCaptured ( ) { this .getAnAccess ( ) .isCapture ( ) }
@@ -193,15 +231,53 @@ module Impl {
193
231
string getName ( ) { result = name_ }
194
232
}
195
233
234
+ pragma [ nomagic]
235
+ private Element getImmediateChildAdj ( Element e , int preOrd , int index ) {
236
+ result = ParentChild:: getImmediateChild ( e , index ) and
237
+ preOrd = 0 and
238
+ not exists ( ConditionScope cs |
239
+ e = cs .getParent ( ) and
240
+ result = cs .getBody ( )
241
+ )
242
+ or
243
+ result = e .( ConditionScope ) .getBody ( ) and
244
+ preOrd = 1 and
245
+ index = 0
246
+ }
247
+
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
+ */
259
+ pragma [ nomagic]
260
+ private Element getImmediateChildAdj ( Element e , int index ) {
261
+ result =
262
+ rank [ index + 1 ] ( Element res , int preOrd , int i |
263
+ res = getImmediateChildAdj ( e , preOrd , i )
264
+ |
265
+ res order by preOrd , i
266
+ )
267
+ }
268
+
269
+ private Element getImmediateParentAdj ( Element e ) { e = getImmediateChildAdj ( result , _) }
270
+
196
271
private AstNode getAnAncestorInVariableScope ( AstNode n ) {
197
272
(
198
273
n instanceof Pat or
199
274
n instanceof VariableAccessCand or
200
275
n instanceof LetStmt or
276
+ n = any ( LetExpr le ) .getScrutinee ( ) or
201
277
n instanceof VariableScope
202
278
) and
203
279
exists ( AstNode n0 |
204
- result = getImmediateParent ( n0 ) or
280
+ result = getImmediateParentAdj ( n0 ) or
205
281
result = n0 .( FormatTemplateVariableAccess ) .getArgument ( ) .getParent ( ) .getParent ( )
206
282
|
207
283
n0 = n
@@ -243,31 +319,32 @@ module Impl {
243
319
this instanceof VariableScope or
244
320
this instanceof VariableAccessCand or
245
321
this instanceof LetStmt or
246
- getImmediateChild ( this , _) instanceof RelevantElement
322
+ this = any ( LetExpr le ) .getScrutinee ( ) or
323
+ getImmediateChildAdj ( this , _) instanceof RelevantElement
247
324
}
248
325
249
326
pragma [ nomagic]
250
- private RelevantElement getChild ( int index ) { result = getImmediateChild ( this , index ) }
327
+ private RelevantElement getChild ( int index ) { result = getImmediateChildAdj ( this , index ) }
251
328
252
329
pragma [ nomagic]
253
- private RelevantElement getImmediateChildMin ( int index ) {
330
+ private RelevantElement getImmediateChildAdjMin ( int index ) {
254
331
// A child may have multiple positions for different accessors,
255
332
// so always use the first
256
333
result = this .getChild ( index ) and
257
334
index = min ( int i | result = this .getChild ( i ) | i )
258
335
}
259
336
260
337
pragma [ nomagic]
261
- RelevantElement getImmediateChild ( int index ) {
338
+ RelevantElement getImmediateChildAdj ( int index ) {
262
339
result =
263
- rank [ index + 1 ] ( Element res , int i | res = this .getImmediateChildMin ( i ) | res order by i )
340
+ rank [ index + 1 ] ( Element res , int i | res = this .getImmediateChildAdjMin ( i ) | res order by i )
264
341
}
265
342
266
343
pragma [ nomagic]
267
344
RelevantElement getImmediateLastChild ( ) {
268
345
exists ( int last |
269
- result = this .getImmediateChild ( last ) and
270
- not exists ( this .getImmediateChild ( last + 1 ) )
346
+ result = this .getImmediateChildAdj ( last ) and
347
+ not exists ( this .getImmediateChildAdj ( last + 1 ) )
271
348
)
272
349
}
273
350
}
@@ -288,13 +365,13 @@ module Impl {
288
365
|
289
366
// first child of a previously numbered node
290
367
result = getPreOrderNumbering ( scope , parent ) + 1 and
291
- n = parent .getImmediateChild ( 0 )
368
+ n = parent .getImmediateChildAdj ( 0 )
292
369
or
293
370
// non-first child of a previously numbered node
294
371
exists ( RelevantElement child , int i |
295
372
result = getLastPreOrderNumbering ( scope , child ) + 1 and
296
- child = parent .getImmediateChild ( i ) and
297
- n = parent .getImmediateChild ( i + 1 )
373
+ child = parent .getImmediateChildAdj ( i ) and
374
+ n = parent .getImmediateChildAdj ( i + 1 )
298
375
)
299
376
)
300
377
}
@@ -309,7 +386,7 @@ module Impl {
309
386
result = getPreOrderNumbering ( scope , leaf ) and
310
387
leaf != scope and
311
388
(
312
- not exists ( leaf .getImmediateChild ( _) )
389
+ not exists ( leaf .getImmediateChildAdj ( _) )
313
390
or
314
391
leaf instanceof VariableScope
315
392
)
@@ -331,7 +408,7 @@ module Impl {
331
408
/**
332
409
* Holds if `v` is named `name` and is declared inside variable scope
333
410
* `scope`. The pre-order numbering of the binding site of `v`, amongst
334
- * all nodes nester under `scope`, is `ord`.
411
+ * all nodes nested under `scope`, is `ord`.
335
412
*/
336
413
private predicate variableDeclInScope ( Variable v , VariableScope scope , string name , int ord ) {
337
414
name = v .getText ( ) and
@@ -354,25 +431,20 @@ module Impl {
354
431
ord = getLastPreOrderNumbering ( scope , let ) + 1
355
432
)
356
433
or
357
- exists ( IfExpr ie , LetExpr let |
434
+ exists ( LetExpr let , Expr scrutinee |
358
435
let .getPat ( ) = pat and
359
- ie .getCondition ( ) = let and
360
- scope = ie .getThen ( ) and
361
- ord = getPreOrderNumbering ( scope , scope )
436
+ scrutinee = let .getScrutinee ( ) and
437
+ scope = getEnclosingScope ( scrutinee ) and
438
+ // for `let` expressions, variables are bound _after_ the expression, i.e.
439
+ // not in the RHS
440
+ ord = getLastPreOrderNumbering ( scope , scrutinee ) + 1
362
441
)
363
442
or
364
443
exists ( ForExpr fe |
365
444
fe .getPat ( ) = pat and
366
445
scope = fe .getLoopBody ( ) and
367
446
ord = getPreOrderNumbering ( scope , scope )
368
447
)
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
- )
376
448
)
377
449
)
378
450
}
@@ -612,7 +684,7 @@ module Impl {
612
684
or
613
685
exists ( Expr mid |
614
686
assignmentExprDescendant ( mid ) and
615
- getImmediateParent ( e ) = mid and
687
+ getImmediateParentAdj ( e ) = mid and
616
688
not mid instanceof DerefExpr and
617
689
not mid instanceof FieldExpr and
618
690
not mid instanceof IndexExpr
0 commit comments