Skip to content

Commit

Permalink
Auto merge of #11359 - Alexendoo:unwrap-or-default-check-suggestion, …
Browse files Browse the repository at this point in the history
…r=dswij

Check that the suggested method exists in unwrap_or_default

Fixes #11355

changelog: none
  • Loading branch information
bors committed Aug 20, 2023
2 parents 7408f1d + 8f2d47e commit fc1152a
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 2 deletions.
19 changes: 17 additions & 2 deletions clippy_lints/src/methods/or_fun_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,26 @@ pub(super) fn check<'tcx>(
};

let sugg = match (name, call_expr.is_some()) {
("unwrap_or", true) | ("unwrap_or_else", false) => "unwrap_or_default",
("or_insert", true) | ("or_insert_with", false) => "or_default",
("unwrap_or", true) | ("unwrap_or_else", false) => sym!(unwrap_or_default),
("or_insert", true) | ("or_insert_with", false) => sym!(or_default),
_ => return false,
};

let receiver_ty = cx.typeck_results().expr_ty_adjusted(receiver).peel_refs();
let has_suggested_method = receiver_ty.ty_adt_def().is_some_and(|adt_def| {
cx.tcx
.inherent_impls(adt_def.did())
.iter()
.flat_map(|impl_id| cx.tcx.associated_items(impl_id).filter_by_name_unhygienic(sugg))
.any(|assoc| {
assoc.fn_has_self_parameter
&& cx.tcx.fn_sig(assoc.def_id).skip_binder().inputs().skip_binder().len() == 1
})
});
if !has_suggested_method {
return false;
}

// needs to target Default::default in particular or be *::new and have a Default impl
// available
if (is_new(fun) && output_type_implements_default(fun))
Expand Down
30 changes: 30 additions & 0 deletions tests/ui/unwrap_or_else_default.fixed
Original file line number Diff line number Diff line change
Expand Up @@ -130,4 +130,34 @@ fn method_call_with_deref() {
let _ = inner_map.entry(0).or_default();
}

fn missing_suggested_method() {
#[derive(Copy, Clone)]
struct S<T>(T);

impl<T> S<T> {
fn or_insert_with(&mut self, default: impl FnOnce() -> T) -> &mut T {
&mut self.0
}

fn or_insert(&mut self, default: T) -> &mut T {
&mut self.0
}

fn unwrap_or_else(self, default: impl FnOnce() -> T) -> T {
self.0
}

fn unwrap_or(self, default: T) -> T {
self.0
}
}

// Don't lint when or_default/unwrap_or_default do not exist on the type
let mut s = S(1);
s.or_insert_with(Default::default);
s.or_insert(Default::default());
s.unwrap_or_else(Default::default);
s.unwrap_or(Default::default());
}

fn main() {}
30 changes: 30 additions & 0 deletions tests/ui/unwrap_or_else_default.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,4 +130,34 @@ fn method_call_with_deref() {
let _ = inner_map.entry(0).or_insert_with(Default::default);
}

fn missing_suggested_method() {
#[derive(Copy, Clone)]
struct S<T>(T);

impl<T> S<T> {
fn or_insert_with(&mut self, default: impl FnOnce() -> T) -> &mut T {
&mut self.0
}

fn or_insert(&mut self, default: T) -> &mut T {
&mut self.0
}

fn unwrap_or_else(self, default: impl FnOnce() -> T) -> T {
self.0
}

fn unwrap_or(self, default: T) -> T {
self.0
}
}

// Don't lint when or_default/unwrap_or_default do not exist on the type
let mut s = S(1);
s.or_insert_with(Default::default);
s.or_insert(Default::default());
s.unwrap_or_else(Default::default);
s.unwrap_or(Default::default());
}

fn main() {}

0 comments on commit fc1152a

Please sign in to comment.