Skip to content

Commit 238ec39

Browse files
authored
[refurb] Avoid panicking unwrap in verbose-decimal-constructor (FURB157) (#16777)
1 parent b04103f commit 238ec39

File tree

3 files changed

+196
-12
lines changed

3 files changed

+196
-12
lines changed

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

+14-1
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,23 @@
4949
Decimal(float(" +nan ")) # Decimal(" +nan ")
5050
# In this one case, " -nan ", the fix has to be
5151
# `Decimal(" nan ")`` because `Decimal("-nan") != Decimal(float("-nan"))`
52-
Decimal(float(" -nan ")) # Decimal(" nan ")
52+
Decimal(float(" -nan ")) # Decimal("nan")
5353
Decimal(float(" inf ")) # Decimal(" inf ")
5454
Decimal(float(" +inf ")) # Decimal(" +inf ")
5555
Decimal(float(" -inf ")) # Decimal(" -inf ")
5656
Decimal(float(" infinity ")) # Decimal(" infinity ")
5757
Decimal(float(" +infinity ")) # Decimal(" +infinity ")
5858
Decimal(float(" -infinity ")) # Decimal(" -infinity ")
59+
60+
# Escape sequence handling in "-nan" case
61+
# Here we do not bother respecting the original whitespace
62+
# and other trivia when offering a fix.
63+
# https://github.com/astral-sh/ruff/issues/16771
64+
Decimal(float("\x2dnan"))
65+
Decimal(float("\x20\x2dnan"))
66+
Decimal(float("\x20\u002dnan"))
67+
Decimal(float("\x20\U0000002dnan"))
68+
Decimal(float("\N{space}\N{hyPHen-MINus}nan"))
69+
Decimal(float("\x20\N{character tabulation}\N{hyphen-minus}nan"))
70+
Decimal(float(" -" "nan"))
71+
Decimal(float("-nAn"))

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

+5-1
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,11 @@ pub(crate) fn verbose_decimal_constructor(checker: &Checker, call: &ast::ExprCal
178178
let mut replacement = checker.locator().slice(float).to_string();
179179
// `Decimal(float("-nan")) == Decimal("nan")`
180180
if trimmed.eq_ignore_ascii_case("-nan") {
181-
replacement.remove(replacement.find('-').unwrap());
181+
// Here we do not attempt to remove just the '-' character.
182+
// It may have been encoded (e.g. as '\N{hyphen-minus}')
183+
// in the original source slice, and the added complexity
184+
// does not make sense for this edge case.
185+
replacement = "\"nan\"".to_string();
182186
}
183187
let mut diagnostic = Diagnostic::new(
184188
VerboseDecimalConstructor {

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

+177-10
Original file line numberDiff line numberDiff line change
@@ -247,33 +247,33 @@ FURB157.py:49:9: FURB157 [*] Verbose expression in `Decimal` constructor
247247
49 |+Decimal(" +nan ") # Decimal(" +nan ")
248248
50 50 | # In this one case, " -nan ", the fix has to be
249249
51 51 | # `Decimal(" nan ")`` because `Decimal("-nan") != Decimal(float("-nan"))`
250-
52 52 | Decimal(float(" -nan ")) # Decimal(" nan ")
250+
52 52 | Decimal(float(" -nan ")) # Decimal("nan")
251251
252252
FURB157.py:52:9: FURB157 [*] Verbose expression in `Decimal` constructor
253253
|
254254
50 | # In this one case, " -nan ", the fix has to be
255255
51 | # `Decimal(" nan ")`` because `Decimal("-nan") != Decimal(float("-nan"))`
256-
52 | Decimal(float(" -nan ")) # Decimal(" nan ")
256+
52 | Decimal(float(" -nan ")) # Decimal("nan")
257257
| ^^^^^^^^^^^^^^^ FURB157
258258
53 | Decimal(float(" inf ")) # Decimal(" inf ")
259259
54 | Decimal(float(" +inf ")) # Decimal(" +inf ")
260260
|
261-
= help: Replace with `" nan "`
261+
= help: Replace with `"nan"`
262262

263263
Safe fix
264264
49 49 | Decimal(float(" +nan ")) # Decimal(" +nan ")
265265
50 50 | # In this one case, " -nan ", the fix has to be
266266
51 51 | # `Decimal(" nan ")`` because `Decimal("-nan") != Decimal(float("-nan"))`
267-
52 |-Decimal(float(" -nan ")) # Decimal(" nan ")
268-
52 |+Decimal(" nan ") # Decimal(" nan ")
267+
52 |-Decimal(float(" -nan ")) # Decimal("nan")
268+
52 |+Decimal("nan") # Decimal("nan")
269269
53 53 | Decimal(float(" inf ")) # Decimal(" inf ")
270270
54 54 | Decimal(float(" +inf ")) # Decimal(" +inf ")
271271
55 55 | Decimal(float(" -inf ")) # Decimal(" -inf ")
272272
273273
FURB157.py:53:9: FURB157 [*] Verbose expression in `Decimal` constructor
274274
|
275275
51 | # `Decimal(" nan ")`` because `Decimal("-nan") != Decimal(float("-nan"))`
276-
52 | Decimal(float(" -nan ")) # Decimal(" nan ")
276+
52 | Decimal(float(" -nan ")) # Decimal("nan")
277277
53 | Decimal(float(" inf ")) # Decimal(" inf ")
278278
| ^^^^^^^^^^^^^^ FURB157
279279
54 | Decimal(float(" +inf ")) # Decimal(" +inf ")
@@ -284,7 +284,7 @@ FURB157.py:53:9: FURB157 [*] Verbose expression in `Decimal` constructor
284284
Safe fix
285285
50 50 | # In this one case, " -nan ", the fix has to be
286286
51 51 | # `Decimal(" nan ")`` because `Decimal("-nan") != Decimal(float("-nan"))`
287-
52 52 | Decimal(float(" -nan ")) # Decimal(" nan ")
287+
52 52 | Decimal(float(" -nan ")) # Decimal("nan")
288288
53 |-Decimal(float(" inf ")) # Decimal(" inf ")
289289
53 |+Decimal(" inf ") # Decimal(" inf ")
290290
54 54 | Decimal(float(" +inf ")) # Decimal(" +inf ")
@@ -293,7 +293,7 @@ FURB157.py:53:9: FURB157 [*] Verbose expression in `Decimal` constructor
293293
294294
FURB157.py:54:9: FURB157 [*] Verbose expression in `Decimal` constructor
295295
|
296-
52 | Decimal(float(" -nan ")) # Decimal(" nan ")
296+
52 | Decimal(float(" -nan ")) # Decimal("nan")
297297
53 | Decimal(float(" inf ")) # Decimal(" inf ")
298298
54 | Decimal(float(" +inf ")) # Decimal(" +inf ")
299299
| ^^^^^^^^^^^^^^^ FURB157
@@ -304,7 +304,7 @@ FURB157.py:54:9: FURB157 [*] Verbose expression in `Decimal` constructor
304304
305305
ℹ Safe fix
306306
51 51 | # `Decimal(" nan ")`` because `Decimal("-nan") != Decimal(float("-nan"))`
307-
52 52 | Decimal(float(" -nan ")) # Decimal(" nan ")
307+
52 52 | Decimal(float(" -nan ")) # Decimal("nan")
308308
53 53 | Decimal(float(" inf ")) # Decimal(" inf ")
309309
54 |-Decimal(float(" +inf ")) # Decimal(" +inf ")
310310
54 |+Decimal(" +inf ") # Decimal(" +inf ")
@@ -324,7 +324,7 @@ FURB157.py:55:9: FURB157 [*] Verbose expression in `Decimal` constructor
324324
= help: Replace with `" -inf "`
325325

326326
Safe fix
327-
52 52 | Decimal(float(" -nan ")) # Decimal(" nan ")
327+
52 52 | Decimal(float(" -nan ")) # Decimal("nan")
328328
53 53 | Decimal(float(" inf ")) # Decimal(" inf ")
329329
54 54 | Decimal(float(" +inf ")) # Decimal(" +inf ")
330330
55 |-Decimal(float(" -inf ")) # Decimal(" -inf ")
@@ -352,6 +352,7 @@ FURB157.py:56:9: FURB157 [*] Verbose expression in `Decimal` constructor
352352
56 |+Decimal(" infinity ") # Decimal(" infinity ")
353353
57 57 | Decimal(float(" +infinity ")) # Decimal(" +infinity ")
354354
58 58 | Decimal(float(" -infinity ")) # Decimal(" -infinity ")
355+
59 59 |
355356

356357
FURB157.py:57:9: FURB157 [*] Verbose expression in `Decimal` constructor
357358
|
@@ -370,13 +371,17 @@ FURB157.py:57:9: FURB157 [*] Verbose expression in `Decimal` constructor
370371
57 |-Decimal(float(" +infinity ")) # Decimal(" +infinity ")
371372
57 |+Decimal(" +infinity ") # Decimal(" +infinity ")
372373
58 58 | Decimal(float(" -infinity ")) # Decimal(" -infinity ")
374+
59 59 |
375+
60 60 | # Escape sequence handling in "-nan" case
373376

374377
FURB157.py:58:9: FURB157 [*] Verbose expression in `Decimal` constructor
375378
|
376379
56 | Decimal(float(" infinity ")) # Decimal(" infinity ")
377380
57 | Decimal(float(" +infinity ")) # Decimal(" +infinity ")
378381
58 | Decimal(float(" -infinity ")) # Decimal(" -infinity ")
379382
| ^^^^^^^^^^^^^^^^^^^^ FURB157
383+
59 |
384+
60 | # Escape sequence handling in "-nan" case
380385
|
381386
= help: Replace with `" -infinity "`
382387

@@ -386,3 +391,165 @@ FURB157.py:58:9: FURB157 [*] Verbose expression in `Decimal` constructor
386391
57 57 | Decimal(float(" +infinity ")) # Decimal(" +infinity ")
387392
58 |-Decimal(float(" -infinity ")) # Decimal(" -infinity ")
388393
58 |+Decimal(" -infinity ") # Decimal(" -infinity ")
394+
59 59 |
395+
60 60 | # Escape sequence handling in "-nan" case
396+
61 61 | # Here we do not bother respecting the original whitespace
397+
398+
FURB157.py:64:9: FURB157 [*] Verbose expression in `Decimal` constructor
399+
|
400+
62 | # and other trivia when offering a fix.
401+
63 | # https://github.com/astral-sh/ruff/issues/16771
402+
64 | Decimal(float("\x2dnan"))
403+
| ^^^^^^^^^^^^^^^^ FURB157
404+
65 | Decimal(float("\x20\x2dnan"))
405+
66 | Decimal(float("\x20\u002dnan"))
406+
|
407+
= help: Replace with `"nan"`
408+
409+
Safe fix
410+
61 61 | # Here we do not bother respecting the original whitespace
411+
62 62 | # and other trivia when offering a fix.
412+
63 63 | # https://github.com/astral-sh/ruff/issues/16771
413+
64 |-Decimal(float("\x2dnan"))
414+
64 |+Decimal("nan")
415+
65 65 | Decimal(float("\x20\x2dnan"))
416+
66 66 | Decimal(float("\x20\u002dnan"))
417+
67 67 | Decimal(float("\x20\U0000002dnan"))
418+
419+
FURB157.py:65:9: FURB157 [*] Verbose expression in `Decimal` constructor
420+
|
421+
63 | # https://github.com/astral-sh/ruff/issues/16771
422+
64 | Decimal(float("\x2dnan"))
423+
65 | Decimal(float("\x20\x2dnan"))
424+
| ^^^^^^^^^^^^^^^^^^^^ FURB157
425+
66 | Decimal(float("\x20\u002dnan"))
426+
67 | Decimal(float("\x20\U0000002dnan"))
427+
|
428+
= help: Replace with `"nan"`
429+
430+
Safe fix
431+
62 62 | # and other trivia when offering a fix.
432+
63 63 | # https://github.com/astral-sh/ruff/issues/16771
433+
64 64 | Decimal(float("\x2dnan"))
434+
65 |-Decimal(float("\x20\x2dnan"))
435+
65 |+Decimal("nan")
436+
66 66 | Decimal(float("\x20\u002dnan"))
437+
67 67 | Decimal(float("\x20\U0000002dnan"))
438+
68 68 | Decimal(float("\N{space}\N{hyPHen-MINus}nan"))
439+
440+
FURB157.py:66:9: FURB157 [*] Verbose expression in `Decimal` constructor
441+
|
442+
64 | Decimal(float("\x2dnan"))
443+
65 | Decimal(float("\x20\x2dnan"))
444+
66 | Decimal(float("\x20\u002dnan"))
445+
| ^^^^^^^^^^^^^^^^^^^^^^ FURB157
446+
67 | Decimal(float("\x20\U0000002dnan"))
447+
68 | Decimal(float("\N{space}\N{hyPHen-MINus}nan"))
448+
|
449+
= help: Replace with `"nan"`
450+
451+
Safe fix
452+
63 63 | # https://github.com/astral-sh/ruff/issues/16771
453+
64 64 | Decimal(float("\x2dnan"))
454+
65 65 | Decimal(float("\x20\x2dnan"))
455+
66 |-Decimal(float("\x20\u002dnan"))
456+
66 |+Decimal("nan")
457+
67 67 | Decimal(float("\x20\U0000002dnan"))
458+
68 68 | Decimal(float("\N{space}\N{hyPHen-MINus}nan"))
459+
69 69 | Decimal(float("\x20\N{character tabulation}\N{hyphen-minus}nan"))
460+
461+
FURB157.py:67:9: FURB157 [*] Verbose expression in `Decimal` constructor
462+
|
463+
65 | Decimal(float("\x20\x2dnan"))
464+
66 | Decimal(float("\x20\u002dnan"))
465+
67 | Decimal(float("\x20\U0000002dnan"))
466+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ FURB157
467+
68 | Decimal(float("\N{space}\N{hyPHen-MINus}nan"))
468+
69 | Decimal(float("\x20\N{character tabulation}\N{hyphen-minus}nan"))
469+
|
470+
= help: Replace with `"nan"`
471+
472+
Safe fix
473+
64 64 | Decimal(float("\x2dnan"))
474+
65 65 | Decimal(float("\x20\x2dnan"))
475+
66 66 | Decimal(float("\x20\u002dnan"))
476+
67 |-Decimal(float("\x20\U0000002dnan"))
477+
67 |+Decimal("nan")
478+
68 68 | Decimal(float("\N{space}\N{hyPHen-MINus}nan"))
479+
69 69 | Decimal(float("\x20\N{character tabulation}\N{hyphen-minus}nan"))
480+
70 70 | Decimal(float(" -" "nan"))
481+
482+
FURB157.py:68:9: FURB157 [*] Verbose expression in `Decimal` constructor
483+
|
484+
66 | Decimal(float("\x20\u002dnan"))
485+
67 | Decimal(float("\x20\U0000002dnan"))
486+
68 | Decimal(float("\N{space}\N{hyPHen-MINus}nan"))
487+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ FURB157
488+
69 | Decimal(float("\x20\N{character tabulation}\N{hyphen-minus}nan"))
489+
70 | Decimal(float(" -" "nan"))
490+
|
491+
= help: Replace with `"nan"`
492+
493+
Safe fix
494+
65 65 | Decimal(float("\x20\x2dnan"))
495+
66 66 | Decimal(float("\x20\u002dnan"))
496+
67 67 | Decimal(float("\x20\U0000002dnan"))
497+
68 |-Decimal(float("\N{space}\N{hyPHen-MINus}nan"))
498+
68 |+Decimal("nan")
499+
69 69 | Decimal(float("\x20\N{character tabulation}\N{hyphen-minus}nan"))
500+
70 70 | Decimal(float(" -" "nan"))
501+
71 71 | Decimal(float("-nAn"))
502+
503+
FURB157.py:69:9: FURB157 [*] Verbose expression in `Decimal` constructor
504+
|
505+
67 | Decimal(float("\x20\U0000002dnan"))
506+
68 | Decimal(float("\N{space}\N{hyPHen-MINus}nan"))
507+
69 | Decimal(float("\x20\N{character tabulation}\N{hyphen-minus}nan"))
508+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ FURB157
509+
70 | Decimal(float(" -" "nan"))
510+
71 | Decimal(float("-nAn"))
511+
|
512+
= help: Replace with `"nan"`
513+
514+
Safe fix
515+
66 66 | Decimal(float("\x20\u002dnan"))
516+
67 67 | Decimal(float("\x20\U0000002dnan"))
517+
68 68 | Decimal(float("\N{space}\N{hyPHen-MINus}nan"))
518+
69 |-Decimal(float("\x20\N{character tabulation}\N{hyphen-minus}nan"))
519+
69 |+Decimal("nan")
520+
70 70 | Decimal(float(" -" "nan"))
521+
71 71 | Decimal(float("-nAn"))
522+
523+
FURB157.py:70:9: FURB157 [*] Verbose expression in `Decimal` constructor
524+
|
525+
68 | Decimal(float("\N{space}\N{hyPHen-MINus}nan"))
526+
69 | Decimal(float("\x20\N{character tabulation}\N{hyphen-minus}nan"))
527+
70 | Decimal(float(" -" "nan"))
528+
| ^^^^^^^^^^^^^^^^^^^ FURB157
529+
71 | Decimal(float("-nAn"))
530+
|
531+
= help: Replace with `"nan"`
532+
533+
Safe fix
534+
67 67 | Decimal(float("\x20\U0000002dnan"))
535+
68 68 | Decimal(float("\N{space}\N{hyPHen-MINus}nan"))
536+
69 69 | Decimal(float("\x20\N{character tabulation}\N{hyphen-minus}nan"))
537+
70 |-Decimal(float(" -" "nan"))
538+
70 |+Decimal("nan")
539+
71 71 | Decimal(float("-nAn"))
540+
541+
FURB157.py:71:9: FURB157 [*] Verbose expression in `Decimal` constructor
542+
|
543+
69 | Decimal(float("\x20\N{character tabulation}\N{hyphen-minus}nan"))
544+
70 | Decimal(float(" -" "nan"))
545+
71 | Decimal(float("-nAn"))
546+
| ^^^^^^^^^^^^^ FURB157
547+
|
548+
= help: Replace with `"nan"`
549+
550+
Safe fix
551+
68 68 | Decimal(float("\N{space}\N{hyPHen-MINus}nan"))
552+
69 69 | Decimal(float("\x20\N{character tabulation}\N{hyphen-minus}nan"))
553+
70 70 | Decimal(float(" -" "nan"))
554+
71 |-Decimal(float("-nAn"))
555+
71 |+Decimal("nan")

0 commit comments

Comments
 (0)