diff --git a/crates/ruff/resources/test/fixtures/flake8_bugbear/B002.py b/crates/ruff/resources/test/fixtures/flake8_bugbear/B002.py index 41b53c41aac4d..ac57eeef35dc6 100644 --- a/crates/ruff/resources/test/fixtures/flake8_bugbear/B002.py +++ b/crates/ruff/resources/test/fixtures/flake8_bugbear/B002.py @@ -1,6 +1,6 @@ """ Should emit: -B002 - on lines 15 and 20 +B002 - on lines 18, 19, and 24 """ @@ -8,13 +8,17 @@ def this_is_all_fine(n): x = n + 1 y = 1 + n z = +x + y - return +z + a = n - 1 + b = 1 - n + c = -a - b + return +z, -c def this_is_buggy(n): x = ++n - return x + y = --n + return x, y def this_is_buggy_too(n): - return ++n + return ++n, --n diff --git a/crates/ruff/src/checkers/ast/mod.rs b/crates/ruff/src/checkers/ast/mod.rs index 9dd96ce866426..c9e7bf08ef497 100644 --- a/crates/ruff/src/checkers/ast/mod.rs +++ b/crates/ruff/src/checkers/ast/mod.rs @@ -3302,8 +3302,10 @@ where check_not_is, ); } - if self.enabled(Rule::UnaryPrefixIncrement) { - flake8_bugbear::rules::unary_prefix_increment(self, expr, *op, operand); + if self.enabled(Rule::UnaryPrefixIncrementDecrement) { + flake8_bugbear::rules::unary_prefix_increment_decrement( + self, expr, *op, operand, + ); } if self.enabled(Rule::NegateEqualOp) { flake8_simplify::rules::negation_with_equal_op(self, expr, *op, operand); diff --git a/crates/ruff/src/codes.rs b/crates/ruff/src/codes.rs index 745489e464413..7ca269945b568 100644 --- a/crates/ruff/src/codes.rs +++ b/crates/ruff/src/codes.rs @@ -235,7 +235,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> { (Flake8Builtins, "003") => (RuleGroup::Unspecified, rules::flake8_builtins::rules::BuiltinAttributeShadowing), // flake8-bugbear - (Flake8Bugbear, "002") => (RuleGroup::Unspecified, rules::flake8_bugbear::rules::UnaryPrefixIncrement), + (Flake8Bugbear, "002") => (RuleGroup::Unspecified, rules::flake8_bugbear::rules::UnaryPrefixIncrementDecrement), (Flake8Bugbear, "003") => (RuleGroup::Unspecified, rules::flake8_bugbear::rules::AssignmentToOsEnviron), (Flake8Bugbear, "004") => (RuleGroup::Unspecified, rules::flake8_bugbear::rules::UnreliableCallableCheck), (Flake8Bugbear, "005") => (RuleGroup::Unspecified, rules::flake8_bugbear::rules::StripWithMultiCharacters), diff --git a/crates/ruff/src/rules/flake8_bugbear/mod.rs b/crates/ruff/src/rules/flake8_bugbear/mod.rs index df1c4632503c4..005fe03002145 100644 --- a/crates/ruff/src/rules/flake8_bugbear/mod.rs +++ b/crates/ruff/src/rules/flake8_bugbear/mod.rs @@ -42,7 +42,7 @@ mod tests { #[test_case(Rule::SetAttrWithConstant, Path::new("B009_B010.py"))] #[test_case(Rule::StarArgUnpackingAfterKeywordArg, Path::new("B026.py"))] #[test_case(Rule::StripWithMultiCharacters, Path::new("B005.py"))] - #[test_case(Rule::UnaryPrefixIncrement, Path::new("B002.py"))] + #[test_case(Rule::UnaryPrefixIncrementDecrement, Path::new("B002.py"))] #[test_case(Rule::UnintentionalTypeAnnotation, Path::new("B032.py"))] #[test_case(Rule::UnreliableCallableCheck, Path::new("B004.py"))] #[test_case(Rule::UnusedLoopControlVariable, Path::new("B007.py"))] diff --git a/crates/ruff/src/rules/flake8_bugbear/rules/mod.rs b/crates/ruff/src/rules/flake8_bugbear/rules/mod.rs index 3a1cfb474f28c..3f8a1fdaf646f 100644 --- a/crates/ruff/src/rules/flake8_bugbear/rules/mod.rs +++ b/crates/ruff/src/rules/flake8_bugbear/rules/mod.rs @@ -23,7 +23,7 @@ pub(crate) use reuse_of_groupby_generator::*; pub(crate) use setattr_with_constant::*; pub(crate) use star_arg_unpacking_after_keyword_arg::*; pub(crate) use strip_with_multi_characters::*; -pub(crate) use unary_prefix_increment::*; +pub(crate) use unary_prefix_increment_decrement::*; pub(crate) use unintentional_type_annotation::*; pub(crate) use unreliable_callable_check::*; pub(crate) use unused_loop_control_variable::*; @@ -57,7 +57,7 @@ mod reuse_of_groupby_generator; mod setattr_with_constant; mod star_arg_unpacking_after_keyword_arg; mod strip_with_multi_characters; -mod unary_prefix_increment; +mod unary_prefix_increment_decrement; mod unintentional_type_annotation; mod unreliable_callable_check; mod unused_loop_control_variable; diff --git a/crates/ruff/src/rules/flake8_bugbear/rules/unary_prefix_increment.rs b/crates/ruff/src/rules/flake8_bugbear/rules/unary_prefix_increment.rs deleted file mode 100644 index e9a096aaccb71..0000000000000 --- a/crates/ruff/src/rules/flake8_bugbear/rules/unary_prefix_increment.rs +++ /dev/null @@ -1,57 +0,0 @@ -use rustpython_parser::ast::{self, Expr, Ranged, UnaryOp}; - -use ruff_diagnostics::{Diagnostic, Violation}; -use ruff_macros::{derive_message_formats, violation}; - -use crate::checkers::ast::Checker; - -/// ## What it does -/// Checks for uses of the unary prefix increment operator (e.g., `++n`). -/// -/// ## Why is this bad? -/// Python does not support the unary prefix increment operator. Writing `++n` -/// is equivalent to `+(+(n))`, which is equivalent to `n`. -/// -/// ## Example -/// ```python -/// ++n -/// ``` -/// -/// Use instead: -/// ```python -/// n += 1 -/// ``` -/// -/// ## References -/// - [Python documentation: Unary arithmetic and bitwise operations](https://docs.python.org/3/reference/expressions.html#unary-arithmetic-and-bitwise-operations) -/// - [Python documentation: Augmented assignment statements](https://docs.python.org/3/reference/simple_stmts.html#augmented-assignment-statements) -#[violation] -pub struct UnaryPrefixIncrement; - -impl Violation for UnaryPrefixIncrement { - #[derive_message_formats] - fn message(&self) -> String { - format!("Python does not support the unary prefix increment") - } -} - -/// B002 -pub(crate) fn unary_prefix_increment( - checker: &mut Checker, - expr: &Expr, - op: UnaryOp, - operand: &Expr, -) { - if !matches!(op, UnaryOp::UAdd) { - return; - } - let Expr::UnaryOp(ast::ExprUnaryOp { op, .. }) = operand else { - return; - }; - if !matches!(op, UnaryOp::UAdd) { - return; - } - checker - .diagnostics - .push(Diagnostic::new(UnaryPrefixIncrement, expr.range())); -} diff --git a/crates/ruff/src/rules/flake8_bugbear/rules/unary_prefix_increment_decrement.rs b/crates/ruff/src/rules/flake8_bugbear/rules/unary_prefix_increment_decrement.rs new file mode 100644 index 0000000000000..b562491334596 --- /dev/null +++ b/crates/ruff/src/rules/flake8_bugbear/rules/unary_prefix_increment_decrement.rs @@ -0,0 +1,87 @@ +use rustpython_parser::ast::{self, Expr, Ranged, UnaryOp}; + +use ruff_diagnostics::{Diagnostic, Violation}; +use ruff_macros::{derive_message_formats, violation}; + +use crate::checkers::ast::Checker; + +/// ## What it does +/// Checks for the attempted use of the unary prefix increment (`++`) or +/// decrement operator (`--`). +/// +/// ## Why is this bad? +/// Python does not support the unary prefix increment or decrement operator. +/// Writing `++n` is equivalent to `+(+(n))` and writing `--n` is equivalent to +/// `-(-(n))`. In both cases, it is equivalent to `n`. +/// +/// ## Example +/// ```python +/// ++x +/// --y +/// ``` +/// +/// Use instead: +/// ```python +/// x += 1 +/// y -= 1 +/// ``` +/// +/// ## References +/// - [Python documentation: Unary arithmetic and bitwise operations](https://docs.python.org/3/reference/expressions.html#unary-arithmetic-and-bitwise-operations) +/// - [Python documentation: Augmented assignment statements](https://docs.python.org/3/reference/simple_stmts.html#augmented-assignment-statements) +#[violation] +pub struct UnaryPrefixIncrementDecrement { + operator: UnaryPrefixOperatorType, +} + +impl Violation for UnaryPrefixIncrementDecrement { + #[derive_message_formats] + fn message(&self) -> String { + let UnaryPrefixIncrementDecrement { operator } = self; + match operator { + UnaryPrefixOperatorType::Increment => { + format!("Python does not support the unary prefix increment operator (`++`)") + } + UnaryPrefixOperatorType::Decrement => { + format!("Python does not support the unary prefix decrement operator (`--`)") + } + } + } +} + +/// B002 +pub(crate) fn unary_prefix_increment_decrement( + checker: &mut Checker, + expr: &Expr, + op: UnaryOp, + operand: &Expr, +) { + let Expr::UnaryOp(ast::ExprUnaryOp { op: nested_op, .. }) = operand else { + return; + }; + match (op, nested_op) { + (UnaryOp::UAdd, UnaryOp::UAdd) => { + checker.diagnostics.push(Diagnostic::new( + UnaryPrefixIncrementDecrement { + operator: UnaryPrefixOperatorType::Increment, + }, + expr.range(), + )); + } + (UnaryOp::USub, UnaryOp::USub) => { + checker.diagnostics.push(Diagnostic::new( + UnaryPrefixIncrementDecrement { + operator: UnaryPrefixOperatorType::Decrement, + }, + expr.range(), + )); + } + _ => {} + } +} + +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +enum UnaryPrefixOperatorType { + Increment, + Decrement, +} diff --git a/crates/ruff/src/rules/flake8_bugbear/snapshots/ruff__rules__flake8_bugbear__tests__B002_B002.py.snap b/crates/ruff/src/rules/flake8_bugbear/snapshots/ruff__rules__flake8_bugbear__tests__B002_B002.py.snap index 5afe7c81896c2..d20338980ce82 100644 --- a/crates/ruff/src/rules/flake8_bugbear/snapshots/ruff__rules__flake8_bugbear__tests__B002_B002.py.snap +++ b/crates/ruff/src/rules/flake8_bugbear/snapshots/ruff__rules__flake8_bugbear__tests__B002_B002.py.snap @@ -1,19 +1,36 @@ --- source: crates/ruff/src/rules/flake8_bugbear/mod.rs --- -B002.py:15:9: B002 Python does not support the unary prefix increment +B002.py:18:9: B002 Python does not support the unary prefix increment operator (`++`) | -14 | def this_is_buggy(n): -15 | x = ++n +17 | def this_is_buggy(n): +18 | x = ++n | ^^^ B002 -16 | return x +19 | y = --n +20 | return x, y | -B002.py:20:12: B002 Python does not support the unary prefix increment +B002.py:19:9: B002 Python does not support the unary prefix decrement operator (`--`) | -19 | def this_is_buggy_too(n): -20 | return ++n +17 | def this_is_buggy(n): +18 | x = ++n +19 | y = --n + | ^^^ B002 +20 | return x, y + | + +B002.py:24:12: B002 Python does not support the unary prefix increment operator (`++`) + | +23 | def this_is_buggy_too(n): +24 | return ++n, --n | ^^^ B002 | +B002.py:24:17: B002 Python does not support the unary prefix decrement operator (`--`) + | +23 | def this_is_buggy_too(n): +24 | return ++n, --n + | ^^^ B002 + | +