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