Skip to content

Commit 5414e0f

Browse files
t-webberprofetia
authored andcommitted
fix: manual_unwrap_or_default
1 parent 75e3a2e commit 5414e0f

File tree

3 files changed

+78
-2
lines changed

3 files changed

+78
-2
lines changed

clippy_lints/src/manual_unwrap_or_default.rs

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use rustc_errors::Applicability;
22
use rustc_hir::def::Res;
33
use rustc_hir::{Arm, Expr, ExprKind, HirId, LangItem, MatchSource, Pat, PatKind, QPath};
44
use rustc_lint::{LateContext, LateLintPass, LintContext};
5-
use rustc_middle::ty::GenericArgKind;
5+
use rustc_middle::ty::{self, GenericArgKind};
66
use rustc_session::declare_lint_pass;
77
use rustc_span::sym;
88

@@ -152,6 +152,42 @@ fn handle<'tcx>(cx: &LateContext<'tcx>, if_let_or_match: IfLetOrMatch<'tcx>, exp
152152
&& is_default_equivalent(cx, body_none)
153153
&& let Some(receiver) = Sugg::hir_opt(cx, condition).map(Sugg::maybe_par)
154154
{
155+
// We check if the expression is not a None variant
156+
if let Some(none_def_id) = cx.tcx.lang_items().option_none_variant() {
157+
if let ExprKind::Path(QPath::Resolved(_, path)) = &condition.kind {
158+
if let Some(def_id) = path.res.opt_def_id() {
159+
if cx.tcx.parent(def_id) == none_def_id {
160+
return span_lint_and_sugg(
161+
cx,
162+
MANUAL_UNWRAP_OR_DEFAULT,
163+
expr.span,
164+
format!("{expr_name} can be simplified with `.unwrap_or_default()`"),
165+
"replace it with",
166+
format!("{receiver}::</* Type */>.unwrap_or_default()"),
167+
Applicability::HasPlaceholders,
168+
);
169+
}
170+
}
171+
}
172+
}
173+
174+
// We check if the expression is not a method or function with a unspecified return type
175+
if let ExprKind::MethodCall(_, expr, _, _) = &condition.kind {
176+
if let ty::Adt(_, substs) = cx.typeck_results().expr_ty(expr).kind() {
177+
if let Some(ok_type) = substs.first() {
178+
return span_lint_and_sugg(
179+
cx,
180+
MANUAL_UNWRAP_OR_DEFAULT,
181+
expr.span,
182+
format!("{expr_name} can be simplified with `.unwrap_or_default()`"),
183+
format!("explicit the type {ok_type} and replace your expression with"),
184+
format!("{receiver}.unwrap_or_default()"),
185+
Applicability::Unspecified,
186+
);
187+
}
188+
}
189+
}
190+
155191
// Machine applicable only if there are no comments present
156192
let applicability = if span_contains_comment(cx.sess().source_map(), expr.span) {
157193
Applicability::MaybeIncorrect

tests/ui/manual_unwrap_or_default.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,3 +132,19 @@ fn issue_12928() {
132132
let y = if let Some(Y(a, _)) = x { a } else { 0 };
133133
let y = if let Some(Y(a, ..)) = x { a } else { 0 };
134134
}
135+
136+
//@no-rustfix
137+
fn issue_12670() {
138+
// no auto: type not found
139+
#[allow(clippy::match_result_ok)]
140+
let _ = if let Some(x) = "1".parse().ok() {
141+
x
142+
} else {
143+
i32::default()
144+
};
145+
let _ = if let Some(x) = None { x } else { i32::default() };
146+
// auto fix with unwrap_or_default
147+
let a: Option<i32> = None;
148+
let _ = if let Some(x) = a { x } else { i32::default() };
149+
let _ = if let Some(x) = Some(99) { x } else { i32::default() };
150+
}

tests/ui/manual_unwrap_or_default.stderr

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,5 +83,29 @@ LL | | _ => 0,
8383
LL | | },
8484
| |_________^ help: replace it with: `(*b).unwrap_or_default()`
8585

86-
error: aborting due to 8 previous errors
86+
error: if let can be simplified with `.unwrap_or_default()`
87+
--> tests/ui/manual_unwrap_or_default.rs:104:30
88+
|
89+
LL | let _ = if let Some(x) = "1".parse().ok() {
90+
| ^^^^^^^^^^^ help: explicit the type i32 and replace your expression with: `"1".parse().ok().unwrap_or_default()`
91+
92+
error: if let can be simplified with `.unwrap_or_default()`
93+
--> tests/ui/manual_unwrap_or_default.rs:109:13
94+
|
95+
LL | let _ = if let Some(x) = None { x } else { i32::default() };
96+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `None::</* Type */>.unwrap_or_default()`
97+
98+
error: if let can be simplified with `.unwrap_or_default()`
99+
--> tests/ui/manual_unwrap_or_default.rs:112:13
100+
|
101+
LL | let _ = if let Some(x) = a { x } else { i32::default() };
102+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `a.unwrap_or_default()`
103+
104+
error: if let can be simplified with `.unwrap_or_default()`
105+
--> tests/ui/manual_unwrap_or_default.rs:113:13
106+
|
107+
LL | let _ = if let Some(x) = Some(99) { x } else { i32::default() };
108+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `Some(99).unwrap_or_default()`
109+
110+
error: aborting due to 10 previous errors
87111

0 commit comments

Comments
 (0)