11use clippy_utils:: diagnostics:: span_lint_and_then;
22use clippy_utils:: path_to_local;
3- use clippy_utils:: source:: snippet_with_applicability ;
3+ use clippy_utils:: source:: snippet ;
44use clippy_utils:: visitors:: { for_each_expr, is_local_used} ;
55use 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 ;
1010use rustc_span:: symbol:: Ident ;
11- use rustc_span:: Span ;
11+ use rustc_span:: { Span , Symbol } ;
12+ use std:: borrow:: Cow ;
1213use std:: ops:: ControlFlow ;
1314
1415use super :: REDUNDANT_GUARDS ;
@@ -41,7 +42,14 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) {
4142 ( PatKind :: Ref ( ..) , None ) | ( _, Some ( _) ) => continue ,
4243 _ => arm. pat . span ,
4344 } ;
44- emit_redundant_guards ( cx, outer_arm, if_expr. span , pat_span, & binding, arm. guard ) ;
45+ emit_redundant_guards (
46+ cx,
47+ outer_arm,
48+ if_expr. span ,
49+ snippet ( cx, pat_span, "<binding>" ) ,
50+ & binding,
51+ arm. guard ,
52+ ) ;
4553 }
4654 // `Some(x) if let Some(2) = x`
4755 else if let Guard :: IfLet ( let_expr) = guard
@@ -52,7 +60,14 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) {
5260 ( PatKind :: Ref ( ..) , None ) | ( _, Some ( _) ) => continue ,
5361 _ => let_expr. pat . span ,
5462 } ;
55- emit_redundant_guards ( cx, outer_arm, let_expr. span , pat_span, & binding, None ) ;
63+ emit_redundant_guards (
64+ cx,
65+ outer_arm,
66+ let_expr. span ,
67+ snippet ( cx, pat_span, "<binding>" ) ,
68+ & binding,
69+ None ,
70+ ) ;
5671 }
5772 // `Some(x) if x == Some(2)`
5873 // `Some(x) if Some(2) == x`
@@ -78,11 +93,76 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) {
7893 ( ExprKind :: AddrOf ( ..) , None ) | ( _, Some ( _) ) => continue ,
7994 _ => pat. span ,
8095 } ;
81- emit_redundant_guards ( cx, outer_arm, if_expr. span , pat_span, & binding, None ) ;
96+ emit_redundant_guards (
97+ cx,
98+ outer_arm,
99+ if_expr. span ,
100+ snippet ( cx, pat_span, "<binding>" ) ,
101+ & binding,
102+ None ,
103+ ) ;
104+ } else if let Guard :: If ( if_expr) = guard
105+ && let ExprKind :: MethodCall ( path, recv, args, ..) = if_expr. kind
106+ && let Some ( binding) = get_pat_binding ( cx, recv, outer_arm)
107+ {
108+ check_method_calls ( cx, outer_arm, path. ident . name , recv, args, if_expr, & binding) ;
82109 }
83110 }
84111}
85112
113+ fn check_method_calls < ' tcx > (
114+ cx : & LateContext < ' tcx > ,
115+ arm : & Arm < ' tcx > ,
116+ method : Symbol ,
117+ recv : & Expr < ' _ > ,
118+ args : & [ Expr < ' _ > ] ,
119+ if_expr : & Expr < ' _ > ,
120+ binding : & PatBindingInfo ,
121+ ) {
122+ let ty = cx. typeck_results ( ) . expr_ty ( recv) . peel_refs ( ) ;
123+ let slice_like = ty. is_slice ( ) || ty. is_array ( ) ;
124+
125+ let sugg = if method == sym ! ( is_empty) {
126+ // `s if s.is_empty()` becomes ""
127+ // `arr if arr.is_empty()` becomes []
128+
129+ if ty. is_str ( ) {
130+ r#""""# . into ( )
131+ } else if slice_like {
132+ "[]" . into ( )
133+ } else {
134+ return ;
135+ }
136+ } else if slice_like
137+ && let Some ( needle) = args. first ( )
138+ && let ExprKind :: AddrOf ( .., needle) = needle. kind
139+ && let ExprKind :: Array ( needles) = needle. kind
140+ && needles. iter ( ) . all ( |needle| expr_can_be_pat ( cx, needle) )
141+ {
142+ // `arr if arr.starts_with(&[123])` becomes [123, ..]
143+ // `arr if arr.ends_with(&[123])` becomes [.., 123]
144+ // `arr if arr.starts_with(&[])` becomes [..] (why would anyone write this?)
145+
146+ let mut sugg = snippet ( cx, needle. span , "<needle>" ) . into_owned ( ) ;
147+
148+ if needles. is_empty ( ) {
149+ sugg. insert_str ( 1 , ".." ) ;
150+ } else if method == sym ! ( starts_with) {
151+ sugg. insert_str ( sugg. len ( ) - 1 , ", .." ) ;
152+ } else if method == sym ! ( ends_with) {
153+ sugg. insert_str ( 1 , ".., " ) ;
154+ } else {
155+ return ;
156+ }
157+
158+ sugg. into ( )
159+ } else {
160+ return ;
161+ } ;
162+
163+ emit_redundant_guards ( cx, arm, if_expr. span , sugg, binding, None ) ;
164+ }
165+
86166struct PatBindingInfo {
87167 span : Span ,
88168 byref_ident : Option < Ident > ,
@@ -134,19 +214,16 @@ fn emit_redundant_guards<'tcx>(
134214 cx : & LateContext < ' tcx > ,
135215 outer_arm : & Arm < ' tcx > ,
136216 guard_span : Span ,
137- pat_span : Span ,
217+ binding_replacement : Cow < ' static , str > ,
138218 pat_binding : & PatBindingInfo ,
139219 inner_guard : Option < Guard < ' _ > > ,
140220) {
141- let mut app = Applicability :: MaybeIncorrect ;
142-
143221 span_lint_and_then (
144222 cx,
145223 REDUNDANT_GUARDS ,
146224 guard_span. source_callsite ( ) ,
147225 "redundant guard" ,
148226 |diag| {
149- let binding_replacement = snippet_with_applicability ( cx, pat_span, "<binding_repl>" , & mut app) ;
150227 let suggestion_span = match * pat_binding {
151228 PatBindingInfo {
152229 span,
@@ -170,14 +247,11 @@ fn emit_redundant_guards<'tcx>(
170247 Guard :: IfLet ( l) => ( "if let" , l. span) ,
171248 } ;
172249
173- format!(
174- " {prefix} {}" ,
175- snippet_with_applicability( cx, span, "<guard>" , & mut app) ,
176- )
250+ format!( " {prefix} {}" , snippet( cx, span, "<guard>" ) )
177251 } ) ,
178252 ) ,
179253 ] ,
180- app ,
254+ Applicability :: MaybeIncorrect ,
181255 ) ;
182256 } ,
183257 ) ;
0 commit comments