1- use clippy_utils:: diagnostics:: { multispan_sugg , span_lint_hir_and_then} ;
1+ use clippy_utils:: diagnostics:: { multispan_sugg_with_applicability , span_lint_hir_and_then} ;
22use clippy_utils:: paths:: { CORE_ITER_ENUMERATE_METHOD , CORE_ITER_ENUMERATE_STRUCT } ;
3- use clippy_utils:: source:: snippet;
3+ use clippy_utils:: source:: { snippet, snippet_opt } ;
44use clippy_utils:: { expr_or_init, is_trait_method, match_def_path, pat_is_wild} ;
5- use rustc_hir:: { Expr , ExprKind , PatKind } ;
5+ use rustc_errors:: Applicability ;
6+ use rustc_hir:: { Expr , ExprKind , FnDecl , PatKind , TyKind } ;
67use rustc_lint:: LateContext ;
78use rustc_middle:: ty:: AdtDef ;
8- use rustc_span:: sym;
9+ use rustc_span:: { sym, Span } ;
910
1011use crate :: loops:: UNUSED_ENUMERATE_INDEX ;
1112
@@ -76,6 +77,18 @@ pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>,
7677 // Make sure the method call is `std::iter::Iterator::enumerate`.
7778 && match_def_path ( cx, enumerate_defid, & CORE_ITER_ENUMERATE_METHOD )
7879 {
80+ // Check if the tuple type was explicit. It may be the type system _needs_ the type of the element
81+ // that would be explicited in the closure.
82+ let new_closure_param = match find_elem_explicit_type_span ( closure. fn_decl ) {
83+ // We have an explicit type. Get its snippet, that of the binding name, and do `binding: ty`.
84+ // Fallback to `..` if we fail getting either snippet.
85+ Some ( ty_span) => snippet_opt ( cx, elem. span )
86+ . and_then ( |binding_name| snippet_opt ( cx, ty_span) . map ( |ty_name| format ! ( "{binding_name}: {ty_name}" ) ) )
87+ . unwrap_or_else ( || ".." . to_string ( ) ) ,
88+ // Otherwise, we have no explicit type. We can replace with the binding name of the element.
89+ None => snippet ( cx, elem. span , ".." ) . into_owned ( ) ,
90+ } ;
91+
7992 // Suggest removing the tuple from the closure and the preceding call to `enumerate`, whose span we
8093 // can get from the `MethodCall`.
8194 span_lint_hir_and_then (
@@ -85,11 +98,12 @@ pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>,
8598 enumerate_span,
8699 "you seem to use `.enumerate()` and immediately discard the index" ,
87100 |diag| {
88- multispan_sugg (
101+ multispan_sugg_with_applicability (
89102 diag,
90103 "remove the `.enumerate()` call" ,
104+ Applicability :: MachineApplicable ,
91105 vec ! [
92- ( closure_param. span, snippet ( cx , elem . span , ".." ) . into_owned ( ) ) ,
106+ ( closure_param. span, new_closure_param ) ,
93107 (
94108 enumerate_span. with_lo( enumerate_recv. span. source_callsite( ) . hi( ) ) ,
95109 String :: new( ) ,
@@ -100,3 +114,22 @@ pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>,
100114 ) ;
101115 }
102116}
117+
118+ /// Find the span of the explicit type of the element.
119+ ///
120+ /// # Returns
121+ /// If the tuple argument:
122+ /// * Has no explicit type, returns `None`
123+ /// * Has an explicit tuple type with an implicit element type (`(usize, _)`), returns `None`
124+ /// * Has an explicit tuple type with an explicit element type (`(_, i32)`), returns the span for
125+ /// the element type.
126+ fn find_elem_explicit_type_span ( fn_decl : & FnDecl < ' _ > ) -> Option < Span > {
127+ if let [ tuple_ty] = fn_decl. inputs
128+ && let TyKind :: Tup ( [ _idx_ty, elem_ty] ) = tuple_ty. kind
129+ && !matches ! ( elem_ty. kind, TyKind :: Err ( ..) | TyKind :: Infer )
130+ {
131+ Some ( elem_ty. span )
132+ } else {
133+ None
134+ }
135+ }
0 commit comments