Skip to content

Commit 2cc38a2

Browse files
committed
Lint iter_not_returning_iterator on the trait definition rather than the implementation
1 parent 92048f4 commit 2cc38a2

File tree

3 files changed

+60
-21
lines changed

3 files changed

+60
-21
lines changed

clippy_lints/src/iter_not_returning_iterator.rs

Lines changed: 41 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
use clippy_utils::{diagnostics::span_lint, return_ty, ty::implements_trait};
2-
use rustc_hir::{ImplItem, ImplItemKind};
1+
use clippy_utils::{diagnostics::span_lint, get_parent_node, ty::implements_trait};
2+
use rustc_hir::{def_id::LocalDefId, FnSig, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind};
33
use rustc_lint::{LateContext, LateLintPass};
44
use rustc_session::{declare_lint_pass, declare_tool_lint};
5-
use rustc_span::symbol::kw;
65
use rustc_span::symbol::sym;
76

87
declare_clippy_lint! {
@@ -41,25 +40,47 @@ declare_clippy_lint! {
4140
declare_lint_pass!(IterNotReturningIterator => [ITER_NOT_RETURNING_ITERATOR]);
4241

4342
impl LateLintPass<'_> for IterNotReturningIterator {
44-
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'tcx>) {
45-
let name = impl_item.ident.name.as_str();
46-
if_chain! {
47-
if let ImplItemKind::Fn(fn_sig, _) = &impl_item.kind;
48-
let ret_ty = return_ty(cx, impl_item.hir_id());
49-
if matches!(name, "iter" | "iter_mut");
50-
if let [param] = cx.tcx.fn_arg_names(impl_item.def_id);
51-
if param.name == kw::SelfLower;
52-
if let Some(iter_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator);
53-
if !implements_trait(cx, ret_ty, iter_trait_id, &[]);
43+
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
44+
let name = item.ident.name.as_str();
45+
if matches!(name, "iter" | "iter_mut") {
46+
if let TraitItemKind::Fn(fn_sig, _) = &item.kind {
47+
check_sig(cx, name, fn_sig, item.def_id);
48+
}
49+
}
50+
}
5451

55-
then {
56-
span_lint(
57-
cx,
58-
ITER_NOT_RETURNING_ITERATOR,
59-
fn_sig.span,
60-
&format!("this method is named `{}` but its return type does not implement `Iterator`", name),
61-
);
52+
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'tcx>) {
53+
let name = item.ident.name.as_str();
54+
if matches!(name, "iter" | "iter_mut")
55+
&& !matches!(
56+
get_parent_node(cx.tcx, item.hir_id()),
57+
Some(Node::Item(Item { kind: ItemKind::Impl(i), .. })) if i.of_trait.is_some()
58+
)
59+
{
60+
if let ImplItemKind::Fn(fn_sig, _) = &item.kind {
61+
check_sig(cx, name, fn_sig, item.def_id);
6262
}
6363
}
6464
}
6565
}
66+
67+
fn check_sig(cx: &LateContext<'_>, name: &str, sig: &FnSig<'_>, fn_id: LocalDefId) {
68+
if sig.decl.implicit_self.has_implicit_self() {
69+
let ret_ty = cx.tcx.fn_sig(fn_id).skip_binder().output();
70+
if cx
71+
.tcx
72+
.get_diagnostic_item(sym::Iterator)
73+
.map_or(false, |iter_id| !implements_trait(cx, ret_ty, iter_id, &[]))
74+
{
75+
span_lint(
76+
cx,
77+
ITER_NOT_RETURNING_ITERATOR,
78+
sig.span,
79+
&format!(
80+
"this method is named `{}` but its return type does not implement `Iterator`",
81+
name
82+
),
83+
);
84+
}
85+
}
86+
}

tests/ui/iter_not_returning_iterator.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,16 @@ impl Iterator for Counter {
4444
}
4545
}
4646

47+
trait Iter {
48+
type I;
49+
fn iter(&self) -> Self::I;
50+
}
51+
52+
impl Iter for () {
53+
type I = core::slice::Iter<'static, ()>;
54+
fn iter(&self) -> Self::I {
55+
[].iter()
56+
}
57+
}
58+
4759
fn main() {}

tests/ui/iter_not_returning_iterator.stderr

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,11 @@ error: this method is named `iter_mut` but its return type does not implement `I
1212
LL | fn iter_mut(&self) -> Counter2 {
1313
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1414

15-
error: aborting due to 2 previous errors
15+
error: this method is named `iter` but its return type does not implement `Iterator`
16+
--> $DIR/iter_not_returning_iterator.rs:49:5
17+
|
18+
LL | fn iter(&self) -> Self::I;
19+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
20+
21+
error: aborting due to 3 previous errors
1622

0 commit comments

Comments
 (0)