From 7331cc0f81d97fbc4f4eb47890cb10fe7c275696 Mon Sep 17 00:00:00 2001 From: Quentin Santos Date: Wed, 1 Jan 2025 22:14:17 +0100 Subject: [PATCH] Only complain about default Iterator::last() --- .../src/methods/double_ended_iterator_last.rs | 17 ++++++++++++++++- tests/ui/double_ended_iterator_last.fixed | 18 ++++++++++++++++++ tests/ui/double_ended_iterator_last.rs | 18 ++++++++++++++++++ 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/methods/double_ended_iterator_last.rs b/clippy_lints/src/methods/double_ended_iterator_last.rs index dec59b1c34ef..118ab7cd93b0 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 cfafd1045764..06c48e337537 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 { + Some(()) + } + fn last(self) -> Option { + Some(()) + } + } + impl DoubleEndedIterator for CustomLast { + fn next_back(&mut self) -> Option { + Some(()) + } + } + let _ = CustomLast.last(); } diff --git a/tests/ui/double_ended_iterator_last.rs b/tests/ui/double_ended_iterator_last.rs index ae80fb648389..9c13b496d117 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 { + Some(()) + } + fn last(self) -> Option { + Some(()) + } + } + impl DoubleEndedIterator for CustomLast { + fn next_back(&mut self) -> Option { + Some(()) + } + } + let _ = CustomLast.last(); }