11use crate :: utils:: paths;
22use 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,
44} ;
55use if_chain:: if_chain;
66use rustc:: hir;
@@ -63,7 +63,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
6363 if args. len( ) == 2 ;
6464 if method. ident. as_str( ) == "map" ;
6565 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 ) ;
6768 if let hir:: ExprKind :: Closure ( _, _, body_id, _, _) = args[ 1 ] . node;
6869 let closure_body = cx. tcx. hir( ) . body( body_id) ;
6970 let closure_expr = remove_blocks( & closure_body. value) ;
@@ -73,23 +74,26 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
7374 hir:: BindingAnnotation :: Unannotated , .., name, None
7475 ) = inner. node {
7576 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) ;
7780 }
7881 } ,
7982 hir:: PatKind :: Binding ( hir:: BindingAnnotation :: Unannotated , .., name, None ) => {
8083 match closure_expr. node {
8184 hir:: ExprKind :: Unary ( hir:: UnOp :: UnDeref , ref inner) => {
8285 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 ) ;
8487 }
8588 } ,
8689 hir:: ExprKind :: MethodCall ( ref method, _, ref obj) => {
8790 if ident_eq( name, & obj[ 0 ] ) && method. ident. as_str( ) == "clone"
8891 && match_trait_method( cx, closure_expr, & paths:: CLONE_TRAIT ) {
8992
9093 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) ;
9397 } else {
9498 lint_needless_cloning( cx, e. span, args[ 0 ] . span) ;
9599 }
@@ -125,18 +129,33 @@ fn lint_needless_cloning(cx: &LateContext<'_, '_>, root: Span, receiver: Span) {
125129 )
126130}
127131
128- fn lint ( cx : & LateContext < ' _ , ' _ > , replace : Span , root : Span ) {
132+ fn lint ( cx : & LateContext < ' _ , ' _ > , replace : Span , root : Span , copied : bool ) {
129133 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+ }
142161}
0 commit comments