Merge pull request #20386 from github/alexet/overlay-informed-dataflow

Dataflow: Overlay informed dataflow.
This commit is contained in:
Alexander Eyers-Taylor
2025-10-07 20:22:57 +01:00
committed by GitHub
8 changed files with 530 additions and 133 deletions

View File

@@ -10,6 +10,6 @@ import java
module DataFlow {
private import semmle.code.java.dataflow.internal.DataFlowImplSpecific
private import codeql.dataflow.DataFlow
import DataFlowMake<Location, JavaDataFlow>
import DataFlowMakeOverlay<Location, JavaDataFlow>
import Public
}

View File

@@ -13,5 +13,5 @@ module TaintTracking {
private import semmle.code.java.dataflow.internal.DataFlowImplSpecific
private import semmle.code.java.dataflow.internal.TaintTrackingImplSpecific
private import codeql.dataflow.TaintTracking
import TaintFlowMake<Location, JavaDataFlow, JavaTaintTracking>
import TaintFlowMakeOverlay<Location, JavaDataFlow, JavaTaintTracking>
}

View File

@@ -6,6 +6,7 @@ module;
private import semmle.code.Location
private import codeql.dataflow.DataFlow
private import semmle.code.java.Overlay
module Private {
import DataFlowPrivate
@@ -29,4 +30,6 @@ module JavaDataFlow implements InputSig<Location> {
predicate mayBenefitFromCallContext = Private::mayBenefitFromCallContext/1;
predicate viableImplInCallContext = Private::viableImplInCallContext/2;
predicate isEvaluatingInOverlay = isOverlay/0;
}

View File

@@ -349,6 +349,18 @@ signature module InputSig<LocationSig Location> {
/** Holds if `fieldFlowBranchLimit` should be ignored for flow going into/out of `c`. */
default predicate ignoreFieldFlowBranchLimit(DataFlowCallable c) { none() }
/**
* Holds if the evaluator is currently evaluating with an overlay. The
* implementation of this predicate needs to be `overlay[local]`. For a
* language with no overlay support, `none()` is a valid implementation.
*
* When called from a local predicate, this predicate holds if we are in the
* overlay-only local evaluation. When called from a global predicate, this
* predicate holds if we are evaluating globally with overlay and base both
* visible.
*/
default predicate isEvaluatingInOverlay() { none() }
}
module Configs<LocationSig Location, InputSig<Location> Lang> {
@@ -645,10 +657,8 @@ private module PathGraphSigMod {
}
}
module DataFlowMake<LocationSig Location, InputSig<Location> Lang> {
private module DataFlowMakeCore<LocationSig Location, InputSig<Location> Lang> {
private import Lang
private import internal.DataFlowImpl::MakeImpl<Location, Lang>
private import internal.DataFlowImplStage1::MakeImplStage1<Location, Lang>
import Configs<Location, Lang>
/**
@@ -691,59 +701,6 @@ module DataFlowMake<LocationSig Location, InputSig<Location> Lang> {
predicate flowToExpr(DataFlowExpr sink);
}
/**
* Constructs a global data flow computation.
*/
module Global<ConfigSig Config> implements GlobalFlowSig {
private module C implements FullStateConfigSig {
import DefaultState<Config>
import Config
predicate accessPathLimit = Config::accessPathLimit/0;
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
Config::isAdditionalFlowStep(node1, node2) and model = "Config"
}
}
private module Stage1 = ImplStage1<C>;
import Stage1::PartialFlow
private module Flow = Impl<C, Stage1::Stage1NoState>;
import Flow
}
/**
* Constructs a global data flow computation using flow state.
*/
module GlobalWithState<StateConfigSig Config> implements GlobalFlowSig {
private module C implements FullStateConfigSig {
import Config
predicate accessPathLimit = Config::accessPathLimit/0;
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
Config::isAdditionalFlowStep(node1, node2) and model = "Config"
}
predicate isAdditionalFlowStep(
Node node1, FlowState state1, Node node2, FlowState state2, string model
) {
Config::isAdditionalFlowStep(node1, state1, node2, state2) and model = "Config"
}
}
private module Stage1 = ImplStage1<C>;
import Stage1::PartialFlow
private module Flow = Impl<C, Stage1::Stage1WithState>;
import Flow
}
signature class PathNodeSig {
/** Gets a textual representation of this element. */
string toString();
@@ -1141,3 +1098,135 @@ module DataFlowMake<LocationSig Location, InputSig<Location> Lang> {
import PathGraph
}
}
module DataFlowMake<LocationSig Location, InputSig<Location> Lang> {
import DataFlowMakeCore<Location, Lang>
private import Lang
private import internal.DataFlowImpl::MakeImpl<Location, Lang>
private import internal.DataFlowImplStage1::MakeImplStage1<Location, Lang>
/**
* Constructs a global data flow computation.
*/
module Global<ConfigSig Config> implements GlobalFlowSig {
private module C implements FullStateConfigSig {
import DefaultState<Config>
import Config
predicate accessPathLimit = Config::accessPathLimit/0;
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
Config::isAdditionalFlowStep(node1, node2) and model = "Config"
}
predicate observeOverlayInformedIncrementalMode() { none() }
}
private module Stage1 = ImplStage1<C>;
import Stage1::PartialFlow
private module Flow = Impl<C, Stage1::Stage1NoState>;
import Flow
}
/**
* Constructs a global data flow computation using flow state.
*/
module GlobalWithState<StateConfigSig Config> implements GlobalFlowSig {
private module C implements FullStateConfigSig {
import Config
predicate accessPathLimit = Config::accessPathLimit/0;
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
Config::isAdditionalFlowStep(node1, node2) and model = "Config"
}
predicate isAdditionalFlowStep(
Node node1, FlowState state1, Node node2, FlowState state2, string model
) {
Config::isAdditionalFlowStep(node1, state1, node2, state2) and model = "Config"
}
predicate observeOverlayInformedIncrementalMode() { none() }
}
private module Stage1 = ImplStage1<C>;
import Stage1::PartialFlow
private module Flow = Impl<C, Stage1::Stage1WithState>;
import Flow
}
}
module DataFlowMakeOverlay<LocationSig Location, InputSig<Location> Lang> {
import DataFlowMake<Location, Lang>
private import Lang
private import internal.DataFlowImpl::MakeImpl<Location, Lang>
private import internal.DataFlowImplStage1::MakeImplStage1<Location, Lang>
/**
* Constructs a global data flow computation.
*/
module Global<ConfigSig Config> implements GlobalFlowSig {
private module C implements FullStateConfigSig {
import DefaultState<Config>
import Config
predicate accessPathLimit = Config::accessPathLimit/0;
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
Config::isAdditionalFlowStep(node1, node2) and model = "Config"
}
predicate observeOverlayInformedIncrementalMode() {
not Config::observeDiffInformedIncrementalMode()
}
}
private module Stage1 = ImplStage1<C>;
import Stage1::PartialFlow
private module Flow = OverlayImpl<C, Stage1::Stage1NoState>;
import Flow
}
/**
* Constructs a global data flow computation using flow state.
*/
module GlobalWithState<StateConfigSig Config> implements GlobalFlowSig {
private module C implements FullStateConfigSig {
import Config
predicate accessPathLimit = Config::accessPathLimit/0;
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
Config::isAdditionalFlowStep(node1, node2) and model = "Config"
}
predicate isAdditionalFlowStep(
Node node1, FlowState state1, Node node2, FlowState state2, string model
) {
Config::isAdditionalFlowStep(node1, state1, node2, state2) and model = "Config"
}
predicate observeOverlayInformedIncrementalMode() {
not Config::observeDiffInformedIncrementalMode()
}
}
private module Stage1 = ImplStage1<C>;
import Stage1::PartialFlow
private module Flow = OverlayImpl<C, Stage1::Stage1WithState>;
import Flow
}
}

View File

@@ -47,16 +47,16 @@ signature module InputSig<LocationSig Location, DF::InputSig<Location> Lang> {
/**
* Construct the modules for taint-tracking analyses.
*/
module TaintFlowMake<
private module TaintFlowMakeCore<
LocationSig Location, DF::InputSig<Location> DataFlowLang,
InputSig<Location, DataFlowLang> TaintTrackingLang>
{
private import TaintTrackingLang
private import DF::DataFlowMake<Location, DataFlowLang> as DataFlow
private import MakeImpl<Location, DataFlowLang> as DataFlowInternal
private import MakeImplStage1<Location, DataFlowLang> as DataFlowInternalStage1
import TaintTrackingLang
import DF::DataFlowMake<Location, DataFlowLang> as DataFlow
import MakeImpl<Location, DataFlowLang> as DataFlowInternal
import MakeImplStage1<Location, DataFlowLang> as DataFlowInternalStage1
private module AddTaintDefaults<DataFlowInternal::FullStateConfigSig Config> implements
module AddTaintDefaults<DataFlowInternal::FullStateConfigSig Config> implements
DataFlowInternal::FullStateConfigSig
{
import Config
@@ -83,71 +83,9 @@ module TaintFlowMake<
}
}
/**
* Constructs a global taint tracking computation.
*/
module Global<DataFlow::ConfigSig Config> implements DataFlow::GlobalFlowSig {
private module Config0 implements DataFlowInternal::FullStateConfigSig {
import DataFlowInternal::DefaultState<Config>
import Config
predicate isAdditionalFlowStep(
DataFlowLang::Node node1, DataFlowLang::Node node2, string model
) {
Config::isAdditionalFlowStep(node1, node2) and model = "Config"
}
}
private module C implements DataFlowInternal::FullStateConfigSig {
import AddTaintDefaults<Config0>
}
private module Stage1 = DataFlowInternalStage1::ImplStage1<C>;
import Stage1::PartialFlow
private module Flow = DataFlowInternal::Impl<C, Stage1::Stage1NoState>;
import Flow
}
/**
* Constructs a global taint tracking computation using flow state.
*/
module GlobalWithState<DataFlow::StateConfigSig Config> implements DataFlow::GlobalFlowSig {
private module Config0 implements DataFlowInternal::FullStateConfigSig {
import Config
predicate isAdditionalFlowStep(
DataFlowLang::Node node1, DataFlowLang::Node node2, string model
) {
Config::isAdditionalFlowStep(node1, node2) and model = "Config"
}
predicate isAdditionalFlowStep(
DataFlowLang::Node node1, FlowState state1, DataFlowLang::Node node2, FlowState state2,
string model
) {
Config::isAdditionalFlowStep(node1, state1, node2, state2) and model = "Config"
}
}
private module C implements DataFlowInternal::FullStateConfigSig {
import AddTaintDefaults<Config0>
}
private module Stage1 = DataFlowInternalStage1::ImplStage1<C>;
import Stage1::PartialFlow
private module Flow = DataFlowInternal::Impl<C, Stage1::Stage1WithState>;
import Flow
}
signature int speculationLimitSig();
private module AddSpeculativeTaintSteps<
module AddSpeculativeTaintSteps<
DataFlowInternal::FullStateConfigSig Config, speculationLimitSig/0 speculationLimit> implements
DataFlowInternal::FullStateConfigSig
{
@@ -215,6 +153,79 @@ module TaintFlowMake<
state1.getState() = state2.getState()
}
}
}
module TaintFlowMake<
LocationSig Location, DF::InputSig<Location> DataFlowLang,
InputSig<Location, DataFlowLang> TaintTrackingLang>
{
private import TaintFlowMakeCore<Location, DataFlowLang, TaintTrackingLang>
/**
* Constructs a global taint tracking computation.
*/
module Global<DataFlow::ConfigSig Config> implements DataFlow::GlobalFlowSig {
private module Config0 implements DataFlowInternal::FullStateConfigSig {
import DataFlowInternal::DefaultState<Config>
import Config
predicate isAdditionalFlowStep(
DataFlowLang::Node node1, DataFlowLang::Node node2, string model
) {
Config::isAdditionalFlowStep(node1, node2) and model = "Config"
}
predicate observeOverlayInformedIncrementalMode() { none() }
}
private module C implements DataFlowInternal::FullStateConfigSig {
import AddTaintDefaults<Config0>
}
private module Stage1 = DataFlowInternalStage1::ImplStage1<C>;
import Stage1::PartialFlow
private module Flow = DataFlowInternal::Impl<C, Stage1::Stage1NoState>;
import Flow
}
/**
* Constructs a global taint tracking computation using flow state.
*/
module GlobalWithState<DataFlow::StateConfigSig Config> implements DataFlow::GlobalFlowSig {
private module Config0 implements DataFlowInternal::FullStateConfigSig {
import Config
predicate isAdditionalFlowStep(
DataFlowLang::Node node1, DataFlowLang::Node node2, string model
) {
Config::isAdditionalFlowStep(node1, node2) and model = "Config"
}
predicate isAdditionalFlowStep(
DataFlowLang::Node node1, FlowState state1, DataFlowLang::Node node2, FlowState state2,
string model
) {
Config::isAdditionalFlowStep(node1, state1, node2, state2) and model = "Config"
}
predicate observeOverlayInformedIncrementalMode() { none() }
}
private module C implements DataFlowInternal::FullStateConfigSig {
import AddTaintDefaults<Config0>
}
private module Stage1 = DataFlowInternalStage1::ImplStage1<C>;
import Stage1::PartialFlow
private module Flow = DataFlowInternal::Impl<C, Stage1::Stage1WithState>;
import Flow
}
/**
* Constructs a global taint tracking computation that also allows a given
@@ -232,6 +243,8 @@ module TaintFlowMake<
) {
Config::isAdditionalFlowStep(node1, node2) and model = "Config"
}
predicate observeOverlayInformedIncrementalMode() { none() }
}
private module C implements DataFlowInternal::FullStateConfigSig {
@@ -270,6 +283,8 @@ module TaintFlowMake<
) {
Config::isAdditionalFlowStep(node1, state1, node2, state2) and model = "Config"
}
predicate observeOverlayInformedIncrementalMode() { none() }
}
private module C implements DataFlowInternal::FullStateConfigSig {
@@ -285,3 +300,157 @@ module TaintFlowMake<
import Flow
}
}
module TaintFlowMakeOverlay<
LocationSig Location, DF::InputSig<Location> DataFlowLang,
InputSig<Location, DataFlowLang> TaintTrackingLang>
{
private import TaintFlowMakeCore<Location, DataFlowLang, TaintTrackingLang>
/**
* Constructs a global taint tracking computation.
*/
module Global<DataFlow::ConfigSig Config> implements DataFlow::GlobalFlowSig {
private module Config0 implements DataFlowInternal::FullStateConfigSig {
import DataFlowInternal::DefaultState<Config>
import Config
predicate isAdditionalFlowStep(
DataFlowLang::Node node1, DataFlowLang::Node node2, string model
) {
Config::isAdditionalFlowStep(node1, node2) and model = "Config"
}
predicate observeOverlayInformedIncrementalMode() {
not Config::observeDiffInformedIncrementalMode()
}
}
private module C implements DataFlowInternal::FullStateConfigSig {
import AddTaintDefaults<Config0>
}
private module Stage1 = DataFlowInternalStage1::ImplStage1<C>;
import Stage1::PartialFlow
private module Flow = DataFlowInternal::OverlayImpl<C, Stage1::Stage1NoState>;
import Flow
}
/**
* Constructs a global taint tracking computation using flow state.
*/
module GlobalWithState<DataFlow::StateConfigSig Config> implements DataFlow::GlobalFlowSig {
private module Config0 implements DataFlowInternal::FullStateConfigSig {
import Config
predicate isAdditionalFlowStep(
DataFlowLang::Node node1, DataFlowLang::Node node2, string model
) {
Config::isAdditionalFlowStep(node1, node2) and model = "Config"
}
predicate isAdditionalFlowStep(
DataFlowLang::Node node1, FlowState state1, DataFlowLang::Node node2, FlowState state2,
string model
) {
Config::isAdditionalFlowStep(node1, state1, node2, state2) and model = "Config"
}
predicate observeOverlayInformedIncrementalMode() {
not Config::observeDiffInformedIncrementalMode()
}
}
private module C implements DataFlowInternal::FullStateConfigSig {
import AddTaintDefaults<Config0>
}
private module Stage1 = DataFlowInternalStage1::ImplStage1<C>;
import Stage1::PartialFlow
private module Flow = DataFlowInternal::OverlayImpl<C, Stage1::Stage1WithState>;
import Flow
}
/**
* Constructs a global taint tracking computation that also allows a given
* maximum number of speculative taint steps.
*/
module SpeculativeGlobal<DataFlow::ConfigSig Config, speculationLimitSig/0 speculationLimit>
implements DataFlow::GlobalFlowSig
{
private module Config0 implements DataFlowInternal::FullStateConfigSig {
import DataFlowInternal::DefaultState<Config>
import Config
predicate isAdditionalFlowStep(
DataFlowLang::Node node1, DataFlowLang::Node node2, string model
) {
Config::isAdditionalFlowStep(node1, node2) and model = "Config"
}
predicate observeOverlayInformedIncrementalMode() {
not Config::observeDiffInformedIncrementalMode()
}
}
private module C implements DataFlowInternal::FullStateConfigSig {
import AddTaintDefaults<AddSpeculativeTaintSteps<Config0, speculationLimit/0>>
}
private module Stage1 = DataFlowInternalStage1::ImplStage1<C>;
import Stage1::PartialFlow
private module Flow = DataFlowInternal::OverlayImpl<C, Stage1::Stage1WithState>;
import Flow
}
/**
* Constructs a global taint tracking computation using flow state that also
* allows a given maximum number of speculative taint steps.
*/
module SpeculativeGlobalWithState<
DataFlow::StateConfigSig Config, speculationLimitSig/0 speculationLimit> implements
DataFlow::GlobalFlowSig
{
private module Config0 implements DataFlowInternal::FullStateConfigSig {
import Config
predicate isAdditionalFlowStep(
DataFlowLang::Node node1, DataFlowLang::Node node2, string model
) {
Config::isAdditionalFlowStep(node1, node2) and model = "Config"
}
predicate isAdditionalFlowStep(
DataFlowLang::Node node1, FlowState state1, DataFlowLang::Node node2, FlowState state2,
string model
) {
Config::isAdditionalFlowStep(node1, state1, node2, state2) and model = "Config"
}
predicate observeOverlayInformedIncrementalMode() {
not Config::observeDiffInformedIncrementalMode()
}
}
private module C implements DataFlowInternal::FullStateConfigSig {
import AddTaintDefaults<AddSpeculativeTaintSteps<Config0, speculationLimit/0>>
}
private module Stage1 = DataFlowInternalStage1::ImplStage1<C>;
import Stage1::PartialFlow
private module Flow = DataFlowInternal::OverlayImpl<C, Stage1::Stage1WithState>;
import Flow
}
}

View File

@@ -143,6 +143,15 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
*/
predicate observeDiffInformedIncrementalMode();
/**
* Holds if sources and sinks should be filtered to only include those that
* may lead to a flow path with either a source or a sink in the overlay database.
* This only has an effect when running
* in overlay-informed incremental mode. This should be used in conjunction
* with the `OverlayImpl` implementation to merge the base results back in.
*/
predicate observeOverlayInformedIncrementalMode();
Location getASelectedSourceLocation(Node source);
Location getASelectedSinkLocation(Node sink);
@@ -171,6 +180,56 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
}
}
/**
* Constructs a data flow computation given a full input configuration, and
* an initial stage 1 pruning with merging of overlay and base results.
*/
module OverlayImpl<FullStateConfigSig Config, Stage1Output<Config::FlowState> Stage1> {
private module Flow = Impl<Config, Stage1>;
import Flow
/**
* Holds if data can flow from `source` to `sink`.
*
* This is a local predicate that only has results local to the overlay/base database.
*/
private predicate flowLocal(Node source, Node sink) = forceLocal(Flow::flow/2)(source, sink)
/**
* Holds if data can flow from `source` to `sink`.
*/
predicate flow(Node source, Node sink) {
Flow::flow(source, sink)
or
// If we are overlay informed (i.e. we are not diff-informed), we
// merge in the local results which includes the base database results.
flowLocal(source, sink) and Config::observeOverlayInformedIncrementalMode()
}
/**
* Holds if data can flow from some source to `sink`.
* This is a local predicate that only has results local to the overlay/base database.
*/
predicate flowToLocal(Node sink) = forceLocal(Flow::flowTo/1)(sink)
/**
* Holds if data can flow from some source to `sink`.
*/
predicate flowTo(Node sink) {
Flow::flowTo(sink)
or
// If we are overlay informed (i.e. we are not diff-informed), we
// merge in the local results which includes the base database results.
flowToLocal(sink) and Config::observeOverlayInformedIncrementalMode()
}
/**
* Holds if data can flow from some source to `sink`.
*/
predicate flowToExpr(Lang::DataFlowExpr sink) { flowTo(exprNode(sink)) }
}
/**
* Constructs a data flow computation given a full input configuration, and
* an initial stage 1 pruning.

View File

@@ -4,7 +4,7 @@
* Provides an implementation of a fast initial pruning of global
* (interprocedural) data flow reachability (Stage 1).
*/
overlay[local?]
overlay[local?] // when this is removed, put `overlay[local?]` on `isOverlayNode`.
module;
private import codeql.util.Unit
@@ -129,23 +129,76 @@ module MakeImplStage1<LocationSig Location, InputSig<Location> Lang> {
private module AlertFiltering = AlertFilteringImpl<Location>;
/**
* Holds if the given node is visible in overlay-only local evaluation.
*
* This predicate needs to be `overlay[local?]`, either directly or
* through annotations from an outer scope. If `Node` is global for the
* language under analysis, then every node is considered an overlay
* node, which means there will effectively be no overlay-based
* filtering of sources and sinks.
*/
private predicate isOverlayNode(Node node) {
isEvaluatingInOverlay() and
// Any local node is an overlay node if we are evaluating in overlay mode
exists(node)
}
/**
* The filtering if we aren't meant to be diff-informed.
*
* Shared between sources and sinks.
*/
overlay[global]
pragma[inline]
private predicate nonDiffInformedFilter(Node node) {
// If we are in base-only global evaluation, do not filter out any sources/sinks.
not isEvaluatingInOverlay()
or
// If the configuration doesn't merge overlays, do not filter out any sources/sinks.
not Config::observeOverlayInformedIncrementalMode()
or
// If we are in global evaluation with an overlay present, restrict
// sources/sinks to those visible in the overlay.
isOverlayNode(node)
}
overlay[global]
pragma[nomagic]
private predicate isFilteredSource(Node source) {
Config::isSource(source, _) and
// Data flow is always incremental in one of two ways.
// 1. If the configuration is diff-informed, we filter to only include nodes in the diff,
// which gives the smallest set of nodes.
// If diff information is not available, we do not filter at all.
// 2. If not, in global evaluation with overlay, we filter to only
// include nodes from files in the overlay; flow from
// other nodes will be added back later.
// We start by seeing if we should be in case 1.
if Config::observeDiffInformedIncrementalMode()
then AlertFiltering::filterByLocation(Config::getASelectedSourceLocation(source))
else any()
then
// Case 1: We are meant to be diff-informed.
// We still only filter if we have diff information.
AlertFiltering::diffInformationAvailable()
implies
AlertFiltering::locationIsInDiff(Config::getASelectedSourceLocation(source))
else nonDiffInformedFilter(source)
}
overlay[global]
pragma[nomagic]
private predicate isFilteredSink(Node sink) {
(
Config::isSink(sink, _) or
Config::isSink(sink)
) and
// See the comments in `isFilteredSource` for the reasoning behind the following.
if Config::observeDiffInformedIncrementalMode()
then AlertFiltering::filterByLocation(Config::getASelectedSinkLocation(sink))
else any()
then
AlertFiltering::diffInformationAvailable()
implies
AlertFiltering::locationIsInDiff(Config::getASelectedSinkLocation(sink))
else nonDiffInformedFilter(sink)
}
private predicate hasFilteredSource() { isFilteredSource(_) }

View File

@@ -82,6 +82,21 @@ module AlertFilteringImpl<LocationSig Location> {
)
}
/** Holds if diff information is available in this evaluation. */
predicate diffInformationAvailable() {
restrictAlertsTo(_, _, _) or restrictAlertsToExactLocation(_, _, _, _, _)
}
/**
* Holds if diff information is available, and `filePath` is in the diff
* range.
*/
predicate fileIsInDiff(string filePath) {
restrictAlertsTo(filePath, _, _)
or
restrictAlertsToExactLocation(filePath, _, _, _, _)
}
/**
* Holds if the given location is a match for one of the active filtering
* predicates in this module, or if all filtering predicates are inactive
@@ -92,8 +107,17 @@ module AlertFilteringImpl<LocationSig Location> {
*/
bindingset[location]
predicate filterByLocation(Location location) {
not restrictAlertsTo(_, _, _) and not restrictAlertsToExactLocation(_, _, _, _, _)
not diffInformationAvailable()
or
locationIsInDiff(location)
}
/**
* Like `filterByLocation`, except that if there is no diff range, this
* predicate never holds.
*/
bindingset[location]
predicate locationIsInDiff(Location location) {
exists(string filePath |
restrictAlertsToEntireFile(filePath) and
location.hasLocationInfo(filePath, _, _, _, _)