1
1
use clippy_utils:: diagnostics:: span_lint_and_sugg;
2
2
use clippy_utils:: source:: snippet;
3
- use clippy_utils:: ty:: { get_iterator_item_ty, implements_trait, is_copy} ;
3
+ use clippy_utils:: ty:: { get_iterator_item_ty, is_copy} ;
4
+ use itertools:: Itertools ;
4
5
use rustc_errors:: Applicability ;
5
6
use rustc_hir as hir;
6
7
use rustc_lint:: LateContext ;
7
8
use rustc_middle:: ty;
8
- use rustc_span :: sym ;
9
+ use std :: ops :: Not ;
9
10
10
11
use super :: ITER_OVEREAGER_CLONED ;
11
12
use crate :: redundant_clone:: REDUNDANT_CLONE ;
@@ -19,72 +20,46 @@ pub(super) fn check<'tcx>(
19
20
map_arg : & [ hir:: Expr < ' _ > ] ,
20
21
) {
21
22
let recv_ty = cx. typeck_results ( ) . expr_ty_adjusted ( recv) ;
23
+ // Check if it's iterator and get type associated with `Item`.
22
24
let inner_ty = match get_iterator_item_ty ( cx, recv_ty) {
23
25
Some ( ty) => ty,
24
26
_ => return ,
25
27
} ;
26
28
27
29
match inner_ty. kind ( ) {
28
- ty:: Ref ( _, ty, _) if is_copy ( cx, ty) => return ,
29
- _ => { } ,
30
+ ty:: Ref ( _, ty, _) if ! is_copy ( cx, ty) => { } ,
31
+ _ => return ,
30
32
} ;
31
33
32
- // lint if callee is an Iterator
33
- let recv_impls_iterator = cx. tcx . get_diagnostic_item ( sym:: Iterator ) . map_or ( false , |id| {
34
- implements_trait ( cx, cx. typeck_results ( ) . expr_ty ( recv) , id, & [ ] )
35
- } ) ;
36
- if recv_impls_iterator {
37
- let ( lint, msg) = match name {
38
- "count" => (
39
- REDUNDANT_CLONE ,
40
- format ! (
41
- "called `cloned().{}()` on an `Iterator`. It may be more efficient to call\
42
- `.{}()` instead",
43
- name, name
44
- ) ,
45
- ) ,
46
- _ if map_arg. is_empty ( ) => (
47
- ITER_OVEREAGER_CLONED ,
48
- format ! (
49
- "called `cloned().{}()` on an `Iterator`. It may be more efficient to call\
50
- `.{}().cloned()` instead",
51
- name, name
52
- ) ,
53
- ) ,
54
- _ => (
55
- ITER_OVEREAGER_CLONED ,
56
- format ! (
57
- "called `cloned().{}(...)` on an `Iterator`. It may be more efficient to call\
58
- `.{}(...).cloned()` instead",
59
- name, name
60
- ) ,
61
- ) ,
62
- } ;
34
+ let ( lint, msg, preserve_clopned) = match name {
35
+ "count" => ( REDUNDANT_CLONE , false ) ,
36
+ _ => ( ITER_OVEREAGER_CLONED , true ) ,
37
+ } ;
38
+ let wildcard_params = map_arg. is_empty ( ) . not ( ) . then ( || "..." ) . unwrap_or_default ( ) ;
39
+ let msg = format ! (
40
+ "called `cloned().{}({})` on an `Iterator`. It may be more efficient to call\
41
+ `.{}({}){}` instead",
42
+ name,
43
+ wildcard_params,
44
+ name,
45
+ wildcard_params,
46
+ preserve_clopned. then( || ".cloned()" ) . unwrap_or_default( ) ,
47
+ ) ;
63
48
64
- let iter_snippet = snippet ( cx, recv. span , ".." ) ;
65
- span_lint_and_sugg (
66
- cx,
67
- lint,
68
- expr. span ,
69
- & msg,
70
- "try this" ,
71
- match name {
72
- "count" => {
73
- format ! ( "{}.{}()" , iter_snippet, name)
74
- } ,
75
- _ if map_arg. is_empty ( ) => {
76
- format ! ( "{}.{}().cloned()" , iter_snippet, name)
77
- } ,
78
- _ => {
79
- format ! (
80
- "{}.{}({}).cloned()" ,
81
- iter_snippet,
82
- name,
83
- snippet( cx, map_arg[ 0 ] . span, ".." )
84
- )
85
- } ,
86
- } ,
87
- Applicability :: MachineApplicable ,
88
- ) ;
89
- }
49
+ let iter_snippet = snippet ( cx, recv. span , ".." ) ;
50
+ span_lint_and_sugg (
51
+ cx,
52
+ lint,
53
+ expr. span ,
54
+ & msg,
55
+ "try this" ,
56
+ format ! (
57
+ "{}.{}({}){}" ,
58
+ iter_snippet,
59
+ name,
60
+ map_arg. iter( ) . map( |a| snippet( cx, a. span, ".." ) ) . join( ", " ) ,
61
+ preserve_clopned. then( || ".cloned()" ) . unwrap_or_default( ) ,
62
+ ) ,
63
+ Applicability :: MachineApplicable ,
64
+ ) ;
90
65
}
0 commit comments