Skip to content

Commit b763b14

Browse files
committed
Auto merge of #9342 - relrelb:or_default, r=dswij
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?). Addresses #3812. *Please write a short comment explaining your change (or "none" for internal only changes)* changelog: [`or_fun_call`]: Suggest `Entry::or_default` for `Entry::or_insert(Default::default())`
2 parents 90804d3 + f0e586c commit b763b14

File tree

5 files changed

+44
-13
lines changed

5 files changed

+44
-13
lines changed

clippy_lints/src/methods/mod.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -825,8 +825,9 @@ declare_clippy_lint! {
825825
declare_clippy_lint! {
826826
/// ### What it does
827827
/// Checks for calls to `.or(foo(..))`, `.unwrap_or(foo(..))`,
828-
/// etc., and suggests to use `or_else`, `unwrap_or_else`, etc., or
829-
/// `unwrap_or_default` instead.
828+
/// `.or_insert(foo(..))` etc., and suggests to use `.or_else(|| foo(..))`,
829+
/// `.unwrap_or_else(|| foo(..))`, `.unwrap_or_default()` or `.or_default()`
830+
/// etc. instead.
830831
///
831832
/// ### Why is this bad?
832833
/// The function will always be called and potentially

clippy_lints/src/methods/or_fun_call.rs

+9-4
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"),

src/docs/or_fun_call.txt

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
### What it does
22
Checks for calls to `.or(foo(..))`, `.unwrap_or(foo(..))`,
3-
etc., and suggests to use `or_else`, `unwrap_or_else`, etc., or
4-
`unwrap_or_default` instead.
3+
`.or_insert(foo(..))` etc., and suggests to use `.or_else(|| foo(..))`,
4+
`.unwrap_or_else(|| foo(..))`, `.unwrap_or_default()` or `.or_default()`
5+
etc. instead.
56

67
### Why is this bad?
78
The function will always be called and potentially

tests/ui/or_fun_call.fixed

+4-4
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

+25-1
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)