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} ;
2
2
use 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 } ;
4
4
use 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 } ;
6
7
use rustc_lint:: LateContext ;
7
8
use rustc_middle:: ty:: AdtDef ;
8
- use rustc_span:: sym;
9
+ use rustc_span:: { sym, Span } ;
9
10
10
11
use crate :: loops:: UNUSED_ENUMERATE_INDEX ;
11
12
@@ -76,6 +77,18 @@ pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>,
76
77
// Make sure the method call is `std::iter::Iterator::enumerate`.
77
78
&& match_def_path ( cx, enumerate_defid, & CORE_ITER_ENUMERATE_METHOD )
78
79
{
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
+
79
92
// Suggest removing the tuple from the closure and the preceding call to `enumerate`, whose span we
80
93
// can get from the `MethodCall`.
81
94
span_lint_hir_and_then (
@@ -85,11 +98,12 @@ pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>,
85
98
enumerate_span,
86
99
"you seem to use `.enumerate()` and immediately discard the index" ,
87
100
|diag| {
88
- multispan_sugg (
101
+ multispan_sugg_with_applicability (
89
102
diag,
90
103
"remove the `.enumerate()` call" ,
104
+ Applicability :: MachineApplicable ,
91
105
vec ! [
92
- ( closure_param. span, snippet ( cx , elem . span , ".." ) . into_owned ( ) ) ,
106
+ ( closure_param. span, new_closure_param ) ,
93
107
(
94
108
enumerate_span. with_lo( enumerate_recv. span. source_callsite( ) . hi( ) ) ,
95
109
String :: new( ) ,
@@ -100,3 +114,22 @@ pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>,
100
114
) ;
101
115
}
102
116
}
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