Auto merge of #11845 - GuillaumeGomez:result_map_or_into_option-extension, r=flip1995

Extend `result_map_or_into_option` lint to handle `Result::map_or_else(|_| None, Some)`

Fixes https://github.com/rust-lang/rust-clippy/issues/10365.

As indicated in the title, it extends the `result_map_or_into_option` lint to handle `Result::map_or_else(|_| None, Some)`.

changelog: extension of the `result_map_or_into_option` lint to handle `Result::map_or_else(|_| None, Some)`

r? `@blyxyas`
This commit is contained in:
bors 2023-11-23 10:00:06 +00:00
commit 840e227bb6
5 changed files with 77 additions and 1 deletions

View File

@ -81,6 +81,7 @@
mod readonly_write_lock;
mod redundant_as_str;
mod repeat_once;
mod result_map_or_else_none;
mod search_is_some;
mod seek_from_current;
mod seek_to_start_instead_of_rewind;
@ -4335,6 +4336,9 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
option_map_or_none::check(cx, expr, recv, def, map);
manual_ok_or::check(cx, expr, recv, def, map);
},
("map_or_else", [def, map]) => {
result_map_or_else_none::check(cx, expr, recv, def, map);
},
("next", []) => {
if let Some((name2, recv2, args2, _, _)) = method_call(recv) {
match (name2, args2) {

View File

@ -0,0 +1,46 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{is_res_lang_ctor, path_res, peel_blocks};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::LangItem::{OptionNone, OptionSome};
use rustc_lint::LateContext;
use rustc_span::symbol::sym;
use super::RESULT_MAP_OR_INTO_OPTION;
/// lint use of `_.map_or_else(|_| None, Some)` for `Result`s
pub(super) fn check<'tcx>(
cx: &LateContext<'tcx>,
expr: &'tcx hir::Expr<'_>,
recv: &'tcx hir::Expr<'_>,
def_arg: &'tcx hir::Expr<'_>,
map_arg: &'tcx hir::Expr<'_>,
) {
let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result);
if !is_result {
return;
}
let f_arg_is_some = is_res_lang_ctor(cx, path_res(cx, map_arg), OptionSome);
if f_arg_is_some
&& let hir::ExprKind::Closure(&hir::Closure { body, .. }) = def_arg.kind
&& let body = cx.tcx.hir().body(body)
&& is_res_lang_ctor(cx, path_res(cx, peel_blocks(body.value)), OptionNone)
{
let msg = "called `map_or_else(|_| None, Some)` on a `Result` value";
let self_snippet = snippet(cx, recv.span, "..");
span_lint_and_sugg(
cx,
RESULT_MAP_OR_INTO_OPTION,
expr.span,
msg,
"try using `ok` instead",
format!("{self_snippet}.ok()"),
Applicability::MachineApplicable,
);
}
}

View File

@ -3,6 +3,12 @@
fn main() {
let opt: Result<u32, &str> = Ok(1);
let _ = opt.ok();
//~^ ERROR: called `map_or(None, Some)` on a `Result` value.
let _ = opt.ok();
//~^ ERROR: called `map_or_else(|_| None, Some)` on a `Result` value
#[rustfmt::skip]
let _ = opt.ok();
//~^ ERROR: called `map_or_else(|_| None, Some)` on a `Result` value
let rewrap = |s: u32| -> Option<u32> { Some(s) };
@ -14,4 +20,5 @@ fn main() {
// return should not emit the lint
let opt: Result<u32, &str> = Ok(1);
_ = opt.map_or(None, |_x| Some(1));
let _ = opt.map_or_else(|a| a.parse::<u32>().ok(), Some);
}

View File

@ -3,6 +3,12 @@
fn main() {
let opt: Result<u32, &str> = Ok(1);
let _ = opt.map_or(None, Some);
//~^ ERROR: called `map_or(None, Some)` on a `Result` value.
let _ = opt.map_or_else(|_| None, Some);
//~^ ERROR: called `map_or_else(|_| None, Some)` on a `Result` value
#[rustfmt::skip]
let _ = opt.map_or_else(|_| { None }, Some);
//~^ ERROR: called `map_or_else(|_| None, Some)` on a `Result` value
let rewrap = |s: u32| -> Option<u32> { Some(s) };
@ -14,4 +20,5 @@ fn main() {
// return should not emit the lint
let opt: Result<u32, &str> = Ok(1);
_ = opt.map_or(None, |_x| Some(1));
let _ = opt.map_or_else(|a| a.parse::<u32>().ok(), Some);
}

View File

@ -7,5 +7,17 @@ LL | let _ = opt.map_or(None, Some);
= note: `-D clippy::result-map-or-into-option` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::result_map_or_into_option)]`
error: aborting due to previous error
error: called `map_or_else(|_| None, Some)` on a `Result` value
--> $DIR/result_map_or_into_option.rs:7:13
|
LL | let _ = opt.map_or_else(|_| None, Some);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `ok` instead: `opt.ok()`
error: called `map_or_else(|_| None, Some)` on a `Result` value
--> $DIR/result_map_or_into_option.rs:10:13
|
LL | let _ = opt.map_or_else(|_| { None }, Some);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `ok` instead: `opt.ok()`
error: aborting due to 3 previous errors