@@ -280,32 +280,13 @@ declare_clippy_lint! {
280
280
"using combinations of `flatten` and `map` which can usually be written as a single method call"
281
281
}
282
282
283
- /// **What it does:** Checks for usage of `_.filter (_).map(_)`,
284
- /// `_.filter(_).flat_map(_)`, `_.filter_map(_).flat_map(_)` and similar .
283
+ /// **What it does:** Checks for usage of `_.filter_map (_).map(_)`, which can be more concisely
284
+ /// written as `_.filter_map(_)` .
285
285
///
286
286
/// **Why is this bad?** Readability, this can be written more concisely as a
287
287
/// single method call.
288
288
///
289
- /// **Known problems:** Often requires a condition + Option/Iterator creation
290
- /// inside the closure.
291
- ///
292
- /// ** filter + map Example:**
293
- /// let ns = [-9, 2, 3, 4, 5, 6];
294
- /// let correct: Vec<i32> = ns.iter()
295
- /// .cloned()
296
- /// .filter(|&x| x > 0)
297
- /// .map(|x| x * 2)
298
- /// .collect();
299
- ///
300
- /// let more_correct: Vec<i32> = ns.iter()
301
- /// .cloned()
302
- /// .filter_map(|x| if x > 0 { Some(x * 2) } else { None })
303
- /// .collect();
304
- ///
305
- /// println!("{:?}", more_correct);
306
- /// assert_eq!(correct, more_correct);
307
- ///
308
- /// ** filter_map + map Example:**
289
+ /// ** Example:**
309
290
/// let ws: Vec<String> = ["is", "this", "shizzle", "for", "rizzle"]
310
291
/// .iter()
311
292
/// .map(|s| s.to_string())
@@ -331,57 +312,36 @@ declare_clippy_lint! {
331
312
/// println!("{:?}", correct);
332
313
/// assert_eq!(correct, more_correct);
333
314
///
334
- /// ** filter + flat_map Example:**
335
- /// let ws: Vec<String> = ["is", "this", "shizzle", "for", "rizzle"]
336
- /// .iter()
337
- /// .map(|s| s.to_string())
338
- /// .collect();
339
- ///
340
- /// let correct: String = ws.iter()
341
- /// .filter(|s| s.contains("izzle"))
342
- /// .flat_map(|s| s.chars())
343
- /// .collect();
344
- ///
345
- /// let more_correct: String = ws.iter()
346
- /// .flat_map(|s| if s.contains("izzle") {
347
- /// return s.chars()
348
- /// } else {
349
- /// "".chars()
350
- /// })
351
- /// .collect();
352
- ///
353
- /// println!("{:?}", correct);
354
- /// assert_eq!(correct, more_correct);
315
+ declare_clippy_lint ! {
316
+ pub FILTER_MAP_MAP ,
317
+ pedantic,
318
+ "using `filter_map` followed by `map` can more concisely be written as a single method call"
319
+ }
320
+
321
+ /// **What it does:** Checks for usage of `_.filter(_).map(_)` used to destructure
322
+ /// `Iterator<Option<_>>` and `Iterator<Result<_>>` into `Iterator<_>` (an iterator of values).
355
323
///
356
- /// ** filter_map + flat_map Example:**
357
- /// let ws: Vec<String> = ["is", "this", "shizzle", "for", "rizzle"]
358
- /// .iter()
359
- /// .map(|s| s.to_string())
360
- /// .collect();
324
+ /// **Why is this bad?** Readability, this can be written more concisely as `_.filter_map(|x| x)`.
361
325
///
362
- /// let correct: String = ws.iter()
363
- /// .filter_map(|s| if s.contains("izzle"){
364
- /// Some(s)
365
- /// } else {
366
- /// None
367
- /// })
368
- /// .flat_map(|s| s.chars())
326
+ /// ** Example:**
327
+ /// let ns = [Some(-9), Some(2), None, Some(3), Some(4), None, Some(5), Some(6)];
328
+ /// let correct: Vec<i32> = ns.clone().iter()
329
+ /// .filter(|x| x.is_some())
330
+ /// .map(|x| x.unwrap() )
369
331
/// .collect();
370
332
///
371
- /// let more_correct: String = ws.iter()
372
- /// .flat_map(|s| if s.contains("izzle") {
373
- /// return s.chars()
374
- /// } else {
375
- /// "".chars()
376
- /// })
333
+ /// let more_correct: Vec<i32> = ns.iter()
334
+ /// .cloned()
335
+ /// .filter_map(|x| x)
377
336
/// .collect();
378
337
///
379
- /// println!("{:?}", correct );
338
+ /// println!("{:?}", more_correct );
380
339
/// assert_eq!(correct, more_correct);
340
+ ///
381
341
declare_clippy_lint ! {
382
342
pub FILTER_MAP ,
383
343
pedantic,
384
- "using combinations of `filter`, `map`, `filter_map` and `flat_map` which can usually be written as a single method call"
344
+ "using `filter` and `map` to destructure an iterator of Options or a Results instead of a single `filter_map` call"
385
345
}
386
346
387
347
/// **What it does:** Checks for an iterator search (such as `find()`,
@@ -933,7 +893,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
933
893
[ "next" , "filter" ] => lint_filter_next ( cx, expr, arg_lists[ 1 ] ) ,
934
894
[ "map" , "filter" ] => lint_filter_map ( cx, expr, arg_lists[ 1 ] , arg_lists[ 0 ] ) ,
935
895
[ "map" , "filter_map" ] => lint_filter_map_map ( cx, expr, arg_lists[ 1 ] , arg_lists[ 0 ] ) ,
936
- [ "flat_map" , "filter" ] => lint_filter_flat_map ( cx, expr, arg_lists[ 1 ] , arg_lists[ 0 ] ) ,
937
896
[ "flatten" , "map" ] => lint_map_flatten ( cx, expr, arg_lists[ 1 ] ) ,
938
897
[ "is_some" , "find" ] => lint_search_is_some ( cx, expr, "find" , arg_lists[ 1 ] , arg_lists[ 0 ] ) ,
939
898
[ "is_some" , "position" ] => lint_search_is_some ( cx, expr, "position" , arg_lists[ 1 ] , arg_lists[ 0 ] ) ,
@@ -1984,14 +1943,25 @@ fn lint_filter_next<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr,
1984
1943
}
1985
1944
}
1986
1945
1987
- /// lint filter_map variants that iterate over Result or Option values
1988
- fn lint_filter_map_variant < ' a , ' tcx > (
1946
+ /// lint use of `filter().map()` for `Iterators`
1947
+ fn lint_filter_map < ' a , ' tcx > (
1989
1948
cx : & LateContext < ' a , ' tcx > ,
1990
1949
expr : & ' tcx hir:: Expr ,
1991
1950
filter_args : & ' tcx [ hir:: Expr ] ,
1992
1951
map_args : & ' tcx [ hir:: Expr ] ,
1993
- responses : & HashMap < String , & str > ,
1994
1952
) {
1953
+ let mut responses: HashMap < String , & str > = HashMap :: new ( ) ;
1954
+ responses. insert (
1955
+ "is_some" . to_string ( ) ,
1956
+ "called `filter(p).map(q)` on an `Iterator<Option<_>>`. \
1957
+ Consider calling `.filter_map(..)` instead."
1958
+ ) ;
1959
+ responses. insert (
1960
+ "is_ok" . to_string ( ) ,
1961
+ "called `filter(p).map(q)` on an `Iterator<Result<_>>`. \
1962
+ Consider calling `.filter_map(..)` instead."
1963
+ ) ;
1964
+
1995
1965
if_chain ! {
1996
1966
if match_trait_method( cx, expr, & paths:: ITERATOR ) ;
1997
1967
if let hir:: ExprKind :: Closure ( _, _, ref map_body_id, _, _) = map_args[ 1 ] . node;
@@ -2009,28 +1979,6 @@ fn lint_filter_map_variant<'a, 'tcx>(
2009
1979
}
2010
1980
}
2011
1981
2012
- /// lint use of `filter().map()` for `Iterators`
2013
- fn lint_filter_map < ' a , ' tcx > (
2014
- cx : & LateContext < ' a , ' tcx > ,
2015
- expr : & ' tcx hir:: Expr ,
2016
- filter_args : & ' tcx [ hir:: Expr ] ,
2017
- map_args : & ' tcx [ hir:: Expr ] ,
2018
- ) {
2019
- let mut responses: HashMap < String , & str > = HashMap :: new ( ) ;
2020
- responses. insert (
2021
- "is_some" . to_string ( ) ,
2022
- "called `filter(p).map(q)` on an `Iterator<Option<_>>`. \
2023
- Consider calling `.filter_map(..)` instead."
2024
- ) ;
2025
- responses. insert (
2026
- "is_ok" . to_string ( ) ,
2027
- "called `filter(p).map(q)` on an `Iterator<Result<_>>`. \
2028
- Consider calling `.filter_map(..)` instead."
2029
- ) ;
2030
-
2031
- lint_filter_map_variant ( cx, expr, filter_args, map_args, & responses) ;
2032
- }
2033
-
2034
1982
/// lint use of `filter().map()` for `Iterators`
2035
1983
fn lint_filter_map_map < ' a , ' tcx > (
2036
1984
cx : & LateContext < ' a , ' tcx > ,
@@ -2049,27 +1997,10 @@ fn lint_filter_map_map<'a, 'tcx>(
2049
1997
if match_trait_method ( cx, expr, & paths:: ITERATOR ) {
2050
1998
let msg = "called `filter_map(p).map(q)` on an `Iterator`. \
2051
1999
This is more succinctly expressed by only calling `.filter_map(..)` instead.";
2052
- span_lint ( cx, FILTER_MAP , span, msg) ;
2000
+ span_lint ( cx, FILTER_MAP_MAP , span, msg) ;
2053
2001
}
2054
2002
}
2055
2003
2056
- /// lint use of `filter().flat_map()` for `Iterators`
2057
- fn lint_filter_flat_map < ' a , ' tcx > (
2058
- cx : & LateContext < ' a , ' tcx > ,
2059
- expr : & ' tcx hir:: Expr ,
2060
- filter_args : & ' tcx [ hir:: Expr ] ,
2061
- map_args : & ' tcx [ hir:: Expr ] ,
2062
- ) {
2063
- let mut responses: HashMap < String , & str > = HashMap :: new ( ) ;
2064
- responses. insert (
2065
- "is_some" . to_string ( ) ,
2066
- "called `filter(p).flat_map(q)` on an `Iterator<Option<_>>`. \
2067
- Consider calling `.filter_map(..)` instead."
2068
- ) ;
2069
-
2070
- lint_filter_map_variant ( cx, expr, filter_args, map_args, & responses) ;
2071
- }
2072
-
2073
2004
/// lint searching an Iterator followed by `is_some()`
2074
2005
fn lint_search_is_some < ' a , ' tcx > (
2075
2006
cx : & LateContext < ' a , ' tcx > ,
0 commit comments