@@ -8,15 +8,14 @@ module;
8
8
private import codeql.util.Location
9
9
10
10
/ * *
11
- * Holds if the query should produce alerts that match the given line ranges.
11
+ * Holds if the query may restrict its computation to only produce alerts that match the given line
12
+ * ranges. This predicate is used for implementing _diff- informed queries_ for pull requests in
13
+ * GitHub Code Scanning.
12
14
*
13
15
* This predicate is active if and only if it is nonempty. If this predicate is inactive, it has no
14
- * effect. If it is active, it accepts any alert that has at least one matching location.
15
- *
16
- * Note that an alert that is not accepted by this filtering predicate may still be included in the
17
- * query results if it is accepted by another active filtering predicate in this module . An alert is
18
- * excluded from the query results if only if ( 1 ) there is at least one active filtering predicate,
19
- * and ( 2 ) it is not accepted by any active filtering predicate .
16
+ * effect. If it is active, queries may omit alerts that don't have a _primary_ or _related_
17
+ * location ( in SARIF terminology) whose start line is within a specified range. Queries are allowed
18
+ * to produce alerts outside this range.
20
19
*
21
20
* An alert location is a match if it matches a row in this predicate . If `startLineStart` and
22
21
* `startLineEnd` are both 0 , the row specifies a whole- file match, and a location is a match if
@@ -29,26 +28,24 @@ private import codeql.util.Location
29
28
* - startLineStart: inclusive start of the range for alert location start line number ( 1 - based) .
30
29
* - startLineEnd: inclusive end of the range for alert location start line number ( 1 - based) .
31
30
*
32
- * A query should either perform no alert filtering, or adhere to all the filtering rules in this
33
- * module and return all and only the accepted alerts.
34
- *
35
- * This predicate is suitable for situations where we want to filter alerts at line granularity,
36
- * such as based on the pull request diff.
31
+ * Note that an alert that is not accepted by this filtering predicate may still be included in the
32
+ * query results if it is accepted by another active filtering predicate in this module . An alert is
33
+ * excluded from the query results if only if ( 1 ) there is at least one active filtering predicate,
34
+ * and ( 2 ) it is not accepted by any active filtering predicate .
37
35
*
38
36
* See also: `restrictAlertsToExactLocation`.
39
37
* /
40
38
extensible predicate restrictAlertsTo( string filePath, int startLineStart, int startLineEnd) ;
41
39
42
40
/**
43
- * Holds if the query should produce alerts that match the given locations.
41
+ * Holds if the query may restrict its computation to only produce alerts that match the given
42
+ * character ranges. This predicate is suitable for testing, where we want to filter by the exact
43
+ * alert location, distinguishing between alerts on the same line.
44
44
*
45
45
* This predicate is active if and only if it is nonempty. If this predicate is inactive, it has no
46
- * effect. If it is active, it accepts any alert that has at least one matching location.
47
- *
48
- * Note that an alert that is not accepted by this filtering predicate may still be included in the
49
- * query results if it is accepted by another active filtering predicate in this module. An alert is
50
- * excluded from the query results if only if (1) there is at least one active filtering predicate,
51
- * and (2) it is not accepted by any active filtering predicate.
46
+ * effect. If it is active, queries may omit alerts that don't have a _primary_ or _related_
47
+ * location (in SARIF terminology) whose location equals a tuple from this predicate. Queries are
48
+ * allowed to produce alerts outside this range.
52
49
*
53
50
* An alert location is a match if it matches a row in this predicate. Each row specifies an exact
54
51
* location: an alert location is a match if its file path matches `filePath`, its start line and
@@ -61,11 +58,10 @@ extensible predicate restrictAlertsTo(string filePath, int startLineStart, int s
61
58
* - endLine: alert location end line number (1-based).
62
59
* - endColumn: alert location end column number (1-based).
63
60
*
64
- * A query should either perform no alert filtering, or adhere to all the filtering rules in this
65
- * module and return all and only the accepted alerts.
66
- *
67
- * This predicate is suitable for situations where we want to filter by the exact alert location,
68
- * distinguishing between alerts on the same line.
61
+ * Note that an alert that is not accepted by this filtering predicate may still be included in the
62
+ * query results if it is accepted by another active filtering predicate in this module. An alert is
63
+ * excluded from the query results if only if (1) there is at least one active filtering predicate,
64
+ * and (2) it is not accepted by any active filtering predicate.
69
65
*
70
66
* See also: `restrictAlertsTo`.
71
67
*/
@@ -75,25 +71,64 @@ extensible predicate restrictAlertsToExactLocation(
75
71
76
72
/** Module for applying alert location filtering. */
77
73
module AlertFilteringImpl< LocationSig Location> {
78
- /** Applies alert filtering to the given location. */
74
+ pragma [ nomagic]
75
+ private predicate restrictAlertsToEntireFile ( string filePath ) { restrictAlertsTo ( filePath , 0 , 0 ) }
76
+
77
+ pragma [ nomagic]
78
+ private predicate restrictAlertsToLine ( string filePath , int line ) {
79
+ exists ( int startLineStart , int startLineEnd |
80
+ restrictAlertsTo ( filePath , startLineStart , startLineEnd ) and
81
+ line = [ startLineStart .. startLineEnd ]
82
+ )
83
+ }
84
+
85
+ /**
86
+ * Holds if the given location intersects the diff range. When that is the
87
+ * case, ensuring that alerts mentioning this location are included in the
88
+ * query results is a valid overapproximation of the requirements for
89
+ * _diff-informed queries_ as documented under `restrictAlertsTo`.
90
+ *
91
+ * Testing for full intersection rather than only matching the start line
92
+ * means that this predicate is more broadly useful than just checking whether
93
+ * a specific element is considered to be in the diff range of GitHub Code
94
+ * Scanning:
95
+ * - If it's inconvenient to pass the exact `Location` of the element of
96
+ * interest, it's valid to use a `Location` of an enclosing element.
97
+ * - This predicate could be useful for other systems of alert presentation
98
+ * where the rules don't exactly match GitHub Code Scanning.
99
+ *
100
+ * If there is no diff range, this predicate holds for all locations. Note
101
+ * that this predicate has a bindingset and will therefore be inlined;
102
+ * callers should include enough context to ensure efficient evaluation.
103
+ */
79
104
bindingset [ location]
80
105
predicate filterByLocation ( Location location ) {
81
106
not restrictAlertsTo ( _, _, _) and not restrictAlertsToExactLocation ( _, _, _, _, _)
82
107
or
83
- exists ( string filePath , int startLineStart , int startLineEnd |
84
- restrictAlertsTo ( filePath , startLineStart , startLineEnd )
85
- |
86
- startLineStart = 0 and
87
- startLineEnd = 0 and
108
+ exists ( string filePath |
109
+ restrictAlertsToEntireFile ( filePath ) and
88
110
location .hasLocationInfo ( filePath , _, _, _, _)
89
111
or
90
- location .hasLocationInfo ( filePath , [ startLineStart .. startLineEnd ] , _, _, _)
112
+ exists ( int locStartLine , int locEndLine |
113
+ location .hasLocationInfo ( filePath , locStartLine , _, locEndLine , _)
114
+ |
115
+ restrictAlertsToLine ( pragma [ only_bind_into ] ( filePath ) , [ locStartLine .. locEndLine ] )
116
+ )
91
117
)
92
118
or
93
- exists ( string filePath , int startLine , int startColumn , int endLine , int endColumn |
94
- restrictAlertsToExactLocation ( filePath , startLine , startColumn , endLine , endColumn )
119
+ // Check if an exact filter-location is fully contained in `location`.
120
+ // This is slow but only used for testing.
121
+ exists (
122
+ string filePath , int startLine , int startColumn , int endLine , int endColumn ,
123
+ int filterStartLine , int filterStartColumn , int filterEndLine , int filterEndColumn
95
124
|
96
- location .hasLocationInfo ( filePath , startLine , startColumn , endLine , endColumn )
125
+ location .hasLocationInfo ( filePath , startLine , startColumn , endLine , endColumn ) and
126
+ restrictAlertsToExactLocation ( filePath , filterStartLine , filterStartColumn , filterEndLine ,
127
+ filterEndColumn ) and
128
+ startLine <= filterStartLine and
129
+ ( startLine != filterStartLine or startColumn <= filterStartColumn ) and
130
+ endLine >= filterEndLine and
131
+ ( endLine != filterEndLine or endColumn >= filterEndColumn )
97
132
)
98
133
}
99
134
}
0 commit comments