1 use clippy_utils::diagnostics::span_lint_and_sugg;
2 use clippy_utils::is_integer_const;
3 use clippy_utils::ty::is_type_diagnostic_item;
8 use rustc_ast::ast::RangeLimits;
9 use rustc_errors::Applicability;
10 use rustc_hir::{Expr, ExprKind, QPath};
11 use rustc_lint::LateContext;
12 use rustc_span::symbol::{sym, Symbol};
15 use super::ITER_WITH_DRAIN;
17 const DRAIN_TYPES: &[Symbol] = &[sym::Vec, sym::VecDeque];
19 pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, arg: &Expr<'_>) {
20 let ty = cx.typeck_results().expr_ty(recv).peel_refs();
21 if let Some(drained_type) = DRAIN_TYPES.iter().find(|&&sym| is_type_diagnostic_item(cx, ty, sym)) {
22 // Refuse to emit `into_iter` suggestion on draining struct fields due
23 // to the strong possibility of processing unmovable field.
24 if let ExprKind::Field(..) = recv.kind {
28 if let Some(range) = higher::Range::hir(arg) {
29 let left_full = match range {
30 Range { start: Some(start), .. } if is_integer_const(cx, start, 0) => true,
31 Range { start: None, .. } => true,
38 limits: RangeLimits::HalfOpen,
41 // `x.drain(..x.len())` call
43 if let ExprKind::MethodCall(len_path, len_args, _) = end.kind;
44 if len_path.ident.name == sym::len && len_args.len() == 1;
45 if let ExprKind::Path(QPath::Resolved(_, drain_path)) = recv.kind;
46 if let ExprKind::Path(QPath::Resolved(_, len_path)) = len_args[0].kind;
47 if SpanlessEq::new(cx).eq_path(drain_path, len_path);
54 limits: RangeLimits::HalfOpen,
63 span.with_hi(expr.span.hi()),
64 &format!("`drain(..)` used on a `{}`", drained_type),
66 "into_iter()".to_string(),
67 Applicability::MaybeIncorrect,