2022-06-06 23:40:32 -05:00
|
|
|
use clippy_utils::diagnostics::span_lint_and_then;
|
|
|
|
use clippy_utils::source::snippet_opt;
|
|
|
|
use clippy_utils::ty::{get_associated_type, implements_trait, is_copy};
|
2022-01-17 06:29:07 -06:00
|
|
|
use rustc_errors::Applicability;
|
2022-06-06 23:40:32 -05:00
|
|
|
use rustc_hir::Expr;
|
2022-01-17 06:29:07 -06:00
|
|
|
use rustc_lint::LateContext;
|
|
|
|
use rustc_middle::ty;
|
2022-03-29 07:51:37 -05:00
|
|
|
use rustc_span::sym;
|
2022-01-17 06:29:07 -06:00
|
|
|
|
|
|
|
use super::ITER_OVEREAGER_CLONED;
|
|
|
|
use crate::redundant_clone::REDUNDANT_CLONE;
|
|
|
|
|
|
|
|
pub(super) fn check<'tcx>(
|
|
|
|
cx: &LateContext<'tcx>,
|
2022-06-06 23:40:32 -05:00
|
|
|
expr: &'tcx Expr<'_>,
|
|
|
|
cloned_call: &'tcx Expr<'_>,
|
|
|
|
cloned_recv: &'tcx Expr<'_>,
|
|
|
|
is_count: bool,
|
|
|
|
needs_into_iter: bool,
|
2022-01-17 06:29:07 -06:00
|
|
|
) {
|
2022-06-06 23:40:32 -05:00
|
|
|
let typeck = cx.typeck_results();
|
|
|
|
if let Some(iter_id) = cx.tcx.get_diagnostic_item(sym::Iterator)
|
|
|
|
&& let Some(method_id) = typeck.type_dependent_def_id(expr.hir_id)
|
|
|
|
&& cx.tcx.trait_of_item(method_id) == Some(iter_id)
|
|
|
|
&& let Some(method_id) = typeck.type_dependent_def_id(cloned_call.hir_id)
|
|
|
|
&& cx.tcx.trait_of_item(method_id) == Some(iter_id)
|
|
|
|
&& let cloned_recv_ty = typeck.expr_ty_adjusted(cloned_recv)
|
|
|
|
&& let Some(iter_assoc_ty) = get_associated_type(cx, cloned_recv_ty, iter_id, "Item")
|
|
|
|
&& matches!(*iter_assoc_ty.kind(), ty::Ref(_, ty, _) if !is_copy(cx, ty))
|
|
|
|
{
|
|
|
|
if needs_into_iter
|
|
|
|
&& let Some(into_iter_id) = cx.tcx.get_diagnostic_item(sym::IntoIterator)
|
|
|
|
&& !implements_trait(cx, iter_assoc_ty, into_iter_id, &[])
|
|
|
|
{
|
2022-03-29 07:51:37 -05:00
|
|
|
return;
|
|
|
|
}
|
2022-01-17 06:29:07 -06:00
|
|
|
|
2022-06-06 23:40:32 -05:00
|
|
|
let (lint, msg, trailing_clone) = if is_count {
|
|
|
|
(REDUNDANT_CLONE, "unneeded cloning of iterator items", "")
|
|
|
|
} else {
|
|
|
|
(ITER_OVEREAGER_CLONED, "unnecessarily eager cloning of iterator items", ".cloned()")
|
|
|
|
};
|
2022-01-17 06:29:07 -06:00
|
|
|
|
2022-06-06 23:40:32 -05:00
|
|
|
span_lint_and_then(
|
|
|
|
cx,
|
|
|
|
lint,
|
|
|
|
expr.span,
|
|
|
|
msg,
|
|
|
|
|diag| {
|
|
|
|
let method_span = expr.span.with_lo(cloned_call.span.hi());
|
|
|
|
if let Some(mut snip) = snippet_opt(cx, method_span) {
|
|
|
|
snip.push_str(trailing_clone);
|
|
|
|
let replace_span = expr.span.with_lo(cloned_recv.span.hi());
|
|
|
|
diag.span_suggestion(replace_span, "try this", snip, Applicability::MachineApplicable);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
2022-01-17 06:29:07 -06:00
|
|
|
}
|