Skip to content

Commit 5750e46

Browse files
committed
fix [manual_unwrap_or_default] suggestion ignoring side-effects
1 parent 124e68b commit 5750e46

File tree

3 files changed

+76
-8
lines changed

3 files changed

+76
-8
lines changed

clippy_lints/src/manual_unwrap_or_default.rs

+18-8
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@ use clippy_utils::sugg::Sugg;
22
use rustc_errors::Applicability;
33
use rustc_hir::def::Res;
44
use rustc_hir::{Arm, Expr, ExprKind, HirId, LangItem, MatchSource, Pat, PatKind, QPath};
5-
use rustc_lint::{LateContext, LateLintPass};
5+
use rustc_lint::{LateContext, LateLintPass, LintContext};
66
use rustc_session::declare_lint_pass;
77
use rustc_span::sym;
88

99
use clippy_utils::diagnostics::span_lint_and_sugg;
1010
use clippy_utils::source::snippet_opt;
1111
use clippy_utils::ty::implements_trait;
12-
use clippy_utils::{in_constant, is_default_equivalent};
12+
use clippy_utils::{in_constant, is_default_equivalent, peel_blocks, span_contains_comment};
1313

1414
declare_clippy_lint! {
1515
/// ### What it does
@@ -119,22 +119,27 @@ fn handle_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
119119
// We now get the bodies for both the `Some` and `None` arms.
120120
&& let Some(((body_some, binding_id), body_none)) = get_some_and_none_bodies(cx, arm1, arm2)
121121
// We check that the `Some(x) => x` doesn't do anything apart "returning" the value in `Some`.
122-
&& let ExprKind::Path(QPath::Resolved(_, path)) = body_some.peel_blocks().kind
122+
&& let ExprKind::Path(QPath::Resolved(_, path)) = peel_blocks(body_some).kind
123123
&& let Res::Local(local_id) = path.res
124124
&& local_id == binding_id
125125
// We now check the `None` arm is calling a method equivalent to `Default::default`.
126-
&& let body_none = body_none.peel_blocks()
126+
&& let body_none = peel_blocks(body_none)
127127
&& is_default_equivalent(cx, body_none)
128128
&& let Some(receiver) = Sugg::hir_opt(cx, match_expr).map(Sugg::maybe_par)
129129
{
130+
let applicability = if span_contains_comment(cx.sess().source_map(), expr.span) {
131+
Applicability::MaybeIncorrect
132+
} else {
133+
Applicability::MachineApplicable
134+
};
130135
span_lint_and_sugg(
131136
cx,
132137
MANUAL_UNWRAP_OR_DEFAULT,
133138
expr.span,
134139
"match can be simplified with `.unwrap_or_default()`",
135140
"replace it with",
136141
format!("{receiver}.unwrap_or_default()"),
137-
Applicability::MachineApplicable,
142+
applicability,
138143
);
139144
}
140145
true
@@ -150,22 +155,27 @@ fn handle_if_let<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
150155
&& implements_trait(cx, match_ty, default_trait_id, &[])
151156
&& let Some(binding_id) = get_some(cx, let_.pat)
152157
// We check that the `Some(x) => x` doesn't do anything apart "returning" the value in `Some`.
153-
&& let ExprKind::Path(QPath::Resolved(_, path)) = if_block.peel_blocks().kind
158+
&& let ExprKind::Path(QPath::Resolved(_, path)) = peel_blocks(if_block).kind
154159
&& let Res::Local(local_id) = path.res
155160
&& local_id == binding_id
156161
// We now check the `None` arm is calling a method equivalent to `Default::default`.
157-
&& let body_else = else_expr.peel_blocks()
162+
&& let body_else = peel_blocks(else_expr)
158163
&& is_default_equivalent(cx, body_else)
159164
&& let Some(if_let_expr_snippet) = snippet_opt(cx, let_.init.span)
160165
{
166+
let applicability = if span_contains_comment(cx.sess().source_map(), expr.span) {
167+
Applicability::MaybeIncorrect
168+
} else {
169+
Applicability::MachineApplicable
170+
};
161171
span_lint_and_sugg(
162172
cx,
163173
MANUAL_UNWRAP_OR_DEFAULT,
164174
expr.span,
165175
"if let can be simplified with `.unwrap_or_default()`",
166176
"replace it with",
167177
format!("{if_let_expr_snippet}.unwrap_or_default()"),
168-
Applicability::MachineApplicable,
178+
applicability,
169179
);
170180
}
171181
}

tests/ui/manual_unwrap_or_default.fixed

+29
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,32 @@ const fn issue_12568(opt: Option<bool>) -> bool {
3333
None => false,
3434
}
3535
}
36+
37+
fn issue_12569() {
38+
let match_none_se = match 1u32.checked_div(0) {
39+
Some(v) => v,
40+
None => {
41+
println!("important");
42+
0
43+
},
44+
};
45+
let match_some_se = match 1u32.checked_div(0) {
46+
Some(v) => {
47+
println!("important");
48+
v
49+
},
50+
None => 0,
51+
};
52+
let iflet_else_se = if let Some(v) = 1u32.checked_div(0) {
53+
v
54+
} else {
55+
println!("important");
56+
0
57+
};
58+
let iflet_then_se = if let Some(v) = 1u32.checked_div(0) {
59+
println!("important");
60+
v
61+
} else {
62+
0
63+
};
64+
}

tests/ui/manual_unwrap_or_default.rs

+29
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,32 @@ const fn issue_12568(opt: Option<bool>) -> bool {
5757
None => false,
5858
}
5959
}
60+
61+
fn issue_12569() {
62+
let match_none_se = match 1u32.checked_div(0) {
63+
Some(v) => v,
64+
None => {
65+
println!("important");
66+
0
67+
},
68+
};
69+
let match_some_se = match 1u32.checked_div(0) {
70+
Some(v) => {
71+
println!("important");
72+
v
73+
},
74+
None => 0,
75+
};
76+
let iflet_else_se = if let Some(v) = 1u32.checked_div(0) {
77+
v
78+
} else {
79+
println!("important");
80+
0
81+
};
82+
let iflet_then_se = if let Some(v) = 1u32.checked_div(0) {
83+
println!("important");
84+
v
85+
} else {
86+
0
87+
};
88+
}

0 commit comments

Comments
 (0)