|
1 | 1 | use clippy_utils::diagnostics::span_lint_and_sugg;
|
| 2 | +use clippy_utils::higher::Range; |
2 | 3 | use clippy_utils::is_integer_const;
|
3 |
| -use clippy_utils::ty::is_type_diagnostic_item; |
4 |
| -use clippy_utils::{ |
5 |
| - higher::{self, Range}, |
6 |
| - SpanlessEq, |
7 |
| -}; |
8 | 4 | use rustc_ast::ast::RangeLimits;
|
9 | 5 | use rustc_errors::Applicability;
|
10 | 6 | use rustc_hir::{Expr, ExprKind, QPath};
|
11 | 7 | use rustc_lint::LateContext;
|
12 |
| -use rustc_span::symbol::{sym, Symbol}; |
| 8 | +use rustc_span::symbol::sym; |
13 | 9 | use rustc_span::Span;
|
14 | 10 |
|
15 | 11 | use super::ITER_WITH_DRAIN;
|
16 | 12 |
|
17 |
| -const DRAIN_TYPES: &[Symbol] = &[sym::Vec, sym::VecDeque]; |
18 |
| - |
19 | 13 | 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 { |
25 |
| - return; |
26 |
| - } |
| 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) |
| 20 | + { |
| 21 | + span_lint_and_sugg( |
| 22 | + cx, |
| 23 | + ITER_WITH_DRAIN, |
| 24 | + span.with_hi(expr.span.hi()), |
| 25 | + &format!("`drain(..)` used on a `{}`", ty_name), |
| 26 | + "try this", |
| 27 | + "into_iter()".to_string(), |
| 28 | + Applicability::MaybeIncorrect, |
| 29 | + ); |
| 30 | + }; |
| 31 | +} |
27 | 32 |
|
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, |
32 |
| - _ => false, |
33 |
| - }; |
34 |
| - let full = left_full |
35 |
| - && match range { |
36 |
| - Range { |
37 |
| - end: Some(end), |
38 |
| - limits: RangeLimits::HalfOpen, |
39 |
| - .. |
40 |
| - } => { |
41 |
| - // `x.drain(..x.len())` call |
42 |
| - if_chain! { |
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); |
48 |
| - then { true } |
49 |
| - else { false } |
50 |
| - } |
51 |
| - }, |
52 |
| - Range { |
53 |
| - end: None, |
54 |
| - limits: RangeLimits::HalfOpen, |
55 |
| - .. |
56 |
| - } => true, |
57 |
| - _ => false, |
58 |
| - }; |
59 |
| - if full { |
60 |
| - span_lint_and_sugg( |
61 |
| - cx, |
62 |
| - ITER_WITH_DRAIN, |
63 |
| - span.with_hi(expr.span.hi()), |
64 |
| - &format!("`drain(..)` used on a `{}`", drained_type), |
65 |
| - "try this", |
66 |
| - "into_iter()".to_string(), |
67 |
| - Applicability::MaybeIncorrect, |
68 |
| - ); |
| 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 |
| 41 | + { |
| 42 | + container_path.res == path.res |
| 43 | + } else { |
| 44 | + false |
69 | 45 | }
|
70 |
| - } |
71 |
| - } |
| 46 | + }) |
72 | 47 | }
|
0 commit comments