@@ -2,12 +2,14 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
2
2
use clippy_utils:: source:: snippet;
3
3
use clippy_utils:: ty:: is_type_diagnostic_item;
4
4
use clippy_utils:: { get_parent_expr, match_def_path, paths, SpanlessEq } ;
5
+ use clippy_utils:: { meets_msrv, msrvs} ;
5
6
use rustc_errors:: Applicability ;
6
7
use rustc_hir as hir;
7
8
use rustc_hir:: def_id:: DefId ;
8
9
use rustc_hir:: ExprKind :: Assign ;
9
10
use 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} ;
11
13
use rustc_span:: symbol:: sym;
12
14
13
15
const ACCEPTABLE_METHODS : [ & [ & str ] ; 4 ] = [
@@ -16,13 +18,13 @@ const ACCEPTABLE_METHODS: [&[&str]; 4] = [
16
18
& paths:: SLICE_INTO ,
17
19
& paths:: VEC_DEQUE_ITER ,
18
20
] ;
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 ) ,
26
28
] ;
27
29
28
30
declare_clippy_lint ! {
@@ -46,7 +48,19 @@ declare_clippy_lint! {
46
48
perf,
47
49
"`retain()` is simpler and the same functionalitys"
48
50
}
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 ] ) ;
50
64
51
65
impl < ' tcx > LateLintPass < ' tcx > for UseRetain {
52
66
fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & ' tcx hir:: Expr < ' _ > ) {
@@ -57,26 +71,29 @@ impl<'tcx> LateLintPass<'tcx> for UseRetain {
57
71
&& let hir:: ExprKind :: MethodCall ( _, [ target_expr] , _) = & collect_expr. kind
58
72
&& let Some ( collect_def_id) = cx. typeck_results ( ) . type_dependent_def_id ( collect_expr. hir_id )
59
73
&& 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 ) ;
63
77
}
64
78
}
79
+
80
+ extract_msrv_attr ! ( LateContext ) ;
65
81
}
66
82
67
83
fn check_into_iter (
68
84
cx : & LateContext < ' _ > ,
69
85
parent_expr : & hir:: Expr < ' _ > ,
70
86
left_expr : & hir:: Expr < ' _ > ,
71
87
target_expr : & hir:: Expr < ' _ > ,
88
+ msrv : Option < RustcVersion > ,
72
89
) {
73
90
if let hir:: ExprKind :: MethodCall ( _, [ into_iter_expr, _] , _) = & target_expr. kind
74
91
&& let Some ( filter_def_id) = cx. typeck_results ( ) . type_dependent_def_id ( target_expr. hir_id )
75
92
&& match_def_path ( cx, filter_def_id, & paths:: CORE_ITER_FILTER )
76
93
&& let hir:: ExprKind :: MethodCall ( _, [ struct_expr] , _) = & into_iter_expr. kind
77
94
&& let Some ( into_iter_def_id) = cx. typeck_results ( ) . type_dependent_def_id ( into_iter_expr. hir_id )
78
95
&& 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 )
80
97
&& SpanlessEq :: new ( cx) . eq_expr ( left_expr, struct_expr) {
81
98
suggest ( cx, parent_expr, left_expr, target_expr) ;
82
99
}
@@ -87,6 +104,7 @@ fn check_iter(
87
104
parent_expr : & hir:: Expr < ' _ > ,
88
105
left_expr : & hir:: Expr < ' _ > ,
89
106
target_expr : & hir:: Expr < ' _ > ,
107
+ msrv : Option < RustcVersion > ,
90
108
) {
91
109
if let hir:: ExprKind :: MethodCall ( _, [ filter_expr] , _) = & target_expr. kind
92
110
&& let Some ( copied_def_id) = cx. typeck_results ( ) . type_dependent_def_id ( target_expr. hir_id )
@@ -98,7 +116,7 @@ fn check_iter(
98
116
&& let hir:: ExprKind :: MethodCall ( _, [ struct_expr] , _) = & iter_expr. kind
99
117
&& let Some ( iter_expr_def_id) = cx. typeck_results ( ) . type_dependent_def_id ( iter_expr. hir_id )
100
118
&& match_acceptable_def_path ( cx, iter_expr_def_id)
101
- && match_acceptable_type ( cx, left_expr)
119
+ && match_acceptable_type ( cx, left_expr, msrv )
102
120
&& SpanlessEq :: new ( cx) . eq_expr ( left_expr, struct_expr) {
103
121
suggest ( cx, parent_expr, left_expr, filter_expr) ;
104
122
}
@@ -109,8 +127,10 @@ fn check_to_owned(
109
127
parent_expr : & hir:: Expr < ' _ > ,
110
128
left_expr : & hir:: Expr < ' _ > ,
111
129
target_expr : & hir:: Expr < ' _ > ,
130
+ msrv : Option < RustcVersion > ,
112
131
) {
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
114
134
&& let Some ( to_owned_def_id) = cx. typeck_results ( ) . type_dependent_def_id ( target_expr. hir_id )
115
135
&& match_def_path ( cx, to_owned_def_id, & paths:: TO_OWNED_METHOD )
116
136
&& 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
199
219
. any ( |& method| match_def_path ( cx, collect_def_id, method) )
200
220
}
201
221
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 {
203
223
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
+ } )
207
228
}
0 commit comments