@@ -4,9 +4,10 @@ use crate::utils::sugg::Sugg;
4
4
use crate :: utils:: usage:: { is_unused, mutated_variables} ;
5
5
use crate :: utils:: {
6
6
contains_name, get_enclosing_block, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait,
7
- 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 ,
7
+ indent_of, is_integer_const, is_no_std_crate, is_refutable, is_type_diagnostic_item, last_path_segment,
8
+ match_trait_method, match_type, match_var, multispan_sugg, qpath_res, single_segment_path, snippet,
9
+ snippet_with_applicability, snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg,
10
+ span_lint_and_then, sugg, SpanlessEq ,
10
11
} ;
11
12
use if_chain:: if_chain;
12
13
use rustc_ast:: ast;
@@ -452,6 +453,31 @@ declare_clippy_lint! {
452
453
"the same item is pushed inside of a for loop"
453
454
}
454
455
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
+
455
481
declare_lint_pass ! ( Loops => [
456
482
MANUAL_MEMCPY ,
457
483
NEEDLESS_RANGE_LOOP ,
@@ -469,6 +495,7 @@ declare_lint_pass!(Loops => [
469
495
MUT_RANGE_BOUND ,
470
496
WHILE_IMMUTABLE_CONDITION ,
471
497
SAME_ITEM_PUSH ,
498
+ SINGLE_ELEMENT_LOOP ,
472
499
] ) ;
473
500
474
501
impl < ' tcx > LateLintPass < ' tcx > for Loops {
@@ -777,6 +804,7 @@ fn check_for_loop<'tcx>(
777
804
check_for_loop_arg ( cx, pat, arg, expr) ;
778
805
check_for_loop_over_map_kv ( cx, pat, arg, body, expr) ;
779
806
check_for_mut_range_bound ( cx, arg, body) ;
807
+ check_for_single_element_loop ( cx, pat, arg, body, expr) ;
780
808
detect_same_item_push ( cx, pat, arg, body, expr) ;
781
809
}
782
810
@@ -1866,6 +1894,43 @@ fn check_for_loop_over_map_kv<'tcx>(
1866
1894
}
1867
1895
}
1868
1896
1897
+ fn check_for_single_element_loop < ' tcx > (
1898
+ cx : & LateContext < ' tcx > ,
1899
+ pat : & ' tcx Pat < ' _ > ,
1900
+ arg : & ' tcx Expr < ' _ > ,
1901
+ body : & ' tcx Expr < ' _ > ,
1902
+ expr : & ' tcx Expr < ' _ > ,
1903
+ ) {
1904
+ if_chain ! {
1905
+ if let ExprKind :: AddrOf ( BorrowKind :: Ref , _, ref arg_expr) = arg. kind;
1906
+ if let PatKind :: Binding ( .., target, _) = pat. kind;
1907
+ if let ExprKind :: Array ( ref arg_expr_list) = arg_expr. kind;
1908
+ if let [ arg_expression] = arg_expr_list;
1909
+ if let ExprKind :: Path ( ref list_item) = arg_expression. kind;
1910
+ if let Some ( list_item_name) = single_segment_path( list_item) . map( |ps| ps. ident. name) ;
1911
+ if let ExprKind :: Block ( ref block, _) = body. kind;
1912
+ if !block. stmts. is_empty( ) ;
1913
+
1914
+ then {
1915
+ let for_span = get_span_of_entire_for_loop( expr) ;
1916
+ let mut block_str = snippet( cx, block. span, ".." ) . into_owned( ) ;
1917
+ block_str. remove( 0 ) ;
1918
+ block_str. pop( ) ;
1919
+
1920
+
1921
+ span_lint_and_sugg(
1922
+ cx,
1923
+ SINGLE_ELEMENT_LOOP ,
1924
+ for_span,
1925
+ "for loop over a single element" ,
1926
+ "try" ,
1927
+ format!( "{{\n {}let {} = &{};{}}}" , " " . repeat( indent_of( cx, block. stmts[ 0 ] . span) . unwrap_or( 0 ) ) , target. name, list_item_name, block_str) ,
1928
+ Applicability :: MachineApplicable
1929
+ )
1930
+ }
1931
+ }
1932
+ }
1933
+
1869
1934
struct MutatePairDelegate < ' a , ' tcx > {
1870
1935
cx : & ' a LateContext < ' tcx > ,
1871
1936
hir_id_low : Option < HirId > ,
0 commit comments