mirror of
https://github.com/astral-sh/ruff.git
synced 2025-07-24 13:33:50 +00:00
Avoid syntax error when removing int over multiple lines (#15230)
## Summary Closes https://github.com/astral-sh/ruff/issues/15226.
This commit is contained in:
parent
2327082c43
commit
3c3f35a548
3 changed files with 105 additions and 20 deletions
|
@ -154,3 +154,9 @@ int(1 / 1)
|
|||
int(1 @ 1)
|
||||
|
||||
int(1. if ... else .2)
|
||||
|
||||
int(1 +
|
||||
1)
|
||||
|
||||
int(round(1,
|
||||
0))
|
||||
|
|
|
@ -1,13 +1,18 @@
|
|||
use ruff_diagnostics::{AlwaysFixableViolation, Applicability, Diagnostic, Edit, Fix};
|
||||
use ruff_macros::{derive_message_formats, ViolationMetadata};
|
||||
use ruff_python_ast::parenthesize::parenthesized_range;
|
||||
use ruff_python_ast::{Arguments, Expr, ExprCall};
|
||||
use ruff_python_semantic::analyze::type_inference::{NumberLike, PythonType, ResolvedPythonType};
|
||||
use ruff_python_semantic::SemanticModel;
|
||||
use ruff_python_trivia::CommentRanges;
|
||||
use ruff_source_file::LineRanges;
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::rules::ruff::rules::unnecessary_round::{
|
||||
rounded_and_ndigits, InferredType, NdigitsValue, RoundedValue,
|
||||
};
|
||||
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_semantic::analyze::type_inference::{NumberLike, PythonType, ResolvedPythonType};
|
||||
use ruff_python_semantic::SemanticModel;
|
||||
use ruff_text_size::Ranged;
|
||||
use crate::Locator;
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for `int` conversions of values that are already integers.
|
||||
|
@ -76,31 +81,48 @@ pub(crate) fn unnecessary_cast_to_int(checker: &mut Checker, call: &ExprCall) {
|
|||
return;
|
||||
};
|
||||
|
||||
let fix = unwrap_int_expression(checker, call, argument, applicability);
|
||||
let diagnostic = Diagnostic::new(UnnecessaryCastToInt, call.range);
|
||||
let fix = unwrap_int_expression(
|
||||
call,
|
||||
argument,
|
||||
applicability,
|
||||
checker.semantic(),
|
||||
checker.locator(),
|
||||
checker.comment_ranges(),
|
||||
checker.source(),
|
||||
);
|
||||
let diagnostic = Diagnostic::new(UnnecessaryCastToInt, call.range());
|
||||
|
||||
checker.diagnostics.push(diagnostic.with_fix(fix));
|
||||
}
|
||||
|
||||
/// Creates a fix that replaces `int(expression)` with `expression`.
|
||||
fn unwrap_int_expression(
|
||||
checker: &Checker,
|
||||
call: &ExprCall,
|
||||
argument: &Expr,
|
||||
applicability: Applicability,
|
||||
semantic: &SemanticModel,
|
||||
locator: &Locator,
|
||||
comment_ranges: &CommentRanges,
|
||||
source: &str,
|
||||
) -> Fix {
|
||||
let (locator, semantic) = (checker.locator(), checker.semantic());
|
||||
|
||||
let argument_expr = locator.slice(argument.range());
|
||||
|
||||
let has_parent_expr = semantic.current_expression_parent().is_some();
|
||||
let new_content = if has_parent_expr || argument.is_named_expr() {
|
||||
format!("({argument_expr})")
|
||||
let content = if let Some(range) = parenthesized_range(
|
||||
argument.into(),
|
||||
(&call.arguments).into(),
|
||||
comment_ranges,
|
||||
source,
|
||||
) {
|
||||
locator.slice(range).to_string()
|
||||
} else {
|
||||
argument_expr.to_string()
|
||||
let parenthesize = semantic.current_expression_parent().is_some()
|
||||
|| argument.is_named_expr()
|
||||
|| locator.count_lines(argument.range()) > 0;
|
||||
if parenthesize && !has_own_parentheses(argument) {
|
||||
format!("({})", locator.slice(argument.range()))
|
||||
} else {
|
||||
locator.slice(argument.range()).to_string()
|
||||
}
|
||||
};
|
||||
|
||||
let edit = Edit::range_replacement(new_content, call.range);
|
||||
let edit = Edit::range_replacement(content, call.range());
|
||||
Fix::applicable_edit(edit, applicability)
|
||||
}
|
||||
|
||||
|
@ -206,3 +228,20 @@ fn round_applicability(checker: &Checker, arguments: &Arguments) -> Option<Appli
|
|||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the given [`Expr`] has its own parentheses (e.g., `()`, `[]`, `{}`).
|
||||
fn has_own_parentheses(expr: &Expr) -> bool {
|
||||
match expr {
|
||||
Expr::ListComp(_)
|
||||
| Expr::SetComp(_)
|
||||
| Expr::DictComp(_)
|
||||
| Expr::Subscript(_)
|
||||
| Expr::List(_)
|
||||
| Expr::Set(_)
|
||||
| Expr::Dict(_)
|
||||
| Expr::Call(_) => true,
|
||||
Expr::Generator(generator) => generator.parenthesized,
|
||||
Expr::Tuple(tuple) => tuple.parenthesized,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/ruff/mod.rs
|
||||
snapshot_kind: text
|
||||
---
|
||||
RUF046.py:10:1: RUF046 [*] Value being casted is already an integer
|
||||
|
|
||||
|
@ -976,3 +975,44 @@ RUF046.py:76:1: RUF046 [*] Value being casted is already an integer
|
|||
77 77 |
|
||||
78 78 |
|
||||
79 79 | ### No errors
|
||||
|
||||
RUF046.py:158:1: RUF046 [*] Value being casted is already an integer
|
||||
|
|
||||
156 | int(1. if ... else .2)
|
||||
157 |
|
||||
158 | / int(1 +
|
||||
159 | | 1)
|
||||
| |______^ RUF046
|
||||
160 |
|
||||
161 | int(round(1,
|
||||
|
|
||||
= help: Remove unnecessary conversion to `int`
|
||||
|
||||
ℹ Safe fix
|
||||
155 155 |
|
||||
156 156 | int(1. if ... else .2)
|
||||
157 157 |
|
||||
158 |-int(1 +
|
||||
158 |+(1 +
|
||||
159 159 | 1)
|
||||
160 160 |
|
||||
161 161 | int(round(1,
|
||||
|
||||
RUF046.py:161:1: RUF046 [*] Value being casted is already an integer
|
||||
|
|
||||
159 | 1)
|
||||
160 |
|
||||
161 | / int(round(1,
|
||||
162 | | 0))
|
||||
| |_____________^ RUF046
|
||||
|
|
||||
= help: Remove unnecessary conversion to `int`
|
||||
|
||||
ℹ Safe fix
|
||||
158 158 | int(1 +
|
||||
159 159 | 1)
|
||||
160 160 |
|
||||
161 |-int(round(1,
|
||||
162 |- 0))
|
||||
161 |+round(1,
|
||||
162 |+ 0)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue