@@ -165,7 +165,7 @@ module Impl {
165165
166166 /**
167167 * 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,
169169 * qualifiers, etc.).
170170 */
171171 private class VariableAccessCand extends PathExprBase {
@@ -231,80 +231,169 @@ module Impl {
231231 )
232232 }
233233
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+
234327 /**
235328 * 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`.
237331 */
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 ) {
241333 name = v .getName ( ) and
242334 (
243335 parameterDeclInScope ( v , scope ) and
244- scope . getLocation ( ) . hasLocationFileInfo ( _ , line , column , _ , _ )
336+ ord = getPreOrderNumbering ( scope , scope )
245337 or
246338 exists ( Pat pat | pat = getAVariablePatAncestor ( v ) |
247339 scope =
248340 any ( MatchArmScope arm |
249341 arm .getPat ( ) = pat and
250- arm . getLocation ( ) . hasLocationFileInfo ( _ , line , column , _ , _ )
342+ ord = getPreOrderNumbering ( scope , arm )
251343 )
252344 or
253345 exists ( LetStmt let |
254346 let .getPat ( ) = pat and
255347 scope = getEnclosingScope ( let ) and
256348 // for `let` statements, variables are bound _after_ the statement, i.e.
257349 // not in the RHS
258- let . getLocation ( ) . hasLocationFileInfo ( _ , _ , _ , line , column )
350+ ord = getLastPreOrderNumbering ( scope , let ) + 1
259351 )
260352 or
261353 exists ( IfExpr ie , LetExpr let |
262354 let .getPat ( ) = pat and
263355 ie .getCondition ( ) = let and
264356 scope = ie .getThen ( ) and
265- scope . getLocation ( ) . hasLocationFileInfo ( _ , line , column , _ , _ )
357+ ord = getPreOrderNumbering ( scope , scope )
266358 )
267359 or
268360 exists ( ForExpr fe |
269361 fe .getPat ( ) = pat and
270362 scope = fe .getLoopBody ( ) and
271- scope . getLocation ( ) . hasLocationFileInfo ( _ , line , column , _ , _ )
363+ ord = getPreOrderNumbering ( scope , scope )
272364 )
273365 or
274366 exists ( WhileExpr we , LetExpr let |
275367 let .getPat ( ) = pat and
276368 we .getCondition ( ) = let and
277369 scope = we .getLoopBody ( ) and
278- scope . getLocation ( ) . hasLocationFileInfo ( _ , line , column , _ , _ )
370+ ord = getPreOrderNumbering ( scope , scope )
279371 )
280372 )
281373 )
282374 }
283375
284376 /**
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`.
288379 *
289380 * `nestLevel` is the number of nested scopes that need to be traversed
290381 * to reach `scope` from `cand`.
291382 */
292383 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
295385 ) {
296386 name = cand .getName ( ) and
297387 scope = [ cand .( VariableScope ) , getEnclosingScope ( cand ) ] and
298- cand . getLocation ( ) . hasLocationFileInfo ( _ , startline , startcolumn , endline , endcolumn ) and
388+ ord = getPreOrderNumbering ( scope , cand ) and
299389 nestLevel = 0
300390 or
301391 exists ( VariableScope inner |
302- variableAccessCandInScope ( cand , inner , name , nestLevel - 1 , _, _ , _ , _ ) and
392+ variableAccessCandInScope ( cand , inner , name , nestLevel - 1 , _) and
303393 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 )
308397 )
309398 }
310399
@@ -375,15 +464,12 @@ module Impl {
375464 }
376465
377466 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
384470 or
385- variableAccessCandInScope ( this .asVariableAccessCand ( ) , scope , name , _, startline , startcolumn ,
386- endline , endcolumn )
471+ variableAccessCandInScope ( this .asVariableAccessCand ( ) , scope , name , _, ord ) and
472+ kind = 1
387473 }
388474 }
389475
@@ -396,11 +482,10 @@ module Impl {
396482
397483 int getRank ( VariableScope scope , string name , VariableOrAccessCand v ) {
398484 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 )
402487 |
403- v0 order by startline , startcolumn , endline , endcolumn
488+ v0 order by ord , kind
404489 )
405490 }
406491 }
@@ -440,7 +525,7 @@ module Impl {
440525 exists ( int rnk |
441526 variableReachesRank ( scope , name , v , rnk ) and
442527 rnk = rankVariableOrAccess ( scope , name , TVariableOrAccessCandVariableAccessCand ( cand ) ) and
443- variableAccessCandInScope ( cand , scope , name , nestLevel , _, _ , _ , _ )
528+ variableAccessCandInScope ( cand , scope , name , nestLevel , _)
444529 )
445530 }
446531
0 commit comments