1 use clippy_utils::{diagnostics::span_lint, return_ty, ty::implements_trait};
2 use rustc_hir::{ImplItem, ImplItemKind};
3 use rustc_lint::{LateContext, LateLintPass};
4 use rustc_session::{declare_lint_pass, declare_tool_lint};
5 use rustc_span::symbol::kw;
6 use rustc_span::symbol::sym;
10 /// Detects methods named `iter` or `iter_mut` that do not have a return type that implements `Iterator`.
12 /// ### Why is this bad?
13 /// Methods named `iter` or `iter_mut` conventionally return an `Iterator`.
17 /// // `String` does not implement `Iterator`
20 /// fn iter(&self) -> String {
27 /// use std::str::Chars;
30 /// fn iter(&self) -> Chars<'static> {
35 pub ITER_NOT_RETURNING_ITERATOR,
37 "methods named `iter` or `iter_mut` that do not return an `Iterator`"
40 declare_lint_pass!(IterNotReturningIterator => [ITER_NOT_RETURNING_ITERATOR]);
42 impl LateLintPass<'_> for IterNotReturningIterator {
43 fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'tcx>) {
44 let name: &str = &impl_item.ident.name.as_str();
46 if let ImplItemKind::Fn(fn_sig, _) = &impl_item.kind;
47 let ret_ty = return_ty(cx, impl_item.hir_id());
48 if matches!(name, "iter" | "iter_mut");
49 if let [param] = cx.tcx.fn_arg_names(impl_item.def_id);
50 if param.name == kw::SelfLower;
51 if let Some(iter_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator);
52 if !implements_trait(cx, ret_ty, iter_trait_id, &[]);
57 ITER_NOT_RETURNING_ITERATOR,
59 &format!("this method is named `{}` but its return type does not implement `Iterator`", name),