1 use clippy_utils::diagnostics::span_lint_and_sugg;
2 use clippy_utils::higher::Range;
3 use clippy_utils::is_integer_const;
4 use rustc_ast::ast::RangeLimits;
5 use rustc_errors::Applicability;
6 use rustc_hir::{Expr, ExprKind, QPath};
7 use rustc_lint::LateContext;
8 use rustc_span::symbol::sym;
11 use super::ITER_WITH_DRAIN;
13 pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, arg: &Expr<'_>) {
14 if !matches!(recv.kind, ExprKind::Field(..))
15 && let Some(adt) = cx.typeck_results().expr_ty(recv).ty_adt_def()
16 && let Some(ty_name) = cx.tcx.get_diagnostic_name(adt.did())
17 && matches!(ty_name, sym::Vec | sym::VecDeque)
18 && let Some(range) = Range::hir(arg)
19 && is_full_range(cx, recv, range)
24 span.with_hi(expr.span.hi()),
25 &format!("`drain(..)` used on a `{ty_name}`"),
27 "into_iter()".to_string(),
28 Applicability::MaybeIncorrect,
33 fn is_full_range(cx: &LateContext<'_>, container: &Expr<'_>, range: Range<'_>) -> bool {
34 range.start.map_or(true, |e| is_integer_const(cx, e, 0))
35 && range.end.map_or(true, |e| {
36 if range.limits == RangeLimits::HalfOpen
37 && let ExprKind::Path(QPath::Resolved(None, container_path)) = container.kind
38 && let ExprKind::MethodCall(name, self_arg, [], _) = e.kind
39 && name.ident.name == sym::len
40 && let ExprKind::Path(QPath::Resolved(None, path)) = self_arg.kind
42 container_path.res == path.res