@@ -147,6 +147,12 @@ abstract class Configuration extends string {
147
147
*/
148
148
FlowFeature getAFeature ( ) { none ( ) }
149
149
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
+
150
156
/**
151
157
* Holds if data may flow from `source` to `sink` for this configuration.
152
158
*/
@@ -158,7 +164,7 @@ abstract class Configuration extends string {
158
164
* The corresponding paths are generated from the end-points and the graph
159
165
* included in the module `PathGraph`.
160
166
*/
161
- predicate hasFlowPath ( PathNode source , PathNode sink ) { flowsTo ( source , sink , _ , _ , this ) }
167
+ predicate hasFlowPath ( PathNode source , PathNode sink ) { hasFlowPath ( source , sink , this ) }
162
168
163
169
/**
164
170
* Holds if data may flow from some source to `sink` for this configuration.
@@ -2712,6 +2718,18 @@ private newtype TPathNode =
2712
2718
state = sink .getState ( ) and
2713
2719
config = sink .getConfiguration ( )
2714
2720
)
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
+ )
2715
2733
}
2716
2734
2717
2735
/**
@@ -2920,6 +2938,22 @@ abstract private class PathNodeImpl extends TPathNode {
2920
2938
)
2921
2939
}
2922
2940
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
+
2923
2957
private string ppAp ( ) {
2924
2958
this instanceof PathNodeSink and result = ""
2925
2959
or
@@ -2959,7 +2993,9 @@ abstract private class PathNodeImpl extends TPathNode {
2959
2993
2960
2994
/** Holds if `n` can reach a sink. */
2961
2995
private 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 ( ) )
2963
2999
}
2964
3000
2965
3001
/** 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 {
3015
3051
3016
3052
/** Holds if this node is a source. */
3017
3053
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 , _) }
3018
3060
}
3019
3061
3020
3062
/**
@@ -3136,9 +3178,66 @@ private class PathNodeSink extends PathNodeImpl, TPathNodeSink {
3136
3178
3137
3179
override Configuration getConfiguration ( ) { result = config }
3138
3180
3139
- override PathNodeImpl getASuccessorImpl ( ) { none ( ) }
3181
+ override PathNodeImpl getASuccessorImpl ( ) {
3182
+ result = TPathNodeSinkGroup ( this .getSinkGroup ( ) , config )
3183
+ }
3140
3184
3141
3185
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
+ }
3142
3241
}
3143
3242
3144
3243
private predicate pathNode (
@@ -3495,6 +3594,15 @@ private module Subpaths {
3495
3594
* Will only have results if `configuration` has non-empty sources and
3496
3595
* sinks.
3497
3596
*/
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
+
3498
3606
private predicate flowsTo (
3499
3607
PathNodeImpl flowsource , PathNodeSink flowsink , Node source , Node sink ,
3500
3608
Configuration configuration
0 commit comments