diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_comprehensions/C420_2.py b/crates/ruff_linter/resources/test/fixtures/flake8_comprehensions/C420_2.py new file mode 100644 index 0000000000..04c5de2df4 --- /dev/null +++ b/crates/ruff_linter/resources/test/fixtures/flake8_comprehensions/C420_2.py @@ -0,0 +1,5 @@ +foo or{x: None for x in bar} + + +# C420 fix must make sure to insert a leading space if needed, +# See https://github.com/astral-sh/ruff/issues/18599 diff --git a/crates/ruff_linter/src/rules/flake8_comprehensions/mod.rs b/crates/ruff_linter/src/rules/flake8_comprehensions/mod.rs index ff95105b11..dbc7be8d93 100644 --- a/crates/ruff_linter/src/rules/flake8_comprehensions/mod.rs +++ b/crates/ruff_linter/src/rules/flake8_comprehensions/mod.rs @@ -24,6 +24,7 @@ mod tests { #[test_case(Rule::UnnecessaryComprehensionInCall, Path::new("C419_2.py"))] #[test_case(Rule::UnnecessaryDictComprehensionForIterable, Path::new("C420.py"))] #[test_case(Rule::UnnecessaryDictComprehensionForIterable, Path::new("C420_1.py"))] + #[test_case(Rule::UnnecessaryDictComprehensionForIterable, Path::new("C420_2.py"))] #[test_case(Rule::UnnecessaryDoubleCastOrProcess, Path::new("C414.py"))] #[test_case(Rule::UnnecessaryGeneratorDict, Path::new("C402.py"))] #[test_case(Rule::UnnecessaryGeneratorList, Path::new("C400.py"))] diff --git a/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_dict_comprehension_for_iterable.rs b/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_dict_comprehension_for_iterable.rs index b4bf05e41a..b0fddc96dc 100644 --- a/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_dict_comprehension_for_iterable.rs +++ b/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_dict_comprehension_for_iterable.rs @@ -7,6 +7,7 @@ use ruff_python_ast::{self as ast, Arguments, Comprehension, Expr, ExprCall, Exp use ruff_text_size::{Ranged, TextRange}; use crate::checkers::ast::Checker; +use crate::fix::edits::pad_start; use crate::{Edit, Fix, FixAvailability, Violation}; /// ## What it does @@ -136,12 +137,16 @@ pub(crate) fn unnecessary_dict_comprehension_for_iterable( if checker.semantic().has_builtin_binding("dict") { let edit = Edit::range_replacement( - checker - .generator() - .expr(&fix_unnecessary_dict_comprehension( - dict_comp.value.as_ref(), - generator, - )), + pad_start( + checker + .generator() + .expr(&fix_unnecessary_dict_comprehension( + dict_comp.value.as_ref(), + generator, + )), + dict_comp.start(), + checker.locator(), + ), dict_comp.range(), ); diagnostic.set_fix(Fix::applicable_edit( diff --git a/crates/ruff_linter/src/rules/flake8_comprehensions/snapshots/ruff_linter__rules__flake8_comprehensions__tests__C420_C420_2.py.snap b/crates/ruff_linter/src/rules/flake8_comprehensions/snapshots/ruff_linter__rules__flake8_comprehensions__tests__C420_C420_2.py.snap new file mode 100644 index 0000000000..c0f88083fa --- /dev/null +++ b/crates/ruff_linter/src/rules/flake8_comprehensions/snapshots/ruff_linter__rules__flake8_comprehensions__tests__C420_C420_2.py.snap @@ -0,0 +1,16 @@ +--- +source: crates/ruff_linter/src/rules/flake8_comprehensions/mod.rs +--- +C420_2.py:1:7: C420 [*] Unnecessary dict comprehension for iterable; use `dict.fromkeys` instead + | +1 | foo or{x: None for x in bar} + | ^^^^^^^^^^^^^^^^^^^^^^ C420 + | + = help: Replace with `dict.fromkeys(iterable, value)`) + +ℹ Safe fix +1 |-foo or{x: None for x in bar} + 1 |+foo or dict.fromkeys(bar) +2 2 | +3 3 | +4 4 | # C420 fix must make sure to insert a leading space if needed,