1 use clippy_utils::diagnostics::span_lint_and_then;
2 use clippy_utils::source::snippet_opt;
3 use clippy_utils::ty::{implements_trait, is_copy};
4 use rustc_errors::Applicability;
6 use rustc_lint::LateContext;
10 use super::ITER_OVEREAGER_CLONED;
11 use crate::redundant_clone::REDUNDANT_CLONE;
13 pub(super) fn check<'tcx>(
14 cx: &LateContext<'tcx>,
16 cloned_call: &'tcx Expr<'_>,
17 cloned_recv: &'tcx Expr<'_>,
19 needs_into_iter: bool,
21 let typeck = cx.typeck_results();
22 if let Some(iter_id) = cx.tcx.get_diagnostic_item(sym::Iterator)
23 && let Some(method_id) = typeck.type_dependent_def_id(expr.hir_id)
24 && cx.tcx.trait_of_item(method_id) == Some(iter_id)
25 && let Some(method_id) = typeck.type_dependent_def_id(cloned_call.hir_id)
26 && cx.tcx.trait_of_item(method_id) == Some(iter_id)
27 && let cloned_recv_ty = typeck.expr_ty_adjusted(cloned_recv)
28 && let Some(iter_assoc_ty) = cx.get_associated_type(cloned_recv_ty, iter_id, "Item")
29 && matches!(*iter_assoc_ty.kind(), ty::Ref(_, ty, _) if !is_copy(cx, ty))
32 && let Some(into_iter_id) = cx.tcx.get_diagnostic_item(sym::IntoIterator)
33 && !implements_trait(cx, iter_assoc_ty, into_iter_id, &[])
38 let (lint, msg, trailing_clone) = if is_count {
39 (REDUNDANT_CLONE, "unneeded cloning of iterator items", "")
41 (ITER_OVEREAGER_CLONED, "unnecessarily eager cloning of iterator items", ".cloned()")
50 let method_span = expr.span.with_lo(cloned_call.span.hi());
51 if let Some(mut snip) = snippet_opt(cx, method_span) {
52 snip.push_str(trailing_clone);
53 let replace_span = expr.span.with_lo(cloned_recv.span.hi());
54 diag.span_suggestion(replace_span, "try this", snip, Applicability::MachineApplicable);