mirror of
https://github.com/rust-lang/rust.git
synced 2025-06-06 12:18:33 +00:00
Auto merge of #7101 - camsteffen:flat-map-option, r=giraffate
Add flat_map_option lint changelog: Add flat_map_option lint Closes #2241
This commit is contained in:
commit
fe5cefceba
@ -2216,6 +2216,7 @@ Released 2018-09-13
|
|||||||
[`filter_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_next
|
[`filter_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_next
|
||||||
[`find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#find_map
|
[`find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#find_map
|
||||||
[`flat_map_identity`]: https://rust-lang.github.io/rust-clippy/master/index.html#flat_map_identity
|
[`flat_map_identity`]: https://rust-lang.github.io/rust-clippy/master/index.html#flat_map_identity
|
||||||
|
[`flat_map_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#flat_map_option
|
||||||
[`float_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_arithmetic
|
[`float_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_arithmetic
|
||||||
[`float_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_cmp
|
[`float_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_cmp
|
||||||
[`float_cmp_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_cmp_const
|
[`float_cmp_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_cmp_const
|
||||||
|
@ -770,6 +770,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||||||
methods::FILTER_MAP_NEXT,
|
methods::FILTER_MAP_NEXT,
|
||||||
methods::FILTER_NEXT,
|
methods::FILTER_NEXT,
|
||||||
methods::FLAT_MAP_IDENTITY,
|
methods::FLAT_MAP_IDENTITY,
|
||||||
|
methods::FLAT_MAP_OPTION,
|
||||||
methods::FROM_ITER_INSTEAD_OF_COLLECT,
|
methods::FROM_ITER_INSTEAD_OF_COLLECT,
|
||||||
methods::GET_UNWRAP,
|
methods::GET_UNWRAP,
|
||||||
methods::IMPLICIT_CLONE,
|
methods::IMPLICIT_CLONE,
|
||||||
@ -1383,6 +1384,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||||||
LintId::of(matches::SINGLE_MATCH_ELSE),
|
LintId::of(matches::SINGLE_MATCH_ELSE),
|
||||||
LintId::of(methods::CLONED_INSTEAD_OF_COPIED),
|
LintId::of(methods::CLONED_INSTEAD_OF_COPIED),
|
||||||
LintId::of(methods::FILTER_MAP_NEXT),
|
LintId::of(methods::FILTER_MAP_NEXT),
|
||||||
|
LintId::of(methods::FLAT_MAP_OPTION),
|
||||||
LintId::of(methods::IMPLICIT_CLONE),
|
LintId::of(methods::IMPLICIT_CLONE),
|
||||||
LintId::of(methods::INEFFICIENT_TO_STRING),
|
LintId::of(methods::INEFFICIENT_TO_STRING),
|
||||||
LintId::of(methods::MAP_FLATTEN),
|
LintId::of(methods::MAP_FLATTEN),
|
||||||
|
@ -1509,7 +1509,7 @@ fn opt_parent_let<'a>(cx: &LateContext<'a>, ex: &Expr<'a>) -> Option<&'a Local<'
|
|||||||
/// Gets all arms that are unbounded `PatRange`s.
|
/// Gets all arms that are unbounded `PatRange`s.
|
||||||
fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) -> Vec<SpannedRange<Constant>> {
|
fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) -> Vec<SpannedRange<Constant>> {
|
||||||
arms.iter()
|
arms.iter()
|
||||||
.flat_map(|arm| {
|
.filter_map(|arm| {
|
||||||
if let Arm { pat, guard: None, .. } = *arm {
|
if let Arm { pat, guard: None, .. } = *arm {
|
||||||
if let PatKind::Range(ref lhs, ref rhs, range_end) = pat.kind {
|
if let PatKind::Range(ref lhs, ref rhs, range_end) = pat.kind {
|
||||||
let lhs = match lhs {
|
let lhs = match lhs {
|
||||||
|
34
clippy_lints/src/methods/flat_map_option.rs
Normal file
34
clippy_lints/src/methods/flat_map_option.rs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||||
|
use clippy_utils::is_trait_method;
|
||||||
|
use rustc_errors::Applicability;
|
||||||
|
use rustc_hir as hir;
|
||||||
|
use rustc_lint::LateContext;
|
||||||
|
use rustc_middle::ty;
|
||||||
|
use rustc_span::{source_map::Span, sym};
|
||||||
|
|
||||||
|
use super::FLAT_MAP_OPTION;
|
||||||
|
use clippy_utils::ty::is_type_diagnostic_item;
|
||||||
|
|
||||||
|
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, arg: &'tcx hir::Expr<'_>, span: Span) {
|
||||||
|
if !is_trait_method(cx, expr, sym::Iterator) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let arg_ty = cx.typeck_results().expr_ty_adjusted(arg);
|
||||||
|
let sig = match arg_ty.kind() {
|
||||||
|
ty::Closure(_, substs) => substs.as_closure().sig(),
|
||||||
|
_ if arg_ty.is_fn() => arg_ty.fn_sig(cx.tcx),
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
if !is_type_diagnostic_item(cx, sig.output().skip_binder(), sym::option_type) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
span_lint_and_sugg(
|
||||||
|
cx,
|
||||||
|
FLAT_MAP_OPTION,
|
||||||
|
span,
|
||||||
|
"used `flat_map` where `filter_map` could be used instead",
|
||||||
|
"try",
|
||||||
|
"filter_map".into(),
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
)
|
||||||
|
}
|
@ -17,6 +17,7 @@ mod filter_map_identity;
|
|||||||
mod filter_map_next;
|
mod filter_map_next;
|
||||||
mod filter_next;
|
mod filter_next;
|
||||||
mod flat_map_identity;
|
mod flat_map_identity;
|
||||||
|
mod flat_map_option;
|
||||||
mod from_iter_instead_of_collect;
|
mod from_iter_instead_of_collect;
|
||||||
mod get_unwrap;
|
mod get_unwrap;
|
||||||
mod implicit_clone;
|
mod implicit_clone;
|
||||||
@ -97,6 +98,29 @@ declare_clippy_lint! {
|
|||||||
"used `cloned` where `copied` could be used instead"
|
"used `cloned` where `copied` could be used instead"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare_clippy_lint! {
|
||||||
|
/// **What it does:** Checks for usages of `Iterator::flat_map()` where `filter_map()` could be
|
||||||
|
/// used instead.
|
||||||
|
///
|
||||||
|
/// **Why is this bad?** When applicable, `filter_map()` is more clear since it shows that
|
||||||
|
/// `Option` is used to produce 0 or 1 items.
|
||||||
|
///
|
||||||
|
/// **Known problems:** None.
|
||||||
|
///
|
||||||
|
/// **Example:**
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// let nums: Vec<i32> = ["1", "2", "whee!"].iter().flat_map(|x| x.parse().ok()).collect();
|
||||||
|
/// ```
|
||||||
|
/// Use instead:
|
||||||
|
/// ```rust
|
||||||
|
/// let nums: Vec<i32> = ["1", "2", "whee!"].iter().filter_map(|x| x.parse().ok()).collect();
|
||||||
|
/// ```
|
||||||
|
pub FLAT_MAP_OPTION,
|
||||||
|
pedantic,
|
||||||
|
"used `flat_map` where `filter_map` could be used instead"
|
||||||
|
}
|
||||||
|
|
||||||
declare_clippy_lint! {
|
declare_clippy_lint! {
|
||||||
/// **What it does:** Checks for `.unwrap()` calls on `Option`s and on `Result`s.
|
/// **What it does:** Checks for `.unwrap()` calls on `Option`s and on `Result`s.
|
||||||
///
|
///
|
||||||
@ -1663,6 +1687,7 @@ impl_lint_pass!(Methods => [
|
|||||||
CLONE_ON_REF_PTR,
|
CLONE_ON_REF_PTR,
|
||||||
CLONE_DOUBLE_REF,
|
CLONE_DOUBLE_REF,
|
||||||
CLONED_INSTEAD_OF_COPIED,
|
CLONED_INSTEAD_OF_COPIED,
|
||||||
|
FLAT_MAP_OPTION,
|
||||||
INEFFICIENT_TO_STRING,
|
INEFFICIENT_TO_STRING,
|
||||||
NEW_RET_NO_SELF,
|
NEW_RET_NO_SELF,
|
||||||
SINGLE_CHAR_PATTERN,
|
SINGLE_CHAR_PATTERN,
|
||||||
@ -1958,7 +1983,10 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
|
|||||||
unnecessary_filter_map::check(cx, expr, arg);
|
unnecessary_filter_map::check(cx, expr, arg);
|
||||||
filter_map_identity::check(cx, expr, arg, span);
|
filter_map_identity::check(cx, expr, arg, span);
|
||||||
},
|
},
|
||||||
("flat_map", [flm_arg]) => flat_map_identity::check(cx, expr, flm_arg, span),
|
("flat_map", [arg]) => {
|
||||||
|
flat_map_identity::check(cx, expr, arg, span);
|
||||||
|
flat_map_option::check(cx, expr, arg, span);
|
||||||
|
},
|
||||||
("flatten", []) => {
|
("flatten", []) => {
|
||||||
if let Some(("map", [recv, map_arg], _)) = method_call!(recv) {
|
if let Some(("map", [recv, map_arg], _)) = method_call!(recv) {
|
||||||
map_flatten::check(cx, expr, recv, map_arg);
|
map_flatten::check(cx, expr, recv, map_arg);
|
||||||
|
@ -154,6 +154,6 @@ pub fn is_doc_hidden(attrs: &[ast::Attribute]) -> bool {
|
|||||||
attrs
|
attrs
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|attr| attr.has_name(sym::doc))
|
.filter(|attr| attr.has_name(sym::doc))
|
||||||
.flat_map(ast::Attribute::meta_item_list)
|
.filter_map(ast::Attribute::meta_item_list)
|
||||||
.any(|l| attr::list_contains_name(&l, sym::hidden))
|
.any(|l| attr::list_contains_name(&l, sym::hidden))
|
||||||
}
|
}
|
||||||
|
13
tests/ui/flat_map_option.fixed
Normal file
13
tests/ui/flat_map_option.fixed
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// run-rustfix
|
||||||
|
#![warn(clippy::flat_map_option)]
|
||||||
|
#![allow(clippy::redundant_closure, clippy::unnecessary_filter_map)]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// yay
|
||||||
|
let c = |x| Some(x);
|
||||||
|
let _ = [1].iter().filter_map(c);
|
||||||
|
let _ = [1].iter().filter_map(Some);
|
||||||
|
|
||||||
|
// nay
|
||||||
|
let _ = [1].iter().flat_map(|_| &Some(1));
|
||||||
|
}
|
13
tests/ui/flat_map_option.rs
Normal file
13
tests/ui/flat_map_option.rs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// run-rustfix
|
||||||
|
#![warn(clippy::flat_map_option)]
|
||||||
|
#![allow(clippy::redundant_closure, clippy::unnecessary_filter_map)]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// yay
|
||||||
|
let c = |x| Some(x);
|
||||||
|
let _ = [1].iter().flat_map(c);
|
||||||
|
let _ = [1].iter().flat_map(Some);
|
||||||
|
|
||||||
|
// nay
|
||||||
|
let _ = [1].iter().flat_map(|_| &Some(1));
|
||||||
|
}
|
16
tests/ui/flat_map_option.stderr
Normal file
16
tests/ui/flat_map_option.stderr
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
error: used `flat_map` where `filter_map` could be used instead
|
||||||
|
--> $DIR/flat_map_option.rs:8:24
|
||||||
|
|
|
||||||
|
LL | let _ = [1].iter().flat_map(c);
|
||||||
|
| ^^^^^^^^ help: try: `filter_map`
|
||||||
|
|
|
||||||
|
= note: `-D clippy::flat-map-option` implied by `-D warnings`
|
||||||
|
|
||||||
|
error: used `flat_map` where `filter_map` could be used instead
|
||||||
|
--> $DIR/flat_map_option.rs:9:24
|
||||||
|
|
|
||||||
|
LL | let _ = [1].iter().flat_map(Some);
|
||||||
|
| ^^^^^^^^ help: try: `filter_map`
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
Loading…
Reference in New Issue
Block a user