return_and_then: only lint returning expressions

If an expression is not going to return from the current function of
closure, it should not get linted.

This also allows `return` expression to be linted, in addition to the
final expression. Those require blockification and proper indentation.
This commit is contained in:
Samuel Tardieu 2025-05-11 17:33:20 +02:00
parent 7f6d507bba
commit c040e9f6fc
No known key found for this signature in database
GPG key ID: BDDC3208C6FEAFA8
4 changed files with 165 additions and 9 deletions

View file

@ -9,7 +9,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::{indent_of, reindent_multiline, snippet_with_applicability};
use clippy_utils::ty::get_type_diagnostic_name;
use clippy_utils::visitors::for_each_unconsumed_temporary;
use clippy_utils::{is_expr_final_block_expr, peel_blocks};
use clippy_utils::{get_parent_expr, peel_blocks};
use super::RETURN_AND_THEN;
@ -21,7 +21,7 @@ pub(super) fn check<'tcx>(
recv: &'tcx hir::Expr<'tcx>,
arg: &'tcx hir::Expr<'_>,
) {
if !is_expr_final_block_expr(cx.tcx, expr) {
if cx.tcx.hir_get_fn_id_for_return_block(expr.hir_id).is_none() {
return;
}
@ -55,12 +55,24 @@ pub(super) fn check<'tcx>(
None => &body_snip,
};
let sugg = format!(
"let {} = {}?;\n{}",
arg_snip,
recv_snip,
reindent_multiline(inner, false, indent_of(cx, expr.span))
);
// If suggestion is going to get inserted as part of a `return` expression, it must be blockified.
let sugg = if let Some(parent_expr) = get_parent_expr(cx, expr) {
let base_indent = indent_of(cx, parent_expr.span);
let inner_indent = base_indent.map(|i| i + 4);
format!(
"{}\n{}\n{}",
reindent_multiline(&format!("{{\nlet {arg_snip} = {recv_snip}?;"), true, inner_indent),
reindent_multiline(inner, false, inner_indent),
reindent_multiline("}", false, base_indent),
)
} else {
format!(
"let {} = {}?;\n{}",
arg_snip,
recv_snip,
reindent_multiline(inner, false, indent_of(cx, expr.span))
)
};
span_lint_and_sugg(
cx,