2 use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
3 use clippy_utils::source::snippet;
4 use clippy_utils::sugg;
5 use clippy_utils::ty::is_type_diagnostic_item;
6 use clippy_utils::visitors::is_local_used;
7 use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Pat, PatKind};
8 use rustc_lint::LateContext;
12 /// Checks for the `FOR_KV_MAP` lint.
13 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, arg: &'tcx Expr<'_>, body: &'tcx Expr<'_>) {
14 let pat_span = pat.span;
16 if let PatKind::Tuple(pat, _) = pat.kind {
18 let arg_span = arg.span;
19 let (new_pat_span, kind, ty, mutbl) = match *cx.typeck_results().expr_ty(arg).kind() {
20 ty::Ref(_, ty, mutbl) => match (&pat[0].kind, &pat[1].kind) {
21 (key, _) if pat_is_wild(cx, key, body) => (pat[1].span, "value", ty, mutbl),
22 (_, value) if pat_is_wild(cx, value, body) => (pat[0].span, "key", ty, Mutability::Not),
27 let mutbl = match mutbl {
28 Mutability::Not => "",
29 Mutability::Mut => "_mut",
31 let arg = match arg.kind {
32 ExprKind::AddrOf(BorrowKind::Ref, _, expr) => expr,
36 if is_type_diagnostic_item(cx, ty, sym::HashMap) || is_type_diagnostic_item(cx, ty, sym::BTreeMap) {
41 &format!("you seem to want to iterate on a map's {}s", kind),
43 let map = sugg::Sugg::hir(cx, arg, "map");
46 "use the corresponding method",
48 (pat_span, snippet(cx, new_pat_span, kind).into_owned()),
49 (arg_span, format!("{}.{}s{}()", map.maybe_par(), kind, mutbl)),
59 /// Returns `true` if the pattern is a `PatWild` or an ident prefixed with `_`.
60 fn pat_is_wild<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx PatKind<'_>, body: &'tcx Expr<'_>) -> bool {
62 PatKind::Wild => true,
63 PatKind::Binding(_, id, ident, None) if ident.as_str().starts_with('_') => !is_local_used(cx, body, id),