mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-02 14:51:25 +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 @ 1)
|
||||||
|
|
||||||
int(1. if ... else .2)
|
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::checkers::ast::Checker;
|
||||||
use crate::rules::ruff::rules::unnecessary_round::{
|
use crate::rules::ruff::rules::unnecessary_round::{
|
||||||
rounded_and_ndigits, InferredType, NdigitsValue, RoundedValue,
|
rounded_and_ndigits, InferredType, NdigitsValue, RoundedValue,
|
||||||
};
|
};
|
||||||
use ruff_diagnostics::{AlwaysFixableViolation, Applicability, Diagnostic, Edit, Fix};
|
use crate::Locator;
|
||||||
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;
|
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for `int` conversions of values that are already integers.
|
/// 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;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let fix = unwrap_int_expression(checker, call, argument, applicability);
|
let fix = unwrap_int_expression(
|
||||||
let diagnostic = Diagnostic::new(UnnecessaryCastToInt, call.range);
|
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));
|
checker.diagnostics.push(diagnostic.with_fix(fix));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a fix that replaces `int(expression)` with `expression`.
|
/// Creates a fix that replaces `int(expression)` with `expression`.
|
||||||
fn unwrap_int_expression(
|
fn unwrap_int_expression(
|
||||||
checker: &Checker,
|
|
||||||
call: &ExprCall,
|
call: &ExprCall,
|
||||||
argument: &Expr,
|
argument: &Expr,
|
||||||
applicability: Applicability,
|
applicability: Applicability,
|
||||||
|
semantic: &SemanticModel,
|
||||||
|
locator: &Locator,
|
||||||
|
comment_ranges: &CommentRanges,
|
||||||
|
source: &str,
|
||||||
) -> Fix {
|
) -> Fix {
|
||||||
let (locator, semantic) = (checker.locator(), checker.semantic());
|
let content = if let Some(range) = parenthesized_range(
|
||||||
|
argument.into(),
|
||||||
let argument_expr = locator.slice(argument.range());
|
(&call.arguments).into(),
|
||||||
|
comment_ranges,
|
||||||
let has_parent_expr = semantic.current_expression_parent().is_some();
|
source,
|
||||||
let new_content = if has_parent_expr || argument.is_named_expr() {
|
) {
|
||||||
format!("({argument_expr})")
|
locator.slice(range).to_string()
|
||||||
} else {
|
} 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(content, call.range());
|
||||||
let edit = Edit::range_replacement(new_content, call.range);
|
|
||||||
Fix::applicable_edit(edit, applicability)
|
Fix::applicable_edit(edit, applicability)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,3 +228,20 @@ fn round_applicability(checker: &Checker, arguments: &Arguments) -> Option<Appli
|
||||||
_ => None,
|
_ => 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
|
source: crates/ruff_linter/src/rules/ruff/mod.rs
|
||||||
snapshot_kind: text
|
|
||||||
---
|
---
|
||||||
RUF046.py:10:1: RUF046 [*] Value being casted is already an integer
|
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 |
|
77 77 |
|
||||||
78 78 |
|
78 78 |
|
||||||
79 79 | ### No errors
|
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