diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs index 686fc4a0fa0..28adcc2f227 100644 --- a/clippy_lints/src/matches/mod.rs +++ b/clippy_lints/src/matches/mod.rs @@ -1045,7 +1045,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if !from_expansion { // These don't depend on a relationship between multiple arms match_wild_err_arm::check(cx, ex, arms); - wild_in_or_pats::check(cx, arms); + wild_in_or_pats::check(cx, ex, arms); } if let MatchSource::TryDesugar(_) = source { diff --git a/clippy_lints/src/matches/wild_in_or_pats.rs b/clippy_lints/src/matches/wild_in_or_pats.rs index 459513e65bf..390ba889fd2 100644 --- a/clippy_lints/src/matches/wild_in_or_pats.rs +++ b/clippy_lints/src/matches/wild_in_or_pats.rs @@ -1,11 +1,19 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::is_wild; -use rustc_hir::{Arm, PatKind}; +use clippy_utils::{has_non_exhaustive_attr, is_wild}; +use rustc_hir::{Arm, Expr, PatKind}; use rustc_lint::LateContext; +use rustc_middle::ty; use super::WILDCARD_IN_OR_PATTERNS; -pub(crate) fn check(cx: &LateContext<'_>, arms: &[Arm<'_>]) { +pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arms: &[Arm<'_>]) { + // first check if we are matching on an enum that has the non_exhaustive attribute + let ty = cx.typeck_results().expr_ty(expr).peel_refs(); + if let ty::Adt(adt_def, _) = ty.kind() + && has_non_exhaustive_attr(cx.tcx, *adt_def) + { + return; + }; for arm in arms { if let PatKind::Or(fields) = arm.pat.kind { // look for multiple fields in this arm that contains at least one Wild pattern diff --git a/tests/ui/wild_in_or_pats.rs b/tests/ui/wild_in_or_pats.rs index f8bb31b83c4..bc8a1dbee71 100644 --- a/tests/ui/wild_in_or_pats.rs +++ b/tests/ui/wild_in_or_pats.rs @@ -37,4 +37,72 @@ fn main() { dbg!("matched (bar or) wild"); }, }; + + // shouldn't lint + #[non_exhaustive] + pub enum NonExhaustiveEnum<'a> { + Message(&'a str), + Quit(&'a str), + Other, + } + + match NonExhaustiveEnum::Message("Pass") { + NonExhaustiveEnum::Message(_) => dbg!("message"), + NonExhaustiveEnum::Quit(_) => dbg!("quit"), + NonExhaustiveEnum::Other | _ => dbg!("wildcard"), + }; + + // should lint + enum ExhaustiveEnum { + Quit, + Write(String), + ChangeColor(i32, i32, i32), + } + + match ExhaustiveEnum::ChangeColor(0, 160, 255) { + ExhaustiveEnum::Write(text) => { + dbg!("Write"); + }, + ExhaustiveEnum::ChangeColor(r, g, b) => { + dbg!("Change the color"); + }, + ExhaustiveEnum::Quit | _ => { + dbg!("Quit or other"); + }, + }; + + // shouldn't lint + #[non_exhaustive] + struct NonExhaustiveStruct { + a: u32, + b: u32, + c: u64, + } + + let b = NonExhaustiveStruct { a: 5, b: 42, c: 342 }; + + match b { + NonExhaustiveStruct { a: 5, b: 42, .. } => {}, + NonExhaustiveStruct { a: 0, b: 0, c: 128 } => {}, + NonExhaustiveStruct { a: 0, b: 0, c: 128, .. } | _ => {}, + } + + // should lint + struct ExhaustiveStruct { + x: i32, + y: i32, + } + + let p = ExhaustiveStruct { x: 0, y: 7 }; + match p { + ExhaustiveStruct { x: 0, y: 0 } => { + dbg!("On the x axis at {x}"); + }, + ExhaustiveStruct { x: 0, y: 1 } => { + dbg!("On the y axis at {y}"); + }, + ExhaustiveStruct { x: 1, y: 1 } | _ => { + dbg!("On neither axis: ({x}, {y})"); + }, + } } diff --git a/tests/ui/wild_in_or_pats.stderr b/tests/ui/wild_in_or_pats.stderr index 06b2415d221..5e409d6dfa6 100644 --- a/tests/ui/wild_in_or_pats.stderr +++ b/tests/ui/wild_in_or_pats.stderr @@ -32,5 +32,21 @@ LL | _ | "bar" => { | = help: consider handling `_` separately -error: aborting due to 4 previous errors +error: wildcard pattern covers any other pattern as it will match anyway + --> tests/ui/wild_in_or_pats.rs:69:9 + | +LL | ExhaustiveEnum::Quit | _ => { + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider handling `_` separately + +error: wildcard pattern covers any other pattern as it will match anyway + --> tests/ui/wild_in_or_pats.rs:104:9 + | +LL | ExhaustiveStruct { x: 1, y: 1 } | _ => { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider handling `_` separately + +error: aborting due to 6 previous errors