]>
Commit | Line | Data |
---|---|---|
dfeec247 XL |
1 | use crate::{LateContext, LateLintPass, LintContext}; |
2 | use rustc::ty; | |
3 | use rustc::ty::adjustment::{Adjust, Adjustment}; | |
4 | use rustc_errors::Applicability; | |
5 | use rustc_hir as hir; | |
6 | use rustc_session::lint::FutureIncompatibleInfo; | |
7 | use rustc_span::symbol::sym; | |
60c5eb7d XL |
8 | |
9 | declare_lint! { | |
10 | pub ARRAY_INTO_ITER, | |
11 | Warn, | |
12 | "detects calling `into_iter` on arrays", | |
13 | @future_incompatible = FutureIncompatibleInfo { | |
14 | reference: "issue #66145 <https://github.com/rust-lang/rust/issues/66145>", | |
15 | edition: None, | |
16 | }; | |
17 | } | |
18 | ||
19 | declare_lint_pass!( | |
20 | /// Checks for instances of calling `into_iter` on arrays. | |
21 | ArrayIntoIter => [ARRAY_INTO_ITER] | |
22 | ); | |
23 | ||
24 | impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ArrayIntoIter { | |
dfeec247 | 25 | fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr<'tcx>) { |
60c5eb7d XL |
26 | // We only care about method call expressions. |
27 | if let hir::ExprKind::MethodCall(call, span, args) = &expr.kind { | |
28 | if call.ident.name != sym::into_iter { | |
29 | return; | |
30 | } | |
31 | ||
32 | // Check if the method call actually calls the libcore | |
33 | // `IntoIterator::into_iter`. | |
34 | let def_id = cx.tables.type_dependent_def_id(expr.hir_id).unwrap(); | |
35 | match cx.tcx.trait_of_item(def_id) { | |
dfeec247 | 36 | Some(trait_id) if cx.tcx.is_diagnostic_item(sym::IntoIterator, trait_id) => {} |
60c5eb7d XL |
37 | _ => return, |
38 | }; | |
39 | ||
40 | // As this is a method call expression, we have at least one | |
41 | // argument. | |
42 | let receiver_arg = &args[0]; | |
43 | ||
dfeec247 XL |
44 | // Peel all `Box<_>` layers. We have to special case `Box` here as |
45 | // `Box` is the only thing that values can be moved out of via | |
46 | // method call. `Box::new([1]).into_iter()` should trigger this | |
47 | // lint. | |
48 | let mut recv_ty = cx.tables.expr_ty(receiver_arg); | |
49 | let mut num_box_derefs = 0; | |
50 | while recv_ty.is_box() { | |
51 | num_box_derefs += 1; | |
52 | recv_ty = recv_ty.boxed_ty(); | |
53 | } | |
54 | ||
55 | // Make sure we found an array after peeling the boxes. | |
56 | if !matches!(recv_ty.kind, ty::Array(..)) { | |
57 | return; | |
60c5eb7d XL |
58 | } |
59 | ||
dfeec247 XL |
60 | // Make sure that there is an autoref coercion at the expected |
61 | // position. The first `num_box_derefs` adjustments are the derefs | |
62 | // of the box. | |
63 | match cx.tables.expr_adjustments(receiver_arg).get(num_box_derefs) { | |
60c5eb7d XL |
64 | Some(Adjustment { kind: Adjust::Borrow(_), .. }) => {} |
65 | _ => return, | |
66 | } | |
67 | ||
68 | // Emit lint diagnostic. | |
69 | let target = match cx.tables.expr_ty_adjusted(receiver_arg).kind { | |
dfeec247 XL |
70 | ty::Ref(_, ty::TyS { kind: ty::Array(..), .. }, _) => "[T; N]", |
71 | ty::Ref(_, ty::TyS { kind: ty::Slice(..), .. }, _) => "[T]", | |
60c5eb7d XL |
72 | |
73 | // We know the original first argument type is an array type, | |
74 | // we know that the first adjustment was an autoref coercion | |
75 | // and we know that `IntoIterator` is the trait involved. The | |
76 | // array cannot be coerced to something other than a reference | |
77 | // to an array or to a slice. | |
78 | _ => bug!("array type coerced to something other than array or slice"), | |
79 | }; | |
74b04a01 XL |
80 | cx.struct_span_lint(ARRAY_INTO_ITER, *span, |lint| { |
81 | lint.build(&format!( | |
60c5eb7d XL |
82 | "this method call currently resolves to `<&{} as IntoIterator>::into_iter` (due \ |
83 | to autoref coercions), but that might change in the future when \ | |
84 | `IntoIterator` impls for arrays are added.", | |
85 | target, | |
74b04a01 | 86 | )) |
60c5eb7d XL |
87 | .span_suggestion( |
88 | call.ident.span, | |
89 | "use `.iter()` instead of `.into_iter()` to avoid ambiguity", | |
90 | "iter".into(), | |
91 | Applicability::MachineApplicable, | |
92 | ) | |
93 | .emit(); | |
74b04a01 | 94 | }) |
60c5eb7d XL |
95 | } |
96 | } | |
97 | } |