Skip to content

Commit eba5886

Browse files
committed
manual-unwrap-or / pr remarks
1 parent 816a08c commit eba5886

File tree

8 files changed

+101
-79
lines changed

8 files changed

+101
-79
lines changed

CHANGELOG.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1781,7 +1781,6 @@ Released 2018-09-13
17811781
[`large_stack_arrays`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_arrays
17821782
[`len_without_is_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_without_is_empty
17831783
[`len_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_zero
1784-
[`less_concise_than_option_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#less_concise_than_option_unwrap_or
17851784
[`let_and_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return
17861785
[`let_underscore_lock`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_lock
17871786
[`let_underscore_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_must_use
@@ -1797,6 +1796,7 @@ Released 2018-09-13
17971796
[`manual_saturating_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_saturating_arithmetic
17981797
[`manual_strip`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip
17991798
[`manual_swap`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_swap
1799+
[`manual_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_unwrap_or
18001800
[`many_single_char_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#many_single_char_names
18011801
[`map_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_clone
18021802
[`map_entry`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_entry

clippy_lints/src/lib.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,6 @@ mod large_const_arrays;
224224
mod large_enum_variant;
225225
mod large_stack_arrays;
226226
mod len_zero;
227-
mod less_concise_than;
228227
mod let_if_seq;
229228
mod let_underscore;
230229
mod lifetimes;
@@ -235,6 +234,7 @@ mod main_recursion;
235234
mod manual_async_fn;
236235
mod manual_non_exhaustive;
237236
mod manual_strip;
237+
mod manual_unwrap_or;
238238
mod map_clone;
239239
mod map_err_ignore;
240240
mod map_identity;
@@ -609,7 +609,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
609609
&large_stack_arrays::LARGE_STACK_ARRAYS,
610610
&len_zero::LEN_WITHOUT_IS_EMPTY,
611611
&len_zero::LEN_ZERO,
612-
&less_concise_than::LESS_CONCISE_THAN_OPTION_UNWRAP_OR,
613612
&let_if_seq::USELESS_LET_IF_SEQ,
614613
&let_underscore::LET_UNDERSCORE_LOCK,
615614
&let_underscore::LET_UNDERSCORE_MUST_USE,
@@ -641,6 +640,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
641640
&manual_async_fn::MANUAL_ASYNC_FN,
642641
&manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE,
643642
&manual_strip::MANUAL_STRIP,
643+
&manual_unwrap_or::MANUAL_UNWRAP_OR,
644644
&map_clone::MAP_CLONE,
645645
&map_err_ignore::MAP_ERR_IGNORE,
646646
&map_identity::MAP_IDENTITY,
@@ -1127,7 +1127,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
11271127
store.register_late_pass(|| box repeat_once::RepeatOnce);
11281128
store.register_late_pass(|| box unwrap_in_result::UnwrapInResult);
11291129
store.register_late_pass(|| box self_assignment::SelfAssignment);
1130-
store.register_late_pass(|| box less_concise_than::LessConciseThan);
1130+
store.register_late_pass(|| box manual_unwrap_or::ManualUnwrapOr);
11311131
store.register_late_pass(|| box float_equality_without_abs::FloatEqualityWithoutAbs);
11321132
store.register_late_pass(|| box async_yields_async::AsyncYieldsAsync);
11331133
store.register_late_pass(|| box manual_strip::ManualStrip);
@@ -1212,7 +1212,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
12121212
LintId::of(&infinite_iter::MAYBE_INFINITE_ITER),
12131213
LintId::of(&items_after_statements::ITEMS_AFTER_STATEMENTS),
12141214
LintId::of(&large_stack_arrays::LARGE_STACK_ARRAYS),
1215-
LintId::of(&less_concise_than::LESS_CONCISE_THAN_OPTION_UNWRAP_OR),
12161215
LintId::of(&literal_representation::LARGE_DIGIT_GROUPS),
12171216
LintId::of(&literal_representation::UNREADABLE_LITERAL),
12181217
LintId::of(&loops::EXPLICIT_INTO_ITER_LOOP),
@@ -1369,6 +1368,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
13691368
LintId::of(&manual_async_fn::MANUAL_ASYNC_FN),
13701369
LintId::of(&manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
13711370
LintId::of(&manual_strip::MANUAL_STRIP),
1371+
LintId::of(&manual_unwrap_or::MANUAL_UNWRAP_OR),
13721372
LintId::of(&map_clone::MAP_CLONE),
13731373
LintId::of(&map_identity::MAP_IDENTITY),
13741374
LintId::of(&map_unit_fn::OPTION_MAP_UNIT_FN),
@@ -1663,6 +1663,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
16631663
LintId::of(&loops::MUT_RANGE_BOUND),
16641664
LintId::of(&loops::WHILE_LET_LOOP),
16651665
LintId::of(&manual_strip::MANUAL_STRIP),
1666+
LintId::of(&manual_unwrap_or::MANUAL_UNWRAP_OR),
16661667
LintId::of(&map_identity::MAP_IDENTITY),
16671668
LintId::of(&map_unit_fn::OPTION_MAP_UNIT_FN),
16681669
LintId::of(&map_unit_fn::RESULT_MAP_UNIT_FN),

clippy_lints/src/manual_unwrap_or.rs

+59-54
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@ use crate::utils;
22
use if_chain::if_chain;
33
use rustc_errors::Applicability;
44
use rustc_hir::{def, Arm, Expr, ExprKind, PatKind, QPath};
5+
use rustc_lint::LintContext;
56
use rustc_lint::{LateContext, LateLintPass};
7+
use rustc_middle::lint::in_external_macro;
68
use rustc_session::{declare_lint_pass, declare_tool_lint};
79

810
declare_clippy_lint! {
911
/// **What it does:**
10-
/// Finds patterns that can be encoded more concisely with `Option::unwrap_or`.
12+
/// Finds patterns that reimplement `Option::unwrap_or`.
1113
///
1214
/// **Why is this bad?**
1315
/// Concise code helps focusing on behavior instead of boilerplate.
@@ -16,47 +18,43 @@ declare_clippy_lint! {
1618
///
1719
/// **Example:**
1820
/// ```rust
19-
/// match int_optional {
21+
/// match int_option {
2022
/// Some(v) => v,
2123
/// None => 1,
2224
/// }
2325
/// ```
2426
///
2527
/// Use instead:
2628
/// ```rust
27-
/// int_optional.unwrap_or(1)
29+
/// int_option.unwrap_or(1)
2830
/// ```
29-
pub LESS_CONCISE_THAN_OPTION_UNWRAP_OR,
30-
pedantic,
31-
"finds patterns that can be encoded more concisely with `Option::unwrap_or`"
31+
pub MANUAL_UNWRAP_OR,
32+
complexity,
33+
"finds patterns that can be encoded more concisely with `Option::unwrap_or(_else)`"
3234
}
3335

34-
declare_lint_pass!(LessConciseThan => [LESS_CONCISE_THAN_OPTION_UNWRAP_OR]);
36+
declare_lint_pass!(ManualUnwrapOr => [MANUAL_UNWRAP_OR]);
3537

36-
impl LateLintPass<'_> for LessConciseThan {
38+
impl LateLintPass<'_> for ManualUnwrapOr {
3739
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
38-
if utils::in_macro(expr.span) {
39-
return;
40-
}
41-
if lint_option_unwrap_or_case(cx, expr) {
40+
if in_external_macro(cx.sess(), expr.span) {
4241
return;
4342
}
43+
lint_option_unwrap_or_case(cx, expr);
4444
}
4545
}
4646

4747
fn lint_option_unwrap_or_case<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
48-
#[allow(clippy::needless_bool)]
4948
fn applicable_none_arm<'a>(arms: &'a [Arm<'a>]) -> Option<&'a Arm<'a>> {
5049
if_chain! {
5150
if arms.len() == 2;
5251
if arms.iter().all(|arm| arm.guard.is_none());
5352
if let Some((idx, none_arm)) = arms.iter().enumerate().find(|(_, arm)|
54-
if_chain! {
55-
if let PatKind::Path(ref qpath) = arm.pat.kind;
56-
if utils::match_qpath(qpath, &utils::paths::OPTION_NONE);
57-
then { true }
58-
else { false }
59-
}
53+
if let PatKind::Path(ref qpath) = arm.pat.kind {
54+
utils::match_qpath(qpath, &utils::paths::OPTION_NONE)
55+
} else {
56+
false
57+
}
6058
);
6159
let some_arm = &arms[1 - idx];
6260
if let PatKind::TupleStruct(ref some_qpath, &[some_binding], _) = some_arm.pat.kind;
@@ -65,43 +63,50 @@ fn lint_option_unwrap_or_case<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tc
6563
if let ExprKind::Path(QPath::Resolved(_, body_path)) = some_arm.body.kind;
6664
if let def::Res::Local(body_path_hir_id) = body_path.res;
6765
if body_path_hir_id == binding_hir_id;
68-
then { Some(none_arm) }
69-
else { None }
66+
if !utils::usage::contains_return_break_continue_macro(none_arm.body);
67+
then {
68+
Some(none_arm)
69+
}
70+
else {
71+
None
72+
}
7073
}
7174
}
75+
7276
if_chain! {
73-
if !utils::usage::contains_return_break_continue_macro(expr);
74-
if let ExprKind::Match (match_expr, match_arms, _) = expr.kind;
75-
let ty = cx.typeck_results().expr_ty(match_expr);
76-
if utils::is_type_diagnostic_item(cx, ty, sym!(option_type));
77-
if let Some(none_arm) = applicable_none_arm(match_arms);
78-
if let Some(match_expr_snippet) = utils::snippet_opt(cx, match_expr.span);
79-
if let Some(none_body_snippet) = utils::snippet_opt(cx, none_arm.body.span);
80-
if let Some(indent) = utils::indent_of(cx, expr.span);
81-
then {
82-
let reindented_none_body =
83-
utils::reindent_multiline(none_body_snippet.into(), true, Some(indent));
84-
let eager_eval = utils::eager_or_lazy::is_eagerness_candidate(cx, none_arm.body);
85-
let method = if eager_eval {
86-
"unwrap_or"
87-
} else {
88-
"unwrap_or_else"
89-
};
90-
utils::span_lint_and_sugg(
91-
cx,
92-
LESS_CONCISE_THAN_OPTION_UNWRAP_OR, expr.span,
93-
"this pattern can be more concisely encoded with `Option::unwrap_or`",
94-
"replace with",
95-
format!(
96-
"{}.{}({}{})",
97-
match_expr_snippet,
98-
method,
99-
if eager_eval { ""} else { "|| " },
100-
reindented_none_body
101-
),
102-
Applicability::MachineApplicable,
103-
);
104-
true
105-
} else { false}
77+
if let ExprKind::Match(scrutinee, match_arms, _) = expr.kind;
78+
let ty = cx.typeck_results().expr_ty(scrutinee);
79+
if utils::is_type_diagnostic_item(cx, ty, sym!(option_type));
80+
if let Some(none_arm) = applicable_none_arm(match_arms);
81+
if let Some(scrutinee_snippet) = utils::snippet_opt(cx, scrutinee.span);
82+
if let Some(none_body_snippet) = utils::snippet_opt(cx, none_arm.body.span);
83+
if let Some(indent) = utils::indent_of(cx, expr.span);
84+
then {
85+
let reindented_none_body =
86+
utils::reindent_multiline(none_body_snippet.into(), true, Some(indent));
87+
let eager_eval = utils::eager_or_lazy::is_eagerness_candidate(cx, none_arm.body);
88+
let method = if eager_eval {
89+
"unwrap_or"
90+
} else {
91+
"unwrap_or_else"
92+
};
93+
utils::span_lint_and_sugg(
94+
cx,
95+
MANUAL_UNWRAP_OR, expr.span,
96+
&format!("this pattern reimplements `Option::{}`", &method),
97+
"replace with",
98+
format!(
99+
"{}.{}({}{})",
100+
scrutinee_snippet,
101+
method,
102+
if eager_eval { ""} else { "|| " },
103+
reindented_none_body
104+
),
105+
Applicability::MachineApplicable,
106+
);
107+
true
108+
} else {
109+
false
110+
}
106111
}
107112
}

src/lintlist/mod.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -1074,13 +1074,6 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
10741074
deprecation: None,
10751075
module: "len_zero",
10761076
},
1077-
Lint {
1078-
name: "less_concise_than_option_unwrap_or",
1079-
group: "pedantic",
1080-
desc: "finds patterns that can be encoded more concisely with `Option::unwrap_or`",
1081-
deprecation: None,
1082-
module: "less_concise_than",
1083-
},
10841077
Lint {
10851078
name: "let_and_return",
10861079
group: "style",
@@ -1186,6 +1179,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
11861179
deprecation: None,
11871180
module: "swap",
11881181
},
1182+
Lint {
1183+
name: "manual_unwrap_or",
1184+
group: "complexity",
1185+
desc: "finds patterns that can be encoded more concisely with `Option::unwrap_or(_else)`",
1186+
deprecation: None,
1187+
module: "manual_unwrap_or",
1188+
},
11891189
Lint {
11901190
name: "many_single_char_names",
11911191
group: "style",

tests/ui/less_concise_than.fixed tests/ui/manual_unwrap_or.fixed

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
// run-rustfix
2-
#![warn(clippy::less_concise_than_option_unwrap_or)]
32
#![allow(dead_code)]
43

54
fn unwrap_or() {
65
// int case
76
Some(1).unwrap_or(42);
87

8+
// int case reversed
9+
Some(1).unwrap_or(42);
10+
911
// richer none expr
1012
Some(1).unwrap_or_else(|| 1 + 42);
1113

tests/ui/less_concise_than.rs tests/ui/manual_unwrap_or.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
// run-rustfix
2-
#![warn(clippy::less_concise_than_option_unwrap_or)]
32
#![allow(dead_code)]
43

54
fn unwrap_or() {
@@ -9,6 +8,12 @@ fn unwrap_or() {
98
None => 42,
109
};
1110

11+
// int case reversed
12+
match Some(1) {
13+
None => 42,
14+
Some(i) => i,
15+
};
16+
1217
// richer none expr
1318
match Some(1) {
1419
Some(i) => i,

tests/ui/less_concise_than.stderr tests/ui/manual_unwrap_or.stderr

+19-10
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,34 @@
1-
error: this pattern can be more concisely encoded with `Option::unwrap_or`
2-
--> $DIR/less_concise_than.rs:7:5
1+
error: this pattern reimplements `Option::unwrap_or`
2+
--> $DIR/manual_unwrap_or.rs:6:5
33
|
44
LL | / match Some(1) {
55
LL | | Some(i) => i,
66
LL | | None => 42,
77
LL | | };
88
| |_____^ help: replace with: `Some(1).unwrap_or(42)`
99
|
10-
= note: `-D clippy::less-concise-than-option-unwrap-or` implied by `-D warnings`
10+
= note: `-D clippy::manual-unwrap-or` implied by `-D warnings`
1111

12-
error: this pattern can be more concisely encoded with `Option::unwrap_or`
13-
--> $DIR/less_concise_than.rs:13:5
12+
error: this pattern reimplements `Option::unwrap_or`
13+
--> $DIR/manual_unwrap_or.rs:12:5
14+
|
15+
LL | / match Some(1) {
16+
LL | | None => 42,
17+
LL | | Some(i) => i,
18+
LL | | };
19+
| |_____^ help: replace with: `Some(1).unwrap_or(42)`
20+
21+
error: this pattern reimplements `Option::unwrap_or_else`
22+
--> $DIR/manual_unwrap_or.rs:18:5
1423
|
1524
LL | / match Some(1) {
1625
LL | | Some(i) => i,
1726
LL | | None => 1 + 42,
1827
LL | | };
1928
| |_____^ help: replace with: `Some(1).unwrap_or_else(|| 1 + 42)`
2029

21-
error: this pattern can be more concisely encoded with `Option::unwrap_or`
22-
--> $DIR/less_concise_than.rs:19:5
30+
error: this pattern reimplements `Option::unwrap_or_else`
31+
--> $DIR/manual_unwrap_or.rs:24:5
2332
|
2433
LL | / match Some(1) {
2534
LL | | Some(i) => i,
@@ -39,14 +48,14 @@ LL | b + 42
3948
LL | });
4049
|
4150

42-
error: this pattern can be more concisely encoded with `Option::unwrap_or`
43-
--> $DIR/less_concise_than.rs:29:5
51+
error: this pattern reimplements `Option::unwrap_or`
52+
--> $DIR/manual_unwrap_or.rs:34:5
4453
|
4554
LL | / match Some("Bob") {
4655
LL | | Some(i) => i,
4756
LL | | None => "Alice",
4857
LL | | };
4958
| |_____^ help: replace with: `Some("Bob").unwrap_or("Alice")`
5059

51-
error: aborting due to 4 previous errors
60+
error: aborting due to 5 previous errors
5261

tests/ui/shadow.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
#![allow(
99
unused_parens,
1010
unused_variables,
11-
clippy::less_concise_than_option_unwrap_or,
11+
clippy::manual_unwrap_or,
1212
clippy::missing_docs_in_private_items,
1313
clippy::single_match
1414
)]

0 commit comments

Comments
 (0)