Skip to content

Commit 5f4eb2c

Browse files
authored
[ruff] Expand lint.external docs and add sub-diagnostic (RUF100, RUF102) (#23268)
Summary -- We've gotten a couple of recent reports about suppressing both of these rules (#23191 and #23267 at least), so I think it's worth trying to provide more information in the diagnostics and also in the documentation. The connection to `lint.external` was at least documented, but the rule docs themselves didn't really help unless you clicked through to the setting itself. I'm not 100% sold on this sub-diagnostic message. It feels a bit verbose, but I like that it's explicit. Given full control over the placement, I'd probably put it below the fix diff, but this seems like the best option we currently have available. Test Plan -- Updated snapshot tests
1 parent f5b61be commit 5f4eb2c

7 files changed

Lines changed: 151 additions & 94 deletions

crates/ruff_linter/src/checkers/ast/mod.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3442,6 +3442,20 @@ impl<'a> LintContext<'a> {
34423442
guard
34433443
}
34443444

3445+
/// Return a [`DiagnosticGuard`] for reporting a diagnostic, with its fix title deferred, if the
3446+
/// corresponding rule is enabled.
3447+
///
3448+
/// Prefer [`LintContext::report_diagnostic_if_enabled`] unless you need to attach
3449+
/// sub-diagnostics before the fix title. See its documentation for more details.
3450+
pub(crate) fn report_custom_diagnostic_if_enabled<'chk, T: Violation>(
3451+
&'chk self,
3452+
kind: T,
3453+
range: TextRange,
3454+
) -> Option<DiagnosticGuard<'chk, 'a>> {
3455+
self.is_rule_enabled(T::rule())
3456+
.then(|| self.report_custom_diagnostic(kind, range))
3457+
}
3458+
34453459
#[inline]
34463460
pub(crate) const fn is_rule_enabled(&self, rule: Rule) -> bool {
34473461
self.rules.enabled(rule)

crates/ruff_linter/src/rules/ruff/rules/invalid_rule_code.rs

Lines changed: 33 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ impl InvalidRuleCodeKind {
4747
/// ```
4848
///
4949
/// ## Options
50+
///
51+
/// This rule will flag rule codes that are unknown to Ruff, even if they are
52+
/// valid for other tools. You can tell Ruff to ignore such codes by configuring
53+
/// the list of known "external" rule codes with the following option:
54+
///
5055
/// - `lint.external`
5156
#[derive(ViolationMetadata)]
5257
#[violation_metadata(stable_since = "0.15.0")]
@@ -120,20 +125,20 @@ fn all_codes_invalid_diagnostic(
120125
locator: &Locator,
121126
context: &LintContext,
122127
) {
123-
context
124-
.report_diagnostic(
125-
InvalidRuleCode {
126-
rule_code: invalid_codes
127-
.into_iter()
128-
.map(Code::as_str)
129-
.collect::<Vec<_>>()
130-
.join(", "),
131-
kind: InvalidRuleCodeKind::Noqa,
132-
whole_comment: true,
133-
},
134-
directive.range(),
135-
)
136-
.set_fix(Fix::safe_edit(delete_comment(directive.range(), locator)));
128+
let mut diagnostic = context.report_custom_diagnostic(
129+
InvalidRuleCode {
130+
rule_code: invalid_codes
131+
.into_iter()
132+
.map(Code::as_str)
133+
.collect::<Vec<_>>()
134+
.join(", "),
135+
kind: InvalidRuleCodeKind::Noqa,
136+
whole_comment: true,
137+
},
138+
directive.range(),
139+
);
140+
diagnostic.set_fix(Fix::safe_edit(delete_comment(directive.range(), locator)));
141+
diagnostic.help("Add non-Ruff rule codes to the `lint.external` configuration option");
137142
}
138143

139144
fn some_codes_are_invalid_diagnostic(
@@ -142,20 +147,20 @@ fn some_codes_are_invalid_diagnostic(
142147
locator: &Locator,
143148
context: &LintContext,
144149
) {
145-
context
146-
.report_diagnostic(
147-
InvalidRuleCode {
148-
rule_code: invalid_code.to_string(),
149-
kind: InvalidRuleCodeKind::Noqa,
150-
whole_comment: false,
151-
},
152-
invalid_code.range(),
153-
)
154-
.set_fix(Fix::safe_edit(remove_invalid_noqa(
155-
codes,
156-
invalid_code,
157-
locator,
158-
)));
150+
let mut diagnostic = context.report_custom_diagnostic(
151+
InvalidRuleCode {
152+
rule_code: invalid_code.to_string(),
153+
kind: InvalidRuleCodeKind::Noqa,
154+
whole_comment: false,
155+
},
156+
invalid_code.range(),
157+
);
158+
diagnostic.set_fix(Fix::safe_edit(remove_invalid_noqa(
159+
codes,
160+
invalid_code,
161+
locator,
162+
)));
163+
diagnostic.help("Add non-Ruff rule codes to the `lint.external` configuration option");
159164
}
160165

161166
fn remove_invalid_noqa(codes: &Codes, invalid_code: &Code, locator: &Locator) -> Edit {

crates/ruff_linter/src/rules/ruff/rules/unused_noqa.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,11 @@ impl UnusedNOQAKind {
7272
/// ```
7373
///
7474
/// ## Options
75+
///
76+
/// This rule will flag rule codes that are unknown to Ruff, even if they are
77+
/// valid for other tools. You can tell Ruff to ignore such codes by configuring
78+
/// the list of known "external" rule codes with the following option:
79+
///
7580
/// - `lint.external`
7681
///
7782
/// ## References

crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF102_RUF102.py.snap

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ RUF102 [*] Invalid rule code in `# noqa`: INVALID123
1010
3 | # External code
1111
4 | import re # noqa: V123
1212
|
13+
help: Add non-Ruff rule codes to the `lint.external` configuration option
1314
help: Remove the `# noqa` comment
1415
1 | # Invalid code
1516
- import os # noqa: INVALID123
@@ -28,6 +29,7 @@ RUF102 [*] Invalid rule code in `# noqa`: V123
2829
5 | # Valid noqa
2930
6 | import sys # noqa: E402
3031
|
32+
help: Add non-Ruff rule codes to the `lint.external` configuration option
3133
help: Remove the `# noqa` comment
3234
1 | # Invalid code
3335
2 | import os # noqa: INVALID123
@@ -48,6 +50,7 @@ RUF102 [*] Invalid rule code in `# noqa`: INVALID456
4850
8 | from itertools import product # Preceeding comment # noqa: INVALID789
4951
9 | # Succeeding comment
5052
|
53+
help: Add non-Ruff rule codes to the `lint.external` configuration option
5154
help: Remove the rule code `INVALID456`
5255
4 | import re # noqa: V123
5356
5 | # Valid noqa
@@ -68,6 +71,7 @@ RUF102 [*] Invalid rule code in `# noqa`: INVALID789
6871
9 | # Succeeding comment
6972
10 | import math # noqa: INVALID000 # Succeeding comment
7073
|
74+
help: Add non-Ruff rule codes to the `lint.external` configuration option
7175
help: Remove the `# noqa` comment
7276
5 | # Valid noqa
7377
6 | import sys # noqa: E402
@@ -88,6 +92,7 @@ RUF102 [*] Invalid rule code in `# noqa`: INVALID000
8892
11 | # Mixed valid and invalid
8993
12 | from typing import List # noqa: F401, INVALID123
9094
|
95+
help: Add non-Ruff rule codes to the `lint.external` configuration option
9196
help: Remove the `# noqa` comment
9297
7 | from functools import cache # Preceeding comment # noqa: F401, INVALID456
9398
8 | from itertools import product # Preceeding comment # noqa: INVALID789
@@ -108,6 +113,7 @@ RUF102 [*] Invalid rule code in `# noqa`: INVALID123
108113
13 | # Test for multiple invalid
109114
14 | from collections import defaultdict # noqa: INVALID100, INVALID200, F401
110115
|
116+
help: Add non-Ruff rule codes to the `lint.external` configuration option
111117
help: Remove the rule code `INVALID123`
112118
9 | # Succeeding comment
113119
10 | import math # noqa: INVALID000 # Succeeding comment
@@ -128,6 +134,7 @@ RUF102 [*] Invalid rule code in `# noqa`: INVALID100
128134
15 | # Test for preserving valid codes when fixing
129135
16 | from itertools import chain # noqa: E402, INVALID300, F401
130136
|
137+
help: Add non-Ruff rule codes to the `lint.external` configuration option
131138
help: Remove the rule code `INVALID100`
132139
11 | # Mixed valid and invalid
133140
12 | from typing import List # noqa: F401, INVALID123
@@ -148,6 +155,7 @@ RUF102 [*] Invalid rule code in `# noqa`: INVALID200
148155
15 | # Test for preserving valid codes when fixing
149156
16 | from itertools import chain # noqa: E402, INVALID300, F401
150157
|
158+
help: Add non-Ruff rule codes to the `lint.external` configuration option
151159
help: Remove the rule code `INVALID200`
152160
11 | # Mixed valid and invalid
153161
12 | from typing import List # noqa: F401, INVALID123
@@ -168,6 +176,7 @@ RUF102 [*] Invalid rule code in `# noqa`: INVALID300
168176
17 | # Test for mixed code types
169177
18 | import json # noqa: E402, INVALID400, V100
170178
|
179+
help: Add non-Ruff rule codes to the `lint.external` configuration option
171180
help: Remove the rule code `INVALID300`
172181
13 | # Test for multiple invalid
173182
14 | from collections import defaultdict # noqa: INVALID100, INVALID200, F401
@@ -188,6 +197,7 @@ RUF102 [*] Invalid rule code in `# noqa`: INVALID400
188197
19 | # Test for rule redirects
189198
20 | import pandas as pd # noqa: TCH002
190199
|
200+
help: Add non-Ruff rule codes to the `lint.external` configuration option
191201
help: Remove the rule code `INVALID400`
192202
15 | # Test for preserving valid codes when fixing
193203
16 | from itertools import chain # noqa: E402, INVALID300, F401
@@ -208,6 +218,7 @@ RUF102 [*] Invalid rule code in `# noqa`: V100
208218
19 | # Test for rule redirects
209219
20 | import pandas as pd # noqa: TCH002
210220
|
221+
help: Add non-Ruff rule codes to the `lint.external` configuration option
211222
help: Remove the rule code `V100`
212223
15 | # Test for preserving valid codes when fixing
213224
16 | from itertools import chain # noqa: E402, INVALID300, F401
@@ -226,6 +237,7 @@ RUF102 [*] Invalid rule code in `# noqa`: INVALID123
226237
22 | import pathlib # noqa: INVALID123 some reason
227238
| ^^^^^^^^^^^^^^^^^^
228239
|
240+
help: Add non-Ruff rule codes to the `lint.external` configuration option
229241
help: Remove the `# noqa` comment
230242
19 | # Test for rule redirects
231243
20 | import pandas as pd # noqa: TCH002

crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__invalid_rule_code_external_rules.snap

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ RUF102 [*] Invalid rule code in `# noqa`: INVALID123
1010
3 | # External code
1111
4 | import re # noqa: V123
1212
|
13+
help: Add non-Ruff rule codes to the `lint.external` configuration option
1314
help: Remove the `# noqa` comment
1415
1 | # Invalid code
1516
- import os # noqa: INVALID123
@@ -28,6 +29,7 @@ RUF102 [*] Invalid rule code in `# noqa`: INVALID456
2829
8 | from itertools import product # Preceeding comment # noqa: INVALID789
2930
9 | # Succeeding comment
3031
|
32+
help: Add non-Ruff rule codes to the `lint.external` configuration option
3133
help: Remove the rule code `INVALID456`
3234
4 | import re # noqa: V123
3335
5 | # Valid noqa
@@ -48,6 +50,7 @@ RUF102 [*] Invalid rule code in `# noqa`: INVALID789
4850
9 | # Succeeding comment
4951
10 | import math # noqa: INVALID000 # Succeeding comment
5052
|
53+
help: Add non-Ruff rule codes to the `lint.external` configuration option
5154
help: Remove the `# noqa` comment
5255
5 | # Valid noqa
5356
6 | import sys # noqa: E402
@@ -68,6 +71,7 @@ RUF102 [*] Invalid rule code in `# noqa`: INVALID000
6871
11 | # Mixed valid and invalid
6972
12 | from typing import List # noqa: F401, INVALID123
7073
|
74+
help: Add non-Ruff rule codes to the `lint.external` configuration option
7175
help: Remove the `# noqa` comment
7276
7 | from functools import cache # Preceeding comment # noqa: F401, INVALID456
7377
8 | from itertools import product # Preceeding comment # noqa: INVALID789
@@ -88,6 +92,7 @@ RUF102 [*] Invalid rule code in `# noqa`: INVALID123
8892
13 | # Test for multiple invalid
8993
14 | from collections import defaultdict # noqa: INVALID100, INVALID200, F401
9094
|
95+
help: Add non-Ruff rule codes to the `lint.external` configuration option
9196
help: Remove the rule code `INVALID123`
9297
9 | # Succeeding comment
9398
10 | import math # noqa: INVALID000 # Succeeding comment
@@ -108,6 +113,7 @@ RUF102 [*] Invalid rule code in `# noqa`: INVALID100
108113
15 | # Test for preserving valid codes when fixing
109114
16 | from itertools import chain # noqa: E402, INVALID300, F401
110115
|
116+
help: Add non-Ruff rule codes to the `lint.external` configuration option
111117
help: Remove the rule code `INVALID100`
112118
11 | # Mixed valid and invalid
113119
12 | from typing import List # noqa: F401, INVALID123
@@ -128,6 +134,7 @@ RUF102 [*] Invalid rule code in `# noqa`: INVALID200
128134
15 | # Test for preserving valid codes when fixing
129135
16 | from itertools import chain # noqa: E402, INVALID300, F401
130136
|
137+
help: Add non-Ruff rule codes to the `lint.external` configuration option
131138
help: Remove the rule code `INVALID200`
132139
11 | # Mixed valid and invalid
133140
12 | from typing import List # noqa: F401, INVALID123
@@ -148,6 +155,7 @@ RUF102 [*] Invalid rule code in `# noqa`: INVALID300
148155
17 | # Test for mixed code types
149156
18 | import json # noqa: E402, INVALID400, V100
150157
|
158+
help: Add non-Ruff rule codes to the `lint.external` configuration option
151159
help: Remove the rule code `INVALID300`
152160
13 | # Test for multiple invalid
153161
14 | from collections import defaultdict # noqa: INVALID100, INVALID200, F401
@@ -168,6 +176,7 @@ RUF102 [*] Invalid rule code in `# noqa`: INVALID400
168176
19 | # Test for rule redirects
169177
20 | import pandas as pd # noqa: TCH002
170178
|
179+
help: Add non-Ruff rule codes to the `lint.external` configuration option
171180
help: Remove the rule code `INVALID400`
172181
15 | # Test for preserving valid codes when fixing
173182
16 | from itertools import chain # noqa: E402, INVALID300, F401
@@ -186,6 +195,7 @@ RUF102 [*] Invalid rule code in `# noqa`: INVALID123
186195
22 | import pathlib # noqa: INVALID123 some reason
187196
| ^^^^^^^^^^^^^^^^^^
188197
|
198+
help: Add non-Ruff rule codes to the `lint.external` configuration option
189199
help: Remove the `# noqa` comment
190200
19 | # Test for rule redirects
191201
20 | import pandas as pd # noqa: TCH002

crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__range_suppressions.snap

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,7 @@ RUF102 [*] Invalid rule code in suppression: YF829
327327
97 | # ruff: enable[YF829]
328328
| -----
329329
|
330+
help: Add non-Ruff rule codes to the `lint.external` configuration option
330331
help: Remove the suppression comment
331332
90 |
332333
91 | def f():
@@ -352,6 +353,7 @@ RUF102 [*] Invalid rule code in suppression: RQW320
352353
| ------
353354
97 | # ruff: enable[YF829]
354355
|
356+
help: Add non-Ruff rule codes to the `lint.external` configuration option
355357
help: Remove the rule code `RQW320`
356358
91 | def f():
357359
92 | # Unknown rule codes

0 commit comments

Comments
 (0)