Skip to content

Commit ee5e1da

Browse files
committed
Add new lint then_some_unwrap_or
New lint suggests using `if .. else ..` instead of `.then_some(..).unwrap_or(..)`.
1 parent 7ea4592 commit ee5e1da

9 files changed

+99
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3925,6 +3925,7 @@ Released 2018-09-13
39253925
[`tabs_in_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#tabs_in_doc_comments
39263926
[`temporary_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_assignment
39273927
[`temporary_cstring_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_cstring_as_ptr
3928+
[`then_some_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#then_some_unwrap_or
39283929
[`to_digit_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_digit_is_some
39293930
[`to_string_in_display`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_in_display
39303931
[`to_string_in_format_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_in_format_args

clippy_lints/src/lib.register_all.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
203203
LintId::of(methods::STRING_EXTEND_CHARS),
204204
LintId::of(methods::SUSPICIOUS_MAP),
205205
LintId::of(methods::SUSPICIOUS_SPLITN),
206+
LintId::of(methods::THEN_SOME_UNWRAP_OR),
206207
LintId::of(methods::UNINIT_ASSUMED_INIT),
207208
LintId::of(methods::UNNECESSARY_FILTER_MAP),
208209
LintId::of(methods::UNNECESSARY_FIND_MAP),

clippy_lints/src/lib.register_lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,7 @@ store.register_lints(&[
345345
methods::STRING_EXTEND_CHARS,
346346
methods::SUSPICIOUS_MAP,
347347
methods::SUSPICIOUS_SPLITN,
348+
methods::THEN_SOME_UNWRAP_OR,
348349
methods::UNINIT_ASSUMED_INIT,
349350
methods::UNNECESSARY_FILTER_MAP,
350351
methods::UNNECESSARY_FIND_MAP,

clippy_lints/src/lib.register_style.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![
7676
LintId::of(methods::SHOULD_IMPLEMENT_TRAIT),
7777
LintId::of(methods::SINGLE_CHAR_ADD_STR),
7878
LintId::of(methods::STRING_EXTEND_CHARS),
79+
LintId::of(methods::THEN_SOME_UNWRAP_OR),
7980
LintId::of(methods::UNNECESSARY_FOLD),
8081
LintId::of(methods::UNNECESSARY_LAZY_EVALUATIONS),
8182
LintId::of(methods::UNWRAP_OR_ELSE_DEFAULT),

clippy_lints/src/methods/mod.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ mod str_splitn;
6262
mod string_extend_chars;
6363
mod suspicious_map;
6464
mod suspicious_splitn;
65+
mod then_some_unwrap_or;
6566
mod uninit_assumed_init;
6667
mod unnecessary_filter_map;
6768
mod unnecessary_fold;
@@ -2259,6 +2260,30 @@ declare_clippy_lint! {
22592260
"replace with no effect"
22602261
}
22612262

2263+
declare_clippy_lint! {
2264+
/// ### What it does
2265+
/// Checks for usages of `.then_some(..).unwrap_or(..)`
2266+
///
2267+
/// ### Why is this bad?
2268+
/// This can be written more clearly with `if .. else ..`
2269+
///
2270+
/// ### Example
2271+
/// ```rust
2272+
/// let x = true;
2273+
/// x.then_some("a").unwrap_or("b");
2274+
/// ```
2275+
/// Use instead:
2276+
/// ```rust
2277+
/// let x = true;
2278+
/// if x { "a" } else { "b" };
2279+
/// ```
2280+
#[clippy::version = "1.64.0"]
2281+
pub THEN_SOME_UNWRAP_OR,
2282+
style,
2283+
"use of `.then_some(..).unwrap_or(..)` can be written \
2284+
more clearly with `if .. else ..`"
2285+
}
2286+
22622287
pub struct Methods {
22632288
avoid_breaking_exported_api: bool,
22642289
msrv: Option<RustcVersion>,
@@ -2360,6 +2385,7 @@ impl_lint_pass!(Methods => [
23602385
IS_DIGIT_ASCII_RADIX,
23612386
NEEDLESS_OPTION_TAKE,
23622387
NO_EFFECT_REPLACE,
2388+
THEN_SOME_UNWRAP_OR,
23632389
]);
23642390

23652391
/// Extracts a method call name, args, and `Span` of the method name.
@@ -2768,6 +2794,9 @@ impl Methods {
27682794
Some(("map", [m_recv, m_arg], span)) => {
27692795
option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span);
27702796
},
2797+
Some(("then_some", [t_recv, t_arg], _)) => {
2798+
then_some_unwrap_or::check(cx, expr, t_recv, t_arg, u_arg);
2799+
},
27712800
_ => {},
27722801
},
27732802
("unwrap_or_else", [u_arg]) => match method_call(recv) {
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// run-rustfix
2+
3+
use super::THEN_SOME_UNWRAP_OR;
4+
use clippy_utils::{diagnostics::span_lint_and_sugg, source::snippet_with_applicability};
5+
use rustc_errors::Applicability;
6+
use rustc_hir as hir;
7+
use rustc_lint::LateContext;
8+
9+
pub(super) fn check<'tcx>(
10+
cx: &LateContext<'tcx>,
11+
expr: &'tcx hir::Expr<'_>,
12+
then_recv: &'tcx hir::Expr<'_>,
13+
then_arg: &'tcx hir::Expr<'_>,
14+
unwrap_arg: &'tcx hir::Expr<'_>,
15+
) {
16+
// something.then_some(blah).unwrap_or(blah)
17+
// ^^^^^^^^^-then_recv ^^^^-then_arg ^^^^- unwrap_arg
18+
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- expr
19+
20+
let recv_ty = cx.typeck_results().expr_ty(then_recv);
21+
22+
if recv_ty.is_bool() {
23+
let mut applicability = Applicability::MachineApplicable;
24+
let sugg = format!(
25+
"if {} {{ {} }} else {{ {} }}",
26+
snippet_with_applicability(cx, then_recv.span, "..", &mut applicability),
27+
snippet_with_applicability(cx, then_arg.span, "..", &mut applicability),
28+
snippet_with_applicability(cx, unwrap_arg.span, "..", &mut applicability)
29+
);
30+
31+
span_lint_and_sugg(
32+
cx,
33+
THEN_SOME_UNWRAP_OR,
34+
expr.span,
35+
"use of `.then_some(..).unwrap_or(..)` can be written \
36+
more clearly with `if .. else ..`",
37+
"try",
38+
sugg,
39+
applicability,
40+
);
41+
}
42+
}

tests/ui/then_some_unwrap_or.fixed

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// run-rustfix
2+
3+
#![warn(clippy::then_some_unwrap_or)]
4+
5+
fn main() {
6+
if true { "a" } else { "b" };
7+
}

tests/ui/then_some_unwrap_or.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// run-rustfix
2+
3+
#![warn(clippy::then_some_unwrap_or)]
4+
5+
fn main() {
6+
true.then_some("a").unwrap_or("b");
7+
}

tests/ui/then_some_unwrap_or.stderr

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
error: use of `.then_some(..).unwrap_or(..)` can be written more clearly with `if .. else ..`
2+
--> $DIR/then_some_unwrap_or.rs:6:5
3+
|
4+
LL | true.then_some("a").unwrap_or("b");
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { "a" } else { "b" }`
6+
|
7+
= note: `-D clippy::then-some-unwrap-or` implied by `-D warnings`
8+
9+
error: aborting due to previous error
10+

0 commit comments

Comments
 (0)