1 use clippy_utils::diagnostics::span_lint_and_sugg;
2 use clippy_utils::source::snippet;
3 use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy};
4 use itertools::Itertools;
5 use rustc_errors::Applicability;
7 use rustc_lint::LateContext;
12 use super::ITER_OVEREAGER_CLONED;
13 use crate::redundant_clone::REDUNDANT_CLONE;
15 /// lint overeager use of `cloned()` for `Iterator`s
16 pub(super) fn check<'tcx>(
17 cx: &LateContext<'tcx>,
18 expr: &'tcx hir::Expr<'_>,
19 recv: &'tcx hir::Expr<'_>,
21 map_arg: &[hir::Expr<'_>],
23 // Check if it's iterator and get type associated with `Item`.
24 let inner_ty = if_chain! {
25 if let Some(iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator);
26 let recv_ty = cx.typeck_results().expr_ty(recv);
27 if implements_trait(cx, recv_ty, iterator_trait_id, &[]);
28 if let Some(inner_ty) = get_iterator_item_ty(cx, cx.typeck_results().expr_ty_adjusted(recv));
36 match inner_ty.kind() {
37 ty::Ref(_, ty, _) if !is_copy(cx, *ty) => {},
41 let (lint, preserve_cloned) = match name {
42 "count" => (REDUNDANT_CLONE, false),
43 _ => (ITER_OVEREAGER_CLONED, true),
45 let wildcard_params = map_arg.is_empty().not().then(|| "...").unwrap_or_default();
47 "called `cloned().{}({})` on an `Iterator`. It may be more efficient to call `{}({}){}` instead",
52 preserve_cloned.then(|| ".cloned()").unwrap_or_default(),
63 snippet(cx, recv.span, ".."),
65 map_arg.iter().map(|a| snippet(cx, a.span, "..")).join(", "),
66 preserve_cloned.then(|| ".cloned()").unwrap_or_default(),
68 Applicability::MachineApplicable,