Skip to content

Commit de03a05

Browse files
committed
unnecessary_map_or: lint .map_or(true, …) as well
1 parent ca963b6 commit de03a05

File tree

5 files changed

+75
-17
lines changed

5 files changed

+75
-17
lines changed

clippy_lints/src/methods/mod.rs

+13-5
Original file line numberDiff line numberDiff line change
@@ -4107,24 +4107,32 @@ declare_clippy_lint! {
41074107
/// ### Why is this bad?
41084108
/// Calls such as `opt.map_or(false, |val| val == 5)` are needlessly long and cumbersome,
41094109
/// and can be reduced to, for example, `opt == Some(5)` assuming `opt` implements `PartialEq`.
4110+
/// Also, calls such as `opt.map_or(true, |val| val == 5)` can be reduced to
4111+
/// `opt.is_none_or(|val| val == 5)`.
41104112
/// This lint offers readability and conciseness improvements.
41114113
///
41124114
/// ### Example
41134115
/// ```no_run
4114-
/// pub fn a(x: Option<i32>) -> bool {
4115-
/// x.map_or(false, |n| n == 5)
4116+
/// pub fn a(x: Option<i32>) -> (bool, bool) {
4117+
/// (
4118+
/// x.map_or(false, |n| n == 5),
4119+
/// x.map_or(true, |n| n > 5),
4120+
/// )
41164121
/// }
41174122
/// ```
41184123
/// Use instead:
41194124
/// ```no_run
4120-
/// pub fn a(x: Option<i32>) -> bool {
4121-
/// x == Some(5)
4125+
/// pub fn a(x: Option<i32>) -> (bool, bool) {
4126+
/// (
4127+
/// x == Some(5),
4128+
/// x.is_none_or(|n| n > 5),
4129+
/// )
41224130
/// }
41234131
/// ```
41244132
#[clippy::version = "1.75.0"]
41254133
pub UNNECESSARY_MAP_OR,
41264134
style,
4127-
"reduce unnecessary pattern matching for constructs that implement `PartialEq`"
4135+
"reduce unnecessary calls to `.map_or(bool, …)`"
41284136
}
41294137

41304138
declare_clippy_lint! {

clippy_lints/src/methods/unnecessary_map_or.rs

+15-3
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ pub(super) fn check<'a>(
6060
Some(_) | None => return,
6161
};
6262

63-
let (sugg, method) = if let ExprKind::Closure(map_closure) = map.kind
63+
let (sugg, method, applicability) = if let ExprKind::Closure(map_closure) = map.kind
6464
&& let closure_body = cx.tcx.hir().body(map_closure.body)
6565
&& let closure_body_value = closure_body.value.peel_blocks()
6666
&& let ExprKind::Binary(op, l, r) = closure_body_value.kind
@@ -100,7 +100,7 @@ pub(super) fn check<'a>(
100100
.maybe_par()
101101
.into_string();
102102

103-
(binop, "a standard comparison")
103+
(binop, "a standard comparison", Applicability::MaybeIncorrect)
104104
} else if !def_bool
105105
&& msrv.meets(msrvs::OPTION_RESULT_IS_VARIANT_AND)
106106
&& let Some(recv_callsite) = snippet_opt(cx, recv.span.source_callsite())
@@ -110,6 +110,18 @@ pub(super) fn check<'a>(
110110
(
111111
format!("{recv_callsite}.{suggested_name}({span_callsite})",),
112112
suggested_name,
113+
Applicability::MachineApplicable,
114+
)
115+
} else if def_bool
116+
&& matches!(variant, Variant::Some)
117+
&& msrv.meets(msrvs::IS_NONE_OR)
118+
&& let Some(recv_callsite) = snippet_opt(cx, recv.span.source_callsite())
119+
&& let Some(span_callsite) = snippet_opt(cx, map.span.source_callsite())
120+
{
121+
(
122+
format!("{recv_callsite}.is_none_or({span_callsite})"),
123+
"is_none_or",
124+
Applicability::MachineApplicable,
113125
)
114126
} else {
115127
return;
@@ -126,6 +138,6 @@ pub(super) fn check<'a>(
126138
"this `map_or` is redundant",
127139
format!("use {method} instead"),
128140
sugg,
129-
Applicability::MaybeIncorrect,
141+
applicability,
130142
);
131143
}

tests/ui/unnecessary_map_or.fixed

+13-3
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,9 @@ fn main() {
2323
let _ = Ok::<Vec<i32>, i32>(vec![5]).is_ok_and(|n| n == [5]);
2424
let _ = (Ok::<i32, i32>(5) == Ok(5));
2525
let _ = (Some(5) == Some(5)).then(|| 1);
26+
let _ = Some(5).is_none_or(|n| n == 5);
27+
let _ = Some(5).is_none_or(|n| 5 == n);
2628

27-
// shouldnt trigger
28-
let _ = Some(5).map_or(true, |n| n == 5);
29-
let _ = Some(5).map_or(true, |n| 5 == n);
3029
macro_rules! x {
3130
() => {
3231
Some(1)
@@ -56,15 +55,26 @@ fn main() {
5655
let r: Result<i32, S> = Ok(3);
5756
let _ = r.is_ok_and(func);
5857
let _ = Some(5).is_some_and(func);
58+
let _ = Some(5).is_none_or(func);
5959

6060
#[derive(PartialEq)]
6161
struct S2;
6262
let r: Result<i32, S2> = Ok(4);
6363
let _ = (r == Ok(8));
64+
65+
// do not lint `Result::map_or(true, …)`
66+
let r: Result<i32, S2> = Ok(4);
67+
let _ = r.map_or(true, |x| x == 8);
6468
}
6569

6670
#[clippy::msrv = "1.69.0"]
6771
fn msrv_1_69() {
6872
// is_some_and added in 1.70.0
6973
let _ = Some(5).map_or(false, |n| n == if 2 > 1 { n } else { 0 });
7074
}
75+
76+
#[clippy::msrv = "1.81.0"]
77+
fn msrv_1_81() {
78+
// is_none_or added in 1.82.0
79+
let _ = Some(5).map_or(true, |n| n == if 2 > 1 { n } else { 0 });
80+
}

tests/ui/unnecessary_map_or.rs

+12-2
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,9 @@ fn main() {
2626
let _ = Ok::<Vec<i32>, i32>(vec![5]).map_or(false, |n| n == [5]);
2727
let _ = Ok::<i32, i32>(5).map_or(false, |n| n == 5);
2828
let _ = Some(5).map_or(false, |n| n == 5).then(|| 1);
29-
30-
// shouldnt trigger
3129
let _ = Some(5).map_or(true, |n| n == 5);
3230
let _ = Some(5).map_or(true, |n| 5 == n);
31+
3332
macro_rules! x {
3433
() => {
3534
Some(1)
@@ -59,15 +58,26 @@ fn main() {
5958
let r: Result<i32, S> = Ok(3);
6059
let _ = r.map_or(false, func);
6160
let _ = Some(5).map_or(false, func);
61+
let _ = Some(5).map_or(true, func);
6262

6363
#[derive(PartialEq)]
6464
struct S2;
6565
let r: Result<i32, S2> = Ok(4);
6666
let _ = r.map_or(false, |x| x == 8);
67+
68+
// do not lint `Result::map_or(true, …)`
69+
let r: Result<i32, S2> = Ok(4);
70+
let _ = r.map_or(true, |x| x == 8);
6771
}
6872

6973
#[clippy::msrv = "1.69.0"]
7074
fn msrv_1_69() {
7175
// is_some_and added in 1.70.0
7276
let _ = Some(5).map_or(false, |n| n == if 2 > 1 { n } else { 0 });
7377
}
78+
79+
#[clippy::msrv = "1.81.0"]
80+
fn msrv_1_81() {
81+
// is_none_or added in 1.82.0
82+
let _ = Some(5).map_or(true, |n| n == if 2 > 1 { n } else { 0 });
83+
}

tests/ui/unnecessary_map_or.stderr

+22-4
Original file line numberDiff line numberDiff line change
@@ -84,28 +84,46 @@ LL | let _ = Some(5).map_or(false, |n| n == 5).then(|| 1);
8484
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(Some(5) == Some(5))`
8585

8686
error: this `map_or` is redundant
87-
--> tests/ui/unnecessary_map_or.rs:55:13
87+
--> tests/ui/unnecessary_map_or.rs:29:13
88+
|
89+
LL | let _ = Some(5).map_or(true, |n| n == 5);
90+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_none_or instead: `Some(5).is_none_or(|n| n == 5)`
91+
92+
error: this `map_or` is redundant
93+
--> tests/ui/unnecessary_map_or.rs:30:13
94+
|
95+
LL | let _ = Some(5).map_or(true, |n| 5 == n);
96+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_none_or instead: `Some(5).is_none_or(|n| 5 == n)`
97+
98+
error: this `map_or` is redundant
99+
--> tests/ui/unnecessary_map_or.rs:54:13
88100
|
89101
LL | let _ = r.map_or(false, |x| x == 7);
90102
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_ok_and instead: `r.is_ok_and(|x| x == 7)`
91103

92104
error: this `map_or` is redundant
93-
--> tests/ui/unnecessary_map_or.rs:60:13
105+
--> tests/ui/unnecessary_map_or.rs:59:13
94106
|
95107
LL | let _ = r.map_or(false, func);
96108
| ^^^^^^^^^^^^^^^^^^^^^ help: use is_ok_and instead: `r.is_ok_and(func)`
97109

98110
error: this `map_or` is redundant
99-
--> tests/ui/unnecessary_map_or.rs:61:13
111+
--> tests/ui/unnecessary_map_or.rs:60:13
100112
|
101113
LL | let _ = Some(5).map_or(false, func);
102114
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_some_and instead: `Some(5).is_some_and(func)`
103115

116+
error: this `map_or` is redundant
117+
--> tests/ui/unnecessary_map_or.rs:61:13
118+
|
119+
LL | let _ = Some(5).map_or(true, func);
120+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_none_or instead: `Some(5).is_none_or(func)`
121+
104122
error: this `map_or` is redundant
105123
--> tests/ui/unnecessary_map_or.rs:66:13
106124
|
107125
LL | let _ = r.map_or(false, |x| x == 8);
108126
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(r == Ok(8))`
109127

110-
error: aborting due to 15 previous errors
128+
error: aborting due to 18 previous errors
111129

0 commit comments

Comments
 (0)