@@ -158,16 +158,16 @@ private predicate joinStep(TypeFlowNode n1, TypeFlowNode n2) {
158
158
159
159
private predicate anyStep ( TypeFlowNode n1 , TypeFlowNode n2 ) { joinStep ( n1 , n2 ) or step ( n1 , n2 ) }
160
160
161
- private predicate sccEdge ( TypeFlowNode n1 , TypeFlowNode n2 ) { anyStep ( n1 , n2 ) and anyStep + ( n2 , n1 ) }
161
+ private import SccReduction
162
162
163
- /*
163
+ /**
164
164
* SCC reduction.
165
165
*
166
166
* This ought to be as easy as `equivalenceRelation(sccEdge/2)(n, scc)`, but
167
167
* this HOP is not currently supported for newtypes.
168
168
*
169
169
* A straightforward implementation would be:
170
- * ```
170
+ * ```ql
171
171
* predicate sccRepr(TypeFlowNode n, TypeFlowNode scc) {
172
172
* scc =
173
173
* max(TypeFlowNode n2 |
@@ -182,60 +182,67 @@ private predicate sccEdge(TypeFlowNode n1, TypeFlowNode n2) { anyStep(n1, n2) an
182
182
* ```
183
183
* but this is quadratic in the size of the SCCs.
184
184
*
185
- * Instead we find local maxima and determine the SCC representatives from those.
185
+ * Instead we find local maxima by following SCC edges and determine the SCC
186
+ * representatives from those.
186
187
* (This is still worst-case quadratic in the size of the SCCs, but generally
187
188
* performs better.)
188
189
*/
190
+ private module SccReduction {
191
+ private predicate sccEdge ( TypeFlowNode n1 , TypeFlowNode n2 ) {
192
+ anyStep ( n1 , n2 ) and anyStep + ( n2 , n1 )
193
+ }
189
194
190
- private predicate sccEdgeWithMax ( TypeFlowNode n1 , TypeFlowNode n2 , TypeFlowNode m ) {
191
- sccEdge ( n1 , n2 ) and
192
- m =
193
- max ( TypeFlowNode n |
194
- n = [ n1 , n2 ]
195
- |
196
- n order by n .getLocation ( ) .getStartLine ( ) , n .getLocation ( ) .getStartColumn ( ) , getNodeKind ( n )
197
- )
198
- }
195
+ private predicate sccEdgeWithMax ( TypeFlowNode n1 , TypeFlowNode n2 , TypeFlowNode m ) {
196
+ sccEdge ( n1 , n2 ) and
197
+ m =
198
+ max ( TypeFlowNode n |
199
+ n = [ n1 , n2 ]
200
+ |
201
+ n order by n .getLocation ( ) .getStartLine ( ) , n .getLocation ( ) .getStartColumn ( ) , getNodeKind ( n )
202
+ )
203
+ }
199
204
200
- private predicate hasLargerNeighbor ( TypeFlowNode n ) {
201
- exists ( TypeFlowNode n2 |
202
- sccEdgeWithMax ( n , n2 , n2 ) and
203
- not sccEdgeWithMax ( n , n2 , n )
204
- or
205
- sccEdgeWithMax ( n2 , n , n2 ) and
206
- not sccEdgeWithMax ( n2 , n , n )
207
- )
208
- }
205
+ private predicate hasLargerNeighbor ( TypeFlowNode n ) {
206
+ exists ( TypeFlowNode n2 |
207
+ sccEdgeWithMax ( n , n2 , n2 ) and
208
+ not sccEdgeWithMax ( n , n2 , n )
209
+ or
210
+ sccEdgeWithMax ( n2 , n , n2 ) and
211
+ not sccEdgeWithMax ( n2 , n , n )
212
+ )
213
+ }
209
214
210
- private predicate localMax ( TypeFlowNode m ) {
211
- sccEdgeWithMax ( _, _, m ) and
212
- not hasLargerNeighbor ( m )
213
- }
215
+ private predicate localMax ( TypeFlowNode m ) {
216
+ sccEdgeWithMax ( _, _, m ) and
217
+ not hasLargerNeighbor ( m )
218
+ }
214
219
215
- private predicate sccReprFromLocalMax ( TypeFlowNode scc ) {
216
- exists ( TypeFlowNode m |
217
- localMax ( m ) and
218
- scc =
219
- max ( TypeFlowNode n2 |
220
- sccEdge + ( m , n2 ) and localMax ( n2 )
221
- |
222
- n2
223
- order by
224
- n2 .getLocation ( ) .getStartLine ( ) , n2 .getLocation ( ) .getStartColumn ( ) , getNodeKind ( n2 )
225
- )
226
- )
227
- }
220
+ private predicate sccReprFromLocalMax ( TypeFlowNode scc ) {
221
+ exists ( TypeFlowNode m |
222
+ localMax ( m ) and
223
+ scc =
224
+ max ( TypeFlowNode n2 |
225
+ sccEdge + ( m , n2 ) and localMax ( n2 )
226
+ |
227
+ n2
228
+ order by
229
+ n2 .getLocation ( ) .getStartLine ( ) , n2 .getLocation ( ) .getStartColumn ( ) , getNodeKind ( n2 )
230
+ )
231
+ )
232
+ }
228
233
229
- private predicate sccRepr ( TypeFlowNode n , TypeFlowNode scc ) {
230
- sccEdge + ( n , scc ) and sccReprFromLocalMax ( scc )
231
- }
234
+ /** Holds if `n` is part of an SCC of size 2 or more represented by `scc`. */
235
+ predicate sccRepr ( TypeFlowNode n , TypeFlowNode scc ) {
236
+ sccEdge + ( n , scc ) and sccReprFromLocalMax ( scc )
237
+ }
232
238
233
- private predicate sccJoinStep ( TypeFlowNode n , TypeFlowNode scc ) {
234
- exists ( TypeFlowNode mid |
235
- joinStep ( n , mid ) and
236
- sccRepr ( mid , scc ) and
237
- not sccRepr ( n , scc )
238
- )
239
+ predicate sccJoinStep ( TypeFlowNode n , TypeFlowNode scc ) {
240
+ exists ( TypeFlowNode mid |
241
+ joinStep ( n , mid ) and
242
+ sccRepr ( mid , scc ) and
243
+ not sccRepr ( n , scc )
244
+ )
245
+ }
239
246
}
240
247
241
248
private signature predicate edgeSig ( TypeFlowNode n1 , TypeFlowNode n2 ) ;
@@ -247,6 +254,10 @@ private signature module RankedEdge {
247
254
}
248
255
249
256
private module RankEdge< edgeSig / 2 edge> implements RankedEdge {
257
+ /**
258
+ * Holds if `r` is a ranking of the incoming edges `(n1,n2)` to `n2`. The used
259
+ * ordering is not necessarily total, so the ranking may have gaps.
260
+ */
250
261
private predicate edgeRank1 ( int r , TypeFlowNode n1 , TypeFlowNode n2 ) {
251
262
n1 =
252
263
rank [ r ] ( TypeFlowNode n |
@@ -256,10 +267,15 @@ private module RankEdge<edgeSig/2 edge> implements RankedEdge {
256
267
)
257
268
}
258
269
270
+ /**
271
+ * Holds if `r2` is a ranking of the ranks from `edgeRank1`. This removes the
272
+ * gaps from the ranking.
273
+ */
259
274
private predicate edgeRank2 ( int r2 , int r1 , TypeFlowNode n ) {
260
275
r1 = rank [ r2 ] ( int r | edgeRank1 ( r , _, n ) | r )
261
276
}
262
277
278
+ /** Holds if `r` is a ranking of the incoming edges `(n1,n2)` to `n2`. */
263
279
predicate edgeRank ( int r , TypeFlowNode n1 , TypeFlowNode n2 ) {
264
280
exists ( int r1 |
265
281
edgeRank1 ( r1 , n1 , n2 ) and
0 commit comments