1 use super::utils::derefs_to_slice;
2 use clippy_utils::diagnostics::span_lint_and_sugg;
3 use clippy_utils::source::snippet_with_applicability;
4 use clippy_utils::ty::is_type_diagnostic_item;
5 use clippy_utils::{get_parent_expr, higher};
6 use if_chain::if_chain;
8 use rustc_errors::Applicability;
10 use rustc_lint::LateContext;
12 use rustc_span::symbol::sym;
14 use super::ITER_NEXT_SLICE;
16 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, caller_expr: &'tcx hir::Expr<'_>) {
17 // Skip lint if the `iter().next()` expression is a for loop argument,
18 // since it is already covered by `&loops::ITER_NEXT_LOOP`
19 let mut parent_expr_opt = get_parent_expr(cx, expr);
20 while let Some(parent_expr) = parent_expr_opt {
21 if higher::for_loop(parent_expr).is_some() {
24 parent_expr_opt = get_parent_expr(cx, parent_expr);
27 if derefs_to_slice(cx, caller_expr, cx.typeck_results().expr_ty(caller_expr)).is_some() {
30 if let hir::ExprKind::Index(caller_var, index_expr) = &caller_expr.kind;
31 if let Some(higher::Range { start: Some(start_expr), end: None, limits: ast::RangeLimits::HalfOpen })
32 = higher::range(index_expr);
33 if let hir::ExprKind::Lit(ref start_lit) = &start_expr.kind;
34 if let ast::LitKind::Int(start_idx, _) = start_lit.node;
36 let mut applicability = Applicability::MachineApplicable;
41 "using `.iter().next()` on a Slice without end index",
43 format!("{}.get({})", snippet_with_applicability(cx, caller_var.span, "..", &mut applicability), start_idx),
48 } else if is_vec_or_array(cx, caller_expr) {
49 // caller is a Vec or an Array
50 let mut applicability = Applicability::MachineApplicable;
55 "using `.iter().next()` on an array",
59 snippet_with_applicability(cx, caller_expr.span, "..", &mut applicability)
66 fn is_vec_or_array<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) -> bool {
67 is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::vec_type)
68 || matches!(&cx.typeck_results().expr_ty(expr).peel_refs().kind(), ty::Array(_, _))