| use rustc_hir::intravisit::FnKind; |
| use rustc_hir::{Block, Body, FnDecl, Stmt}; |
| use rustc_lint::{LateContext, LateLintPass}; |
| use rustc_session::declare_lint_pass; |
| use rustc_span::Span; |
| use rustc_span::def_id::LocalDefId; |
| |
| mod let_and_return; |
| mod needless_return; |
| mod needless_return_with_question_mark; |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for `let`-bindings, which are subsequently |
| /// returned. |
| /// |
| /// ### Why is this bad? |
| /// It is just extraneous code. Remove it to make your code |
| /// more rusty. |
| /// |
| /// ### Known problems |
| /// In the case of some temporaries, e.g. locks, eliding the variable binding could lead |
| /// to deadlocks. See [this issue](https://github.com/rust-lang/rust/issues/37612). |
| /// This could become relevant if the code is later changed to use the code that would have been |
| /// bound without first assigning it to a let-binding. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// fn foo() -> String { |
| /// let x = String::new(); |
| /// x |
| /// } |
| /// ``` |
| /// instead, use |
| /// ```no_run |
| /// fn foo() -> String { |
| /// String::new() |
| /// } |
| /// ``` |
| #[clippy::version = "pre 1.29.0"] |
| pub LET_AND_RETURN, |
| style, |
| "creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a block" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for return statements at the end of a block. |
| /// |
| /// ### Why is this bad? |
| /// Removing the `return` and semicolon will make the code |
| /// more rusty. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// fn foo(x: usize) -> usize { |
| /// return x; |
| /// } |
| /// ``` |
| /// simplify to |
| /// ```no_run |
| /// fn foo(x: usize) -> usize { |
| /// x |
| /// } |
| /// ``` |
| #[clippy::version = "pre 1.29.0"] |
| pub NEEDLESS_RETURN, |
| // This lint requires some special handling in `check_final_expr` for `#[expect]`. |
| // This handling needs to be updated if the group gets changed. This should also |
| // be caught by tests. |
| style, |
| "using a return statement like `return expr;` where an expression would suffice" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for return statements on `Err` paired with the `?` operator. |
| /// |
| /// ### Why is this bad? |
| /// The `return` is unnecessary. |
| /// |
| /// Returns may be used to add attributes to the return expression. Return |
| /// statements with attributes are therefore be accepted by this lint. |
| /// |
| /// ### Example |
| /// ```rust,ignore |
| /// fn foo(x: usize) -> Result<(), Box<dyn Error>> { |
| /// if x == 0 { |
| /// return Err(...)?; |
| /// } |
| /// Ok(()) |
| /// } |
| /// ``` |
| /// simplify to |
| /// ```rust,ignore |
| /// fn foo(x: usize) -> Result<(), Box<dyn Error>> { |
| /// if x == 0 { |
| /// Err(...)?; |
| /// } |
| /// Ok(()) |
| /// } |
| /// ``` |
| /// if paired with `try_err`, use instead: |
| /// ```rust,ignore |
| /// fn foo(x: usize) -> Result<(), Box<dyn Error>> { |
| /// if x == 0 { |
| /// return Err(...); |
| /// } |
| /// Ok(()) |
| /// } |
| /// ``` |
| #[clippy::version = "1.73.0"] |
| pub NEEDLESS_RETURN_WITH_QUESTION_MARK, |
| style, |
| "using a return statement like `return Err(expr)?;` where removing it would suffice" |
| } |
| |
| declare_lint_pass!(Return => [LET_AND_RETURN, NEEDLESS_RETURN, NEEDLESS_RETURN_WITH_QUESTION_MARK]); |
| |
| impl<'tcx> LateLintPass<'tcx> for Return { |
| fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { |
| needless_return_with_question_mark::check_stmt(cx, stmt); |
| } |
| |
| fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) { |
| let_and_return::check_block(cx, block); |
| } |
| |
| fn check_fn( |
| &mut self, |
| cx: &LateContext<'tcx>, |
| kind: FnKind<'tcx>, |
| _: &'tcx FnDecl<'tcx>, |
| body: &'tcx Body<'tcx>, |
| sp: Span, |
| _: LocalDefId, |
| ) { |
| needless_return::check_fn(cx, kind, body, sp); |
| } |
| } |