1
1
use clippy_utils:: diagnostics:: span_lint_and_then;
2
2
use clippy_utils:: get_parent_as_impl;
3
+ use clippy_utils:: source:: snippet;
3
4
use clippy_utils:: ty:: { implements_trait, make_normalized_projection} ;
4
5
use rustc_errors:: Applicability ;
5
- use rustc_hir:: { FnRetTy , ImplItemKind , ImplicitSelfKind , Mutability , QPath , TyKind } ;
6
- use rustc_hir_analysis:: hir_ty_to_ty;
6
+ use rustc_hir:: { FnRetTy , ImplItemKind , ImplicitSelfKind , Mutability , TyKind } ;
7
7
use rustc_lint:: { LateContext , LateLintPass } ;
8
- use rustc_middle:: ty:: print:: with_forced_trimmed_paths;
9
- use rustc_middle:: ty:: { self } ;
10
8
use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
11
9
use rustc_span:: sym;
12
10
@@ -59,6 +57,7 @@ fn is_nameable_in_impl_trait(ty: &rustc_hir::Ty<'_>) -> bool {
59
57
}
60
58
61
59
fn check_for_mutability ( cx : & LateContext < ' _ > , item : & rustc_hir:: ImplItem < ' _ > , expected_mtbl : Mutability ) {
60
+ let item_did = item. owner_id . to_def_id ( ) ;
62
61
let ( borrow_prefix, name, expected_implicit_self) = match expected_mtbl {
63
62
Mutability :: Not => ( "&" , "iter" , ImplicitSelfKind :: ImmRef ) ,
64
63
Mutability :: Mut => ( "&mut " , "iter_mut" , ImplicitSelfKind :: MutRef ) ,
@@ -67,38 +66,32 @@ fn check_for_mutability(cx: &LateContext<'_>, item: &rustc_hir::ImplItem<'_>, ex
67
66
if let ImplItemKind :: Fn ( sig, _) = item. kind
68
67
&& let FnRetTy :: Return ( ret) = sig. decl . output
69
68
&& is_nameable_in_impl_trait ( ret)
70
- && cx. tcx . generics_of ( item . owner_id . def_id ) . params . is_empty ( )
69
+ && cx. tcx . generics_of ( item_did ) . params . is_empty ( )
71
70
&& sig. decl . implicit_self == expected_implicit_self
72
71
&& sig. decl . inputs . len ( ) == 1
73
72
&& let Some ( imp) = get_parent_as_impl ( cx. tcx , item. hir_id ( ) )
74
73
&& imp. of_trait . is_none ( )
75
- && let TyKind :: Path ( QPath :: Resolved ( _, path) ) = imp. self_ty . kind
76
- && let Some ( ty_did) = path. res . opt_def_id ( )
77
- && let middle_ty = cx. tcx . type_of ( ty_did) . skip_binder ( )
78
- && let ref_ty = cx. tcx . mk_ty_from_kind ( ty:: Ref ( cx. tcx . lifetimes . re_erased , middle_ty, expected_mtbl) )
79
- && let Some ( into_iter_did) = cx. tcx . get_diagnostic_item ( sym:: IntoIterator )
80
- && let bound_vars = cx. tcx . late_bound_vars ( item. hir_id ( ) )
81
- // We need to erase late bounds regions so that `-> Iter<'_, T>` works
82
- && let ret_middle_ty = cx. tcx . erase_late_bound_regions (
83
- ty:: Binder :: bind_with_vars ( hir_ty_to_ty ( cx. tcx , ret) , bound_vars)
74
+ && let sig = cx. tcx . liberate_late_bound_regions (
75
+ item_did,
76
+ cx. tcx . fn_sig ( item_did) . skip_binder ( )
84
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 ( )
85
81
// Order is important here, we need to check that the `fn iter` return type actually implements `IntoIterator`
86
82
// *before* normalizing `<_ as IntoIterator>::Item` (otherwise make_normalized_projection ICEs)
87
- && implements_trait ( cx, ret_middle_ty , into_iter_did, & [ ] )
88
- && let Some ( ret_iter_ty ) = make_normalized_projection (
83
+ && implements_trait ( cx, ret_ty , into_iter_did, & [ ] )
84
+ && let Some ( iter_ty ) = make_normalized_projection (
89
85
cx. tcx ,
90
86
cx. param_env ,
91
87
into_iter_did,
92
88
sym ! ( Item ) ,
93
- [ ret_middle_ty ]
89
+ [ ret_ty ] ,
94
90
)
95
91
// Only lint if the `IntoIterator` impl doesn't actually exist
96
92
&& !implements_trait ( cx, ref_ty, into_iter_did, & [ ] )
97
93
{
98
- let ( self_ty_snippet, into_iter_snippet) = with_forced_trimmed_paths ! ( (
99
- format!( "{borrow_prefix}{}" , cx. tcx. def_path_str( ty_did) ) ,
100
- cx. tcx. def_path_str( into_iter_did)
101
- ) ) ;
94
+ let self_ty_snippet = format ! ( "{borrow_prefix}{}" , snippet( cx, imp. self_ty. span, ".." ) ) ;
102
95
103
96
span_lint_and_then (
104
97
cx,
@@ -116,16 +109,15 @@ fn check_for_mutability(cx: &LateContext<'_>, item: &rustc_hir::ImplItem<'_>, ex
116
109
117
110
let sugg = format ! (
118
111
"
119
- impl {into_iter_snippet} for {self_ty_snippet} {{
120
- type IntoIter = {ret_middle_ty };
121
- type Iter = {ret_iter_ty };
112
+ impl IntoIterator for {self_ty_snippet} {{
113
+ type IntoIter = {ret_ty };
114
+ type Iter = {iter_ty };
122
115
fn into_iter() -> Self::IntoIter {{
123
116
self.iter()
124
117
}}
125
118
}}
126
119
"
127
120
) ;
128
-
129
121
diag. span_suggestion_verbose (
130
122
span_behind_impl,
131
123
format ! ( "consider implementing `IntoIterator` for `{self_ty_snippet}`" ) ,
0 commit comments