@@ -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,7 @@ 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) ;
779807 detect_same_item_push ( cx, pat, arg, body, expr) ;
780808}
781809
@@ -1865,6 +1893,29 @@ fn check_for_loop_over_map_kv<'tcx>(
18651893 }
18661894}
18671895
1896+ fn check_for_single_element_loop < ' tcx > ( cx : & LateContext < ' tcx > , pat : & ' tcx Pat < ' _ > , arg : & ' tcx Expr < ' _ > ) {
1897+ if_chain ! {
1898+ if let ExprKind :: AddrOf ( BorrowKind :: Ref , _, ref expr) = arg. kind;
1899+ if let PatKind :: Binding ( .., target, _) = pat. kind;
1900+ if let ExprKind :: Array ( ref expr_list) = expr. kind;
1901+ if expr_list. len( ) == 1 ;
1902+ if let ExprKind :: Path ( ref list_item) = expr_list[ 0 ] . kind;
1903+ if let Some ( list_tem_name) = single_segment_path( list_item) . map( |ps| ps. ident. name) ;
1904+
1905+ then {
1906+ span_lint_and_sugg(
1907+ cx,
1908+ SINGLE_ELEMENT_LOOP ,
1909+ expr. span,
1910+ "do not iterate over a single element array" ,
1911+ "try" ,
1912+ format!( "let {} = &{};" , target. name, list_tem_name) ,
1913+ Applicability :: MachineApplicable
1914+ )
1915+ }
1916+ }
1917+ }
1918+
18681919struct MutatePairDelegate < ' a , ' tcx > {
18691920 cx : & ' a LateContext < ' tcx > ,
18701921 hir_id_low : Option < HirId > ,
0 commit comments