@@ -20,6 +20,7 @@ use rustc_span::source_map::Span;
20
20
use rustc_span:: symbol:: { sym, Symbol , SymbolStr } ;
21
21
use syntax:: ast;
22
22
23
+ use crate :: consts:: { constant, Constant } ;
23
24
use crate :: utils:: usage:: mutated_variables;
24
25
use crate :: utils:: {
25
26
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! {
756
757
"using `Iterator::step_by(0)`, which will panic at runtime"
757
758
}
758
759
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
+
759
787
declare_clippy_lint ! {
760
788
/// **What it does:** Checks for use of `.iter().nth()` (and the related
761
789
/// `.iter_mut().nth()`) on standard library types with O(1) element access.
@@ -1136,6 +1164,7 @@ declare_lint_pass!(Methods => [
1136
1164
MAP_FLATTEN ,
1137
1165
ITERATOR_STEP_BY_ZERO ,
1138
1166
ITER_NTH ,
1167
+ ITER_NTH_ZERO ,
1139
1168
ITER_SKIP_NEXT ,
1140
1169
GET_UNWRAP ,
1141
1170
STRING_EXTEND_CHARS ,
@@ -1191,8 +1220,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods {
1191
1220
[ "as_ptr" , "unwrap" ] | [ "as_ptr" , "expect" ] => {
1192
1221
lint_cstring_as_ptr ( cx, expr, & arg_lists[ 1 ] [ 0 ] , & arg_lists[ 0 ] [ 0 ] )
1193
1222
} ,
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 ] ) ,
1196
1226
[ "step_by" , ..] => lint_step_by ( cx, expr, arg_lists[ 0 ] ) ,
1197
1227
[ "next" , "skip" ] => lint_iter_skip_next ( cx, expr) ,
1198
1228
[ "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
1983
2013
1984
2014
fn lint_step_by < ' a , ' tcx > ( cx : & LateContext < ' a , ' tcx > , expr : & hir:: Expr < ' _ > , args : & ' tcx [ hir:: Expr < ' _ > ] ) {
1985
2015
if match_trait_method ( cx, expr, & paths:: ITERATOR ) {
1986
- use crate :: consts:: { constant, Constant } ;
1987
2016
if let Some ( ( Constant :: Int ( 0 ) , _) ) = constant ( cx, cx. tables , & args[ 1 ] ) {
1988
2017
span_lint (
1989
2018
cx,
@@ -1998,9 +2027,10 @@ fn lint_step_by<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &hir::Expr<'_>, args
1998
2027
fn lint_iter_nth < ' a , ' tcx > (
1999
2028
cx : & LateContext < ' a , ' tcx > ,
2000
2029
expr : & hir:: Expr < ' _ > ,
2001
- iter_args : & ' tcx [ hir:: Expr < ' _ > ] ,
2030
+ nth_and_iter_args : & [ & ' tcx [ hir:: Expr < ' tcx > ] ] ,
2002
2031
is_mut : bool ,
2003
2032
) {
2033
+ let iter_args = nth_and_iter_args[ 1 ] ;
2004
2034
let mut_str = if is_mut { "_mut" } else { "" } ;
2005
2035
let caller_type = if derefs_to_slice ( cx, & iter_args[ 0 ] , cx. tables . expr_ty ( & iter_args[ 0 ] ) ) . is_some ( ) {
2006
2036
"slice"
@@ -2009,6 +2039,8 @@ fn lint_iter_nth<'a, 'tcx>(
2009
2039
} else if match_type ( cx, cx. tables . expr_ty ( & iter_args[ 0 ] ) , & paths:: VEC_DEQUE ) {
2010
2040
"VecDeque"
2011
2041
} else {
2042
+ let nth_args = nth_and_iter_args[ 0 ] ;
2043
+ lint_iter_nth_zero ( cx, expr, & nth_args) ;
2012
2044
return ; // caller is not a type that we want to lint
2013
2045
} ;
2014
2046
@@ -2023,6 +2055,25 @@ fn lint_iter_nth<'a, 'tcx>(
2023
2055
) ;
2024
2056
}
2025
2057
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
+
2026
2077
fn lint_get_unwrap < ' a , ' tcx > (
2027
2078
cx : & LateContext < ' a , ' tcx > ,
2028
2079
expr : & hir:: Expr < ' _ > ,
0 commit comments