Only complain about default Iterator::last()

This commit is contained in:
Quentin Santos 2025-01-01 22:14:17 +01:00
parent 27acfd8a5b
commit 7331cc0f81
3 changed files with 52 additions and 1 deletions

View file

@ -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,

View file

@ -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();
}

View file

@ -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();
}