@@ -20,6 +20,7 @@ use syntax::ast;
20
20
use syntax:: source_map:: Span ;
21
21
use syntax:: symbol:: { sym, Symbol , SymbolStr } ;
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,32 @@ 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,ignore
771
+ /// // Bad
772
+ /// let mut s = HashSet::new();
773
+ /// s.insert(1);
774
+ /// let x = s.iter().nth(0);
775
+ ///
776
+ /// // Good
777
+ /// let mut s = HashSet::new();
778
+ /// s.insert(1);
779
+ /// let x = s.iter().next();
780
+ /// ```
781
+ pub ITER_NTH_ZERO ,
782
+ style,
783
+ "replace `iter.nth(0)` with `iter.next()`"
784
+ }
785
+
759
786
declare_clippy_lint ! {
760
787
/// **What it does:** Checks for use of `.iter().nth()` (and the related
761
788
/// `.iter_mut().nth()`) on standard library types with O(1) element access.
@@ -1136,6 +1163,7 @@ declare_lint_pass!(Methods => [
1136
1163
MAP_FLATTEN ,
1137
1164
ITERATOR_STEP_BY_ZERO ,
1138
1165
ITER_NTH ,
1166
+ ITER_NTH_ZERO ,
1139
1167
ITER_SKIP_NEXT ,
1140
1168
GET_UNWRAP ,
1141
1169
STRING_EXTEND_CHARS ,
@@ -1191,8 +1219,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods {
1191
1219
[ "as_ptr" , "unwrap" ] | [ "as_ptr" , "expect" ] => {
1192
1220
lint_cstring_as_ptr ( cx, expr, & arg_lists[ 1 ] [ 0 ] , & arg_lists[ 0 ] [ 0 ] )
1193
1221
} ,
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 ) ,
1222
+ [ "nth" , "iter" ] => lint_iter_nth ( cx, expr, & arg_lists, false ) ,
1223
+ [ "nth" , "iter_mut" ] => lint_iter_nth ( cx, expr, & arg_lists, true ) ,
1224
+ [ "nth" , ..] => lint_iter_nth_zero ( cx, expr, arg_lists[ 0 ] ) ,
1196
1225
[ "step_by" , ..] => lint_step_by ( cx, expr, arg_lists[ 0 ] ) ,
1197
1226
[ "next" , "skip" ] => lint_iter_skip_next ( cx, expr) ,
1198
1227
[ "collect" , "cloned" ] => lint_iter_cloned_collect ( cx, expr, arg_lists[ 1 ] ) ,
@@ -1983,7 +2012,6 @@ fn lint_unnecessary_fold(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, fold_ar
1983
2012
1984
2013
fn lint_step_by < ' a , ' tcx > ( cx : & LateContext < ' a , ' tcx > , expr : & hir:: Expr < ' _ > , args : & ' tcx [ hir:: Expr < ' _ > ] ) {
1985
2014
if match_trait_method ( cx, expr, & paths:: ITERATOR ) {
1986
- use crate :: consts:: { constant, Constant } ;
1987
2015
if let Some ( ( Constant :: Int ( 0 ) , _) ) = constant ( cx, cx. tables , & args[ 1 ] ) {
1988
2016
span_lint (
1989
2017
cx,
@@ -1998,9 +2026,10 @@ fn lint_step_by<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &hir::Expr<'_>, args
1998
2026
fn lint_iter_nth < ' a , ' tcx > (
1999
2027
cx : & LateContext < ' a , ' tcx > ,
2000
2028
expr : & hir:: Expr < ' _ > ,
2001
- iter_args : & ' tcx [ hir:: Expr < ' _ > ] ,
2029
+ nth_and_iter_args : & [ & ' tcx [ hir:: Expr < ' tcx > ] ] ,
2002
2030
is_mut : bool ,
2003
2031
) {
2032
+ let iter_args = nth_and_iter_args[ 1 ] ;
2004
2033
let mut_str = if is_mut { "_mut" } else { "" } ;
2005
2034
let caller_type = if derefs_to_slice ( cx, & iter_args[ 0 ] , cx. tables . expr_ty ( & iter_args[ 0 ] ) ) . is_some ( ) {
2006
2035
"slice"
@@ -2009,6 +2038,8 @@ fn lint_iter_nth<'a, 'tcx>(
2009
2038
} else if match_type ( cx, cx. tables . expr_ty ( & iter_args[ 0 ] ) , & paths:: VEC_DEQUE ) {
2010
2039
"VecDeque"
2011
2040
} else {
2041
+ let nth_args = nth_and_iter_args[ 0 ] ;
2042
+ lint_iter_nth_zero ( cx, expr, & nth_args) ;
2012
2043
return ; // caller is not a type that we want to lint
2013
2044
} ;
2014
2045
@@ -2023,6 +2054,25 @@ fn lint_iter_nth<'a, 'tcx>(
2023
2054
) ;
2024
2055
}
2025
2056
2057
+ fn lint_iter_nth_zero < ' a , ' tcx > ( cx : & LateContext < ' a , ' tcx > , expr : & hir:: Expr < ' _ > , nth_args : & ' tcx [ hir:: Expr < ' _ > ] ) {
2058
+ if_chain ! {
2059
+ if match_trait_method( cx, expr, & paths:: ITERATOR ) ;
2060
+ if let Some ( ( Constant :: Int ( 0 ) , _) ) = constant( cx, cx. tables, & nth_args[ 1 ] ) ;
2061
+ then {
2062
+ let mut applicability = Applicability :: MachineApplicable ;
2063
+ span_lint_and_sugg(
2064
+ cx,
2065
+ ITER_NTH_ZERO ,
2066
+ expr. span,
2067
+ "called `.nth(0)` on a `std::iter::Iterator`" ,
2068
+ "try calling" ,
2069
+ format!( "{}.next()" , snippet_with_applicability( cx, nth_args[ 0 ] . span, ".." , & mut applicability) ) ,
2070
+ applicability,
2071
+ ) ;
2072
+ }
2073
+ }
2074
+ }
2075
+
2026
2076
fn lint_get_unwrap < ' a , ' tcx > (
2027
2077
cx : & LateContext < ' a , ' tcx > ,
2028
2078
expr : & hir:: Expr < ' _ > ,
0 commit comments