1 use super::EXPLICIT_ITER_LOOP;
2 use crate::utils::{match_trait_method, snippet_with_applicability, span_lint_and_sugg};
3 use rustc_errors::Applicability;
4 use rustc_hir::{Expr, Mutability};
5 use rustc_lint::LateContext;
6 use rustc_middle::ty::{self, Ty, TyS};
9 use crate::utils::{is_type_diagnostic_item, match_type, paths};
11 pub(super) fn check(cx: &LateContext<'_>, args: &[Expr<'_>], arg: &Expr<'_>, method_name: &str) {
12 let should_lint = match method_name {
13 "iter" | "iter_mut" => is_ref_iterable_type(cx, &args[0]),
14 "into_iter" if match_trait_method(cx, arg, &paths::INTO_ITERATOR) => {
15 let receiver_ty = cx.typeck_results().expr_ty(&args[0]);
16 let receiver_ty_adjusted = cx.typeck_results().expr_ty_adjusted(&args[0]);
17 let ref_receiver_ty = cx.tcx.mk_ref(
18 cx.tcx.lifetimes.re_erased,
21 mutbl: Mutability::Not,
24 TyS::same_type(receiver_ty_adjusted, ref_receiver_ty)
33 let mut applicability = Applicability::MachineApplicable;
34 let object = snippet_with_applicability(cx, args[0].span, "_", &mut applicability);
35 let muta = if method_name == "iter_mut" { "mut " } else { "" };
40 "it is more concise to loop over references to containers instead of using explicit \
42 "to write this more concisely, try",
43 format!("&{}{}", muta, object),
48 /// Returns `true` if the type of expr is one that provides `IntoIterator` impls
49 /// for `&T` and `&mut T`, such as `Vec`.
51 fn is_ref_iterable_type(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
52 // no walk_ptrs_ty: calling iter() on a reference can make sense because it
53 // will allow further borrows afterwards
54 let ty = cx.typeck_results().expr_ty(e);
55 is_iterable_array(ty, cx) ||
56 is_type_diagnostic_item(cx, ty, sym::vec_type) ||
57 match_type(cx, ty, &paths::LINKED_LIST) ||
58 is_type_diagnostic_item(cx, ty, sym::hashmap_type) ||
59 is_type_diagnostic_item(cx, ty, sym::hashset_type) ||
60 is_type_diagnostic_item(cx, ty, sym::vecdeque_type) ||
61 match_type(cx, ty, &paths::BINARY_HEAP) ||
62 match_type(cx, ty, &paths::BTREEMAP) ||
63 match_type(cx, ty, &paths::BTREESET)
66 fn is_iterable_array<'tcx>(ty: Ty<'tcx>, cx: &LateContext<'tcx>) -> bool {
67 // IntoIterator is currently only implemented for array sizes <= 32 in rustc
70 .try_eval_usize(cx.tcx, cx.param_env)
71 .map_or(false, |val| (0..=32).contains(&val)),