Skip to content

Commit acb5d6e

Browse files
committed
Python: use shared AlertSuppression.qll
1 parent 621a108 commit acb5d6e

File tree

3 files changed

+23
-80
lines changed

3 files changed

+23
-80
lines changed

python/ql/src/analysis/AlertSuppression.ql

Lines changed: 16 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -5,101 +5,37 @@
55
* @id py/alert-suppression
66
*/
77

8-
import python
8+
private import codeql.suppression.AlertSuppression as AS
9+
private import semmle.python.Comment as P
910

10-
/**
11-
* An alert suppression comment.
12-
*/
13-
abstract class SuppressionComment extends Comment {
14-
/** Gets the scope of this suppression. */
15-
abstract SuppressionScope getScope();
16-
17-
/** Gets the suppression annotation in this comment. */
18-
abstract string getAnnotation();
19-
20-
/**
21-
* Holds if this comment applies to the range from column `startcolumn` of line `startline`
22-
* to column `endcolumn` of line `endline` in file `filepath`.
23-
*/
24-
abstract predicate covers(
25-
string filepath, int startline, int startcolumn, int endline, int endcolumn
26-
);
27-
}
28-
29-
/**
30-
* An alert comment that applies to a single line
31-
*/
32-
abstract class LineSuppressionComment extends SuppressionComment {
33-
LineSuppressionComment() {
34-
exists(string filepath, int l |
35-
this.getLocation().hasLocationInfo(filepath, l, _, _, _) and
36-
any(AstNode a).getLocation().hasLocationInfo(filepath, l, _, _, _)
37-
)
38-
}
39-
40-
/** Gets the scope of this suppression. */
41-
override SuppressionScope getScope() { result = this }
42-
43-
override predicate covers(
11+
class SingleLineComment instanceof P::Comment {
12+
predicate hasLocationInfo(
4413
string filepath, int startline, int startcolumn, int endline, int endcolumn
4514
) {
46-
this.getLocation().hasLocationInfo(filepath, startline, _, endline, endcolumn) and
47-
startcolumn = 1
15+
super.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
4816
}
49-
}
50-
51-
/**
52-
* An lgtm suppression comment.
53-
*/
54-
class LgtmSuppressionComment extends LineSuppressionComment {
55-
string annotation;
5617

57-
LgtmSuppressionComment() {
58-
exists(string all | all = this.getContents() |
59-
// match `lgtm[...]` anywhere in the comment
60-
annotation = all.regexpFind("(?i)\\blgtm\\s*\\[[^\\]]*\\]", _, _)
61-
or
62-
// match `lgtm` at the start of the comment and after semicolon
63-
annotation = all.regexpFind("(?i)(?<=^|;)\\s*lgtm(?!\\B|\\s*\\[)", _, _).trim()
64-
)
65-
}
18+
string getText() { result = super.getContents() }
6619

67-
/** Gets the suppression annotation in this comment. */
68-
override string getAnnotation() { result = annotation }
20+
string toString() { result = super.toString() }
6921
}
7022

23+
import AS::Make<SingleLineComment>
24+
7125
/**
7226
* A noqa suppression comment. Both pylint and pyflakes respect this, so lgtm ought to too.
7327
*/
74-
class NoqaSuppressionComment extends LineSuppressionComment {
75-
NoqaSuppressionComment() { this.getContents().toLowerCase().regexpMatch("\\s*noqa\\s*([^:].*)?") }
28+
class NoqaSuppressionComment extends SuppressionComment instanceof SingleLineComment {
29+
NoqaSuppressionComment() {
30+
SingleLineComment.super.getText().regexpMatch("(?i)\\s*noqa\\s*([^:].*)?")
31+
}
7632

7733
override string getAnnotation() { result = "lgtm" }
78-
}
7934

80-
/**
81-
* The scope of an alert suppression comment.
82-
*/
83-
class SuppressionScope extends @py_comment instanceof SuppressionComment {
84-
/**
85-
* Holds if this element is at the specified location.
86-
* The location spans column `startcolumn` of line `startline` to
87-
* column `endcolumn` of line `endline` in file `filepath`.
88-
* For more information, see
89-
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
90-
*/
91-
predicate hasLocationInfo(
35+
override predicate covers(
9236
string filepath, int startline, int startcolumn, int endline, int endcolumn
9337
) {
94-
super.covers(filepath, startline, startcolumn, endline, endcolumn)
38+
this.hasLocationInfo(filepath, startline, _, endline, endcolumn) and
39+
startcolumn = 1
9540
}
96-
97-
/** Gets a textual representation of this element. */
98-
string toString() { result = "suppression range" }
9941
}
100-
101-
from SuppressionComment c
102-
select c, // suppression comment
103-
c.getContents(), // text of suppression comment (excluding delimiters)
104-
c.getAnnotation(), // text of suppression annotation
105-
c.getScope() // scope of suppression

python/ql/src/qlpack.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ groups:
66
dependencies:
77
codeql/python-all: ${workspace}
88
codeql/suite-helpers: ${workspace}
9+
codeql/util: ${workspace}
910
suites: codeql-suites
1011
extractor: python
1112
defaultSuiteFile: codeql-suites/python-code-scanning.qls

python/ql/test/query-tests/analysis/suppression/AlertSuppression.expected

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,17 @@
1414
| test.py:18:4:18:12 | Comment # lgtm | lgtm | lgtm | test.py:18:1:18:12 | suppression range |
1515
| test.py:19:4:19:31 | Comment # lgtm [py/line-too-long] | lgtm [py/line-too-long] | lgtm [py/line-too-long] | test.py:19:1:19:31 | suppression range |
1616
| test.py:20:4:20:14 | Comment # lgtm lgtm | lgtm lgtm | lgtm | test.py:20:1:20:14 | suppression range |
17+
| test.py:23:1:23:41 | Comment #lgtm -- Ignore this -- No line or scope. | lgtm -- Ignore this -- No line or scope. | lgtm | test.py:23:1:23:41 | suppression range |
1718
| test.py:27:12:27:23 | Comment #lgtm [func] | lgtm [func] | lgtm [func] | test.py:27:1:27:23 | suppression range |
19+
| test.py:28:5:28:70 | Comment # lgtm -- Blank line (ignore for now, maybe scope wide in future). | lgtm -- Blank line (ignore for now, maybe scope wide in future). | lgtm | test.py:28:1:28:70 | suppression range |
1820
| test.py:29:17:29:35 | Comment # lgtm on docstring | lgtm on docstring | lgtm | test.py:29:1:29:35 | suppression range |
1921
| test.py:30:16:30:47 | Comment #lgtm [py/duplicate-key-in-dict] | lgtm [py/duplicate-key-in-dict] | lgtm [py/duplicate-key-in-dict] | test.py:30:1:30:47 | suppression range |
2022
| test.py:35:10:35:21 | Comment # lgtm class | lgtm class | lgtm | test.py:35:1:35:21 | suppression range |
2123
| test.py:36:21:36:33 | Comment # lgtm method | lgtm method | lgtm | test.py:36:1:36:33 | suppression range |
2224
| test.py:39:4:39:8 | Comment #noqa | noqa | lgtm | test.py:39:1:39:8 | suppression range |
2325
| test.py:40:4:40:9 | Comment # noqa | noqa | lgtm | test.py:40:1:40:9 | suppression range |
2426
| test.py:45:4:45:31 | Comment # noqa -- Some extra detail. | noqa -- Some extra detail. | lgtm | test.py:45:1:45:31 | suppression range |
27+
| test.py:49:1:49:10 | Comment #LGTM-1929 | LGTM-1929 | LGTM | test.py:49:1:49:10 | suppression range |
2528
| test.py:50:34:50:117 | Comment # noqa: E501; (line too long) pylint: disable=invalid-name; lgtm [py/missing-equals] | noqa: E501; (line too long) pylint: disable=invalid-name; lgtm [py/missing-equals] | lgtm [py/missing-equals] | test.py:50:1:50:117 | suppression range |
2629
| test.py:52:4:52:67 | Comment # noqa: E501; (line too long) pylint: disable=invalid-name; lgtm | noqa: E501; (line too long) pylint: disable=invalid-name; lgtm | lgtm | test.py:52:1:52:67 | suppression range |
2730
| test.py:53:4:53:78 | Comment # random nonsense lgtm [py/missing-equals] and then some more commentary... | random nonsense lgtm [py/missing-equals] and then some more commentary... | lgtm [py/missing-equals] | test.py:53:1:53:78 | suppression range |
@@ -47,13 +50,16 @@
4750
| testWindows.py:18:4:18:12 | Comment # lgtm | lgtm | lgtm | testWindows.py:18:1:18:12 | suppression range |
4851
| testWindows.py:19:4:19:31 | Comment # lgtm [py/line-too-long] | lgtm [py/line-too-long] | lgtm [py/line-too-long] | testWindows.py:19:1:19:31 | suppression range |
4952
| testWindows.py:20:4:20:14 | Comment # lgtm lgtm | lgtm lgtm | lgtm | testWindows.py:20:1:20:14 | suppression range |
53+
| testWindows.py:23:1:23:41 | Comment #lgtm -- Ignore this -- No line or scope. | lgtm -- Ignore this -- No line or scope. | lgtm | testWindows.py:23:1:23:41 | suppression range |
5054
| testWindows.py:27:12:27:23 | Comment #lgtm [func] | lgtm [func] | lgtm [func] | testWindows.py:27:1:27:23 | suppression range |
55+
| testWindows.py:28:5:28:70 | Comment # lgtm -- Blank line (ignore for now, maybe scope wide in future). | lgtm -- Blank line (ignore for now, maybe scope wide in future). | lgtm | testWindows.py:28:1:28:70 | suppression range |
5156
| testWindows.py:29:17:29:35 | Comment # lgtm on docstring | lgtm on docstring | lgtm | testWindows.py:29:1:29:35 | suppression range |
5257
| testWindows.py:30:16:30:47 | Comment #lgtm [py/duplicate-key-in-dict] | lgtm [py/duplicate-key-in-dict] | lgtm [py/duplicate-key-in-dict] | testWindows.py:30:1:30:47 | suppression range |
5358
| testWindows.py:35:10:35:21 | Comment # lgtm class | lgtm class | lgtm | testWindows.py:35:1:35:21 | suppression range |
5459
| testWindows.py:36:21:36:33 | Comment # lgtm method | lgtm method | lgtm | testWindows.py:36:1:36:33 | suppression range |
5560
| testWindows.py:39:3:39:7 | Comment #noqa | noqa | lgtm | testWindows.py:39:1:39:7 | suppression range |
5661
| testWindows.py:40:4:40:9 | Comment # noqa | noqa | lgtm | testWindows.py:40:1:40:9 | suppression range |
62+
| testWindows.py:45:1:45:28 | Comment # noqa -- Some extra detail. | noqa -- Some extra detail. | lgtm | testWindows.py:45:1:45:28 | suppression range |
5763
| testWindows.py:48:4:48:60 | Comment # lgtm[py/line-too-long] and lgtm[py/non-callable-called] | lgtm[py/line-too-long] and lgtm[py/non-callable-called] | lgtm[py/line-too-long] | testWindows.py:48:1:48:60 | suppression range |
5864
| testWindows.py:48:4:48:60 | Comment # lgtm[py/line-too-long] and lgtm[py/non-callable-called] | lgtm[py/line-too-long] and lgtm[py/non-callable-called] | lgtm[py/non-callable-called] | testWindows.py:48:1:48:60 | suppression range |
5965
| testWindows.py:49:4:49:33 | Comment # lgtm[py/line-too-long]; lgtm | lgtm[py/line-too-long]; lgtm | lgtm | testWindows.py:49:1:49:33 | suppression range |

0 commit comments

Comments
 (0)