@@ -3,11 +3,11 @@ use super::MANUAL_FLATTEN;
33use clippy_utils:: diagnostics:: span_lint_and_then;
44use clippy_utils:: higher;
55use clippy_utils:: visitors:: is_local_used;
6- use clippy_utils:: { is_lang_ctor, path_to_local_id} ;
6+ use clippy_utils:: { is_lang_ctor, path_to_local_id, peel_blocks_with_stmt } ;
77use if_chain:: if_chain;
88use rustc_errors:: Applicability ;
99use rustc_hir:: LangItem :: { OptionSome , ResultOk } ;
10- use rustc_hir:: { Expr , ExprKind , Pat , PatKind , StmtKind } ;
10+ use rustc_hir:: { Expr , Pat , PatKind } ;
1111use rustc_lint:: LateContext ;
1212use rustc_middle:: ty;
1313use rustc_span:: source_map:: Span ;
@@ -21,71 +21,55 @@ pub(super) fn check<'tcx>(
2121 body : & ' tcx Expr < ' _ > ,
2222 span : Span ,
2323) {
24- if let ExprKind :: Block ( block, _) = body. kind {
25- // Ensure the `if let` statement is the only expression or statement in the for-loop
26- let inner_expr = if block. stmts . len ( ) == 1 && block. expr . is_none ( ) {
27- let match_stmt = & block. stmts [ 0 ] ;
28- if let StmtKind :: Semi ( inner_expr) = match_stmt. kind {
29- Some ( inner_expr)
30- } else {
31- None
32- }
33- } else if block. stmts . is_empty ( ) {
34- block. expr
35- } else {
36- None
37- } ;
24+ let inner_expr = peel_blocks_with_stmt ( body) ;
25+ if_chain ! {
26+ if let Some ( higher:: IfLet { let_pat, let_expr, if_then, if_else: None } )
27+ = higher:: IfLet :: hir( cx, inner_expr) ;
28+ // Ensure match_expr in `if let` statement is the same as the pat from the for-loop
29+ if let PatKind :: Binding ( _, pat_hir_id, _, _) = pat. kind;
30+ if path_to_local_id( let_expr, pat_hir_id) ;
31+ // Ensure the `if let` statement is for the `Some` variant of `Option` or the `Ok` variant of `Result`
32+ if let PatKind :: TupleStruct ( ref qpath, _, _) = let_pat. kind;
33+ let some_ctor = is_lang_ctor( cx, qpath, OptionSome ) ;
34+ let ok_ctor = is_lang_ctor( cx, qpath, ResultOk ) ;
35+ if some_ctor || ok_ctor;
36+ // Ensure expr in `if let` is not used afterwards
37+ if !is_local_used( cx, if_then, pat_hir_id) ;
38+ then {
39+ let if_let_type = if some_ctor { "Some" } else { "Ok" } ;
40+ // Prepare the error message
41+ let msg = format!( "unnecessary `if let` since only the `{}` variant of the iterator element is used" , if_let_type) ;
3842
39- if_chain ! {
40- if let Some ( inner_expr) = inner_expr;
41- if let Some ( higher:: IfLet { let_pat, let_expr, if_then, if_else: None } )
42- = higher:: IfLet :: hir( cx, inner_expr) ;
43- // Ensure match_expr in `if let` statement is the same as the pat from the for-loop
44- if let PatKind :: Binding ( _, pat_hir_id, _, _) = pat. kind;
45- if path_to_local_id( let_expr, pat_hir_id) ;
46- // Ensure the `if let` statement is for the `Some` variant of `Option` or the `Ok` variant of `Result`
47- if let PatKind :: TupleStruct ( ref qpath, _, _) = let_pat. kind;
48- let some_ctor = is_lang_ctor( cx, qpath, OptionSome ) ;
49- let ok_ctor = is_lang_ctor( cx, qpath, ResultOk ) ;
50- if some_ctor || ok_ctor;
51- // Ensure epxr in `if let` is not used afterwards
52- if !is_local_used( cx, if_then, pat_hir_id) ;
53- then {
54- let if_let_type = if some_ctor { "Some" } else { "Ok" } ;
55- // Prepare the error message
56- let msg = format!( "unnecessary `if let` since only the `{}` variant of the iterator element is used" , if_let_type) ;
57-
58- // Prepare the help message
59- let mut applicability = Applicability :: MaybeIncorrect ;
60- let arg_snippet = make_iterator_snippet( cx, arg, & mut applicability) ;
61- let copied = match cx. typeck_results( ) . expr_ty( let_expr) . kind( ) {
62- ty:: Ref ( _, inner, _) => match inner. kind( ) {
63- ty:: Ref ( ..) => ".copied()" ,
64- _ => ""
65- }
43+ // Prepare the help message
44+ let mut applicability = Applicability :: MaybeIncorrect ;
45+ let arg_snippet = make_iterator_snippet( cx, arg, & mut applicability) ;
46+ let copied = match cx. typeck_results( ) . expr_ty( let_expr) . kind( ) {
47+ ty:: Ref ( _, inner, _) => match inner. kind( ) {
48+ ty:: Ref ( ..) => ".copied()" ,
6649 _ => ""
67- } ;
50+ }
51+ _ => ""
52+ } ;
6853
69- span_lint_and_then(
70- cx,
71- MANUAL_FLATTEN ,
72- span,
73- & msg,
74- |diag| {
75- let sugg = format!( "{}{}.flatten()" , arg_snippet, copied) ;
76- diag. span_suggestion(
77- arg. span,
78- "try" ,
79- sugg,
80- Applicability :: MaybeIncorrect ,
81- ) ;
82- diag. span_help(
83- inner_expr. span,
84- "...and remove the `if let` statement in the for loop" ,
85- ) ;
86- }
87- ) ;
88- }
54+ span_lint_and_then(
55+ cx,
56+ MANUAL_FLATTEN ,
57+ span,
58+ & msg,
59+ |diag| {
60+ let sugg = format!( "{}{}.flatten()" , arg_snippet, copied) ;
61+ diag. span_suggestion(
62+ arg. span,
63+ "try" ,
64+ sugg,
65+ Applicability :: MaybeIncorrect ,
66+ ) ;
67+ diag. span_help(
68+ inner_expr. span,
69+ "...and remove the `if let` statement in the for loop" ,
70+ ) ;
71+ }
72+ ) ;
8973 }
9074 }
9175}
0 commit comments