]> git.lizzy.rs Git - rust.git/blob - src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
Auto merge of #105018 - zertosh:path_buf_deref_mut, r=dtolnay
[rust.git] / src / tools / clippy / clippy_lints / src / methods / iter_overeager_cloned.rs
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;
5 use rustc_hir::Expr;
6 use rustc_lint::LateContext;
7 use rustc_middle::ty;
8 use rustc_span::sym;
9
10 use super::ITER_OVEREAGER_CLONED;
11 use crate::redundant_clone::REDUNDANT_CLONE;
12
13 pub(super) fn check<'tcx>(
14     cx: &LateContext<'tcx>,
15     expr: &'tcx Expr<'_>,
16     cloned_call: &'tcx Expr<'_>,
17     cloned_recv: &'tcx Expr<'_>,
18     is_count: bool,
19     needs_into_iter: bool,
20 ) {
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))
30     {
31         if needs_into_iter
32             && let Some(into_iter_id) = cx.tcx.get_diagnostic_item(sym::IntoIterator)
33             && !implements_trait(cx, iter_assoc_ty, into_iter_id, &[])
34         {
35             return;
36         }
37
38         let (lint, msg, trailing_clone) = if is_count {
39             (REDUNDANT_CLONE, "unneeded cloning of iterator items", "")
40         } else {
41             (ITER_OVEREAGER_CLONED, "unnecessarily eager cloning of iterator items", ".cloned()")
42         };
43
44         span_lint_and_then(
45             cx,
46             lint,
47             expr.span,
48             msg,
49             |diag| {
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);
55                 }
56             }
57         );
58     }
59 }