@@ -1996,52 +1996,82 @@ fn check_manual_flatten<'tcx>(
1996
1996
body : & ' tcx Expr < ' _ > ,
1997
1997
span : Span ,
1998
1998
) {
1999
- if_chain ! {
2000
- // Ensure the `if let` statement is the only expression in the for-loop
2001
- if let ExprKind :: Block ( ref block, _) = body. kind;
2002
- if block. stmts. is_empty( ) ;
2003
- if let Some ( inner_expr) = block. expr;
2004
- if let ExprKind :: Match (
2005
- ref match_expr, ref match_arms, MatchSource :: IfLetDesugar { contains_else_clause: false }
2006
- ) = inner_expr. kind;
2007
- // Ensure match_expr in `if let` statement is the same as the pat from the for-loop
2008
- if let PatKind :: Binding ( _, pat_hir_id, _, _) = pat. kind;
2009
- if let ExprKind :: Path ( QPath :: Resolved ( None , match_expr_path) ) = match_expr. kind;
2010
- if let Res :: Local ( match_expr_path_id) = match_expr_path. res;
2011
- if pat_hir_id == match_expr_path_id;
2012
- // Ensure the `if let` statement is for the `Some` variant of `Option` or the `Ok` variant of `Result`
2013
- if let PatKind :: TupleStruct ( QPath :: Resolved ( None , path) , _, _) = match_arms[ 0 ] . pat. kind;
2014
- if is_some_ctor( cx, path. res) || is_ok_ctor( cx, path. res) ;
2015
- let if_let_type = if is_some_ctor( cx, path. res) {
2016
- "Some"
1999
+ if let ExprKind :: Block ( ref block, _) = body. kind {
2000
+ // Ensure the `if let` statement is the only expression or statement in the for-loop
2001
+ let inner_expr = if block. stmts . len ( ) == 1 && block. expr . is_none ( ) {
2002
+ let match_stmt = & block. stmts [ 0 ] ;
2003
+ if let StmtKind :: Semi ( inner_expr) = match_stmt. kind {
2004
+ Some ( inner_expr)
2005
+ } else {
2006
+ None
2007
+ }
2008
+ } else if block. stmts . is_empty ( ) {
2009
+ block. expr
2017
2010
} else {
2018
- "Ok"
2011
+ None
2019
2012
} ;
2020
- // Determine if `arg` is `Iterator` or implicitly calls `into_iter`
2021
- let arg_ty = cx. typeck_results( ) . expr_ty( arg) ;
2022
- if let Some ( id) = get_trait_def_id( cx, & paths:: ITERATOR ) ;
2023
- if let is_iterator = implements_trait( cx, arg_ty, id, & [ ] ) ;
2024
2013
2025
- then {
2026
- // Prepare the error message
2027
- let msg = format!( "Unnecessary `if let` since only the `{}` variant of the iterator element is used." , if_let_type) ;
2014
+ if_chain ! {
2015
+ if let Some ( inner_expr) = inner_expr;
2016
+ if let ExprKind :: Match (
2017
+ ref match_expr, ref match_arms, MatchSource :: IfLetDesugar { contains_else_clause: false }
2018
+ ) = inner_expr. kind;
2019
+ // Ensure match_expr in `if let` statement is the same as the pat from the for-loop
2020
+ if let PatKind :: Binding ( _, pat_hir_id, _, _) = pat. kind;
2021
+ if let ExprKind :: Path ( QPath :: Resolved ( None , match_expr_path) ) = match_expr. kind;
2022
+ if let Res :: Local ( match_expr_path_id) = match_expr_path. res;
2023
+ if pat_hir_id == match_expr_path_id;
2024
+ // Ensure the `if let` statement is for the `Some` variant of `Option` or the `Ok` variant of `Result`
2025
+ if let PatKind :: TupleStruct ( QPath :: Resolved ( None , path) , _, _) = match_arms[ 0 ] . pat. kind;
2026
+ let some_ctor = is_some_ctor( cx, path. res) ;
2027
+ let ok_ctor = is_ok_ctor( cx, path. res) ;
2028
+ if some_ctor || ok_ctor;
2029
+ let if_let_type = if some_ctor { "Some" } else { "Ok" } ;
2028
2030
2029
- // Prepare the help message
2030
- let arg_snippet = snippet( cx, arg. span, ".." ) ;
2031
- let hint = if is_iterator {
2032
- format!( "try: `{}.flatten()`" , arg_snippet)
2033
- } else {
2034
- format!( "try: `{}.into_iter().flatten()`" , arg_snippet)
2035
- } ;
2031
+ then {
2032
+ // Prepare the error message
2033
+ let msg = format!( "unnecessary `if let` since only the `{}` variant of the iterator element is used" , if_let_type) ;
2036
2034
2037
- span_lint_and_help(
2038
- cx,
2039
- MANUAL_FLATTEN ,
2040
- span,
2041
- & msg,
2042
- Some ( arg. span) ,
2043
- & hint,
2044
- ) ;
2035
+ // Prepare the help message
2036
+ let mut applicability = Applicability :: MaybeIncorrect ;
2037
+ let arg_snippet = snippet_with_applicability(
2038
+ cx,
2039
+ arg. span,
2040
+ ".." ,
2041
+ & mut applicability,
2042
+ ) ;
2043
+ // Determine if `arg` is by reference, an `Iterator`, or implicitly adjusted with `into_iter`
2044
+ let hint = match arg. kind {
2045
+ ExprKind :: AddrOf ( _, _, arg_expr) => {
2046
+ format!( "{}.iter().flatten()" , snippet( cx, arg_expr. span, ".." ) )
2047
+ } ,
2048
+ ExprKind :: MethodCall ( _, _, _, _) | ExprKind :: Path ( QPath :: Resolved ( None , _) ) => {
2049
+ // Determine if `arg` is `Iterator` or implicitly calls `into_iter`
2050
+ let arg_ty = cx. typeck_results( ) . expr_ty( arg) ;
2051
+ if let Some ( id) = get_trait_def_id( cx, & paths:: ITERATOR ) {
2052
+ let is_iterator = implements_trait( cx, arg_ty, id, & [ ] ) ;
2053
+ if is_iterator {
2054
+ format!( "{}.flatten()" , arg_snippet)
2055
+ } else {
2056
+ format!( "{}.into_iter().flatten()" , arg_snippet)
2057
+ }
2058
+ } else {
2059
+ return
2060
+ }
2061
+ } ,
2062
+ _ => return ,
2063
+ } ;
2064
+
2065
+ span_lint_and_sugg(
2066
+ cx,
2067
+ MANUAL_FLATTEN ,
2068
+ span,
2069
+ & msg,
2070
+ "try" ,
2071
+ hint,
2072
+ applicability,
2073
+ )
2074
+ }
2045
2075
}
2046
2076
}
2047
2077
}
0 commit comments