@@ -20,6 +20,7 @@ use rustc_span::source_map::Span;
2020use rustc_span:: symbol:: { sym, Symbol , SymbolStr } ;
2121use syntax:: ast;
2222
23+ use crate :: consts:: { constant, Constant } ;
2324use crate :: utils:: usage:: mutated_variables;
2425use crate :: utils:: {
2526 get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, implements_trait, in_macro, is_copy,
@@ -756,6 +757,33 @@ declare_clippy_lint! {
756757 "using `Iterator::step_by(0)`, which will panic at runtime"
757758}
758759
760+ declare_clippy_lint ! {
761+ /// **What it does:** Checks for the use of `iter.nth(0)`.
762+ ///
763+ /// **Why is this bad?** `iter.nth(0)` is unnecessary, and `iter.next()`
764+ /// is more readable.
765+ ///
766+ /// **Known problems:** None.
767+ ///
768+ /// **Example:**
769+ ///
770+ /// ```rust
771+ /// # use std::collections::HashSet;
772+ /// // Bad
773+ /// # let mut s = HashSet::new();
774+ /// # s.insert(1);
775+ /// let x = s.iter().nth(0);
776+ ///
777+ /// // Good
778+ /// # let mut s = HashSet::new();
779+ /// # s.insert(1);
780+ /// let x = s.iter().next();
781+ /// ```
782+ pub ITER_NTH_ZERO ,
783+ style,
784+ "replace `iter.nth(0)` with `iter.next()`"
785+ }
786+
759787declare_clippy_lint ! {
760788 /// **What it does:** Checks for use of `.iter().nth()` (and the related
761789 /// `.iter_mut().nth()`) on standard library types with O(1) element access.
@@ -1136,6 +1164,7 @@ declare_lint_pass!(Methods => [
11361164 MAP_FLATTEN ,
11371165 ITERATOR_STEP_BY_ZERO ,
11381166 ITER_NTH ,
1167+ ITER_NTH_ZERO ,
11391168 ITER_SKIP_NEXT ,
11401169 GET_UNWRAP ,
11411170 STRING_EXTEND_CHARS ,
@@ -1191,8 +1220,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods {
11911220 [ "as_ptr" , "unwrap" ] | [ "as_ptr" , "expect" ] => {
11921221 lint_cstring_as_ptr ( cx, expr, & arg_lists[ 1 ] [ 0 ] , & arg_lists[ 0 ] [ 0 ] )
11931222 } ,
1194- [ "nth" , "iter" ] => lint_iter_nth ( cx, expr, arg_lists[ 1 ] , false ) ,
1195- [ "nth" , "iter_mut" ] => lint_iter_nth ( cx, expr, arg_lists[ 1 ] , true ) ,
1223+ [ "nth" , "iter" ] => lint_iter_nth ( cx, expr, & arg_lists, false ) ,
1224+ [ "nth" , "iter_mut" ] => lint_iter_nth ( cx, expr, & arg_lists, true ) ,
1225+ [ "nth" , ..] => lint_iter_nth_zero ( cx, expr, arg_lists[ 0 ] ) ,
11961226 [ "step_by" , ..] => lint_step_by ( cx, expr, arg_lists[ 0 ] ) ,
11971227 [ "next" , "skip" ] => lint_iter_skip_next ( cx, expr) ,
11981228 [ "collect" , "cloned" ] => lint_iter_cloned_collect ( cx, expr, arg_lists[ 1 ] ) ,
@@ -1983,7 +2013,6 @@ fn lint_unnecessary_fold(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, fold_ar
19832013
19842014fn lint_step_by < ' a , ' tcx > ( cx : & LateContext < ' a , ' tcx > , expr : & hir:: Expr < ' _ > , args : & ' tcx [ hir:: Expr < ' _ > ] ) {
19852015 if match_trait_method ( cx, expr, & paths:: ITERATOR ) {
1986- use crate :: consts:: { constant, Constant } ;
19872016 if let Some ( ( Constant :: Int ( 0 ) , _) ) = constant ( cx, cx. tables , & args[ 1 ] ) {
19882017 span_lint (
19892018 cx,
@@ -1998,9 +2027,10 @@ fn lint_step_by<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &hir::Expr<'_>, args
19982027fn lint_iter_nth < ' a , ' tcx > (
19992028 cx : & LateContext < ' a , ' tcx > ,
20002029 expr : & hir:: Expr < ' _ > ,
2001- iter_args : & ' tcx [ hir:: Expr < ' _ > ] ,
2030+ nth_and_iter_args : & [ & ' tcx [ hir:: Expr < ' tcx > ] ] ,
20022031 is_mut : bool ,
20032032) {
2033+ let iter_args = nth_and_iter_args[ 1 ] ;
20042034 let mut_str = if is_mut { "_mut" } else { "" } ;
20052035 let caller_type = if derefs_to_slice ( cx, & iter_args[ 0 ] , cx. tables . expr_ty ( & iter_args[ 0 ] ) ) . is_some ( ) {
20062036 "slice"
@@ -2009,6 +2039,8 @@ fn lint_iter_nth<'a, 'tcx>(
20092039 } else if match_type ( cx, cx. tables . expr_ty ( & iter_args[ 0 ] ) , & paths:: VEC_DEQUE ) {
20102040 "VecDeque"
20112041 } else {
2042+ let nth_args = nth_and_iter_args[ 0 ] ;
2043+ lint_iter_nth_zero ( cx, expr, & nth_args) ;
20122044 return ; // caller is not a type that we want to lint
20132045 } ;
20142046
@@ -2023,6 +2055,25 @@ fn lint_iter_nth<'a, 'tcx>(
20232055 ) ;
20242056}
20252057
2058+ fn lint_iter_nth_zero < ' a , ' tcx > ( cx : & LateContext < ' a , ' tcx > , expr : & hir:: Expr < ' _ > , nth_args : & ' tcx [ hir:: Expr < ' _ > ] ) {
2059+ if_chain ! {
2060+ if match_trait_method( cx, expr, & paths:: ITERATOR ) ;
2061+ if let Some ( ( Constant :: Int ( 0 ) , _) ) = constant( cx, cx. tables, & nth_args[ 1 ] ) ;
2062+ then {
2063+ let mut applicability = Applicability :: MachineApplicable ;
2064+ span_lint_and_sugg(
2065+ cx,
2066+ ITER_NTH_ZERO ,
2067+ expr. span,
2068+ "called `.nth(0)` on a `std::iter::Iterator`" ,
2069+ "try calling" ,
2070+ format!( "{}.next()" , snippet_with_applicability( cx, nth_args[ 0 ] . span, ".." , & mut applicability) ) ,
2071+ applicability,
2072+ ) ;
2073+ }
2074+ }
2075+ }
2076+
20262077fn lint_get_unwrap < ' a , ' tcx > (
20272078 cx : & LateContext < ' a , ' tcx > ,
20282079 expr : & hir:: Expr < ' _ > ,
0 commit comments