@@ -53,40 +53,41 @@ declare_clippy_lint! {
5353 #[ clippy:: version = "1.70.0" ]
5454 pub LINES_FILTER_MAP_OK ,
5555 suspicious,
56- "filtering `std::io::Lines` with `filter_map()` or `flat_map ()` might cause an infinite loop"
56+ "filtering `std::io::Lines` with `filter_map()`, `flat_map()`, or `flatten ()` might cause an infinite loop"
5757}
5858declare_lint_pass ! ( LinesFilterMapOk => [ LINES_FILTER_MAP_OK ] ) ;
5959
6060impl LateLintPass < ' _ > for LinesFilterMapOk {
6161 fn check_expr ( & mut self , cx : & LateContext < ' _ > , expr : & Expr < ' _ > ) {
62- if let ExprKind :: MethodCall ( fm_method, fm_receiver, [ fm_arg] , fm_span) = expr. kind
63- && is_trait_method ( cx, expr, sym:: Iterator )
64- && ( fm_method. ident . as_str ( ) == "filter_map" || fm_method. ident . as_str ( ) == "flat_map" )
65- && is_type_diagnostic_item ( cx, cx. typeck_results ( ) . expr_ty_adjusted ( fm_receiver) , sym:: IoLines )
62+ if let ExprKind :: MethodCall ( fm_method, fm_receiver, fm_args, fm_span) = expr. kind &&
63+ is_trait_method ( cx, expr, sym:: Iterator ) &&
64+ let fm_method_str = fm_method. ident . as_str ( ) &&
65+ matches ! ( fm_method_str, "filter_map" | "flat_map" | "flatten" ) &&
66+ is_type_diagnostic_item ( cx, cx. typeck_results ( ) . expr_ty_adjusted ( fm_receiver) , sym:: IoLines )
6667 {
67- let lint = match & fm_arg. kind {
68- // Detect `Result::ok`
69- ExprKind :: Path ( qpath) => cx
70- . qpath_res ( qpath, fm_arg. hir_id )
71- . opt_def_id ( )
72- . map ( |did| match_def_path ( cx, did, & paths:: CORE_RESULT_OK_METHOD ) )
73- . unwrap_or_default ( ) ,
74- // Detect `|x| x.ok()`
75- ExprKind :: Closure ( Closure { body, .. } ) => {
76- if let Body {
77- params : [ param] , value, ..
78- } = cx. tcx . hir ( ) . body ( * body)
79- && let ExprKind :: MethodCall ( method, receiver, [ ] , _) = value. kind
80- && path_to_local_id ( receiver, param. pat . hir_id )
81- && let Some ( method_did) = cx. typeck_results ( ) . type_dependent_def_id ( value. hir_id )
82- {
83- is_diag_item_method ( cx, method_did, sym:: Result ) && method. ident . as_str ( ) == "ok"
84- } else {
85- false
86- }
87- } ,
88- _ => false ,
68+ let lint = if let [ fm_arg] = fm_args {
69+ match & fm_arg. kind {
70+ // Detect `Result::ok`
71+ ExprKind :: Path ( qpath) =>
72+ cx. qpath_res ( qpath, fm_arg. hir_id ) . opt_def_id ( ) . map ( |did|
73+ match_def_path ( cx, did, & paths:: CORE_RESULT_OK_METHOD ) ) . unwrap_or_default ( ) ,
74+ // Detect `|x| x.ok()`
75+ ExprKind :: Closure ( Closure { body, .. } ) =>
76+ if let Body { params : [ param] , value, .. } = cx. tcx . hir ( ) . body ( * body) &&
77+ let ExprKind :: MethodCall ( method, receiver, [ ] , _) = value. kind &&
78+ path_to_local_id ( receiver, param. pat . hir_id ) &&
79+ let Some ( method_did) = cx. typeck_results ( ) . type_dependent_def_id ( value. hir_id )
80+ {
81+ is_diag_item_method ( cx, method_did, sym:: Result ) && method. ident . as_str ( ) == "ok"
82+ } else {
83+ false
84+ } ,
85+ _ => false ,
86+ }
87+ } else {
88+ fm_method_str == "flatten"
8989 } ;
90+
9091 if lint {
9192 span_lint_and_then (
9293 cx,
0 commit comments