fix: for_kv_map wrongly unmangled macros

This commit is contained in:
Linshu Yang
2026-01-03 01:59:18 +00:00
parent 908860ed10
commit 8ccfc833a0
5 changed files with 65 additions and 9 deletions
+17 -7
View File
@@ -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,
);
},
);
+1 -1
View File
@@ -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);
+17
View File
@@ -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<u64, u64> = HashMap::new();
let wrapped = Rc::new(m);
for v in test_map!(wrapped).values() {
//~^ for_kv_map
let _v = v;
}
}
+17
View File
@@ -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<u64, u64> = HashMap::new();
let wrapped = Rc::new(m);
for (_, v) in test_map!(wrapped) {
//~^ for_kv_map
let _v = v;
}
}
+13 -1
View File
@@ -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