]> git.lizzy.rs Git - rust.git/blobdiff - clippy_lints/src/iter_not_returning_iterator.rs
modify code
[rust.git] / clippy_lints / src / iter_not_returning_iterator.rs
index 6c779348ca28a4f5e6484392c033350f31188747..b56d87c5348c2996ace5bafdf1475582df5c2d98 100644 (file)
@@ -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! {
@@ -32,6 +31,7 @@
     ///    }
     /// }
     /// ```
+    #[clippy::version = "1.57.0"]
     pub ITER_NOT_RETURNING_ITERATOR,
     pedantic,
     "methods named `iter` or `iter_mut` that do not return an `Iterator`"
 
 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: &str = &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, &[]);
+impl<'tcx> LateLintPass<'tcx> for IterNotReturningIterator {
+    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.erase_late_bound_regions(cx.tcx.fn_sig(fn_id).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
+                ),
+            );
+        }
+    }
+}