Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions clippy_lints/src/returns/needless_return_with_question_mark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use clippy_utils::res::{MaybeDef, MaybeQPath};
use clippy_utils::{is_from_proc_macro, is_inside_let_else};
use rustc_errors::Applicability;
use rustc_hir::LangItem::ResultErr;
use rustc_hir::{ExprKind, HirId, ItemKind, MatchSource, Node, OwnerNode, Stmt, StmtKind};
use rustc_hir::{Expr, ExprKind, HirId, MatchSource, Node, Stmt, StmtKind};
use rustc_lint::{LateContext, LintContext};
use rustc_middle::ty::adjustment::Adjust;

Expand All @@ -23,10 +23,8 @@ pub(super) fn check_stmt<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
&& maybe_constr.res(cx).ctor_parent(cx).is_lang_item(cx, ResultErr)

// Ensure this is not the final stmt, otherwise removing it would cause a compile error
&& let OwnerNode::Item(item) = cx.tcx.hir_owner_node(cx.tcx.hir_get_parent_item(expr.hir_id))
&& let ItemKind::Fn { body, .. } = item.kind
&& let block = cx.tcx.hir_body(body).value
&& let ExprKind::Block(block, _) = block.kind
&& let block = cx.tcx.hir_body_owned_by(cx.tcx.hir_enclosing_body_owner(expr.hir_id)).value
&& let ExprKind::Block(block, _) = peel_async_body(block).kind
&& !is_inside_let_else(cx.tcx, expr)
&& let [.., final_stmt] = block.stmts
&& final_stmt.hir_id != stmt.hir_id
Expand All @@ -45,6 +43,21 @@ pub(super) fn check_stmt<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
}
}

/// In async functions, the body is wrapped in a
/// `Block { expr: DropTemps(inner) }`. We peel through to `inner` so
/// we can check the actual stmts.
/// Returns `body_value` unchanged for non-async functions.
fn peel_async_body<'a>(body_value: &'a Expr<'a>) -> &'a Expr<'a> {
if let ExprKind::Block(block, _) = body_value.kind
&& let Some(expr) = block.expr
&& let ExprKind::DropTemps(inner) = expr.kind
{
inner
} else {
body_value
}
}

/// Checks if a return statement is "needed" in the middle of a block, or if it can be removed.
/// This is the case when the enclosing block expression is coerced to some other type,
/// which only works because of the never-ness of `return` expressions
Expand Down
26 changes: 26 additions & 0 deletions tests/ui/needless_return_with_question_mark.fixed
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,29 @@ fn general_return() {
Ok(())
}
}

async fn async_fn() -> Result<(), ()> {
if true {
Err(())?;
//~^ needless_return_with_question_mark
}
Ok(())
}

async fn async_block() -> Result<(), ()> {
async {
if true {
Err(())?;
//~^ needless_return_with_question_mark
}
Ok(())
}
.await
}

async fn async_block_final_stmt() -> Result<(), ()> {
async {
return Err(())?;
}
.await
}
26 changes: 26 additions & 0 deletions tests/ui/needless_return_with_question_mark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,29 @@ fn general_return() {
Ok(())
}
}

async fn async_fn() -> Result<(), ()> {
if true {
return Err(())?;
//~^ needless_return_with_question_mark
}
Ok(())
}

async fn async_block() -> Result<(), ()> {
async {
if true {
return Err(())?;
//~^ needless_return_with_question_mark
}
Ok(())
}
.await
}

async fn async_block_final_stmt() -> Result<(), ()> {
async {
return Err(())?;
}
.await
}
14 changes: 13 additions & 1 deletion tests/ui/needless_return_with_question_mark.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,17 @@ error: unneeded `return` statement with `?` operator
LL | return Err(())?;
| ^^^^^^^ help: remove it

error: aborting due to 2 previous errors
error: unneeded `return` statement with `?` operator
--> tests/ui/needless_return_with_question_mark.rs:134:9
|
LL | return Err(())?;
| ^^^^^^^ help: remove it

error: unneeded `return` statement with `?` operator
--> tests/ui/needless_return_with_question_mark.rs:143:13
|
LL | return Err(())?;
| ^^^^^^^ help: remove it

error: aborting due to 4 previous errors