about summary refs log tree commit diff
diff options
context:
space:
mode:
authorCentri3 <114838443+Centri3@users.noreply.github.com>2023-06-20 00:39:22 -0500
committerCatherine <114838443+Centri3@users.noreply.github.com>2023-06-21 15:58:52 -0500
commit242807a9c1cb24ef5e0d665fa9ac696d2a095c71 (patch)
tree161aba99d90ca36c1f2840e1305fd3d75bdca66a
parent89294e1756309da6e5ea0056222c19a09898af2c (diff)
downloadrust-242807a9c1cb24ef5e0d665fa9ac696d2a095c71.tar.gz
rust-242807a9c1cb24ef5e0d665fa9ac696d2a095c71.zip
Don't lint `iter_nth_zero` in `next`
-rw-r--r--clippy_lints/src/methods/iter_nth.rs4
-rw-r--r--clippy_lints/src/methods/iter_nth_zero.rs35
-rw-r--r--tests/ui/iter_nth.stderr8
-rw-r--r--tests/ui/iter_nth_zero.fixed15
-rw-r--r--tests/ui/iter_nth_zero.rs15
5 files changed, 54 insertions, 23 deletions
diff --git a/clippy_lints/src/methods/iter_nth.rs b/clippy_lints/src/methods/iter_nth.rs
index ceee12784cb..12104310405 100644
--- a/clippy_lints/src/methods/iter_nth.rs
+++ b/clippy_lints/src/methods/iter_nth.rs
@@ -20,9 +20,9 @@ pub(super) fn check<'tcx>(
     let caller_type = if derefs_to_slice(cx, iter_recv, cx.typeck_results().expr_ty(iter_recv)).is_some() {
         "slice"
     } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(iter_recv), sym::Vec) {
-        "Vec"
+        "`Vec`"
     } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(iter_recv), sym::VecDeque) {
-        "VecDeque"
+        "`VecDeque`"
     } else {
         iter_nth_zero::check(cx, expr, nth_recv, nth_arg);
         return; // caller is not a type that we want to lint
diff --git a/clippy_lints/src/methods/iter_nth_zero.rs b/clippy_lints/src/methods/iter_nth_zero.rs
index d1609eebfdc..e1f950d5a4a 100644
--- a/clippy_lints/src/methods/iter_nth_zero.rs
+++ b/clippy_lints/src/methods/iter_nth_zero.rs
@@ -1,8 +1,8 @@
 use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::is_trait_method;
 use clippy_utils::source::snippet_with_applicability;
-use if_chain::if_chain;
+use clippy_utils::{is_lang_item_or_ctor, is_trait_method};
+use hir::{LangItem, OwnerNode};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
@@ -11,20 +11,21 @@ use rustc_span::sym;
 use super::ITER_NTH_ZERO;
 
 pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) {
-    if_chain! {
-        if is_trait_method(cx, expr, sym::Iterator);
-        if let Some(Constant::Int(0)) = constant(cx, cx.typeck_results(), arg);
-        then {
-            let mut applicability = Applicability::MachineApplicable;
-            span_lint_and_sugg(
-                cx,
-                ITER_NTH_ZERO,
-                expr.span,
-                "called `.nth(0)` on a `std::iter::Iterator`, when `.next()` is equivalent",
-                "try calling `.next()` instead of `.nth(0)`",
-                format!("{}.next()", snippet_with_applicability(cx, recv.span, "..", &mut applicability)),
-                applicability,
-            );
-        }
+    if let OwnerNode::Item(item) = cx.tcx.hir().owner(cx.tcx.hir().get_parent_item(expr.hir_id))
+        && let def_id = item.owner_id.to_def_id()
+        && is_trait_method(cx, expr, sym::Iterator)
+        && let Some(Constant::Int(0)) = constant(cx, cx.typeck_results(), arg)
+        && !is_lang_item_or_ctor(cx, def_id, LangItem::IteratorNext)
+    {
+        let mut app = Applicability::MachineApplicable;
+        span_lint_and_sugg(
+            cx,
+            ITER_NTH_ZERO,
+            expr.span,
+            "called `.nth(0)` on a `std::iter::Iterator`, when `.next()` is equivalent",
+            "try calling `.next()` instead of `.nth(0)`",
+            format!("{}.next()", snippet_with_applicability(cx, recv.span, "..", &mut app)),
+            app,
+        );
     }
 }
diff --git a/tests/ui/iter_nth.stderr b/tests/ui/iter_nth.stderr
index 975a5a62ad5..24be814548a 100644
--- a/tests/ui/iter_nth.stderr
+++ b/tests/ui/iter_nth.stderr
@@ -1,4 +1,4 @@
-error: called `.iter().nth()` on a Vec
+error: called `.iter().nth()` on a `Vec`
   --> $DIR/iter_nth.rs:34:23
    |
 LL |         let bad_vec = some_vec.iter().nth(3);
@@ -23,7 +23,7 @@ LL |         let bad_boxed_slice = boxed_slice.iter().nth(3);
    |
    = help: calling `.get()` is both faster and more readable
 
-error: called `.iter().nth()` on a VecDeque
+error: called `.iter().nth()` on a `VecDeque`
   --> $DIR/iter_nth.rs:37:29
    |
 LL |         let bad_vec_deque = some_vec_deque.iter().nth(3);
@@ -31,7 +31,7 @@ LL |         let bad_vec_deque = some_vec_deque.iter().nth(3);
    |
    = help: calling `.get()` is both faster and more readable
 
-error: called `.iter_mut().nth()` on a Vec
+error: called `.iter_mut().nth()` on a `Vec`
   --> $DIR/iter_nth.rs:42:23
    |
 LL |         let bad_vec = some_vec.iter_mut().nth(3);
@@ -47,7 +47,7 @@ LL |         let bad_slice = &some_vec[..].iter_mut().nth(3);
    |
    = help: calling `.get_mut()` is both faster and more readable
 
-error: called `.iter_mut().nth()` on a VecDeque
+error: called `.iter_mut().nth()` on a `VecDeque`
   --> $DIR/iter_nth.rs:48:29
    |
 LL |         let bad_vec_deque = some_vec_deque.iter_mut().nth(3);
diff --git a/tests/ui/iter_nth_zero.fixed b/tests/ui/iter_nth_zero.fixed
index 587b0d1d366..91f4a7ba0d2 100644
--- a/tests/ui/iter_nth_zero.fixed
+++ b/tests/ui/iter_nth_zero.fixed
@@ -29,3 +29,18 @@ fn main() {
     let mut iter2 = s3.iter();
     let _unwrapped = iter2.next().unwrap();
 }
+
+struct Issue9820;
+
+impl Iterator for Issue9820 {
+    type Item = ();
+
+    fn nth(&mut self, _n: usize) -> Option<Self::Item> {
+        todo!()
+    }
+
+    // Don't lint in implementations of `next`, as calling `next` in `next` is incorrect
+    fn next(&mut self) -> Option<Self::Item> {
+        self.nth(0)
+    }
+}
diff --git a/tests/ui/iter_nth_zero.rs b/tests/ui/iter_nth_zero.rs
index 93b576ec56f..160a895bb7b 100644
--- a/tests/ui/iter_nth_zero.rs
+++ b/tests/ui/iter_nth_zero.rs
@@ -29,3 +29,18 @@ fn main() {
     let mut iter2 = s3.iter();
     let _unwrapped = iter2.nth(0).unwrap();
 }
+
+struct Issue9820;
+
+impl Iterator for Issue9820 {
+    type Item = ();
+
+    fn nth(&mut self, _n: usize) -> Option<Self::Item> {
+        todo!()
+    }
+
+    // Don't lint in implementations of `next`, as calling `next` in `next` is incorrect
+    fn next(&mut self) -> Option<Self::Item> {
+        self.nth(0)
+    }
+}