Skip to content

Commit fc1152a

Browse files
committed
Auto merge of rust-lang#11359 - Alexendoo:unwrap-or-default-check-suggestion, r=dswij
Check that the suggested method exists in unwrap_or_default Fixes rust-lang#11355 changelog: none
2 parents 7408f1d + 8f2d47e commit fc1152a

File tree

3 files changed

+77
-2
lines changed

3 files changed

+77
-2
lines changed

clippy_lints/src/methods/or_fun_call.rs

+17-2
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,26 @@ pub(super) fn check<'tcx>(
6565
};
6666

6767
let sugg = match (name, call_expr.is_some()) {
68-
("unwrap_or", true) | ("unwrap_or_else", false) => "unwrap_or_default",
69-
("or_insert", true) | ("or_insert_with", false) => "or_default",
68+
("unwrap_or", true) | ("unwrap_or_else", false) => sym!(unwrap_or_default),
69+
("or_insert", true) | ("or_insert_with", false) => sym!(or_default),
7070
_ => return false,
7171
};
7272

73+
let receiver_ty = cx.typeck_results().expr_ty_adjusted(receiver).peel_refs();
74+
let has_suggested_method = receiver_ty.ty_adt_def().is_some_and(|adt_def| {
75+
cx.tcx
76+
.inherent_impls(adt_def.did())
77+
.iter()
78+
.flat_map(|impl_id| cx.tcx.associated_items(impl_id).filter_by_name_unhygienic(sugg))
79+
.any(|assoc| {
80+
assoc.fn_has_self_parameter
81+
&& cx.tcx.fn_sig(assoc.def_id).skip_binder().inputs().skip_binder().len() == 1
82+
})
83+
});
84+
if !has_suggested_method {
85+
return false;
86+
}
87+
7388
// needs to target Default::default in particular or be *::new and have a Default impl
7489
// available
7590
if (is_new(fun) && output_type_implements_default(fun))

tests/ui/unwrap_or_else_default.fixed

+30
Original file line numberDiff line numberDiff line change
@@ -130,4 +130,34 @@ fn method_call_with_deref() {
130130
let _ = inner_map.entry(0).or_default();
131131
}
132132

133+
fn missing_suggested_method() {
134+
#[derive(Copy, Clone)]
135+
struct S<T>(T);
136+
137+
impl<T> S<T> {
138+
fn or_insert_with(&mut self, default: impl FnOnce() -> T) -> &mut T {
139+
&mut self.0
140+
}
141+
142+
fn or_insert(&mut self, default: T) -> &mut T {
143+
&mut self.0
144+
}
145+
146+
fn unwrap_or_else(self, default: impl FnOnce() -> T) -> T {
147+
self.0
148+
}
149+
150+
fn unwrap_or(self, default: T) -> T {
151+
self.0
152+
}
153+
}
154+
155+
// Don't lint when or_default/unwrap_or_default do not exist on the type
156+
let mut s = S(1);
157+
s.or_insert_with(Default::default);
158+
s.or_insert(Default::default());
159+
s.unwrap_or_else(Default::default);
160+
s.unwrap_or(Default::default());
161+
}
162+
133163
fn main() {}

tests/ui/unwrap_or_else_default.rs

+30
Original file line numberDiff line numberDiff line change
@@ -130,4 +130,34 @@ fn method_call_with_deref() {
130130
let _ = inner_map.entry(0).or_insert_with(Default::default);
131131
}
132132

133+
fn missing_suggested_method() {
134+
#[derive(Copy, Clone)]
135+
struct S<T>(T);
136+
137+
impl<T> S<T> {
138+
fn or_insert_with(&mut self, default: impl FnOnce() -> T) -> &mut T {
139+
&mut self.0
140+
}
141+
142+
fn or_insert(&mut self, default: T) -> &mut T {
143+
&mut self.0
144+
}
145+
146+
fn unwrap_or_else(self, default: impl FnOnce() -> T) -> T {
147+
self.0
148+
}
149+
150+
fn unwrap_or(self, default: T) -> T {
151+
self.0
152+
}
153+
}
154+
155+
// Don't lint when or_default/unwrap_or_default do not exist on the type
156+
let mut s = S(1);
157+
s.or_insert_with(Default::default);
158+
s.or_insert(Default::default());
159+
s.unwrap_or_else(Default::default);
160+
s.unwrap_or(Default::default());
161+
}
162+
133163
fn main() {}

0 commit comments

Comments
 (0)