[ruff] Do not simplify round() calls (RUF046) (#14832)

## Summary

Part 1 of the big change introduced in #14828. This temporarily causes
all fixes for `round(...)` to be considered unsafe, but they will
eventually be enhanced.

## Test Plan

`cargo nextest run` and `cargo insta test`.
This commit is contained in:
InSync 2024-12-09 22:51:27 +07:00 committed by GitHub
parent 68eb0a2511
commit c62ba48ad4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 569 additions and 374 deletions

View file

@ -1,9 +1,12 @@
import math
inferred_int = 1
inferred_float = 1.
### Safely fixable
# Arguments are not checked
int(id())
int(len([]))
int(ord(foo))
@ -17,6 +20,15 @@ int(math.lcm())
int(math.isqrt())
int(math.perm())
int(round(1, 0))
int(round(1, 10))
int(round(1))
int(round(1, None))
int(round(1.))
int(round(1., None))
### Unsafe
@ -24,27 +36,35 @@ int(math.ceil())
int(math.floor())
int(math.trunc())
int(round(inferred_int, 0))
int(round(inferred_int, 10))
### `round()`
int(round(inferred_int))
int(round(inferred_int, None))
## Errors
int(round(0))
int(round(0, 0))
int(round(0, None))
int(round(inferred_float))
int(round(inferred_float, None))
int(round(0.1))
int(round(0.1, None))
int(round(unknown))
int(round(unknown, None))
# Argument type is not checked
foo = type("Foo", (), {"__round__": lambda self: 4.2})()
int(round(foo))
int(round(foo, 0))
int(round(foo, None))
### No errors
int(round(1, unknown))
int(round(1., unknown))
int(round(1., 0))
int(round(inferred_float, 0))
int(round(inferred_int, unknown))
int(round(inferred_float, unknown))
int(round(unknown, 0))
int(round(unknown, unknown))
## No errors
int(round(0, 3.14))
int(round(0, non_literal))
int(round(inferred_int, 3.14))
int(round(0, 0), base)
int(round(0, 0, extra=keyword))
int(round(0.1, 0))

View file

@ -1,7 +1,7 @@
use crate::checkers::ast::Checker;
use ruff_diagnostics::{AlwaysFixableViolation, Applicability, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, ViolationMetadata};
use ruff_python_ast::{Arguments, Expr, ExprCall, ExprName, ExprNumberLiteral, Number};
use ruff_python_ast::{Arguments, Expr, ExprCall, ExprNumberLiteral, Number};
use ruff_python_semantic::analyze::typing;
use ruff_python_semantic::SemanticModel;
use ruff_text_size::TextRange;
@ -74,7 +74,7 @@ pub(crate) fn unnecessary_cast_to_int(checker: &mut Checker, call: &ExprCall) {
// Depends on `ndigits` and `number.__round__`
["" | "builtins", "round"] => {
if let Some(fix) = replace_with_shortened_round_call(checker, outer_range, arguments) {
if let Some(fix) = replace_with_round(checker, outer_range, inner_range, arguments) {
fix
} else {
return;
@ -89,9 +89,9 @@ pub(crate) fn unnecessary_cast_to_int(checker: &mut Checker, call: &ExprCall) {
_ => return,
};
checker
.diagnostics
.push(Diagnostic::new(UnnecessaryCastToInt, call.range).with_fix(fix));
let diagnostic = Diagnostic::new(UnnecessaryCastToInt, call.range);
checker.diagnostics.push(diagnostic.with_fix(fix));
}
fn single_argument_to_int_call<'a>(
@ -117,12 +117,29 @@ fn single_argument_to_int_call<'a>(
Some(argument)
}
/// Returns an [`Edit`] when the call is of any of the forms:
/// * `round(integer)`, `round(integer, 0)`, `round(integer, None)`
/// * `round(whatever)`, `round(whatever, None)`
fn replace_with_shortened_round_call(
/// The type of the first argument to `round()`
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum Rounded {
InferredInt,
InferredFloat,
LiteralInt,
LiteralFloat,
Other,
}
/// The type of the second argument to `round()`
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum Ndigits {
NotGiven,
LiteralInt,
LiteralNone,
Other,
}
fn replace_with_round(
checker: &Checker,
outer_range: TextRange,
inner_range: TextRange,
arguments: &Arguments,
) -> Option<Fix> {
if arguments.len() > 2 {
@ -132,48 +149,56 @@ fn replace_with_shortened_round_call(
let number = arguments.find_argument("number", 0)?;
let ndigits = arguments.find_argument("ndigits", 1);
let number_is_int = match number {
Expr::Name(name) => is_int(checker.semantic(), name),
Expr::NumberLiteral(ExprNumberLiteral { value, .. }) => matches!(value, Number::Int(..)),
_ => false,
let number_kind = match number {
Expr::Name(name) => {
let semantic = checker.semantic();
match semantic.only_binding(name).map(|id| semantic.binding(id)) {
Some(binding) if typing::is_int(binding, semantic) => Rounded::InferredInt,
Some(binding) if typing::is_float(binding, semantic) => Rounded::InferredFloat,
_ => Rounded::Other,
}
}
Expr::NumberLiteral(ExprNumberLiteral { value, .. }) => match value {
Number::Int(..) => Rounded::LiteralInt,
Number::Float(..) => Rounded::LiteralFloat,
Number::Complex { .. } => Rounded::Other,
},
_ => Rounded::Other,
};
match ndigits {
Some(Expr::NumberLiteral(ExprNumberLiteral { value, .. }))
if is_literal_zero(value) && number_is_int => {}
Some(Expr::NoneLiteral(_)) | None => {}
let ndigits_kind = match ndigits {
None => Ndigits::NotGiven,
Some(Expr::NoneLiteral(_)) => Ndigits::LiteralNone,
Some(Expr::NumberLiteral(ExprNumberLiteral {
value: Number::Int(..),
..
})) => Ndigits::LiteralInt,
_ => Ndigits::Other,
};
let applicability = match (number_kind, ndigits_kind) {
(Rounded::LiteralInt, Ndigits::LiteralInt)
| (Rounded::LiteralInt | Rounded::LiteralFloat, Ndigits::NotGiven | Ndigits::LiteralNone) => {
Applicability::Safe
}
(Rounded::InferredInt, Ndigits::LiteralInt)
| (
Rounded::InferredInt | Rounded::InferredFloat | Rounded::Other,
Ndigits::NotGiven | Ndigits::LiteralNone,
) => Applicability::Unsafe,
_ => return None,
};
let number_expr = checker.locator().slice(number);
let new_content = format!("round({number_expr})");
let edit = replace_with_inner(checker, outer_range, inner_range);
let applicability = if number_is_int {
Applicability::Safe
} else {
Applicability::Unsafe
};
Some(Fix::applicable_edit(
Edit::range_replacement(new_content, outer_range),
applicability,
))
}
fn is_int(semantic: &SemanticModel, name: &ExprName) -> bool {
let Some(binding) = semantic.only_binding(name).map(|id| semantic.binding(id)) else {
return false;
};
typing::is_int(binding, semantic)
}
fn is_literal_zero(value: &Number) -> bool {
let Number::Int(int) = value else {
return false;
};
matches!(int.as_u8(), Some(0))
Some(Fix::applicable_edit(edit, applicability))
}
fn replace_with_inner(checker: &Checker, outer_range: TextRange, inner_range: TextRange) -> Edit {

View file

@ -2,429 +2,566 @@
source: crates/ruff_linter/src/rules/ruff/mod.rs
snapshot_kind: text
---
RUF046.py:7:1: RUF046 [*] Value being casted is already an integer
|
6 | # Arguments are not checked
7 | int(id())
| ^^^^^^^^^ RUF046
8 | int(len([]))
9 | int(ord(foo))
|
= help: Remove unnecessary conversion to `int`
Safe fix
4 4 | ### Safely fixable
5 5 |
6 6 | # Arguments are not checked
7 |-int(id())
7 |+id()
8 8 | int(len([]))
9 9 | int(ord(foo))
10 10 | int(hash(foo, bar))
RUF046.py:8:1: RUF046 [*] Value being casted is already an integer
|
6 | # Arguments are not checked
7 | int(id())
8 | int(len([]))
| ^^^^^^^^^^^^ RUF046
9 | int(ord(foo))
10 | int(hash(foo, bar))
|
= help: Remove unnecessary conversion to `int`
Safe fix
5 5 |
6 6 | # Arguments are not checked
7 7 | int(id())
8 |-int(len([]))
8 |+len([])
9 9 | int(ord(foo))
10 10 | int(hash(foo, bar))
11 11 | int(int(''))
RUF046.py:9:1: RUF046 [*] Value being casted is already an integer
|
7 | int(id())
8 | int(len([]))
9 | int(ord(foo))
| ^^^^^^^^^^^^^ RUF046
10 | int(hash(foo, bar))
11 | int(int(''))
|
= help: Remove unnecessary conversion to `int`
Safe fix
6 6 | # Arguments are not checked
7 7 | int(id())
8 8 | int(len([]))
9 |-int(ord(foo))
9 |+ord(foo)
10 10 | int(hash(foo, bar))
11 11 | int(int(''))
12 12 |
RUF046.py:10:1: RUF046 [*] Value being casted is already an integer
|
8 | int(len([]))
9 | int(ord(foo))
10 | int(hash(foo, bar))
| ^^^^^^^^^^^^^^^^^^^ RUF046
11 | int(int(''))
8 | ### Safely fixable
9 |
10 | int(id())
| ^^^^^^^^^ RUF046
11 | int(len([]))
12 | int(ord(foo))
|
= help: Remove unnecessary conversion to `int`
Safe fix
7 7 | int(id())
8 8 | int(len([]))
9 9 | int(ord(foo))
10 |-int(hash(foo, bar))
10 |+hash(foo, bar)
11 11 | int(int(''))
12 12 |
13 13 | int(math.comb())
7 7 |
8 8 | ### Safely fixable
9 9 |
10 |-int(id())
10 |+id()
11 11 | int(len([]))
12 12 | int(ord(foo))
13 13 | int(hash(foo, bar))
RUF046.py:11:1: RUF046 [*] Value being casted is already an integer
|
9 | int(ord(foo))
10 | int(hash(foo, bar))
11 | int(int(''))
10 | int(id())
11 | int(len([]))
| ^^^^^^^^^^^^ RUF046
12 |
13 | int(math.comb())
12 | int(ord(foo))
13 | int(hash(foo, bar))
|
= help: Remove unnecessary conversion to `int`
Safe fix
8 8 | int(len([]))
9 9 | int(ord(foo))
10 10 | int(hash(foo, bar))
11 |-int(int(''))
11 |+int('')
12 12 |
13 13 | int(math.comb())
14 14 | int(math.factorial())
8 8 | ### Safely fixable
9 9 |
10 10 | int(id())
11 |-int(len([]))
11 |+len([])
12 12 | int(ord(foo))
13 13 | int(hash(foo, bar))
14 14 | int(int(''))
RUF046.py:12:1: RUF046 [*] Value being casted is already an integer
|
10 | int(id())
11 | int(len([]))
12 | int(ord(foo))
| ^^^^^^^^^^^^^ RUF046
13 | int(hash(foo, bar))
14 | int(int(''))
|
= help: Remove unnecessary conversion to `int`
Safe fix
9 9 |
10 10 | int(id())
11 11 | int(len([]))
12 |-int(ord(foo))
12 |+ord(foo)
13 13 | int(hash(foo, bar))
14 14 | int(int(''))
15 15 |
RUF046.py:13:1: RUF046 [*] Value being casted is already an integer
|
11 | int(int(''))
12 |
13 | int(math.comb())
| ^^^^^^^^^^^^^^^^ RUF046
14 | int(math.factorial())
15 | int(math.gcd())
11 | int(len([]))
12 | int(ord(foo))
13 | int(hash(foo, bar))
| ^^^^^^^^^^^^^^^^^^^ RUF046
14 | int(int(''))
|
= help: Remove unnecessary conversion to `int`
Safe fix
10 10 | int(hash(foo, bar))
11 11 | int(int(''))
12 12 |
13 |-int(math.comb())
13 |+math.comb()
14 14 | int(math.factorial())
15 15 | int(math.gcd())
16 16 | int(math.lcm())
10 10 | int(id())
11 11 | int(len([]))
12 12 | int(ord(foo))
13 |-int(hash(foo, bar))
13 |+hash(foo, bar)
14 14 | int(int(''))
15 15 |
16 16 | int(math.comb())
RUF046.py:14:1: RUF046 [*] Value being casted is already an integer
|
13 | int(math.comb())
14 | int(math.factorial())
| ^^^^^^^^^^^^^^^^^^^^^ RUF046
15 | int(math.gcd())
16 | int(math.lcm())
12 | int(ord(foo))
13 | int(hash(foo, bar))
14 | int(int(''))
| ^^^^^^^^^^^^ RUF046
15 |
16 | int(math.comb())
|
= help: Remove unnecessary conversion to `int`
Safe fix
11 11 | int(int(''))
12 12 |
13 13 | int(math.comb())
14 |-int(math.factorial())
14 |+math.factorial()
15 15 | int(math.gcd())
16 16 | int(math.lcm())
17 17 | int(math.isqrt())
RUF046.py:15:1: RUF046 [*] Value being casted is already an integer
|
13 | int(math.comb())
14 | int(math.factorial())
15 | int(math.gcd())
| ^^^^^^^^^^^^^^^ RUF046
16 | int(math.lcm())
17 | int(math.isqrt())
|
= help: Remove unnecessary conversion to `int`
Safe fix
12 12 |
13 13 | int(math.comb())
14 14 | int(math.factorial())
15 |-int(math.gcd())
15 |+math.gcd()
16 16 | int(math.lcm())
17 17 | int(math.isqrt())
18 18 | int(math.perm())
11 11 | int(len([]))
12 12 | int(ord(foo))
13 13 | int(hash(foo, bar))
14 |-int(int(''))
14 |+int('')
15 15 |
16 16 | int(math.comb())
17 17 | int(math.factorial())
RUF046.py:16:1: RUF046 [*] Value being casted is already an integer
|
14 | int(math.factorial())
15 | int(math.gcd())
16 | int(math.lcm())
| ^^^^^^^^^^^^^^^ RUF046
17 | int(math.isqrt())
18 | int(math.perm())
14 | int(int(''))
15 |
16 | int(math.comb())
| ^^^^^^^^^^^^^^^^ RUF046
17 | int(math.factorial())
18 | int(math.gcd())
|
= help: Remove unnecessary conversion to `int`
Safe fix
13 13 | int(math.comb())
14 14 | int(math.factorial())
15 15 | int(math.gcd())
16 |-int(math.lcm())
16 |+math.lcm()
17 17 | int(math.isqrt())
18 18 | int(math.perm())
19 19 |
13 13 | int(hash(foo, bar))
14 14 | int(int(''))
15 15 |
16 |-int(math.comb())
16 |+math.comb()
17 17 | int(math.factorial())
18 18 | int(math.gcd())
19 19 | int(math.lcm())
RUF046.py:17:1: RUF046 [*] Value being casted is already an integer
|
15 | int(math.gcd())
16 | int(math.lcm())
17 | int(math.isqrt())
| ^^^^^^^^^^^^^^^^^ RUF046
18 | int(math.perm())
16 | int(math.comb())
17 | int(math.factorial())
| ^^^^^^^^^^^^^^^^^^^^^ RUF046
18 | int(math.gcd())
19 | int(math.lcm())
|
= help: Remove unnecessary conversion to `int`
Safe fix
14 14 | int(math.factorial())
15 15 | int(math.gcd())
16 16 | int(math.lcm())
17 |-int(math.isqrt())
17 |+math.isqrt()
18 18 | int(math.perm())
19 19 |
20 20 |
14 14 | int(int(''))
15 15 |
16 16 | int(math.comb())
17 |-int(math.factorial())
17 |+math.factorial()
18 18 | int(math.gcd())
19 19 | int(math.lcm())
20 20 | int(math.isqrt())
RUF046.py:18:1: RUF046 [*] Value being casted is already an integer
|
16 | int(math.lcm())
17 | int(math.isqrt())
18 | int(math.perm())
| ^^^^^^^^^^^^^^^^ RUF046
16 | int(math.comb())
17 | int(math.factorial())
18 | int(math.gcd())
| ^^^^^^^^^^^^^^^ RUF046
19 | int(math.lcm())
20 | int(math.isqrt())
|
= help: Remove unnecessary conversion to `int`
Safe fix
15 15 | int(math.gcd())
16 16 | int(math.lcm())
17 17 | int(math.isqrt())
18 |-int(math.perm())
18 |+math.perm()
19 19 |
20 20 |
21 21 | ### Unsafe
15 15 |
16 16 | int(math.comb())
17 17 | int(math.factorial())
18 |-int(math.gcd())
18 |+math.gcd()
19 19 | int(math.lcm())
20 20 | int(math.isqrt())
21 21 | int(math.perm())
RUF046.py:19:1: RUF046 [*] Value being casted is already an integer
|
17 | int(math.factorial())
18 | int(math.gcd())
19 | int(math.lcm())
| ^^^^^^^^^^^^^^^ RUF046
20 | int(math.isqrt())
21 | int(math.perm())
|
= help: Remove unnecessary conversion to `int`
Safe fix
16 16 | int(math.comb())
17 17 | int(math.factorial())
18 18 | int(math.gcd())
19 |-int(math.lcm())
19 |+math.lcm()
20 20 | int(math.isqrt())
21 21 | int(math.perm())
22 22 |
RUF046.py:20:1: RUF046 [*] Value being casted is already an integer
|
18 | int(math.gcd())
19 | int(math.lcm())
20 | int(math.isqrt())
| ^^^^^^^^^^^^^^^^^ RUF046
21 | int(math.perm())
|
= help: Remove unnecessary conversion to `int`
Safe fix
17 17 | int(math.factorial())
18 18 | int(math.gcd())
19 19 | int(math.lcm())
20 |-int(math.isqrt())
20 |+math.isqrt()
21 21 | int(math.perm())
22 22 |
23 23 | int(round(1, 0))
RUF046.py:21:1: RUF046 [*] Value being casted is already an integer
|
19 | int(math.lcm())
20 | int(math.isqrt())
21 | int(math.perm())
| ^^^^^^^^^^^^^^^^ RUF046
22 |
23 | int(round(1, 0))
|
= help: Remove unnecessary conversion to `int`
Safe fix
18 18 | int(math.gcd())
19 19 | int(math.lcm())
20 20 | int(math.isqrt())
21 |-int(math.perm())
21 |+math.perm()
22 22 |
23 23 | int(round(1, 0))
24 24 | int(round(1, 10))
RUF046.py:23:1: RUF046 [*] Value being casted is already an integer
|
21 | ### Unsafe
21 | int(math.perm())
22 |
23 | int(math.ceil())
23 | int(round(1, 0))
| ^^^^^^^^^^^^^^^^ RUF046
24 | int(math.floor())
25 | int(math.trunc())
24 | int(round(1, 10))
|
= help: Remove unnecessary conversion to `int`
Unsafe fix
20 20 |
21 21 | ### Unsafe
Safe fix
20 20 | int(math.isqrt())
21 21 | int(math.perm())
22 22 |
23 |-int(math.ceil())
23 |+math.ceil()
24 24 | int(math.floor())
25 25 | int(math.trunc())
26 26 |
23 |-int(round(1, 0))
23 |+round(1, 0)
24 24 | int(round(1, 10))
25 25 |
26 26 | int(round(1))
RUF046.py:24:1: RUF046 [*] Value being casted is already an integer
|
23 | int(math.ceil())
24 | int(math.floor())
23 | int(round(1, 0))
24 | int(round(1, 10))
| ^^^^^^^^^^^^^^^^^ RUF046
25 | int(math.trunc())
25 |
26 | int(round(1))
|
= help: Remove unnecessary conversion to `int`
Unsafe fix
21 21 | ### Unsafe
Safe fix
21 21 | int(math.perm())
22 22 |
23 23 | int(math.ceil())
24 |-int(math.floor())
24 |+math.floor()
25 25 | int(math.trunc())
26 26 |
27 27 |
23 23 | int(round(1, 0))
24 |-int(round(1, 10))
24 |+round(1, 10)
25 25 |
26 26 | int(round(1))
27 27 | int(round(1, None))
RUF046.py:25:1: RUF046 [*] Value being casted is already an integer
RUF046.py:26:1: RUF046 [*] Value being casted is already an integer
|
23 | int(math.ceil())
24 | int(math.floor())
25 | int(math.trunc())
| ^^^^^^^^^^^^^^^^^ RUF046
|
= help: Remove unnecessary conversion to `int`
Unsafe fix
22 22 |
23 23 | int(math.ceil())
24 24 | int(math.floor())
25 |-int(math.trunc())
25 |+math.trunc()
26 26 |
27 27 |
28 28 | ### `round()`
RUF046.py:31:1: RUF046 [*] Value being casted is already an integer
|
30 | ## Errors
31 | int(round(0))
24 | int(round(1, 10))
25 |
26 | int(round(1))
| ^^^^^^^^^^^^^ RUF046
32 | int(round(0, 0))
33 | int(round(0, None))
27 | int(round(1, None))
|
= help: Remove unnecessary conversion to `int`
Safe fix
28 28 | ### `round()`
29 29 |
30 30 | ## Errors
31 |-int(round(0))
31 |+round(0)
32 32 | int(round(0, 0))
33 33 | int(round(0, None))
34 34 |
23 23 | int(round(1, 0))
24 24 | int(round(1, 10))
25 25 |
26 |-int(round(1))
26 |+round(1)
27 27 | int(round(1, None))
28 28 |
29 29 | int(round(1.))
RUF046.py:32:1: RUF046 [*] Value being casted is already an integer
RUF046.py:27:1: RUF046 [*] Value being casted is already an integer
|
30 | ## Errors
31 | int(round(0))
32 | int(round(0, 0))
| ^^^^^^^^^^^^^^^^ RUF046
33 | int(round(0, None))
|
= help: Remove unnecessary conversion to `int`
Safe fix
29 29 |
30 30 | ## Errors
31 31 | int(round(0))
32 |-int(round(0, 0))
32 |+round(0)
33 33 | int(round(0, None))
34 34 |
35 35 | int(round(0.1))
RUF046.py:33:1: RUF046 [*] Value being casted is already an integer
|
31 | int(round(0))
32 | int(round(0, 0))
33 | int(round(0, None))
26 | int(round(1))
27 | int(round(1, None))
| ^^^^^^^^^^^^^^^^^^^ RUF046
34 |
35 | int(round(0.1))
28 |
29 | int(round(1.))
|
= help: Remove unnecessary conversion to `int`
Safe fix
30 30 | ## Errors
31 31 | int(round(0))
32 32 | int(round(0, 0))
33 |-int(round(0, None))
33 |+round(0)
34 34 |
35 35 | int(round(0.1))
36 36 | int(round(0.1, None))
24 24 | int(round(1, 10))
25 25 |
26 26 | int(round(1))
27 |-int(round(1, None))
27 |+round(1, None)
28 28 |
29 29 | int(round(1.))
30 30 | int(round(1., None))
RUF046.py:29:1: RUF046 [*] Value being casted is already an integer
|
27 | int(round(1, None))
28 |
29 | int(round(1.))
| ^^^^^^^^^^^^^^ RUF046
30 | int(round(1., None))
|
= help: Remove unnecessary conversion to `int`
Safe fix
26 26 | int(round(1))
27 27 | int(round(1, None))
28 28 |
29 |-int(round(1.))
29 |+round(1.)
30 30 | int(round(1., None))
31 31 |
32 32 |
RUF046.py:30:1: RUF046 [*] Value being casted is already an integer
|
29 | int(round(1.))
30 | int(round(1., None))
| ^^^^^^^^^^^^^^^^^^^^ RUF046
|
= help: Remove unnecessary conversion to `int`
Safe fix
27 27 | int(round(1, None))
28 28 |
29 29 | int(round(1.))
30 |-int(round(1., None))
30 |+round(1., None)
31 31 |
32 32 |
33 33 | ### Unsafe
RUF046.py:35:1: RUF046 [*] Value being casted is already an integer
|
33 | int(round(0, None))
33 | ### Unsafe
34 |
35 | int(round(0.1))
| ^^^^^^^^^^^^^^^ RUF046
36 | int(round(0.1, None))
35 | int(math.ceil())
| ^^^^^^^^^^^^^^^^ RUF046
36 | int(math.floor())
37 | int(math.trunc())
|
= help: Remove unnecessary conversion to `int`
Unsafe fix
32 32 | int(round(0, 0))
33 33 | int(round(0, None))
32 32 |
33 33 | ### Unsafe
34 34 |
35 |-int(round(0.1))
35 |+round(0.1)
36 36 | int(round(0.1, None))
37 37 |
38 38 | # Argument type is not checked
35 |-int(math.ceil())
35 |+math.ceil()
36 36 | int(math.floor())
37 37 | int(math.trunc())
38 38 |
RUF046.py:36:1: RUF046 [*] Value being casted is already an integer
|
35 | int(round(0.1))
36 | int(round(0.1, None))
| ^^^^^^^^^^^^^^^^^^^^^ RUF046
37 |
38 | # Argument type is not checked
35 | int(math.ceil())
36 | int(math.floor())
| ^^^^^^^^^^^^^^^^^ RUF046
37 | int(math.trunc())
|
= help: Remove unnecessary conversion to `int`
Unsafe fix
33 33 | int(round(0, None))
33 33 | ### Unsafe
34 34 |
35 35 | int(round(0.1))
36 |-int(round(0.1, None))
36 |+round(0.1)
37 37 |
38 38 | # Argument type is not checked
39 39 | foo = type("Foo", (), {"__round__": lambda self: 4.2})()
35 35 | int(math.ceil())
36 |-int(math.floor())
36 |+math.floor()
37 37 | int(math.trunc())
38 38 |
39 39 | int(round(inferred_int, 0))
RUF046.py:41:1: RUF046 [*] Value being casted is already an integer
RUF046.py:37:1: RUF046 [*] Value being casted is already an integer
|
39 | foo = type("Foo", (), {"__round__": lambda self: 4.2})()
40 |
41 | int(round(foo))
| ^^^^^^^^^^^^^^^ RUF046
42 | int(round(foo, 0))
43 | int(round(foo, None))
35 | int(math.ceil())
36 | int(math.floor())
37 | int(math.trunc())
| ^^^^^^^^^^^^^^^^^ RUF046
38 |
39 | int(round(inferred_int, 0))
|
= help: Remove unnecessary conversion to `int`
Unsafe fix
38 38 | # Argument type is not checked
39 39 | foo = type("Foo", (), {"__round__": lambda self: 4.2})()
40 40 |
41 |-int(round(foo))
41 |+round(foo)
42 42 | int(round(foo, 0))
43 43 | int(round(foo, None))
34 34 |
35 35 | int(math.ceil())
36 36 | int(math.floor())
37 |-int(math.trunc())
37 |+math.trunc()
38 38 |
39 39 | int(round(inferred_int, 0))
40 40 | int(round(inferred_int, 10))
RUF046.py:39:1: RUF046 [*] Value being casted is already an integer
|
37 | int(math.trunc())
38 |
39 | int(round(inferred_int, 0))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF046
40 | int(round(inferred_int, 10))
|
= help: Remove unnecessary conversion to `int`
Unsafe fix
36 36 | int(math.floor())
37 37 | int(math.trunc())
38 38 |
39 |-int(round(inferred_int, 0))
39 |+round(inferred_int, 0)
40 40 | int(round(inferred_int, 10))
41 41 |
42 42 | int(round(inferred_int))
RUF046.py:40:1: RUF046 [*] Value being casted is already an integer
|
39 | int(round(inferred_int, 0))
40 | int(round(inferred_int, 10))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF046
41 |
42 | int(round(inferred_int))
|
= help: Remove unnecessary conversion to `int`
Unsafe fix
37 37 | int(math.trunc())
38 38 |
39 39 | int(round(inferred_int, 0))
40 |-int(round(inferred_int, 10))
40 |+round(inferred_int, 10)
41 41 |
42 42 | int(round(inferred_int))
43 43 | int(round(inferred_int, None))
RUF046.py:42:1: RUF046 [*] Value being casted is already an integer
|
40 | int(round(inferred_int, 10))
41 |
42 | int(round(inferred_int))
| ^^^^^^^^^^^^^^^^^^^^^^^^ RUF046
43 | int(round(inferred_int, None))
|
= help: Remove unnecessary conversion to `int`
Unsafe fix
39 39 | int(round(inferred_int, 0))
40 40 | int(round(inferred_int, 10))
41 41 |
42 |-int(round(inferred_int))
42 |+round(inferred_int)
43 43 | int(round(inferred_int, None))
44 44 |
45 45 | int(round(inferred_float))
RUF046.py:43:1: RUF046 [*] Value being casted is already an integer
|
41 | int(round(foo))
42 | int(round(foo, 0))
43 | int(round(foo, None))
| ^^^^^^^^^^^^^^^^^^^^^ RUF046
42 | int(round(inferred_int))
43 | int(round(inferred_int, None))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF046
44 |
45 | ## No errors
45 | int(round(inferred_float))
|
= help: Remove unnecessary conversion to `int`
Unsafe fix
40 40 |
41 41 | int(round(foo))
42 42 | int(round(foo, 0))
43 |-int(round(foo, None))
43 |+round(foo)
40 40 | int(round(inferred_int, 10))
41 41 |
42 42 | int(round(inferred_int))
43 |-int(round(inferred_int, None))
43 |+round(inferred_int, None)
44 44 |
45 45 | ## No errors
46 46 | int(round(0, 3.14))
45 45 | int(round(inferred_float))
46 46 | int(round(inferred_float, None))
RUF046.py:45:1: RUF046 [*] Value being casted is already an integer
|
43 | int(round(inferred_int, None))
44 |
45 | int(round(inferred_float))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF046
46 | int(round(inferred_float, None))
|
= help: Remove unnecessary conversion to `int`
Unsafe fix
42 42 | int(round(inferred_int))
43 43 | int(round(inferred_int, None))
44 44 |
45 |-int(round(inferred_float))
45 |+round(inferred_float)
46 46 | int(round(inferred_float, None))
47 47 |
48 48 | int(round(unknown))
RUF046.py:46:1: RUF046 [*] Value being casted is already an integer
|
45 | int(round(inferred_float))
46 | int(round(inferred_float, None))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RUF046
47 |
48 | int(round(unknown))
|
= help: Remove unnecessary conversion to `int`
Unsafe fix
43 43 | int(round(inferred_int, None))
44 44 |
45 45 | int(round(inferred_float))
46 |-int(round(inferred_float, None))
46 |+round(inferred_float, None)
47 47 |
48 48 | int(round(unknown))
49 49 | int(round(unknown, None))
RUF046.py:48:1: RUF046 [*] Value being casted is already an integer
|
46 | int(round(inferred_float, None))
47 |
48 | int(round(unknown))
| ^^^^^^^^^^^^^^^^^^^ RUF046
49 | int(round(unknown, None))
|
= help: Remove unnecessary conversion to `int`
Unsafe fix
45 45 | int(round(inferred_float))
46 46 | int(round(inferred_float, None))
47 47 |
48 |-int(round(unknown))
48 |+round(unknown)
49 49 | int(round(unknown, None))
50 50 |
51 51 |
RUF046.py:49:1: RUF046 [*] Value being casted is already an integer
|
48 | int(round(unknown))
49 | int(round(unknown, None))
| ^^^^^^^^^^^^^^^^^^^^^^^^^ RUF046
|
= help: Remove unnecessary conversion to `int`
Unsafe fix
46 46 | int(round(inferred_float, None))
47 47 |
48 48 | int(round(unknown))
49 |-int(round(unknown, None))
49 |+round(unknown, None)
50 50 |
51 51 |
52 52 | ### No errors

View file

@ -665,6 +665,14 @@ impl BuiltinTypeChecker for IntChecker {
const EXPR_TYPE: PythonType = PythonType::Number(NumberLike::Integer);
}
struct FloatChecker;
impl BuiltinTypeChecker for FloatChecker {
const BUILTIN_TYPE_NAME: &'static str = "float";
const TYPING_NAME: Option<&'static str> = None;
const EXPR_TYPE: PythonType = PythonType::Number(NumberLike::Float);
}
pub struct IoBaseChecker;
impl TypeChecker for IoBaseChecker {
@ -850,6 +858,11 @@ pub fn is_int(binding: &Binding, semantic: &SemanticModel) -> bool {
check_type::<IntChecker>(binding, semantic)
}
/// Test whether the given binding can be considered an instance of `float`.
pub fn is_float(binding: &Binding, semantic: &SemanticModel) -> bool {
check_type::<FloatChecker>(binding, semantic)
}
/// Test whether the given binding can be considered a set.
///
/// For this, we check what value might be associated with it through it's initialization and