mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-28 15:41:10 +00:00
Auto merge of #8520 - J-ZhengLi:issue8506, r=xFrednet
fix suggestion on `[map_flatten]` being cropped causing possible information loss fixes #8506 Multi-line suggestion given by the lint is missing its bottom part, which could potentially contains useful information about the fix. --- changelog: [`map_flatten`]: Long suggestions will now be splitup into two help messages
This commit is contained in:
commit
ff0a3687d8
9 changed files with 403 additions and 132 deletions
|
@ -1,26 +1,65 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg_for_edges;
|
||||
use clippy_utils::is_trait_method;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::Expr;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::{symbol::sym, Span};
|
||||
|
||||
use super::MAP_FLATTEN;
|
||||
|
||||
/// lint use of `map().flatten()` for `Iterators` and 'Options'
|
||||
pub(super) fn check<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
expr: &'tcx hir::Expr<'_>,
|
||||
recv: &'tcx hir::Expr<'_>,
|
||||
map_arg: &'tcx hir::Expr<'_>,
|
||||
) {
|
||||
// lint if caller of `.map().flatten()` is an Iterator
|
||||
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, map_arg: &Expr<'_>, map_span: Span) {
|
||||
if let Some((caller_ty_name, method_to_use)) = try_get_caller_ty_name_and_method_name(cx, expr, recv, map_arg) {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let help_msgs = [
|
||||
&format!("try replacing `map` with `{}`", method_to_use),
|
||||
"and remove the `.flatten()`",
|
||||
];
|
||||
let closure_snippet = snippet_with_applicability(cx, map_arg.span, "..", &mut applicability);
|
||||
span_lint_and_sugg_for_edges(
|
||||
cx,
|
||||
MAP_FLATTEN,
|
||||
expr.span.with_lo(map_span.lo()),
|
||||
&format!("called `map(..).flatten()` on `{}`", caller_ty_name),
|
||||
&help_msgs,
|
||||
format!("{}({})", method_to_use, closure_snippet),
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn try_get_caller_ty_name_and_method_name(
|
||||
cx: &LateContext<'_>,
|
||||
expr: &Expr<'_>,
|
||||
caller_expr: &Expr<'_>,
|
||||
map_arg: &Expr<'_>,
|
||||
) -> Option<(&'static str, &'static str)> {
|
||||
if is_trait_method(cx, expr, sym::Iterator) {
|
||||
if is_map_to_option(cx, map_arg) {
|
||||
// `(...).map(...)` has type `impl Iterator<Item=Option<...>>
|
||||
Some(("Iterator", "filter_map"))
|
||||
} else {
|
||||
// `(...).map(...)` has type `impl Iterator<Item=impl Iterator<...>>
|
||||
Some(("Iterator", "flat_map"))
|
||||
}
|
||||
} else {
|
||||
if let ty::Adt(adt, _) = cx.typeck_results().expr_ty(caller_expr).kind() {
|
||||
if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) {
|
||||
return Some(("Option", "and_then"));
|
||||
} else if cx.tcx.is_diagnostic_item(sym::Result, adt.did()) {
|
||||
return Some(("Result", "and_then"));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn is_map_to_option(cx: &LateContext<'_>, map_arg: &Expr<'_>) -> bool {
|
||||
let map_closure_ty = cx.typeck_results().expr_ty(map_arg);
|
||||
let is_map_to_option = match map_closure_ty.kind() {
|
||||
match map_closure_ty.kind() {
|
||||
ty::Closure(_, _) | ty::FnDef(_, _) | ty::FnPtr(_) => {
|
||||
let map_closure_sig = match map_closure_ty.kind() {
|
||||
ty::Closure(_, substs) => substs.as_closure().sig(),
|
||||
|
@ -30,54 +69,5 @@ pub(super) fn check<'tcx>(
|
|||
is_type_diagnostic_item(cx, map_closure_return_ty, sym::Option)
|
||||
},
|
||||
_ => false,
|
||||
};
|
||||
|
||||
let method_to_use = if is_map_to_option {
|
||||
// `(...).map(...)` has type `impl Iterator<Item=Option<...>>
|
||||
"filter_map"
|
||||
} else {
|
||||
// `(...).map(...)` has type `impl Iterator<Item=impl Iterator<...>>
|
||||
"flat_map"
|
||||
};
|
||||
let func_snippet = snippet(cx, map_arg.span, "..");
|
||||
let hint = format!(".{0}({1})", method_to_use, func_snippet);
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
MAP_FLATTEN,
|
||||
expr.span.with_lo(recv.span.hi()),
|
||||
"called `map(..).flatten()` on an `Iterator`",
|
||||
&format!("try using `{}` instead", method_to_use),
|
||||
hint,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
|
||||
// lint if caller of `.map().flatten()` is an Option or Result
|
||||
let caller_type = match cx.typeck_results().expr_ty(recv).kind() {
|
||||
ty::Adt(adt, _) => {
|
||||
if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) {
|
||||
"Option"
|
||||
} else if cx.tcx.is_diagnostic_item(sym::Result, adt.did()) {
|
||||
"Result"
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
return;
|
||||
},
|
||||
};
|
||||
|
||||
let func_snippet = snippet(cx, map_arg.span, "..");
|
||||
let hint = format!(".and_then({})", func_snippet);
|
||||
let lint_info = format!("called `map(..).flatten()` on an `{}`", caller_type);
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
MAP_FLATTEN,
|
||||
expr.span.with_lo(recv.span.hi()),
|
||||
&lint_info,
|
||||
"try using `and_then` instead",
|
||||
hint,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -2377,7 +2377,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
|
|||
flat_map_option::check(cx, expr, arg, span);
|
||||
},
|
||||
(name @ "flatten", args @ []) => match method_call(recv) {
|
||||
Some(("map", [recv, map_arg], _)) => map_flatten::check(cx, expr, recv, map_arg),
|
||||
Some(("map", [recv, map_arg], map_span)) => map_flatten::check(cx, expr, recv, map_arg, map_span),
|
||||
Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv2, name, args),
|
||||
_ => {},
|
||||
},
|
||||
|
|
|
@ -85,7 +85,7 @@ macro_rules! CONFIGURATION_VALUE_TEMPLATE {
|
|||
};
|
||||
}
|
||||
|
||||
const LINT_EMISSION_FUNCTIONS: [&[&str]; 7] = [
|
||||
const LINT_EMISSION_FUNCTIONS: [&[&str]; 8] = [
|
||||
&["clippy_utils", "diagnostics", "span_lint"],
|
||||
&["clippy_utils", "diagnostics", "span_lint_and_help"],
|
||||
&["clippy_utils", "diagnostics", "span_lint_and_note"],
|
||||
|
@ -93,6 +93,7 @@ const LINT_EMISSION_FUNCTIONS: [&[&str]; 7] = [
|
|||
&["clippy_utils", "diagnostics", "span_lint_and_sugg"],
|
||||
&["clippy_utils", "diagnostics", "span_lint_and_then"],
|
||||
&["clippy_utils", "diagnostics", "span_lint_hir_and_then"],
|
||||
&["clippy_utils", "diagnostics", "span_lint_and_sugg_for_edges"],
|
||||
];
|
||||
const SUGGESTION_DIAGNOSTIC_BUILDER_METHODS: [(&str, bool); 9] = [
|
||||
("span_suggestion", false),
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
//! Thank you!
|
||||
//! ~The `INTERNAL_METADATA_COLLECTOR` lint
|
||||
|
||||
use rustc_errors::{Applicability, Diagnostic};
|
||||
use rustc_errors::{emitter::MAX_SUGGESTION_HIGHLIGHT_LINES, Applicability, Diagnostic};
|
||||
use rustc_hir::HirId;
|
||||
use rustc_lint::{LateContext, Lint, LintContext};
|
||||
use rustc_span::source_map::{MultiSpan, Span};
|
||||
|
@ -213,6 +213,90 @@ pub fn span_lint_and_sugg<'a, T: LintContext>(
|
|||
});
|
||||
}
|
||||
|
||||
/// Like [`span_lint_and_sugg`] with a focus on the edges. The output will either
|
||||
/// emit single span or multispan suggestion depending on the number of its lines.
|
||||
///
|
||||
/// If the given suggestion string has more lines than the maximum display length defined by
|
||||
/// [`MAX_SUGGESTION_HIGHLIGHT_LINES`][`rustc_errors::emitter::MAX_SUGGESTION_HIGHLIGHT_LINES`],
|
||||
/// this function will split the suggestion and span to showcase the change for the top and
|
||||
/// bottom edge of the code. For normal suggestions, in one display window, the help message
|
||||
/// will be combined with a colon.
|
||||
///
|
||||
/// Multipart suggestions like the one being created here currently cannot be
|
||||
/// applied by rustfix (See [rustfix#141](https://github.com/rust-lang/rustfix/issues/141)).
|
||||
/// Testing rustfix with this lint emission function might require a file with
|
||||
/// suggestions that can be fixed and those that can't. See
|
||||
/// [clippy#8520](https://github.com/rust-lang/rust-clippy/pull/8520/files) for
|
||||
/// an example and of this.
|
||||
///
|
||||
/// # Example for a long suggestion
|
||||
///
|
||||
/// ```text
|
||||
/// error: called `map(..).flatten()` on `Option`
|
||||
/// --> $DIR/map_flatten.rs:8:10
|
||||
/// |
|
||||
/// LL | .map(|x| {
|
||||
/// | __________^
|
||||
/// LL | | if x <= 5 {
|
||||
/// LL | | Some(x)
|
||||
/// LL | | } else {
|
||||
/// ... |
|
||||
/// LL | | })
|
||||
/// LL | | .flatten();
|
||||
/// | |__________________^
|
||||
/// |
|
||||
/// = note: `-D clippy::map-flatten` implied by `-D warnings`
|
||||
/// help: try replacing `map` with `and_then`
|
||||
/// |
|
||||
/// LL ~ .and_then(|x| {
|
||||
/// LL + if x <= 5 {
|
||||
/// LL + Some(x)
|
||||
/// |
|
||||
/// help: and remove the `.flatten()`
|
||||
/// |
|
||||
/// LL + None
|
||||
/// LL + }
|
||||
/// LL ~ });
|
||||
/// |
|
||||
/// ```
|
||||
pub fn span_lint_and_sugg_for_edges(
|
||||
cx: &LateContext<'_>,
|
||||
lint: &'static Lint,
|
||||
sp: Span,
|
||||
msg: &str,
|
||||
helps: &[&str; 2],
|
||||
sugg: String,
|
||||
applicability: Applicability,
|
||||
) {
|
||||
span_lint_and_then(cx, lint, sp, msg, |diag| {
|
||||
let sugg_lines_count = sugg.lines().count();
|
||||
if sugg_lines_count > MAX_SUGGESTION_HIGHLIGHT_LINES {
|
||||
let sm = cx.sess().source_map();
|
||||
if let (Ok(line_upper), Ok(line_bottom)) = (sm.lookup_line(sp.lo()), sm.lookup_line(sp.hi())) {
|
||||
let split_idx = MAX_SUGGESTION_HIGHLIGHT_LINES / 2;
|
||||
let span_upper = sm.span_until_char(sp.with_hi(line_upper.sf.lines[line_upper.line + split_idx]), '\n');
|
||||
let span_bottom = sp.with_lo(line_bottom.sf.lines[line_bottom.line - split_idx]);
|
||||
|
||||
let sugg_lines_vec = sugg.lines().collect::<Vec<&str>>();
|
||||
let sugg_upper = sugg_lines_vec[..split_idx].join("\n");
|
||||
let sugg_bottom = sugg_lines_vec[sugg_lines_count - split_idx..].join("\n");
|
||||
|
||||
diag.span_suggestion(span_upper, helps[0], sugg_upper, applicability);
|
||||
diag.span_suggestion(span_bottom, helps[1], sugg_bottom, applicability);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
diag.span_suggestion_with_style(
|
||||
sp,
|
||||
&helps.join(", "),
|
||||
sugg,
|
||||
applicability,
|
||||
rustc_errors::SuggestionStyle::ShowAlways,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/// Create a suggestion made from several `span → replacement`.
|
||||
///
|
||||
/// Note: in the JSON format (used by `compiletest_rs`), the help message will
|
||||
|
|
|
@ -1,31 +1,55 @@
|
|||
// run-rustfix
|
||||
|
||||
#![warn(clippy::all, clippy::pedantic)]
|
||||
#![allow(clippy::let_underscore_drop)]
|
||||
#![allow(clippy::missing_docs_in_private_items)]
|
||||
#![allow(clippy::map_identity)]
|
||||
#![allow(clippy::redundant_closure)]
|
||||
#![allow(clippy::unnecessary_wraps)]
|
||||
#![warn(clippy::map_flatten)]
|
||||
#![feature(result_flattening)]
|
||||
|
||||
fn main() {
|
||||
// mapping to Option on Iterator
|
||||
fn option_id(x: i8) -> Option<i8> {
|
||||
// issue #8506, multi-line
|
||||
#[rustfmt::skip]
|
||||
fn long_span() {
|
||||
let _: Option<i32> = Some(1)
|
||||
.map(|x| {
|
||||
if x <= 5 {
|
||||
Some(x)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
let option_id_ref: fn(i8) -> Option<i8> = option_id;
|
||||
let option_id_closure = |x| Some(x);
|
||||
let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().collect();
|
||||
let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_ref).flatten().collect();
|
||||
let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_closure).flatten().collect();
|
||||
let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| x.checked_add(1)).flatten().collect();
|
||||
})
|
||||
.flatten();
|
||||
|
||||
// mapping to Iterator on Iterator
|
||||
let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect();
|
||||
let _: Result<i32, i32> = Ok(1)
|
||||
.map(|x| {
|
||||
if x == 1 {
|
||||
Ok(x)
|
||||
} else {
|
||||
Err(0)
|
||||
}
|
||||
})
|
||||
.flatten();
|
||||
|
||||
// mapping to Option on Option
|
||||
let _: Option<_> = (Some(Some(1))).map(|x| x).flatten();
|
||||
let result: Result<i32, i32> = Ok(2);
|
||||
fn do_something() { }
|
||||
let _: Result<i32, i32> = result
|
||||
.map(|res| {
|
||||
if res > 0 {
|
||||
do_something();
|
||||
Ok(res)
|
||||
} else {
|
||||
Err(0)
|
||||
}
|
||||
})
|
||||
.flatten();
|
||||
|
||||
// mapping to Result on Result
|
||||
let _: Result<_, &str> = (Ok(Ok(1))).map(|x| x).flatten();
|
||||
let _: Vec<_> = vec![5_i8; 6]
|
||||
.into_iter()
|
||||
.map(|some_value| {
|
||||
if some_value > 3 {
|
||||
Some(some_value)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.flatten()
|
||||
.collect();
|
||||
}
|
||||
|
||||
fn main() {
|
||||
long_span();
|
||||
}
|
||||
|
|
|
@ -1,46 +1,107 @@
|
|||
error: called `map(..).flatten()` on an `Iterator`
|
||||
--> $DIR/map_flatten.rs:18:46
|
||||
error: called `map(..).flatten()` on `Option`
|
||||
--> $DIR/map_flatten.rs:8:10
|
||||
|
|
||||
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().collect();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(option_id)`
|
||||
LL | .map(|x| {
|
||||
| __________^
|
||||
LL | | if x <= 5 {
|
||||
LL | | Some(x)
|
||||
LL | | } else {
|
||||
... |
|
||||
LL | | })
|
||||
LL | | .flatten();
|
||||
| |__________________^
|
||||
|
|
||||
= note: `-D clippy::map-flatten` implied by `-D warnings`
|
||||
|
||||
error: called `map(..).flatten()` on an `Iterator`
|
||||
--> $DIR/map_flatten.rs:19:46
|
||||
help: try replacing `map` with `and_then`
|
||||
|
|
||||
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_ref).flatten().collect();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(option_id_ref)`
|
||||
|
||||
error: called `map(..).flatten()` on an `Iterator`
|
||||
--> $DIR/map_flatten.rs:20:46
|
||||
LL ~ .and_then(|x| {
|
||||
LL + if x <= 5 {
|
||||
LL + Some(x)
|
||||
|
|
||||
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_closure).flatten().collect();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(option_id_closure)`
|
||||
|
||||
error: called `map(..).flatten()` on an `Iterator`
|
||||
--> $DIR/map_flatten.rs:21:46
|
||||
help: and remove the `.flatten()`
|
||||
|
|
||||
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| x.checked_add(1)).flatten().collect();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(|x| x.checked_add(1))`
|
||||
|
||||
error: called `map(..).flatten()` on an `Iterator`
|
||||
--> $DIR/map_flatten.rs:24:46
|
||||
LL + None
|
||||
LL + }
|
||||
LL ~ });
|
||||
|
|
||||
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `flat_map` instead: `.flat_map(|x| 0..x)`
|
||||
|
||||
error: called `map(..).flatten()` on an `Option`
|
||||
--> $DIR/map_flatten.rs:27:39
|
||||
error: called `map(..).flatten()` on `Result`
|
||||
--> $DIR/map_flatten.rs:18:10
|
||||
|
|
||||
LL | let _: Option<_> = (Some(Some(1))).map(|x| x).flatten();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ help: try using `and_then` instead: `.and_then(|x| x)`
|
||||
|
||||
error: called `map(..).flatten()` on an `Result`
|
||||
--> $DIR/map_flatten.rs:30:41
|
||||
LL | .map(|x| {
|
||||
| __________^
|
||||
LL | | if x == 1 {
|
||||
LL | | Ok(x)
|
||||
LL | | } else {
|
||||
... |
|
||||
LL | | })
|
||||
LL | | .flatten();
|
||||
| |__________________^
|
||||
|
|
||||
help: try replacing `map` with `and_then`
|
||||
|
|
||||
LL ~ .and_then(|x| {
|
||||
LL + if x == 1 {
|
||||
LL + Ok(x)
|
||||
|
|
||||
help: and remove the `.flatten()`
|
||||
|
|
||||
LL + Err(0)
|
||||
LL + }
|
||||
LL ~ });
|
||||
|
|
||||
LL | let _: Result<_, &str> = (Ok(Ok(1))).map(|x| x).flatten();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ help: try using `and_then` instead: `.and_then(|x| x)`
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
error: called `map(..).flatten()` on `Result`
|
||||
--> $DIR/map_flatten.rs:30:10
|
||||
|
|
||||
LL | .map(|res| {
|
||||
| __________^
|
||||
LL | | if res > 0 {
|
||||
LL | | do_something();
|
||||
LL | | Ok(res)
|
||||
... |
|
||||
LL | | })
|
||||
LL | | .flatten();
|
||||
| |__________________^
|
||||
|
|
||||
help: try replacing `map` with `and_then`
|
||||
|
|
||||
LL ~ .and_then(|res| {
|
||||
LL + if res > 0 {
|
||||
LL + do_something();
|
||||
|
|
||||
help: and remove the `.flatten()`
|
||||
|
|
||||
LL + Err(0)
|
||||
LL + }
|
||||
LL ~ });
|
||||
|
|
||||
|
||||
error: called `map(..).flatten()` on `Iterator`
|
||||
--> $DIR/map_flatten.rs:42:10
|
||||
|
|
||||
LL | .map(|some_value| {
|
||||
| __________^
|
||||
LL | | if some_value > 3 {
|
||||
LL | | Some(some_value)
|
||||
LL | | } else {
|
||||
... |
|
||||
LL | | })
|
||||
LL | | .flatten()
|
||||
| |__________________^
|
||||
|
|
||||
help: try replacing `map` with `filter_map`
|
||||
|
|
||||
LL ~ .filter_map(|some_value| {
|
||||
LL + if some_value > 3 {
|
||||
LL + Some(some_value)
|
||||
|
|
||||
help: and remove the `.flatten()`
|
||||
|
|
||||
LL + None
|
||||
LL + }
|
||||
LL + })
|
||||
|
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
|
31
tests/ui/map_flatten_fixable.rs
Normal file
31
tests/ui/map_flatten_fixable.rs
Normal file
|
@ -0,0 +1,31 @@
|
|||
// run-rustfix
|
||||
|
||||
#![warn(clippy::all, clippy::pedantic)]
|
||||
#![allow(clippy::let_underscore_drop)]
|
||||
#![allow(clippy::missing_docs_in_private_items)]
|
||||
#![allow(clippy::map_identity)]
|
||||
#![allow(clippy::redundant_closure)]
|
||||
#![allow(clippy::unnecessary_wraps)]
|
||||
#![feature(result_flattening)]
|
||||
|
||||
fn main() {
|
||||
// mapping to Option on Iterator
|
||||
fn option_id(x: i8) -> Option<i8> {
|
||||
Some(x)
|
||||
}
|
||||
let option_id_ref: fn(i8) -> Option<i8> = option_id;
|
||||
let option_id_closure = |x| Some(x);
|
||||
let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().collect();
|
||||
let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_ref).flatten().collect();
|
||||
let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_closure).flatten().collect();
|
||||
let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| x.checked_add(1)).flatten().collect();
|
||||
|
||||
// mapping to Iterator on Iterator
|
||||
let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect();
|
||||
|
||||
// mapping to Option on Option
|
||||
let _: Option<_> = (Some(Some(1))).map(|x| x).flatten();
|
||||
|
||||
// mapping to Result on Result
|
||||
let _: Result<_, &str> = (Ok(Ok(1))).map(|x| x).flatten();
|
||||
}
|
80
tests/ui/map_flatten_fixable.stderr
Normal file
80
tests/ui/map_flatten_fixable.stderr
Normal file
|
@ -0,0 +1,80 @@
|
|||
error: called `map(..).flatten()` on `Iterator`
|
||||
--> $DIR/map_flatten_fixable.rs:18:47
|
||||
|
|
||||
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().collect();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::map-flatten` implied by `-D warnings`
|
||||
help: try replacing `map` with `filter_map`, and remove the `.flatten()`
|
||||
|
|
||||
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().filter_map(option_id).collect();
|
||||
| ~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error: called `map(..).flatten()` on `Iterator`
|
||||
--> $DIR/map_flatten_fixable.rs:19:47
|
||||
|
|
||||
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_ref).flatten().collect();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: try replacing `map` with `filter_map`, and remove the `.flatten()`
|
||||
|
|
||||
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().filter_map(option_id_ref).collect();
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error: called `map(..).flatten()` on `Iterator`
|
||||
--> $DIR/map_flatten_fixable.rs:20:47
|
||||
|
|
||||
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_closure).flatten().collect();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: try replacing `map` with `filter_map`, and remove the `.flatten()`
|
||||
|
|
||||
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().filter_map(option_id_closure).collect();
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error: called `map(..).flatten()` on `Iterator`
|
||||
--> $DIR/map_flatten_fixable.rs:21:47
|
||||
|
|
||||
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| x.checked_add(1)).flatten().collect();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: try replacing `map` with `filter_map`, and remove the `.flatten()`
|
||||
|
|
||||
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().filter_map(|x| x.checked_add(1)).collect();
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error: called `map(..).flatten()` on `Iterator`
|
||||
--> $DIR/map_flatten_fixable.rs:24:47
|
||||
|
|
||||
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: try replacing `map` with `flat_map`, and remove the `.flatten()`
|
||||
|
|
||||
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().flat_map(|x| 0..x).collect();
|
||||
| ~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error: called `map(..).flatten()` on `Option`
|
||||
--> $DIR/map_flatten_fixable.rs:27:40
|
||||
|
|
||||
LL | let _: Option<_> = (Some(Some(1))).map(|x| x).flatten();
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: try replacing `map` with `and_then`, and remove the `.flatten()`
|
||||
|
|
||||
LL | let _: Option<_> = (Some(Some(1))).and_then(|x| x);
|
||||
| ~~~~~~~~~~~~~~~
|
||||
|
||||
error: called `map(..).flatten()` on `Result`
|
||||
--> $DIR/map_flatten_fixable.rs:30:42
|
||||
|
|
||||
LL | let _: Result<_, &str> = (Ok(Ok(1))).map(|x| x).flatten();
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: try replacing `map` with `and_then`, and remove the `.flatten()`
|
||||
|
|
||||
LL | let _: Result<_, &str> = (Ok(Ok(1))).and_then(|x| x);
|
||||
| ~~~~~~~~~~~~~~~
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
|
Loading…
Reference in a new issue