diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM905.py b/crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM905.py index 86ef2171949ff7..049b60dfaffc60 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM905.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM905.py @@ -110,3 +110,23 @@ # https://github.com/astral-sh/ruff/issues/18042 print("a,b".rsplit(",")) print("a,b,c".rsplit(",", 1)) + +# https://github.com/astral-sh/ruff/issues/18069 + +print("".split(maxsplit=0)) +print("".split(sep=None, maxsplit=0)) +print(" ".split(maxsplit=0)) +print(" ".split(sep=None, maxsplit=0)) +print(" x ".split(maxsplit=0)) +print(" x ".split(sep=None, maxsplit=0)) +print(" x ".split(maxsplit=0)) +print(" x ".split(sep=None, maxsplit=0)) +print("".rsplit(maxsplit=0)) +print("".rsplit(sep=None, maxsplit=0)) +print(" ".rsplit(maxsplit=0)) +print(" ".rsplit(sep=None, maxsplit=0)) +print(" x ".rsplit(maxsplit=0)) +print(" x ".rsplit(maxsplit=0)) +print(" x ".rsplit(sep=None, maxsplit=0)) +print(" x ".rsplit(maxsplit=0)) +print(" x ".rsplit(sep=None, maxsplit=0)) \ No newline at end of file diff --git a/crates/ruff_linter/src/rules/flake8_simplify/rules/split_static_string.rs b/crates/ruff_linter/src/rules/flake8_simplify/rules/split_static_string.rs index 8c9c863b64d786..af2b4797d518a5 100644 --- a/crates/ruff_linter/src/rules/flake8_simplify/rules/split_static_string.rs +++ b/crates/ruff_linter/src/rules/flake8_simplify/rules/split_static_string.rs @@ -83,7 +83,7 @@ pub(crate) fn split_static_string( let sep_arg = arguments.find_argument_value("sep", 0); let split_replacement = if let Some(sep) = sep_arg { match sep { - Expr::NoneLiteral(_) => split_default(str_value, maxsplit_value), + Expr::NoneLiteral(_) => split_default(str_value, maxsplit_value, direction), Expr::StringLiteral(sep_value) => { let sep_value_str = sep_value.value.to_str(); Some(split_sep( @@ -99,7 +99,7 @@ pub(crate) fn split_static_string( } } } else { - split_default(str_value, maxsplit_value) + split_default(str_value, maxsplit_value, direction) }; let mut diagnostic = Diagnostic::new(SplitStaticString, call.range()); @@ -144,7 +144,11 @@ fn construct_replacement(elts: &[&str], flags: StringLiteralFlags) -> Expr { }) } -fn split_default(str_value: &StringLiteralValue, max_split: i32) -> Option { +fn split_default( + str_value: &StringLiteralValue, + max_split: i32, + direction: Direction, +) -> Option { // From the Python documentation: // > If sep is not specified or is None, a different splitting algorithm is applied: runs of // > consecutive whitespace are regarded as a single separator, and the result will contain @@ -152,6 +156,7 @@ fn split_default(str_value: &StringLiteralValue, max_split: i32) -> Option // > Consequently, splitting an empty string or a string consisting of just whitespace with // > a None separator returns []. // https://docs.python.org/3/library/stdtypes.html#str.split + let string_val = str_value.to_str(); match max_split.cmp(&0) { Ordering::Greater => { // Autofix for `maxsplit` without separator not yet implemented, as @@ -160,14 +165,30 @@ fn split_default(str_value: &StringLiteralValue, max_split: i32) -> Option None } Ordering::Equal => { - let list_items: Vec<&str> = vec![str_value.to_str()]; + // Behavior for maxsplit = 0 when sep is None: + // - If the string is empty or all whitespace, result is []. + // - Otherwise: + // - " x ".split(maxsplit=0) -> ['x '] + // - " x ".rsplit(maxsplit=0) -> [' x'] + // - "".split(maxsplit=0) -> [] + // - " ".split(maxsplit=0) -> [] + let processed_str = if direction == Direction::Left { + string_val.trim_start() + } else { + string_val.trim_end() + }; + let list_items: &[_] = if processed_str.is_empty() { + &[] + } else { + &[processed_str] + }; Some(construct_replacement( - &list_items, + list_items, str_value.first_literal_flags(), )) } Ordering::Less => { - let list_items: Vec<&str> = str_value.to_str().split_whitespace().collect(); + let list_items: Vec<&str> = string_val.split_whitespace().collect(); Some(construct_replacement( &list_items, str_value.first_literal_flags(), diff --git a/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM905_SIM905.py.snap b/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM905_SIM905.py.snap index 0a3684c5ce71e5..ae93115007f43f 100644 --- a/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM905_SIM905.py.snap +++ b/crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM905_SIM905.py.snap @@ -890,6 +890,8 @@ SIM905.py:111:7: SIM905 [*] Consider using a list literal instead of `str.split` 111 |-print("a,b".rsplit(",")) 111 |+print(["a", "b"]) 112 112 | print("a,b,c".rsplit(",", 1)) +113 113 | +114 114 | # https://github.com/astral-sh/ruff/issues/18069 SIM905.py:112:7: SIM905 [*] Consider using a list literal instead of `str.split` | @@ -897,6 +899,8 @@ SIM905.py:112:7: SIM905 [*] Consider using a list literal instead of `str.split` 111 | print("a,b".rsplit(",")) 112 | print("a,b,c".rsplit(",", 1)) | ^^^^^^^^^^^^^^^^^^^^^^ SIM905 +113 | +114 | # https://github.com/astral-sh/ruff/issues/18069 | = help: Replace with list literal @@ -906,3 +910,353 @@ SIM905.py:112:7: SIM905 [*] Consider using a list literal instead of `str.split` 111 111 | print("a,b".rsplit(",")) 112 |-print("a,b,c".rsplit(",", 1)) 112 |+print(["a,b", "c"]) +113 113 | +114 114 | # https://github.com/astral-sh/ruff/issues/18069 +115 115 | + +SIM905.py:116:7: SIM905 [*] Consider using a list literal instead of `str.split` + | +114 | # https://github.com/astral-sh/ruff/issues/18069 +115 | +116 | print("".split(maxsplit=0)) + | ^^^^^^^^^^^^^^^^^^^^ SIM905 +117 | print("".split(sep=None, maxsplit=0)) +118 | print(" ".split(maxsplit=0)) + | + = help: Replace with list literal + +ℹ Safe fix +113 113 | +114 114 | # https://github.com/astral-sh/ruff/issues/18069 +115 115 | +116 |-print("".split(maxsplit=0)) + 116 |+print([]) +117 117 | print("".split(sep=None, maxsplit=0)) +118 118 | print(" ".split(maxsplit=0)) +119 119 | print(" ".split(sep=None, maxsplit=0)) + +SIM905.py:117:7: SIM905 [*] Consider using a list literal instead of `str.split` + | +116 | print("".split(maxsplit=0)) +117 | print("".split(sep=None, maxsplit=0)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM905 +118 | print(" ".split(maxsplit=0)) +119 | print(" ".split(sep=None, maxsplit=0)) + | + = help: Replace with list literal + +ℹ Safe fix +114 114 | # https://github.com/astral-sh/ruff/issues/18069 +115 115 | +116 116 | print("".split(maxsplit=0)) +117 |-print("".split(sep=None, maxsplit=0)) + 117 |+print([]) +118 118 | print(" ".split(maxsplit=0)) +119 119 | print(" ".split(sep=None, maxsplit=0)) +120 120 | print(" x ".split(maxsplit=0)) + +SIM905.py:118:7: SIM905 [*] Consider using a list literal instead of `str.split` + | +116 | print("".split(maxsplit=0)) +117 | print("".split(sep=None, maxsplit=0)) +118 | print(" ".split(maxsplit=0)) + | ^^^^^^^^^^^^^^^^^^^^^ SIM905 +119 | print(" ".split(sep=None, maxsplit=0)) +120 | print(" x ".split(maxsplit=0)) + | + = help: Replace with list literal + +ℹ Safe fix +115 115 | +116 116 | print("".split(maxsplit=0)) +117 117 | print("".split(sep=None, maxsplit=0)) +118 |-print(" ".split(maxsplit=0)) + 118 |+print([]) +119 119 | print(" ".split(sep=None, maxsplit=0)) +120 120 | print(" x ".split(maxsplit=0)) +121 121 | print(" x ".split(sep=None, maxsplit=0)) + +SIM905.py:119:7: SIM905 [*] Consider using a list literal instead of `str.split` + | +117 | print("".split(sep=None, maxsplit=0)) +118 | print(" ".split(maxsplit=0)) +119 | print(" ".split(sep=None, maxsplit=0)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM905 +120 | print(" x ".split(maxsplit=0)) +121 | print(" x ".split(sep=None, maxsplit=0)) + | + = help: Replace with list literal + +ℹ Safe fix +116 116 | print("".split(maxsplit=0)) +117 117 | print("".split(sep=None, maxsplit=0)) +118 118 | print(" ".split(maxsplit=0)) +119 |-print(" ".split(sep=None, maxsplit=0)) + 119 |+print([]) +120 120 | print(" x ".split(maxsplit=0)) +121 121 | print(" x ".split(sep=None, maxsplit=0)) +122 122 | print(" x ".split(maxsplit=0)) + +SIM905.py:120:7: SIM905 [*] Consider using a list literal instead of `str.split` + | +118 | print(" ".split(maxsplit=0)) +119 | print(" ".split(sep=None, maxsplit=0)) +120 | print(" x ".split(maxsplit=0)) + | ^^^^^^^^^^^^^^^^^^^^^^^ SIM905 +121 | print(" x ".split(sep=None, maxsplit=0)) +122 | print(" x ".split(maxsplit=0)) + | + = help: Replace with list literal + +ℹ Safe fix +117 117 | print("".split(sep=None, maxsplit=0)) +118 118 | print(" ".split(maxsplit=0)) +119 119 | print(" ".split(sep=None, maxsplit=0)) +120 |-print(" x ".split(maxsplit=0)) + 120 |+print(["x "]) +121 121 | print(" x ".split(sep=None, maxsplit=0)) +122 122 | print(" x ".split(maxsplit=0)) +123 123 | print(" x ".split(sep=None, maxsplit=0)) + +SIM905.py:121:7: SIM905 [*] Consider using a list literal instead of `str.split` + | +119 | print(" ".split(sep=None, maxsplit=0)) +120 | print(" x ".split(maxsplit=0)) +121 | print(" x ".split(sep=None, maxsplit=0)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM905 +122 | print(" x ".split(maxsplit=0)) +123 | print(" x ".split(sep=None, maxsplit=0)) + | + = help: Replace with list literal + +ℹ Safe fix +118 118 | print(" ".split(maxsplit=0)) +119 119 | print(" ".split(sep=None, maxsplit=0)) +120 120 | print(" x ".split(maxsplit=0)) +121 |-print(" x ".split(sep=None, maxsplit=0)) + 121 |+print(["x "]) +122 122 | print(" x ".split(maxsplit=0)) +123 123 | print(" x ".split(sep=None, maxsplit=0)) +124 124 | print("".rsplit(maxsplit=0)) + +SIM905.py:122:7: SIM905 [*] Consider using a list literal instead of `str.split` + | +120 | print(" x ".split(maxsplit=0)) +121 | print(" x ".split(sep=None, maxsplit=0)) +122 | print(" x ".split(maxsplit=0)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^ SIM905 +123 | print(" x ".split(sep=None, maxsplit=0)) +124 | print("".rsplit(maxsplit=0)) + | + = help: Replace with list literal + +ℹ Safe fix +119 119 | print(" ".split(sep=None, maxsplit=0)) +120 120 | print(" x ".split(maxsplit=0)) +121 121 | print(" x ".split(sep=None, maxsplit=0)) +122 |-print(" x ".split(maxsplit=0)) + 122 |+print(["x "]) +123 123 | print(" x ".split(sep=None, maxsplit=0)) +124 124 | print("".rsplit(maxsplit=0)) +125 125 | print("".rsplit(sep=None, maxsplit=0)) + +SIM905.py:123:7: SIM905 [*] Consider using a list literal instead of `str.split` + | +121 | print(" x ".split(sep=None, maxsplit=0)) +122 | print(" x ".split(maxsplit=0)) +123 | print(" x ".split(sep=None, maxsplit=0)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM905 +124 | print("".rsplit(maxsplit=0)) +125 | print("".rsplit(sep=None, maxsplit=0)) + | + = help: Replace with list literal + +ℹ Safe fix +120 120 | print(" x ".split(maxsplit=0)) +121 121 | print(" x ".split(sep=None, maxsplit=0)) +122 122 | print(" x ".split(maxsplit=0)) +123 |-print(" x ".split(sep=None, maxsplit=0)) + 123 |+print(["x "]) +124 124 | print("".rsplit(maxsplit=0)) +125 125 | print("".rsplit(sep=None, maxsplit=0)) +126 126 | print(" ".rsplit(maxsplit=0)) + +SIM905.py:124:7: SIM905 [*] Consider using a list literal instead of `str.split` + | +122 | print(" x ".split(maxsplit=0)) +123 | print(" x ".split(sep=None, maxsplit=0)) +124 | print("".rsplit(maxsplit=0)) + | ^^^^^^^^^^^^^^^^^^^^^ SIM905 +125 | print("".rsplit(sep=None, maxsplit=0)) +126 | print(" ".rsplit(maxsplit=0)) + | + = help: Replace with list literal + +ℹ Safe fix +121 121 | print(" x ".split(sep=None, maxsplit=0)) +122 122 | print(" x ".split(maxsplit=0)) +123 123 | print(" x ".split(sep=None, maxsplit=0)) +124 |-print("".rsplit(maxsplit=0)) + 124 |+print([]) +125 125 | print("".rsplit(sep=None, maxsplit=0)) +126 126 | print(" ".rsplit(maxsplit=0)) +127 127 | print(" ".rsplit(sep=None, maxsplit=0)) + +SIM905.py:125:7: SIM905 [*] Consider using a list literal instead of `str.split` + | +123 | print(" x ".split(sep=None, maxsplit=0)) +124 | print("".rsplit(maxsplit=0)) +125 | print("".rsplit(sep=None, maxsplit=0)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM905 +126 | print(" ".rsplit(maxsplit=0)) +127 | print(" ".rsplit(sep=None, maxsplit=0)) + | + = help: Replace with list literal + +ℹ Safe fix +122 122 | print(" x ".split(maxsplit=0)) +123 123 | print(" x ".split(sep=None, maxsplit=0)) +124 124 | print("".rsplit(maxsplit=0)) +125 |-print("".rsplit(sep=None, maxsplit=0)) + 125 |+print([]) +126 126 | print(" ".rsplit(maxsplit=0)) +127 127 | print(" ".rsplit(sep=None, maxsplit=0)) +128 128 | print(" x ".rsplit(maxsplit=0)) + +SIM905.py:126:7: SIM905 [*] Consider using a list literal instead of `str.split` + | +124 | print("".rsplit(maxsplit=0)) +125 | print("".rsplit(sep=None, maxsplit=0)) +126 | print(" ".rsplit(maxsplit=0)) + | ^^^^^^^^^^^^^^^^^^^^^^ SIM905 +127 | print(" ".rsplit(sep=None, maxsplit=0)) +128 | print(" x ".rsplit(maxsplit=0)) + | + = help: Replace with list literal + +ℹ Safe fix +123 123 | print(" x ".split(sep=None, maxsplit=0)) +124 124 | print("".rsplit(maxsplit=0)) +125 125 | print("".rsplit(sep=None, maxsplit=0)) +126 |-print(" ".rsplit(maxsplit=0)) + 126 |+print([]) +127 127 | print(" ".rsplit(sep=None, maxsplit=0)) +128 128 | print(" x ".rsplit(maxsplit=0)) +129 129 | print(" x ".rsplit(maxsplit=0)) + +SIM905.py:127:7: SIM905 [*] Consider using a list literal instead of `str.split` + | +125 | print("".rsplit(sep=None, maxsplit=0)) +126 | print(" ".rsplit(maxsplit=0)) +127 | print(" ".rsplit(sep=None, maxsplit=0)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM905 +128 | print(" x ".rsplit(maxsplit=0)) +129 | print(" x ".rsplit(maxsplit=0)) + | + = help: Replace with list literal + +ℹ Safe fix +124 124 | print("".rsplit(maxsplit=0)) +125 125 | print("".rsplit(sep=None, maxsplit=0)) +126 126 | print(" ".rsplit(maxsplit=0)) +127 |-print(" ".rsplit(sep=None, maxsplit=0)) + 127 |+print([]) +128 128 | print(" x ".rsplit(maxsplit=0)) +129 129 | print(" x ".rsplit(maxsplit=0)) +130 130 | print(" x ".rsplit(sep=None, maxsplit=0)) + +SIM905.py:128:7: SIM905 [*] Consider using a list literal instead of `str.split` + | +126 | print(" ".rsplit(maxsplit=0)) +127 | print(" ".rsplit(sep=None, maxsplit=0)) +128 | print(" x ".rsplit(maxsplit=0)) + | ^^^^^^^^^^^^^^^^^^^^^^^^ SIM905 +129 | print(" x ".rsplit(maxsplit=0)) +130 | print(" x ".rsplit(sep=None, maxsplit=0)) + | + = help: Replace with list literal + +ℹ Safe fix +125 125 | print("".rsplit(sep=None, maxsplit=0)) +126 126 | print(" ".rsplit(maxsplit=0)) +127 127 | print(" ".rsplit(sep=None, maxsplit=0)) +128 |-print(" x ".rsplit(maxsplit=0)) + 128 |+print([" x"]) +129 129 | print(" x ".rsplit(maxsplit=0)) +130 130 | print(" x ".rsplit(sep=None, maxsplit=0)) +131 131 | print(" x ".rsplit(maxsplit=0)) + +SIM905.py:129:7: SIM905 [*] Consider using a list literal instead of `str.split` + | +127 | print(" ".rsplit(sep=None, maxsplit=0)) +128 | print(" x ".rsplit(maxsplit=0)) +129 | print(" x ".rsplit(maxsplit=0)) + | ^^^^^^^^^^^^^^^^^^^^^^^^ SIM905 +130 | print(" x ".rsplit(sep=None, maxsplit=0)) +131 | print(" x ".rsplit(maxsplit=0)) + | + = help: Replace with list literal + +ℹ Safe fix +126 126 | print(" ".rsplit(maxsplit=0)) +127 127 | print(" ".rsplit(sep=None, maxsplit=0)) +128 128 | print(" x ".rsplit(maxsplit=0)) +129 |-print(" x ".rsplit(maxsplit=0)) + 129 |+print([" x"]) +130 130 | print(" x ".rsplit(sep=None, maxsplit=0)) +131 131 | print(" x ".rsplit(maxsplit=0)) +132 132 | print(" x ".rsplit(sep=None, maxsplit=0)) + +SIM905.py:130:7: SIM905 [*] Consider using a list literal instead of `str.split` + | +128 | print(" x ".rsplit(maxsplit=0)) +129 | print(" x ".rsplit(maxsplit=0)) +130 | print(" x ".rsplit(sep=None, maxsplit=0)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM905 +131 | print(" x ".rsplit(maxsplit=0)) +132 | print(" x ".rsplit(sep=None, maxsplit=0)) + | + = help: Replace with list literal + +ℹ Safe fix +127 127 | print(" ".rsplit(sep=None, maxsplit=0)) +128 128 | print(" x ".rsplit(maxsplit=0)) +129 129 | print(" x ".rsplit(maxsplit=0)) +130 |-print(" x ".rsplit(sep=None, maxsplit=0)) + 130 |+print([" x"]) +131 131 | print(" x ".rsplit(maxsplit=0)) +132 132 | print(" x ".rsplit(sep=None, maxsplit=0)) + +SIM905.py:131:7: SIM905 [*] Consider using a list literal instead of `str.split` + | +129 | print(" x ".rsplit(maxsplit=0)) +130 | print(" x ".rsplit(sep=None, maxsplit=0)) +131 | print(" x ".rsplit(maxsplit=0)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM905 +132 | print(" x ".rsplit(sep=None, maxsplit=0)) + | + = help: Replace with list literal + +ℹ Safe fix +128 128 | print(" x ".rsplit(maxsplit=0)) +129 129 | print(" x ".rsplit(maxsplit=0)) +130 130 | print(" x ".rsplit(sep=None, maxsplit=0)) +131 |-print(" x ".rsplit(maxsplit=0)) + 131 |+print([" x"]) +132 132 | print(" x ".rsplit(sep=None, maxsplit=0)) + +SIM905.py:132:7: SIM905 [*] Consider using a list literal instead of `str.split` + | +130 | print(" x ".rsplit(sep=None, maxsplit=0)) +131 | print(" x ".rsplit(maxsplit=0)) +132 | print(" x ".rsplit(sep=None, maxsplit=0)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM905 + | + = help: Replace with list literal + +ℹ Safe fix +129 129 | print(" x ".rsplit(maxsplit=0)) +130 130 | print(" x ".rsplit(sep=None, maxsplit=0)) +131 131 | print(" x ".rsplit(maxsplit=0)) +132 |-print(" x ".rsplit(sep=None, maxsplit=0)) + 132 |+print([" x"])