1
1
use clippy_utils:: diagnostics:: span_lint_and_sugg;
2
2
use clippy_utils:: source:: snippet_with_applicability;
3
3
use clippy_utils:: ty:: { is_copy, is_type_diagnostic_item} ;
4
- use clippy_utils:: { is_trait_method, peel_blocks} ;
4
+ use clippy_utils:: { is_trait_method, meets_msrv , msrvs , peel_blocks} ;
5
5
use if_chain:: if_chain;
6
6
use rustc_errors:: Applicability ;
7
7
use rustc_hir as hir;
8
- use rustc_lint:: { LateContext , LateLintPass } ;
8
+ use rustc_lint:: { LateContext , LateLintPass , LintContext } ;
9
9
use rustc_middle:: mir:: Mutability ;
10
10
use rustc_middle:: ty;
11
11
use rustc_middle:: ty:: adjustment:: Adjust ;
12
- use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
12
+ use rustc_semver:: RustcVersion ;
13
+ use rustc_session:: { declare_tool_lint, impl_lint_pass} ;
13
14
use rustc_span:: symbol:: Ident ;
14
15
use rustc_span:: { sym, Span } ;
15
16
@@ -42,7 +43,17 @@ declare_clippy_lint! {
42
43
"using `iterator.map(|x| x.clone())`, or dereferencing closures for `Copy` types"
43
44
}
44
45
45
- declare_lint_pass ! ( MapClone => [ MAP_CLONE ] ) ;
46
+ pub struct MapClone {
47
+ msrv : Option < RustcVersion > ,
48
+ }
49
+
50
+ impl_lint_pass ! ( MapClone => [ MAP_CLONE ] ) ;
51
+
52
+ impl MapClone {
53
+ pub fn new ( msrv : Option < RustcVersion > ) -> Self {
54
+ Self { msrv }
55
+ }
56
+ }
46
57
47
58
impl < ' tcx > LateLintPass < ' tcx > for MapClone {
48
59
fn check_expr ( & mut self , cx : & LateContext < ' _ > , e : & hir:: Expr < ' _ > ) {
@@ -65,15 +76,15 @@ impl<'tcx> LateLintPass<'tcx> for MapClone {
65
76
hir:: BindingAnnotation :: Unannotated , .., name, None
66
77
) = inner. kind {
67
78
if ident_eq( name, closure_expr) {
68
- lint ( cx, e. span, args[ 0 ] . span, true ) ;
79
+ self . lint_explicit_closure ( cx, e. span, args[ 0 ] . span, true ) ;
69
80
}
70
81
} ,
71
82
hir:: PatKind :: Binding ( hir:: BindingAnnotation :: Unannotated , .., name, None ) => {
72
83
match closure_expr. kind {
73
84
hir:: ExprKind :: Unary ( hir:: UnOp :: Deref , inner) => {
74
85
if ident_eq( name, inner) {
75
86
if let ty:: Ref ( .., Mutability :: Not ) = cx. typeck_results( ) . expr_ty( inner) . kind( ) {
76
- lint ( cx, e. span, args[ 0 ] . span, true ) ;
87
+ self . lint_explicit_closure ( cx, e. span, args[ 0 ] . span, true ) ;
77
88
}
78
89
}
79
90
} ,
@@ -90,7 +101,7 @@ impl<'tcx> LateLintPass<'tcx> for MapClone {
90
101
if let ty:: Ref ( _, ty, mutability) = obj_ty. kind( ) {
91
102
if matches!( mutability, Mutability :: Not ) {
92
103
let copy = is_copy( cx, ty) ;
93
- lint ( cx, e. span, args[ 0 ] . span, copy) ;
104
+ self . lint_explicit_closure ( cx, e. span, args[ 0 ] . span, copy) ;
94
105
}
95
106
} else {
96
107
lint_needless_cloning( cx, e. span, args[ 0 ] . span) ;
@@ -105,6 +116,8 @@ impl<'tcx> LateLintPass<'tcx> for MapClone {
105
116
}
106
117
}
107
118
}
119
+
120
+ extract_msrv_attr ! ( LateContext ) ;
108
121
}
109
122
110
123
fn ident_eq ( name : Ident , path : & hir:: Expr < ' _ > ) -> bool {
@@ -127,31 +140,30 @@ fn lint_needless_cloning(cx: &LateContext<'_>, root: Span, receiver: Span) {
127
140
) ;
128
141
}
129
142
130
- fn lint ( cx : & LateContext < ' _ > , replace : Span , root : Span , copied : bool ) {
131
- let mut applicability = Applicability :: MachineApplicable ;
132
- if copied {
133
- span_lint_and_sugg (
134
- cx,
135
- MAP_CLONE ,
136
- replace,
137
- "you are using an explicit closure for copying elements" ,
138
- "consider calling the dedicated `copied` method" ,
139
- format ! (
140
- "{}.copied()" ,
141
- snippet_with_applicability( cx, root, ".." , & mut applicability)
142
- ) ,
143
- applicability,
144
- ) ;
145
- } else {
143
+ impl MapClone {
144
+ fn lint_explicit_closure ( & self , cx : & LateContext < ' _ > , replace : Span , root : Span , is_copy : bool ) {
145
+ let mut applicability = Applicability :: MachineApplicable ;
146
+ let message = if is_copy {
147
+ "you are using an explicit closure for copying elements"
148
+ } else {
149
+ "you are using an explicit closure for cloning elements"
150
+ } ;
151
+ let sugg_method = if is_copy && meets_msrv ( self . msrv . as_ref ( ) , & msrvs:: ITERATOR_COPIED ) {
152
+ "copied"
153
+ } else {
154
+ "cloned"
155
+ } ;
156
+
146
157
span_lint_and_sugg (
147
158
cx,
148
159
MAP_CLONE ,
149
160
replace,
150
- "you are using an explicit closure for cloning elements" ,
151
- "consider calling the dedicated `cloned ` method" ,
161
+ message ,
162
+ & format ! ( "consider calling the dedicated `{} ` method" , sugg_method ) ,
152
163
format ! (
153
- "{}.cloned()" ,
154
- snippet_with_applicability( cx, root, ".." , & mut applicability)
164
+ "{}.{}()" ,
165
+ snippet_with_applicability( cx, root, ".." , & mut applicability) ,
166
+ sugg_method,
155
167
) ,
156
168
applicability,
157
169
) ;
0 commit comments