diff --git a/crates/ruff/src/rules/tryceratops/rules/verbose_raise.rs b/crates/ruff/src/rules/tryceratops/rules/verbose_raise.rs index c2829ca70742b..0ffc6685989e2 100644 --- a/crates/ruff/src/rules/tryceratops/rules/verbose_raise.rs +++ b/crates/ruff/src/rules/tryceratops/rules/verbose_raise.rs @@ -1,10 +1,11 @@ use rustpython_parser::ast::{self, ExceptHandler, Expr, Ranged, Stmt}; -use ruff_diagnostics::{Diagnostic, Violation}; +use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix}; use ruff_macros::{derive_message_formats, violation}; use ruff_python_ast::statement_visitor::{walk_stmt, StatementVisitor}; use crate::checkers::ast::Checker; +use crate::registry::AsRule; /// ## What it does /// Checks for needless exception names in `raise` statements. @@ -33,16 +34,20 @@ use crate::checkers::ast::Checker; #[violation] pub struct VerboseRaise; -impl Violation for VerboseRaise { +impl AlwaysAutofixableViolation for VerboseRaise { #[derive_message_formats] fn message(&self) -> String { format!("Use `raise` without specifying exception name") } + + fn autofix_title(&self) -> String { + format!("Remove exception name") + } } #[derive(Default)] struct RaiseStatementVisitor<'a> { - raises: Vec<(Option<&'a Expr>, Option<&'a Expr>)>, + raises: Vec<&'a ast::StmtRaise>, } impl<'a, 'b> StatementVisitor<'b> for RaiseStatementVisitor<'a> @@ -51,12 +56,8 @@ where { fn visit_stmt(&mut self, stmt: &'b Stmt) { match stmt { - Stmt::Raise(ast::StmtRaise { - exc, - cause, - range: _, - }) => { - self.raises.push((exc.as_deref(), cause.as_deref())); + Stmt::Raise(raise @ ast::StmtRaise { .. }) => { + self.raises.push(raise); } Stmt::Try(ast::StmtTry { body, finalbody, .. @@ -88,17 +89,22 @@ pub(crate) fn verbose_raise(checker: &mut Checker, handlers: &[ExceptHandler]) { visitor.visit_body(body); visitor.raises }; - for (exc, cause) in raises { - if cause.is_some() { + for raise in raises { + if raise.cause.is_some() { continue; } - if let Some(exc) = exc { + if let Some(exc) = raise.exc.as_ref() { // ...and the raised object is bound to the same name... - if let Expr::Name(ast::ExprName { id, .. }) = exc { + if let Expr::Name(ast::ExprName { id, .. }) = exc.as_ref() { if id == exception_name.as_str() { - checker - .diagnostics - .push(Diagnostic::new(VerboseRaise, exc.range())); + let mut diagnostic = Diagnostic::new(VerboseRaise, exc.range()); + if checker.patch(diagnostic.kind.rule()) { + diagnostic.set_fix(Fix::suggested(Edit::range_replacement( + "raise".to_string(), + raise.range(), + ))); + } + checker.diagnostics.push(diagnostic); } } } diff --git a/crates/ruff/src/rules/tryceratops/snapshots/ruff__rules__tryceratops__tests__verbose-raise_TRY201.py.snap b/crates/ruff/src/rules/tryceratops/snapshots/ruff__rules__tryceratops__tests__verbose-raise_TRY201.py.snap index 302ffa8a66011..9ee76c288ee88 100644 --- a/crates/ruff/src/rules/tryceratops/snapshots/ruff__rules__tryceratops__tests__verbose-raise_TRY201.py.snap +++ b/crates/ruff/src/rules/tryceratops/snapshots/ruff__rules__tryceratops__tests__verbose-raise_TRY201.py.snap @@ -1,27 +1,57 @@ --- source: crates/ruff/src/rules/tryceratops/mod.rs --- -TRY201.py:20:15: TRY201 Use `raise` without specifying exception name +TRY201.py:20:15: TRY201 [*] Use `raise` without specifying exception name | 18 | except MyException as e: 19 | logger.exception("process failed") 20 | raise e | ^ TRY201 | + = help: Remove exception name -TRY201.py:63:19: TRY201 Use `raise` without specifying exception name +ℹ Suggested fix +17 17 | process() +18 18 | except MyException as e: +19 19 | logger.exception("process failed") +20 |- raise e + 20 |+ raise +21 21 | +22 22 | +23 23 | def good(): + +TRY201.py:63:19: TRY201 [*] Use `raise` without specifying exception name | 61 | logger.exception("process failed") 62 | if True: 63 | raise e | ^ TRY201 | + = help: Remove exception name + +ℹ Suggested fix +60 60 | except MyException as e: +61 61 | logger.exception("process failed") +62 62 | if True: +63 |- raise e + 63 |+ raise +64 64 | +65 65 | +66 66 | def bad_that_needs_recursion_2(): -TRY201.py:74:23: TRY201 Use `raise` without specifying exception name +TRY201.py:74:23: TRY201 [*] Use `raise` without specifying exception name | 73 | def foo(): 74 | raise e | ^ TRY201 | + = help: Remove exception name + +ℹ Suggested fix +71 71 | if True: +72 72 | +73 73 | def foo(): +74 |- raise e + 74 |+ raise