@@ -45,6 +45,12 @@ signature module UniversalFlowInput<LocationSig Location> {
4545 Location getLocation ( ) ;
4646 }
4747
48+ /**
49+ * Gets an identifier for node `n`, if any. When no identifier is provided for `n`,
50+ * the library falls back to location-based ranking.
51+ */
52+ default int getFlowNodeId ( FlowNode n ) { none ( ) }
53+
4854 /**
4955 * Holds if data can flow from `n1` to `n2` in one step.
5056 *
@@ -149,17 +155,44 @@ module Make<LocationSig Location, UniversalFlowInput<Location> I> {
149155 private module RankEdge< Edge E> implements RankedEdge< E:: Node > {
150156 private import E
151157
158+ private predicate needsNodeId ( FlowNode n ) { edge ( n , _) }
159+
160+ private int getFlowNodeIdByLoc ( FlowNode n ) {
161+ n =
162+ rank [ result ] ( FlowNode n0 , string filePath , int startline , int startcolumn |
163+ needsNodeId ( n0 ) and
164+ not exists ( getFlowNodeId ( n0 ) ) and
165+ n0 .getLocation ( ) .hasLocationInfo ( filePath , startline , startcolumn , _, _)
166+ |
167+ n0 order by filePath , startline , startcolumn
168+ )
169+ }
170+
171+ private int getFlowNodeIdExt ( FlowNode n ) {
172+ n =
173+ rank [ result ] ( FlowNode n0 , int a , int b |
174+ needsNodeId ( n0 ) and
175+ a = 0 and
176+ b = getFlowNodeId ( n0 )
177+ or
178+ a = 1 and
179+ b = getFlowNodeIdByLoc ( n0 )
180+ |
181+ n0 order by a , b
182+ )
183+ }
184+
152185 /**
153186 * Holds if `r` is a ranking of the incoming edges `(n1,n2)` to `n2`. The used
154187 * ordering is not necessarily total, so the ranking may have gaps.
155188 */
156189 private predicate edgeRank1 ( int r , FlowNode n1 , Node n2 ) {
157190 n1 =
158- rank [ r ] ( FlowNode n , int startline , int startcolumn |
191+ rank [ r ] ( FlowNode n , int id |
159192 edge ( n , n2 ) and
160- n . getLocation ( ) . hasLocationInfo ( _ , startline , startcolumn , _ , _ )
193+ id = getFlowNodeIdExt ( n )
161194 |
162- n order by startline , startcolumn
195+ n order by id
163196 )
164197 }
165198
0 commit comments