Skip to content

Commit 9135923

Browse files
authored
trigger obfuscated_if_else for .then(..).unwrap_or(..) (rust-lang#14021)
part of rust-lang#9100 The `obfuscated_if_else` lint currently only triggers for the pattern `.then_some(..).unwrap_or(..)`, but there're other cases where this lint should be triggered, one of which is `.then(..).unwrap_or(..)`. changelog: [`obfuscated_if_else`]: trigger lint for the `.then(..).unwrap_or(..)` pattern as well
2 parents 4825666 + db97768 commit 9135923

File tree

5 files changed

+58
-15
lines changed

5 files changed

+58
-15
lines changed

clippy_lints/src/methods/mod.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -2418,14 +2418,14 @@ declare_clippy_lint! {
24182418

24192419
declare_clippy_lint! {
24202420
/// ### What it does
2421-
/// Checks for usage of `.then_some(..).unwrap_or(..)`
2421+
/// Checks for unnecessary method chains that can be simplified into `if .. else ..`.
24222422
///
24232423
/// ### Why is this bad?
24242424
/// This can be written more clearly with `if .. else ..`
24252425
///
24262426
/// ### Limitations
24272427
/// This lint currently only looks for usages of
2428-
/// `.then_some(..).unwrap_or(..)`, but will be expanded
2428+
/// `.then_some(..).unwrap_or(..)` and `.then(..).unwrap_or(..)`, but will be expanded
24292429
/// to account for similar patterns.
24302430
///
24312431
/// ### Example
@@ -5276,8 +5276,8 @@ impl Methods {
52765276
Some(("map", m_recv, [m_arg], span, _)) => {
52775277
option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span, &self.msrv);
52785278
},
5279-
Some(("then_some", t_recv, [t_arg], _, _)) => {
5280-
obfuscated_if_else::check(cx, expr, t_recv, t_arg, u_arg);
5279+
Some((then_method @ ("then" | "then_some"), t_recv, [t_arg], _, _)) => {
5280+
obfuscated_if_else::check(cx, expr, t_recv, t_arg, u_arg, then_method);
52815281
},
52825282
_ => {},
52835283
}

clippy_lints/src/methods/obfuscated_if_else.rs

+15-8
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
use super::OBFUSCATED_IF_ELSE;
22
use clippy_utils::diagnostics::span_lint_and_sugg;
33
use clippy_utils::source::snippet_with_applicability;
4+
use clippy_utils::sugg::Sugg;
45
use rustc_errors::Applicability;
56
use rustc_hir as hir;
7+
use rustc_hir::ExprKind;
68
use rustc_lint::LateContext;
79

810
pub(super) fn check<'tcx>(
@@ -11,28 +13,33 @@ pub(super) fn check<'tcx>(
1113
then_recv: &'tcx hir::Expr<'_>,
1214
then_arg: &'tcx hir::Expr<'_>,
1315
unwrap_arg: &'tcx hir::Expr<'_>,
16+
then_method_name: &str,
1417
) {
15-
// something.then_some(blah).unwrap_or(blah)
16-
// ^^^^^^^^^-then_recv ^^^^-then_arg ^^^^- unwrap_arg
17-
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- expr
18-
1918
let recv_ty = cx.typeck_results().expr_ty(then_recv);
2019

2120
if recv_ty.is_bool() {
2221
let mut applicability = Applicability::MachineApplicable;
22+
let if_then = match then_method_name {
23+
"then" if let ExprKind::Closure(closure) = then_arg.kind => {
24+
let body = cx.tcx.hir().body(closure.body);
25+
snippet_with_applicability(cx, body.value.span, "..", &mut applicability)
26+
},
27+
"then_some" => snippet_with_applicability(cx, then_arg.span, "..", &mut applicability),
28+
_ => String::new().into(),
29+
};
30+
2331
let sugg = format!(
2432
"if {} {{ {} }} else {{ {} }}",
25-
snippet_with_applicability(cx, then_recv.span, "..", &mut applicability),
26-
snippet_with_applicability(cx, then_arg.span, "..", &mut applicability),
33+
Sugg::hir_with_applicability(cx, then_recv, "..", &mut applicability),
34+
if_then,
2735
snippet_with_applicability(cx, unwrap_arg.span, "..", &mut applicability)
2836
);
2937

3038
span_lint_and_sugg(
3139
cx,
3240
OBFUSCATED_IF_ELSE,
3341
expr.span,
34-
"use of `.then_some(..).unwrap_or(..)` can be written \
35-
more clearly with `if .. else ..`",
42+
"this method chain can be written more clearly with `if .. else ..`",
3643
"try",
3744
sugg,
3845
applicability,

tests/ui/obfuscated_if_else.fixed

+9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
#![warn(clippy::obfuscated_if_else)]
2+
#![allow(clippy::unnecessary_lazy_evaluations)]
23

34
fn main() {
45
if true { "a" } else { "b" };
6+
if true { "a" } else { "b" };
7+
8+
let a = 1;
9+
if a == 1 { "a" } else { "b" };
10+
if a == 1 { "a" } else { "b" };
11+
12+
let partial = (a == 1).then_some("a");
13+
partial.unwrap_or("b"); // not lint
514
}

tests/ui/obfuscated_if_else.rs

+9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
#![warn(clippy::obfuscated_if_else)]
2+
#![allow(clippy::unnecessary_lazy_evaluations)]
23

34
fn main() {
45
true.then_some("a").unwrap_or("b");
6+
true.then(|| "a").unwrap_or("b");
7+
8+
let a = 1;
9+
(a == 1).then_some("a").unwrap_or("b");
10+
(a == 1).then(|| "a").unwrap_or("b");
11+
12+
let partial = (a == 1).then_some("a");
13+
partial.unwrap_or("b"); // not lint
514
}

tests/ui/obfuscated_if_else.stderr

+21-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,29 @@
1-
error: use of `.then_some(..).unwrap_or(..)` can be written more clearly with `if .. else ..`
2-
--> tests/ui/obfuscated_if_else.rs:4:5
1+
error: this method chain can be written more clearly with `if .. else ..`
2+
--> tests/ui/obfuscated_if_else.rs:5:5
33
|
44
LL | true.then_some("a").unwrap_or("b");
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { "a" } else { "b" }`
66
|
77
= note: `-D clippy::obfuscated-if-else` implied by `-D warnings`
88
= help: to override `-D warnings` add `#[allow(clippy::obfuscated_if_else)]`
99

10-
error: aborting due to 1 previous error
10+
error: this method chain can be written more clearly with `if .. else ..`
11+
--> tests/ui/obfuscated_if_else.rs:6:5
12+
|
13+
LL | true.then(|| "a").unwrap_or("b");
14+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { "a" } else { "b" }`
15+
16+
error: this method chain can be written more clearly with `if .. else ..`
17+
--> tests/ui/obfuscated_if_else.rs:9:5
18+
|
19+
LL | (a == 1).then_some("a").unwrap_or("b");
20+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if a == 1 { "a" } else { "b" }`
21+
22+
error: this method chain can be written more clearly with `if .. else ..`
23+
--> tests/ui/obfuscated_if_else.rs:10:5
24+
|
25+
LL | (a == 1).then(|| "a").unwrap_or("b");
26+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if a == 1 { "a" } else { "b" }`
27+
28+
error: aborting due to 4 previous errors
1129

0 commit comments

Comments
 (0)