]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/methods/iter_overeager_cloned.rs
Merge commit '984330a6ee3c4d15626685d6dc8b7b759ff630bd' into clippyup
[rust.git] / clippy_lints / src / methods / iter_overeager_cloned.rs
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;
6 use rustc_hir as hir;
7 use rustc_lint::LateContext;
8 use rustc_middle::ty;
9 use rustc_span::sym;
10 use std::ops::Not;
11
12 use super::ITER_OVEREAGER_CLONED;
13 use crate::redundant_clone::REDUNDANT_CLONE;
14
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<'_>,
20     name: &str,
21     map_arg: &[hir::Expr<'_>],
22 ) {
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));
29         then {
30             inner_ty
31         } else {
32             return;
33         }
34     };
35
36     match inner_ty.kind() {
37         ty::Ref(_, ty, _) if !is_copy(cx, *ty) => {},
38         _ => return,
39     };
40
41     let (lint, preserve_cloned) = match name {
42         "count" => (REDUNDANT_CLONE, false),
43         _ => (ITER_OVEREAGER_CLONED, true),
44     };
45     let wildcard_params = map_arg.is_empty().not().then(|| "...").unwrap_or_default();
46     let msg = format!(
47         "called `cloned().{}({})` on an `Iterator`. It may be more efficient to call `{}({}){}` instead",
48         name,
49         wildcard_params,
50         name,
51         wildcard_params,
52         preserve_cloned.then(|| ".cloned()").unwrap_or_default(),
53     );
54
55     span_lint_and_sugg(
56         cx,
57         lint,
58         expr.span,
59         &msg,
60         "try this",
61         format!(
62             "{}.{}({}){}",
63             snippet(cx, recv.span, ".."),
64             name,
65             map_arg.iter().map(|a| snippet(cx, a.span, "..")).join(", "),
66             preserve_cloned.then(|| ".cloned()").unwrap_or_default(),
67         ),
68         Applicability::MachineApplicable,
69     );
70 }