Skip to content

Commit 92b9677

Browse files
committed
Auto merge of #6820 - mgacek8:issue_6562_enhance_mem_replace_with_default_with_other_ctors, r=phansch
mem_replace_with_default: recognize some std library ctors fixes #6562 changelog: mem_replace_with_default: recognize some common constructors equivalent to `Default::default()`
2 parents 28759b2 + 41be515 commit 92b9677

File tree

5 files changed

+166
-8
lines changed

5 files changed

+166
-8
lines changed

Diff for: clippy_lints/src/mem_replace.rs

+35-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use crate::utils::{
44
};
55
use if_chain::if_chain;
66
use rustc_errors::Applicability;
7+
use rustc_hir::def_id::DefId;
78
use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, QPath};
89
use rustc_lint::{LateContext, LateLintPass, LintContext};
910
use rustc_middle::lint::in_external_macro;
@@ -12,6 +13,8 @@ use rustc_session::{declare_tool_lint, impl_lint_pass};
1213
use rustc_span::source_map::Span;
1314
use rustc_span::symbol::sym;
1415

16+
use clippy_utils::is_diagnostic_assoc_item;
17+
1518
declare_clippy_lint! {
1619
/// **What it does:** Checks for `mem::replace()` on an `Option` with
1720
/// `None`.
@@ -194,13 +197,44 @@ fn check_replace_with_uninit(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<'
194197
}
195198
}
196199

200+
/// Returns true if the `def_id` associated with the `path` is recognized as a "default-equivalent"
201+
/// constructor from the std library
202+
fn is_default_equivalent_ctor(cx: &LateContext<'_>, def_id: DefId, path: &QPath<'_>) -> bool {
203+
let std_types_symbols = &[
204+
sym::string_type,
205+
sym::vec_type,
206+
sym::vecdeque_type,
207+
sym::LinkedList,
208+
sym::hashmap_type,
209+
sym::BTreeMap,
210+
sym::hashset_type,
211+
sym::BTreeSet,
212+
sym::BinaryHeap,
213+
];
214+
215+
if std_types_symbols
216+
.iter()
217+
.any(|symbol| is_diagnostic_assoc_item(cx, def_id, *symbol))
218+
{
219+
if let QPath::TypeRelative(_, ref method) = path {
220+
if method.ident.name == sym::new {
221+
return true;
222+
}
223+
}
224+
}
225+
226+
false
227+
}
228+
197229
fn check_replace_with_default(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<'_>, expr_span: Span) {
198230
if let ExprKind::Call(ref repl_func, _) = src.kind {
199231
if_chain! {
200232
if !in_external_macro(cx.tcx.sess, expr_span);
201233
if let ExprKind::Path(ref repl_func_qpath) = repl_func.kind;
202234
if let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id();
203-
if match_def_path(cx, repl_def_id, &paths::DEFAULT_TRAIT_METHOD);
235+
if is_diagnostic_assoc_item(cx, repl_def_id, sym::Default)
236+
|| is_default_equivalent_ctor(cx, repl_def_id, repl_func_qpath);
237+
204238
then {
205239
span_lint_and_then(
206240
cx,

Diff for: clippy_utils/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ pub fn match_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, path: &[&str])
280280
trt_id.map_or(false, |trt_id| match_def_path(cx, trt_id, path))
281281
}
282282

283-
/// Checks if the method call given in `expr` belongs to a trait or other container with a given
283+
/// Checks if the method call given in `def_id` belongs to a trait or other container with a given
284284
/// diagnostic item
285285
pub fn is_diagnostic_assoc_item(cx: &LateContext<'_>, def_id: DefId, diag_item: Symbol) -> bool {
286286
cx.tcx

Diff for: tests/ui/mem_replace.fixed

+29
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
clippy::mem_replace_with_default
88
)]
99

10+
use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList, VecDeque};
1011
use std::mem;
1112

1213
fn replace_option_with_none() {
@@ -19,9 +20,37 @@ fn replace_option_with_none() {
1920
fn replace_with_default() {
2021
let mut s = String::from("foo");
2122
let _ = std::mem::take(&mut s);
23+
2224
let s = &mut String::from("foo");
2325
let _ = std::mem::take(s);
2426
let _ = std::mem::take(s);
27+
28+
let mut v = vec![123];
29+
let _ = std::mem::take(&mut v);
30+
let _ = std::mem::take(&mut v);
31+
let _ = std::mem::take(&mut v);
32+
let _ = std::mem::take(&mut v);
33+
34+
let mut hash_map: HashMap<i32, i32> = HashMap::new();
35+
let _ = std::mem::take(&mut hash_map);
36+
37+
let mut btree_map: BTreeMap<i32, i32> = BTreeMap::new();
38+
let _ = std::mem::take(&mut btree_map);
39+
40+
let mut vd: VecDeque<i32> = VecDeque::new();
41+
let _ = std::mem::take(&mut vd);
42+
43+
let mut hash_set: HashSet<&str> = HashSet::new();
44+
let _ = std::mem::take(&mut hash_set);
45+
46+
let mut btree_set: BTreeSet<&str> = BTreeSet::new();
47+
let _ = std::mem::take(&mut btree_set);
48+
49+
let mut list: LinkedList<i32> = LinkedList::new();
50+
let _ = std::mem::take(&mut list);
51+
52+
let mut binary_heap: BinaryHeap<i32> = BinaryHeap::new();
53+
let _ = std::mem::take(&mut binary_heap);
2554
}
2655

2756
fn main() {

Diff for: tests/ui/mem_replace.rs

+29
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
clippy::mem_replace_with_default
88
)]
99

10+
use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList, VecDeque};
1011
use std::mem;
1112

1213
fn replace_option_with_none() {
@@ -19,9 +20,37 @@ fn replace_option_with_none() {
1920
fn replace_with_default() {
2021
let mut s = String::from("foo");
2122
let _ = std::mem::replace(&mut s, String::default());
23+
2224
let s = &mut String::from("foo");
2325
let _ = std::mem::replace(s, String::default());
2426
let _ = std::mem::replace(s, Default::default());
27+
28+
let mut v = vec![123];
29+
let _ = std::mem::replace(&mut v, Vec::default());
30+
let _ = std::mem::replace(&mut v, Default::default());
31+
let _ = std::mem::replace(&mut v, Vec::new());
32+
let _ = std::mem::replace(&mut v, vec![]);
33+
34+
let mut hash_map: HashMap<i32, i32> = HashMap::new();
35+
let _ = std::mem::replace(&mut hash_map, HashMap::new());
36+
37+
let mut btree_map: BTreeMap<i32, i32> = BTreeMap::new();
38+
let _ = std::mem::replace(&mut btree_map, BTreeMap::new());
39+
40+
let mut vd: VecDeque<i32> = VecDeque::new();
41+
let _ = std::mem::replace(&mut vd, VecDeque::new());
42+
43+
let mut hash_set: HashSet<&str> = HashSet::new();
44+
let _ = std::mem::replace(&mut hash_set, HashSet::new());
45+
46+
let mut btree_set: BTreeSet<&str> = BTreeSet::new();
47+
let _ = std::mem::replace(&mut btree_set, BTreeSet::new());
48+
49+
let mut list: LinkedList<i32> = LinkedList::new();
50+
let _ = std::mem::replace(&mut list, LinkedList::new());
51+
52+
let mut binary_heap: BinaryHeap<i32> = BinaryHeap::new();
53+
let _ = std::mem::replace(&mut binary_heap, BinaryHeap::new());
2554
}
2655

2756
fn main() {

Diff for: tests/ui/mem_replace.stderr

+72-6
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,102 @@
11
error: replacing an `Option` with `None`
2-
--> $DIR/mem_replace.rs:14:13
2+
--> $DIR/mem_replace.rs:15:13
33
|
44
LL | let _ = mem::replace(&mut an_option, None);
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `an_option.take()`
66
|
77
= note: `-D clippy::mem-replace-option-with-none` implied by `-D warnings`
88

99
error: replacing an `Option` with `None`
10-
--> $DIR/mem_replace.rs:16:13
10+
--> $DIR/mem_replace.rs:17:13
1111
|
1212
LL | let _ = mem::replace(an_option, None);
1313
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `an_option.take()`
1414

1515
error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
16-
--> $DIR/mem_replace.rs:21:13
16+
--> $DIR/mem_replace.rs:22:13
1717
|
1818
LL | let _ = std::mem::replace(&mut s, String::default());
1919
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut s)`
2020
|
2121
= note: `-D clippy::mem-replace-with-default` implied by `-D warnings`
2222

2323
error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
24-
--> $DIR/mem_replace.rs:23:13
24+
--> $DIR/mem_replace.rs:25:13
2525
|
2626
LL | let _ = std::mem::replace(s, String::default());
2727
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(s)`
2828

2929
error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
30-
--> $DIR/mem_replace.rs:24:13
30+
--> $DIR/mem_replace.rs:26:13
3131
|
3232
LL | let _ = std::mem::replace(s, Default::default());
3333
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(s)`
3434

35-
error: aborting due to 5 previous errors
35+
error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
36+
--> $DIR/mem_replace.rs:29:13
37+
|
38+
LL | let _ = std::mem::replace(&mut v, Vec::default());
39+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut v)`
40+
41+
error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
42+
--> $DIR/mem_replace.rs:30:13
43+
|
44+
LL | let _ = std::mem::replace(&mut v, Default::default());
45+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut v)`
46+
47+
error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
48+
--> $DIR/mem_replace.rs:31:13
49+
|
50+
LL | let _ = std::mem::replace(&mut v, Vec::new());
51+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut v)`
52+
53+
error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
54+
--> $DIR/mem_replace.rs:32:13
55+
|
56+
LL | let _ = std::mem::replace(&mut v, vec![]);
57+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut v)`
58+
59+
error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
60+
--> $DIR/mem_replace.rs:35:13
61+
|
62+
LL | let _ = std::mem::replace(&mut hash_map, HashMap::new());
63+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut hash_map)`
64+
65+
error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
66+
--> $DIR/mem_replace.rs:38:13
67+
|
68+
LL | let _ = std::mem::replace(&mut btree_map, BTreeMap::new());
69+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut btree_map)`
70+
71+
error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
72+
--> $DIR/mem_replace.rs:41:13
73+
|
74+
LL | let _ = std::mem::replace(&mut vd, VecDeque::new());
75+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut vd)`
76+
77+
error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
78+
--> $DIR/mem_replace.rs:44:13
79+
|
80+
LL | let _ = std::mem::replace(&mut hash_set, HashSet::new());
81+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut hash_set)`
82+
83+
error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
84+
--> $DIR/mem_replace.rs:47:13
85+
|
86+
LL | let _ = std::mem::replace(&mut btree_set, BTreeSet::new());
87+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut btree_set)`
88+
89+
error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
90+
--> $DIR/mem_replace.rs:50:13
91+
|
92+
LL | let _ = std::mem::replace(&mut list, LinkedList::new());
93+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut list)`
94+
95+
error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
96+
--> $DIR/mem_replace.rs:53:13
97+
|
98+
LL | let _ = std::mem::replace(&mut binary_heap, BinaryHeap::new());
99+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut binary_heap)`
100+
101+
error: aborting due to 16 previous errors
36102

0 commit comments

Comments
 (0)