1
1
use crate :: utils:: paths;
2
2
use crate :: utils:: {
3
- in_macro, match_trait_method, match_type, remove_blocks, snippet_with_applicability, span_lint_and_sugg,
3
+ in_macro, is_copy , match_trait_method, match_type, remove_blocks, snippet_with_applicability, span_lint_and_sugg,
4
4
} ;
5
5
use if_chain:: if_chain;
6
6
use rustc:: hir;
@@ -63,7 +63,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
63
63
if args. len( ) == 2 ;
64
64
if method. ident. as_str( ) == "map" ;
65
65
let ty = cx. tables. expr_ty( & args[ 0 ] ) ;
66
- if match_type( cx, ty, & paths:: OPTION ) || match_trait_method( cx, e, & paths:: ITERATOR ) ;
66
+ let is_option = match_type( cx, ty, & paths:: OPTION ) ;
67
+ if is_option || match_trait_method( cx, e, & paths:: ITERATOR ) ;
67
68
if let hir:: ExprKind :: Closure ( _, _, body_id, _, _) = args[ 1 ] . node;
68
69
let closure_body = cx. tcx. hir( ) . body( body_id) ;
69
70
let closure_expr = remove_blocks( & closure_body. value) ;
@@ -73,23 +74,26 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
73
74
hir:: BindingAnnotation :: Unannotated , .., name, None
74
75
) = inner. node {
75
76
if ident_eq( name, closure_expr) {
76
- lint( cx, e. span, args[ 0 ] . span) ;
77
+ // FIXME When Iterator::copied() stabilizes we can remove is_option
78
+ // from here and the other lint() calls
79
+ lint( cx, e. span, args[ 0 ] . span, is_option) ;
77
80
}
78
81
} ,
79
82
hir:: PatKind :: Binding ( hir:: BindingAnnotation :: Unannotated , .., name, None ) => {
80
83
match closure_expr. node {
81
84
hir:: ExprKind :: Unary ( hir:: UnOp :: UnDeref , ref inner) => {
82
85
if ident_eq( name, inner) && !cx. tables. expr_ty( inner) . is_box( ) {
83
- lint( cx, e. span, args[ 0 ] . span) ;
86
+ lint( cx, e. span, args[ 0 ] . span, is_option ) ;
84
87
}
85
88
} ,
86
89
hir:: ExprKind :: MethodCall ( ref method, _, ref obj) => {
87
90
if ident_eq( name, & obj[ 0 ] ) && method. ident. as_str( ) == "clone"
88
91
&& match_trait_method( cx, closure_expr, & paths:: CLONE_TRAIT ) {
89
92
90
93
let obj_ty = cx. tables. expr_ty( & obj[ 0 ] ) ;
91
- if let ty:: Ref ( ..) = obj_ty. sty {
92
- lint( cx, e. span, args[ 0 ] . span) ;
94
+ if let ty:: Ref ( _, ty, _) = obj_ty. sty {
95
+ let copy = is_copy( cx, ty) ;
96
+ lint( cx, e. span, args[ 0 ] . span, is_option && copy) ;
93
97
} else {
94
98
lint_needless_cloning( cx, e. span, args[ 0 ] . span) ;
95
99
}
@@ -125,18 +129,33 @@ fn lint_needless_cloning(cx: &LateContext<'_, '_>, root: Span, receiver: Span) {
125
129
)
126
130
}
127
131
128
- fn lint ( cx : & LateContext < ' _ , ' _ > , replace : Span , root : Span ) {
132
+ fn lint ( cx : & LateContext < ' _ , ' _ > , replace : Span , root : Span , copied : bool ) {
129
133
let mut applicability = Applicability :: MachineApplicable ;
130
- span_lint_and_sugg (
131
- cx,
132
- MAP_CLONE ,
133
- replace,
134
- "You are using an explicit closure for cloning elements" ,
135
- "Consider calling the dedicated `cloned` method" ,
136
- format ! (
137
- "{}.cloned()" ,
138
- snippet_with_applicability( cx, root, ".." , & mut applicability)
139
- ) ,
140
- applicability,
141
- )
134
+ if copied {
135
+ span_lint_and_sugg (
136
+ cx,
137
+ MAP_CLONE ,
138
+ replace,
139
+ "You are using an explicit closure for copying elements" ,
140
+ "Consider calling the dedicated `copied` method" ,
141
+ format ! (
142
+ "{}.copied()" ,
143
+ snippet_with_applicability( cx, root, ".." , & mut applicability)
144
+ ) ,
145
+ applicability,
146
+ )
147
+ } else {
148
+ span_lint_and_sugg (
149
+ cx,
150
+ MAP_CLONE ,
151
+ replace,
152
+ "You are using an explicit closure for cloning elements" ,
153
+ "Consider calling the dedicated `cloned` method" ,
154
+ format ! (
155
+ "{}.cloned()" ,
156
+ snippet_with_applicability( cx, root, ".." , & mut applicability)
157
+ ) ,
158
+ applicability,
159
+ )
160
+ }
142
161
}
0 commit comments