-use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
-use clippy_utils::source::{snippet, snippet_with_applicability};
-use clippy_utils::sugg::Sugg;
-use clippy_utils::{is_wild, meets_msrv, msrvs, path_to_local_id, peel_blocks, strip_pat_refs};
-use core::iter::once;
+use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::{is_wild, meets_msrv, msrvs};
use if_chain::if_chain;
-use rustc_errors::Applicability;
-use rustc_hir::{Arm, BorrowKind, Expr, ExprKind, Local, MatchSource, Mutability, Pat, PatKind, QPath};
+use rustc_hir::{Arm, Expr, ExprKind, Local, MatchSource, Pat, PatKind, QPath};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass};
+mod infalliable_detructuring_match;
mod match_as_ref;
mod match_bool;
mod match_like_matches;
+mod match_ref_pats;
mod match_same_arms;
mod match_single_binding;
mod match_wild_enum;
}
}
if let ExprKind::Match(ex, arms, _) = expr.kind {
- check_match_ref_pats(cx, ex, arms.iter().map(|el| el.pat), expr);
+ match_ref_pats::check(cx, ex, arms.iter().map(|el| el.pat), expr);
}
}
fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'_>) {
- if_chain! {
- if !local.span.from_expansion();
- if let Some(expr) = local.init;
- if let ExprKind::Match(target, arms, MatchSource::Normal) = expr.kind;
- if arms.len() == 1 && arms[0].guard.is_none();
- if let PatKind::TupleStruct(
- QPath::Resolved(None, variant_name), args, _) = arms[0].pat.kind;
- if args.len() == 1;
- if let PatKind::Binding(_, arg, ..) = strip_pat_refs(&args[0]).kind;
- let body = peel_blocks(arms[0].body);
- if path_to_local_id(body, arg);
-
- then {
- let mut applicability = Applicability::MachineApplicable;
- self.infallible_destructuring_match_linted = true;
- span_lint_and_sugg(
- cx,
- INFALLIBLE_DESTRUCTURING_MATCH,
- local.span,
- "you seem to be trying to use `match` to destructure a single infallible pattern. \
- Consider using `let`",
- "try this",
- format!(
- "let {}({}) = {};",
- snippet_with_applicability(cx, variant_name.span, "..", &mut applicability),
- snippet_with_applicability(cx, local.pat.span, "..", &mut applicability),
- snippet_with_applicability(cx, target.span, "..", &mut applicability),
- ),
- applicability,
- );
- }
- }
+ self.infallible_destructuring_match_linted |= infalliable_detructuring_match::check(cx, local);
}
fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
extract_msrv_attr!(LateContext);
}
-fn check_match_ref_pats<'a, 'b, I>(cx: &LateContext<'_>, ex: &Expr<'_>, pats: I, expr: &Expr<'_>)
-where
- 'b: 'a,
- I: Clone + Iterator<Item = &'a Pat<'b>>,
-{
- if !has_multiple_ref_pats(pats.clone()) {
- return;
- }
-
- let (first_sugg, msg, title);
- let span = ex.span.source_callsite();
- if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = ex.kind {
- first_sugg = once((span, Sugg::hir_with_macro_callsite(cx, inner, "..").to_string()));
- msg = "try";
- title = "you don't need to add `&` to both the expression and the patterns";
- } else {
- first_sugg = once((span, Sugg::hir_with_macro_callsite(cx, ex, "..").deref().to_string()));
- msg = "instead of prefixing all patterns with `&`, you can dereference the expression";
- title = "you don't need to add `&` to all patterns";
- }
-
- let remaining_suggs = pats.filter_map(|pat| {
- if let PatKind::Ref(refp, _) = pat.kind {
- Some((pat.span, snippet(cx, refp.span, "..").to_string()))
- } else {
- None
- }
- });
-
- span_lint_and_then(cx, MATCH_REF_PATS, expr.span, title, |diag| {
- if !expr.span.from_expansion() {
- multispan_sugg(diag, msg, first_sugg.chain(remaining_suggs));
- }
- });
-}
-
fn check_wild_in_or_pats(cx: &LateContext<'_>, arms: &[Arm<'_>]) {
for arm in arms {
if let PatKind::Or(fields) = arm.pat.kind {
}
}
}
-
-fn has_multiple_ref_pats<'a, 'b, I>(pats: I) -> bool
-where
- 'b: 'a,
- I: Iterator<Item = &'a Pat<'b>>,
-{
- let mut ref_count = 0;
- for opt in pats.map(|pat| match pat.kind {
- PatKind::Ref(..) => Some(true), // &-patterns
- PatKind::Wild => Some(false), // an "anything" wildcard is also fine
- _ => None, // any other pattern is not fine
- }) {
- if let Some(inner) = opt {
- if inner {
- ref_count += 1;
- }
- } else {
- return false;
- }
- }
- ref_count > 1
-}