@@ -3,7 +3,7 @@ use clippy_utils::get_parent_as_impl;
3
3
use clippy_utils:: source:: snippet;
4
4
use clippy_utils:: ty:: { implements_trait, make_normalized_projection} ;
5
5
use rustc_errors:: Applicability ;
6
- use rustc_hir:: { FnRetTy , ImplItemKind , ImplicitSelfKind , Mutability , TyKind } ;
6
+ use rustc_hir:: { FnRetTy , ImplItemKind , ImplicitSelfKind , TyKind } ;
7
7
use rustc_lint:: { LateContext , LateLintPass } ;
8
8
use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
9
9
use rustc_span:: sym;
@@ -56,58 +56,60 @@ fn is_nameable_in_impl_trait(ty: &rustc_hir::Ty<'_>) -> bool {
56
56
!matches ! ( ty. kind, TyKind :: OpaqueDef ( ..) )
57
57
}
58
58
59
- fn check_for_mutability ( cx : & LateContext < ' _ > , item : & rustc_hir:: ImplItem < ' _ > , expected_mtbl : Mutability ) {
60
- let item_did = item. owner_id . to_def_id ( ) ;
61
- let ( borrow_prefix, name, expected_implicit_self) = match expected_mtbl {
62
- Mutability :: Not => ( "&" , "iter" , ImplicitSelfKind :: ImmRef ) ,
63
- Mutability :: Mut => ( "&mut " , "iter_mut" , ImplicitSelfKind :: MutRef ) ,
64
- } ;
59
+ impl LateLintPass < ' _ > for IterWithoutIntoIter {
60
+ fn check_impl_item ( & mut self , cx : & LateContext < ' _ > , item : & rustc_hir:: ImplItem < ' _ > ) {
61
+ let item_did = item. owner_id . to_def_id ( ) ;
62
+ let ( borrow_prefix, expected_implicit_self) = match item. ident . name {
63
+ sym:: iter => ( "&" , ImplicitSelfKind :: ImmRef ) ,
64
+ sym:: iter_mut => ( "&mut " , ImplicitSelfKind :: MutRef ) ,
65
+ _ => return ,
66
+ } ;
65
67
66
- if let ImplItemKind :: Fn ( sig, _) = item. kind
67
- && let FnRetTy :: Return ( ret) = sig. decl . output
68
- && is_nameable_in_impl_trait ( ret)
69
- && cx. tcx . generics_of ( item_did) . params . is_empty ( )
70
- && sig. decl . implicit_self == expected_implicit_self
71
- && sig. decl . inputs . len ( ) == 1
72
- && let Some ( imp) = get_parent_as_impl ( cx. tcx , item. hir_id ( ) )
73
- && imp. of_trait . is_none ( )
74
- && let sig = cx. tcx . liberate_late_bound_regions (
75
- item_did,
76
- cx. tcx . fn_sig ( item_did) . skip_binder ( )
77
- )
78
- && let ref_ty = sig. inputs ( ) [ 0 ]
79
- && let Some ( into_iter_did) = cx. tcx . get_diagnostic_item ( sym:: IntoIterator )
80
- && let ret_ty = sig. output ( )
81
- // Order is important here, we need to check that the `fn iter` return type actually implements `IntoIterator`
82
- // *before* normalizing `<_ as IntoIterator>::Item` (otherwise make_normalized_projection ICEs)
83
- && implements_trait ( cx, ret_ty, into_iter_did, & [ ] )
84
- && let Some ( iter_ty) = make_normalized_projection (
85
- cx. tcx ,
86
- cx. param_env ,
87
- into_iter_did,
88
- sym ! ( Item ) ,
89
- [ ret_ty] ,
90
- )
91
- // Only lint if the `IntoIterator` impl doesn't actually exist
92
- && !implements_trait ( cx, ref_ty, into_iter_did, & [ ] )
93
- {
94
- let self_ty_snippet = format ! ( "{borrow_prefix}{}" , snippet( cx, imp. self_ty. span, ".." ) ) ;
68
+ if let ImplItemKind :: Fn ( sig, _) = item. kind
69
+ && let FnRetTy :: Return ( ret) = sig. decl . output
70
+ && is_nameable_in_impl_trait ( ret)
71
+ && cx. tcx . generics_of ( item_did) . params . is_empty ( )
72
+ && sig. decl . implicit_self == expected_implicit_self
73
+ && sig. decl . inputs . len ( ) == 1
74
+ && let Some ( imp) = get_parent_as_impl ( cx. tcx , item. hir_id ( ) )
75
+ && imp. of_trait . is_none ( )
76
+ && let sig = cx. tcx . liberate_late_bound_regions (
77
+ item_did,
78
+ cx. tcx . fn_sig ( item_did) . skip_binder ( )
79
+ )
80
+ && let ref_ty = sig. inputs ( ) [ 0 ]
81
+ && let Some ( into_iter_did) = cx. tcx . get_diagnostic_item ( sym:: IntoIterator )
82
+ && let ret_ty = sig. output ( )
83
+ // Order is important here, we need to check that the `fn iter` return type actually implements `IntoIterator`
84
+ // *before* normalizing `<_ as IntoIterator>::Item` (otherwise make_normalized_projection ICEs)
85
+ && implements_trait ( cx, ret_ty, into_iter_did, & [ ] )
86
+ && let Some ( iter_ty) = make_normalized_projection (
87
+ cx. tcx ,
88
+ cx. param_env ,
89
+ into_iter_did,
90
+ sym ! ( Item ) ,
91
+ [ ret_ty] ,
92
+ )
93
+ // Only lint if the `IntoIterator` impl doesn't actually exist
94
+ && !implements_trait ( cx, ref_ty, into_iter_did, & [ ] )
95
+ {
96
+ let self_ty_snippet = format ! ( "{borrow_prefix}{}" , snippet( cx, imp. self_ty. span, ".." ) ) ;
95
97
96
- span_lint_and_then (
97
- cx,
98
- ITER_WITHOUT_INTO_ITER ,
99
- item. span ,
100
- & format ! ( "`{name }` method without an `IntoIterator` impl for `{self_ty_snippet}`" ) ,
101
- |diag| {
102
- // Get the lower span of the `impl` block, and insert the suggestion right before it:
103
- // impl X {
104
- // ^ fn iter(&self) -> impl IntoIterator { ... }
105
- // }
106
- let span_behind_impl = cx. tcx
107
- . def_span ( cx. tcx . hir ( ) . parent_id ( item. hir_id ( ) ) . owner . def_id )
108
- . shrink_to_lo ( ) ;
98
+ span_lint_and_then (
99
+ cx,
100
+ ITER_WITHOUT_INTO_ITER ,
101
+ item. span ,
102
+ & format ! ( "`{}` method without an `IntoIterator` impl for `{self_ty_snippet}`" , item . ident ) ,
103
+ |diag| {
104
+ // Get the lower span of the `impl` block, and insert the suggestion right before it:
105
+ // impl X {
106
+ // ^ fn iter(&self) -> impl IntoIterator { ... }
107
+ // }
108
+ let span_behind_impl = cx. tcx
109
+ . def_span ( cx. tcx . hir ( ) . parent_id ( item. hir_id ( ) ) . owner . def_id )
110
+ . shrink_to_lo ( ) ;
109
111
110
- let sugg = format ! (
112
+ let sugg = format ! (
111
113
"
112
114
impl IntoIterator for {self_ty_snippet} {{
113
115
type IntoIter = {ret_ty};
@@ -117,25 +119,16 @@ impl IntoIterator for {self_ty_snippet} {{
117
119
}}
118
120
}}
119
121
"
120
- ) ;
121
- diag. span_suggestion_verbose (
122
- span_behind_impl,
123
- format ! ( "consider implementing `IntoIterator` for `{self_ty_snippet}`" ) ,
124
- sugg,
125
- // Suggestion is on a best effort basis, might need some adjustments by the user
126
- // such as adding some lifetimes in the associated types, or importing types.
127
- Applicability :: Unspecified ,
128
- ) ;
129
- } ) ;
130
- }
131
- }
132
-
133
- impl LateLintPass < ' _ > for IterWithoutIntoIter {
134
- fn check_impl_item ( & mut self , cx : & LateContext < ' _ > , item : & rustc_hir:: ImplItem < ' _ > ) {
135
- match item. ident . name {
136
- sym:: iter => check_for_mutability ( cx, item, Mutability :: Not ) ,
137
- sym:: iter_mut => check_for_mutability ( cx, item, Mutability :: Mut ) ,
138
- _ => { } ,
139
- } ;
122
+ ) ;
123
+ diag. span_suggestion_verbose (
124
+ span_behind_impl,
125
+ format ! ( "consider implementing `IntoIterator` for `{self_ty_snippet}`" ) ,
126
+ sugg,
127
+ // Suggestion is on a best effort basis, might need some adjustments by the user
128
+ // such as adding some lifetimes in the associated types, or importing types.
129
+ Applicability :: Unspecified ,
130
+ ) ;
131
+ } ) ;
132
+ }
140
133
}
141
134
}
0 commit comments