@@ -1840,13 +1840,38 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
18401840/// * `|[x, y]| [x, y]`
18411841/// * `|Foo(bar, baz)| Foo(bar, baz)`
18421842/// * `|Foo { bar, baz }| Foo { bar, baz }`
1843+ /// * `|x| { let y = x; ...; let z = y; z }`
1844+ /// * `|x| { let y = x; ...; let z = y; return z }`
18431845///
18441846/// Consider calling [`is_expr_untyped_identity_function`] or [`is_expr_identity_function`] instead.
1845- fn is_body_identity_function ( cx : & LateContext < ' _ > , func : & Body < ' _ > ) -> bool {
1847+ fn is_body_identity_function < ' hir > ( cx : & LateContext < ' _ > , func : & Body < ' hir > ) -> bool {
18461848 let [ param] = func. params else {
18471849 return false ;
18481850 } ;
18491851
1852+ let mut param_pat = param. pat ;
1853+
1854+ // Given a sequence of `Stmt`s of the form `let p = e` where `e` is an expr identical to the
1855+ // current `param_pat`, advance the current `param_pat` to `p`.
1856+ //
1857+ // Note: This is similar to `clippy_utils::get_last_chain_binding_hir_id`, but it works
1858+ // directly over a `Pattern` rather than a `HirId`. And it checks for compatibility via
1859+ // `is_expr_identity_of_pat` rather than `HirId` equality
1860+ let mut advance_param_pat_over_stmts = |stmts : & [ Stmt < ' hir > ] | {
1861+ for stmt in stmts {
1862+ if let StmtKind :: Let ( local) = stmt. kind
1863+ && let Some ( init) = local. init
1864+ && is_expr_identity_of_pat ( cx, param_pat, init, true )
1865+ {
1866+ param_pat = local. pat ;
1867+ } else {
1868+ return false ;
1869+ }
1870+ }
1871+
1872+ true
1873+ } ;
1874+
18501875 let mut expr = func. value ;
18511876 loop {
18521877 match expr. kind {
@@ -1875,7 +1900,30 @@ fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool {
18751900 return false ;
18761901 }
18771902 } ,
1878- _ => return is_expr_identity_of_pat ( cx, param. pat , expr, true ) ,
1903+ ExprKind :: Block (
1904+ & Block {
1905+ stmts, expr : Some ( e) , ..
1906+ } ,
1907+ _,
1908+ ) => {
1909+ if !advance_param_pat_over_stmts ( stmts) {
1910+ return false ;
1911+ }
1912+
1913+ expr = e;
1914+ } ,
1915+ ExprKind :: Block ( & Block { stmts, expr : None , .. } , _) => {
1916+ if let Some ( ( last_stmt, stmts) ) = stmts. split_last ( )
1917+ && advance_param_pat_over_stmts ( stmts)
1918+ && let StmtKind :: Semi ( e) | StmtKind :: Expr ( e) = last_stmt. kind
1919+ && let ExprKind :: Ret ( Some ( ret_val) ) = e. kind
1920+ {
1921+ expr = ret_val;
1922+ } else {
1923+ return false ;
1924+ }
1925+ } ,
1926+ _ => return is_expr_identity_of_pat ( cx, param_pat, expr, true ) ,
18791927 }
18801928 }
18811929}
0 commit comments