1 use clippy_utils::diagnostics::span_lint_and_sugg;
2 use clippy_utils::source::snippet;
3 use clippy_utils::{get_expr_use_or_unification_node, is_no_std_crate, is_res_lang_ctor, path_res};
5 use rustc_errors::Applicability;
6 use rustc_hir::LangItem::{OptionNone, OptionSome};
7 use rustc_hir::{Expr, ExprKind, Node};
8 use rustc_lint::LateContext;
10 use super::{ITER_ON_EMPTY_COLLECTIONS, ITER_ON_SINGLE_ITEMS};
19 fn ref_prefix(&self) -> &'static str {
22 Self::IterMut => "&mut ",
28 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, method_name: &str, recv: &Expr<'_>) {
29 let item = match recv.kind {
30 ExprKind::Array([]) => None,
31 ExprKind::Array([e]) => Some(e),
32 ExprKind::Path(ref p) if is_res_lang_ctor(cx, cx.qpath_res(p, recv.hir_id), OptionNone) => None,
33 ExprKind::Call(f, [arg]) if is_res_lang_ctor(cx, path_res(cx, f), OptionSome) => Some(arg),
36 let iter_type = match method_name {
37 "iter" => IterType::Iter,
38 "iter_mut" => IterType::IterMut,
39 "into_iter" => IterType::IntoIter,
43 let is_unified = match get_expr_use_or_unification_node(cx.tcx, expr) {
44 Some((Node::Expr(parent), child_id)) => match parent.kind {
45 ExprKind::If(e, _, _) | ExprKind::Match(e, _, _) if e.hir_id == child_id => false,
47 | ExprKind::Match(_, _, _)
48 | ExprKind::Closure(_)
50 | ExprKind::Break(_, _) => true,
53 Some((Node::Stmt(_) | Node::Local(_), _)) => false,
61 if let Some(i) = item {
63 "{}::iter::once({}{})",
64 if is_no_std_crate(cx) { "core" } else { "std" },
65 iter_type.ref_prefix(),
66 snippet(cx, i.span, "...")
72 &format!("`{method_name}` call on a collection with only one item"),
75 Applicability::MaybeIncorrect,
80 ITER_ON_EMPTY_COLLECTIONS,
82 &format!("`{method_name}` call on an empty collection"),
84 if is_no_std_crate(cx) {
85 "core::iter::empty()".to_string()
87 "std::iter::empty()".to_string()
89 Applicability::MaybeIncorrect,