1
+ mod manual_flatten;
2
+ mod utils;
3
+
1
4
use crate :: consts:: constant;
2
5
use crate :: utils:: sugg:: Sugg ;
3
6
use crate :: utils:: usage:: mutated_variables;
4
7
use crate :: utils:: visitors:: LocalUsedVisitor ;
5
8
use crate :: utils:: {
6
9
contains_name, get_enclosing_block, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait,
7
- indent_of, is_in_panic_handler, is_integer_const, is_no_std_crate, is_ok_ctor , is_refutable, is_some_ctor ,
8
- is_type_diagnostic_item , last_path_segment, match_trait_method, match_type, multispan_sugg, path_to_local,
9
- path_to_local_id , paths , single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite,
10
- span_lint , span_lint_and_help, span_lint_and_sugg, span_lint_and_then, sugg, SpanlessEq ,
10
+ indent_of, is_in_panic_handler, is_integer_const, is_no_std_crate, is_refutable, is_type_diagnostic_item ,
11
+ last_path_segment, match_trait_method, match_type, multispan_sugg, path_to_local, path_to_local_id , paths ,
12
+ single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint ,
13
+ span_lint_and_help, span_lint_and_sugg, span_lint_and_then, sugg, SpanlessEq ,
11
14
} ;
12
15
use if_chain:: if_chain;
13
16
use rustc_ast:: ast;
@@ -31,6 +34,7 @@ use rustc_span::symbol::{sym, Ident, Symbol};
31
34
use rustc_typeck:: expr_use_visitor:: { ConsumeMode , Delegate , ExprUseVisitor , PlaceBase , PlaceWithHirId } ;
32
35
use std:: iter:: { once, Iterator } ;
33
36
use std:: mem;
37
+ use utils:: make_iterator_snippet;
34
38
35
39
declare_clippy_lint ! {
36
40
/// **What it does:** Checks for for-loops that manually copy items between
@@ -862,7 +866,7 @@ fn check_for_loop<'tcx>(
862
866
check_for_mut_range_bound ( cx, arg, body) ;
863
867
check_for_single_element_loop ( cx, pat, arg, body, expr) ;
864
868
detect_same_item_push ( cx, pat, arg, body, expr) ;
865
- check_manual_flatten ( cx, pat, arg, body, span) ;
869
+ manual_flatten :: lint ( cx, pat, arg, body, span) ;
866
870
}
867
871
868
872
// this function assumes the given expression is a `for` loop.
@@ -1839,42 +1843,6 @@ fn check_for_loop_explicit_counter<'tcx>(
1839
1843
}
1840
1844
}
1841
1845
1842
- /// If `arg` was the argument to a `for` loop, return the "cleanest" way of writing the
1843
- /// actual `Iterator` that the loop uses.
1844
- fn make_iterator_snippet ( cx : & LateContext < ' _ > , arg : & Expr < ' _ > , applic_ref : & mut Applicability ) -> String {
1845
- let impls_iterator = get_trait_def_id ( cx, & paths:: ITERATOR ) . map_or ( false , |id| {
1846
- implements_trait ( cx, cx. typeck_results ( ) . expr_ty ( arg) , id, & [ ] )
1847
- } ) ;
1848
- if impls_iterator {
1849
- format ! (
1850
- "{}" ,
1851
- sugg:: Sugg :: hir_with_applicability( cx, arg, "_" , applic_ref) . maybe_par( )
1852
- )
1853
- } else {
1854
- // (&x).into_iter() ==> x.iter()
1855
- // (&mut x).into_iter() ==> x.iter_mut()
1856
- match & arg. kind {
1857
- ExprKind :: AddrOf ( BorrowKind :: Ref , mutability, arg_inner)
1858
- if has_iter_method ( cx, cx. typeck_results ( ) . expr_ty ( & arg_inner) ) . is_some ( ) =>
1859
- {
1860
- let meth_name = match mutability {
1861
- Mutability :: Mut => "iter_mut" ,
1862
- Mutability :: Not => "iter" ,
1863
- } ;
1864
- format ! (
1865
- "{}.{}()" ,
1866
- sugg:: Sugg :: hir_with_applicability( cx, & arg_inner, "_" , applic_ref) . maybe_par( ) ,
1867
- meth_name,
1868
- )
1869
- }
1870
- _ => format ! (
1871
- "{}.into_iter()" ,
1872
- sugg:: Sugg :: hir_with_applicability( cx, arg, "_" , applic_ref) . maybe_par( )
1873
- ) ,
1874
- }
1875
- }
1876
- }
1877
-
1878
1846
/// Checks for the `FOR_KV_MAP` lint.
1879
1847
fn check_for_loop_over_map_kv < ' tcx > (
1880
1848
cx : & LateContext < ' tcx > ,
@@ -1964,77 +1932,6 @@ fn check_for_single_element_loop<'tcx>(
1964
1932
}
1965
1933
}
1966
1934
1967
- /// Check for unnecessary `if let` usage in a for loop where only the `Some` or `Ok` variant of the
1968
- /// iterator element is used.
1969
- fn check_manual_flatten < ' tcx > (
1970
- cx : & LateContext < ' tcx > ,
1971
- pat : & ' tcx Pat < ' _ > ,
1972
- arg : & ' tcx Expr < ' _ > ,
1973
- body : & ' tcx Expr < ' _ > ,
1974
- span : Span ,
1975
- ) {
1976
- if let ExprKind :: Block ( ref block, _) = body. kind {
1977
- // Ensure the `if let` statement is the only expression or statement in the for-loop
1978
- let inner_expr = if block. stmts . len ( ) == 1 && block. expr . is_none ( ) {
1979
- let match_stmt = & block. stmts [ 0 ] ;
1980
- if let StmtKind :: Semi ( inner_expr) = match_stmt. kind {
1981
- Some ( inner_expr)
1982
- } else {
1983
- None
1984
- }
1985
- } else if block. stmts . is_empty ( ) {
1986
- block. expr
1987
- } else {
1988
- None
1989
- } ;
1990
-
1991
- if_chain ! {
1992
- if let Some ( inner_expr) = inner_expr;
1993
- if let ExprKind :: Match (
1994
- ref match_expr, ref match_arms, MatchSource :: IfLetDesugar { contains_else_clause: false }
1995
- ) = inner_expr. kind;
1996
- // Ensure match_expr in `if let` statement is the same as the pat from the for-loop
1997
- if let PatKind :: Binding ( _, pat_hir_id, _, _) = pat. kind;
1998
- if path_to_local_id( match_expr, pat_hir_id) ;
1999
- // Ensure the `if let` statement is for the `Some` variant of `Option` or the `Ok` variant of `Result`
2000
- if let PatKind :: TupleStruct ( QPath :: Resolved ( None , path) , _, _) = match_arms[ 0 ] . pat. kind;
2001
- let some_ctor = is_some_ctor( cx, path. res) ;
2002
- let ok_ctor = is_ok_ctor( cx, path. res) ;
2003
- if some_ctor || ok_ctor;
2004
- let if_let_type = if some_ctor { "Some" } else { "Ok" } ;
2005
-
2006
- then {
2007
- // Prepare the error message
2008
- let msg = format!( "unnecessary `if let` since only the `{}` variant of the iterator element is used" , if_let_type) ;
2009
-
2010
- // Prepare the help message
2011
- let mut applicability = Applicability :: MaybeIncorrect ;
2012
- let arg_snippet = make_iterator_snippet( cx, arg, & mut applicability) ;
2013
-
2014
- span_lint_and_then(
2015
- cx,
2016
- MANUAL_FLATTEN ,
2017
- span,
2018
- & msg,
2019
- |diag| {
2020
- let sugg = format!( "{}.flatten()" , arg_snippet) ;
2021
- diag. span_suggestion(
2022
- arg. span,
2023
- "try" ,
2024
- sugg,
2025
- Applicability :: MaybeIncorrect ,
2026
- ) ;
2027
- diag. span_help(
2028
- inner_expr. span,
2029
- "...and remove the `if let` statement in the for loop" ,
2030
- ) ;
2031
- }
2032
- ) ;
2033
- }
2034
- }
2035
- }
2036
- }
2037
-
2038
1935
struct MutatePairDelegate < ' a , ' tcx > {
2039
1936
cx : & ' a LateContext < ' tcx > ,
2040
1937
hir_id_low : Option < HirId > ,
0 commit comments