diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_comprehensions/C403.py b/crates/ruff_linter/resources/test/fixtures/flake8_comprehensions/C403.py index 989581c5bc..ba0d2598ea 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_comprehensions/C403.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_comprehensions/C403.py @@ -21,3 +21,14 @@ s = set( # comment s = set([ # comment x for x in range(3) ]) + +s = set(([x for x in range(3)])) + +s = set(((([x for x in range(3)])))) + +s = set( # outer set comment +( # inner paren comment - not preserved +(( +[ # comprehension comment + x for x in range(3)] + )))) diff --git a/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_list_comprehension_set.rs b/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_list_comprehension_set.rs index 6fdee558c7..6a1792eb8f 100644 --- a/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_list_comprehension_set.rs +++ b/crates/ruff_linter/src/rules/flake8_comprehensions/rules/unnecessary_list_comprehension_set.rs @@ -1,6 +1,7 @@ use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, ViolationMetadata}; use ruff_python_ast as ast; +use ruff_python_ast::parenthesize::parenthesized_range; use ruff_text_size::{Ranged, TextSize}; use crate::checkers::ast::Checker; @@ -55,32 +56,39 @@ pub(crate) fn unnecessary_list_comprehension_set(checker: &mut Checker, call: &a if !checker.semantic().has_builtin_binding("set") { return; } - if argument.is_list_comp_expr() { - let diagnostic = Diagnostic::new(UnnecessaryListComprehensionSet, call.range()); - let fix = { - // Replace `set(` with `{`. - let call_start = Edit::replacement( - pad_start("{", call.range(), checker.locator(), checker.semantic()), - call.start(), - call.arguments.start() + TextSize::from(1), - ); - - // Replace `)` with `}`. - let call_end = Edit::replacement( - pad_end("}", call.range(), checker.locator(), checker.semantic()), - call.arguments.end() - TextSize::from(1), - call.end(), - ); - - // Delete the open bracket (`[`). - let argument_start = - Edit::deletion(argument.start(), argument.start() + TextSize::from(1)); - - // Delete the close bracket (`]`). - let argument_end = Edit::deletion(argument.end() - TextSize::from(1), argument.end()); - - Fix::unsafe_edits(call_start, [argument_start, argument_end, call_end]) - }; - checker.diagnostics.push(diagnostic.with_fix(fix)); + if !argument.is_list_comp_expr() { + return; } + let diagnostic = Diagnostic::new(UnnecessaryListComprehensionSet, call.range()); + let one = TextSize::from(1); + + // Replace `set(` with `{`. + let call_start = Edit::replacement( + pad_start("{", call.range(), checker.locator(), checker.semantic()), + call.start(), + call.arguments.start() + one, + ); + + // Replace `)` with `}`. + let call_end = Edit::replacement( + pad_end("}", call.range(), checker.locator(), checker.semantic()), + call.arguments.end() - one, + call.end(), + ); + + // If the list comprehension is parenthesized, remove the parentheses in addition to + // removing the brackets. + let replacement_range = parenthesized_range( + argument.into(), + (&call.arguments).into(), + checker.comment_ranges(), + checker.locator().contents(), + ) + .unwrap_or_else(|| argument.range()); + + let span = argument.range().add_start(one).sub_end(one); + let replacement = + Edit::range_replacement(checker.source()[span].to_string(), replacement_range); + let fix = Fix::unsafe_edits(call_start, [call_end, replacement]); + checker.diagnostics.push(diagnostic.with_fix(fix)); } diff --git a/crates/ruff_linter/src/rules/flake8_comprehensions/snapshots/ruff_linter__rules__flake8_comprehensions__tests__C403_C403.py.snap b/crates/ruff_linter/src/rules/flake8_comprehensions/snapshots/ruff_linter__rules__flake8_comprehensions__tests__C403_C403.py.snap index 6ea5a28385..fa588c4210 100644 --- a/crates/ruff_linter/src/rules/flake8_comprehensions/snapshots/ruff_linter__rules__flake8_comprehensions__tests__C403_C403.py.snap +++ b/crates/ruff_linter/src/rules/flake8_comprehensions/snapshots/ruff_linter__rules__flake8_comprehensions__tests__C403_C403.py.snap @@ -220,6 +220,8 @@ C403.py:21:5: C403 [*] Unnecessary list comprehension (rewrite as a set comprehe 22 | | x for x in range(3) 23 | | ]) | |__^ C403 +24 | +25 | s = set(([x for x in range(3)])) | = help: Rewrite as a set comprehension @@ -232,3 +234,77 @@ C403.py:21:5: C403 [*] Unnecessary list comprehension (rewrite as a set comprehe 22 22 | x for x in range(3) 23 |-]) 23 |+} +24 24 | +25 25 | s = set(([x for x in range(3)])) +26 26 | + +C403.py:25:5: C403 [*] Unnecessary list comprehension (rewrite as a set comprehension) + | +23 | ]) +24 | +25 | s = set(([x for x in range(3)])) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C403 +26 | +27 | s = set(((([x for x in range(3)])))) + | + = help: Rewrite as a set comprehension + +ℹ Unsafe fix +22 22 | x for x in range(3) +23 23 | ]) +24 24 | +25 |-s = set(([x for x in range(3)])) + 25 |+s = {x for x in range(3)} +26 26 | +27 27 | s = set(((([x for x in range(3)])))) +28 28 | + +C403.py:27:5: C403 [*] Unnecessary list comprehension (rewrite as a set comprehension) + | +25 | s = set(([x for x in range(3)])) +26 | +27 | s = set(((([x for x in range(3)])))) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C403 +28 | +29 | s = set( # outer set comment + | + = help: Rewrite as a set comprehension + +ℹ Unsafe fix +24 24 | +25 25 | s = set(([x for x in range(3)])) +26 26 | +27 |-s = set(((([x for x in range(3)])))) + 27 |+s = {x for x in range(3)} +28 28 | +29 29 | s = set( # outer set comment +30 30 | ( # inner paren comment - not preserved + +C403.py:29:5: C403 [*] Unnecessary list comprehension (rewrite as a set comprehension) + | +27 | s = set(((([x for x in range(3)])))) +28 | +29 | s = set( # outer set comment + | _____^ +30 | | ( # inner paren comment - not preserved +31 | | (( +32 | | [ # comprehension comment +33 | | x for x in range(3)] +34 | | )))) + | |_____^ C403 + | + = help: Rewrite as a set comprehension + +ℹ Unsafe fix +26 26 | +27 27 | s = set(((([x for x in range(3)])))) +28 28 | +29 |-s = set( # outer set comment +30 |-( # inner paren comment - not preserved +31 |-(( +32 |-[ # comprehension comment +33 |- x for x in range(3)] +34 |- )))) + 29 |+s = { # outer set comment + 30 |+ # comprehension comment + 31 |+ x for x in range(3)}