mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-27 04:19:18 +00:00
Expand the scope of useless-expression (B018) (#3455)
This commit is contained in:
parent
aea925a898
commit
e8d17d23cb
8 changed files with 146 additions and 56 deletions
|
@ -57,3 +57,9 @@ def foo3():
|
||||||
|
|
||||||
def foo4():
|
def foo4():
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
|
def foo5():
|
||||||
|
foo.bar # Attribute (raise)
|
||||||
|
object().__class__ # Attribute (raise)
|
||||||
|
"foo" + "bar" # BinOp (raise)
|
||||||
|
|
|
@ -420,10 +420,6 @@ where
|
||||||
pyupgrade::rules::lru_cache_with_maxsize_none(self, decorator_list);
|
pyupgrade::rules::lru_cache_with_maxsize_none(self, decorator_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.settings.rules.enabled(Rule::UselessExpression) {
|
|
||||||
flake8_bugbear::rules::useless_expression(self, body);
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.settings.rules.enabled(Rule::CachedInstanceMethod) {
|
if self.settings.rules.enabled(Rule::CachedInstanceMethod) {
|
||||||
flake8_bugbear::rules::cached_instance_method(self, decorator_list);
|
flake8_bugbear::rules::cached_instance_method(self, decorator_list);
|
||||||
}
|
}
|
||||||
|
@ -756,10 +752,6 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.settings.rules.enabled(Rule::UselessExpression) {
|
|
||||||
flake8_bugbear::rules::useless_expression(self, body);
|
|
||||||
}
|
|
||||||
|
|
||||||
if !self.is_stub {
|
if !self.is_stub {
|
||||||
if self.settings.rules.any_enabled(&[
|
if self.settings.rules.any_enabled(&[
|
||||||
Rule::AbstractBaseClassWithoutAbstractMethod,
|
Rule::AbstractBaseClassWithoutAbstractMethod,
|
||||||
|
@ -1830,6 +1822,9 @@ where
|
||||||
if self.settings.rules.enabled(Rule::UselessComparison) {
|
if self.settings.rules.enabled(Rule::UselessComparison) {
|
||||||
flake8_bugbear::rules::useless_comparison(self, value);
|
flake8_bugbear::rules::useless_comparison(self, value);
|
||||||
}
|
}
|
||||||
|
if self.settings.rules.enabled(Rule::UselessExpression) {
|
||||||
|
flake8_bugbear::rules::useless_expression(self, value);
|
||||||
|
}
|
||||||
if self
|
if self
|
||||||
.settings
|
.settings
|
||||||
.rules
|
.rules
|
||||||
|
|
|
@ -19,6 +19,7 @@ impl Violation for UselessComparison {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// B015
|
||||||
pub fn useless_comparison(checker: &mut Checker, expr: &Expr) {
|
pub fn useless_comparison(checker: &mut Checker, expr: &Expr) {
|
||||||
if matches!(expr.node, ExprKind::Compare { .. }) {
|
if matches!(expr.node, ExprKind::Compare { .. }) {
|
||||||
checker
|
checker
|
||||||
|
|
|
@ -1,41 +1,77 @@
|
||||||
use rustpython_parser::ast::{Constant, ExprKind, Stmt, StmtKind};
|
use rustpython_parser::ast::{Constant, Expr, ExprKind};
|
||||||
|
|
||||||
use ruff_diagnostics::{Diagnostic, Violation};
|
use ruff_diagnostics::{Diagnostic, Violation};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
|
use ruff_python_ast::helpers::contains_effect;
|
||||||
use ruff_python_ast::types::Range;
|
use ruff_python_ast::types::Range;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub enum Kind {
|
||||||
|
Expression,
|
||||||
|
Attribute,
|
||||||
|
}
|
||||||
|
|
||||||
#[violation]
|
#[violation]
|
||||||
pub struct UselessExpression;
|
pub struct UselessExpression {
|
||||||
|
kind: Kind,
|
||||||
|
}
|
||||||
|
|
||||||
impl Violation for UselessExpression {
|
impl Violation for UselessExpression {
|
||||||
#[derive_message_formats]
|
#[derive_message_formats]
|
||||||
fn message(&self) -> String {
|
fn message(&self) -> String {
|
||||||
format!("Found useless expression. Either assign it to a variable or remove it.")
|
match self.kind {
|
||||||
}
|
Kind::Expression => {
|
||||||
}
|
format!("Found useless expression. Either assign it to a variable or remove it.")
|
||||||
|
}
|
||||||
/// B018
|
Kind::Attribute => {
|
||||||
pub fn useless_expression(checker: &mut Checker, body: &[Stmt]) {
|
format!(
|
||||||
for stmt in body {
|
"Found useless attribute access. Either assign it to a variable or remove it."
|
||||||
if let StmtKind::Expr { value } = &stmt.node {
|
)
|
||||||
match &value.node {
|
|
||||||
ExprKind::List { .. } | ExprKind::Dict { .. } | ExprKind::Set { .. } => {
|
|
||||||
checker
|
|
||||||
.diagnostics
|
|
||||||
.push(Diagnostic::new(UselessExpression, Range::from(value)));
|
|
||||||
}
|
|
||||||
ExprKind::Constant { value: val, .. } => match &val {
|
|
||||||
Constant::Str { .. } | Constant::Ellipsis => {}
|
|
||||||
_ => {
|
|
||||||
checker
|
|
||||||
.diagnostics
|
|
||||||
.push(Diagnostic::new(UselessExpression, Range::from(value)));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// B018
|
||||||
|
pub fn useless_expression(checker: &mut Checker, value: &Expr) {
|
||||||
|
// Ignore comparisons, as they're handled by `useless_comparison`.
|
||||||
|
if matches!(value.node, ExprKind::Compare { .. }) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore strings, to avoid false positives with docstrings.
|
||||||
|
if matches!(
|
||||||
|
value.node,
|
||||||
|
ExprKind::JoinedStr { .. }
|
||||||
|
| ExprKind::Constant {
|
||||||
|
value: Constant::Str(..) | Constant::Ellipsis,
|
||||||
|
..
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore statements that have side effects.
|
||||||
|
if contains_effect(&checker.ctx, value) {
|
||||||
|
// Flag attributes as useless expressions, even if they're attached to calls or other
|
||||||
|
// expressions.
|
||||||
|
if matches!(value.node, ExprKind::Attribute { .. }) {
|
||||||
|
checker.diagnostics.push(Diagnostic::new(
|
||||||
|
UselessExpression {
|
||||||
|
kind: Kind::Attribute,
|
||||||
|
},
|
||||||
|
Range::from(value),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
checker.diagnostics.push(Diagnostic::new(
|
||||||
|
UselessExpression {
|
||||||
|
kind: Kind::Expression,
|
||||||
|
},
|
||||||
|
Range::from(value),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
|
@ -314,4 +314,43 @@ expression: diagnostics
|
||||||
column: 5
|
column: 5
|
||||||
fix: ~
|
fix: ~
|
||||||
parent: ~
|
parent: ~
|
||||||
|
- kind:
|
||||||
|
name: UselessExpression
|
||||||
|
body: Found useless expression. Either assign it to a variable or remove it.
|
||||||
|
suggestion: ~
|
||||||
|
fixable: false
|
||||||
|
location:
|
||||||
|
row: 63
|
||||||
|
column: 4
|
||||||
|
end_location:
|
||||||
|
row: 63
|
||||||
|
column: 11
|
||||||
|
fix: ~
|
||||||
|
parent: ~
|
||||||
|
- kind:
|
||||||
|
name: UselessExpression
|
||||||
|
body: Found useless attribute access. Either assign it to a variable or remove it.
|
||||||
|
suggestion: ~
|
||||||
|
fixable: false
|
||||||
|
location:
|
||||||
|
row: 64
|
||||||
|
column: 4
|
||||||
|
end_location:
|
||||||
|
row: 64
|
||||||
|
column: 22
|
||||||
|
fix: ~
|
||||||
|
parent: ~
|
||||||
|
- kind:
|
||||||
|
name: UselessExpression
|
||||||
|
body: Found useless expression. Either assign it to a variable or remove it.
|
||||||
|
suggestion: ~
|
||||||
|
fixable: false
|
||||||
|
location:
|
||||||
|
row: 65
|
||||||
|
column: 4
|
||||||
|
end_location:
|
||||||
|
row: 65
|
||||||
|
column: 17
|
||||||
|
fix: ~
|
||||||
|
parent: ~
|
||||||
|
|
||||||
|
|
|
@ -42,26 +42,6 @@ expression: diagnostics
|
||||||
row: 15
|
row: 15
|
||||||
column: 21
|
column: 21
|
||||||
parent: ~
|
parent: ~
|
||||||
- kind:
|
|
||||||
name: IfElseBlockInsteadOfDictGet
|
|
||||||
body: "Use `var = a_dict.get(key, val1 + val2)` instead of an `if` block"
|
|
||||||
suggestion: "Replace with `var = a_dict.get(key, val1 + val2)`"
|
|
||||||
fixable: true
|
|
||||||
location:
|
|
||||||
row: 18
|
|
||||||
column: 0
|
|
||||||
end_location:
|
|
||||||
row: 21
|
|
||||||
column: 21
|
|
||||||
fix:
|
|
||||||
content: "var = a_dict.get(key, val1 + val2)"
|
|
||||||
location:
|
|
||||||
row: 18
|
|
||||||
column: 0
|
|
||||||
end_location:
|
|
||||||
row: 21
|
|
||||||
column: 21
|
|
||||||
parent: ~
|
|
||||||
- kind:
|
- kind:
|
||||||
name: IfElseBlockInsteadOfDictGet
|
name: IfElseBlockInsteadOfDictGet
|
||||||
body: "Use `var = a_dict.get(keys[idx], \"default\")` instead of an `if` block"
|
body: "Use `var = a_dict.get(keys[idx], \"default\")` instead of an `if` block"
|
||||||
|
|
|
@ -37,10 +37,10 @@ expression: diagnostics
|
||||||
content: ""
|
content: ""
|
||||||
location:
|
location:
|
||||||
row: 16
|
row: 16
|
||||||
column: 0
|
column: 4
|
||||||
end_location:
|
end_location:
|
||||||
row: 17
|
row: 16
|
||||||
column: 0
|
column: 8
|
||||||
parent: ~
|
parent: ~
|
||||||
- kind:
|
- kind:
|
||||||
name: UnusedVariable
|
name: UnusedVariable
|
||||||
|
|
|
@ -131,6 +131,39 @@ pub fn contains_effect(ctx: &Context, expr: &Expr) -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Avoid false positive for overloaded operators.
|
||||||
|
if let ExprKind::BinOp { left, right, .. } = &expr.node {
|
||||||
|
if !matches!(
|
||||||
|
left.node,
|
||||||
|
ExprKind::Constant { .. }
|
||||||
|
| ExprKind::JoinedStr { .. }
|
||||||
|
| ExprKind::List { .. }
|
||||||
|
| ExprKind::Tuple { .. }
|
||||||
|
| ExprKind::Set { .. }
|
||||||
|
| ExprKind::Dict { .. }
|
||||||
|
| ExprKind::ListComp { .. }
|
||||||
|
| ExprKind::SetComp { .. }
|
||||||
|
| ExprKind::DictComp { .. }
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if !matches!(
|
||||||
|
right.node,
|
||||||
|
ExprKind::Constant { .. }
|
||||||
|
| ExprKind::JoinedStr { .. }
|
||||||
|
| ExprKind::List { .. }
|
||||||
|
| ExprKind::Tuple { .. }
|
||||||
|
| ExprKind::Set { .. }
|
||||||
|
| ExprKind::Dict { .. }
|
||||||
|
| ExprKind::ListComp { .. }
|
||||||
|
| ExprKind::SetComp { .. }
|
||||||
|
| ExprKind::DictComp { .. }
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Otherwise, avoid all complex expressions.
|
// Otherwise, avoid all complex expressions.
|
||||||
matches!(
|
matches!(
|
||||||
expr.node,
|
expr.node,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue