@@ -165,7 +165,7 @@ module Impl {
165
165
166
166
/**
167
167
* A path expression that may access a local variable. These are paths that
168
- * only consists of a simple name (i.e., without generic arguments,
168
+ * only consist of a simple name (i.e., without generic arguments,
169
169
* qualifiers, etc.).
170
170
*/
171
171
private class VariableAccessCand extends PathExprBase {
@@ -231,80 +231,169 @@ module Impl {
231
231
)
232
232
}
233
233
234
+ /** A subset of `Element`s for which we want to compute pre-order numbers. */
235
+ private class RelevantElement extends Element {
236
+ RelevantElement ( ) {
237
+ this instanceof VariableScope or
238
+ this instanceof VariableAccessCand or
239
+ this instanceof LetStmt or
240
+ getImmediateChildAndAccessor ( this , _, _) instanceof RelevantElement
241
+ }
242
+
243
+ pragma [ nomagic]
244
+ private RelevantElement getChild ( int index ) {
245
+ result = getImmediateChildAndAccessor ( this , index , _)
246
+ }
247
+
248
+ pragma [ nomagic]
249
+ private RelevantElement getImmediateChildMin ( int index ) {
250
+ // A child may have multiple positions for different accessors,
251
+ // so always use the first
252
+ result = this .getChild ( index ) and
253
+ index = min ( int i | result = this .getChild ( i ) | i )
254
+ }
255
+
256
+ pragma [ nomagic]
257
+ RelevantElement getImmediateChild ( int index ) {
258
+ result =
259
+ rank [ index + 1 ] ( Element res , int i | res = this .getImmediateChildMin ( i ) | res order by i )
260
+ }
261
+
262
+ pragma [ nomagic]
263
+ RelevantElement getImmediateLastChild ( ) {
264
+ exists ( int last |
265
+ result = this .getImmediateChild ( last ) and
266
+ not exists ( this .getImmediateChild ( last + 1 ) )
267
+ )
268
+ }
269
+ }
270
+
271
+ /**
272
+ * Gets the pre-order numbering of `n`, where the immediately enclosing
273
+ * variable scope of `n` is `scope`.
274
+ */
275
+ pragma [ nomagic]
276
+ private int getPreOrderNumbering ( VariableScope scope , RelevantElement n ) {
277
+ n = scope and
278
+ result = 0
279
+ or
280
+ exists ( RelevantElement parent |
281
+ not parent instanceof VariableScope
282
+ or
283
+ parent = scope
284
+ |
285
+ // first child of a previously numbered node
286
+ result = getPreOrderNumbering ( scope , parent ) + 1 and
287
+ n = parent .getImmediateChild ( 0 )
288
+ or
289
+ // non-first child of a previously numbered node
290
+ exists ( RelevantElement child , int i |
291
+ result = getLastPreOrderNumbering ( scope , child ) + 1 and
292
+ child = parent .getImmediateChild ( i ) and
293
+ n = parent .getImmediateChild ( i + 1 )
294
+ )
295
+ )
296
+ }
297
+
298
+ /**
299
+ * Gets the pre-order numbering of the _last_ node nested under `n`, where the
300
+ * immediately enclosing variable scope of `n` (and the last node) is `scope`.
301
+ */
302
+ pragma [ nomagic]
303
+ private int getLastPreOrderNumbering ( VariableScope scope , RelevantElement n ) {
304
+ exists ( RelevantElement leaf |
305
+ result = getPreOrderNumbering ( scope , leaf ) and
306
+ leaf != scope and
307
+ (
308
+ not exists ( leaf .getImmediateChild ( _) )
309
+ or
310
+ leaf instanceof VariableScope
311
+ )
312
+ |
313
+ n = leaf
314
+ or
315
+ n .getImmediateLastChild ( ) = leaf and
316
+ not n instanceof VariableScope
317
+ )
318
+ or
319
+ exists ( RelevantElement mid |
320
+ mid = n .getImmediateLastChild ( ) and
321
+ result = getLastPreOrderNumbering ( scope , mid ) and
322
+ not mid instanceof VariableScope and
323
+ not n instanceof VariableScope
324
+ )
325
+ }
326
+
234
327
/**
235
328
* Holds if `v` is named `name` and is declared inside variable scope
236
- * `scope`, and `v` is bound starting from `(line, column)`.
329
+ * `scope`. The pre-order numbering of the binding site of `v`, amongst
330
+ * all nodes nester under `scope`, is `ord`.
237
331
*/
238
- private predicate variableDeclInScope (
239
- Variable v , VariableScope scope , string name , int line , int column
240
- ) {
332
+ private predicate variableDeclInScope ( Variable v , VariableScope scope , string name , int ord ) {
241
333
name = v .getName ( ) and
242
334
(
243
335
parameterDeclInScope ( v , scope ) and
244
- scope . getLocation ( ) . hasLocationFileInfo ( _ , line , column , _ , _ )
336
+ ord = getPreOrderNumbering ( scope , scope )
245
337
or
246
338
exists ( Pat pat | pat = getAVariablePatAncestor ( v ) |
247
339
scope =
248
340
any ( MatchArmScope arm |
249
341
arm .getPat ( ) = pat and
250
- arm . getLocation ( ) . hasLocationFileInfo ( _ , line , column , _ , _ )
342
+ ord = getPreOrderNumbering ( scope , arm )
251
343
)
252
344
or
253
345
exists ( LetStmt let |
254
346
let .getPat ( ) = pat and
255
347
scope = getEnclosingScope ( let ) and
256
348
// for `let` statements, variables are bound _after_ the statement, i.e.
257
349
// not in the RHS
258
- let . getLocation ( ) . hasLocationFileInfo ( _ , _ , _ , line , column )
350
+ ord = getLastPreOrderNumbering ( scope , let ) + 1
259
351
)
260
352
or
261
353
exists ( IfExpr ie , LetExpr let |
262
354
let .getPat ( ) = pat and
263
355
ie .getCondition ( ) = let and
264
356
scope = ie .getThen ( ) and
265
- scope . getLocation ( ) . hasLocationFileInfo ( _ , line , column , _ , _ )
357
+ ord = getPreOrderNumbering ( scope , scope )
266
358
)
267
359
or
268
360
exists ( ForExpr fe |
269
361
fe .getPat ( ) = pat and
270
362
scope = fe .getLoopBody ( ) and
271
- scope . getLocation ( ) . hasLocationFileInfo ( _ , line , column , _ , _ )
363
+ ord = getPreOrderNumbering ( scope , scope )
272
364
)
273
365
or
274
366
exists ( WhileExpr we , LetExpr let |
275
367
let .getPat ( ) = pat and
276
368
we .getCondition ( ) = let and
277
369
scope = we .getLoopBody ( ) and
278
- scope . getLocation ( ) . hasLocationFileInfo ( _ , line , column , _ , _ )
370
+ ord = getPreOrderNumbering ( scope , scope )
279
371
)
280
372
)
281
373
)
282
374
}
283
375
284
376
/**
285
- * Holds if `cand` may access a variable named `name` at
286
- * `(startline, startcolumn, endline, endcolumn)` in the variable scope
287
- * `scope`.
377
+ * Holds if `cand` may access a variable named `name` at pre-order number `ord`
378
+ * in the variable scope `scope`.
288
379
*
289
380
* `nestLevel` is the number of nested scopes that need to be traversed
290
381
* to reach `scope` from `cand`.
291
382
*/
292
383
private predicate variableAccessCandInScope (
293
- VariableAccessCand cand , VariableScope scope , string name , int nestLevel , int startline ,
294
- int startcolumn , int endline , int endcolumn
384
+ VariableAccessCand cand , VariableScope scope , string name , int nestLevel , int ord
295
385
) {
296
386
name = cand .getName ( ) and
297
387
scope = [ cand .( VariableScope ) , getEnclosingScope ( cand ) ] and
298
- cand . getLocation ( ) . hasLocationFileInfo ( _ , startline , startcolumn , endline , endcolumn ) and
388
+ ord = getPreOrderNumbering ( scope , cand ) and
299
389
nestLevel = 0
300
390
or
301
391
exists ( VariableScope inner |
302
- variableAccessCandInScope ( cand , inner , name , nestLevel - 1 , _, _ , _ , _ ) and
392
+ variableAccessCandInScope ( cand , inner , name , nestLevel - 1 , _) and
303
393
scope = getEnclosingScope ( inner ) and
304
- // Use the location of the inner scope as the location of the access, instead of the
305
- // actual access location. This allows us to collapse multiple accesses in inner
306
- // scopes to a single entity
307
- inner .getLocation ( ) .hasLocationFileInfo ( _, startline , startcolumn , endline , endcolumn )
394
+ // Use the pre-order number of the inner scope as the number of the access. This allows
395
+ // us to collapse multiple accesses in inner scopes to a single entity
396
+ ord = getPreOrderNumbering ( scope , inner )
308
397
)
309
398
}
310
399
@@ -375,15 +464,12 @@ module Impl {
375
464
}
376
465
377
466
pragma [ nomagic]
378
- predicate rankBy (
379
- string name , VariableScope scope , int startline , int startcolumn , int endline , int endcolumn
380
- ) {
381
- variableDeclInScope ( this .asVariable ( ) , scope , name , startline , startcolumn ) and
382
- endline = - 1 and
383
- endcolumn = - 1
467
+ predicate rankBy ( string name , VariableScope scope , int ord , int kind ) {
468
+ variableDeclInScope ( this .asVariable ( ) , scope , name , ord ) and
469
+ kind = 0
384
470
or
385
- variableAccessCandInScope ( this .asVariableAccessCand ( ) , scope , name , _, startline , startcolumn ,
386
- endline , endcolumn )
471
+ variableAccessCandInScope ( this .asVariableAccessCand ( ) , scope , name , _, ord ) and
472
+ kind = 1
387
473
}
388
474
}
389
475
@@ -396,11 +482,10 @@ module Impl {
396
482
397
483
int getRank ( VariableScope scope , string name , VariableOrAccessCand v ) {
398
484
v =
399
- rank [ result ] ( VariableOrAccessCand v0 , int startline , int startcolumn , int endline ,
400
- int endcolumn |
401
- v0 .rankBy ( name , scope , startline , startcolumn , endline , endcolumn )
485
+ rank [ result ] ( VariableOrAccessCand v0 , int ord , int kind |
486
+ v0 .rankBy ( name , scope , ord , kind )
402
487
|
403
- v0 order by startline , startcolumn , endline , endcolumn
488
+ v0 order by ord , kind
404
489
)
405
490
}
406
491
}
@@ -440,7 +525,7 @@ module Impl {
440
525
exists ( int rnk |
441
526
variableReachesRank ( scope , name , v , rnk ) and
442
527
rnk = rankVariableOrAccess ( scope , name , TVariableOrAccessCandVariableAccessCand ( cand ) ) and
443
- variableAccessCandInScope ( cand , scope , name , nestLevel , _, _ , _ , _ )
528
+ variableAccessCandInScope ( cand , scope , name , nestLevel , _)
444
529
)
445
530
}
446
531
0 commit comments