Implement B018 (#582)

This commit is contained in:
Harutaka Kawamura 2022-11-04 23:53:30 +09:00 committed by GitHub
parent 1da44485d5
commit ec3fed5a61
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 310 additions and 0 deletions

55
resources/test/fixtures/B018.py vendored Normal file
View File

@ -0,0 +1,55 @@
class Foo1:
"""abc"""
class Foo2:
"""abc"""
a = 2
"str" # Str (no raise)
f"{int}" # JoinedStr (no raise)
1j # Number (complex)
1 # Number (int)
1.0 # Number (float)
b"foo" # Binary
True # NameConstant (True)
False # NameConstant (False)
None # NameConstant (None)
[1, 2] # list
{1, 2} # set
{"foo": "bar"} # dict
class Foo3:
123
a = 2
"str"
1
def foo1():
"""my docstring"""
def foo2():
"""my docstring"""
a = 2
"str" # Str (no raise)
f"{int}" # JoinedStr (no raise)
1j # Number (complex)
1 # Number (int)
1.0 # Number (float)
b"foo" # Binary
True # NameConstant (True)
False # NameConstant (False)
None # NameConstant (None)
[1, 2] # list
{1, 2} # set
{"foo": "bar"} # dict
def foo3():
123
a = 2
"str"
3

View File

@ -240,6 +240,7 @@ where
decorator_list, decorator_list,
returns, returns,
args, args,
body,
.. ..
} }
| StmtKind::AsyncFunctionDef { | StmtKind::AsyncFunctionDef {
@ -247,6 +248,7 @@ where
decorator_list, decorator_list,
returns, returns,
args, args,
body,
.. ..
} => { } => {
if self.settings.enabled.contains(&CheckCode::E743) { if self.settings.enabled.contains(&CheckCode::E743) {
@ -300,6 +302,10 @@ where
} }
} }
if self.settings.enabled.contains(&CheckCode::B018) {
flake8_bugbear::plugins::useless_expression(self, body);
}
self.check_builtin_shadowing(name, Range::from_located(stmt), true); self.check_builtin_shadowing(name, Range::from_located(stmt), true);
// Visit the decorators and arguments, but avoid the body, which will be // Visit the decorators and arguments, but avoid the body, which will be
@ -370,6 +376,7 @@ where
bases, bases,
keywords, keywords,
decorator_list, decorator_list,
body,
.. ..
} => { } => {
if self.settings.enabled.contains(&CheckCode::U004) { if self.settings.enabled.contains(&CheckCode::U004) {
@ -401,6 +408,10 @@ where
} }
} }
if self.settings.enabled.contains(&CheckCode::B018) {
flake8_bugbear::plugins::useless_expression(self, body);
}
self.check_builtin_shadowing( self.check_builtin_shadowing(
name, name,
self.locate_check(Range::from_located(stmt)), self.locate_check(Range::from_located(stmt)),

View File

@ -84,6 +84,7 @@ pub enum CheckCode {
B013, B013,
B014, B014,
B017, B017,
B018,
B025, B025,
// flake8-comprehensions // flake8-comprehensions
C400, C400,
@ -294,6 +295,7 @@ pub enum CheckKind {
RedundantTupleInExceptionHandler(String), RedundantTupleInExceptionHandler(String),
DuplicateHandlerException(Vec<String>), DuplicateHandlerException(Vec<String>),
NoAssertRaisesException, NoAssertRaisesException,
UselessExpression,
DuplicateTryBlockException(String), DuplicateTryBlockException(String),
// flake8-comprehensions // flake8-comprehensions
UnnecessaryGeneratorList, UnnecessaryGeneratorList,
@ -476,6 +478,7 @@ impl CheckCode {
} }
CheckCode::B014 => CheckKind::DuplicateHandlerException(vec!["ValueError".to_string()]), CheckCode::B014 => CheckKind::DuplicateHandlerException(vec!["ValueError".to_string()]),
CheckCode::B017 => CheckKind::NoAssertRaisesException, CheckCode::B017 => CheckKind::NoAssertRaisesException,
CheckCode::B018 => CheckKind::UselessExpression,
CheckCode::B025 => CheckKind::DuplicateTryBlockException("Exception".to_string()), CheckCode::B025 => CheckKind::DuplicateTryBlockException("Exception".to_string()),
// flake8-comprehensions // flake8-comprehensions
CheckCode::C400 => CheckKind::UnnecessaryGeneratorList, CheckCode::C400 => CheckKind::UnnecessaryGeneratorList,
@ -665,6 +668,7 @@ impl CheckCode {
CheckCode::B013 => CheckCategory::Flake8Bugbear, CheckCode::B013 => CheckCategory::Flake8Bugbear,
CheckCode::B014 => CheckCategory::Flake8Bugbear, CheckCode::B014 => CheckCategory::Flake8Bugbear,
CheckCode::B017 => CheckCategory::Flake8Bugbear, CheckCode::B017 => CheckCategory::Flake8Bugbear,
CheckCode::B018 => CheckCategory::Flake8Bugbear,
CheckCode::B025 => CheckCategory::Flake8Bugbear, CheckCode::B025 => CheckCategory::Flake8Bugbear,
CheckCode::C400 => CheckCategory::Flake8Comprehensions, CheckCode::C400 => CheckCategory::Flake8Comprehensions,
CheckCode::C401 => CheckCategory::Flake8Comprehensions, CheckCode::C401 => CheckCategory::Flake8Comprehensions,
@ -822,6 +826,7 @@ impl CheckKind {
CheckKind::RedundantTupleInExceptionHandler(_) => &CheckCode::B013, CheckKind::RedundantTupleInExceptionHandler(_) => &CheckCode::B013,
CheckKind::DuplicateHandlerException(_) => &CheckCode::B014, CheckKind::DuplicateHandlerException(_) => &CheckCode::B014,
CheckKind::NoAssertRaisesException => &CheckCode::B017, CheckKind::NoAssertRaisesException => &CheckCode::B017,
CheckKind::UselessExpression => &CheckCode::B018,
CheckKind::DuplicateTryBlockException(_) => &CheckCode::B025, CheckKind::DuplicateTryBlockException(_) => &CheckCode::B025,
// flake8-comprehensions // flake8-comprehensions
CheckKind::UnnecessaryGeneratorList => &CheckCode::C400, CheckKind::UnnecessaryGeneratorList => &CheckCode::C400,
@ -1110,6 +1115,9 @@ impl CheckKind {
`assertRaisesRegex`, or use the context manager form of `assertRaises`." `assertRaisesRegex`, or use the context manager form of `assertRaises`."
.to_string() .to_string()
} }
CheckKind::UselessExpression => {
"Found useless expression. Either assign it to a variable or remove it.".to_string()
}
CheckKind::DuplicateTryBlockException(name) => { CheckKind::DuplicateTryBlockException(name) => {
format!("try-except block with duplicate exception `{name}`") format!("try-except block with duplicate exception `{name}`")
} }

View File

@ -26,6 +26,7 @@ pub enum CheckCodePrefix {
B013, B013,
B014, B014,
B017, B017,
B018,
B02, B02,
B025, B025,
C, C,
@ -256,6 +257,7 @@ impl CheckCodePrefix {
CheckCode::B013, CheckCode::B013,
CheckCode::B014, CheckCode::B014,
CheckCode::B017, CheckCode::B017,
CheckCode::B018,
CheckCode::B025, CheckCode::B025,
], ],
CheckCodePrefix::B0 => vec![ CheckCodePrefix::B0 => vec![
@ -266,6 +268,7 @@ impl CheckCodePrefix {
CheckCode::B013, CheckCode::B013,
CheckCode::B014, CheckCode::B014,
CheckCode::B017, CheckCode::B017,
CheckCode::B018,
CheckCode::B025, CheckCode::B025,
], ],
CheckCodePrefix::B00 => vec![CheckCode::B002, CheckCode::B006, CheckCode::B007], CheckCodePrefix::B00 => vec![CheckCode::B002, CheckCode::B006, CheckCode::B007],
@ -278,12 +281,14 @@ impl CheckCodePrefix {
CheckCode::B013, CheckCode::B013,
CheckCode::B014, CheckCode::B014,
CheckCode::B017, CheckCode::B017,
CheckCode::B018,
] ]
} }
CheckCodePrefix::B011 => vec![CheckCode::B011], CheckCodePrefix::B011 => vec![CheckCode::B011],
CheckCodePrefix::B013 => vec![CheckCode::B013], CheckCodePrefix::B013 => vec![CheckCode::B013],
CheckCodePrefix::B014 => vec![CheckCode::B014], CheckCodePrefix::B014 => vec![CheckCode::B014],
CheckCodePrefix::B017 => vec![CheckCode::B017], CheckCodePrefix::B017 => vec![CheckCode::B017],
CheckCodePrefix::B018 => vec![CheckCode::B018],
CheckCodePrefix::B02 => vec![CheckCode::B025], CheckCodePrefix::B02 => vec![CheckCode::B025],
CheckCodePrefix::B025 => vec![CheckCode::B025], CheckCodePrefix::B025 => vec![CheckCode::B025],
CheckCodePrefix::C => vec![ CheckCodePrefix::C => vec![
@ -912,6 +917,7 @@ impl CheckCodePrefix {
CheckCodePrefix::B013 => PrefixSpecificity::Explicit, CheckCodePrefix::B013 => PrefixSpecificity::Explicit,
CheckCodePrefix::B014 => PrefixSpecificity::Explicit, CheckCodePrefix::B014 => PrefixSpecificity::Explicit,
CheckCodePrefix::B017 => PrefixSpecificity::Explicit, CheckCodePrefix::B017 => PrefixSpecificity::Explicit,
CheckCodePrefix::B018 => PrefixSpecificity::Explicit,
CheckCodePrefix::B02 => PrefixSpecificity::Tens, CheckCodePrefix::B02 => PrefixSpecificity::Tens,
CheckCodePrefix::B025 => PrefixSpecificity::Explicit, CheckCodePrefix::B025 => PrefixSpecificity::Explicit,
CheckCodePrefix::C => PrefixSpecificity::Category, CheckCodePrefix::C => PrefixSpecificity::Category,

View File

@ -5,6 +5,7 @@ pub use mutable_argument_default::mutable_argument_default;
pub use redundant_tuple_in_exception_handler::redundant_tuple_in_exception_handler; pub use redundant_tuple_in_exception_handler::redundant_tuple_in_exception_handler;
pub use unary_prefix_increment::unary_prefix_increment; pub use unary_prefix_increment::unary_prefix_increment;
pub use unused_loop_control_variable::unused_loop_control_variable; pub use unused_loop_control_variable::unused_loop_control_variable;
pub use useless_expression::useless_expression;
mod assert_false; mod assert_false;
mod assert_raises_exception; mod assert_raises_exception;
@ -13,3 +14,4 @@ mod mutable_argument_default;
mod redundant_tuple_in_exception_handler; mod redundant_tuple_in_exception_handler;
mod unary_prefix_increment; mod unary_prefix_increment;
mod unused_loop_control_variable; mod unused_loop_control_variable;
mod useless_expression;

View File

@ -0,0 +1,30 @@
use rustpython_ast::{Constant, ExprKind, Stmt, StmtKind};
use crate::ast::types::{CheckLocator, Range};
use crate::check_ast::Checker;
use crate::checks::{Check, CheckKind};
pub fn useless_expression(checker: &mut Checker, body: &[Stmt]) {
for stmt in body {
if let StmtKind::Expr { value } = &stmt.node {
match &value.node {
ExprKind::List { .. } | ExprKind::Dict { .. } | ExprKind::Set { .. } => {
checker.add_check(Check::new(
CheckKind::UselessExpression,
checker.locate_check(Range::from_located(value)),
));
}
ExprKind::Constant { value: val, .. } => match &val {
Constant::Str { .. } => {}
_ => {
checker.add_check(Check::new(
CheckKind::UselessExpression,
checker.locate_check(Range::from_located(value)),
));
}
},
_ => {}
}
}
}
}

View File

@ -262,6 +262,7 @@ mod tests {
#[test_case(CheckCode::B013, Path::new("B013.py"); "B013")] #[test_case(CheckCode::B013, Path::new("B013.py"); "B013")]
#[test_case(CheckCode::B014, Path::new("B014.py"); "B014")] #[test_case(CheckCode::B014, Path::new("B014.py"); "B014")]
#[test_case(CheckCode::B017, Path::new("B017.py"); "B017")] #[test_case(CheckCode::B017, Path::new("B017.py"); "B017")]
#[test_case(CheckCode::B018, Path::new("B018.py"); "B018")]
#[test_case(CheckCode::B025, Path::new("B025.py"); "B025")] #[test_case(CheckCode::B025, Path::new("B025.py"); "B025")]
#[test_case(CheckCode::C400, Path::new("C400.py"); "C400")] #[test_case(CheckCode::C400, Path::new("C400.py"); "C400")]
#[test_case(CheckCode::C401, Path::new("C401.py"); "C401")] #[test_case(CheckCode::C401, Path::new("C401.py"); "C401")]

View File

@ -0,0 +1,197 @@
---
source: src/linter.rs
expression: checks
---
- kind: UselessExpression
location:
row: 11
column: 4
end_location:
row: 11
column: 6
fix: ~
- kind: UselessExpression
location:
row: 12
column: 4
end_location:
row: 12
column: 5
fix: ~
- kind: UselessExpression
location:
row: 13
column: 4
end_location:
row: 13
column: 7
fix: ~
- kind: UselessExpression
location:
row: 14
column: 4
end_location:
row: 14
column: 10
fix: ~
- kind: UselessExpression
location:
row: 15
column: 4
end_location:
row: 15
column: 8
fix: ~
- kind: UselessExpression
location:
row: 16
column: 4
end_location:
row: 16
column: 9
fix: ~
- kind: UselessExpression
location:
row: 17
column: 4
end_location:
row: 17
column: 8
fix: ~
- kind: UselessExpression
location:
row: 18
column: 4
end_location:
row: 18
column: 10
fix: ~
- kind: UselessExpression
location:
row: 19
column: 4
end_location:
row: 19
column: 10
fix: ~
- kind: UselessExpression
location:
row: 20
column: 4
end_location:
row: 20
column: 18
fix: ~
- kind: UselessExpression
location:
row: 24
column: 4
end_location:
row: 24
column: 7
fix: ~
- kind: UselessExpression
location:
row: 27
column: 4
end_location:
row: 27
column: 5
fix: ~
- kind: UselessExpression
location:
row: 39
column: 4
end_location:
row: 39
column: 6
fix: ~
- kind: UselessExpression
location:
row: 40
column: 4
end_location:
row: 40
column: 5
fix: ~
- kind: UselessExpression
location:
row: 41
column: 4
end_location:
row: 41
column: 7
fix: ~
- kind: UselessExpression
location:
row: 42
column: 4
end_location:
row: 42
column: 10
fix: ~
- kind: UselessExpression
location:
row: 43
column: 4
end_location:
row: 43
column: 8
fix: ~
- kind: UselessExpression
location:
row: 44
column: 4
end_location:
row: 44
column: 9
fix: ~
- kind: UselessExpression
location:
row: 45
column: 4
end_location:
row: 45
column: 8
fix: ~
- kind: UselessExpression
location:
row: 46
column: 4
end_location:
row: 46
column: 10
fix: ~
- kind: UselessExpression
location:
row: 47
column: 4
end_location:
row: 47
column: 10
fix: ~
- kind: UselessExpression
location:
row: 48
column: 4
end_location:
row: 48
column: 18
fix: ~
- kind: UselessExpression
location:
row: 52
column: 4
end_location:
row: 52
column: 7
fix: ~
- kind: UselessExpression
location:
row: 55
column: 4
end_location:
row: 55
column: 5
fix: ~