Skip to content

Commit f110d80

Browse files
authored
[refurb] Skip slice-to-remove-prefix-or-suffix (FURB188) when nontrivial slice step is present (#13405)
1 parent a6d3d2f commit f110d80

File tree

3 files changed

+116
-1
lines changed

3 files changed

+116
-1
lines changed

crates/ruff_linter/resources/test/fixtures/refurb/FURB188.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,4 +151,22 @@ def remove_prefix_comparable_literal_expr() -> None:
151151
def shadow_builtins(filename: str, extension: str) -> None:
152152
from builtins import len as builtins_len
153153

154-
return filename[:-builtins_len(extension)] if filename.endswith(extension) else filename
154+
return filename[:-builtins_len(extension)] if filename.endswith(extension) else filename
155+
156+
def okay_steps():
157+
text = "!x!y!z"
158+
if text.startswith("!"):
159+
text = text[1::1]
160+
if text.startswith("!"):
161+
text = text[1::True]
162+
if text.startswith("!"):
163+
text = text[1::None]
164+
print(text)
165+
166+
167+
# this should be skipped
168+
def ignore_step():
169+
text = "!x!y!z"
170+
if text.startswith("!"):
171+
text = text[1::2]
172+
print(text)

crates/ruff_linter/src/rules/refurb/rules/slice_to_remove_prefix_or_suffix.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,27 @@ fn affix_removal_data<'a>(
246246
return None;
247247
}
248248
let slice = slice.as_slice_expr()?;
249+
250+
// Exit early if slice step is...
251+
if slice
252+
.step
253+
.as_deref()
254+
// present and
255+
.is_some_and(|step| match step {
256+
// not equal to 1
257+
ast::Expr::NumberLiteral(ast::ExprNumberLiteral {
258+
value: ast::Number::Int(x),
259+
..
260+
}) => x.as_u8() != Some(1),
261+
// and not equal to `None` or `True`
262+
ast::Expr::NoneLiteral(_)
263+
| ast::Expr::BooleanLiteral(ast::ExprBooleanLiteral { value: true, .. }) => false,
264+
_ => true,
265+
})
266+
{
267+
return None;
268+
};
269+
249270
let compr_test_expr = ast::comparable::ComparableExpr::from(
250271
&test.as_call_expr()?.func.as_attribute_expr()?.value,
251272
);

crates/ruff_linter/src/rules/refurb/snapshots/ruff_linter__rules__refurb__tests__FURB188_FURB188.py.snap

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,8 @@ FURB188.py:154:12: FURB188 [*] Prefer `removesuffix` over conditionally replacin
166166
153 |
167167
154 | return filename[:-builtins_len(extension)] if filename.endswith(extension) else filename
168168
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ FURB188
169+
155 |
170+
156 | def okay_steps():
169171
|
170172
= help: Use removesuffix instead of ternary expression conditional upon endswith.
171173

@@ -175,3 +177,77 @@ FURB188.py:154:12: FURB188 [*] Prefer `removesuffix` over conditionally replacin
175177
153 153 |
176178
154 |- return filename[:-builtins_len(extension)] if filename.endswith(extension) else filename
177179
154 |+ return filename.removesuffix(extension)
180+
155 155 |
181+
156 156 | def okay_steps():
182+
157 157 | text = "!x!y!z"
183+
184+
FURB188.py:158:5: FURB188 [*] Prefer `removeprefix` over conditionally replacing with slice.
185+
|
186+
156 | def okay_steps():
187+
157 | text = "!x!y!z"
188+
158 | if text.startswith("!"):
189+
| _____^
190+
159 | | text = text[1::1]
191+
| |_________________________^ FURB188
192+
160 | if text.startswith("!"):
193+
161 | text = text[1::True]
194+
|
195+
= help: Use removeprefix instead of assignment conditional upon startswith.
196+
197+
Safe fix
198+
155 155 |
199+
156 156 | def okay_steps():
200+
157 157 | text = "!x!y!z"
201+
158 |- if text.startswith("!"):
202+
159 |- text = text[1::1]
203+
158 |+ text = text.removeprefix("!")
204+
160 159 | if text.startswith("!"):
205+
161 160 | text = text[1::True]
206+
162 161 | if text.startswith("!"):
207+
208+
FURB188.py:160:5: FURB188 [*] Prefer `removeprefix` over conditionally replacing with slice.
209+
|
210+
158 | if text.startswith("!"):
211+
159 | text = text[1::1]
212+
160 | if text.startswith("!"):
213+
| _____^
214+
161 | | text = text[1::True]
215+
| |____________________________^ FURB188
216+
162 | if text.startswith("!"):
217+
163 | text = text[1::None]
218+
|
219+
= help: Use removeprefix instead of assignment conditional upon startswith.
220+
221+
Safe fix
222+
157 157 | text = "!x!y!z"
223+
158 158 | if text.startswith("!"):
224+
159 159 | text = text[1::1]
225+
160 |- if text.startswith("!"):
226+
161 |- text = text[1::True]
227+
160 |+ text = text.removeprefix("!")
228+
162 161 | if text.startswith("!"):
229+
163 162 | text = text[1::None]
230+
164 163 | print(text)
231+
232+
FURB188.py:162:5: FURB188 [*] Prefer `removeprefix` over conditionally replacing with slice.
233+
|
234+
160 | if text.startswith("!"):
235+
161 | text = text[1::True]
236+
162 | if text.startswith("!"):
237+
| _____^
238+
163 | | text = text[1::None]
239+
| |____________________________^ FURB188
240+
164 | print(text)
241+
|
242+
= help: Use removeprefix instead of assignment conditional upon startswith.
243+
244+
Safe fix
245+
159 159 | text = text[1::1]
246+
160 160 | if text.startswith("!"):
247+
161 161 | text = text[1::True]
248+
162 |- if text.startswith("!"):
249+
163 |- text = text[1::None]
250+
162 |+ text = text.removeprefix("!")
251+
164 163 | print(text)
252+
165 164 |
253+
166 165 |

0 commit comments

Comments
 (0)