-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Retain parentheses when fixing SIM210
#7118
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,7 @@ use ruff_text_size::{Ranged, TextRange}; | |
use ruff_diagnostics::{AlwaysAutofixableViolation, AutofixKind, Diagnostic, Edit, Fix, Violation}; | ||
use ruff_macros::{derive_message_formats, violation}; | ||
use ruff_python_ast::helpers::{is_const_false, is_const_true}; | ||
use ruff_python_ast::parenthesize::parenthesized_range; | ||
|
||
use crate::checkers::ast::Checker; | ||
use crate::registry::AsRule; | ||
|
@@ -30,21 +31,29 @@ use crate::registry::AsRule; | |
/// - [Python documentation: Truth Value Testing](https://docs.python.org/3/library/stdtypes.html#truth-value-testing) | ||
#[violation] | ||
pub struct IfExprWithTrueFalse { | ||
expr: String, | ||
is_compare: bool, | ||
} | ||
|
||
impl Violation for IfExprWithTrueFalse { | ||
const AUTOFIX: AutofixKind = AutofixKind::Sometimes; | ||
|
||
#[derive_message_formats] | ||
fn message(&self) -> String { | ||
let IfExprWithTrueFalse { expr } = self; | ||
format!("Use `bool({expr})` instead of `True if {expr} else False`") | ||
let IfExprWithTrueFalse { is_compare } = self; | ||
if *is_compare { | ||
format!("Remove unnecessary `True if ... else False`") | ||
} else { | ||
format!("Use `bool(...)` instead of `True if ... else False`") | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I decided to remove the raw source code from these. I think we're hoping that this information is instead conveyed by showing code frames. |
||
} | ||
|
||
fn autofix_title(&self) -> Option<String> { | ||
let IfExprWithTrueFalse { expr } = self; | ||
Some(format!("Replace with `not {expr}")) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This message was wrong (mixed up with the next rule). |
||
let IfExprWithTrueFalse { is_compare } = self; | ||
if *is_compare { | ||
Some(format!("Remove unnecessary `True if ... else False`")) | ||
} else { | ||
Some(format!("Replace with `bool(...)")) | ||
} | ||
} | ||
} | ||
|
||
|
@@ -70,20 +79,16 @@ impl Violation for IfExprWithTrueFalse { | |
/// ## References | ||
/// - [Python documentation: Truth Value Testing](https://docs.python.org/3/library/stdtypes.html#truth-value-testing) | ||
#[violation] | ||
pub struct IfExprWithFalseTrue { | ||
expr: String, | ||
} | ||
pub struct IfExprWithFalseTrue; | ||
|
||
impl AlwaysAutofixableViolation for IfExprWithFalseTrue { | ||
#[derive_message_formats] | ||
fn message(&self) -> String { | ||
let IfExprWithFalseTrue { expr } = self; | ||
format!("Use `not {expr}` instead of `False if {expr} else True`") | ||
format!("Use `not ...` instead of `False if ... else True`") | ||
} | ||
|
||
fn autofix_title(&self) -> String { | ||
let IfExprWithFalseTrue { expr } = self; | ||
format!("Replace with `bool({expr})") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This message was wrong (mixed up with the previous rule). |
||
format!("Replace with `not ...`") | ||
} | ||
} | ||
|
||
|
@@ -135,7 +140,7 @@ impl AlwaysAutofixableViolation for IfExprWithTwistedArms { | |
} | ||
|
||
/// SIM210 | ||
pub(crate) fn explicit_true_false_in_ifexpr( | ||
pub(crate) fn if_expr_with_true_false( | ||
checker: &mut Checker, | ||
expr: &Expr, | ||
test: &Expr, | ||
|
@@ -148,33 +153,43 @@ pub(crate) fn explicit_true_false_in_ifexpr( | |
|
||
let mut diagnostic = Diagnostic::new( | ||
IfExprWithTrueFalse { | ||
expr: checker.generator().expr(test), | ||
is_compare: test.is_compare_expr(), | ||
}, | ||
expr.range(), | ||
); | ||
if checker.patch(diagnostic.kind.rule()) { | ||
if test.is_compare_expr() { | ||
diagnostic.set_fix(Fix::suggested(Edit::range_replacement( | ||
checker.locator().slice(test).to_string(), | ||
checker | ||
.locator() | ||
.slice( | ||
parenthesized_range(test.into(), expr.into(), checker.locator().contents()) | ||
.unwrap_or(test.range()), | ||
) | ||
.to_string(), | ||
expr.range(), | ||
))); | ||
} else if checker.semantic().is_builtin("bool") { | ||
let node = ast::ExprName { | ||
id: "bool".into(), | ||
ctx: ExprContext::Load, | ||
range: TextRange::default(), | ||
}; | ||
let node1 = ast::ExprCall { | ||
func: Box::new(node.into()), | ||
arguments: Arguments { | ||
args: vec![test.clone()], | ||
keywords: vec![], | ||
range: TextRange::default(), | ||
}, | ||
range: TextRange::default(), | ||
}; | ||
diagnostic.set_fix(Fix::suggested(Edit::range_replacement( | ||
checker.generator().expr(&node1.into()), | ||
checker.generator().expr( | ||
&ast::ExprCall { | ||
func: Box::new( | ||
ast::ExprName { | ||
id: "bool".into(), | ||
ctx: ExprContext::Load, | ||
range: TextRange::default(), | ||
} | ||
.into(), | ||
), | ||
arguments: Arguments { | ||
args: vec![test.clone()], | ||
keywords: vec![], | ||
range: TextRange::default(), | ||
}, | ||
range: TextRange::default(), | ||
} | ||
.into(), | ||
), | ||
expr.range(), | ||
))); | ||
}; | ||
|
@@ -183,7 +198,7 @@ pub(crate) fn explicit_true_false_in_ifexpr( | |
} | ||
|
||
/// SIM211 | ||
pub(crate) fn explicit_false_true_in_ifexpr( | ||
pub(crate) fn if_expr_with_false_true( | ||
checker: &mut Checker, | ||
expr: &Expr, | ||
test: &Expr, | ||
|
@@ -194,21 +209,17 @@ pub(crate) fn explicit_false_true_in_ifexpr( | |
return; | ||
} | ||
|
||
let mut diagnostic = Diagnostic::new( | ||
IfExprWithFalseTrue { | ||
expr: checker.generator().expr(test), | ||
}, | ||
expr.range(), | ||
); | ||
let mut diagnostic = Diagnostic::new(IfExprWithFalseTrue, expr.range()); | ||
if checker.patch(diagnostic.kind.rule()) { | ||
let node = test.clone(); | ||
let node1 = ast::ExprUnaryOp { | ||
op: UnaryOp::Not, | ||
operand: Box::new(node), | ||
range: TextRange::default(), | ||
}; | ||
diagnostic.set_fix(Fix::suggested(Edit::range_replacement( | ||
checker.generator().expr(&node1.into()), | ||
checker.generator().expr( | ||
&ast::ExprUnaryOp { | ||
op: UnaryOp::Not, | ||
operand: Box::new(test.clone()), | ||
range: TextRange::default(), | ||
} | ||
.into(), | ||
), | ||
expr.range(), | ||
))); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These names were wrong.