Skip to content

Commit 3c501e4

Browse files
committed
[iter_without_into_iter]: fix papercuts + only lint on pub types
1 parent 2b030eb commit 3c501e4

File tree

5 files changed

+345
-343
lines changed

5 files changed

+345
-343
lines changed

clippy_lints/src/iter_without_into_iter.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,12 @@ fn is_nameable_in_impl_trait(ty: &rustc_hir::Ty<'_>) -> bool {
104104
!matches!(ty.kind, TyKind::OpaqueDef(..))
105105
}
106106

107+
fn is_ty_exported(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
108+
ty.ty_adt_def()
109+
.and_then(|adt| adt.did().as_local())
110+
.is_some_and(|did| cx.effective_visibilities.is_exported(did))
111+
}
112+
107113
/// Returns the deref chain of a type, starting with the type itself.
108114
fn deref_chain<'cx, 'tcx>(cx: &'cx LateContext<'tcx>, ty: Ty<'tcx>) -> impl Iterator<Item = Ty<'tcx>> + 'cx {
109115
iter::successors(Some(ty), |&ty| {
@@ -154,6 +160,7 @@ impl LateLintPass<'_> for IterWithoutIntoIter {
154160
None
155161
}
156162
})
163+
&& is_ty_exported(cx, ty)
157164
{
158165
span_lint_and_then(
159166
cx,
@@ -226,6 +233,7 @@ impl {self_ty_without_ref} {{
226233
)
227234
// Only lint if the `IntoIterator` impl doesn't actually exist
228235
&& !implements_trait(cx, ref_ty, into_iter_did, &[])
236+
&& is_ty_exported(cx, ref_ty.peel_refs())
229237
{
230238
let self_ty_snippet = format!("{borrow_prefix}{}", snippet(cx, imp.self_ty.span, ".."));
231239

@@ -247,8 +255,8 @@ impl {self_ty_without_ref} {{
247255
"
248256
impl IntoIterator for {self_ty_snippet} {{
249257
type IntoIter = {ret_ty};
250-
type Iter = {iter_ty};
251-
fn into_iter() -> Self::IntoIter {{
258+
type Item = {iter_ty};
259+
fn into_iter(self) -> Self::IntoIter {{
252260
self.iter()
253261
}}
254262
}}

tests/ui/into_iter_without_iter.rs

Lines changed: 96 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -3,127 +3,117 @@
33

44
use std::iter::IntoIterator;
55

6-
fn main() {
7-
{
8-
struct S;
9-
10-
impl<'a> IntoIterator for &'a S {
11-
//~^ ERROR: `IntoIterator` implemented for a reference type without an `iter` method
12-
type IntoIter = std::slice::Iter<'a, u8>;
13-
type Item = &'a u8;
14-
fn into_iter(self) -> Self::IntoIter {
15-
todo!()
16-
}
17-
}
18-
impl<'a> IntoIterator for &'a mut S {
19-
//~^ ERROR: `IntoIterator` implemented for a reference type without an `iter_mut` method
20-
type IntoIter = std::slice::IterMut<'a, u8>;
21-
type Item = &'a mut u8;
22-
fn into_iter(self) -> Self::IntoIter {
23-
todo!()
24-
}
25-
}
6+
pub struct S1;
7+
impl<'a> IntoIterator for &'a S1 {
8+
//~^ ERROR: `IntoIterator` implemented for a reference type without an `iter` method
9+
type IntoIter = std::slice::Iter<'a, u8>;
10+
type Item = &'a u8;
11+
fn into_iter(self) -> Self::IntoIter {
12+
todo!()
2613
}
27-
{
28-
struct S<T>(T);
29-
impl<'a, T> IntoIterator for &'a S<T> {
30-
//~^ ERROR: `IntoIterator` implemented for a reference type without an `iter` method
31-
type IntoIter = std::slice::Iter<'a, T>;
32-
type Item = &'a T;
33-
fn into_iter(self) -> Self::IntoIter {
34-
todo!()
35-
}
36-
}
37-
impl<'a, T> IntoIterator for &'a mut S<T> {
38-
//~^ ERROR: `IntoIterator` implemented for a reference type without an `iter_mut` method
39-
type IntoIter = std::slice::IterMut<'a, T>;
40-
type Item = &'a mut T;
41-
fn into_iter(self) -> Self::IntoIter {
42-
todo!()
43-
}
44-
}
14+
}
15+
impl<'a> IntoIterator for &'a mut S1 {
16+
//~^ ERROR: `IntoIterator` implemented for a reference type without an `iter_mut` method
17+
type IntoIter = std::slice::IterMut<'a, u8>;
18+
type Item = &'a mut u8;
19+
fn into_iter(self) -> Self::IntoIter {
20+
todo!()
4521
}
46-
{
47-
// Both iter and iter_mut methods exist, don't lint
48-
struct S<'a, T>(&'a T);
49-
50-
impl<'a, T> S<'a, T> {
51-
fn iter(&self) -> std::slice::Iter<'a, T> {
52-
todo!()
53-
}
54-
fn iter_mut(&mut self) -> std::slice::IterMut<'a, T> {
55-
todo!()
56-
}
57-
}
22+
}
5823

59-
impl<'a, T> IntoIterator for &S<'a, T> {
60-
type IntoIter = std::slice::Iter<'a, T>;
61-
type Item = &'a T;
62-
fn into_iter(self) -> Self::IntoIter {
63-
todo!()
64-
}
65-
}
24+
pub struct S2<T>(T);
25+
impl<'a, T> IntoIterator for &'a S2<T> {
26+
//~^ ERROR: `IntoIterator` implemented for a reference type without an `iter` method
27+
type IntoIter = std::slice::Iter<'a, T>;
28+
type Item = &'a T;
29+
fn into_iter(self) -> Self::IntoIter {
30+
todo!()
31+
}
32+
}
33+
impl<'a, T> IntoIterator for &'a mut S2<T> {
34+
//~^ ERROR: `IntoIterator` implemented for a reference type without an `iter_mut` method
35+
type IntoIter = std::slice::IterMut<'a, T>;
36+
type Item = &'a mut T;
37+
fn into_iter(self) -> Self::IntoIter {
38+
todo!()
39+
}
40+
}
6641

67-
impl<'a, T> IntoIterator for &mut S<'a, T> {
68-
type IntoIter = std::slice::IterMut<'a, T>;
69-
type Item = &'a mut T;
70-
fn into_iter(self) -> Self::IntoIter {
71-
todo!()
72-
}
73-
}
42+
// Both iter and iter_mut methods exist, don't lint
43+
pub struct S3<'a, T>(&'a T);
44+
impl<'a, T> S3<'a, T> {
45+
fn iter(&self) -> std::slice::Iter<'a, T> {
46+
todo!()
47+
}
48+
fn iter_mut(&mut self) -> std::slice::IterMut<'a, T> {
49+
todo!()
50+
}
51+
}
52+
impl<'a, T> IntoIterator for &S3<'a, T> {
53+
type IntoIter = std::slice::Iter<'a, T>;
54+
type Item = &'a T;
55+
fn into_iter(self) -> Self::IntoIter {
56+
todo!()
57+
}
58+
}
59+
impl<'a, T> IntoIterator for &mut S3<'a, T> {
60+
type IntoIter = std::slice::IterMut<'a, T>;
61+
type Item = &'a mut T;
62+
fn into_iter(self) -> Self::IntoIter {
63+
todo!()
7464
}
75-
{
76-
// Only `iter` exists, no `iter_mut`
77-
struct S<'a, T>(&'a T);
65+
}
7866

79-
impl<'a, T> S<'a, T> {
80-
fn iter(&self) -> std::slice::Iter<'a, T> {
81-
todo!()
82-
}
83-
}
67+
// Only `iter` exists, no `iter_mut`
68+
pub struct S4<'a, T>(&'a T);
8469

85-
impl<'a, T> IntoIterator for &S<'a, T> {
86-
type IntoIter = std::slice::Iter<'a, T>;
87-
type Item = &'a T;
88-
fn into_iter(self) -> Self::IntoIter {
89-
todo!()
90-
}
91-
}
70+
impl<'a, T> S4<'a, T> {
71+
fn iter(&self) -> std::slice::Iter<'a, T> {
72+
todo!()
73+
}
74+
}
9275

93-
impl<'a, T> IntoIterator for &mut S<'a, T> {
94-
//~^ ERROR: `IntoIterator` implemented for a reference type without an `iter_mut` method
95-
type IntoIter = std::slice::IterMut<'a, T>;
96-
type Item = &'a mut T;
97-
fn into_iter(self) -> Self::IntoIter {
98-
todo!()
99-
}
100-
}
76+
impl<'a, T> IntoIterator for &S4<'a, T> {
77+
type IntoIter = std::slice::Iter<'a, T>;
78+
type Item = &'a T;
79+
fn into_iter(self) -> Self::IntoIter {
80+
todo!()
10181
}
102-
{
103-
// `iter` exists, but `IntoIterator` is implemented for an alias. inherent_impls doesn't "normalize"
104-
// aliases so that `inherent_impls(Alias)` where `type Alias = S` returns nothing, so this can lead
105-
// to fun FPs. Make sure it doesn't happen here (we're using type_of, which should skip the alias).
106-
struct S;
82+
}
10783

108-
impl S {
109-
fn iter(&self) -> std::slice::Iter<'static, u8> {
110-
todo!()
111-
}
112-
}
84+
impl<'a, T> IntoIterator for &mut S4<'a, T> {
85+
//~^ ERROR: `IntoIterator` implemented for a reference type without an `iter_mut` method
86+
type IntoIter = std::slice::IterMut<'a, T>;
87+
type Item = &'a mut T;
88+
fn into_iter(self) -> Self::IntoIter {
89+
todo!()
90+
}
91+
}
11392

114-
type Alias = S;
93+
// `iter` exists, but `IntoIterator` is implemented for an alias. inherent_impls doesn't "normalize"
94+
// aliases so that `inherent_impls(Alias)` where `type Alias = S` returns nothing, so this can lead
95+
// to fun FPs. Make sure it doesn't happen here (we're using type_of, which should skip the alias).
96+
pub struct S5;
11597

116-
impl IntoIterator for &Alias {
117-
type IntoIter = std::slice::Iter<'static, u8>;
118-
type Item = &'static u8;
119-
fn into_iter(self) -> Self::IntoIter {
120-
todo!()
121-
}
122-
}
98+
impl S5 {
99+
fn iter(&self) -> std::slice::Iter<'static, u8> {
100+
todo!()
101+
}
102+
}
103+
104+
pub type Alias = S5;
105+
106+
impl IntoIterator for &Alias {
107+
type IntoIter = std::slice::Iter<'static, u8>;
108+
type Item = &'static u8;
109+
fn into_iter(self) -> Self::IntoIter {
110+
todo!()
123111
}
124112
}
125113

126-
fn issue11635() {
114+
fn main() {}
115+
116+
pub mod issue11635 {
127117
// A little more involved than the original repro in the issue, but this tests that it correctly
128118
// works for more than one deref step
129119

0 commit comments

Comments
 (0)