@@ -2,7 +2,7 @@ use crate::utils::visitors::LocalUsedVisitor;
2
2
use crate :: utils:: { span_lint_and_then, SpanlessEq } ;
3
3
use if_chain:: if_chain;
4
4
use 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 } ;
6
6
use rustc_lint:: { LateContext , LateLintPass } ;
7
7
use rustc_middle:: ty:: { DefIdTree , TyCtxt } ;
8
8
use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
@@ -72,8 +72,7 @@ fn check_arm(arm: &Arm<'_>, wild_outer_arm: &Arm<'_>, cx: &LateContext<'_>) {
72
72
if arms_inner. iter( ) . all( |arm| arm. guard. is_none( ) ) ;
73
73
// match expression must be a local binding
74
74
// 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) ;
77
76
// one of the branches must be "wild-like"
78
77
if let Some ( wild_inner_arm_idx) = arms_inner. iter( ) . rposition( |arm_inner| arm_is_wild_like( arm_inner, cx. tcx) ) ;
79
78
let ( wild_inner_arm, non_wild_inner_arm) =
@@ -85,7 +84,12 @@ fn check_arm(arm: &Arm<'_>, wild_outer_arm: &Arm<'_>, cx: &LateContext<'_>) {
85
84
// the "wild-like" branches must be equal
86
85
if SpanlessEq :: new( cx) . eq_expr( wild_inner_arm. body, wild_outer_arm. body) ;
87
86
// 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
+ } ;
89
93
// ...or anywhere in the inner match
90
94
if !arms_inner. iter( ) . any( |arm| LocalUsedVisitor :: new( binding_id) . check_arm( arm) ) ;
91
95
then {
@@ -170,3 +174,20 @@ fn is_none_ctor(res: Res, tcx: TyCtxt<'_>) -> bool {
170
174
}
171
175
false
172
176
}
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