@@ -5,8 +5,9 @@ use crate::utils::usage::{is_unused, mutated_variables};
55use crate :: utils:: {
66 contains_name, get_enclosing_block, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait,
77 is_integer_const, is_no_std_crate, is_refutable, is_type_diagnostic_item, last_path_segment, match_trait_method,
8- match_type, match_var, multispan_sugg, qpath_res, snippet, snippet_with_applicability, snippet_with_macro_callsite,
9- span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, sugg, SpanlessEq ,
8+ match_type, match_var, multispan_sugg, qpath_res, single_segment_path, snippet, snippet_with_applicability,
9+ snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, sugg,
10+ SpanlessEq ,
1011} ;
1112use if_chain:: if_chain;
1213use rustc_ast:: ast;
@@ -452,6 +453,31 @@ declare_clippy_lint! {
452453 "the same item is pushed inside of a for loop"
453454}
454455
456+ declare_clippy_lint ! {
457+ /// **What it does:** Checks whether a for loop has a single element.
458+ ///
459+ /// **Why is this bad?** There is no reason to have a loop of a
460+ /// single element.
461+ /// **Known problems:** None
462+ ///
463+ /// **Example:**
464+ /// ```rust
465+ /// let item1 = 2;
466+ /// for item in &[item1] {
467+ /// println!("{}", item);
468+ /// }
469+ /// ```
470+ /// could be written as
471+ /// ```rust
472+ /// let item1 = 2;
473+ /// let item = &item1;
474+ /// println!("{}", item);
475+ /// ```
476+ pub SINGLE_ELEMENT_LOOP ,
477+ complexity,
478+ "there is no reason to have a single element loop"
479+ }
480+
455481declare_lint_pass ! ( Loops => [
456482 MANUAL_MEMCPY ,
457483 NEEDLESS_RANGE_LOOP ,
@@ -469,6 +495,7 @@ declare_lint_pass!(Loops => [
469495 MUT_RANGE_BOUND ,
470496 WHILE_IMMUTABLE_CONDITION ,
471497 SAME_ITEM_PUSH ,
498+ SINGLE_ELEMENT_LOOP ,
472499] ) ;
473500
474501impl < ' tcx > LateLintPass < ' tcx > for Loops {
@@ -776,6 +803,8 @@ fn check_for_loop<'tcx>(
776803 check_for_loop_arg ( cx, pat, arg, expr) ;
777804 check_for_loop_over_map_kv ( cx, pat, arg, body, expr) ;
778805 check_for_mut_range_bound ( cx, arg, body) ;
806+ check_for_single_element_loop ( cx, pat, arg) ;
807+ detect_manual_memcpy ( cx, pat, arg, body, expr) ;
779808 detect_same_item_push ( cx, pat, arg, body, expr) ;
780809}
781810
@@ -1865,6 +1894,29 @@ fn check_for_loop_over_map_kv<'tcx>(
18651894 }
18661895}
18671896
1897+ fn check_for_single_element_loop < ' tcx > ( cx : & LateContext < ' tcx > , pat : & ' tcx Pat < ' _ > , arg : & ' tcx Expr < ' _ > ) {
1898+ if_chain ! {
1899+ if let ExprKind :: AddrOf ( BorrowKind :: Ref , _, ref expr) = arg. kind;
1900+ if let PatKind :: Binding ( .., target, _) = pat. kind;
1901+ if let ExprKind :: Array ( ref expr_list) = expr. kind;
1902+ if expr_list. len( ) == 1 ;
1903+ if let ExprKind :: Path ( ref list_item) = expr_list[ 0 ] . kind;
1904+ if let Some ( list_tem_name) = single_segment_path( list_item) . map( |ps| ps. ident. name) ;
1905+
1906+ then {
1907+ span_lint_and_sugg(
1908+ cx,
1909+ SINGLE_ELEMENT_LOOP ,
1910+ expr. span,
1911+ "do not iterate over a single element array" ,
1912+ "try" ,
1913+ format!( "let {} = &{};" , target. name, list_tem_name) ,
1914+ Applicability :: MachineApplicable
1915+ )
1916+ }
1917+ }
1918+ }
1919+
18681920struct MutatePairDelegate < ' a , ' tcx > {
18691921 cx : & ' a LateContext < ' tcx > ,
18701922 hir_id_low : Option < HirId > ,
0 commit comments