@@ -2,11 +2,12 @@ use clippy_utils::diagnostics::span_lint_and_then;
22use clippy_utils:: path_to_local;
33use clippy_utils:: source:: snippet_with_applicability;
44use clippy_utils:: visitors:: { for_each_expr, is_local_used} ;
5- use rustc_ast:: LitKind ;
5+ use rustc_ast:: { BorrowKind , LitKind } ;
66use rustc_errors:: Applicability ;
77use rustc_hir:: def:: { DefKind , Res } ;
88use rustc_hir:: { Arm , BinOpKind , Expr , ExprKind , Guard , MatchSource , Node , Pat , PatKind } ;
99use rustc_lint:: LateContext ;
10+ use rustc_span:: symbol:: Ident ;
1011use rustc_span:: Span ;
1112use std:: ops:: ControlFlow ;
1213
@@ -34,45 +35,37 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) {
3435 ] ,
3536 MatchSource :: Normal ,
3637 ) = if_expr. kind
37- && let Some ( ( binding_span , is_field , is_byref ) ) = get_pat_binding ( cx, scrutinee, outer_arm)
38+ && let Some ( binding ) = get_pat_binding ( cx, scrutinee, outer_arm)
3839 {
39- if is_field && is_byref { return ; }
40- let pat_span = if let PatKind :: Ref ( pat, _) = arm. pat . kind {
41- if is_byref { pat. span } else { continue ; }
42- } else {
43- if is_byref { continue ; }
44- arm. pat . span
40+ let pat_span = match ( arm. pat . kind , binding. byref_ident ) {
41+ ( PatKind :: Ref ( pat, _) , Some ( _) ) => pat. span ,
42+ ( PatKind :: Ref ( ..) , None ) | ( _, Some ( _) ) => continue ,
43+ _ => arm. pat . span ,
4544 } ;
46-
4745 emit_redundant_guards (
4846 cx,
4947 outer_arm,
5048 if_expr. span ,
5149 pat_span,
52- binding_span,
53- is_field,
50+ & binding,
5451 arm. guard ,
5552 ) ;
5653 }
5754 // `Some(x) if let Some(2) = x`
5855 else if let Guard :: IfLet ( let_expr) = guard
59- && let Some ( ( binding_span , is_field , is_byref ) ) = get_pat_binding ( cx, let_expr. init , outer_arm)
56+ && let Some ( binding ) = get_pat_binding ( cx, let_expr. init , outer_arm)
6057 {
61- if is_field && is_byref { return ; }
62- let pat_span = if let PatKind :: Ref ( pat, _) = let_expr. pat . kind {
63- if is_byref && !is_field { pat. span } else { continue ; }
64- } else {
65- if is_byref { continue ; }
66- let_expr. pat . span
58+ let pat_span = match ( let_expr. pat . kind , binding. byref_ident ) {
59+ ( PatKind :: Ref ( pat, _) , Some ( _) ) => pat. span ,
60+ ( PatKind :: Ref ( ..) , None ) | ( _, Some ( _) ) => continue ,
61+ _ => let_expr. pat . span ,
6762 } ;
68-
6963 emit_redundant_guards (
7064 cx,
7165 outer_arm,
7266 let_expr. span ,
7367 pat_span,
74- binding_span,
75- is_field,
68+ & binding,
7669 None ,
7770 ) ;
7871 }
@@ -88,61 +81,63 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) {
8881 //
8982 // This isn't necessary in the other two checks, as they must be a pattern already.
9083 && cx. typeck_results ( ) . expr_ty ( local) == cx. typeck_results ( ) . expr_ty ( pat)
91- && let Some ( ( binding_span , is_field , is_byref ) ) = get_pat_binding ( cx, local, outer_arm)
84+ && let Some ( binding ) = get_pat_binding ( cx, local, outer_arm)
9285 {
93- if is_field && is_byref { return ; }
94- let pat_span = if let ExprKind :: AddrOf ( rustc_ast:: BorrowKind :: Ref , _, expr) = pat. kind {
95- if is_byref { expr. span } else { continue ; }
96- } else {
97- if is_byref { continue ; }
98- pat. span
86+ let pat_span = match ( pat. kind , binding. byref_ident ) {
87+ ( ExprKind :: AddrOf ( BorrowKind :: Ref , _, expr) , Some ( _) ) => expr. span ,
88+ ( ExprKind :: AddrOf ( ..) , None ) | ( _, Some ( _) ) => continue ,
89+ _ => pat. span ,
9990 } ;
100-
10191 emit_redundant_guards (
10292 cx,
10393 outer_arm,
10494 if_expr. span ,
10595 pat_span,
106- binding_span,
107- is_field,
96+ & binding,
10897 None ,
10998 ) ;
11099 }
111100 }
112101}
113102
103+ struct PatBindingInfo {
104+ span : Span ,
105+ byref_ident : Option < Ident > ,
106+ is_field : bool ,
107+ }
108+
114109fn get_pat_binding < ' tcx > (
115110 cx : & LateContext < ' tcx > ,
116111 guard_expr : & Expr < ' _ > ,
117112 outer_arm : & Arm < ' tcx > ,
118- ) -> Option < ( Span , bool , bool ) > {
113+ ) -> Option < PatBindingInfo > {
119114 if let Some ( local) = path_to_local ( guard_expr) && !is_local_used ( cx, outer_arm. body , local) {
120115 let mut span = None ;
116+ let mut byref_ident = None ;
121117 let mut multiple_bindings = false ;
122- let mut is_byref = false ;
123118 // `each_binding` gives the `HirId` of the `Pat` itself, not the binding
124119 outer_arm. pat . walk ( |pat| {
125- if let PatKind :: Binding ( bind_annot, hir_id, _ , _) = pat. kind
120+ if let PatKind :: Binding ( bind_annot, hir_id, ident , _) = pat. kind
126121 && hir_id == local
127122 {
128- is_byref = matches ! ( bind_annot. 0 , rustc_ast:: ByRef :: Yes ) ;
123+ if matches ! ( bind_annot. 0 , rustc_ast:: ByRef :: Yes ) {
124+ let _ = byref_ident. insert ( ident) ;
125+ }
126+ // the second call of `replce()` returns a `Some(span)`, meaning a multi-binding pattern
129127 if span. replace ( pat. span ) . is_some ( ) {
130128 multiple_bindings = true ;
131129 return false ;
132130 }
133131 }
134-
135132 true
136133 } ) ;
137134
138135 // Ignore bindings from or patterns, like `First(x) | Second(x, _) | Third(x, _, _)`
139136 if !multiple_bindings {
140- return span. map ( |span| {
141- (
142- span,
143- matches ! ( cx. tcx. hir( ) . get_parent( local) , Node :: PatField ( _) ) ,
144- is_byref,
145- )
137+ return span. map ( |span| PatBindingInfo {
138+ span,
139+ byref_ident,
140+ is_field : matches ! ( cx. tcx. hir( ) . get_parent( local) , Node :: PatField ( _) ) ,
146141 } ) ;
147142 }
148143 }
@@ -155,8 +150,7 @@ fn emit_redundant_guards<'tcx>(
155150 outer_arm : & Arm < ' tcx > ,
156151 guard_span : Span ,
157152 pat_span : Span ,
158- binding_span : Span ,
159- field_binding : bool ,
153+ pat_binding : & PatBindingInfo ,
160154 inner_guard : Option < Guard < ' _ > > ,
161155) {
162156 let mut app = Applicability :: MaybeIncorrect ;
@@ -168,14 +162,21 @@ fn emit_redundant_guards<'tcx>(
168162 "redundant guard" ,
169163 |diag| {
170164 let binding_replacement = snippet_with_applicability ( cx, pat_span, "<binding_repl>" , & mut app) ;
165+ let suggestion_span = match * pat_binding {
166+ PatBindingInfo {
167+ span,
168+ byref_ident : Some ( ident) ,
169+ is_field : true ,
170+ } => ( span, format ! ( "{ident}: {binding_replacement}" ) ) ,
171+ PatBindingInfo {
172+ span, is_field : true , ..
173+ } => ( span. shrink_to_hi ( ) , format ! ( ": {binding_replacement}" ) ) ,
174+ PatBindingInfo { span, .. } => ( span, binding_replacement. into_owned ( ) ) ,
175+ } ;
171176 diag. multipart_suggestion_verbose (
172177 "try" ,
173178 vec ! [
174- if field_binding {
175- ( binding_span. shrink_to_hi( ) , format!( ": {binding_replacement}" ) )
176- } else {
177- ( binding_span, binding_replacement. into_owned( ) )
178- } ,
179+ suggestion_span,
179180 (
180181 guard_span. source_callsite( ) . with_lo( outer_arm. pat. span. hi( ) ) ,
181182 inner_guard. map_or_else( String :: new, |guard| {
0 commit comments