1
1
use clippy_utils:: diagnostics:: span_lint_and_then;
2
2
use clippy_utils:: path_to_local;
3
- use clippy_utils:: source:: snippet_with_applicability ;
3
+ use clippy_utils:: source:: snippet ;
4
4
use clippy_utils:: visitors:: { for_each_expr, is_local_used} ;
5
5
use rustc_ast:: { BorrowKind , LitKind } ;
6
6
use rustc_errors:: Applicability ;
7
7
use rustc_hir:: def:: { DefKind , Res } ;
8
8
use rustc_hir:: { Arm , BinOpKind , Expr , ExprKind , Guard , MatchSource , Node , Pat , PatKind } ;
9
9
use rustc_lint:: LateContext ;
10
10
use rustc_span:: symbol:: Ident ;
11
- use rustc_span:: Span ;
11
+ use rustc_span:: { Span , Symbol } ;
12
+ use std:: borrow:: Cow ;
12
13
use std:: ops:: ControlFlow ;
13
14
14
15
use super :: REDUNDANT_GUARDS ;
@@ -41,7 +42,14 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) {
41
42
( PatKind :: Ref ( ..) , None ) | ( _, Some ( _) ) => continue ,
42
43
_ => arm. pat . span ,
43
44
} ;
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
+ ) ;
45
53
}
46
54
// `Some(x) if let Some(2) = x`
47
55
else if let Guard :: IfLet ( let_expr) = guard
@@ -52,7 +60,14 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) {
52
60
( PatKind :: Ref ( ..) , None ) | ( _, Some ( _) ) => continue ,
53
61
_ => let_expr. pat . span ,
54
62
} ;
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
+ ) ;
56
71
}
57
72
// `Some(x) if x == Some(2)`
58
73
// `Some(x) if Some(2) == x`
@@ -78,11 +93,76 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) {
78
93
( ExprKind :: AddrOf ( ..) , None ) | ( _, Some ( _) ) => continue ,
79
94
_ => pat. span ,
80
95
} ;
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) ;
82
109
}
83
110
}
84
111
}
85
112
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
+
86
166
struct PatBindingInfo {
87
167
span : Span ,
88
168
byref_ident : Option < Ident > ,
@@ -134,19 +214,16 @@ fn emit_redundant_guards<'tcx>(
134
214
cx : & LateContext < ' tcx > ,
135
215
outer_arm : & Arm < ' tcx > ,
136
216
guard_span : Span ,
137
- pat_span : Span ,
217
+ binding_replacement : Cow < ' static , str > ,
138
218
pat_binding : & PatBindingInfo ,
139
219
inner_guard : Option < Guard < ' _ > > ,
140
220
) {
141
- let mut app = Applicability :: MaybeIncorrect ;
142
-
143
221
span_lint_and_then (
144
222
cx,
145
223
REDUNDANT_GUARDS ,
146
224
guard_span. source_callsite ( ) ,
147
225
"redundant guard" ,
148
226
|diag| {
149
- let binding_replacement = snippet_with_applicability ( cx, pat_span, "<binding_repl>" , & mut app) ;
150
227
let suggestion_span = match * pat_binding {
151
228
PatBindingInfo {
152
229
span,
@@ -170,14 +247,11 @@ fn emit_redundant_guards<'tcx>(
170
247
Guard :: IfLet ( l) => ( "if let" , l. span) ,
171
248
} ;
172
249
173
- format!(
174
- " {prefix} {}" ,
175
- snippet_with_applicability( cx, span, "<guard>" , & mut app) ,
176
- )
250
+ format!( " {prefix} {}" , snippet( cx, span, "<guard>" ) )
177
251
} ) ,
178
252
) ,
179
253
] ,
180
- app ,
254
+ Applicability :: MaybeIncorrect ,
181
255
) ;
182
256
} ,
183
257
) ;
0 commit comments