Skip to content

Commit 65b288b

Browse files
authored
[flake8-comprehension] Mark autofix for C420 as unsafe if there's comments inside the dict comprehension (#18768)
1 parent 06da2c8 commit 65b288b

File tree

3 files changed

+66
-2
lines changed

3 files changed

+66
-2
lines changed

crates/ruff_linter/resources/test/fixtures/flake8_comprehensions/C420.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,3 +90,14 @@ def f():
9090

9191
def func():
9292
{(a, b): a + b for (a, b) in [(1, 2), (3, 4)]} # OK
93+
94+
# https://github.com/astral-sh/ruff/issues/18764
95+
{ # 1
96+
a # 2
97+
: # 3
98+
None # 4
99+
for # 5
100+
a # 6
101+
in # 7
102+
iterable # 8
103+
} # 9

crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_dict_comprehension_for_iterable.rs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use ast::ExprName;
2+
use ruff_diagnostics::Applicability;
23
use ruff_macros::{ViolationMetadata, derive_message_formats};
34
use ruff_python_ast::comparable::ComparableExpr;
45
use ruff_python_ast::helpers::any_over_expr;
@@ -31,6 +32,19 @@ use crate::{Edit, Fix, FixAvailability, Violation};
3132
/// dict.fromkeys(iterable, 1)
3233
/// ```
3334
///
35+
/// ## Fix safety
36+
/// This rule's fix is marked as unsafe if there's comments inside the dict comprehension,
37+
/// as comments may be removed.
38+
///
39+
/// For example, the fix would be marked as unsafe in the following case:
40+
/// ```python
41+
/// { # comment 1
42+
/// a: # comment 2
43+
/// None # comment 3
44+
/// for a in iterable # comment 4
45+
/// }
46+
/// ```
47+
///
3448
/// ## References
3549
/// - [Python documentation: `dict.fromkeys`](https://docs.python.org/3/library/stdtypes.html#dict.fromkeys)
3650
#[derive(ViolationMetadata)]
@@ -121,15 +135,23 @@ pub(crate) fn unnecessary_dict_comprehension_for_iterable(
121135
);
122136

123137
if checker.semantic().has_builtin_binding("dict") {
124-
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
138+
let edit = Edit::range_replacement(
125139
checker
126140
.generator()
127141
.expr(&fix_unnecessary_dict_comprehension(
128142
dict_comp.value.as_ref(),
129143
generator,
130144
)),
131145
dict_comp.range(),
132-
)));
146+
);
147+
diagnostic.set_fix(Fix::applicable_edit(
148+
edit,
149+
if checker.comment_ranges().intersects(dict_comp.range()) {
150+
Applicability::Unsafe
151+
} else {
152+
Applicability::Safe
153+
},
154+
));
133155
}
134156
}
135157

crates/ruff_linter/src/rules/flake8_comprehensions/snapshots/ruff_linter__rules__flake8_comprehensions__tests__C420_C420.py.snap

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,3 +202,34 @@ C420.py:59:6: C420 [*] Unnecessary dict comprehension for iterable; use `dict.fr
202202
60 60 |
203203
61 61 |
204204
62 62 | # Non-violation cases: RUF025
205+
206+
C420.py:95:1: C420 [*] Unnecessary dict comprehension for iterable; use `dict.fromkeys` instead
207+
|
208+
94 | # https://github.com/astral-sh/ruff/issues/18764
209+
95 | / { # 1
210+
96 | | a # 2
211+
97 | | : # 3
212+
98 | | None # 4
213+
99 | | for # 5
214+
100 | | a # 6
215+
101 | | in # 7
216+
102 | | iterable # 8
217+
103 | | } # 9
218+
| |_^ C420
219+
|
220+
= help: Replace with `dict.fromkeys(iterable, value)`)
221+
222+
Unsafe fix
223+
92 92 | {(a, b): a + b for (a, b) in [(1, 2), (3, 4)]} # OK
224+
93 93 |
225+
94 94 | # https://github.com/astral-sh/ruff/issues/18764
226+
95 |-{ # 1
227+
96 |-a # 2
228+
97 |-: # 3
229+
98 |-None # 4
230+
99 |-for # 5
231+
100 |-a # 6
232+
101 |-in # 7
233+
102 |-iterable # 8
234+
103 |-} # 9
235+
95 |+dict.fromkeys(iterable) # 9

0 commit comments

Comments
 (0)