1 use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
2 use clippy_utils::source::snippet;
3 use clippy_utils::sugg::Sugg;
5 use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Pat, PatKind};
6 use rustc_lint::LateContext;
8 use super::MATCH_REF_PATS;
10 pub(crate) fn check<'a, 'b, I>(cx: &LateContext<'_>, ex: &Expr<'_>, pats: I, expr: &Expr<'_>)
13 I: Clone + Iterator<Item = &'a Pat<'b>>,
15 if !has_multiple_ref_pats(pats.clone()) {
19 let (first_sugg, msg, title);
20 let span = ex.span.source_callsite();
21 if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = ex.kind {
22 first_sugg = once((span, Sugg::hir_with_macro_callsite(cx, inner, "..").to_string()));
24 title = "you don't need to add `&` to both the expression and the patterns";
26 first_sugg = once((span, Sugg::hir_with_macro_callsite(cx, ex, "..").deref().to_string()));
27 msg = "instead of prefixing all patterns with `&`, you can dereference the expression";
28 title = "you don't need to add `&` to all patterns";
31 let remaining_suggs = pats.filter_map(|pat| {
32 if let PatKind::Ref(refp, _) = pat.kind {
33 Some((pat.span, snippet(cx, refp.span, "..").to_string()))
39 span_lint_and_then(cx, MATCH_REF_PATS, expr.span, title, |diag| {
40 if !expr.span.from_expansion() {
41 multispan_sugg(diag, msg, first_sugg.chain(remaining_suggs));
46 fn has_multiple_ref_pats<'a, 'b, I>(pats: I) -> bool
49 I: Iterator<Item = &'a Pat<'b>>,
51 let mut ref_count = 0;
52 for opt in pats.map(|pat| match pat.kind {
53 PatKind::Ref(..) => Some(true), // &-patterns
54 PatKind::Wild => Some(false), // an "anything" wildcard is also fine
55 _ => None, // any other pattern is not fine
57 if let Some(inner) = opt {