@@ -158,16 +158,16 @@ private predicate joinStep(TypeFlowNode n1, TypeFlowNode n2) {
158158
159159private predicate anyStep ( TypeFlowNode n1 , TypeFlowNode n2 ) { joinStep ( n1 , n2 ) or step ( n1 , n2 ) }
160160
161- private predicate sccEdge ( TypeFlowNode n1 , TypeFlowNode n2 ) { anyStep ( n1 , n2 ) and anyStep + ( n2 , n1 ) }
161+ private import SccReduction
162162
163- /*
163+ /**
164164 * SCC reduction.
165165 *
166166 * This ought to be as easy as `equivalenceRelation(sccEdge/2)(n, scc)`, but
167167 * this HOP is not currently supported for newtypes.
168168 *
169169 * A straightforward implementation would be:
170- * ```
170+ * ```ql
171171 * predicate sccRepr(TypeFlowNode n, TypeFlowNode scc) {
172172 * scc =
173173 * max(TypeFlowNode n2 |
@@ -182,60 +182,67 @@ private predicate sccEdge(TypeFlowNode n1, TypeFlowNode n2) { anyStep(n1, n2) an
182182 * ```
183183 * but this is quadratic in the size of the SCCs.
184184 *
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.
186187 * (This is still worst-case quadratic in the size of the SCCs, but generally
187188 * performs better.)
188189 */
190+ private module SccReduction {
191+ private predicate sccEdge ( TypeFlowNode n1 , TypeFlowNode n2 ) {
192+ anyStep ( n1 , n2 ) and anyStep + ( n2 , n1 )
193+ }
189194
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+ }
199204
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+ }
209214
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+ }
214219
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+ }
228233
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+ }
232238
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+ }
239246}
240247
241248private signature predicate edgeSig ( TypeFlowNode n1 , TypeFlowNode n2 ) ;
@@ -247,6 +254,10 @@ private signature module RankedEdge {
247254}
248255
249256private 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+ */
250261 private predicate edgeRank1 ( int r , TypeFlowNode n1 , TypeFlowNode n2 ) {
251262 n1 =
252263 rank [ r ] ( TypeFlowNode n |
@@ -256,10 +267,15 @@ private module RankEdge<edgeSig/2 edge> implements RankedEdge {
256267 )
257268 }
258269
270+ /**
271+ * Holds if `r2` is a ranking of the ranks from `edgeRank1`. This removes the
272+ * gaps from the ranking.
273+ */
259274 private predicate edgeRank2 ( int r2 , int r1 , TypeFlowNode n ) {
260275 r1 = rank [ r2 ] ( int r | edgeRank1 ( r , _, n ) | r )
261276 }
262277
278+ /** Holds if `r` is a ranking of the incoming edges `(n1,n2)` to `n2`. */
263279 predicate edgeRank ( int r , TypeFlowNode n1 , TypeFlowNode n2 ) {
264280 exists ( int r1 |
265281 edgeRank1 ( r1 , n1 , n2 ) and
0 commit comments