11use clippy_utils:: diagnostics:: span_lint_and_help;
2- use clippy_utils:: last_path_segment;
32use 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 ,
64} ;
75use rustc_lint:: { LateContext , LateLintPass , LintContext } ;
86use 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;
118use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
129use rustc_span:: source_map:: Span ;
13- use std:: iter;
1410
1511declare_clippy_lint ! {
1612 /// ### What it does
@@ -87,43 +83,28 @@ declare_lint_pass!(PatternTypeMismatch => [PATTERN_TYPE_MISMATCH]);
8783impl < ' tcx > LateLintPass < ' tcx > for PatternTypeMismatch {
8884 fn check_stmt ( & mut self , cx : & LateContext < ' tcx > , stmt : & ' tcx Stmt < ' _ > ) {
8985 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 ;
10288 }
89+ let deref_possible = match local. source {
90+ LocalSource :: Normal => DerefPossible :: Possible ,
91+ _ => DerefPossible :: Impossible ,
92+ } ;
93+ apply_lint ( cx, local. pat , deref_possible) ;
10394 }
10495 }
10596
10697 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 ;
117103 }
118104 }
119105 }
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 ) ;
127108 }
128109 }
129110
@@ -134,12 +115,10 @@ impl<'tcx> LateLintPass<'tcx> for PatternTypeMismatch {
134115 _: & ' tcx FnDecl < ' _ > ,
135116 body : & ' tcx Body < ' _ > ,
136117 _: Span ,
137- hir_id : HirId ,
118+ _ : HirId ,
138119 ) {
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 ) ;
143122 }
144123 }
145124}
@@ -150,8 +129,8 @@ enum DerefPossible {
150129 Impossible ,
151130}
152131
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) ;
155134 if let Some ( ( span, mutability, level) ) = maybe_mismatch {
156135 span_lint_and_help (
157136 cx,
@@ -184,132 +163,32 @@ enum Level {
184163}
185164
186165#[ 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 ;
211171 }
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 ;
227174 }
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,
275178 } ;
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) ) ;
300188 }
301- break ' definitions;
302189 }
303190 }
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
315194}
0 commit comments