use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::source::SpanRangeExt; use itertools::Itertools; use rustc_ast::ast::{Pat, PatKind}; use rustc_lint::EarlyContext; use super::UNNEEDED_FIELD_PATTERN; pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) { if let PatKind::Struct(_, ref npat, ref pfields, _) = pat.kind { let mut wilds = 0; let type_name = npat .segments .last() .expect("A path must have at least one segment") .ident .name; for field in pfields { if let PatKind::Wild = field.pat.kind { wilds += 1; } } if !pfields.is_empty() && wilds == pfields.len() { #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] span_lint_and_then( cx, UNNEEDED_FIELD_PATTERN, pat.span, "all the struct fields are matched to a wildcard pattern, consider using `..`", |diag| { diag.help(format!("try with `{type_name} {{ .. }}` instead")); }, ); return; } if wilds > 0 { for field in pfields { if let PatKind::Wild = field.pat.kind { wilds -= 1; if wilds > 0 { span_lint( cx, UNNEEDED_FIELD_PATTERN, field.span, "you matched a field with a wildcard pattern, consider using `..` instead", ); } else { #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] span_lint_and_then( cx, UNNEEDED_FIELD_PATTERN, field.span, "you matched a field with a wildcard pattern, consider using `..` instead", |diag| { diag.help(format!( "try with `{type_name} {{ {}, .. }}`", pfields .iter() .filter_map(|f| match f.pat.kind { PatKind::Wild => None, _ => f.span.get_source_text(cx), }) .format(", "), )); }, ); } } } } } }