@@ -184,7 +184,6 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
184184
185185 string toString ( ) { result = "DataFlow::DiffInformedQuery" }
186186
187- // TODO: how to wire this up? It overlaps with the data-flow configuration signature!
188187 Location getASelectedSourceLocation ( Node source ) { result = source .getLocation ( ) }
189188
190189 Location getASelectedSinkLocation ( Node sink ) { result = sink .getLocation ( ) }
@@ -200,6 +199,90 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
200199 }
201200 }
202201
202+ module MakePrimaryDiffInformed< FullStateConfigSig Config> implements FullStateConfigSig {
203+ // Workaround for name clash
204+ predicate accessPathLimit = Config:: accessPathLimit / 0 ;
205+
206+ import Config
207+
208+ predicate observeDiffInformedIncrementalMode ( ) {
209+ // Add to existing configuration to support composition of config transformers
210+ Config:: observeDiffInformedIncrementalMode ( )
211+ or
212+ exists ( DiffInformedQueryImpl q )
213+ }
214+
215+ Location getASelectedSourceLocation ( Node source ) {
216+ result = Config:: getASelectedSourceLocation ( source )
217+ or
218+ exists ( DiffInformedQueryImpl q | result = q .getASelectedSourceLocation ( source ) )
219+ }
220+
221+ Location getASelectedSinkLocation ( Node sink ) {
222+ result = Config:: getASelectedSinkLocation ( sink )
223+ or
224+ exists ( DiffInformedQueryImpl q | result = q .getASelectedSinkLocation ( sink ) )
225+ }
226+ }
227+
228+ module SecondaryConfigHelpers {
229+ newtype IsSourceOrSink =
230+ IsSource ( ) or
231+ IsSink ( )
232+
233+ signature module SecondaryConfig {
234+ /**
235+ * Gets the source/sink node from the primary configuration that is
236+ * informed by a given source/sink node from the secondary configuration.
237+ * Whether the secondary node is a source or a sink is determined by
238+ * `sourceOrSink`.
239+ */
240+ bindingset [ sourceOrSink, secondaryNode]
241+ Node getPrimaryOfSecondaryNode ( IsSourceOrSink sourceOrSink , Node secondaryNode ) ;
242+ }
243+ }
244+
245+ module MakeSinkFinder< FullStateConfigSig Config, SecondaryConfig SC> implements FullStateConfigSig
246+ {
247+ // Workaround for name clash
248+ predicate accessPathLimit = Config:: accessPathLimit / 0 ;
249+
250+ import Config
251+
252+ predicate observeDiffInformedIncrementalMode ( ) {
253+ // Add to existing configuration to support composition of config transformers
254+ Config:: observeDiffInformedIncrementalMode ( )
255+ or
256+ // Because this configuration is for finding sinks to be used in a main
257+ // data-flow configuration, this configuration should only restrict the
258+ // sinks to be found if there are no main-configuration sources in the
259+ // diff range. That's because if there is such a source, we need to
260+ // report query results for it even with sinks outside the diff range.
261+ //
262+ // The `MakeSinkFinder` and `MakeSourceFinder` modules are separate
263+ // because each can only call one of `hasSourceInDiffRange` or
264+ // `hasSinkInDiffRange`. Otherwise it would look like a non-monotonic
265+ // recursion.
266+ exists ( DiffInformedQuery q | not q .hasSourceInDiffRange ( ) )
267+ }
268+
269+ Location getASelectedSourceLocation ( Node source ) {
270+ result = Config:: getASelectedSourceLocation ( source )
271+ or
272+ exists ( DiffInformedQueryImpl q , IsSource s |
273+ result = q .getASelectedSourceLocation ( SC:: getPrimaryOfSecondaryNode ( s , source ) )
274+ )
275+ }
276+
277+ Location getASelectedSinkLocation ( Node sink ) {
278+ result = Config:: getASelectedSinkLocation ( sink )
279+ or
280+ exists ( DiffInformedQueryImpl q , IsSink s |
281+ result = q .getASelectedSinkLocation ( SC:: getPrimaryOfSecondaryNode ( s , sink ) )
282+ )
283+ }
284+ }
285+
203286 /**
204287 * Constructs a data flow computation given a full input configuration, and
205288 * an initial stage 1 pruning.
0 commit comments