Skip to content

Commit c9f0374

Browse files
committed
fix: manual_unwrap_or_default
1 parent cdd6336 commit c9f0374

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

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

tests/ui/manual_unwrap_or_default.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,3 +96,19 @@ fn issue_12569() {
9696
0
9797
};
9898
}
99+
100+
//@no-rustfix
101+
fn issue_12670() {
102+
// no auto: type not found
103+
#[allow(clippy::match_result_ok)]
104+
let _ = if let Some(x) = "1".parse().ok() {
105+
x
106+
} else {
107+
i32::default()
108+
};
109+
let _ = if let Some(x) = None { x } else { i32::default() };
110+
// auto fix with unwrap_or_default
111+
let a: Option<i32> = None;
112+
let _ = if let Some(x) = a { x } else { i32::default() };
113+
let _ = if let Some(x) = Some(99) { x } else { i32::default() };
114+
}

tests/ui/manual_unwrap_or_default.stderr

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

65-
error: aborting due to 6 previous errors
65+
error: if let can be simplified with `.unwrap_or_default()`
66+
--> tests/ui/manual_unwrap_or_default.rs:104:30
67+
|
68+
LL | let _ = if let Some(x) = "1".parse().ok() {
69+
| ^^^^^^^^^^^ help: explicit the type i32 and replace your expression with: `"1".parse().ok().unwrap_or_default()`
70+
71+
error: if let can be simplified with `.unwrap_or_default()`
72+
--> tests/ui/manual_unwrap_or_default.rs:109:13
73+
|
74+
LL | let _ = if let Some(x) = None { x } else { i32::default() };
75+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `None::</* Type */>.unwrap_or_default()`
76+
77+
error: if let can be simplified with `.unwrap_or_default()`
78+
--> tests/ui/manual_unwrap_or_default.rs:112:13
79+
|
80+
LL | let _ = if let Some(x) = a { x } else { i32::default() };
81+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `a.unwrap_or_default()`
82+
83+
error: if let can be simplified with `.unwrap_or_default()`
84+
--> tests/ui/manual_unwrap_or_default.rs:113:13
85+
|
86+
LL | let _ = if let Some(x) = Some(99) { x } else { i32::default() };
87+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `Some(99).unwrap_or_default()`
88+
89+
error: aborting due to 10 previous errors
6690

0 commit comments

Comments
 (0)