@@ -26,7 +26,7 @@ use rustc_span::symbol::{sym, SymbolStr};
2626use crate :: consts:: { constant, Constant } ;
2727use crate :: utils:: usage:: mutated_variables;
2828use crate :: utils:: {
29- get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, implements_trait, in_macro, is_copy,
29+ get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, higher , implements_trait, in_macro, is_copy,
3030 is_ctor_or_promotable_const_function, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment,
3131 match_def_path, match_qpath, match_trait_method, match_type, match_var, method_calls, method_chain_args, paths,
3232 remove_blocks, return_ty, same_tys, single_segment_path, snippet, snippet_with_applicability,
@@ -1242,6 +1242,32 @@ declare_clippy_lint! {
12421242 "using `as_ref().map(Deref::deref)`, which is more succinctly expressed as `as_deref()`"
12431243}
12441244
1245+ declare_clippy_lint ! {
1246+ /// **What it does:** Checks for usage of `iter().next()` on a Slice or an Array
1247+ ///
1248+ /// **Why is this bad?** These can be shortened into `.get()`
1249+ ///
1250+ /// **Known problems:** None.
1251+ ///
1252+ /// **Example:**
1253+ /// ```rust
1254+ /// # let a = [1, 2, 3];
1255+ /// # let b = vec![1, 2, 3];
1256+ /// a[2..].iter().next();
1257+ /// b.iter().next();
1258+ /// ```
1259+ /// should be written as:
1260+ /// ```rust
1261+ /// # let a = [1, 2, 3];
1262+ /// # let b = vec![1, 2, 3];
1263+ /// a.get(2);
1264+ /// b.get(0);
1265+ /// ```
1266+ pub ITER_NEXT_SLICE ,
1267+ style,
1268+ "using `.iter().next()` on a sliced array, which can be shortened to just `.get()`"
1269+ }
1270+
12451271declare_lint_pass ! ( Methods => [
12461272 UNWRAP_USED ,
12471273 EXPECT_USED ,
@@ -1273,6 +1299,7 @@ declare_lint_pass!(Methods => [
12731299 FIND_MAP ,
12741300 MAP_FLATTEN ,
12751301 ITERATOR_STEP_BY_ZERO ,
1302+ ITER_NEXT_SLICE ,
12761303 ITER_NTH ,
12771304 ITER_NTH_ZERO ,
12781305 ITER_SKIP_NEXT ,
@@ -1320,6 +1347,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods {
13201347 } ,
13211348 [ "next" , "filter" ] => lint_filter_next ( cx, expr, arg_lists[ 1 ] ) ,
13221349 [ "next" , "skip_while" ] => lint_skip_while_next ( cx, expr, arg_lists[ 1 ] ) ,
1350+ [ "next" , "iter" ] => lint_iter_next ( cx, expr, arg_lists[ 1 ] ) ,
13231351 [ "map" , "filter" ] => lint_filter_map ( cx, expr, arg_lists[ 1 ] , arg_lists[ 0 ] ) ,
13241352 [ "map" , "filter_map" ] => lint_filter_map_map ( cx, expr, arg_lists[ 1 ] , arg_lists[ 0 ] ) ,
13251353 [ "next" , "filter_map" ] => lint_filter_map_next ( cx, expr, arg_lists[ 1 ] ) ,
@@ -2199,6 +2227,60 @@ fn lint_step_by<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &hir::Expr<'_>, args
21992227 }
22002228}
22012229
2230+ fn lint_iter_next < ' a , ' tcx > ( cx : & LateContext < ' a , ' tcx > , expr : & ' tcx hir:: Expr < ' _ > , iter_args : & ' tcx [ hir:: Expr < ' _ > ] ) {
2231+ let caller_expr = & iter_args[ 0 ] ;
2232+
2233+ // Skip lint if the `iter().next()` expression is a for loop argument,
2234+ // since it is already covered by `&loops::ITER_NEXT_LOOP`
2235+ let mut parent_expr_opt = get_parent_expr ( cx, expr) ;
2236+ while let Some ( parent_expr) = parent_expr_opt {
2237+ if higher:: for_loop ( parent_expr) . is_some ( ) {
2238+ return ;
2239+ }
2240+ parent_expr_opt = get_parent_expr ( cx, parent_expr) ;
2241+ }
2242+
2243+ if derefs_to_slice ( cx, caller_expr, cx. tables . expr_ty ( caller_expr) ) . is_some ( ) {
2244+ // caller is a Slice
2245+ if_chain ! {
2246+ if let hir:: ExprKind :: Index ( ref caller_var, ref index_expr) = & caller_expr. kind;
2247+ if let Some ( higher:: Range { start: Some ( start_expr) , end: None , limits: ast:: RangeLimits :: HalfOpen } )
2248+ = higher:: range( cx, index_expr) ;
2249+ if let hir:: ExprKind :: Lit ( ref start_lit) = & start_expr. kind;
2250+ if let ast:: LitKind :: Int ( start_idx, _) = start_lit. node;
2251+ then {
2252+ let mut applicability = Applicability :: MachineApplicable ;
2253+ span_lint_and_sugg(
2254+ cx,
2255+ ITER_NEXT_SLICE ,
2256+ expr. span,
2257+ "Using `.iter().next()` on a Slice without end index." ,
2258+ "try calling" ,
2259+ format!( "{}.get({})" , snippet_with_applicability( cx, caller_var. span, ".." , & mut applicability) , start_idx) ,
2260+ applicability,
2261+ ) ;
2262+ }
2263+ }
2264+ } else if is_type_diagnostic_item ( cx, cx. tables . expr_ty ( caller_expr) , sym ! ( vec_type) )
2265+ || matches ! ( & walk_ptrs_ty( cx. tables. expr_ty( caller_expr) ) . kind, ty:: Array ( _, _) )
2266+ {
2267+ // caller is a Vec or an Array
2268+ let mut applicability = Applicability :: MachineApplicable ;
2269+ span_lint_and_sugg (
2270+ cx,
2271+ ITER_NEXT_SLICE ,
2272+ expr. span ,
2273+ "Using `.iter().next()` on an array" ,
2274+ "try calling" ,
2275+ format ! (
2276+ "{}.get(0)" ,
2277+ snippet_with_applicability( cx, caller_expr. span, ".." , & mut applicability)
2278+ ) ,
2279+ applicability,
2280+ ) ;
2281+ }
2282+ }
2283+
22022284fn lint_iter_nth < ' a , ' tcx > (
22032285 cx : & LateContext < ' a , ' tcx > ,
22042286 expr : & hir:: Expr < ' _ > ,
0 commit comments