Skip to content

Commit e8c8a93

Browse files
committed
Suggest Entry::or_default for Entry::or_insert(Default::default())
Unlike past similar work done in #6228, expand the existing `or_fun_call` lint to detect `or_insert` calls with a `T::new()` or `T::default()` argument, much like currently done for `unwrap_or` calls. In that case, suggest the use of `or_default`, which is more idiomatic. Note that even with this change, `or_insert_with(T::default)` calls aren't detected as candidates for `or_default()`, in the same manner that currently `unwrap_or_else(T::default)` calls aren't detected as candidates for `unwrap_or_default()`. Also, as a nearby cleanup, change `KNOW_TYPES` from `static` to `const`, since as far as I understand it's preferred (should Clippy have a lint for that?). Fixes #3812.
1 parent 3a54117 commit e8c8a93

File tree

4 files changed

+40
-11
lines changed

4 files changed

+40
-11
lines changed

clippy_lints/src/methods/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -797,8 +797,8 @@ declare_clippy_lint! {
797797
declare_clippy_lint! {
798798
/// ### What it does
799799
/// Checks for calls to `.or(foo(..))`, `.unwrap_or(foo(..))`,
800-
/// etc., and suggests to use `or_else`, `unwrap_or_else`, etc., or
801-
/// `unwrap_or_default` instead.
800+
/// `or_insert(foo(...))` etc., and suggests to use `or_else`,
801+
/// `unwrap_or_else`, etc., `unwrap_or_default` or `or_default` instead.
802802
///
803803
/// ### Why is this bad?
804804
/// The function will always be called and potentially

clippy_lints/src/methods/or_fun_call.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ pub(super) fn check<'tcx>(
2222
name: &str,
2323
args: &'tcx [hir::Expr<'_>],
2424
) {
25-
/// Checks for `unwrap_or(T::new())` or `unwrap_or(T::default())`.
25+
/// Checks for `unwrap_or(T::new())`, `unwrap_or(T::default())`,
26+
/// `or_insert(T::new())` or `or_insert(T::default())`.
2627
#[allow(clippy::too_many_arguments)]
2728
fn check_unwrap_or_default(
2829
cx: &LateContext<'_>,
@@ -42,7 +43,11 @@ pub(super) fn check<'tcx>(
4243

4344
if_chain! {
4445
if !or_has_args;
45-
if name == "unwrap_or";
46+
if let Some(sugg) = match name {
47+
"unwrap_or" => Some("unwrap_or_default"),
48+
"or_insert" => Some("or_default"),
49+
_ => None,
50+
};
4651
if let hir::ExprKind::Path(ref qpath) = fun.kind;
4752
if let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default);
4853
let path = last_path_segment(qpath).ident.name;
@@ -58,7 +63,7 @@ pub(super) fn check<'tcx>(
5863
method_span.with_hi(span.hi()),
5964
&format!("use of `{}` followed by a call to `{}`", name, path),
6065
"try this",
61-
"unwrap_or_default()".to_string(),
66+
format!("{}()", sugg),
6267
Applicability::MachineApplicable,
6368
);
6469

@@ -82,7 +87,7 @@ pub(super) fn check<'tcx>(
8287
fun_span: Option<Span>,
8388
) {
8489
// (path, fn_has_argument, methods, suffix)
85-
static KNOW_TYPES: [(&[&str], bool, &[&str], &str); 4] = [
90+
const KNOW_TYPES: [(&[&str], bool, &[&str], &str); 4] = [
8691
(&paths::BTREEMAP_ENTRY, false, &["or_insert"], "with"),
8792
(&paths::HASHMAP_ENTRY, false, &["or_insert"], "with"),
8893
(&paths::OPTION, false, &["map_or", "ok_or", "or", "unwrap_or"], "else"),

tests/ui/or_fun_call.fixed

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,16 +79,16 @@ fn or_fun_call() {
7979
without_default.unwrap_or_else(Foo::new);
8080

8181
let mut map = HashMap::<u64, String>::new();
82-
map.entry(42).or_insert(String::new());
82+
map.entry(42).or_default();
8383

8484
let mut map_vec = HashMap::<u64, Vec<i32>>::new();
85-
map_vec.entry(42).or_insert(vec![]);
85+
map_vec.entry(42).or_default();
8686

8787
let mut btree = BTreeMap::<u64, String>::new();
88-
btree.entry(42).or_insert(String::new());
88+
btree.entry(42).or_default();
8989

9090
let mut btree_vec = BTreeMap::<u64, Vec<i32>>::new();
91-
btree_vec.entry(42).or_insert(vec![]);
91+
btree_vec.entry(42).or_default();
9292

9393
let stringy = Some(String::new());
9494
let _ = stringy.unwrap_or_default();

tests/ui/or_fun_call.stderr

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,30 @@ error: use of `unwrap_or` followed by a function call
6666
LL | without_default.unwrap_or(Foo::new());
6767
| ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(Foo::new)`
6868

69+
error: use of `or_insert` followed by a call to `new`
70+
--> $DIR/or_fun_call.rs:82:19
71+
|
72+
LL | map.entry(42).or_insert(String::new());
73+
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_default()`
74+
75+
error: use of `or_insert` followed by a call to `new`
76+
--> $DIR/or_fun_call.rs:85:23
77+
|
78+
LL | map_vec.entry(42).or_insert(vec![]);
79+
| ^^^^^^^^^^^^^^^^^ help: try this: `or_default()`
80+
81+
error: use of `or_insert` followed by a call to `new`
82+
--> $DIR/or_fun_call.rs:88:21
83+
|
84+
LL | btree.entry(42).or_insert(String::new());
85+
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_default()`
86+
87+
error: use of `or_insert` followed by a call to `new`
88+
--> $DIR/or_fun_call.rs:91:25
89+
|
90+
LL | btree_vec.entry(42).or_insert(vec![]);
91+
| ^^^^^^^^^^^^^^^^^ help: try this: `or_default()`
92+
6993
error: use of `unwrap_or` followed by a call to `new`
7094
--> $DIR/or_fun_call.rs:94:21
7195
|
@@ -132,5 +156,5 @@ error: use of `unwrap_or` followed by a call to `new`
132156
LL | .unwrap_or(String::new());
133157
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()`
134158

135-
error: aborting due to 22 previous errors
159+
error: aborting due to 26 previous errors
136160

0 commit comments

Comments
 (0)