From c810b4f63f845d7a26f379099d0c73e18887def4 Mon Sep 17 00:00:00 2001 From: InSyncWithFoo Date: Fri, 3 Jan 2025 04:59:08 +0000 Subject: [PATCH 1/3] [`ruff`] Avoid fixing when `ndigits` is possibly negative (`RUF057`) --- .../resources/test/fixtures/ruff/RUF057.py | 23 +++++---- .../ruff/rules/unnecessary_cast_to_int.rs | 25 +++++----- .../src/rules/ruff/rules/unnecessary_round.rs | 48 ++++++++++++------- 3 files changed, 60 insertions(+), 36 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/ruff/RUF057.py b/crates/ruff_linter/resources/test/fixtures/ruff/RUF057.py index df33b0fb62944..7daf273bd7ae8 100644 --- a/crates/ruff_linter/resources/test/fixtures/ruff/RUF057.py +++ b/crates/ruff_linter/resources/test/fixtures/ruff/RUF057.py @@ -6,14 +6,16 @@ round(42) # Error (safe) round(42, None) # Error (safe) round(42, 2) # Error (safe) -round(42, inferred_int) # Error (safe) -round(42, 3 + 4) # Error (safe) -round(42, foo) # Error (unsafe) +round(42, -2) # No error +round(42, inferred_int) # No error +round(42, 3 + 4) # No error +round(42, foo) # No error round(42.) # No error round(42., None) # No error round(42., 2) # No error +round(42., -2) # No error round(42., inferred_int) # No error round(42., 3 + 4) # No error round(42., foo) # No error @@ -22,14 +24,16 @@ round(4 + 2) # Error (safe) round(4 + 2, None) # Error (safe) round(4 + 2, 2) # Error (safe) -round(4 + 2, inferred_int) # Error (safe) -round(4 + 2, 3 + 4) # Error (safe) -round(4 + 2, foo) # Error (unsafe) +round(4 + 2, -2) # No error +round(4 + 2, inferred_int) # No error +round(4 + 2, 3 + 4) # No error +round(4 + 2, foo) # No error round(4. + 2.) # No error round(4. + 2., None) # No error round(4. + 2., 2) # No error +round(4. + 2., -2) # No error round(4. + 2., inferred_int) # No error round(4. + 2., 3 + 4) # No error round(4. + 2., foo) # No error @@ -38,14 +42,16 @@ round(inferred_int) # Error (unsafe) round(inferred_int, None) # Error (unsafe) round(inferred_int, 2) # Error (unsafe) -round(inferred_int, inferred_int) # Error (unsafe) -round(inferred_int, 3 + 4) # Error (unsafe) +round(inferred_int, -2) # No error +round(inferred_int, inferred_int) # No error +round(inferred_int, 3 + 4) # No error round(inferred_int, foo) # No error round(inferred_float) # No error round(inferred_float, None) # No error round(inferred_float, 2) # No error +round(inferred_float, -2) # No error round(inferred_float, inferred_int) # No error round(inferred_float, 3 + 4) # No error round(inferred_float, foo) # No error @@ -54,6 +60,7 @@ round(lorem) # No error round(lorem, None) # No error round(lorem, 2) # No error +round(lorem, -2) # No error round(lorem, inferred_int) # No error round(lorem, 3 + 4) # No error round(lorem, foo) # No error diff --git a/crates/ruff_linter/src/rules/ruff/rules/unnecessary_cast_to_int.rs b/crates/ruff_linter/src/rules/ruff/rules/unnecessary_cast_to_int.rs index 28783fa8798c1..ab25bde1ae590 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/unnecessary_cast_to_int.rs +++ b/crates/ruff_linter/src/rules/ruff/rules/unnecessary_cast_to_int.rs @@ -179,37 +179,40 @@ fn round_applicability(arguments: &Arguments, semantic: &SemanticModel) -> Optio match (rounded_value, ndigits_value) { // ```python + // int(round(2, -1)) // int(round(2, 0)) // int(round(2)) // int(round(2, None)) // ``` ( RoundedValue::Int(InferredType::Equivalent), - NdigitsValue::Int(InferredType::Equivalent) - | NdigitsValue::NotGiven - | NdigitsValue::LiteralNone, + NdigitsValue::LiteralNegativeInt + | NdigitsValue::LiteralNonNegativeInt + | NdigitsValue::NonLiteralInt(InferredType::Equivalent) + | NdigitsValue::NotGivenOrNone, ) => Some(Applicability::Safe), // ```python // int(round(2.0)) // int(round(2.0, None)) // ``` - ( - RoundedValue::Float(InferredType::Equivalent), - NdigitsValue::NotGiven | NdigitsValue::LiteralNone, - ) => Some(Applicability::Safe), + (RoundedValue::Float(InferredType::Equivalent), NdigitsValue::NotGivenOrNone) => { + Some(Applicability::Safe) + } // ```python // a: int = 2 # or True + // int(round(a, -2)) // int(round(a, 1)) // int(round(a)) // int(round(a, None)) // ``` ( RoundedValue::Int(InferredType::AssignableTo), - NdigitsValue::Int(InferredType::Equivalent) - | NdigitsValue::NotGiven - | NdigitsValue::LiteralNone, + NdigitsValue::LiteralNonNegativeInt + | NdigitsValue::LiteralNegativeInt + | NdigitsValue::NonLiteralInt(InferredType::Equivalent) + | NdigitsValue::NotGivenOrNone, ) => Some(Applicability::Unsafe), // ```python @@ -220,7 +223,7 @@ fn round_applicability(arguments: &Arguments, semantic: &SemanticModel) -> Optio // ``` ( RoundedValue::Float(InferredType::AssignableTo) | RoundedValue::Other, - NdigitsValue::NotGiven | NdigitsValue::LiteralNone, + NdigitsValue::NotGivenOrNone, ) => Some(Applicability::Unsafe), _ => None, diff --git a/crates/ruff_linter/src/rules/ruff/rules/unnecessary_round.rs b/crates/ruff_linter/src/rules/ruff/rules/unnecessary_round.rs index d66845e1ea1df..ba55f4d26768c 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/unnecessary_round.rs +++ b/crates/ruff_linter/src/rules/ruff/rules/unnecessary_round.rs @@ -2,7 +2,7 @@ use crate::checkers::ast::Checker; use crate::Locator; use ruff_diagnostics::{AlwaysFixableViolation, Applicability, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, ViolationMetadata}; -use ruff_python_ast::{Arguments, Expr, ExprCall}; +use ruff_python_ast::{Arguments, Expr, ExprCall, ExprNumberLiteral, Number}; use ruff_python_semantic::analyze::type_inference::{NumberLike, PythonType, ResolvedPythonType}; use ruff_python_semantic::analyze::typing; use ruff_python_semantic::SemanticModel; @@ -52,14 +52,14 @@ pub(crate) fn unnecessary_round(checker: &mut Checker, call: &ExprCall) { return; }; - let applicability = match (rounded_value, ndigits_value) { - // ```python - // rounded(1, unknown) - // ``` - (RoundedValue::Int(InferredType::Equivalent), NdigitsValue::Other) => Applicability::Unsafe, - - (_, NdigitsValue::Other) => return, + if !matches!( + ndigits_value, + NdigitsValue::NotGivenOrNone | NdigitsValue::LiteralNonNegativeInt + ) { + return; + } + let applicability = match rounded_value { // ```python // some_int: int // @@ -69,7 +69,7 @@ pub(crate) fn unnecessary_round(checker: &mut Checker, call: &ExprCall) { // rounded(1, 4 + 2) // rounded(1, some_int) // ``` - (RoundedValue::Int(InferredType::Equivalent), _) => Applicability::Safe, + RoundedValue::Int(InferredType::Equivalent) => Applicability::Safe, // ```python // some_int: int @@ -81,7 +81,7 @@ pub(crate) fn unnecessary_round(checker: &mut Checker, call: &ExprCall) { // rounded(some_int, 4 + 2) // rounded(some_int, some_other_int) // ``` - (RoundedValue::Int(InferredType::AssignableTo), _) => Applicability::Unsafe, + RoundedValue::Int(InferredType::AssignableTo) => Applicability::Unsafe, _ => return, }; @@ -113,9 +113,10 @@ pub(super) enum RoundedValue { /// The type of the second argument to `round()` #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub(super) enum NdigitsValue { - NotGiven, - LiteralNone, - Int(InferredType), + NotGivenOrNone, + LiteralNegativeInt, + LiteralNonNegativeInt, + NonLiteralInt(InferredType), Other, } @@ -157,21 +158,34 @@ pub(super) fn rounded_and_ndigits<'a>( }; let ndigits_kind = match ndigits { - None => NdigitsValue::NotGiven, - Some(Expr::NoneLiteral(_)) => NdigitsValue::LiteralNone, + None | Some(Expr::NoneLiteral(_)) => NdigitsValue::NotGivenOrNone, Some(Expr::Name(name)) => { match semantic.only_binding(name).map(|id| semantic.binding(id)) { Some(binding) if typing::is_int(binding, semantic) => { - NdigitsValue::Int(InferredType::AssignableTo) + NdigitsValue::NonLiteralInt(InferredType::AssignableTo) } _ => NdigitsValue::Other, } } + Some(Expr::NumberLiteral(ExprNumberLiteral { + value: Number::Int(int), + .. + })) => match int.as_i64() { + None => NdigitsValue::NonLiteralInt(InferredType::Equivalent), + Some(value) => { + if value < 0 { + NdigitsValue::LiteralNegativeInt + } else { + NdigitsValue::LiteralNonNegativeInt + } + } + }, + Some(ndigits) => match ResolvedPythonType::from(ndigits) { ResolvedPythonType::Atom(PythonType::Number(NumberLike::Integer)) => { - NdigitsValue::Int(InferredType::Equivalent) + NdigitsValue::NonLiteralInt(InferredType::Equivalent) } _ => NdigitsValue::Other, }, From acd5d07306ed3b1004f2c9563dcc7f35cd19ec15 Mon Sep 17 00:00:00 2001 From: InSyncWithFoo Date: Fri, 3 Jan 2025 05:13:58 +0000 Subject: [PATCH 2/3] Missing snapshot --- ...uff__tests__preview__RUF057_RUF057.py.snap | 343 +++++------------- 1 file changed, 91 insertions(+), 252 deletions(-) diff --git a/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__preview__RUF057_RUF057.py.snap b/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__preview__RUF057_RUF057.py.snap index f44d92622db16..99b4d0a03c5df 100644 --- a/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__preview__RUF057_RUF057.py.snap +++ b/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__preview__RUF057_RUF057.py.snap @@ -19,7 +19,7 @@ RUF057.py:6:1: RUF057 [*] Value being rounded is already an integer 6 |+42 # Error (safe) 7 7 | round(42, None) # Error (safe) 8 8 | round(42, 2) # Error (safe) -9 9 | round(42, inferred_int) # Error (safe) +9 9 | round(42, -2) # No error RUF057.py:7:1: RUF057 [*] Value being rounded is already an integer | @@ -27,7 +27,7 @@ RUF057.py:7:1: RUF057 [*] Value being rounded is already an integer 7 | round(42, None) # Error (safe) | ^^^^^^^^^^^^^^^ RUF057 8 | round(42, 2) # Error (safe) -9 | round(42, inferred_int) # Error (safe) +9 | round(42, -2) # No error | = help: Remove unnecessary `round` call @@ -38,8 +38,8 @@ RUF057.py:7:1: RUF057 [*] Value being rounded is already an integer 7 |-round(42, None) # Error (safe) 7 |+42 # Error (safe) 8 8 | round(42, 2) # Error (safe) -9 9 | round(42, inferred_int) # Error (safe) -10 10 | round(42, 3 + 4) # Error (safe) +9 9 | round(42, -2) # No error +10 10 | round(42, inferred_int) # No error RUF057.py:8:1: RUF057 [*] Value being rounded is already an integer | @@ -47,8 +47,8 @@ RUF057.py:8:1: RUF057 [*] Value being rounded is already an integer 7 | round(42, None) # Error (safe) 8 | round(42, 2) # Error (safe) | ^^^^^^^^^^^^ RUF057 - 9 | round(42, inferred_int) # Error (safe) -10 | round(42, 3 + 4) # Error (safe) + 9 | round(42, -2) # No error +10 | round(42, inferred_int) # No error | = help: Remove unnecessary `round` call @@ -58,287 +58,126 @@ RUF057.py:8:1: RUF057 [*] Value being rounded is already an integer 7 7 | round(42, None) # Error (safe) 8 |-round(42, 2) # Error (safe) 8 |+42 # Error (safe) -9 9 | round(42, inferred_int) # Error (safe) -10 10 | round(42, 3 + 4) # Error (safe) -11 11 | round(42, foo) # Error (unsafe) - -RUF057.py:9:1: RUF057 [*] Value being rounded is already an integer - | - 7 | round(42, None) # Error (safe) - 8 | round(42, 2) # Error (safe) - 9 | round(42, inferred_int) # Error (safe) - | ^^^^^^^^^^^^^^^^^^^^^^^ RUF057 -10 | round(42, 3 + 4) # Error (safe) -11 | round(42, foo) # Error (unsafe) - | - = help: Remove unnecessary `round` call - -ℹ Safe fix -6 6 | round(42) # Error (safe) -7 7 | round(42, None) # Error (safe) -8 8 | round(42, 2) # Error (safe) -9 |-round(42, inferred_int) # Error (safe) - 9 |+42 # Error (safe) -10 10 | round(42, 3 + 4) # Error (safe) -11 11 | round(42, foo) # Error (unsafe) -12 12 | - -RUF057.py:10:1: RUF057 [*] Value being rounded is already an integer - | - 8 | round(42, 2) # Error (safe) - 9 | round(42, inferred_int) # Error (safe) -10 | round(42, 3 + 4) # Error (safe) - | ^^^^^^^^^^^^^^^^ RUF057 -11 | round(42, foo) # Error (unsafe) - | - = help: Remove unnecessary `round` call - -ℹ Safe fix -7 7 | round(42, None) # Error (safe) -8 8 | round(42, 2) # Error (safe) -9 9 | round(42, inferred_int) # Error (safe) -10 |-round(42, 3 + 4) # Error (safe) - 10 |+42 # Error (safe) -11 11 | round(42, foo) # Error (unsafe) -12 12 | -13 13 | - -RUF057.py:11:1: RUF057 [*] Value being rounded is already an integer - | - 9 | round(42, inferred_int) # Error (safe) -10 | round(42, 3 + 4) # Error (safe) -11 | round(42, foo) # Error (unsafe) - | ^^^^^^^^^^^^^^ RUF057 - | - = help: Remove unnecessary `round` call - -ℹ Unsafe fix -8 8 | round(42, 2) # Error (safe) -9 9 | round(42, inferred_int) # Error (safe) -10 10 | round(42, 3 + 4) # Error (safe) -11 |-round(42, foo) # Error (unsafe) - 11 |+42 # Error (unsafe) -12 12 | -13 13 | -14 14 | round(42.) # No error - -RUF057.py:22:1: RUF057 [*] Value being rounded is already an integer - | -22 | round(4 + 2) # Error (safe) - | ^^^^^^^^^^^^ RUF057 -23 | round(4 + 2, None) # Error (safe) -24 | round(4 + 2, 2) # Error (safe) - | - = help: Remove unnecessary `round` call - -ℹ Safe fix -19 19 | round(42., foo) # No error -20 20 | -21 21 | -22 |-round(4 + 2) # Error (safe) - 22 |+4 + 2 # Error (safe) -23 23 | round(4 + 2, None) # Error (safe) -24 24 | round(4 + 2, 2) # Error (safe) -25 25 | round(4 + 2, inferred_int) # Error (safe) - -RUF057.py:23:1: RUF057 [*] Value being rounded is already an integer - | -22 | round(4 + 2) # Error (safe) -23 | round(4 + 2, None) # Error (safe) - | ^^^^^^^^^^^^^^^^^^ RUF057 -24 | round(4 + 2, 2) # Error (safe) -25 | round(4 + 2, inferred_int) # Error (safe) - | - = help: Remove unnecessary `round` call - -ℹ Safe fix -20 20 | -21 21 | -22 22 | round(4 + 2) # Error (safe) -23 |-round(4 + 2, None) # Error (safe) - 23 |+4 + 2 # Error (safe) -24 24 | round(4 + 2, 2) # Error (safe) -25 25 | round(4 + 2, inferred_int) # Error (safe) -26 26 | round(4 + 2, 3 + 4) # Error (safe) +9 9 | round(42, -2) # No error +10 10 | round(42, inferred_int) # No error +11 11 | round(42, 3 + 4) # No error RUF057.py:24:1: RUF057 [*] Value being rounded is already an integer | -22 | round(4 + 2) # Error (safe) -23 | round(4 + 2, None) # Error (safe) -24 | round(4 + 2, 2) # Error (safe) - | ^^^^^^^^^^^^^^^ RUF057 -25 | round(4 + 2, inferred_int) # Error (safe) -26 | round(4 + 2, 3 + 4) # Error (safe) +24 | round(4 + 2) # Error (safe) + | ^^^^^^^^^^^^ RUF057 +25 | round(4 + 2, None) # Error (safe) +26 | round(4 + 2, 2) # Error (safe) | = help: Remove unnecessary `round` call ℹ Safe fix -21 21 | -22 22 | round(4 + 2) # Error (safe) -23 23 | round(4 + 2, None) # Error (safe) -24 |-round(4 + 2, 2) # Error (safe) - 24 |+4 + 2 # Error (safe) -25 25 | round(4 + 2, inferred_int) # Error (safe) -26 26 | round(4 + 2, 3 + 4) # Error (safe) -27 27 | round(4 + 2, foo) # Error (unsafe) +21 21 | round(42., foo) # No error +22 22 | +23 23 | +24 |-round(4 + 2) # Error (safe) + 24 |+4 + 2 # Error (safe) +25 25 | round(4 + 2, None) # Error (safe) +26 26 | round(4 + 2, 2) # Error (safe) +27 27 | round(4 + 2, -2) # No error RUF057.py:25:1: RUF057 [*] Value being rounded is already an integer | -23 | round(4 + 2, None) # Error (safe) -24 | round(4 + 2, 2) # Error (safe) -25 | round(4 + 2, inferred_int) # Error (safe) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF057 -26 | round(4 + 2, 3 + 4) # Error (safe) -27 | round(4 + 2, foo) # Error (unsafe) +24 | round(4 + 2) # Error (safe) +25 | round(4 + 2, None) # Error (safe) + | ^^^^^^^^^^^^^^^^^^ RUF057 +26 | round(4 + 2, 2) # Error (safe) +27 | round(4 + 2, -2) # No error | = help: Remove unnecessary `round` call ℹ Safe fix -22 22 | round(4 + 2) # Error (safe) -23 23 | round(4 + 2, None) # Error (safe) -24 24 | round(4 + 2, 2) # Error (safe) -25 |-round(4 + 2, inferred_int) # Error (safe) - 25 |+4 + 2 # Error (safe) -26 26 | round(4 + 2, 3 + 4) # Error (safe) -27 27 | round(4 + 2, foo) # Error (unsafe) -28 28 | +22 22 | +23 23 | +24 24 | round(4 + 2) # Error (safe) +25 |-round(4 + 2, None) # Error (safe) + 25 |+4 + 2 # Error (safe) +26 26 | round(4 + 2, 2) # Error (safe) +27 27 | round(4 + 2, -2) # No error +28 28 | round(4 + 2, inferred_int) # No error RUF057.py:26:1: RUF057 [*] Value being rounded is already an integer | -24 | round(4 + 2, 2) # Error (safe) -25 | round(4 + 2, inferred_int) # Error (safe) -26 | round(4 + 2, 3 + 4) # Error (safe) - | ^^^^^^^^^^^^^^^^^^^ RUF057 -27 | round(4 + 2, foo) # Error (unsafe) +24 | round(4 + 2) # Error (safe) +25 | round(4 + 2, None) # Error (safe) +26 | round(4 + 2, 2) # Error (safe) + | ^^^^^^^^^^^^^^^ RUF057 +27 | round(4 + 2, -2) # No error +28 | round(4 + 2, inferred_int) # No error | = help: Remove unnecessary `round` call ℹ Safe fix -23 23 | round(4 + 2, None) # Error (safe) -24 24 | round(4 + 2, 2) # Error (safe) -25 25 | round(4 + 2, inferred_int) # Error (safe) -26 |-round(4 + 2, 3 + 4) # Error (safe) - 26 |+4 + 2 # Error (safe) -27 27 | round(4 + 2, foo) # Error (unsafe) -28 28 | -29 29 | +23 23 | +24 24 | round(4 + 2) # Error (safe) +25 25 | round(4 + 2, None) # Error (safe) +26 |-round(4 + 2, 2) # Error (safe) + 26 |+4 + 2 # Error (safe) +27 27 | round(4 + 2, -2) # No error +28 28 | round(4 + 2, inferred_int) # No error +29 29 | round(4 + 2, 3 + 4) # No error -RUF057.py:27:1: RUF057 [*] Value being rounded is already an integer - | -25 | round(4 + 2, inferred_int) # Error (safe) -26 | round(4 + 2, 3 + 4) # Error (safe) -27 | round(4 + 2, foo) # Error (unsafe) - | ^^^^^^^^^^^^^^^^^ RUF057 - | - = help: Remove unnecessary `round` call - -ℹ Unsafe fix -24 24 | round(4 + 2, 2) # Error (safe) -25 25 | round(4 + 2, inferred_int) # Error (safe) -26 26 | round(4 + 2, 3 + 4) # Error (safe) -27 |-round(4 + 2, foo) # Error (unsafe) - 27 |+4 + 2 # Error (unsafe) -28 28 | -29 29 | -30 30 | round(4. + 2.) # No error - -RUF057.py:38:1: RUF057 [*] Value being rounded is already an integer +RUF057.py:42:1: RUF057 [*] Value being rounded is already an integer | -38 | round(inferred_int) # Error (unsafe) +42 | round(inferred_int) # Error (unsafe) | ^^^^^^^^^^^^^^^^^^^ RUF057 -39 | round(inferred_int, None) # Error (unsafe) -40 | round(inferred_int, 2) # Error (unsafe) +43 | round(inferred_int, None) # Error (unsafe) +44 | round(inferred_int, 2) # Error (unsafe) | = help: Remove unnecessary `round` call ℹ Unsafe fix -35 35 | round(4. + 2., foo) # No error -36 36 | -37 37 | -38 |-round(inferred_int) # Error (unsafe) - 38 |+inferred_int # Error (unsafe) -39 39 | round(inferred_int, None) # Error (unsafe) -40 40 | round(inferred_int, 2) # Error (unsafe) -41 41 | round(inferred_int, inferred_int) # Error (unsafe) - -RUF057.py:39:1: RUF057 [*] Value being rounded is already an integer - | -38 | round(inferred_int) # Error (unsafe) -39 | round(inferred_int, None) # Error (unsafe) +39 39 | round(4. + 2., foo) # No error +40 40 | +41 41 | +42 |-round(inferred_int) # Error (unsafe) + 42 |+inferred_int # Error (unsafe) +43 43 | round(inferred_int, None) # Error (unsafe) +44 44 | round(inferred_int, 2) # Error (unsafe) +45 45 | round(inferred_int, -2) # No error + +RUF057.py:43:1: RUF057 [*] Value being rounded is already an integer + | +42 | round(inferred_int) # Error (unsafe) +43 | round(inferred_int, None) # Error (unsafe) | ^^^^^^^^^^^^^^^^^^^^^^^^^ RUF057 -40 | round(inferred_int, 2) # Error (unsafe) -41 | round(inferred_int, inferred_int) # Error (unsafe) +44 | round(inferred_int, 2) # Error (unsafe) +45 | round(inferred_int, -2) # No error | = help: Remove unnecessary `round` call ℹ Unsafe fix -36 36 | -37 37 | -38 38 | round(inferred_int) # Error (unsafe) -39 |-round(inferred_int, None) # Error (unsafe) - 39 |+inferred_int # Error (unsafe) -40 40 | round(inferred_int, 2) # Error (unsafe) -41 41 | round(inferred_int, inferred_int) # Error (unsafe) -42 42 | round(inferred_int, 3 + 4) # Error (unsafe) - -RUF057.py:40:1: RUF057 [*] Value being rounded is already an integer - | -38 | round(inferred_int) # Error (unsafe) -39 | round(inferred_int, None) # Error (unsafe) -40 | round(inferred_int, 2) # Error (unsafe) +40 40 | +41 41 | +42 42 | round(inferred_int) # Error (unsafe) +43 |-round(inferred_int, None) # Error (unsafe) + 43 |+inferred_int # Error (unsafe) +44 44 | round(inferred_int, 2) # Error (unsafe) +45 45 | round(inferred_int, -2) # No error +46 46 | round(inferred_int, inferred_int) # No error + +RUF057.py:44:1: RUF057 [*] Value being rounded is already an integer + | +42 | round(inferred_int) # Error (unsafe) +43 | round(inferred_int, None) # Error (unsafe) +44 | round(inferred_int, 2) # Error (unsafe) | ^^^^^^^^^^^^^^^^^^^^^^ RUF057 -41 | round(inferred_int, inferred_int) # Error (unsafe) -42 | round(inferred_int, 3 + 4) # Error (unsafe) - | - = help: Remove unnecessary `round` call - -ℹ Unsafe fix -37 37 | -38 38 | round(inferred_int) # Error (unsafe) -39 39 | round(inferred_int, None) # Error (unsafe) -40 |-round(inferred_int, 2) # Error (unsafe) - 40 |+inferred_int # Error (unsafe) -41 41 | round(inferred_int, inferred_int) # Error (unsafe) -42 42 | round(inferred_int, 3 + 4) # Error (unsafe) -43 43 | round(inferred_int, foo) # No error - -RUF057.py:41:1: RUF057 [*] Value being rounded is already an integer - | -39 | round(inferred_int, None) # Error (unsafe) -40 | round(inferred_int, 2) # Error (unsafe) -41 | round(inferred_int, inferred_int) # Error (unsafe) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF057 -42 | round(inferred_int, 3 + 4) # Error (unsafe) -43 | round(inferred_int, foo) # No error - | - = help: Remove unnecessary `round` call - -ℹ Unsafe fix -38 38 | round(inferred_int) # Error (unsafe) -39 39 | round(inferred_int, None) # Error (unsafe) -40 40 | round(inferred_int, 2) # Error (unsafe) -41 |-round(inferred_int, inferred_int) # Error (unsafe) - 41 |+inferred_int # Error (unsafe) -42 42 | round(inferred_int, 3 + 4) # Error (unsafe) -43 43 | round(inferred_int, foo) # No error -44 44 | - -RUF057.py:42:1: RUF057 [*] Value being rounded is already an integer - | -40 | round(inferred_int, 2) # Error (unsafe) -41 | round(inferred_int, inferred_int) # Error (unsafe) -42 | round(inferred_int, 3 + 4) # Error (unsafe) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF057 -43 | round(inferred_int, foo) # No error +45 | round(inferred_int, -2) # No error +46 | round(inferred_int, inferred_int) # No error | = help: Remove unnecessary `round` call ℹ Unsafe fix -39 39 | round(inferred_int, None) # Error (unsafe) -40 40 | round(inferred_int, 2) # Error (unsafe) -41 41 | round(inferred_int, inferred_int) # Error (unsafe) -42 |-round(inferred_int, 3 + 4) # Error (unsafe) - 42 |+inferred_int # Error (unsafe) -43 43 | round(inferred_int, foo) # No error -44 44 | -45 45 | +41 41 | +42 42 | round(inferred_int) # Error (unsafe) +43 43 | round(inferred_int, None) # Error (unsafe) +44 |-round(inferred_int, 2) # Error (unsafe) + 44 |+inferred_int # Error (unsafe) +45 45 | round(inferred_int, -2) # No error +46 46 | round(inferred_int, inferred_int) # No error +47 47 | round(inferred_int, 3 + 4) # No error From 90d63efaa85f2b0ac78f9ce409618bea963c2a3a Mon Sep 17 00:00:00 2001 From: InSyncWithFoo Date: Fri, 3 Jan 2025 18:36:28 +0000 Subject: [PATCH 3/3] Per review --- .../ruff/rules/unnecessary_cast_to_int.rs | 10 ++++---- .../src/rules/ruff/rules/unnecessary_round.rs | 23 ++++++++----------- 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/crates/ruff_linter/src/rules/ruff/rules/unnecessary_cast_to_int.rs b/crates/ruff_linter/src/rules/ruff/rules/unnecessary_cast_to_int.rs index ab25bde1ae590..f2f2b8c0a480a 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/unnecessary_cast_to_int.rs +++ b/crates/ruff_linter/src/rules/ruff/rules/unnecessary_cast_to_int.rs @@ -186,9 +186,8 @@ fn round_applicability(arguments: &Arguments, semantic: &SemanticModel) -> Optio // ``` ( RoundedValue::Int(InferredType::Equivalent), - NdigitsValue::LiteralNegativeInt - | NdigitsValue::LiteralNonNegativeInt - | NdigitsValue::NonLiteralInt(InferredType::Equivalent) + NdigitsValue::LiteralInt { .. } + | NdigitsValue::Int(InferredType::Equivalent) | NdigitsValue::NotGivenOrNone, ) => Some(Applicability::Safe), @@ -209,9 +208,8 @@ fn round_applicability(arguments: &Arguments, semantic: &SemanticModel) -> Optio // ``` ( RoundedValue::Int(InferredType::AssignableTo), - NdigitsValue::LiteralNonNegativeInt - | NdigitsValue::LiteralNegativeInt - | NdigitsValue::NonLiteralInt(InferredType::Equivalent) + NdigitsValue::LiteralInt { .. } + | NdigitsValue::Int(InferredType::Equivalent) | NdigitsValue::NotGivenOrNone, ) => Some(Applicability::Unsafe), diff --git a/crates/ruff_linter/src/rules/ruff/rules/unnecessary_round.rs b/crates/ruff_linter/src/rules/ruff/rules/unnecessary_round.rs index ba55f4d26768c..c449f81104266 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/unnecessary_round.rs +++ b/crates/ruff_linter/src/rules/ruff/rules/unnecessary_round.rs @@ -54,7 +54,7 @@ pub(crate) fn unnecessary_round(checker: &mut Checker, call: &ExprCall) { if !matches!( ndigits_value, - NdigitsValue::NotGivenOrNone | NdigitsValue::LiteralNonNegativeInt + NdigitsValue::NotGivenOrNone | NdigitsValue::LiteralInt { is_negative: false } ) { return; } @@ -114,9 +114,8 @@ pub(super) enum RoundedValue { #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub(super) enum NdigitsValue { NotGivenOrNone, - LiteralNegativeInt, - LiteralNonNegativeInt, - NonLiteralInt(InferredType), + LiteralInt { is_negative: bool }, + Int(InferredType), Other, } @@ -163,7 +162,7 @@ pub(super) fn rounded_and_ndigits<'a>( Some(Expr::Name(name)) => { match semantic.only_binding(name).map(|id| semantic.binding(id)) { Some(binding) if typing::is_int(binding, semantic) => { - NdigitsValue::NonLiteralInt(InferredType::AssignableTo) + NdigitsValue::Int(InferredType::AssignableTo) } _ => NdigitsValue::Other, } @@ -173,19 +172,15 @@ pub(super) fn rounded_and_ndigits<'a>( value: Number::Int(int), .. })) => match int.as_i64() { - None => NdigitsValue::NonLiteralInt(InferredType::Equivalent), - Some(value) => { - if value < 0 { - NdigitsValue::LiteralNegativeInt - } else { - NdigitsValue::LiteralNonNegativeInt - } - } + None => NdigitsValue::Int(InferredType::Equivalent), + Some(value) => NdigitsValue::LiteralInt { + is_negative: value < 0, + }, }, Some(ndigits) => match ResolvedPythonType::from(ndigits) { ResolvedPythonType::Atom(PythonType::Number(NumberLike::Integer)) => { - NdigitsValue::NonLiteralInt(InferredType::Equivalent) + NdigitsValue::Int(InferredType::Equivalent) } _ => NdigitsValue::Other, },