Add lint unnecessary_option_map_or_else (#14662)

changelog: [`unnecessary_option_map_or_else`]: Added lint
unnecessary_option_map_or_else. As suggested in the issue description,
the implementation takes as reference the issue
rust-lang/rust-clippy#7328. The tests for lints `option_if_let_else` and
`or_fun_call` needed to be adjusted to comply with new lint.
fixes rust-lang/rust-clippy#14588
This commit is contained in:
llogiq 2025-10-09 21:56:14 +00:00 committed by GitHub
commit e6febbd13b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 428 additions and 80 deletions

View file

@ -6897,6 +6897,7 @@ Released 2018-09-13
[`unnecessary_min_or_max`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_min_or_max
[`unnecessary_mut_passed`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_mut_passed
[`unnecessary_operation`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_operation
[`unnecessary_option_map_or_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_option_map_or_else
[`unnecessary_owned_empty_strings`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_owned_empty_strings
[`unnecessary_result_map_or_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_result_map_or_else
[`unnecessary_safety_comment`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_safety_comment

View file

@ -488,6 +488,7 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[
crate::methods::UNNECESSARY_LITERAL_UNWRAP_INFO,
crate::methods::UNNECESSARY_MAP_OR_INFO,
crate::methods::UNNECESSARY_MIN_OR_MAX_INFO,
crate::methods::UNNECESSARY_OPTION_MAP_OR_ELSE_INFO,
crate::methods::UNNECESSARY_RESULT_MAP_OR_ELSE_INFO,
crate::methods::UNNECESSARY_SORT_BY_INFO,
crate::methods::UNNECESSARY_TO_OWNED_INFO,

View file

@ -133,6 +133,7 @@ mod unnecessary_lazy_eval;
mod unnecessary_literal_unwrap;
mod unnecessary_map_or;
mod unnecessary_min_or_max;
mod unnecessary_option_map_or_else;
mod unnecessary_result_map_or_else;
mod unnecessary_sort_by;
mod unnecessary_to_owned;
@ -4639,6 +4640,30 @@ declare_clippy_lint! {
"detects redundant calls to `Iterator::cloned`"
}
declare_clippy_lint! {
/// Checks for usage of `.map_or_else()` "map closure" for `Option` type.
///
/// ### Why is this bad?
/// This can be written more concisely by using `unwrap_or_else()`.
///
/// ### Example
/// ```no_run
/// let k = 10;
/// let x: Option<u32> = Some(4);
/// let y = x.map_or_else(|| 2 * k, |n| n);
/// ```
/// Use instead:
/// ```no_run
/// let k = 10;
/// let x: Option<u32> = Some(4);
/// let y = x.unwrap_or_else(|| 2 * k);
/// ```
#[clippy::version = "1.88.0"]
pub UNNECESSARY_OPTION_MAP_OR_ELSE,
suspicious,
"making no use of the \"map closure\" when calling `.map_or_else(|| 2 * k, |n| n)`"
}
#[expect(clippy::struct_excessive_bools)]
pub struct Methods {
avoid_breaking_exported_api: bool,
@ -4820,6 +4845,7 @@ impl_lint_pass!(Methods => [
SWAP_WITH_TEMPORARY,
IP_CONSTANT,
REDUNDANT_ITER_CLONED,
UNNECESSARY_OPTION_MAP_OR_ELSE,
]);
/// Extracts a method call name, args, and `Span` of the method name.
@ -5275,6 +5301,7 @@ impl Methods {
},
(sym::map_or_else, [def, map]) => {
result_map_or_else_none::check(cx, expr, recv, def, map);
unnecessary_option_map_or_else::check(cx, expr, recv, def, map);
unnecessary_result_map_or_else::check(cx, expr, recv, def, map);
},
(sym::next, []) => {

View file

@ -0,0 +1,111 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{expr_or_init, find_binding_init, peel_blocks};
use rustc_errors::Applicability;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::{Body, BodyId, Closure, Expr, ExprKind, HirId, QPath};
use rustc_lint::LateContext;
use rustc_span::symbol::sym;
use super::UNNECESSARY_OPTION_MAP_OR_ELSE;
use super::utils::get_last_chain_binding_hir_id;
fn emit_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, def_arg: &Expr<'_>) {
let msg = "unused \"map closure\" when calling `Option::map_or_else` value";
let mut applicability = Applicability::MachineApplicable;
let self_snippet = snippet_with_applicability(cx, recv.span, "_", &mut applicability);
let err_snippet = snippet_with_applicability(cx, def_arg.span, "..", &mut applicability);
span_lint_and_sugg(
cx,
UNNECESSARY_OPTION_MAP_OR_ELSE,
expr.span,
msg,
"consider using `unwrap_or_else`",
format!("{self_snippet}.unwrap_or_else({err_snippet})"),
Applicability::MachineApplicable,
);
}
fn handle_qpath(
cx: &LateContext<'_>,
expr: &Expr<'_>,
recv: &Expr<'_>,
def_arg: &Expr<'_>,
expected_hir_id: HirId,
qpath: QPath<'_>,
) {
if let QPath::Resolved(_, path) = qpath
&& let Res::Local(hir_id) = path.res
&& expected_hir_id == hir_id
{
emit_lint(cx, expr, recv, def_arg);
}
}
fn handle_closure(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, def_arg: &Expr<'_>, body_id: BodyId) {
let body = cx.tcx.hir_body(body_id);
handle_fn_body(cx, expr, recv, def_arg, body);
}
fn handle_fn_body(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, def_arg: &Expr<'_>, body: &Body<'_>) {
if let Some(first_param) = body.params.first() {
let body_expr = peel_blocks(body.value);
match body_expr.kind {
ExprKind::Path(qpath) => {
handle_qpath(cx, expr, recv, def_arg, first_param.pat.hir_id, qpath);
},
// If this is a block (that wasn't peeled off), then it means there are statements.
ExprKind::Block(block, _) => {
if let Some(block_expr) = block.expr
// First we ensure that this is a "binding chain" (each statement is a binding
// of the previous one) and that it is a binding of the closure argument.
&& let Some(last_chain_binding_id) =
get_last_chain_binding_hir_id(first_param.pat.hir_id, block.stmts)
&& let ExprKind::Path(qpath) = block_expr.kind
{
handle_qpath(cx, expr, recv, def_arg, last_chain_binding_id, qpath);
}
},
_ => {},
}
}
}
/// lint use of `_.map_or_else(|err| err, |n| n)` for `Option`s.
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, def_arg: &Expr<'_>, map_arg: &Expr<'_>) {
// lint if the caller of `map_or_else()` is an `Option`
if !is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Option) {
return;
}
match map_arg.kind {
// If the second argument is a closure, we can check its body.
ExprKind::Closure(&Closure { body, .. }) => {
handle_closure(cx, expr, recv, def_arg, body);
},
ExprKind::Path(qpath) => {
let res = cx.qpath_res(&qpath, map_arg.hir_id);
match res {
// Case 1: Local variable (could be a closure)
Res::Local(hir_id) => {
if let Some(init_expr) = find_binding_init(cx, hir_id) {
let origin = expr_or_init(cx, init_expr);
if let ExprKind::Closure(&Closure { body, .. }) = origin.kind {
handle_closure(cx, expr, recv, def_arg, body);
}
}
},
// Case 2: Function definition
Res::Def(DefKind::Fn, def_id) => {
if let Some(local_def_id) = def_id.as_local()
&& let Some(body) = cx.tcx.hir_maybe_body_owned_by(local_def_id)
{
handle_fn_body(cx, expr, recv, def_arg, body);
}
},
_ => (),
}
},
_ => (),
}
}

View file

@ -6,7 +6,8 @@
clippy::redundant_locals,
clippy::manual_midpoint,
clippy::manual_unwrap_or_default,
clippy::manual_unwrap_or
clippy::manual_unwrap_or,
clippy::unnecessary_option_map_or_else
)]
fn bad1(string: Option<&str>) -> (bool, &str) {

View file

@ -6,7 +6,8 @@
clippy::redundant_locals,
clippy::manual_midpoint,
clippy::manual_unwrap_or_default,
clippy::manual_unwrap_or
clippy::manual_unwrap_or,
clippy::unnecessary_option_map_or_else
)]
fn bad1(string: Option<&str>) -> (bool, &str) {

View file

@ -1,5 +1,5 @@
error: use Option::map_or instead of an if let/else
--> tests/ui/option_if_let_else.rs:13:5
--> tests/ui/option_if_let_else.rs:14:5
|
LL | / if let Some(x) = string {
LL | |
@ -13,19 +13,19 @@ LL | | }
= help: to override `-D warnings` add `#[allow(clippy::option_if_let_else)]`
error: use Option::map_or instead of an if let/else
--> tests/ui/option_if_let_else.rs:32:13
--> tests/ui/option_if_let_else.rs:33:13
|
LL | let _ = if let Some(s) = *string { s.len() } else { 0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `string.map_or(0, |s| s.len())`
error: use Option::map_or instead of an if let/else
--> tests/ui/option_if_let_else.rs:34:13
--> tests/ui/option_if_let_else.rs:35:13
|
LL | let _ = if let Some(s) = &num { s } else { &0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)`
error: use Option::map_or instead of an if let/else
--> tests/ui/option_if_let_else.rs:36:13
--> tests/ui/option_if_let_else.rs:37:13
|
LL | let _ = if let Some(s) = &mut num {
| _____________^
@ -47,13 +47,13 @@ LL ~ });
|
error: use Option::map_or instead of an if let/else
--> tests/ui/option_if_let_else.rs:43:13
--> tests/ui/option_if_let_else.rs:44:13
|
LL | let _ = if let Some(ref s) = num { s } else { &0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)`
error: use Option::map_or instead of an if let/else
--> tests/ui/option_if_let_else.rs:45:13
--> tests/ui/option_if_let_else.rs:46:13
|
LL | let _ = if let Some(mut s) = num {
| _____________^
@ -75,7 +75,7 @@ LL ~ });
|
error: use Option::map_or instead of an if let/else
--> tests/ui/option_if_let_else.rs:52:13
--> tests/ui/option_if_let_else.rs:53:13
|
LL | let _ = if let Some(ref mut s) = num {
| _____________^
@ -97,7 +97,7 @@ LL ~ });
|
error: use Option::map_or instead of an if let/else
--> tests/ui/option_if_let_else.rs:62:5
--> tests/ui/option_if_let_else.rs:63:5
|
LL | / if let Some(x) = arg {
LL | |
@ -118,7 +118,7 @@ LL + })
|
error: use Option::map_or_else instead of an if let/else
--> tests/ui/option_if_let_else.rs:76:13
--> tests/ui/option_if_let_else.rs:77:13
|
LL | let _ = if let Some(x) = arg {
| _____________^
@ -131,7 +131,7 @@ LL | | };
| |_____^ help: try: `arg.map_or_else(side_effect, |x| x)`
error: use Option::map_or_else instead of an if let/else
--> tests/ui/option_if_let_else.rs:86:13
--> tests/ui/option_if_let_else.rs:87:13
|
LL | let _ = if let Some(x) = arg {
| _____________^
@ -154,7 +154,7 @@ LL ~ }, |x| x * x * x * x);
|
error: use Option::map_or_else instead of an if let/else
--> tests/ui/option_if_let_else.rs:120:13
--> tests/ui/option_if_let_else.rs:121:13
|
LL | / if let Some(idx) = s.find('.') {
LL | |
@ -165,7 +165,7 @@ LL | | }
| |_____________^ help: try: `s.find('.').map_or_else(|| vec![s.to_string()], |idx| vec![s[..idx].to_string(), s[idx..].to_string()])`
error: use Option::map_or_else instead of an if let/else
--> tests/ui/option_if_let_else.rs:132:5
--> tests/ui/option_if_let_else.rs:133:5
|
LL | / if let Ok(binding) = variable {
LL | |
@ -189,7 +189,7 @@ LL + })
|
error: use Option::map_or_else instead of an if let/else
--> tests/ui/option_if_let_else.rs:157:5
--> tests/ui/option_if_let_else.rs:158:5
|
LL | / match r {
LL | |
@ -199,7 +199,7 @@ LL | | }
| |_____^ help: try: `r.map_or_else(|_| Vec::new(), |s| s.to_owned())`
error: use Option::map_or_else instead of an if let/else
--> tests/ui/option_if_let_else.rs:166:5
--> tests/ui/option_if_let_else.rs:167:5
|
LL | / if let Ok(s) = r { s.to_owned() }
LL | |
@ -207,13 +207,13 @@ LL | | else { Vec::new() }
| |_______________________^ help: try: `r.map_or_else(|_| Vec::new(), |s| s.to_owned())`
error: use Option::map_or instead of an if let/else
--> tests/ui/option_if_let_else.rs:173:13
--> tests/ui/option_if_let_else.rs:174:13
|
LL | let _ = if let Some(x) = optional { x + 2 } else { 5 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `optional.map_or(5, |x| x + 2)`
error: use Option::map_or instead of an if let/else
--> tests/ui/option_if_let_else.rs:184:13
--> tests/ui/option_if_let_else.rs:185:13
|
LL | let _ = if let Some(x) = Some(0) {
| _____________^
@ -235,13 +235,13 @@ LL ~ });
|
error: use Option::map_or instead of an if let/else
--> tests/ui/option_if_let_else.rs:213:13
--> tests/ui/option_if_let_else.rs:214:13
|
LL | let _ = if let Some(x) = Some(0) { s.len() + x } else { s.len() };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(0).map_or(s.len(), |x| s.len() + x)`
error: use Option::map_or instead of an if let/else
--> tests/ui/option_if_let_else.rs:218:13
--> tests/ui/option_if_let_else.rs:219:13
|
LL | let _ = if let Some(x) = Some(0) {
| _____________^
@ -263,7 +263,7 @@ LL ~ });
|
error: use Option::map_or instead of an if let/else
--> tests/ui/option_if_let_else.rs:258:13
--> tests/ui/option_if_let_else.rs:259:13
|
LL | let _ = match s {
| _____________^
@ -274,7 +274,7 @@ LL | | };
| |_____^ help: try: `s.map_or(1, |string| string.len())`
error: use Option::map_or instead of an if let/else
--> tests/ui/option_if_let_else.rs:263:13
--> tests/ui/option_if_let_else.rs:264:13
|
LL | let _ = match Some(10) {
| _____________^
@ -285,7 +285,7 @@ LL | | };
| |_____^ help: try: `Some(10).map_or(5, |a| a + 1)`
error: use Option::map_or instead of an if let/else
--> tests/ui/option_if_let_else.rs:270:13
--> tests/ui/option_if_let_else.rs:271:13
|
LL | let _ = match res {
| _____________^
@ -296,7 +296,7 @@ LL | | };
| |_____^ help: try: `res.map_or(1, |a| a + 1)`
error: use Option::map_or instead of an if let/else
--> tests/ui/option_if_let_else.rs:275:13
--> tests/ui/option_if_let_else.rs:276:13
|
LL | let _ = match res {
| _____________^
@ -307,13 +307,13 @@ LL | | };
| |_____^ help: try: `res.map_or(1, |a| a + 1)`
error: use Option::map_or instead of an if let/else
--> tests/ui/option_if_let_else.rs:280:13
--> tests/ui/option_if_let_else.rs:281:13
|
LL | let _ = if let Ok(a) = res { a + 1 } else { 5 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `res.map_or(5, |a| a + 1)`
error: use Option::map_or instead of an if let/else
--> tests/ui/option_if_let_else.rs:298:17
--> tests/ui/option_if_let_else.rs:299:17
|
LL | let _ = match initial {
| _________________^
@ -324,7 +324,7 @@ LL | | };
| |_________^ help: try: `initial.as_ref().map_or(42, |value| do_something(value))`
error: use Option::map_or instead of an if let/else
--> tests/ui/option_if_let_else.rs:306:17
--> tests/ui/option_if_let_else.rs:307:17
|
LL | let _ = match initial {
| _________________^
@ -335,7 +335,7 @@ LL | | };
| |_________^ help: try: `initial.as_mut().map_or(42, |value| do_something2(value))`
error: use Option::map_or_else instead of an if let/else
--> tests/ui/option_if_let_else.rs:330:24
--> tests/ui/option_if_let_else.rs:331:24
|
LL | let mut _hashmap = if let Some(hm) = &opt {
| ________________________^
@ -347,19 +347,19 @@ LL | | };
| |_____^ help: try: `opt.as_ref().map_or_else(HashMap::new, |hm| hm.clone())`
error: use Option::map_or_else instead of an if let/else
--> tests/ui/option_if_let_else.rs:337:19
--> tests/ui/option_if_let_else.rs:338:19
|
LL | let mut _hm = if let Some(hm) = &opt { hm.clone() } else { new_map!() };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.as_ref().map_or_else(|| new_map!(), |hm| hm.clone())`
error: use Option::map_or instead of an if let/else
--> tests/ui/option_if_let_else.rs:388:22
--> tests/ui/option_if_let_else.rs:389:22
|
LL | let _ = unsafe { if let Some(o) = *opt_raw_ptr { o } else { 1 } };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(*opt_raw_ptr).map_or(1, |o| o)`
error: use Option::map_or_else instead of an if let/else
--> tests/ui/option_if_let_else.rs:394:13
--> tests/ui/option_if_let_else.rs:395:13
|
LL | let _ = match res {
| _____________^

View file

@ -5,6 +5,7 @@
clippy::unnecessary_wraps,
clippy::unnecessary_literal_unwrap,
clippy::unnecessary_result_map_or_else,
clippy::unnecessary_option_map_or_else,
clippy::useless_vec
)]

View file

@ -5,6 +5,7 @@
clippy::unnecessary_wraps,
clippy::unnecessary_literal_unwrap,
clippy::unnecessary_result_map_or_else,
clippy::unnecessary_option_map_or_else,
clippy::useless_vec
)]

View file

@ -1,5 +1,5 @@
error: function call inside of `unwrap_or`
--> tests/ui/or_fun_call.rs:52:22
--> tests/ui/or_fun_call.rs:53:22
|
LL | with_constructor.unwrap_or(make());
| ^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(make)`
@ -8,7 +8,7 @@ LL | with_constructor.unwrap_or(make());
= help: to override `-D warnings` add `#[allow(clippy::or_fun_call)]`
error: use of `unwrap_or` to construct default value
--> tests/ui/or_fun_call.rs:56:14
--> tests/ui/or_fun_call.rs:57:14
|
LL | with_new.unwrap_or(Vec::new());
| ^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
@ -17,205 +17,205 @@ LL | with_new.unwrap_or(Vec::new());
= help: to override `-D warnings` add `#[allow(clippy::unwrap_or_default)]`
error: function call inside of `unwrap_or`
--> tests/ui/or_fun_call.rs:60:21
--> tests/ui/or_fun_call.rs:61:21
|
LL | with_const_args.unwrap_or(Vec::with_capacity(12));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| Vec::with_capacity(12))`
error: function call inside of `unwrap_or`
--> tests/ui/or_fun_call.rs:64:14
--> tests/ui/or_fun_call.rs:65:14
|
LL | with_err.unwrap_or(make());
| ^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|_| make())`
error: function call inside of `unwrap_or`
--> tests/ui/or_fun_call.rs:68:19
--> tests/ui/or_fun_call.rs:69:19
|
LL | with_err_args.unwrap_or(Vec::with_capacity(12));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|_| Vec::with_capacity(12))`
error: use of `unwrap_or` to construct default value
--> tests/ui/or_fun_call.rs:72:24
--> tests/ui/or_fun_call.rs:73:24
|
LL | with_default_trait.unwrap_or(Default::default());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
error: use of `unwrap_or` to construct default value
--> tests/ui/or_fun_call.rs:76:23
--> tests/ui/or_fun_call.rs:77:23
|
LL | with_default_type.unwrap_or(u64::default());
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
error: function call inside of `unwrap_or`
--> tests/ui/or_fun_call.rs:96:18
--> tests/ui/or_fun_call.rs:97:18
|
LL | self_default.unwrap_or(<FakeDefault>::default());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(<FakeDefault>::default)`
error: use of `unwrap_or` to construct default value
--> tests/ui/or_fun_call.rs:100:18
--> tests/ui/or_fun_call.rs:101:18
|
LL | real_default.unwrap_or(<FakeDefault as Default>::default());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
error: use of `unwrap_or` to construct default value
--> tests/ui/or_fun_call.rs:104:14
--> tests/ui/or_fun_call.rs:105:14
|
LL | with_vec.unwrap_or(Vec::new());
| ^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
error: function call inside of `unwrap_or`
--> tests/ui/or_fun_call.rs:108:21
--> tests/ui/or_fun_call.rs:109:21
|
LL | without_default.unwrap_or(Foo::new());
| ^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(Foo::new)`
error: use of `or_insert` to construct default value
--> tests/ui/or_fun_call.rs:112:19
--> tests/ui/or_fun_call.rs:113:19
|
LL | map.entry(42).or_insert(String::new());
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
error: use of `or_insert` to construct default value
--> tests/ui/or_fun_call.rs:116:23
--> tests/ui/or_fun_call.rs:117:23
|
LL | map_vec.entry(42).or_insert(Vec::new());
| ^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
error: use of `or_insert` to construct default value
--> tests/ui/or_fun_call.rs:120:21
--> tests/ui/or_fun_call.rs:121:21
|
LL | btree.entry(42).or_insert(String::new());
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
error: use of `or_insert` to construct default value
--> tests/ui/or_fun_call.rs:124:25
--> tests/ui/or_fun_call.rs:125:25
|
LL | btree_vec.entry(42).or_insert(Vec::new());
| ^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
error: use of `unwrap_or` to construct default value
--> tests/ui/or_fun_call.rs:128:21
--> tests/ui/or_fun_call.rs:129:21
|
LL | let _ = stringy.unwrap_or(String::new());
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
error: function call inside of `ok_or`
--> tests/ui/or_fun_call.rs:133:17
--> tests/ui/or_fun_call.rs:134:17
|
LL | let _ = opt.ok_or(format!("{} world.", hello));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ok_or_else(|| format!("{} world.", hello))`
error: function call inside of `unwrap_or`
--> tests/ui/or_fun_call.rs:138:21
--> tests/ui/or_fun_call.rs:139:21
|
LL | let _ = Some(1).unwrap_or(map[&1]);
| ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| map[&1])`
error: function call inside of `unwrap_or`
--> tests/ui/or_fun_call.rs:141:21
--> tests/ui/or_fun_call.rs:142:21
|
LL | let _ = Some(1).unwrap_or(map[&1]);
| ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| map[&1])`
error: function call inside of `or`
--> tests/ui/or_fun_call.rs:166:35
--> tests/ui/or_fun_call.rs:167:35
|
LL | let _ = Some("a".to_string()).or(Some("b".to_string()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_else(|| Some("b".to_string()))`
error: function call inside of `unwrap_or`
--> tests/ui/or_fun_call.rs:209:18
--> tests/ui/or_fun_call.rs:210:18
|
LL | None.unwrap_or(ptr_to_ref(s));
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| ptr_to_ref(s))`
error: function call inside of `unwrap_or`
--> tests/ui/or_fun_call.rs:217:14
--> tests/ui/or_fun_call.rs:218:14
|
LL | None.unwrap_or(unsafe { ptr_to_ref(s) });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })`
error: function call inside of `unwrap_or`
--> tests/ui/or_fun_call.rs:220:14
--> tests/ui/or_fun_call.rs:221:14
|
LL | None.unwrap_or( unsafe { ptr_to_ref(s) } );
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })`
error: function call inside of `map_or`
--> tests/ui/or_fun_call.rs:296:25
--> tests/ui/or_fun_call.rs:297:25
|
LL | let _ = Some(4).map_or(g(), |v| v);
| ^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(g, |v| v)`
error: function call inside of `map_or`
--> tests/ui/or_fun_call.rs:298:25
--> tests/ui/or_fun_call.rs:299:25
|
LL | let _ = Some(4).map_or(g(), f);
| ^^^^^^^^^^^^^^ help: try: `map_or_else(g, f)`
error: function call inside of `map_or`
--> tests/ui/or_fun_call.rs:301:25
--> tests/ui/or_fun_call.rs:302:25
|
LL | let _ = Some(4).map_or("asd".to_string().len() as i32, f);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(|| "asd".to_string().len() as i32, f)`
error: use of `unwrap_or_else` to construct default value
--> tests/ui/or_fun_call.rs:332:18
--> tests/ui/or_fun_call.rs:333:18
|
LL | with_new.unwrap_or_else(Vec::new);
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
error: use of `unwrap_or_else` to construct default value
--> tests/ui/or_fun_call.rs:336:28
--> tests/ui/or_fun_call.rs:337:28
|
LL | with_default_trait.unwrap_or_else(Default::default);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
error: use of `unwrap_or_else` to construct default value
--> tests/ui/or_fun_call.rs:340:27
--> tests/ui/or_fun_call.rs:341:27
|
LL | with_default_type.unwrap_or_else(u64::default);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
error: use of `unwrap_or_else` to construct default value
--> tests/ui/or_fun_call.rs:344:22
--> tests/ui/or_fun_call.rs:345:22
|
LL | real_default.unwrap_or_else(<FakeDefault as Default>::default);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
error: use of `or_insert_with` to construct default value
--> tests/ui/or_fun_call.rs:348:23
--> tests/ui/or_fun_call.rs:349:23
|
LL | map.entry(42).or_insert_with(String::new);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
error: use of `or_insert_with` to construct default value
--> tests/ui/or_fun_call.rs:352:25
--> tests/ui/or_fun_call.rs:353:25
|
LL | btree.entry(42).or_insert_with(String::new);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
error: use of `unwrap_or_else` to construct default value
--> tests/ui/or_fun_call.rs:356:25
--> tests/ui/or_fun_call.rs:357:25
|
LL | let _ = stringy.unwrap_or_else(String::new);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
error: function call inside of `unwrap_or`
--> tests/ui/or_fun_call.rs:398:17
--> tests/ui/or_fun_call.rs:399:17
|
LL | let _ = opt.unwrap_or({ f() }); // suggest `.unwrap_or_else(f)`
| ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(f)`
error: function call inside of `unwrap_or`
--> tests/ui/or_fun_call.rs:403:17
--> tests/ui/or_fun_call.rs:404:17
|
LL | let _ = opt.unwrap_or(f() + 1); // suggest `.unwrap_or_else(|| f() + 1)`
| ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| f() + 1)`
error: function call inside of `unwrap_or`
--> tests/ui/or_fun_call.rs:408:17
--> tests/ui/or_fun_call.rs:409:17
|
LL | let _ = opt.unwrap_or({
| _________________^
@ -235,79 +235,79 @@ LL ~ });
|
error: function call inside of `map_or`
--> tests/ui/or_fun_call.rs:414:17
--> tests/ui/or_fun_call.rs:415:17
|
LL | let _ = opt.map_or(f() + 1, |v| v); // suggest `.map_or_else(|| f() + 1, |v| v)`
| ^^^^^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(|| f() + 1, |v| v)`
error: use of `unwrap_or` to construct default value
--> tests/ui/or_fun_call.rs:419:17
--> tests/ui/or_fun_call.rs:420:17
|
LL | let _ = opt.unwrap_or({ i32::default() });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
error: function call inside of `unwrap_or`
--> tests/ui/or_fun_call.rs:426:21
--> tests/ui/or_fun_call.rs:427:21
|
LL | let _ = opt_foo.unwrap_or(Foo { val: String::default() });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| Foo { val: String::default() })`
error: function call inside of `map_or`
--> tests/ui/or_fun_call.rs:441:19
--> tests/ui/or_fun_call.rs:442:19
|
LL | let _ = x.map_or(g(), |v| v);
| ^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(|_| g(), |v| v)`
error: function call inside of `map_or`
--> tests/ui/or_fun_call.rs:443:19
--> tests/ui/or_fun_call.rs:444:19
|
LL | let _ = x.map_or(g(), f);
| ^^^^^^^^^^^^^^ help: try: `map_or_else(|_| g(), f)`
error: function call inside of `map_or`
--> tests/ui/or_fun_call.rs:446:19
--> tests/ui/or_fun_call.rs:447:19
|
LL | let _ = x.map_or("asd".to_string().len() as i32, f);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(|_| "asd".to_string().len() as i32, f)`
error: function call inside of `get_or_insert`
--> tests/ui/or_fun_call.rs:457:15
--> tests/ui/or_fun_call.rs:458:15
|
LL | let _ = x.get_or_insert(g());
| ^^^^^^^^^^^^^^^^^^ help: try: `get_or_insert_with(g)`
error: function call inside of `and`
--> tests/ui/or_fun_call.rs:467:15
--> tests/ui/or_fun_call.rs:468:15
|
LL | let _ = x.and(g());
| ^^^^^^^^ help: try: `and_then(|_| g())`
error: function call inside of `and`
--> tests/ui/or_fun_call.rs:477:15
--> tests/ui/or_fun_call.rs:478:15
|
LL | let _ = x.and(g());
| ^^^^^^^^ help: try: `and_then(|_| g())`
error: use of `unwrap_or` to construct default value
--> tests/ui/or_fun_call.rs:483:17
--> tests/ui/or_fun_call.rs:484:17
|
LL | let _ = opt.unwrap_or(Default::default());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
error: function call inside of `unwrap_or`
--> tests/ui/or_fun_call.rs:485:17
--> tests/ui/or_fun_call.rs:486:17
|
LL | let _ = res.unwrap_or(Default::default());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|_| Default::default())`
error: use of `unwrap_or` to construct default value
--> tests/ui/or_fun_call.rs:491:17
--> tests/ui/or_fun_call.rs:492:17
|
LL | let _ = opt.unwrap_or(Default::default());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
error: use of `unwrap_or` to construct default value
--> tests/ui/or_fun_call.rs:493:17
--> tests/ui/or_fun_call.rs:494:17
|
LL | let _ = res.unwrap_or(Default::default());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`

View file

@ -0,0 +1,75 @@
#![warn(clippy::unnecessary_option_map_or_else)]
#![allow(
clippy::let_and_return,
clippy::let_unit_value,
clippy::unnecessary_lazy_evaluations,
clippy::unnecessary_literal_unwrap
)]
const fn identity<T>(x: T) -> T {
x
}
const fn double_it(x: i32) -> i32 {
x * 2
}
fn main() {
// Expected errors
// Basic scenario
let option = Some(());
option.unwrap_or_else(|| ()); //~ ERROR: unused "map closure" when calling
// Type ascription
let option = Some(());
option.unwrap_or_else(|| ()); //~ ERROR: unused "map closure" when calling
// Auto-deref
let string = String::new();
let option = Some(&string);
let _: &str = option.unwrap_or_else(|| &string); //~ ERROR: unused "map closure" when calling
// Temporary variable
let option = Some(());
option.unwrap_or_else(|| ());
// Identity
let string = String::new();
let option = Some(&string);
let _: &str = option.unwrap_or_else(|| &string); //~ ERROR: unused "map closure" when calling
// Closure bound to a variable
let do_nothing = |x: String| x;
let string = String::new();
let option = Some(string.clone());
let _: String = option.unwrap_or_else(|| string); //~ ERROR: unused "map closure" when calling
// Correct usages
let option = Some(());
option.map_or_else(|| (), |_| ());
let option = Some(());
option.map_or_else(|| (), |_: ()| ());
let string = String::new();
let option = Some(&string);
let _: &str = option.map_or_else(|| &string, |_| &string);
let option = Some(());
option.map_or_else(
|| (),
|_| {
let tmp = ();
tmp
},
);
let num = 5;
let option = Some(num);
let _: i32 = option.map_or_else(|| 0, double_it);
let increase = |x: i32| x + 1;
let num = 5;
let option = Some(num);
let _: i32 = option.map_or_else(|| 0, increase);
}

View file

@ -0,0 +1,82 @@
#![warn(clippy::unnecessary_option_map_or_else)]
#![allow(
clippy::let_and_return,
clippy::let_unit_value,
clippy::unnecessary_lazy_evaluations,
clippy::unnecessary_literal_unwrap
)]
const fn identity<T>(x: T) -> T {
x
}
const fn double_it(x: i32) -> i32 {
x * 2
}
fn main() {
// Expected errors
// Basic scenario
let option = Some(());
option.map_or_else(|| (), |x| x); //~ ERROR: unused "map closure" when calling
// Type ascription
let option = Some(());
option.map_or_else(|| (), |x: ()| x); //~ ERROR: unused "map closure" when calling
// Auto-deref
let string = String::new();
let option = Some(&string);
let _: &str = option.map_or_else(|| &string, |x| x); //~ ERROR: unused "map closure" when calling
// Temporary variable
let option = Some(());
option.map_or_else(
//~^ ERROR: unused "map closure" when calling
|| (),
|x| {
let tmp = x;
tmp
},
);
// Identity
let string = String::new();
let option = Some(&string);
let _: &str = option.map_or_else(|| &string, identity); //~ ERROR: unused "map closure" when calling
// Closure bound to a variable
let do_nothing = |x: String| x;
let string = String::new();
let option = Some(string.clone());
let _: String = option.map_or_else(|| string, do_nothing); //~ ERROR: unused "map closure" when calling
// Correct usages
let option = Some(());
option.map_or_else(|| (), |_| ());
let option = Some(());
option.map_or_else(|| (), |_: ()| ());
let string = String::new();
let option = Some(&string);
let _: &str = option.map_or_else(|| &string, |_| &string);
let option = Some(());
option.map_or_else(
|| (),
|_| {
let tmp = ();
tmp
},
);
let num = 5;
let option = Some(num);
let _: i32 = option.map_or_else(|| 0, double_it);
let increase = |x: i32| x + 1;
let num = 5;
let option = Some(num);
let _: i32 = option.map_or_else(|| 0, increase);
}

View file

@ -0,0 +1,47 @@
error: unused "map closure" when calling `Option::map_or_else` value
--> tests/ui/unnecessary_option_map_or_else.rs:21:5
|
LL | option.map_or_else(|| (), |x| x);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `unwrap_or_else`: `option.unwrap_or_else(|| ())`
|
= note: `-D clippy::unnecessary-option-map-or-else` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::unnecessary_option_map_or_else)]`
error: unused "map closure" when calling `Option::map_or_else` value
--> tests/ui/unnecessary_option_map_or_else.rs:25:5
|
LL | option.map_or_else(|| (), |x: ()| x);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `unwrap_or_else`: `option.unwrap_or_else(|| ())`
error: unused "map closure" when calling `Option::map_or_else` value
--> tests/ui/unnecessary_option_map_or_else.rs:30:19
|
LL | let _: &str = option.map_or_else(|| &string, |x| x);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `unwrap_or_else`: `option.unwrap_or_else(|| &string)`
error: unused "map closure" when calling `Option::map_or_else` value
--> tests/ui/unnecessary_option_map_or_else.rs:34:5
|
LL | / option.map_or_else(
LL | |
LL | | || (),
LL | | |x| {
... |
LL | | },
LL | | );
| |_____^ help: consider using `unwrap_or_else`: `option.unwrap_or_else(|| ())`
error: unused "map closure" when calling `Option::map_or_else` value
--> tests/ui/unnecessary_option_map_or_else.rs:46:19
|
LL | let _: &str = option.map_or_else(|| &string, identity);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `unwrap_or_else`: `option.unwrap_or_else(|| &string)`
error: unused "map closure" when calling `Option::map_or_else` value
--> tests/ui/unnecessary_option_map_or_else.rs:52:21
|
LL | let _: String = option.map_or_else(|| string, do_nothing);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `unwrap_or_else`: `option.unwrap_or_else(|| string)`
error: aborting due to 6 previous errors