mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-28 07:30:57 +00:00
Auto merge of #9689 - koka831:fix/or_fun_call_map_or, r=flip1995
fix: support `map_or` for `or_fun_call` lint fixes https://github.com/rust-lang/rust-clippy/issues/8993 The methods defined in `KNOW_TYPES`, except for `map_or`, accepts only one argument, so the matching `if let [arg] = args` works only for these methods. This PR adds `rest_arg` argument to `check_general_case` method and handling of cases with two arguments to support `map_or`. changelog: `or_fun_call` support `map_or` * add `rest_arg` to pass second argument from `map_or(U, F)` * extract some procedures into closure
This commit is contained in:
commit
b97d29acb7
7 changed files with 92 additions and 21 deletions
|
@ -83,6 +83,8 @@ pub(super) fn check<'tcx>(
|
|||
method_span: Span,
|
||||
self_expr: &hir::Expr<'_>,
|
||||
arg: &'tcx hir::Expr<'_>,
|
||||
// `Some` if fn has second argument
|
||||
second_arg: Option<&hir::Expr<'_>>,
|
||||
span: Span,
|
||||
// None if lambda is required
|
||||
fun_span: Option<Span>,
|
||||
|
@ -109,30 +111,40 @@ pub(super) fn check<'tcx>(
|
|||
if poss.contains(&name);
|
||||
|
||||
then {
|
||||
let macro_expanded_snipped;
|
||||
let sugg: Cow<'_, str> = {
|
||||
let sugg = {
|
||||
let (snippet_span, use_lambda) = match (fn_has_arguments, fun_span) {
|
||||
(false, Some(fun_span)) => (fun_span, false),
|
||||
_ => (arg.span, true),
|
||||
};
|
||||
let snippet = {
|
||||
let not_macro_argument_snippet = snippet_with_macro_callsite(cx, snippet_span, "..");
|
||||
if not_macro_argument_snippet == "vec![]" {
|
||||
macro_expanded_snipped = snippet(cx, snippet_span, "..");
|
||||
|
||||
let format_span = |span: Span| {
|
||||
let not_macro_argument_snippet = snippet_with_macro_callsite(cx, span, "..");
|
||||
let snip = if not_macro_argument_snippet == "vec![]" {
|
||||
let macro_expanded_snipped = snippet(cx, snippet_span, "..");
|
||||
match macro_expanded_snipped.strip_prefix("$crate::vec::") {
|
||||
Some(stripped) => Cow::from(stripped),
|
||||
Some(stripped) => Cow::Owned(stripped.to_owned()),
|
||||
None => macro_expanded_snipped,
|
||||
}
|
||||
} else {
|
||||
not_macro_argument_snippet
|
||||
}
|
||||
};
|
||||
|
||||
if use_lambda {
|
||||
snip.to_string()
|
||||
};
|
||||
|
||||
let snip = format_span(snippet_span);
|
||||
let snip = if use_lambda {
|
||||
let l_arg = if fn_has_arguments { "_" } else { "" };
|
||||
format!("|{l_arg}| {snippet}").into()
|
||||
format!("|{l_arg}| {snip}")
|
||||
} else {
|
||||
snippet
|
||||
snip
|
||||
};
|
||||
|
||||
if let Some(f) = second_arg {
|
||||
let f = format_span(f.span);
|
||||
format!("{snip}, {f}")
|
||||
} else {
|
||||
snip
|
||||
}
|
||||
};
|
||||
let span_replace_word = method_span.with_hi(span.hi());
|
||||
|
@ -149,8 +161,8 @@ pub(super) fn check<'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
if let [arg] = args {
|
||||
let inner_arg = if let hir::ExprKind::Block(
|
||||
let extract_inner_arg = |arg: &'tcx hir::Expr<'_>| {
|
||||
if let hir::ExprKind::Block(
|
||||
hir::Block {
|
||||
stmts: [],
|
||||
expr: Some(expr),
|
||||
|
@ -162,19 +174,32 @@ pub(super) fn check<'tcx>(
|
|||
expr
|
||||
} else {
|
||||
arg
|
||||
}
|
||||
};
|
||||
|
||||
if let [arg] = args {
|
||||
let inner_arg = extract_inner_arg(arg);
|
||||
match inner_arg.kind {
|
||||
hir::ExprKind::Call(fun, or_args) => {
|
||||
let or_has_args = !or_args.is_empty();
|
||||
if !check_unwrap_or_default(cx, name, fun, arg, or_has_args, expr.span, method_span) {
|
||||
let fun_span = if or_has_args { None } else { Some(fun.span) };
|
||||
check_general_case(cx, name, method_span, receiver, arg, expr.span, fun_span);
|
||||
check_general_case(cx, name, method_span, receiver, arg, None, expr.span, fun_span);
|
||||
}
|
||||
},
|
||||
hir::ExprKind::Index(..) | hir::ExprKind::MethodCall(..) => {
|
||||
check_general_case(cx, name, method_span, receiver, arg, expr.span, None);
|
||||
check_general_case(cx, name, method_span, receiver, arg, None, expr.span, None);
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
// `map_or` takes two arguments
|
||||
if let [arg, lambda] = args {
|
||||
let inner_arg = extract_inner_arg(arg);
|
||||
if let hir::ExprKind::Call(fun, or_args) = inner_arg.kind {
|
||||
let fun_span = if or_args.is_empty() { Some(fun.span) } else { None };
|
||||
check_general_case(cx, name, method_span, receiver, arg, Some(lambda), expr.span, fun_span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// run-rustfix
|
||||
#![warn(clippy::manual_ok_or)]
|
||||
#![allow(clippy::or_fun_call)]
|
||||
#![allow(clippy::disallowed_names)]
|
||||
#![allow(clippy::redundant_closure)]
|
||||
#![allow(dead_code)]
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// run-rustfix
|
||||
#![warn(clippy::manual_ok_or)]
|
||||
#![allow(clippy::or_fun_call)]
|
||||
#![allow(clippy::disallowed_names)]
|
||||
#![allow(clippy::redundant_closure)]
|
||||
#![allow(dead_code)]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error: this pattern reimplements `Option::ok_or`
|
||||
--> $DIR/manual_ok_or.rs:11:5
|
||||
--> $DIR/manual_ok_or.rs:12:5
|
||||
|
|
||||
LL | foo.map_or(Err("error"), |v| Ok(v));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `foo.ok_or("error")`
|
||||
|
@ -7,19 +7,19 @@ LL | foo.map_or(Err("error"), |v| Ok(v));
|
|||
= note: `-D clippy::manual-ok-or` implied by `-D warnings`
|
||||
|
||||
error: this pattern reimplements `Option::ok_or`
|
||||
--> $DIR/manual_ok_or.rs:14:5
|
||||
--> $DIR/manual_ok_or.rs:15:5
|
||||
|
|
||||
LL | foo.map_or(Err("error"), Ok);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `foo.ok_or("error")`
|
||||
|
||||
error: this pattern reimplements `Option::ok_or`
|
||||
--> $DIR/manual_ok_or.rs:17:5
|
||||
--> $DIR/manual_ok_or.rs:18:5
|
||||
|
|
||||
LL | None::<i32>.map_or(Err("error"), |v| Ok(v));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `None::<i32>.ok_or("error")`
|
||||
|
||||
error: this pattern reimplements `Option::ok_or`
|
||||
--> $DIR/manual_ok_or.rs:21:5
|
||||
--> $DIR/manual_ok_or.rs:22:5
|
||||
|
|
||||
LL | / foo.map_or(Err::<i32, &str>(
|
||||
LL | | &format!(
|
||||
|
|
|
@ -236,4 +236,20 @@ mod issue9608 {
|
|||
}
|
||||
}
|
||||
|
||||
mod issue8993 {
|
||||
fn g() -> i32 {
|
||||
3
|
||||
}
|
||||
|
||||
fn f(n: i32) -> i32 {
|
||||
n
|
||||
}
|
||||
|
||||
fn test_map_or() {
|
||||
let _ = Some(4).map_or_else(g, |v| v);
|
||||
let _ = Some(4).map_or_else(g, f);
|
||||
let _ = Some(4).map_or(0, f);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -236,4 +236,20 @@ mod issue9608 {
|
|||
}
|
||||
}
|
||||
|
||||
mod issue8993 {
|
||||
fn g() -> i32 {
|
||||
3
|
||||
}
|
||||
|
||||
fn f(n: i32) -> i32 {
|
||||
n
|
||||
}
|
||||
|
||||
fn test_map_or() {
|
||||
let _ = Some(4).map_or(g(), |v| v);
|
||||
let _ = Some(4).map_or(g(), f);
|
||||
let _ = Some(4).map_or(0, f);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -156,5 +156,17 @@ error: use of `unwrap_or` followed by a call to `new`
|
|||
LL | .unwrap_or(String::new());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()`
|
||||
|
||||
error: aborting due to 26 previous errors
|
||||
error: use of `map_or` followed by a function call
|
||||
--> $DIR/or_fun_call.rs:249:25
|
||||
|
|
||||
LL | let _ = Some(4).map_or(g(), |v| v);
|
||||
| ^^^^^^^^^^^^^^^^^^ help: try this: `map_or_else(g, |v| v)`
|
||||
|
||||
error: use of `map_or` followed by a function call
|
||||
--> $DIR/or_fun_call.rs:250:25
|
||||
|
|
||||
LL | let _ = Some(4).map_or(g(), f);
|
||||
| ^^^^^^^^^^^^^^ help: try this: `map_or_else(g, f)`
|
||||
|
||||
error: aborting due to 28 previous errors
|
||||
|
||||
|
|
Loading…
Reference in a new issue