11use clippy_utils:: diagnostics:: span_lint_and_sugg;
22use clippy_utils:: source:: snippet_with_applicability;
33use 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} ;
55use if_chain:: if_chain;
66use rustc_errors:: Applicability ;
77use rustc_hir as hir;
8- use rustc_lint:: { LateContext , LateLintPass } ;
8+ use rustc_lint:: { LateContext , LateLintPass , LintContext } ;
99use rustc_middle:: mir:: Mutability ;
1010use rustc_middle:: ty;
1111use 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} ;
1314use rustc_span:: symbol:: Ident ;
1415use rustc_span:: { sym, Span } ;
1516
@@ -42,7 +43,17 @@ declare_clippy_lint! {
4243 "using `iterator.map(|x| x.clone())`, or dereferencing closures for `Copy` types"
4344}
4445
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+ }
4657
4758impl < ' tcx > LateLintPass < ' tcx > for MapClone {
4859 fn check_expr ( & mut self , cx : & LateContext < ' _ > , e : & hir:: Expr < ' _ > ) {
@@ -65,15 +76,15 @@ impl<'tcx> LateLintPass<'tcx> for MapClone {
6576 hir:: BindingAnnotation :: Unannotated , .., name, None
6677 ) = inner. kind {
6778 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 ) ;
6980 }
7081 } ,
7182 hir:: PatKind :: Binding ( hir:: BindingAnnotation :: Unannotated , .., name, None ) => {
7283 match closure_expr. kind {
7384 hir:: ExprKind :: Unary ( hir:: UnOp :: Deref , inner) => {
7485 if ident_eq( name, inner) {
7586 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 ) ;
7788 }
7889 }
7990 } ,
@@ -90,7 +101,7 @@ impl<'tcx> LateLintPass<'tcx> for MapClone {
90101 if let ty:: Ref ( _, ty, mutability) = obj_ty. kind( ) {
91102 if matches!( mutability, Mutability :: Not ) {
92103 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) ;
94105 }
95106 } else {
96107 lint_needless_cloning( cx, e. span, args[ 0 ] . span) ;
@@ -105,6 +116,8 @@ impl<'tcx> LateLintPass<'tcx> for MapClone {
105116 }
106117 }
107118 }
119+
120+ extract_msrv_attr ! ( LateContext ) ;
108121}
109122
110123fn ident_eq ( name : Ident , path : & hir:: Expr < ' _ > ) -> bool {
@@ -127,31 +140,30 @@ fn lint_needless_cloning(cx: &LateContext<'_>, root: Span, receiver: Span) {
127140 ) ;
128141}
129142
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+
146157 span_lint_and_sugg (
147158 cx,
148159 MAP_CLONE ,
149160 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 ) ,
152163 format ! (
153- "{}.cloned()" ,
154- snippet_with_applicability( cx, root, ".." , & mut applicability)
164+ "{}.{}()" ,
165+ snippet_with_applicability( cx, root, ".." , & mut applicability) ,
166+ sugg_method,
155167 ) ,
156168 applicability,
157169 ) ;
0 commit comments