@@ -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 ;
@@ -69,19 +70,27 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
69
70
hir:: PatKind :: Ref ( ref inner, _) => if let hir:: PatKind :: Binding (
70
71
hir:: BindingAnnotation :: Unannotated , _, name, None
71
72
) = inner. node {
72
- lint( cx, e. span, args[ 0 ] . span, name, closure_expr) ;
73
+ if ident_eq( name, closure_expr) {
74
+ lint( cx, e. span, args[ 0 ] . span) ;
75
+ }
73
76
} ,
74
77
hir:: PatKind :: Binding ( hir:: BindingAnnotation :: Unannotated , _, name, None ) => {
75
78
match closure_expr. node {
76
79
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 ) ;
80
+ if ident_eq ( name , inner ) && !cx. tables. expr_ty( inner) . is_box( ) {
81
+ lint( cx, e. span, args[ 0 ] . span) ;
79
82
}
80
83
} ,
81
84
hir:: ExprKind :: MethodCall ( ref method, _, ref obj) => {
82
- if method. ident. as_str( ) == "clone"
85
+ if ident_eq ( name , & obj [ 0 ] ) && method. ident. as_str( ) == "clone"
83
86
&& match_trait_method( cx, closure_expr, & paths:: CLONE_TRAIT ) {
84
- lint( cx, e. span, args[ 0 ] . span, name, & obj[ 0 ] ) ;
87
+
88
+ let obj_ty = cx. tables. expr_ty( & obj[ 0 ] ) ;
89
+ if let ty:: Ref ( ..) = obj_ty. sty {
90
+ lint( cx, e. span, args[ 0 ] . span) ;
91
+ } else {
92
+ lint_needless_cloning( cx, e. span, args[ 0 ] . span) ;
93
+ }
85
94
}
86
95
} ,
87
96
_ => { } ,
@@ -94,22 +103,38 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
94
103
}
95
104
}
96
105
97
- fn lint ( cx : & LateContext < ' _ , ' _ > , replace : Span , root : Span , name : Ident , path : & hir:: Expr ) {
106
+ fn ident_eq ( name : Ident , path : & hir:: Expr ) -> bool {
98
107
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
- }
108
+ path. segments . len ( ) == 1 && path. segments [ 0 ] . ident == name
109
+ } else {
110
+ false
114
111
}
115
112
}
113
+
114
+ fn lint_needless_cloning ( cx : & LateContext < ' _ , ' _ > , root : Span , receiver : Span ) {
115
+ span_lint_and_sugg (
116
+ cx,
117
+ MAP_CLONE ,
118
+ root. trim_start ( receiver) . unwrap ( ) ,
119
+ "You are needlessly cloning iterator elements" ,
120
+ "Remove the map call" ,
121
+ String :: new ( ) ,
122
+ Applicability :: MachineApplicable ,
123
+ )
124
+ }
125
+
126
+ fn lint ( cx : & LateContext < ' _ , ' _ > , replace : Span , root : Span ) {
127
+ let mut applicability = Applicability :: MachineApplicable ;
128
+ span_lint_and_sugg (
129
+ cx,
130
+ MAP_CLONE ,
131
+ replace,
132
+ "You are using an explicit closure for cloning elements" ,
133
+ "Consider calling the dedicated `cloned` method" ,
134
+ format ! (
135
+ "{}.cloned()" ,
136
+ snippet_with_applicability( cx, root, ".." , & mut applicability)
137
+ ) ,
138
+ applicability,
139
+ )
140
+ }
0 commit comments