@@ -25,9 +25,11 @@ mod iter_nth_zero;
25
25
mod iterator_step_by_zero;
26
26
mod manual_saturating_arithmetic;
27
27
mod map_collect_result_unit;
28
+ mod map_flatten;
28
29
mod ok_expect;
29
30
mod option_as_ref_deref;
30
31
mod option_map_unwrap_or;
32
+ mod search_is_some;
31
33
mod single_char_insert_string;
32
34
mod single_char_pattern;
33
35
mod single_char_push_string;
@@ -1711,13 +1713,13 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
1711
1713
[ "flat_map" , "filter" ] => filter_flat_map:: check ( cx, expr, arg_lists[ 1 ] , arg_lists[ 0 ] ) ,
1712
1714
[ "flat_map" , "filter_map" ] => filter_map_flat_map:: check ( cx, expr, arg_lists[ 1 ] , arg_lists[ 0 ] ) ,
1713
1715
[ "flat_map" , ..] => flat_map_identity:: check ( cx, expr, arg_lists[ 0 ] , method_spans[ 0 ] ) ,
1714
- [ "flatten" , "map" ] => lint_map_flatten ( cx, expr, arg_lists[ 1 ] ) ,
1715
- [ "is_some" , "find" ] => lint_search_is_some ( cx, expr, "find" , arg_lists[ 1 ] , arg_lists[ 0 ] , method_spans[ 1 ] ) ,
1716
+ [ "flatten" , "map" ] => map_flatten :: check ( cx, expr, arg_lists[ 1 ] ) ,
1717
+ [ "is_some" , "find" ] => search_is_some :: check ( cx, expr, "find" , arg_lists[ 1 ] , arg_lists[ 0 ] , method_spans[ 1 ] ) ,
1716
1718
[ "is_some" , "position" ] => {
1717
- lint_search_is_some ( cx, expr, "position" , arg_lists[ 1 ] , arg_lists[ 0 ] , method_spans[ 1 ] )
1719
+ search_is_some :: check ( cx, expr, "position" , arg_lists[ 1 ] , arg_lists[ 0 ] , method_spans[ 1 ] )
1718
1720
} ,
1719
1721
[ "is_some" , "rposition" ] => {
1720
- lint_search_is_some ( cx, expr, "rposition" , arg_lists[ 1 ] , arg_lists[ 0 ] , method_spans[ 1 ] )
1722
+ search_is_some :: check ( cx, expr, "rposition" , arg_lists[ 1 ] , arg_lists[ 0 ] , method_spans[ 1 ] )
1721
1723
} ,
1722
1724
[ "extend" , ..] => string_extend_chars:: check ( cx, expr, arg_lists[ 0 ] ) ,
1723
1725
[ "count" , "into_iter" ] => iter_count:: check ( cx, expr, & arg_lists[ 1 ] , "into_iter" ) ,
@@ -2566,59 +2568,6 @@ fn derefs_to_slice<'tcx>(
2566
2568
}
2567
2569
}
2568
2570
2569
- /// lint use of `map().flatten()` for `Iterators` and 'Options'
2570
- fn lint_map_flatten < ' tcx > ( cx : & LateContext < ' tcx > , expr : & ' tcx hir:: Expr < ' _ > , map_args : & ' tcx [ hir:: Expr < ' _ > ] ) {
2571
- // lint if caller of `.map().flatten()` is an Iterator
2572
- if match_trait_method ( cx, expr, & paths:: ITERATOR ) {
2573
- let map_closure_ty = cx. typeck_results ( ) . expr_ty ( & map_args[ 1 ] ) ;
2574
- let is_map_to_option = match map_closure_ty. kind ( ) {
2575
- ty:: Closure ( _, _) | ty:: FnDef ( _, _) | ty:: FnPtr ( _) => {
2576
- let map_closure_sig = match map_closure_ty. kind ( ) {
2577
- ty:: Closure ( _, substs) => substs. as_closure ( ) . sig ( ) ,
2578
- _ => map_closure_ty. fn_sig ( cx. tcx ) ,
2579
- } ;
2580
- let map_closure_return_ty = cx. tcx . erase_late_bound_regions ( map_closure_sig. output ( ) ) ;
2581
- is_type_diagnostic_item ( cx, map_closure_return_ty, sym:: option_type)
2582
- } ,
2583
- _ => false ,
2584
- } ;
2585
-
2586
- let method_to_use = if is_map_to_option {
2587
- // `(...).map(...)` has type `impl Iterator<Item=Option<...>>
2588
- "filter_map"
2589
- } else {
2590
- // `(...).map(...)` has type `impl Iterator<Item=impl Iterator<...>>
2591
- "flat_map"
2592
- } ;
2593
- let func_snippet = snippet ( cx, map_args[ 1 ] . span , ".." ) ;
2594
- let hint = format ! ( ".{0}({1})" , method_to_use, func_snippet) ;
2595
- span_lint_and_sugg (
2596
- cx,
2597
- MAP_FLATTEN ,
2598
- expr. span . with_lo ( map_args[ 0 ] . span . hi ( ) ) ,
2599
- "called `map(..).flatten()` on an `Iterator`" ,
2600
- & format ! ( "try using `{}` instead" , method_to_use) ,
2601
- hint,
2602
- Applicability :: MachineApplicable ,
2603
- ) ;
2604
- }
2605
-
2606
- // lint if caller of `.map().flatten()` is an Option
2607
- if is_type_diagnostic_item ( cx, cx. typeck_results ( ) . expr_ty ( & map_args[ 0 ] ) , sym:: option_type) {
2608
- let func_snippet = snippet ( cx, map_args[ 1 ] . span , ".." ) ;
2609
- let hint = format ! ( ".and_then({})" , func_snippet) ;
2610
- span_lint_and_sugg (
2611
- cx,
2612
- MAP_FLATTEN ,
2613
- expr. span . with_lo ( map_args[ 0 ] . span . hi ( ) ) ,
2614
- "called `map(..).flatten()` on an `Option`" ,
2615
- "try using `and_then` instead" ,
2616
- hint,
2617
- Applicability :: MachineApplicable ,
2618
- ) ;
2619
- }
2620
- }
2621
-
2622
2571
const MAP_UNWRAP_OR_MSRV : RustcVersion = RustcVersion :: new ( 1 , 41 , 0 ) ;
2623
2572
2624
2573
/// lint use of `map().unwrap_or_else()` for `Option`s and `Result`s
@@ -2756,93 +2705,6 @@ fn lint_map_or_none<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map
2756
2705
) ;
2757
2706
}
2758
2707
2759
- /// lint searching an Iterator followed by `is_some()`
2760
- /// or calling `find()` on a string followed by `is_some()`
2761
- fn lint_search_is_some < ' tcx > (
2762
- cx : & LateContext < ' tcx > ,
2763
- expr : & ' tcx hir:: Expr < ' _ > ,
2764
- search_method : & str ,
2765
- search_args : & ' tcx [ hir:: Expr < ' _ > ] ,
2766
- is_some_args : & ' tcx [ hir:: Expr < ' _ > ] ,
2767
- method_span : Span ,
2768
- ) {
2769
- // lint if caller of search is an Iterator
2770
- if match_trait_method ( cx, & is_some_args[ 0 ] , & paths:: ITERATOR ) {
2771
- let msg = format ! (
2772
- "called `is_some()` after searching an `Iterator` with `{}`" ,
2773
- search_method
2774
- ) ;
2775
- let hint = "this is more succinctly expressed by calling `any()`" ;
2776
- let search_snippet = snippet ( cx, search_args[ 1 ] . span , ".." ) ;
2777
- if search_snippet. lines ( ) . count ( ) <= 1 {
2778
- // suggest `any(|x| ..)` instead of `any(|&x| ..)` for `find(|&x| ..).is_some()`
2779
- // suggest `any(|..| *..)` instead of `any(|..| **..)` for `find(|..| **..).is_some()`
2780
- let any_search_snippet = if_chain ! {
2781
- if search_method == "find" ;
2782
- if let hir:: ExprKind :: Closure ( _, _, body_id, ..) = search_args[ 1 ] . kind;
2783
- let closure_body = cx. tcx. hir( ) . body( body_id) ;
2784
- if let Some ( closure_arg) = closure_body. params. get( 0 ) ;
2785
- then {
2786
- if let hir:: PatKind :: Ref ( ..) = closure_arg. pat. kind {
2787
- Some ( search_snippet. replacen( '&' , "" , 1 ) )
2788
- } else if let PatKind :: Binding ( _, _, ident, _) = strip_pat_refs( & closure_arg. pat) . kind {
2789
- let name = & * ident. name. as_str( ) ;
2790
- Some ( search_snippet. replace( & format!( "*{}" , name) , name) )
2791
- } else {
2792
- None
2793
- }
2794
- } else {
2795
- None
2796
- }
2797
- } ;
2798
- // add note if not multi-line
2799
- span_lint_and_sugg (
2800
- cx,
2801
- SEARCH_IS_SOME ,
2802
- method_span. with_hi ( expr. span . hi ( ) ) ,
2803
- & msg,
2804
- "use `any()` instead" ,
2805
- format ! (
2806
- "any({})" ,
2807
- any_search_snippet. as_ref( ) . map_or( & * search_snippet, String :: as_str)
2808
- ) ,
2809
- Applicability :: MachineApplicable ,
2810
- ) ;
2811
- } else {
2812
- span_lint_and_help ( cx, SEARCH_IS_SOME , expr. span , & msg, None , hint) ;
2813
- }
2814
- }
2815
- // lint if `find()` is called by `String` or `&str`
2816
- else if search_method == "find" {
2817
- let is_string_or_str_slice = |e| {
2818
- let self_ty = cx. typeck_results ( ) . expr_ty ( e) . peel_refs ( ) ;
2819
- if is_type_diagnostic_item ( cx, self_ty, sym:: string_type) {
2820
- true
2821
- } else {
2822
- * self_ty. kind ( ) == ty:: Str
2823
- }
2824
- } ;
2825
- if_chain ! {
2826
- if is_string_or_str_slice( & search_args[ 0 ] ) ;
2827
- if is_string_or_str_slice( & search_args[ 1 ] ) ;
2828
- then {
2829
- let msg = "called `is_some()` after calling `find()` on a string" ;
2830
- let mut applicability = Applicability :: MachineApplicable ;
2831
- let find_arg = snippet_with_applicability( cx, search_args[ 1 ] . span, ".." , & mut applicability) ;
2832
- span_lint_and_sugg(
2833
- cx,
2834
- SEARCH_IS_SOME ,
2835
- method_span. with_hi( expr. span. hi( ) ) ,
2836
- msg,
2837
- "use `contains()` instead" ,
2838
- format!( "contains({})" , find_arg) ,
2839
- applicability,
2840
- ) ;
2841
- }
2842
- }
2843
- }
2844
- }
2845
-
2846
2708
/// Used for `lint_binary_expr_with_method_call`.
2847
2709
#[ derive( Copy , Clone ) ]
2848
2710
struct BinaryExprInfo < ' a > {
0 commit comments