]> git.lizzy.rs Git - rust.git/blob - src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs
Auto merge of #82680 - jturner314:div_euclid-docs, r=JohnTitor
[rust.git] / src / tools / clippy / clippy_lints / src / methods / iter_next_slice.rs
1 use crate::methods::derefs_to_slice;
2 use crate::utils::{get_parent_expr, higher, is_type_diagnostic_item, snippet_with_applicability, span_lint_and_sugg};
3 use if_chain::if_chain;
4 use rustc_ast::ast;
5 use rustc_errors::Applicability;
6 use rustc_hir as hir;
7 use rustc_lint::LateContext;
8 use rustc_middle::ty;
9 use rustc_span::symbol::sym;
10
11 use super::ITER_NEXT_SLICE;
12
13 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, iter_args: &'tcx [hir::Expr<'_>]) {
14     let caller_expr = &iter_args[0];
15
16     // Skip lint if the `iter().next()` expression is a for loop argument,
17     // since it is already covered by `&loops::ITER_NEXT_LOOP`
18     let mut parent_expr_opt = get_parent_expr(cx, expr);
19     while let Some(parent_expr) = parent_expr_opt {
20         if higher::for_loop(parent_expr).is_some() {
21             return;
22         }
23         parent_expr_opt = get_parent_expr(cx, parent_expr);
24     }
25
26     if derefs_to_slice(cx, caller_expr, cx.typeck_results().expr_ty(caller_expr)).is_some() {
27         // caller is a Slice
28         if_chain! {
29             if let hir::ExprKind::Index(ref caller_var, ref index_expr) = &caller_expr.kind;
30             if let Some(higher::Range { start: Some(start_expr), end: None, limits: ast::RangeLimits::HalfOpen })
31                 = higher::range(index_expr);
32             if let hir::ExprKind::Lit(ref start_lit) = &start_expr.kind;
33             if let ast::LitKind::Int(start_idx, _) = start_lit.node;
34             then {
35                 let mut applicability = Applicability::MachineApplicable;
36                 span_lint_and_sugg(
37                     cx,
38                     ITER_NEXT_SLICE,
39                     expr.span,
40                     "using `.iter().next()` on a Slice without end index",
41                     "try calling",
42                     format!("{}.get({})", snippet_with_applicability(cx, caller_var.span, "..", &mut applicability), start_idx),
43                     applicability,
44                 );
45             }
46         }
47     } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(caller_expr), sym::vec_type)
48         || matches!(
49             &cx.typeck_results().expr_ty(caller_expr).peel_refs().kind(),
50             ty::Array(_, _)
51         )
52     {
53         // caller is a Vec or an Array
54         let mut applicability = Applicability::MachineApplicable;
55         span_lint_and_sugg(
56             cx,
57             ITER_NEXT_SLICE,
58             expr.span,
59             "using `.iter().next()` on an array",
60             "try calling",
61             format!(
62                 "{}.get(0)",
63                 snippet_with_applicability(cx, caller_expr.span, "..", &mut applicability)
64             ),
65             applicability,
66         );
67     }
68 }