Skip to content

Commit 50af574

Browse files
committed
check msrv
1 parent 6884f4c commit 50af574

File tree

6 files changed

+123
-45
lines changed

6 files changed

+123
-45
lines changed

clippy_lints/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -908,7 +908,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
908908
store.register_late_pass(|| Box::new(swap_ptr_to_ref::SwapPtrToRef));
909909
store.register_late_pass(|| Box::new(mismatching_type_param_order::TypeParamMismatch));
910910
store.register_late_pass(|| Box::new(as_underscore::AsUnderscore));
911-
store.register_late_pass(|| Box::new(use_retain::UseRetain));
911+
store.register_late_pass(move || Box::new(use_retain::UseRetain::new(msrv)));
912912
// add lints here, do not remove this comment, it's used in `new_lint`
913913
}
914914

clippy_lints/src/use_retain.rs

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
22
use clippy_utils::source::snippet;
33
use clippy_utils::ty::is_type_diagnostic_item;
44
use clippy_utils::{get_parent_expr, match_def_path, paths, SpanlessEq};
5+
use clippy_utils::{meets_msrv, msrvs};
56
use rustc_errors::Applicability;
67
use rustc_hir as hir;
78
use rustc_hir::def_id::DefId;
89
use rustc_hir::ExprKind::Assign;
910
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};
1113
use rustc_span::symbol::sym;
1214

1315
const 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

2830
declare_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

5165
impl<'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

6783
fn 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
}

clippy_utils/src/msrvs.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ macro_rules! msrv_aliases {
1212

1313
// names may refer to stabilized feature flags or library items
1414
msrv_aliases! {
15-
1,53,0 { OR_PATTERNS, MANUAL_BITS }
15+
1,53,0 { OR_PATTERNS, MANUAL_BITS, BTREE_MAP_RETAIN, BTREE_SET_RETAIN }
1616
1,52,0 { STR_SPLIT_ONCE }
1717
1,51,0 { BORROW_AS_PTR, UNSIGNED_ABS }
1818
1,50,0 { BOOL_THEN }
@@ -30,7 +30,8 @@ msrv_aliases! {
3030
1,34,0 { TRY_FROM }
3131
1,30,0 { ITERATOR_FIND_MAP, TOOL_ATTRIBUTES }
3232
1,28,0 { FROM_BOOL }
33-
1,26,0 { RANGE_INCLUSIVE }
33+
1,26,0 { RANGE_INCLUSIVE, STRING_RETAIN }
34+
1,18,0 { HASH_MAP_RETAIN, HASH_SET_RETAIN }
3435
1,17,0 { FIELD_INIT_SHORTHAND, STATIC_IN_CONST, EXPECT_ERR }
3536
1,16,0 { STR_REPEAT }
3637
1,24,0 { IS_ASCII_DIGIT }

tests/ui/use_retain.fixed

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// run-rustfix
2+
#![feature(custom_inner_attributes)]
23
#![warn(clippy::use_retain)]
34
#![allow(unused)]
45
use std::collections::BTreeMap;
@@ -15,12 +16,16 @@ fn main() {
1516
hash_set_retain();
1617
hash_map_retain();
1718
string_retain();
18-
vec_queue_retain();
19+
vec_deque_retain();
1920
vec_retain();
21+
_msrv_153();
22+
_msrv_126();
23+
_msrv_118();
2024
}
2125

2226
fn binary_heap_retain() {
2327
// NOTE: Do not lint now, because binary_heap_retain is nighyly API.
28+
// And we need to add a test case for msrv if we update this implmention.
2429
// https://github.com/rust-lang/rust/issues/71503
2530
let mut heap = BinaryHeap::from([1, 2, 3]);
2631
heap = heap.into_iter().filter(|x| x % 2 == 0).collect();
@@ -179,7 +184,7 @@ fn vec_retain() {
179184
bar = foobar.into_iter().filter(|x| x % 2 == 0).collect();
180185
}
181186

182-
fn vec_queue_retain() {
187+
fn vec_deque_retain() {
183188
let mut vec_deque = VecDeque::new();
184189
vec_deque.extend(1..5);
185190

@@ -210,3 +215,26 @@ fn vec_queue_retain() {
210215
bar = foobar.iter().filter(|&x| x % 2 == 0).cloned().collect();
211216
bar = foobar.into_iter().filter(|x| x % 2 == 0).collect();
212217
}
218+
219+
fn _msrv_153() {
220+
#![clippy::msrv = "1.52"]
221+
let mut btree_map: BTreeMap<i8, i8> = (0..8).map(|x| (x, x * 10)).collect();
222+
btree_map = btree_map.into_iter().filter(|(k, _)| k % 2 == 0).collect();
223+
224+
let mut btree_set = BTreeSet::from([1, 2, 3, 4, 5, 6]);
225+
btree_set = btree_set.iter().filter(|&x| x % 2 == 0).copied().collect();
226+
}
227+
228+
fn _msrv_126() {
229+
#![clippy::msrv = "1.25"]
230+
let mut s = String::from("foobar");
231+
s = s.chars().filter(|&c| c != 'o').to_owned().collect();
232+
}
233+
234+
fn _msrv_118() {
235+
#![clippy::msrv = "1.17"]
236+
let mut hash_set = HashSet::from([1, 2, 3, 4, 5, 6]);
237+
hash_set = hash_set.into_iter().filter(|x| x % 2 == 0).collect();
238+
let mut hash_map: HashMap<i8, i8> = (0..8).map(|x| (x, x * 10)).collect();
239+
hash_map = hash_map.into_iter().filter(|(k, _)| k % 2 == 0).collect();
240+
}

tests/ui/use_retain.rs

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// run-rustfix
2+
#![feature(custom_inner_attributes)]
23
#![warn(clippy::use_retain)]
34
#![allow(unused)]
45
use std::collections::BTreeMap;
@@ -15,12 +16,16 @@ fn main() {
1516
hash_set_retain();
1617
hash_map_retain();
1718
string_retain();
18-
vec_queue_retain();
19+
vec_deque_retain();
1920
vec_retain();
21+
_msrv_153();
22+
_msrv_126();
23+
_msrv_118();
2024
}
2125

2226
fn binary_heap_retain() {
2327
// NOTE: Do not lint now, because binary_heap_retain is nighyly API.
28+
// And we need to add a test case for msrv if we update this implmention.
2429
// https://github.com/rust-lang/rust/issues/71503
2530
let mut heap = BinaryHeap::from([1, 2, 3]);
2631
heap = heap.into_iter().filter(|x| x % 2 == 0).collect();
@@ -185,7 +190,7 @@ fn vec_retain() {
185190
bar = foobar.into_iter().filter(|x| x % 2 == 0).collect();
186191
}
187192

188-
fn vec_queue_retain() {
193+
fn vec_deque_retain() {
189194
let mut vec_deque = VecDeque::new();
190195
vec_deque.extend(1..5);
191196

@@ -216,3 +221,26 @@ fn vec_queue_retain() {
216221
bar = foobar.iter().filter(|&x| x % 2 == 0).cloned().collect();
217222
bar = foobar.into_iter().filter(|x| x % 2 == 0).collect();
218223
}
224+
225+
fn _msrv_153() {
226+
#![clippy::msrv = "1.52"]
227+
let mut btree_map: BTreeMap<i8, i8> = (0..8).map(|x| (x, x * 10)).collect();
228+
btree_map = btree_map.into_iter().filter(|(k, _)| k % 2 == 0).collect();
229+
230+
let mut btree_set = BTreeSet::from([1, 2, 3, 4, 5, 6]);
231+
btree_set = btree_set.iter().filter(|&x| x % 2 == 0).copied().collect();
232+
}
233+
234+
fn _msrv_126() {
235+
#![clippy::msrv = "1.25"]
236+
let mut s = String::from("foobar");
237+
s = s.chars().filter(|&c| c != 'o').to_owned().collect();
238+
}
239+
240+
fn _msrv_118() {
241+
#![clippy::msrv = "1.17"]
242+
let mut hash_set = HashSet::from([1, 2, 3, 4, 5, 6]);
243+
hash_set = hash_set.into_iter().filter(|x| x % 2 == 0).collect();
244+
let mut hash_map: HashMap<i8, i8> = (0..8).map(|x| (x, x * 10)).collect();
245+
hash_map = hash_map.into_iter().filter(|(k, _)| k % 2 == 0).collect();
246+
}

0 commit comments

Comments
 (0)