@@ -2,12 +2,14 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
22use clippy_utils:: source:: snippet;
33use clippy_utils:: ty:: is_type_diagnostic_item;
44use clippy_utils:: { get_parent_expr, match_def_path, paths, SpanlessEq } ;
5+ use clippy_utils:: { meets_msrv, msrvs} ;
56use rustc_errors:: Applicability ;
67use rustc_hir as hir;
78use rustc_hir:: def_id:: DefId ;
89use rustc_hir:: ExprKind :: Assign ;
910use rustc_lint:: { LateContext , LateLintPass } ;
10- use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
11+ use rustc_semver:: RustcVersion ;
12+ use rustc_session:: { declare_tool_lint, impl_lint_pass} ;
1113use rustc_span:: symbol:: sym;
1214
1315const ACCEPTABLE_METHODS : [ & [ & str ] ; 4 ] = [
@@ -16,13 +18,13 @@ const ACCEPTABLE_METHODS: [&[&str]; 4] = [
1618 & paths:: SLICE_INTO ,
1719 & paths:: VEC_DEQUE_ITER ,
1820] ;
19- const ACCEPTABLE_TYPES : [ rustc_span:: Symbol ; 6 ] = [
20- sym:: BTreeSet ,
21- sym:: BTreeMap ,
22- sym:: HashSet ,
23- sym:: HashMap ,
24- sym:: Vec ,
25- sym:: VecDeque ,
21+ const ACCEPTABLE_TYPES : [ ( rustc_span:: Symbol , Option < RustcVersion > ) ; 6 ] = [
22+ ( sym:: BTreeSet , Some ( msrvs :: BTREE_SET_RETAIN ) ) ,
23+ ( sym:: BTreeMap , Some ( msrvs :: BTREE_MAP_RETAIN ) ) ,
24+ ( sym:: HashSet , Some ( msrvs :: HASH_SET_RETAIN ) ) ,
25+ ( sym:: HashMap , Some ( msrvs :: HASH_MAP_RETAIN ) ) ,
26+ ( sym:: Vec , None ) ,
27+ ( sym:: VecDeque , None ) ,
2628] ;
2729
2830declare_clippy_lint ! {
@@ -46,7 +48,19 @@ declare_clippy_lint! {
4648 perf,
4749 "`retain()` is simpler and the same functionalitys"
4850}
49- declare_lint_pass ! ( UseRetain => [ USE_RETAIN ] ) ;
51+
52+ pub struct UseRetain {
53+ msrv : Option < RustcVersion > ,
54+ }
55+
56+ impl UseRetain {
57+ #[ must_use]
58+ pub fn new ( msrv : Option < RustcVersion > ) -> Self {
59+ Self { msrv }
60+ }
61+ }
62+
63+ impl_lint_pass ! ( UseRetain => [ USE_RETAIN ] ) ;
5064
5165impl < ' tcx > LateLintPass < ' tcx > for UseRetain {
5266 fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & ' tcx hir:: Expr < ' _ > ) {
@@ -57,26 +71,29 @@ impl<'tcx> LateLintPass<'tcx> for UseRetain {
5771 && let hir:: ExprKind :: MethodCall ( _, [ target_expr] , _) = & collect_expr. kind
5872 && let Some ( collect_def_id) = cx. typeck_results ( ) . type_dependent_def_id ( collect_expr. hir_id )
5973 && match_def_path ( cx, collect_def_id, & paths:: CORE_ITER_COLLECT ) {
60- check_into_iter ( cx, parent_expr, left_expr, target_expr) ;
61- check_iter ( cx, parent_expr, left_expr, target_expr) ;
62- check_to_owned ( cx, parent_expr, left_expr, target_expr) ;
74+ check_into_iter ( cx, parent_expr, left_expr, target_expr, self . msrv ) ;
75+ check_iter ( cx, parent_expr, left_expr, target_expr, self . msrv ) ;
76+ check_to_owned ( cx, parent_expr, left_expr, target_expr, self . msrv ) ;
6377 }
6478 }
79+
80+ extract_msrv_attr ! ( LateContext ) ;
6581}
6682
6783fn check_into_iter (
6884 cx : & LateContext < ' _ > ,
6985 parent_expr : & hir:: Expr < ' _ > ,
7086 left_expr : & hir:: Expr < ' _ > ,
7187 target_expr : & hir:: Expr < ' _ > ,
88+ msrv : Option < RustcVersion > ,
7289) {
7390 if let hir:: ExprKind :: MethodCall ( _, [ into_iter_expr, _] , _) = & target_expr. kind
7491 && let Some ( filter_def_id) = cx. typeck_results ( ) . type_dependent_def_id ( target_expr. hir_id )
7592 && match_def_path ( cx, filter_def_id, & paths:: CORE_ITER_FILTER )
7693 && let hir:: ExprKind :: MethodCall ( _, [ struct_expr] , _) = & into_iter_expr. kind
7794 && let Some ( into_iter_def_id) = cx. typeck_results ( ) . type_dependent_def_id ( into_iter_expr. hir_id )
7895 && match_def_path ( cx, into_iter_def_id, & paths:: CORE_ITER_INTO_ITER )
79- && match_acceptable_type ( cx, left_expr)
96+ && match_acceptable_type ( cx, left_expr, msrv )
8097 && SpanlessEq :: new ( cx) . eq_expr ( left_expr, struct_expr) {
8198 suggest ( cx, parent_expr, left_expr, target_expr) ;
8299 }
@@ -87,6 +104,7 @@ fn check_iter(
87104 parent_expr : & hir:: Expr < ' _ > ,
88105 left_expr : & hir:: Expr < ' _ > ,
89106 target_expr : & hir:: Expr < ' _ > ,
107+ msrv : Option < RustcVersion > ,
90108) {
91109 if let hir:: ExprKind :: MethodCall ( _, [ filter_expr] , _) = & target_expr. kind
92110 && let Some ( copied_def_id) = cx. typeck_results ( ) . type_dependent_def_id ( target_expr. hir_id )
@@ -98,7 +116,7 @@ fn check_iter(
98116 && let hir:: ExprKind :: MethodCall ( _, [ struct_expr] , _) = & iter_expr. kind
99117 && let Some ( iter_expr_def_id) = cx. typeck_results ( ) . type_dependent_def_id ( iter_expr. hir_id )
100118 && match_acceptable_def_path ( cx, iter_expr_def_id)
101- && match_acceptable_type ( cx, left_expr)
119+ && match_acceptable_type ( cx, left_expr, msrv )
102120 && SpanlessEq :: new ( cx) . eq_expr ( left_expr, struct_expr) {
103121 suggest ( cx, parent_expr, left_expr, filter_expr) ;
104122 }
@@ -109,8 +127,10 @@ fn check_to_owned(
109127 parent_expr : & hir:: Expr < ' _ > ,
110128 left_expr : & hir:: Expr < ' _ > ,
111129 target_expr : & hir:: Expr < ' _ > ,
130+ msrv : Option < RustcVersion > ,
112131) {
113- if let hir:: ExprKind :: MethodCall ( _, [ filter_expr] , _) = & target_expr. kind
132+ if meets_msrv ( msrv, msrvs:: STRING_RETAIN )
133+ && let hir:: ExprKind :: MethodCall ( _, [ filter_expr] , _) = & target_expr. kind
114134 && let Some ( to_owned_def_id) = cx. typeck_results ( ) . type_dependent_def_id ( target_expr. hir_id )
115135 && match_def_path ( cx, to_owned_def_id, & paths:: TO_OWNED_METHOD )
116136 && let hir:: ExprKind :: MethodCall ( _, [ chars_expr, _] , _) = & filter_expr. kind
@@ -199,9 +219,10 @@ fn match_acceptable_def_path(cx: &LateContext<'_>, collect_def_id: DefId) -> boo
199219 . any ( |& method| match_def_path ( cx, collect_def_id, method) )
200220}
201221
202- fn match_acceptable_type ( cx : & LateContext < ' _ > , expr : & hir:: Expr < ' _ > ) -> bool {
222+ fn match_acceptable_type ( cx : & LateContext < ' _ > , expr : & hir:: Expr < ' _ > , msrv : Option < RustcVersion > ) -> bool {
203223 let expr_ty = cx. typeck_results ( ) . expr_ty ( expr) . peel_refs ( ) ;
204- ACCEPTABLE_TYPES
205- . iter ( )
206- . any ( |& ty| is_type_diagnostic_item ( cx, expr_ty, ty) )
224+ ACCEPTABLE_TYPES . iter ( ) . any ( |( ty, acceptable_msrv) | {
225+ is_type_diagnostic_item ( cx, expr_ty, * ty)
226+ && acceptable_msrv. map_or ( true , |acceptable_msrv| meets_msrv ( msrv, acceptable_msrv) )
227+ } )
207228}
0 commit comments