diff --git a/clippy_lints/src/loops/for_kv_map.rs b/clippy_lints/src/loops/for_kv_map.rs index 39b2391c98ec..7fb8e51377a2 100644 --- a/clippy_lints/src/loops/for_kv_map.rs +++ b/clippy_lints/src/loops/for_kv_map.rs @@ -1,16 +1,22 @@ use super::FOR_KV_MAP; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::res::MaybeDef; -use clippy_utils::source::snippet; +use clippy_utils::source::{snippet_with_applicability, walk_span_to_context}; use clippy_utils::{pat_is_wild, sugg}; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Pat, PatKind}; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::sym; +use rustc_span::{Span, sym}; /// Checks for the `FOR_KV_MAP` lint. -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, arg: &'tcx Expr<'_>, body: &'tcx Expr<'_>) { +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + pat: &'tcx Pat<'_>, + arg: &'tcx Expr<'_>, + body: &'tcx Expr<'_>, + span: Span, +) { let pat_span = pat.span; if let PatKind::Tuple(pat, _) = pat.kind @@ -34,21 +40,25 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, arg: &'tcx _ => arg, }; - if matches!(ty.opt_diag_name(cx), Some(sym::HashMap | sym::BTreeMap)) { + if matches!(ty.opt_diag_name(cx), Some(sym::HashMap | sym::BTreeMap)) + && let Some(arg_span) = walk_span_to_context(arg_span, span.ctxt()) + { span_lint_and_then( cx, FOR_KV_MAP, arg_span, format!("you seem to want to iterate on a map's {kind}s"), |diag| { - let map = sugg::Sugg::hir(cx, arg, "map"); + let mut applicability = Applicability::MachineApplicable; + let map = sugg::Sugg::hir_with_context(cx, arg, span.ctxt(), "map", &mut applicability); + let pat = snippet_with_applicability(cx, new_pat_span, kind, &mut applicability); diag.multipart_suggestion( "use the corresponding method", vec![ - (pat_span, snippet(cx, new_pat_span, kind).into_owned()), + (pat_span, pat.to_string()), (arg_span, format!("{}.{kind}s{mutbl}()", map.maybe_paren())), ], - Applicability::MachineApplicable, + applicability, ); }, ); diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs index ddc783069385..83574cab6b67 100644 --- a/clippy_lints/src/loops/mod.rs +++ b/clippy_lints/src/loops/mod.rs @@ -943,7 +943,7 @@ fn check_for_loop<'tcx>( explicit_counter_loop::check(cx, pat, arg, body, expr, label); } self.check_for_loop_arg(cx, pat, arg); - for_kv_map::check(cx, pat, arg, body); + for_kv_map::check(cx, pat, arg, body, span); mut_range_bound::check(cx, arg, body); single_element_loop::check(cx, pat, arg, body, expr); same_item_push::check(cx, pat, arg, body, expr, self.msrv); diff --git a/tests/ui/for_kv_map.fixed b/tests/ui/for_kv_map.fixed index 2a68b7443fbf..6ec4cb01ffd1 100644 --- a/tests/ui/for_kv_map.fixed +++ b/tests/ui/for_kv_map.fixed @@ -69,3 +69,20 @@ fn main() { let _v = v; } } + +fn wrongly_unmangled_macros() { + use std::collections::HashMap; + + macro_rules! test_map { + ($val:expr) => { + &*$val + }; + } + + let m: HashMap = HashMap::new(); + let wrapped = Rc::new(m); + for v in test_map!(wrapped).values() { + //~^ for_kv_map + let _v = v; + } +} diff --git a/tests/ui/for_kv_map.rs b/tests/ui/for_kv_map.rs index 485a97815e3c..19e907ff10a6 100644 --- a/tests/ui/for_kv_map.rs +++ b/tests/ui/for_kv_map.rs @@ -69,3 +69,20 @@ fn main() { let _v = v; } } + +fn wrongly_unmangled_macros() { + use std::collections::HashMap; + + macro_rules! test_map { + ($val:expr) => { + &*$val + }; + } + + let m: HashMap = HashMap::new(); + let wrapped = Rc::new(m); + for (_, v) in test_map!(wrapped) { + //~^ for_kv_map + let _v = v; + } +} diff --git a/tests/ui/for_kv_map.stderr b/tests/ui/for_kv_map.stderr index 0bd474a10682..5436592f2ab6 100644 --- a/tests/ui/for_kv_map.stderr +++ b/tests/ui/for_kv_map.stderr @@ -72,5 +72,17 @@ LL - 'label: for (k, _value) in rm { LL + 'label: for k in rm.keys() { | -error: aborting due to 6 previous errors +error: you seem to want to iterate on a map's values + --> tests/ui/for_kv_map.rs:84:19 + | +LL | for (_, v) in test_map!(wrapped) { + | ^^^^^^^^^^^^^^^^^^ + | +help: use the corresponding method + | +LL - for (_, v) in test_map!(wrapped) { +LL + for v in test_map!(wrapped).values() { + | + +error: aborting due to 7 previous errors