mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-26 05:44:26 +00:00
allowing [map_flatten
] to split long suggestions
add new function `span_lint_and_sugg_` for edges in `clippy_utils::diagnostics`
This commit is contained in:
parent
47b93ea5ef
commit
5b6295d663
@ -1,83 +1,73 @@
|
|||||||
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::is_trait_method;
|
||||||
use clippy_utils::source::snippet;
|
use clippy_utils::source::snippet_with_applicability;
|
||||||
use clippy_utils::ty::is_type_diagnostic_item;
|
use clippy_utils::ty::is_type_diagnostic_item;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir as hir;
|
use rustc_hir::Expr;
|
||||||
use rustc_lint::LateContext;
|
use rustc_lint::LateContext;
|
||||||
use rustc_middle::ty;
|
use rustc_middle::ty;
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::{symbol::sym, Span};
|
||||||
|
|
||||||
use super::MAP_FLATTEN;
|
use super::MAP_FLATTEN;
|
||||||
|
|
||||||
/// lint use of `map().flatten()` for `Iterators` and 'Options'
|
/// lint use of `map().flatten()` for `Iterators` and 'Options'
|
||||||
pub(super) fn check<'tcx>(
|
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, map_arg: &Expr<'_>, map_span: Span) {
|
||||||
cx: &LateContext<'tcx>,
|
if let Some((caller_ty_name, method_to_use)) = try_get_caller_ty_name_and_method_name(cx, expr, recv, map_arg) {
|
||||||
expr: &'tcx hir::Expr<'_>,
|
let mut applicability = Applicability::MachineApplicable;
|
||||||
recv: &'tcx hir::Expr<'_>,
|
let help_msgs = [
|
||||||
map_arg: &'tcx hir::Expr<'_>,
|
&format!("try replacing `map` with `{}`", method_to_use),
|
||||||
) {
|
"and remove the `.flatten()`",
|
||||||
// lint if caller of `.map().flatten()` is an Iterator
|
];
|
||||||
if is_trait_method(cx, expr, sym::Iterator) {
|
let closure_snippet = snippet_with_applicability(cx, map_arg.span, "..", &mut applicability);
|
||||||
let map_closure_ty = cx.typeck_results().expr_ty(map_arg);
|
span_lint_and_sugg_for_edges(
|
||||||
let is_map_to_option = 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(),
|
|
||||||
_ => map_closure_ty.fn_sig(cx.tcx),
|
|
||||||
};
|
|
||||||
let map_closure_return_ty = cx.tcx.erase_late_bound_regions(map_closure_sig.output());
|
|
||||||
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,
|
cx,
|
||||||
MAP_FLATTEN,
|
MAP_FLATTEN,
|
||||||
expr.span.with_lo(recv.span.hi()),
|
expr.span.with_lo(map_span.lo()),
|
||||||
"called `map(..).flatten()` on an `Iterator`",
|
&format!("called `map(..).flatten()` on `{}`", caller_ty_name),
|
||||||
&format!("try using `{}` instead", method_to_use),
|
&help_msgs,
|
||||||
hint,
|
format!("{}({})", method_to_use, closure_snippet),
|
||||||
Applicability::MachineApplicable,
|
applicability,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// lint if caller of `.map().flatten()` is an Option or Result
|
|
||||||
let caller_type = match cx.typeck_results().expr_ty(recv).kind() {
|
fn try_get_caller_ty_name_and_method_name(
|
||||||
ty::Adt(adt, _) => {
|
cx: &LateContext<'_>,
|
||||||
if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) {
|
expr: &Expr<'_>,
|
||||||
"Option"
|
caller_expr: &Expr<'_>,
|
||||||
} else if cx.tcx.is_diagnostic_item(sym::Result, adt.did()) {
|
map_arg: &Expr<'_>,
|
||||||
"Result"
|
) -> Option<(&'static str, &'static str)> {
|
||||||
} else {
|
if is_trait_method(cx, expr, sym::Iterator) {
|
||||||
return;
|
if is_map_to_option(cx, map_arg) {
|
||||||
}
|
// `(...).map(...)` has type `impl Iterator<Item=Option<...>>
|
||||||
},
|
Some(("Iterator", "filter_map"))
|
||||||
_ => {
|
} else {
|
||||||
return;
|
// `(...).map(...)` has type `impl Iterator<Item=impl Iterator<...>>
|
||||||
},
|
Some(("Iterator", "flat_map"))
|
||||||
};
|
}
|
||||||
|
} else {
|
||||||
let func_snippet = snippet(cx, map_arg.span, "..");
|
if let ty::Adt(adt, _) = cx.typeck_results().expr_ty(caller_expr).kind() {
|
||||||
let hint = format!(".and_then({})", func_snippet);
|
if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) {
|
||||||
let lint_info = format!("called `map(..).flatten()` on an `{}`", caller_type);
|
return Some(("Option", "and_then"));
|
||||||
span_lint_and_sugg(
|
} else if cx.tcx.is_diagnostic_item(sym::Result, adt.did()) {
|
||||||
cx,
|
return Some(("Result", "and_then"));
|
||||||
MAP_FLATTEN,
|
}
|
||||||
expr.span.with_lo(recv.span.hi()),
|
}
|
||||||
&lint_info,
|
None
|
||||||
"try using `and_then` instead",
|
}
|
||||||
hint,
|
}
|
||||||
Applicability::MachineApplicable,
|
|
||||||
);
|
fn is_map_to_option(cx: &LateContext<'_>, map_arg: &Expr<'_>) -> bool {
|
||||||
|
let map_closure_ty = cx.typeck_results().expr_ty(map_arg);
|
||||||
|
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(),
|
||||||
|
_ => map_closure_ty.fn_sig(cx.tcx),
|
||||||
|
};
|
||||||
|
let map_closure_return_ty = cx.tcx.erase_late_bound_regions(map_closure_sig.output());
|
||||||
|
is_type_diagnostic_item(cx, map_closure_return_ty, sym::Option)
|
||||||
|
},
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2377,7 +2377,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
|
|||||||
flat_map_option::check(cx, expr, arg, span);
|
flat_map_option::check(cx, expr, arg, span);
|
||||||
},
|
},
|
||||||
(name @ "flatten", args @ []) => match method_call(recv) {
|
(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),
|
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"],
|
||||||
&["clippy_utils", "diagnostics", "span_lint_and_help"],
|
&["clippy_utils", "diagnostics", "span_lint_and_help"],
|
||||||
&["clippy_utils", "diagnostics", "span_lint_and_note"],
|
&["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_sugg"],
|
||||||
&["clippy_utils", "diagnostics", "span_lint_and_then"],
|
&["clippy_utils", "diagnostics", "span_lint_and_then"],
|
||||||
&["clippy_utils", "diagnostics", "span_lint_hir_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] = [
|
const SUGGESTION_DIAGNOSTIC_BUILDER_METHODS: [(&str, bool); 9] = [
|
||||||
("span_suggestion", false),
|
("span_suggestion", false),
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
//! Thank you!
|
//! Thank you!
|
||||||
//! ~The `INTERNAL_METADATA_COLLECTOR` lint
|
//! ~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_hir::HirId;
|
||||||
use rustc_lint::{LateContext, Lint, LintContext};
|
use rustc_lint::{LateContext, Lint, LintContext};
|
||||||
use rustc_span::source_map::{MultiSpan, Span};
|
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`.
|
/// Create a suggestion made from several `span → replacement`.
|
||||||
///
|
///
|
||||||
/// Note: in the JSON format (used by `compiletest_rs`), the help message will
|
/// Note: in the JSON format (used by `compiletest_rs`), the help message will
|
||||||
|
@ -1,31 +1,55 @@
|
|||||||
// run-rustfix
|
#![warn(clippy::map_flatten)]
|
||||||
|
|
||||||
#![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)]
|
#![feature(result_flattening)]
|
||||||
|
|
||||||
fn main() {
|
// issue #8506, multi-line
|
||||||
// mapping to Option on Iterator
|
#[rustfmt::skip]
|
||||||
fn option_id(x: i8) -> Option<i8> {
|
fn long_span() {
|
||||||
Some(x)
|
let _: Option<i32> = Some(1)
|
||||||
}
|
.map(|x| {
|
||||||
let option_id_ref: fn(i8) -> Option<i8> = option_id;
|
if x <= 5 {
|
||||||
let option_id_closure = |x| Some(x);
|
Some(x)
|
||||||
let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().collect();
|
} else {
|
||||||
let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_ref).flatten().collect();
|
None
|
||||||
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 _: Result<i32, i32> = Ok(1)
|
||||||
let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect();
|
.map(|x| {
|
||||||
|
if x == 1 {
|
||||||
|
Ok(x)
|
||||||
|
} else {
|
||||||
|
Err(0)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.flatten();
|
||||||
|
|
||||||
// mapping to Option on Option
|
let result: Result<i32, i32> = Ok(2);
|
||||||
let _: Option<_> = (Some(Some(1))).map(|x| x).flatten();
|
fn do_something() { }
|
||||||
|
let _: Result<i32, i32> = result
|
||||||
// mapping to Result on Result
|
.map(|res| {
|
||||||
let _: Result<_, &str> = (Ok(Ok(1))).map(|x| x).flatten();
|
if res > 0 {
|
||||||
|
do_something();
|
||||||
|
Ok(res)
|
||||||
|
} else {
|
||||||
|
Err(0)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.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`
|
error: called `map(..).flatten()` on `Option`
|
||||||
--> $DIR/map_flatten.rs:18:46
|
--> $DIR/map_flatten.rs:8:10
|
||||||
|
|
|
|
||||||
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().collect();
|
LL | .map(|x| {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(option_id)`
|
| __________^
|
||||||
|
LL | | if x <= 5 {
|
||||||
|
LL | | Some(x)
|
||||||
|
LL | | } else {
|
||||||
|
... |
|
||||||
|
LL | | })
|
||||||
|
LL | | .flatten();
|
||||||
|
| |__________________^
|
||||||
|
|
|
|
||||||
= note: `-D clippy::map-flatten` implied by `-D warnings`
|
= note: `-D clippy::map-flatten` implied by `-D warnings`
|
||||||
|
help: try replacing `map` with `and_then`
|
||||||
error: called `map(..).flatten()` on an `Iterator`
|
|
||||||
--> $DIR/map_flatten.rs:19:46
|
|
||||||
|
|
|
|
||||||
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_ref).flatten().collect();
|
LL ~ .and_then(|x| {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(option_id_ref)`
|
LL + if x <= 5 {
|
||||||
|
LL + Some(x)
|
||||||
error: called `map(..).flatten()` on an `Iterator`
|
|
||||||
--> $DIR/map_flatten.rs:20:46
|
|
||||||
|
|
|
|
||||||
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_closure).flatten().collect();
|
help: and remove the `.flatten()`
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(option_id_closure)`
|
|
||||||
|
|
||||||
error: called `map(..).flatten()` on an `Iterator`
|
|
||||||
--> $DIR/map_flatten.rs:21:46
|
|
||||||
|
|
|
|
||||||
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| x.checked_add(1)).flatten().collect();
|
LL + None
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(|x| x.checked_add(1))`
|
LL + }
|
||||||
|
LL ~ });
|
||||||
error: called `map(..).flatten()` on an `Iterator`
|
|
||||||
--> $DIR/map_flatten.rs:24:46
|
|
||||||
|
|
|
|
||||||
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`
|
error: called `map(..).flatten()` on `Result`
|
||||||
--> $DIR/map_flatten.rs:27:39
|
--> $DIR/map_flatten.rs:18:10
|
||||||
|
|
|
|
||||||
LL | let _: Option<_> = (Some(Some(1))).map(|x| x).flatten();
|
LL | .map(|x| {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^ help: try using `and_then` instead: `.and_then(|x| x)`
|
| __________^
|
||||||
|
LL | | if x == 1 {
|
||||||
error: called `map(..).flatten()` on an `Result`
|
LL | | Ok(x)
|
||||||
--> $DIR/map_flatten.rs:30:41
|
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 New Issue
Block a user