diff --git a/README.md b/README.md index a81f87362a..2ae891468c 100644 --- a/README.md +++ b/README.md @@ -469,6 +469,7 @@ The 🛠 emoji indicates that a rule is automatically fixable by the `--fix` com | B013 | RedundantTupleInExceptionHandler | A length-one tuple literal is redundant. Write `except ValueError:` instead of `except (ValueError,):`. | | | B014 | DuplicateHandlerException | Exception handler with duplicate exception: `ValueError` | 🛠 | | B015 | UselessComparison | Pointless comparison. This comparison does nothing but waste CPU instructions. Either prepend `assert` or remove it. | | +| B016 | CannotRaiseLiteral | Cannot raise a literal. Did you intend to return it or raise an Exception? | | | B017 | NoAssertRaisesException | `assertRaises(Exception):` should be considered evil. | | | B018 | UselessExpression | Found useless expression. Either assign it to a variable or remove it. | | | B025 | DuplicateTryBlockException | try-except block with duplicate exception `Exception` | | diff --git a/resources/test/fixtures/B016.py b/resources/test/fixtures/B016.py new file mode 100644 index 0000000000..cc023a0f0f --- /dev/null +++ b/resources/test/fixtures/B016.py @@ -0,0 +1,11 @@ +""" +Should emit: +B016 - on lines 6, 7, and 8 +""" + +raise False +raise 1 +raise "string" +raise Exception(False) +raise Exception(1) +raise Exception("string") diff --git a/src/check_ast.rs b/src/check_ast.rs index 4e0b46107b..3f8623267f 100644 --- a/src/check_ast.rs +++ b/src/check_ast.rs @@ -733,6 +733,11 @@ where pyflakes::plugins::raise_not_implemented(self, expr); } } + if self.settings.enabled.contains(&CheckCode::B016) { + if let Some(exc) = exc { + flake8_bugbear::plugins::cannot_raise_literal(self, exc); + } + } } StmtKind::AugAssign { target, .. } => { self.handle_node_load(target); diff --git a/src/checks.rs b/src/checks.rs index a8b8ad0592..1fd20edf4e 100644 --- a/src/checks.rs +++ b/src/checks.rs @@ -85,6 +85,7 @@ pub enum CheckCode { B013, B014, B015, + B016, B017, B018, B025, @@ -303,6 +304,7 @@ pub enum CheckKind { RedundantTupleInExceptionHandler(String), DuplicateHandlerException(Vec), UselessComparison, + CannotRaiseLiteral, NoAssertRaisesException, UselessExpression, DuplicateTryBlockException(String), @@ -493,6 +495,7 @@ impl CheckCode { } CheckCode::B014 => CheckKind::DuplicateHandlerException(vec!["ValueError".to_string()]), CheckCode::B015 => CheckKind::UselessComparison, + CheckCode::B016 => CheckKind::CannotRaiseLiteral, CheckCode::B017 => CheckKind::NoAssertRaisesException, CheckCode::B018 => CheckKind::UselessExpression, CheckCode::B025 => CheckKind::DuplicateTryBlockException("Exception".to_string()), @@ -688,6 +691,7 @@ impl CheckCode { CheckCode::B013 => CheckCategory::Flake8Bugbear, CheckCode::B014 => CheckCategory::Flake8Bugbear, CheckCode::B015 => CheckCategory::Flake8Bugbear, + CheckCode::B016 => CheckCategory::Flake8Bugbear, CheckCode::B017 => CheckCategory::Flake8Bugbear, CheckCode::B018 => CheckCategory::Flake8Bugbear, CheckCode::B025 => CheckCategory::Flake8Bugbear, @@ -850,6 +854,7 @@ impl CheckKind { CheckKind::RedundantTupleInExceptionHandler(_) => &CheckCode::B013, CheckKind::DuplicateHandlerException(_) => &CheckCode::B014, CheckKind::UselessComparison => &CheckCode::B015, + CheckKind::CannotRaiseLiteral => &CheckCode::B016, CheckKind::NoAssertRaisesException => &CheckCode::B017, CheckKind::UselessExpression => &CheckCode::B018, CheckKind::DuplicateTryBlockException(_) => &CheckCode::B025, @@ -1134,6 +1139,9 @@ impl CheckKind { but waste CPU instructions. Either prepend `assert` \ or remove it." .to_string(), + CheckKind::CannotRaiseLiteral => "Cannot raise a literal. Did you intend to return it \ + or raise an Exception?" + .to_string(), CheckKind::DuplicateHandlerException(names) => { if names.len() == 1 { let name = &names[0]; diff --git a/src/checks_gen.rs b/src/checks_gen.rs index 3f6571dc3d..f682dcb8f7 100644 --- a/src/checks_gen.rs +++ b/src/checks_gen.rs @@ -25,6 +25,7 @@ pub enum CheckCodePrefix { B013, B014, B015, + B016, B017, B018, B02, @@ -263,6 +264,7 @@ impl CheckCodePrefix { CheckCode::B013, CheckCode::B014, CheckCode::B015, + CheckCode::B016, CheckCode::B017, CheckCode::B018, CheckCode::B025, @@ -276,6 +278,7 @@ impl CheckCodePrefix { CheckCode::B013, CheckCode::B014, CheckCode::B015, + CheckCode::B016, CheckCode::B017, CheckCode::B018, CheckCode::B025, @@ -290,6 +293,7 @@ impl CheckCodePrefix { CheckCode::B013, CheckCode::B014, CheckCode::B015, + CheckCode::B016, CheckCode::B017, CheckCode::B018, ], @@ -297,6 +301,7 @@ impl CheckCodePrefix { CheckCodePrefix::B013 => vec![CheckCode::B013], CheckCodePrefix::B014 => vec![CheckCode::B014], CheckCodePrefix::B015 => vec![CheckCode::B015], + CheckCodePrefix::B016 => vec![CheckCode::B016], CheckCodePrefix::B017 => vec![CheckCode::B017], CheckCodePrefix::B018 => vec![CheckCode::B018], CheckCodePrefix::B02 => vec![CheckCode::B025], @@ -923,6 +928,7 @@ impl CheckCodePrefix { CheckCodePrefix::B013 => PrefixSpecificity::Explicit, CheckCodePrefix::B014 => PrefixSpecificity::Explicit, CheckCodePrefix::B015 => PrefixSpecificity::Explicit, + CheckCodePrefix::B016 => PrefixSpecificity::Explicit, CheckCodePrefix::B017 => PrefixSpecificity::Explicit, CheckCodePrefix::B018 => PrefixSpecificity::Explicit, CheckCodePrefix::B02 => PrefixSpecificity::Tens, diff --git a/src/flake8_bugbear/plugins/cannot_raise_literal.rs b/src/flake8_bugbear/plugins/cannot_raise_literal.rs new file mode 100644 index 0000000000..9908e32590 --- /dev/null +++ b/src/flake8_bugbear/plugins/cannot_raise_literal.rs @@ -0,0 +1,15 @@ +use rustpython_ast::{Expr, ExprKind}; + +use crate::ast::types::{CheckLocator, Range}; +use crate::check_ast::Checker; +use crate::checks::{Check, CheckKind}; + +/// B016 +pub fn cannot_raise_literal(checker: &mut Checker, expr: &Expr) { + if let ExprKind::Constant { .. } = &expr.node { + checker.add_check(Check::new( + CheckKind::CannotRaiseLiteral, + checker.locate_check(Range::from_located(expr)), + )); + } +} diff --git a/src/flake8_bugbear/plugins/mod.rs b/src/flake8_bugbear/plugins/mod.rs index b2e597c31a..c3911bab81 100644 --- a/src/flake8_bugbear/plugins/mod.rs +++ b/src/flake8_bugbear/plugins/mod.rs @@ -1,5 +1,6 @@ pub use assert_false::assert_false; pub use assert_raises_exception::assert_raises_exception; +pub use cannot_raise_literal::cannot_raise_literal; pub use duplicate_exceptions::{duplicate_exceptions, duplicate_handler_exceptions}; pub use function_call_argument_default::function_call_argument_default; pub use mutable_argument_default::mutable_argument_default; @@ -11,6 +12,7 @@ pub use useless_expression::useless_expression; mod assert_false; mod assert_raises_exception; +mod cannot_raise_literal; mod duplicate_exceptions; mod function_call_argument_default; mod mutable_argument_default; diff --git a/src/linter.rs b/src/linter.rs index bb49364e81..7fb6a0d2fe 100644 --- a/src/linter.rs +++ b/src/linter.rs @@ -300,6 +300,7 @@ mod tests { #[test_case(CheckCode::B013, Path::new("B013.py"); "B013")] #[test_case(CheckCode::B014, Path::new("B014.py"); "B014")] #[test_case(CheckCode::B015, Path::new("B015.py"); "B015")] + #[test_case(CheckCode::B016, Path::new("B016.py"); "B016")] #[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")] diff --git a/src/snapshots/ruff__linter__tests__B016_B016.py.snap b/src/snapshots/ruff__linter__tests__B016_B016.py.snap new file mode 100644 index 0000000000..0ca8862916 --- /dev/null +++ b/src/snapshots/ruff__linter__tests__B016_B016.py.snap @@ -0,0 +1,29 @@ +--- +source: src/linter.rs +expression: checks +--- +- kind: CannotRaiseLiteral + location: + row: 6 + column: 6 + end_location: + row: 6 + column: 11 + fix: ~ +- kind: CannotRaiseLiteral + location: + row: 7 + column: 6 + end_location: + row: 7 + column: 7 + fix: ~ +- kind: CannotRaiseLiteral + location: + row: 8 + column: 6 + end_location: + row: 8 + column: 14 + fix: ~ +