@@ -147,6 +147,12 @@ abstract class Configuration extends string {
147147 */
148148 FlowFeature getAFeature ( ) { none ( ) }
149149
150+ /** Holds if sources should be grouped in the result of `hasFlowPath`. */
151+ predicate sourceGrouping ( Node source , string sourceGroup ) { none ( ) }
152+
153+ /** Holds if sinks should be grouped in the result of `hasFlowPath`. */
154+ predicate sinkGrouping ( Node sink , string sinkGroup ) { none ( ) }
155+
150156 /**
151157 * Holds if data may flow from `source` to `sink` for this configuration.
152158 */
@@ -158,7 +164,7 @@ abstract class Configuration extends string {
158164 * The corresponding paths are generated from the end-points and the graph
159165 * included in the module `PathGraph`.
160166 */
161- predicate hasFlowPath ( PathNode source , PathNode sink ) { flowsTo ( source , sink , _ , _ , this ) }
167+ predicate hasFlowPath ( PathNode source , PathNode sink ) { hasFlowPath ( source , sink , this ) }
162168
163169 /**
164170 * Holds if data may flow from some source to `sink` for this configuration.
@@ -2712,6 +2718,18 @@ private newtype TPathNode =
27122718 state = sink .getState ( ) and
27132719 config = sink .getConfiguration ( )
27142720 )
2721+ } or
2722+ TPathNodeSourceGroup ( string sourceGroup , Configuration config ) {
2723+ exists ( PathNodeImpl source |
2724+ sourceGroup = source .getSourceGroup ( ) and
2725+ config = source .getConfiguration ( )
2726+ )
2727+ } or
2728+ TPathNodeSinkGroup ( string sinkGroup , Configuration config ) {
2729+ exists ( PathNodeSink sink |
2730+ sinkGroup = sink .getSinkGroup ( ) and
2731+ config = sink .getConfiguration ( )
2732+ )
27152733 }
27162734
27172735/**
@@ -2920,6 +2938,22 @@ abstract private class PathNodeImpl extends TPathNode {
29202938 )
29212939 }
29222940
2941+ string getSourceGroup ( ) {
2942+ this .isSource ( ) and
2943+ this .getConfiguration ( ) .sourceGrouping ( this .getNodeEx ( ) .asNode ( ) , result )
2944+ }
2945+
2946+ predicate isFlowSource ( ) {
2947+ this .isSource ( ) and not exists ( this .getSourceGroup ( ) )
2948+ or
2949+ this instanceof PathNodeSourceGroup
2950+ }
2951+
2952+ predicate isFlowSink ( ) {
2953+ this = any ( PathNodeSink sink | not exists ( sink .getSinkGroup ( ) ) ) or
2954+ this instanceof PathNodeSinkGroup
2955+ }
2956+
29232957 private string ppAp ( ) {
29242958 this instanceof PathNodeSink and result = ""
29252959 or
@@ -2959,7 +2993,9 @@ abstract private class PathNodeImpl extends TPathNode {
29592993
29602994/** Holds if `n` can reach a sink. */
29612995private predicate directReach ( PathNodeImpl n ) {
2962- n instanceof PathNodeSink or directReach ( n .getANonHiddenSuccessor ( ) )
2996+ n instanceof PathNodeSink or
2997+ n instanceof PathNodeSinkGroup or
2998+ directReach ( n .getANonHiddenSuccessor ( ) )
29632999}
29643000
29653001/** Holds if `n` can reach a sink or is used in a subpath that can reach a sink. */
@@ -3015,6 +3051,12 @@ class PathNode instanceof PathNodeImpl {
30153051
30163052 /** Holds if this node is a source. */
30173053 final predicate isSource ( ) { super .isSource ( ) }
3054+
3055+ /** Holds if this node is a grouping of source nodes. */
3056+ final predicate isSourceGroup ( string group ) { this = TPathNodeSourceGroup ( group , _) }
3057+
3058+ /** Holds if this node is a grouping of sink nodes. */
3059+ final predicate isSinkGroup ( string group ) { this = TPathNodeSinkGroup ( group , _) }
30183060}
30193061
30203062/**
@@ -3136,9 +3178,66 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
31363178
31373179 override Configuration getConfiguration ( ) { result = config }
31383180
3139- override PathNodeImpl getASuccessorImpl ( ) { none ( ) }
3181+ override PathNodeImpl getASuccessorImpl ( ) {
3182+ result = TPathNodeSinkGroup ( this .getSinkGroup ( ) , config )
3183+ }
31403184
31413185 override predicate isSource ( ) { sourceNode ( node , state , config ) }
3186+
3187+ string getSinkGroup ( ) { config .sinkGrouping ( node .asNode ( ) , result ) }
3188+ }
3189+
3190+ private class PathNodeSourceGroup extends PathNodeImpl , TPathNodeSourceGroup {
3191+ string sourceGroup ;
3192+ Configuration config ;
3193+
3194+ PathNodeSourceGroup ( ) { this = TPathNodeSourceGroup ( sourceGroup , config ) }
3195+
3196+ override NodeEx getNodeEx ( ) { none ( ) }
3197+
3198+ override FlowState getState ( ) { none ( ) }
3199+
3200+ override Configuration getConfiguration ( ) { result = config }
3201+
3202+ override PathNodeImpl getASuccessorImpl ( ) {
3203+ result .getSourceGroup ( ) = sourceGroup and
3204+ result .getConfiguration ( ) = config
3205+ }
3206+
3207+ override predicate isSource ( ) { none ( ) }
3208+
3209+ override string toString ( ) { result = sourceGroup }
3210+
3211+ override predicate hasLocationInfo (
3212+ string filepath , int startline , int startcolumn , int endline , int endcolumn
3213+ ) {
3214+ filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
3215+ }
3216+ }
3217+
3218+ private class PathNodeSinkGroup extends PathNodeImpl , TPathNodeSinkGroup {
3219+ string sinkGroup ;
3220+ Configuration config ;
3221+
3222+ PathNodeSinkGroup ( ) { this = TPathNodeSinkGroup ( sinkGroup , config ) }
3223+
3224+ override NodeEx getNodeEx ( ) { none ( ) }
3225+
3226+ override FlowState getState ( ) { none ( ) }
3227+
3228+ override Configuration getConfiguration ( ) { result = config }
3229+
3230+ override PathNodeImpl getASuccessorImpl ( ) { none ( ) }
3231+
3232+ override predicate isSource ( ) { none ( ) }
3233+
3234+ override string toString ( ) { result = sinkGroup }
3235+
3236+ override predicate hasLocationInfo (
3237+ string filepath , int startline , int startcolumn , int endline , int endcolumn
3238+ ) {
3239+ filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
3240+ }
31423241}
31433242
31443243private predicate pathNode (
@@ -3495,6 +3594,15 @@ private module Subpaths {
34953594 * Will only have results if `configuration` has non-empty sources and
34963595 * sinks.
34973596 */
3597+ private predicate hasFlowPath (
3598+ PathNodeImpl flowsource , PathNodeImpl flowsink , Configuration configuration
3599+ ) {
3600+ flowsource .isFlowSource ( ) and
3601+ flowsource .getConfiguration ( ) = configuration and
3602+ ( flowsource = flowsink or pathSuccPlus ( flowsource , flowsink ) ) and
3603+ flowsink .isFlowSink ( )
3604+ }
3605+
34983606private predicate flowsTo (
34993607 PathNodeImpl flowsource , PathNodeSink flowsink , Node source , Node sink ,
35003608 Configuration configuration
0 commit comments