Skip to content

Commit 7331cc0

Browse files
committed
Only complain about default Iterator::last()
1 parent 27acfd8 commit 7331cc0

File tree

3 files changed

+52
-1
lines changed

3 files changed

+52
-1
lines changed

clippy_lints/src/methods/double_ended_iterator_last.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,29 @@ use clippy_utils::ty::implements_trait;
44
use rustc_errors::Applicability;
55
use rustc_hir::Expr;
66
use rustc_lint::LateContext;
7+
use rustc_middle::ty::Instance;
78
use rustc_span::{Span, sym};
89

910
use super::DOUBLE_ENDED_ITERATOR_LAST;
1011

1112
pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, self_expr: &'_ Expr<'_>, call_span: Span) {
13+
let typeck = cx.typeck_results();
14+
15+
// if the "last" method is that of Iterator
1216
if is_trait_method(cx, expr, sym::Iterator)
17+
// if self implements DoubleEndedIterator
1318
&& let Some(deiter_id) = cx.tcx.get_diagnostic_item(sym::DoubleEndedIterator)
14-
&& implements_trait(cx, cx.typeck_results().expr_ty(self_expr).peel_refs(), deiter_id, &[])
19+
&& let self_type = cx.typeck_results().expr_ty(self_expr)
20+
&& implements_trait(cx, self_type.peel_refs(), deiter_id, &[])
21+
// resolve the method definition
22+
&& let id = typeck.type_dependent_def_id(expr.hir_id).unwrap()
23+
&& let args = typeck.node_args(expr.hir_id)
24+
&& let Ok(Some(fn_def)) = Instance::try_resolve(cx.tcx, cx.typing_env(), id, args)
25+
// find the provided definition of Iterator::last
26+
&& let Some(item) = cx.tcx.get_diagnostic_item(sym::Iterator)
27+
&& let Some(last_def) = cx.tcx.provided_trait_methods(item).find(|m| m.name == sym!(last))
28+
// if the resolved method is the same as the provided definition
29+
&& fn_def.def_id() == last_def.def_id
1530
{
1631
span_lint_and_sugg(
1732
cx,

tests/ui/double_ended_iterator_last.fixed

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,22 @@ fn main() {
3232
}
3333
}
3434
let _ = SimpleIterator.last();
35+
36+
// Should not apply to custom implementations of last()
37+
struct CustomLast;
38+
impl Iterator for CustomLast {
39+
type Item = ();
40+
fn next(&mut self) -> Option<Self::Item> {
41+
Some(())
42+
}
43+
fn last(self) -> Option<Self::Item> {
44+
Some(())
45+
}
46+
}
47+
impl DoubleEndedIterator for CustomLast {
48+
fn next_back(&mut self) -> Option<Self::Item> {
49+
Some(())
50+
}
51+
}
52+
let _ = CustomLast.last();
3553
}

tests/ui/double_ended_iterator_last.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,22 @@ fn main() {
3232
}
3333
}
3434
let _ = SimpleIterator.last();
35+
36+
// Should not apply to custom implementations of last()
37+
struct CustomLast;
38+
impl Iterator for CustomLast {
39+
type Item = ();
40+
fn next(&mut self) -> Option<Self::Item> {
41+
Some(())
42+
}
43+
fn last(self) -> Option<Self::Item> {
44+
Some(())
45+
}
46+
}
47+
impl DoubleEndedIterator for CustomLast {
48+
fn next_back(&mut self) -> Option<Self::Item> {
49+
Some(())
50+
}
51+
}
52+
let _ = CustomLast.last();
3553
}

0 commit comments

Comments
 (0)