@@ -5,6 +5,7 @@ use crate::utils::{
5
5
use if_chain:: if_chain;
6
6
use rustc:: hir;
7
7
use rustc:: lint:: { LateContext , LateLintPass , LintArray , LintPass } ;
8
+ use rustc:: ty;
8
9
use rustc:: { declare_tool_lint, lint_array} ;
9
10
use rustc_errors:: Applicability ;
10
11
use syntax:: ast:: Ident ;
@@ -18,9 +19,7 @@ pub struct Pass;
18
19
///
19
20
/// **Why is this bad?** Readability, this can be written more concisely
20
21
///
21
- /// **Known problems:** Sometimes `.cloned()` requires stricter trait
22
- /// bound than `.map(|e| e.clone())` (which works because of the coercion).
23
- /// See [#498](https://github.com/rust-lang-nursery/rust-clippy/issues/498).
22
+ /// **Known problems:** None
24
23
///
25
24
/// **Example:**
26
25
///
@@ -69,19 +68,27 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
69
68
hir:: PatKind :: Ref ( ref inner, _) => if let hir:: PatKind :: Binding (
70
69
hir:: BindingAnnotation :: Unannotated , _, name, None
71
70
) = inner. node {
72
- lint( cx, e. span, args[ 0 ] . span, name, closure_expr) ;
71
+ if ident_eq( name, closure_expr) {
72
+ lint( cx, e. span, args[ 0 ] . span) ;
73
+ }
73
74
} ,
74
75
hir:: PatKind :: Binding ( hir:: BindingAnnotation :: Unannotated , _, name, None ) => {
75
76
match closure_expr. node {
76
77
hir:: ExprKind :: Unary ( hir:: UnOp :: UnDeref , ref inner) => {
77
- if !cx. tables. expr_ty( inner) . is_box( ) {
78
- lint( cx, e. span, args[ 0 ] . span, name , inner ) ;
78
+ if ident_eq ( name , inner ) && !cx. tables. expr_ty( inner) . is_box( ) {
79
+ lint( cx, e. span, args[ 0 ] . span) ;
79
80
}
80
81
} ,
81
82
hir:: ExprKind :: MethodCall ( ref method, _, ref obj) => {
82
- if method. ident. as_str( ) == "clone"
83
+ if ident_eq ( name , & obj [ 0 ] ) && method. ident. as_str( ) == "clone"
83
84
&& match_trait_method( cx, closure_expr, & paths:: CLONE_TRAIT ) {
84
- lint( cx, e. span, args[ 0 ] . span, name, & obj[ 0 ] ) ;
85
+
86
+ let obj_ty = cx. tables. expr_ty( & obj[ 0 ] ) ;
87
+ if let ty:: Ref ( ..) = obj_ty. sty {
88
+ lint( cx, e. span, args[ 0 ] . span) ;
89
+ } else {
90
+ lint_needless_cloning( cx, e. span, args[ 0 ] . span) ;
91
+ }
85
92
}
86
93
} ,
87
94
_ => { } ,
@@ -94,22 +101,38 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
94
101
}
95
102
}
96
103
97
- fn lint ( cx : & LateContext < ' _ , ' _ > , replace : Span , root : Span , name : Ident , path : & hir:: Expr ) {
104
+ fn ident_eq ( name : Ident , path : & hir:: Expr ) -> bool {
98
105
if let hir:: ExprKind :: Path ( hir:: QPath :: Resolved ( None , ref path) ) = path. node {
99
- if path. segments . len ( ) == 1 && path. segments [ 0 ] . ident == name {
100
- let mut applicability = Applicability :: MachineApplicable ;
101
- span_lint_and_sugg (
102
- cx,
103
- MAP_CLONE ,
104
- replace,
105
- "You are using an explicit closure for cloning elements" ,
106
- "Consider calling the dedicated `cloned` method" ,
107
- format ! (
108
- "{}.cloned()" ,
109
- snippet_with_applicability( cx, root, ".." , & mut applicability)
110
- ) ,
111
- applicability,
112
- )
113
- }
106
+ path. segments . len ( ) == 1 && path. segments [ 0 ] . ident == name
107
+ } else {
108
+ false
114
109
}
115
110
}
111
+
112
+ fn lint_needless_cloning ( cx : & LateContext < ' _ , ' _ > , root : Span , receiver : Span ) {
113
+ span_lint_and_sugg (
114
+ cx,
115
+ MAP_CLONE ,
116
+ root. trim_start ( receiver) . unwrap ( ) ,
117
+ "You are needlessly cloning iterator elements" ,
118
+ "Remove the map call" ,
119
+ String :: new ( ) ,
120
+ Applicability :: MachineApplicable ,
121
+ )
122
+ }
123
+
124
+ fn lint ( cx : & LateContext < ' _ , ' _ > , replace : Span , root : Span ) {
125
+ let mut applicability = Applicability :: MachineApplicable ;
126
+ span_lint_and_sugg (
127
+ cx,
128
+ MAP_CLONE ,
129
+ replace,
130
+ "You are using an explicit closure for cloning elements" ,
131
+ "Consider calling the dedicated `cloned` method" ,
132
+ format ! (
133
+ "{}.cloned()" ,
134
+ snippet_with_applicability( cx, root, ".." , & mut applicability)
135
+ ) ,
136
+ applicability,
137
+ )
138
+ }
0 commit comments