@@ -9,6 +9,7 @@ use rustc_lint::{LateContext, LateLintPass};
9
9
use rustc_middle:: ty:: { self , Ty } ;
10
10
use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
11
11
use rustc_span:: { sym, Symbol } ;
12
+ use std:: iter;
12
13
13
14
declare_clippy_lint ! {
14
15
/// ### What it does
@@ -52,7 +53,8 @@ declare_clippy_lint! {
52
53
declare_clippy_lint ! {
53
54
/// ### What it does
54
55
/// This is the opposite of the `iter_without_into_iter` lint.
55
- /// It looks for `IntoIterator for (&|&mut) Type` implementations without an inherent `iter` or `iter_mut` method.
56
+ /// It looks for `IntoIterator for (&|&mut) Type` implementations without an inherent `iter` or `iter_mut` method
57
+ /// on the type or on any of the types in its `Deref` chain.
56
58
///
57
59
/// ### Why is this bad?
58
60
/// It's not bad, but having them is idiomatic and allows the type to be used in iterator chains
@@ -102,7 +104,20 @@ fn is_nameable_in_impl_trait(ty: &rustc_hir::Ty<'_>) -> bool {
102
104
!matches ! ( ty. kind, TyKind :: OpaqueDef ( ..) )
103
105
}
104
106
105
- fn type_has_inherent_method ( cx : & LateContext < ' _ > , ty : Ty < ' _ > , method_name : Symbol ) -> bool {
107
+ /// Returns the deref chain of a type, starting with the type itself.
108
+ fn deref_chain < ' cx , ' tcx > ( cx : & ' cx LateContext < ' tcx > , ty : Ty < ' tcx > ) -> impl Iterator < Item = Ty < ' tcx > > + ' cx {
109
+ iter:: successors ( Some ( ty) , |& ty| {
110
+ if let Some ( deref_did) = cx. tcx . lang_items ( ) . deref_trait ( )
111
+ && implements_trait ( cx, ty, deref_did, & [ ] )
112
+ {
113
+ make_normalized_projection ( cx. tcx , cx. param_env , deref_did, sym:: Target , [ ty] )
114
+ } else {
115
+ None
116
+ }
117
+ } )
118
+ }
119
+
120
+ fn adt_has_inherent_method ( cx : & LateContext < ' _ > , ty : Ty < ' _ > , method_name : Symbol ) -> bool {
106
121
if let Some ( ty_did) = ty. ty_adt_def ( ) . map ( ty:: AdtDef :: did) {
107
122
cx. tcx . inherent_impls ( ty_did) . iter ( ) . any ( |& did| {
108
123
cx. tcx
@@ -127,7 +142,11 @@ impl LateLintPass<'_> for IterWithoutIntoIter {
127
142
Mutability :: Mut => sym:: iter_mut,
128
143
Mutability :: Not => sym:: iter,
129
144
}
130
- && !type_has_inherent_method ( cx, ty, expected_method_name)
145
+ && !deref_chain ( cx, ty)
146
+ . any ( |ty| {
147
+ // We can't check inherent impls for slices, but we know that they have an `iter(_mut)` method
148
+ ty. peel_refs ( ) . is_slice ( ) || adt_has_inherent_method ( cx, ty, expected_method_name)
149
+ } )
131
150
&& let Some ( iter_assoc_span) = imp. items . iter ( ) . find_map ( |item| {
132
151
if item. ident . name == sym ! ( IntoIter ) {
133
152
Some ( cx. tcx . hir ( ) . impl_item ( item. id ) . expect_type ( ) . span )
0 commit comments