1
1
use clippy_utils:: diagnostics:: span_lint_and_help;
2
- use clippy_utils:: last_path_segment;
3
2
use rustc_hir:: {
4
- intravisit, Body , Expr , ExprKind , FnDecl , HirId , LocalSource , MatchSource , Mutability , Pat , PatField , PatKind ,
5
- QPath , Stmt , StmtKind ,
3
+ intravisit, Body , Expr , ExprKind , FnDecl , HirId , LocalSource , Mutability , Pat , PatKind , Stmt , StmtKind ,
6
4
} ;
7
5
use rustc_lint:: { LateContext , LateLintPass , LintContext } ;
8
6
use rustc_middle:: lint:: in_external_macro;
9
- use rustc_middle:: ty:: subst:: SubstsRef ;
10
- use rustc_middle:: ty:: { AdtDef , FieldDef , Ty , TyKind , VariantDef } ;
7
+ use rustc_middle:: ty;
11
8
use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
12
9
use rustc_span:: source_map:: Span ;
13
- use std:: iter;
14
10
15
11
declare_clippy_lint ! {
16
12
/// ### What it does
@@ -87,43 +83,28 @@ declare_lint_pass!(PatternTypeMismatch => [PATTERN_TYPE_MISMATCH]);
87
83
impl < ' tcx > LateLintPass < ' tcx > for PatternTypeMismatch {
88
84
fn check_stmt ( & mut self , cx : & LateContext < ' tcx > , stmt : & ' tcx Stmt < ' _ > ) {
89
85
if let StmtKind :: Local ( local) = stmt. kind {
90
- if let Some ( init) = & local. init {
91
- if let Some ( init_ty) = cx. typeck_results ( ) . node_type_opt ( init. hir_id ) {
92
- let pat = & local. pat ;
93
- if in_external_macro ( cx. sess ( ) , pat. span ) {
94
- return ;
95
- }
96
- let deref_possible = match local. source {
97
- LocalSource :: Normal => DerefPossible :: Possible ,
98
- _ => DerefPossible :: Impossible ,
99
- } ;
100
- apply_lint ( cx, pat, init_ty, deref_possible) ;
101
- }
86
+ if in_external_macro ( cx. sess ( ) , local. pat . span ) {
87
+ return ;
102
88
}
89
+ let deref_possible = match local. source {
90
+ LocalSource :: Normal => DerefPossible :: Possible ,
91
+ _ => DerefPossible :: Impossible ,
92
+ } ;
93
+ apply_lint ( cx, local. pat , deref_possible) ;
103
94
}
104
95
}
105
96
106
97
fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' _ > ) {
107
- if let ExprKind :: Match ( scrutinee, arms, MatchSource :: Normal ) = expr. kind {
108
- if let Some ( expr_ty) = cx. typeck_results ( ) . node_type_opt ( scrutinee. hir_id ) {
109
- ' pattern_checks: for arm in arms {
110
- let pat = & arm. pat ;
111
- if in_external_macro ( cx. sess ( ) , pat. span ) {
112
- continue ' pattern_checks;
113
- }
114
- if apply_lint ( cx, pat, expr_ty, DerefPossible :: Possible ) {
115
- break ' pattern_checks;
116
- }
98
+ if let ExprKind :: Match ( _, arms, _) = expr. kind {
99
+ for arm in arms {
100
+ let pat = & arm. pat ;
101
+ if apply_lint ( cx, pat, DerefPossible :: Possible ) {
102
+ break ;
117
103
}
118
104
}
119
105
}
120
- if let ExprKind :: Let ( let_pat, let_expr, _) = expr. kind {
121
- if let Some ( expr_ty) = cx. typeck_results ( ) . node_type_opt ( let_expr. hir_id ) {
122
- if in_external_macro ( cx. sess ( ) , let_pat. span ) {
123
- return ;
124
- }
125
- apply_lint ( cx, let_pat, expr_ty, DerefPossible :: Possible ) ;
126
- }
106
+ if let ExprKind :: Let ( let_pat, ..) = expr. kind {
107
+ apply_lint ( cx, let_pat, DerefPossible :: Possible ) ;
127
108
}
128
109
}
129
110
@@ -134,12 +115,10 @@ impl<'tcx> LateLintPass<'tcx> for PatternTypeMismatch {
134
115
_: & ' tcx FnDecl < ' _ > ,
135
116
body : & ' tcx Body < ' _ > ,
136
117
_: Span ,
137
- hir_id : HirId ,
118
+ _ : HirId ,
138
119
) {
139
- if let Some ( fn_sig) = cx. typeck_results ( ) . liberated_fn_sigs ( ) . get ( hir_id) {
140
- for ( param, ty) in iter:: zip ( body. params , fn_sig. inputs ( ) ) {
141
- apply_lint ( cx, param. pat , ty, DerefPossible :: Impossible ) ;
142
- }
120
+ for param in body. params {
121
+ apply_lint ( cx, param. pat , DerefPossible :: Impossible ) ;
143
122
}
144
123
}
145
124
}
@@ -150,8 +129,8 @@ enum DerefPossible {
150
129
Impossible ,
151
130
}
152
131
153
- fn apply_lint < ' tcx > ( cx : & LateContext < ' tcx > , pat : & Pat < ' _ > , expr_ty : Ty < ' tcx > , deref_possible : DerefPossible ) -> bool {
154
- let maybe_mismatch = find_first_mismatch ( cx, pat, expr_ty , Level :: Top ) ;
132
+ fn apply_lint < ' tcx > ( cx : & LateContext < ' tcx > , pat : & Pat < ' _ > , deref_possible : DerefPossible ) -> bool {
133
+ let maybe_mismatch = find_first_mismatch ( cx, pat) ;
155
134
if let Some ( ( span, mutability, level) ) = maybe_mismatch {
156
135
span_lint_and_help (
157
136
cx,
@@ -184,132 +163,32 @@ enum Level {
184
163
}
185
164
186
165
#[ allow( rustc:: usage_of_ty_tykind) ]
187
- fn find_first_mismatch < ' tcx > (
188
- cx : & LateContext < ' tcx > ,
189
- pat : & Pat < ' _ > ,
190
- ty : Ty < ' tcx > ,
191
- level : Level ,
192
- ) -> Option < ( Span , Mutability , Level ) > {
193
- if let PatKind :: Ref ( sub_pat, _) = pat. kind {
194
- if let TyKind :: Ref ( _, sub_ty, _) = ty. kind ( ) {
195
- return find_first_mismatch ( cx, sub_pat, sub_ty, Level :: Lower ) ;
196
- }
197
- }
198
-
199
- if let TyKind :: Ref ( _, _, mutability) = * ty. kind ( ) {
200
- if is_non_ref_pattern ( & pat. kind ) {
201
- return Some ( ( pat. span , mutability, level) ) ;
202
- }
203
- }
204
-
205
- if let PatKind :: Struct ( ref qpath, field_pats, _) = pat. kind {
206
- if let TyKind :: Adt ( adt_def, substs_ref) = ty. kind ( ) {
207
- if let Some ( variant) = get_variant ( adt_def, qpath) {
208
- let field_defs = & variant. fields ;
209
- return find_first_mismatch_in_struct ( cx, field_pats, field_defs, substs_ref) ;
210
- }
166
+ fn find_first_mismatch < ' tcx > ( cx : & LateContext < ' tcx > , pat : & Pat < ' _ > ) -> Option < ( Span , Mutability , Level ) > {
167
+ let mut result = None ;
168
+ pat. walk ( |p| {
169
+ if result. is_some ( ) {
170
+ return false ;
211
171
}
212
- }
213
-
214
- if let PatKind :: TupleStruct ( ref qpath, pats, _) = pat. kind {
215
- if let TyKind :: Adt ( adt_def, substs_ref) = ty. kind ( ) {
216
- if let Some ( variant) = get_variant ( adt_def, qpath) {
217
- let field_defs = & variant. fields ;
218
- let ty_iter = field_defs. iter ( ) . map ( |field_def| field_def. ty ( cx. tcx , substs_ref) ) ;
219
- return find_first_mismatch_in_tuple ( cx, pats, ty_iter) ;
220
- }
221
- }
222
- }
223
-
224
- if let PatKind :: Tuple ( pats, _) = pat. kind {
225
- if let TyKind :: Tuple ( ..) = ty. kind ( ) {
226
- return find_first_mismatch_in_tuple ( cx, pats, ty. tuple_fields ( ) ) ;
172
+ if in_external_macro ( cx. sess ( ) , p. span ) {
173
+ return true ;
227
174
}
228
- }
229
-
230
- if let PatKind :: Or ( sub_pats) = pat. kind {
231
- for pat in sub_pats {
232
- let maybe_mismatch = find_first_mismatch ( cx, pat, ty, level) ;
233
- if let Some ( mismatch) = maybe_mismatch {
234
- return Some ( mismatch) ;
235
- }
236
- }
237
- }
238
-
239
- None
240
- }
241
-
242
- fn get_variant < ' a > ( adt_def : & ' a AdtDef , qpath : & QPath < ' _ > ) -> Option < & ' a VariantDef > {
243
- if adt_def. is_struct ( ) {
244
- if let Some ( variant) = adt_def. variants . iter ( ) . next ( ) {
245
- return Some ( variant) ;
246
- }
247
- }
248
-
249
- if adt_def. is_enum ( ) {
250
- let pat_ident = last_path_segment ( qpath) . ident ;
251
- for variant in & adt_def. variants {
252
- if variant. ident == pat_ident {
253
- return Some ( variant) ;
254
- }
255
- }
256
- }
257
-
258
- None
259
- }
260
-
261
- fn find_first_mismatch_in_tuple < ' tcx , I > (
262
- cx : & LateContext < ' tcx > ,
263
- pats : & [ Pat < ' _ > ] ,
264
- ty_iter_src : I ,
265
- ) -> Option < ( Span , Mutability , Level ) >
266
- where
267
- I : IntoIterator < Item = Ty < ' tcx > > ,
268
- {
269
- let mut field_tys = ty_iter_src. into_iter ( ) ;
270
- ' fields: for pat in pats {
271
- let field_ty = if let Some ( ty) = field_tys. next ( ) {
272
- ty
273
- } else {
274
- break ' fields;
175
+ let adjust_pat = match p. kind {
176
+ PatKind :: Or ( [ p, ..] ) => p,
177
+ _ => p,
275
178
} ;
276
-
277
- let maybe_mismatch = find_first_mismatch ( cx, pat, field_ty, Level :: Lower ) ;
278
- if let Some ( mismatch) = maybe_mismatch {
279
- return Some ( mismatch) ;
280
- }
281
- }
282
-
283
- None
284
- }
285
-
286
- fn find_first_mismatch_in_struct < ' tcx > (
287
- cx : & LateContext < ' tcx > ,
288
- field_pats : & [ PatField < ' _ > ] ,
289
- field_defs : & [ FieldDef ] ,
290
- substs_ref : SubstsRef < ' tcx > ,
291
- ) -> Option < ( Span , Mutability , Level ) > {
292
- for field_pat in field_pats {
293
- ' definitions: for field_def in field_defs {
294
- if field_pat. ident == field_def. ident {
295
- let field_ty = field_def. ty ( cx. tcx , substs_ref) ;
296
- let pat = & field_pat. pat ;
297
- let maybe_mismatch = find_first_mismatch ( cx, pat, field_ty, Level :: Lower ) ;
298
- if let Some ( mismatch) = maybe_mismatch {
299
- return Some ( mismatch) ;
179
+ if let Some ( adjustments) = cx. typeck_results ( ) . pat_adjustments ( ) . get ( adjust_pat. hir_id ) {
180
+ if let [ first, ..] = * * adjustments {
181
+ if let ty:: Ref ( .., mutability) = * first. kind ( ) {
182
+ let level = if p. hir_id == pat. hir_id {
183
+ Level :: Top
184
+ } else {
185
+ Level :: Lower
186
+ } ;
187
+ result = Some ( ( p. span , mutability, level) ) ;
300
188
}
301
- break ' definitions;
302
189
}
303
190
}
304
- }
305
-
306
- None
307
- }
308
-
309
- fn is_non_ref_pattern ( pat_kind : & PatKind < ' _ > ) -> bool {
310
- match pat_kind {
311
- PatKind :: Struct ( ..) | PatKind :: Tuple ( ..) | PatKind :: TupleStruct ( ..) | PatKind :: Path ( ..) => true ,
312
- PatKind :: Or ( sub_pats) => sub_pats. iter ( ) . any ( |pat| is_non_ref_pattern ( & pat. kind ) ) ,
313
- _ => false ,
314
- }
191
+ result. is_none ( )
192
+ } ) ;
193
+ result
315
194
}
0 commit comments