@@ -2,7 +2,7 @@ use crate::utils::visitors::LocalUsedVisitor;
22use crate :: utils:: { span_lint_and_then, SpanlessEq } ;
33use if_chain:: if_chain;
44use rustc_hir:: def:: { CtorKind , CtorOf , DefKind , Res } ;
5- use rustc_hir:: { Arm , Expr , ExprKind , Guard , HirId , Pat , PatKind , QPath , StmtKind } ;
5+ use rustc_hir:: { Arm , Expr , ExprKind , Guard , HirId , Pat , PatKind , QPath , StmtKind , UnOp } ;
66use rustc_lint:: { LateContext , LateLintPass } ;
77use rustc_middle:: ty:: { DefIdTree , TyCtxt } ;
88use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
@@ -72,8 +72,7 @@ fn check_arm(arm: &Arm<'_>, wild_outer_arm: &Arm<'_>, cx: &LateContext<'_>) {
7272 if arms_inner. iter( ) . all( |arm| arm. guard. is_none( ) ) ;
7373 // match expression must be a local binding
7474 // match <local> { .. }
75- if let ExprKind :: Path ( QPath :: Resolved ( None , path) ) = expr_in. kind;
76- if let Res :: Local ( binding_id) = path. res;
75+ if let Some ( binding_id) = addr_adjusted_binding( expr_in, cx) ;
7776 // one of the branches must be "wild-like"
7877 if let Some ( wild_inner_arm_idx) = arms_inner. iter( ) . rposition( |arm_inner| arm_is_wild_like( arm_inner, cx. tcx) ) ;
7978 let ( wild_inner_arm, non_wild_inner_arm) =
@@ -85,7 +84,12 @@ fn check_arm(arm: &Arm<'_>, wild_outer_arm: &Arm<'_>, cx: &LateContext<'_>) {
8584 // the "wild-like" branches must be equal
8685 if SpanlessEq :: new( cx) . eq_expr( wild_inner_arm. body, wild_outer_arm. body) ;
8786 // the binding must not be used in the if guard
88- if !matches!( arm. guard, Some ( Guard :: If ( guard) ) if LocalUsedVisitor :: new( binding_id) . check_expr( guard) ) ;
87+ if match arm. guard {
88+ None => true ,
89+ Some ( Guard :: If ( expr) | Guard :: IfLet ( _, expr) ) => {
90+ !LocalUsedVisitor :: new( binding_id) . check_expr( expr)
91+ }
92+ } ;
8993 // ...or anywhere in the inner match
9094 if !arms_inner. iter( ) . any( |arm| LocalUsedVisitor :: new( binding_id) . check_arm( arm) ) ;
9195 then {
@@ -170,3 +174,20 @@ fn is_none_ctor(res: Res, tcx: TyCtxt<'_>) -> bool {
170174 }
171175 false
172176}
177+
178+ /// Retrieves a binding ID with optional `&` and/or `*` operators removed. (e.g. `&**foo`)
179+ /// Returns `None` if a non-reference type is de-referenced.
180+ /// For example, if `Vec` is de-referenced to a slice, `None` is returned.
181+ fn addr_adjusted_binding ( mut expr : & Expr < ' _ > , cx : & LateContext < ' _ > ) -> Option < HirId > {
182+ loop {
183+ match expr. kind {
184+ ExprKind :: AddrOf ( _, _, e) => expr = e,
185+ ExprKind :: Path ( QPath :: Resolved ( None , path) ) => match path. res {
186+ Res :: Local ( binding_id) => break Some ( binding_id) ,
187+ _ => break None ,
188+ } ,
189+ ExprKind :: Unary ( UnOp :: UnDeref , e) if cx. typeck_results ( ) . expr_ty ( e) . is_ref ( ) => expr = e,
190+ _ => break None ,
191+ }
192+ }
193+ }
0 commit comments