@@ -4,14 +4,29 @@ use clippy_utils::ty::implements_trait;
4
4
use rustc_errors:: Applicability ;
5
5
use rustc_hir:: Expr ;
6
6
use rustc_lint:: LateContext ;
7
+ use rustc_middle:: ty:: Instance ;
7
8
use rustc_span:: { Span , sym} ;
8
9
9
10
use super :: DOUBLE_ENDED_ITERATOR_LAST ;
10
11
11
12
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
12
16
if is_trait_method ( cx, expr, sym:: Iterator )
17
+ // if self implements DoubleEndedIterator
13
18
&& 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
15
30
{
16
31
span_lint_and_sugg (
17
32
cx,
0 commit comments