Skip to content

Commit

Permalink
Auto merge of #8228 - Jarcho:iter_not_returning_iterator_8225, r=gira…
Browse files Browse the repository at this point in the history
…ffate

fix `iter_not_returning_iterator`

fixes #8225

changelog: Handle type projections in `iter_not_returning_iterator`
changelog: Don't lint `iter_not_returning_iterator` in trait implementations
changelog: Lint `iter_not_returning_iterator` in trait definitions
  • Loading branch information
bors committed Jan 10, 2022
2 parents 1816361 + d98339d commit b66dbe8
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 21 deletions.
65 changes: 45 additions & 20 deletions clippy_lints/src/iter_not_returning_iterator.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use clippy_utils::{diagnostics::span_lint, return_ty, ty::implements_trait};
use rustc_hir::{ImplItem, ImplItemKind};
use clippy_utils::{diagnostics::span_lint, get_parent_node, ty::implements_trait};
use rustc_hir::{def_id::LocalDefId, FnSig, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::symbol::kw;
use rustc_span::symbol::sym;

declare_clippy_lint! {
Expand Down Expand Up @@ -41,25 +40,51 @@ declare_clippy_lint! {
declare_lint_pass!(IterNotReturningIterator => [ITER_NOT_RETURNING_ITERATOR]);

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

then {
span_lint(
cx,
ITER_NOT_RETURNING_ITERATOR,
fn_sig.span,
&format!("this method is named `{}` but its return type does not implement `Iterator`", name),
);
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'tcx>) {
let name = item.ident.name.as_str();
if matches!(name, "iter" | "iter_mut")
&& !matches!(
get_parent_node(cx.tcx, item.hir_id()),
Some(Node::Item(Item { kind: ItemKind::Impl(i), .. })) if i.of_trait.is_some()
)
{
if let ImplItemKind::Fn(fn_sig, _) = &item.kind {
check_sig(cx, name, fn_sig, item.def_id);
}
}
}
}

fn check_sig(cx: &LateContext<'_>, name: &str, sig: &FnSig<'_>, fn_id: LocalDefId) {
if sig.decl.implicit_self.has_implicit_self() {
let ret_ty = cx.tcx.fn_sig(fn_id).skip_binder().output();
let ret_ty = cx
.tcx
.try_normalize_erasing_regions(cx.param_env, ret_ty)
.unwrap_or(ret_ty);
if cx
.tcx
.get_diagnostic_item(sym::Iterator)
.map_or(false, |iter_id| !implements_trait(cx, ret_ty, iter_id, &[]))
{
span_lint(
cx,
ITER_NOT_RETURNING_ITERATOR,
sig.span,
&format!(
"this method is named `{}` but its return type does not implement `Iterator`",
name
),
);
}
}
}
20 changes: 20 additions & 0 deletions tests/ui/iter_not_returning_iterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,24 @@ impl Iterator for Counter {
}
}

// Issue #8225
trait Iter {
type I;
fn iter(&self) -> Self::I;
}

impl Iter for () {
type I = core::slice::Iter<'static, ()>;
fn iter(&self) -> Self::I {
[].iter()
}
}

struct S;
impl S {
fn iter(&self) -> <() as Iter>::I {
().iter()
}
}

fn main() {}
8 changes: 7 additions & 1 deletion tests/ui/iter_not_returning_iterator.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,11 @@ error: this method is named `iter_mut` but its return type does not implement `I
LL | fn iter_mut(&self) -> Counter2 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 2 previous errors
error: this method is named `iter` but its return type does not implement `Iterator`
--> $DIR/iter_not_returning_iterator.rs:50:5
|
LL | fn iter(&self) -> Self::I;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 3 previous errors

0 comments on commit b66dbe8

Please sign in to comment.