about summary refs log tree commit diff
diff options
context:
space:
mode:
authorQuentin Santos <qsantos@qsantos.fr>2025-01-01 22:14:17 +0100
committerQuentin Santos <qsantos@qsantos.fr>2025-01-01 22:16:07 +0100
commit7331cc0f81d97fbc4f4eb47890cb10fe7c275696 (patch)
tree11cc0dfa872775d78cef16f1990432e46f7c6e76
parent27acfd8a5b9dd1eb91e044e07201b4a9044a2bbd (diff)
downloadrust-7331cc0f81d97fbc4f4eb47890cb10fe7c275696.tar.gz
rust-7331cc0f81d97fbc4f4eb47890cb10fe7c275696.zip
Only complain about default Iterator::last()
-rw-r--r--clippy_lints/src/methods/double_ended_iterator_last.rs17
-rw-r--r--tests/ui/double_ended_iterator_last.fixed18
-rw-r--r--tests/ui/double_ended_iterator_last.rs18
3 files changed, 52 insertions, 1 deletions
diff --git a/clippy_lints/src/methods/double_ended_iterator_last.rs b/clippy_lints/src/methods/double_ended_iterator_last.rs
index dec59b1c34e..118ab7cd93b 100644
--- a/clippy_lints/src/methods/double_ended_iterator_last.rs
+++ b/clippy_lints/src/methods/double_ended_iterator_last.rs
@@ -4,14 +4,29 @@ use clippy_utils::ty::implements_trait;
 use rustc_errors::Applicability;
 use rustc_hir::Expr;
 use rustc_lint::LateContext;
+use rustc_middle::ty::Instance;
 use rustc_span::{Span, sym};
 
 use super::DOUBLE_ENDED_ITERATOR_LAST;
 
 pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, self_expr: &'_ Expr<'_>, call_span: Span) {
+    let typeck = cx.typeck_results();
+
+    // if the "last" method is that of Iterator
     if is_trait_method(cx, expr, sym::Iterator)
+        // if self implements DoubleEndedIterator
         && let Some(deiter_id) = cx.tcx.get_diagnostic_item(sym::DoubleEndedIterator)
-        && implements_trait(cx, cx.typeck_results().expr_ty(self_expr).peel_refs(), deiter_id, &[])
+        && let self_type = cx.typeck_results().expr_ty(self_expr)
+        && implements_trait(cx, self_type.peel_refs(), deiter_id, &[])
+        // resolve the method definition
+        && let id = typeck.type_dependent_def_id(expr.hir_id).unwrap()
+        && let args = typeck.node_args(expr.hir_id)
+        && let Ok(Some(fn_def)) = Instance::try_resolve(cx.tcx, cx.typing_env(), id, args)
+        // find the provided definition of Iterator::last
+        && let Some(item) = cx.tcx.get_diagnostic_item(sym::Iterator)
+        && let Some(last_def) = cx.tcx.provided_trait_methods(item).find(|m| m.name == sym!(last))
+        // if the resolved method is the same as the provided definition
+        && fn_def.def_id() == last_def.def_id
     {
         span_lint_and_sugg(
             cx,
diff --git a/tests/ui/double_ended_iterator_last.fixed b/tests/ui/double_ended_iterator_last.fixed
index cfafd104576..06c48e33753 100644
--- a/tests/ui/double_ended_iterator_last.fixed
+++ b/tests/ui/double_ended_iterator_last.fixed
@@ -32,4 +32,22 @@ fn main() {
         }
     }
     let _ = SimpleIterator.last();
+
+    // Should not apply to custom implementations of last()
+    struct CustomLast;
+    impl Iterator for CustomLast {
+        type Item = ();
+        fn next(&mut self) -> Option<Self::Item> {
+            Some(())
+        }
+        fn last(self) -> Option<Self::Item> {
+            Some(())
+        }
+    }
+    impl DoubleEndedIterator for CustomLast {
+        fn next_back(&mut self) -> Option<Self::Item> {
+            Some(())
+        }
+    }
+    let _ = CustomLast.last();
 }
diff --git a/tests/ui/double_ended_iterator_last.rs b/tests/ui/double_ended_iterator_last.rs
index ae80fb64838..9c13b496d11 100644
--- a/tests/ui/double_ended_iterator_last.rs
+++ b/tests/ui/double_ended_iterator_last.rs
@@ -32,4 +32,22 @@ fn main() {
         }
     }
     let _ = SimpleIterator.last();
+
+    // Should not apply to custom implementations of last()
+    struct CustomLast;
+    impl Iterator for CustomLast {
+        type Item = ();
+        fn next(&mut self) -> Option<Self::Item> {
+            Some(())
+        }
+        fn last(self) -> Option<Self::Item> {
+            Some(())
+        }
+    }
+    impl DoubleEndedIterator for CustomLast {
+        fn next_back(&mut self) -> Option<Self::Item> {
+            Some(())
+        }
+    }
+    let _ = CustomLast.last();
 }