Skip to content

Commit 0fb004d

Browse files
authored
extend obfuscated_if_else to support {then(), then_some()}.unwrap_or_else() (rust-lang#14165)
These method chains can be expressed concisely with `if`/`else`. changelog: [`obfuscated_if_else`]: support `then().unwrap_or_else()` and `then_some().unwrap_or_else()`
2 parents 0fa1706 + 6c6ffd2 commit 0fb004d

File tree

5 files changed

+111
-20
lines changed

5 files changed

+111
-20
lines changed

clippy_lints/src/methods/mod.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -5423,7 +5423,7 @@ impl Methods {
54235423
option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span, &self.msrv);
54245424
},
54255425
Some((then_method @ ("then" | "then_some"), t_recv, [t_arg], _, _)) => {
5426-
obfuscated_if_else::check(cx, expr, t_recv, t_arg, u_arg, then_method);
5426+
obfuscated_if_else::check(cx, expr, t_recv, t_arg, u_arg, then_method, "unwrap_or");
54275427
},
54285428
_ => {},
54295429
}
@@ -5442,6 +5442,9 @@ impl Methods {
54425442
match method_call(recv) {
54435443
Some(("map", recv, [map_arg], _, _))
54445444
if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, &self.msrv) => {},
5445+
Some((then_method @ ("then" | "then_some"), t_recv, [t_arg], _, _)) => {
5446+
obfuscated_if_else::check(cx, expr, t_recv, t_arg, u_arg, then_method, "unwrap_or_else");
5447+
},
54455448
_ => {
54465449
unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or");
54475450
},

clippy_lints/src/methods/obfuscated_if_else.rs

+16-2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ pub(super) fn check<'tcx>(
1616
then_arg: &'tcx hir::Expr<'_>,
1717
unwrap_arg: &'tcx hir::Expr<'_>,
1818
then_method_name: &str,
19+
unwrap_method_name: &str,
1920
) {
2021
let recv_ty = cx.typeck_results().expr_ty(then_recv);
2122

@@ -32,14 +33,27 @@ pub(super) fn check<'tcx>(
3233
snippet_with_applicability(cx, body.value.span, "..", &mut applicability)
3334
},
3435
"then_some" => snippet_with_applicability(cx, then_arg.span, "..", &mut applicability),
35-
_ => String::new().into(),
36+
_ => return,
37+
};
38+
39+
// FIXME: Add `unwrap_or_else` symbol
40+
let els = match unwrap_method_name {
41+
"unwrap_or" => snippet_with_applicability(cx, unwrap_arg.span, "..", &mut applicability),
42+
"unwrap_or_else" if let ExprKind::Closure(closure) = unwrap_arg.kind => {
43+
let body = cx.tcx.hir_body(closure.body);
44+
snippet_with_applicability(cx, body.value.span, "..", &mut applicability)
45+
},
46+
"unwrap_or_else" if let ExprKind::Path(_) = unwrap_arg.kind => {
47+
snippet_with_applicability(cx, unwrap_arg.span, "_", &mut applicability) + "()"
48+
},
49+
_ => return,
3650
};
3751

3852
let sugg = format!(
3953
"if {} {{ {} }} else {{ {} }}",
4054
Sugg::hir_with_applicability(cx, then_recv, "..", &mut applicability),
4155
if_then,
42-
snippet_with_applicability(cx, unwrap_arg.span, "..", &mut applicability)
56+
els
4357
);
4458

4559
// To be parsed as an expression, the `if { … } else { … }` as the left operand of a binary operator

tests/ui/obfuscated_if_else.fixed

+23-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
#![warn(clippy::obfuscated_if_else)]
2-
#![allow(clippy::unnecessary_lazy_evaluations, clippy::unit_arg, clippy::unused_unit)]
2+
#![allow(
3+
clippy::unnecessary_lazy_evaluations,
4+
clippy::unit_arg,
5+
clippy::unused_unit,
6+
clippy::unwrap_or_default
7+
)]
38

49
fn main() {
510
if true { "a" } else { "b" };
@@ -24,6 +29,23 @@ fn main() {
2429

2530
if true { () } else { a += 2 };
2631
//~^ obfuscated_if_else
32+
33+
let mut n = 1;
34+
if true { n = 1 } else { n = 2 };
35+
//~^ obfuscated_if_else
36+
if true { 1 } else { n * 2 };
37+
//~^ obfuscated_if_else
38+
if true { n += 1 } else { () };
39+
//~^ obfuscated_if_else
40+
41+
let _ = if true { 1 } else { n * 2 };
42+
//~^ obfuscated_if_else
43+
44+
if true { 1 } else { Default::default() };
45+
//~^ obfuscated_if_else
46+
47+
let partial = true.then_some(1);
48+
partial.unwrap_or_else(|| n * 2); // not lint
2749
}
2850

2951
fn issue11141() {

tests/ui/obfuscated_if_else.rs

+23-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
#![warn(clippy::obfuscated_if_else)]
2-
#![allow(clippy::unnecessary_lazy_evaluations, clippy::unit_arg, clippy::unused_unit)]
2+
#![allow(
3+
clippy::unnecessary_lazy_evaluations,
4+
clippy::unit_arg,
5+
clippy::unused_unit,
6+
clippy::unwrap_or_default
7+
)]
38

49
fn main() {
510
true.then_some("a").unwrap_or("b");
@@ -24,6 +29,23 @@ fn main() {
2429

2530
true.then_some(()).unwrap_or(a += 2);
2631
//~^ obfuscated_if_else
32+
33+
let mut n = 1;
34+
true.then(|| n = 1).unwrap_or_else(|| n = 2);
35+
//~^ obfuscated_if_else
36+
true.then_some(1).unwrap_or_else(|| n * 2);
37+
//~^ obfuscated_if_else
38+
true.then_some(n += 1).unwrap_or_else(|| ());
39+
//~^ obfuscated_if_else
40+
41+
let _ = true.then_some(1).unwrap_or_else(|| n * 2);
42+
//~^ obfuscated_if_else
43+
44+
true.then_some(1).unwrap_or_else(Default::default);
45+
//~^ obfuscated_if_else
46+
47+
let partial = true.then_some(1);
48+
partial.unwrap_or_else(|| n * 2); // not lint
2749
}
2850

2951
fn issue11141() {

tests/ui/obfuscated_if_else.stderr

+45-15
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: this method chain can be written more clearly with `if .. else ..`
2-
--> tests/ui/obfuscated_if_else.rs:5:5
2+
--> tests/ui/obfuscated_if_else.rs:10:5
33
|
44
LL | true.then_some("a").unwrap_or("b");
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { "a" } else { "b" }`
@@ -8,82 +8,112 @@ LL | true.then_some("a").unwrap_or("b");
88
= help: to override `-D warnings` add `#[allow(clippy::obfuscated_if_else)]`
99

1010
error: this method chain can be written more clearly with `if .. else ..`
11-
--> tests/ui/obfuscated_if_else.rs:8:5
11+
--> tests/ui/obfuscated_if_else.rs:13:5
1212
|
1313
LL | true.then(|| "a").unwrap_or("b");
1414
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { "a" } else { "b" }`
1515

1616
error: this method chain can be written more clearly with `if .. else ..`
17-
--> tests/ui/obfuscated_if_else.rs:12:5
17+
--> tests/ui/obfuscated_if_else.rs:17:5
1818
|
1919
LL | (a == 1).then_some("a").unwrap_or("b");
2020
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if a == 1 { "a" } else { "b" }`
2121

2222
error: this method chain can be written more clearly with `if .. else ..`
23-
--> tests/ui/obfuscated_if_else.rs:15:5
23+
--> tests/ui/obfuscated_if_else.rs:20:5
2424
|
2525
LL | (a == 1).then(|| "a").unwrap_or("b");
2626
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if a == 1 { "a" } else { "b" }`
2727

2828
error: this method chain can be written more clearly with `if .. else ..`
29-
--> tests/ui/obfuscated_if_else.rs:22:5
29+
--> tests/ui/obfuscated_if_else.rs:27:5
3030
|
3131
LL | true.then_some(a += 1).unwrap_or(());
3232
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { a += 1 } else { () }`
3333

3434
error: this method chain can be written more clearly with `if .. else ..`
35-
--> tests/ui/obfuscated_if_else.rs:25:5
35+
--> tests/ui/obfuscated_if_else.rs:30:5
3636
|
3737
LL | true.then_some(()).unwrap_or(a += 2);
3838
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { () } else { a += 2 }`
3939

4040
error: this method chain can be written more clearly with `if .. else ..`
41-
--> tests/ui/obfuscated_if_else.rs:31:13
41+
--> tests/ui/obfuscated_if_else.rs:34:5
42+
|
43+
LL | true.then(|| n = 1).unwrap_or_else(|| n = 2);
44+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { n = 1 } else { n = 2 }`
45+
46+
error: this method chain can be written more clearly with `if .. else ..`
47+
--> tests/ui/obfuscated_if_else.rs:36:5
48+
|
49+
LL | true.then_some(1).unwrap_or_else(|| n * 2);
50+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { 1 } else { n * 2 }`
51+
52+
error: this method chain can be written more clearly with `if .. else ..`
53+
--> tests/ui/obfuscated_if_else.rs:38:5
54+
|
55+
LL | true.then_some(n += 1).unwrap_or_else(|| ());
56+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { n += 1 } else { () }`
57+
58+
error: this method chain can be written more clearly with `if .. else ..`
59+
--> tests/ui/obfuscated_if_else.rs:41:13
60+
|
61+
LL | let _ = true.then_some(1).unwrap_or_else(|| n * 2);
62+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { 1 } else { n * 2 }`
63+
64+
error: this method chain can be written more clearly with `if .. else ..`
65+
--> tests/ui/obfuscated_if_else.rs:44:5
66+
|
67+
LL | true.then_some(1).unwrap_or_else(Default::default);
68+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { 1 } else { Default::default() }`
69+
70+
error: this method chain can be written more clearly with `if .. else ..`
71+
--> tests/ui/obfuscated_if_else.rs:53:13
4272
|
4373
LL | let _ = true.then_some(40).unwrap_or(17) | 2;
4474
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(if true { 40 } else { 17 })`
4575

4676
error: this method chain can be written more clearly with `if .. else ..`
47-
--> tests/ui/obfuscated_if_else.rs:35:13
77+
--> tests/ui/obfuscated_if_else.rs:57:13
4878
|
4979
LL | let _ = true.then_some(30).unwrap_or(17) | true.then_some(2).unwrap_or(3) | true.then_some(10).unwrap_or(1);
5080
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(if true { 30 } else { 17 })`
5181

5282
error: this method chain can be written more clearly with `if .. else ..`
53-
--> tests/ui/obfuscated_if_else.rs:35:48
83+
--> tests/ui/obfuscated_if_else.rs:57:48
5484
|
5585
LL | let _ = true.then_some(30).unwrap_or(17) | true.then_some(2).unwrap_or(3) | true.then_some(10).unwrap_or(1);
5686
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { 2 } else { 3 }`
5787

5888
error: this method chain can be written more clearly with `if .. else ..`
59-
--> tests/ui/obfuscated_if_else.rs:35:81
89+
--> tests/ui/obfuscated_if_else.rs:57:81
6090
|
6191
LL | let _ = true.then_some(30).unwrap_or(17) | true.then_some(2).unwrap_or(3) | true.then_some(10).unwrap_or(1);
6292
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { 10 } else { 1 }`
6393

6494
error: this method chain can be written more clearly with `if .. else ..`
65-
--> tests/ui/obfuscated_if_else.rs:41:17
95+
--> tests/ui/obfuscated_if_else.rs:63:17
6696
|
6797
LL | let _ = 2 | true.then_some(40).unwrap_or(17);
6898
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { 40 } else { 17 }`
6999

70100
error: this method chain can be written more clearly with `if .. else ..`
71-
--> tests/ui/obfuscated_if_else.rs:45:13
101+
--> tests/ui/obfuscated_if_else.rs:67:13
72102
|
73103
LL | let _ = true.then_some(42).unwrap_or(17) as u8;
74104
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { 42 } else { 17 }`
75105

76106
error: this method chain can be written more clearly with `if .. else ..`
77-
--> tests/ui/obfuscated_if_else.rs:49:14
107+
--> tests/ui/obfuscated_if_else.rs:71:14
78108
|
79109
LL | let _ = *true.then_some(&42).unwrap_or(&17);
80110
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { &42 } else { &17 }`
81111

82112
error: this method chain can be written more clearly with `if .. else ..`
83-
--> tests/ui/obfuscated_if_else.rs:53:14
113+
--> tests/ui/obfuscated_if_else.rs:75:14
84114
|
85115
LL | let _ = *true.then_some(&42).unwrap_or(&17) as u8;
86116
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { &42 } else { &17 }`
87117

88-
error: aborting due to 14 previous errors
118+
error: aborting due to 19 previous errors
89119

0 commit comments

Comments
 (0)