mirror of
https://github.com/rust-lang/rust.git
synced 2026-02-15 01:14:05 +00:00
Having a macro call as the scrutinee is supported. However, the proposed suggestion must use the macro call itself, not its expansion. When the scrutinee is a macro call, do not complain about an irrefutable match, as the user may not be aware of the result of the macro. A comparaison will be suggested instead, as if we couldn't see the outcome of the macro. Similarly, do not accept macro calls as arm patterns.
506 lines
9.4 KiB
Rust
506 lines
9.4 KiB
Rust
//@require-annotations-for-level: WARN
|
|
#![warn(clippy::single_match)]
|
|
#![allow(
|
|
unused,
|
|
clippy::uninlined_format_args,
|
|
clippy::needless_if,
|
|
clippy::redundant_guards,
|
|
clippy::redundant_pattern_matching,
|
|
clippy::manual_unwrap_or_default
|
|
)]
|
|
fn dummy() {}
|
|
|
|
fn single_match() {
|
|
let x = Some(1u8);
|
|
|
|
match x {
|
|
Some(y) => {
|
|
println!("{:?}", y);
|
|
},
|
|
_ => (),
|
|
};
|
|
//~^^^^^^ single_match
|
|
|
|
let x = Some(1u8);
|
|
match x {
|
|
// Note the missing block braces.
|
|
// We suggest `if let Some(y) = x { .. }` because the macro
|
|
// is expanded before we can do anything.
|
|
Some(y) => println!("{:?}", y),
|
|
_ => (),
|
|
}
|
|
//~^^^^^^^ single_match
|
|
//~| NOTE: you might want to preserve the comments from inside the `match`
|
|
|
|
let z = (1u8, 1u8);
|
|
match z {
|
|
(2..=3, 7..=9) => dummy(),
|
|
_ => {},
|
|
};
|
|
//~^^^^ single_match
|
|
|
|
// Not linted (pattern guards used)
|
|
match x {
|
|
Some(y) if y == 0 => println!("{:?}", y),
|
|
_ => (),
|
|
}
|
|
|
|
// Not linted (no block with statements in the single arm)
|
|
match z {
|
|
(2..=3, 7..=9) => println!("{:?}", z),
|
|
_ => println!("nope"),
|
|
}
|
|
}
|
|
|
|
enum Foo {
|
|
Bar,
|
|
Baz(u8),
|
|
}
|
|
use Foo::*;
|
|
use std::borrow::Cow;
|
|
|
|
fn single_match_know_enum() {
|
|
let x = Some(1u8);
|
|
let y: Result<_, i8> = Ok(1i8);
|
|
|
|
match x {
|
|
Some(y) => dummy(),
|
|
None => (),
|
|
};
|
|
//~^^^^ single_match
|
|
|
|
match y {
|
|
Ok(y) => dummy(),
|
|
Err(..) => (),
|
|
};
|
|
//~^^^^ single_match
|
|
|
|
let c = Cow::Borrowed("");
|
|
|
|
match c {
|
|
Cow::Borrowed(..) => dummy(),
|
|
Cow::Owned(..) => (),
|
|
};
|
|
//~^^^^ single_match
|
|
|
|
let z = Foo::Bar;
|
|
// no warning
|
|
match z {
|
|
Bar => println!("42"),
|
|
Baz(_) => (),
|
|
}
|
|
|
|
match z {
|
|
Baz(_) => println!("42"),
|
|
Bar => (),
|
|
}
|
|
}
|
|
|
|
// issue #173
|
|
fn if_suggestion() {
|
|
let x = "test";
|
|
match x {
|
|
"test" => println!(),
|
|
_ => (),
|
|
}
|
|
//~^^^^ single_match
|
|
|
|
#[derive(PartialEq, Eq)]
|
|
enum Foo {
|
|
A,
|
|
B,
|
|
C(u32),
|
|
}
|
|
|
|
let x = Foo::A;
|
|
match x {
|
|
Foo::A => println!(),
|
|
_ => (),
|
|
}
|
|
//~^^^^ single_match
|
|
|
|
const FOO_C: Foo = Foo::C(0);
|
|
match x {
|
|
FOO_C => println!(),
|
|
_ => (),
|
|
}
|
|
//~^^^^ single_match
|
|
|
|
match &&x {
|
|
Foo::A => println!(),
|
|
_ => (),
|
|
}
|
|
//~^^^^ single_match
|
|
|
|
let x = &x;
|
|
match &x {
|
|
Foo::A => println!(),
|
|
_ => (),
|
|
}
|
|
//~^^^^ single_match
|
|
|
|
enum Bar {
|
|
A,
|
|
B,
|
|
}
|
|
impl PartialEq for Bar {
|
|
fn eq(&self, rhs: &Self) -> bool {
|
|
matches!((self, rhs), (Self::A, Self::A) | (Self::B, Self::B))
|
|
}
|
|
}
|
|
impl Eq for Bar {}
|
|
|
|
let x = Bar::A;
|
|
match x {
|
|
Bar::A => println!(),
|
|
_ => (),
|
|
}
|
|
//~^^^^ single_match
|
|
|
|
// issue #7038
|
|
struct X;
|
|
let x = Some(X);
|
|
match x {
|
|
None => println!(),
|
|
_ => (),
|
|
};
|
|
//~^^^^ single_match
|
|
}
|
|
|
|
// See: issue #8282
|
|
fn ranges() {
|
|
enum E {
|
|
V,
|
|
}
|
|
let x = (Some(E::V), Some(42));
|
|
|
|
// Don't lint, because the `E` enum can be extended with additional fields later. Thus, the
|
|
// proposed replacement to `if let Some(E::V)` may hide non-exhaustive warnings that appeared
|
|
// because of `match` construction.
|
|
match x {
|
|
(Some(E::V), _) => {},
|
|
(None, _) => {},
|
|
}
|
|
|
|
// lint
|
|
match x {
|
|
(Some(_), _) => {},
|
|
(None, _) => {},
|
|
}
|
|
//~^^^^ single_match
|
|
|
|
// lint
|
|
match x {
|
|
(Some(E::V), _) => todo!(),
|
|
(_, _) => {},
|
|
}
|
|
//~^^^^ single_match
|
|
|
|
// lint
|
|
match (Some(42), Some(E::V), Some(42)) {
|
|
(.., Some(E::V), _) => {},
|
|
(..) => {},
|
|
}
|
|
//~^^^^ single_match
|
|
|
|
// Don't lint, see above.
|
|
match (Some(E::V), Some(E::V), Some(E::V)) {
|
|
(.., Some(E::V), _) => {},
|
|
(.., None, _) => {},
|
|
}
|
|
|
|
// Don't lint, see above.
|
|
match (Some(E::V), Some(E::V), Some(E::V)) {
|
|
(Some(E::V), ..) => {},
|
|
(None, ..) => {},
|
|
}
|
|
|
|
// Don't lint, see above.
|
|
match (Some(E::V), Some(E::V), Some(E::V)) {
|
|
(_, Some(E::V), ..) => {},
|
|
(_, None, ..) => {},
|
|
}
|
|
}
|
|
|
|
fn skip_type_aliases() {
|
|
enum OptionEx {
|
|
Some(i32),
|
|
None,
|
|
}
|
|
enum ResultEx {
|
|
Err(i32),
|
|
Ok(i32),
|
|
}
|
|
|
|
use OptionEx::{None, Some};
|
|
use ResultEx::{Err, Ok};
|
|
|
|
// don't lint
|
|
match Err(42) {
|
|
Ok(_) => dummy(),
|
|
Err(_) => (),
|
|
};
|
|
|
|
// don't lint
|
|
match Some(1i32) {
|
|
Some(_) => dummy(),
|
|
None => (),
|
|
};
|
|
}
|
|
|
|
macro_rules! single_match {
|
|
($num:literal) => {
|
|
match $num {
|
|
15 => println!("15"),
|
|
_ => (),
|
|
}
|
|
};
|
|
}
|
|
|
|
fn main() {
|
|
single_match!(5);
|
|
|
|
// Don't lint
|
|
let _ = match Some(0) {
|
|
#[cfg(feature = "foo")]
|
|
Some(10) => 11,
|
|
Some(x) => x,
|
|
_ => 0,
|
|
};
|
|
}
|
|
|
|
fn issue_10808(bar: Option<i32>) {
|
|
match bar {
|
|
Some(v) => unsafe {
|
|
let r = &v as *const i32;
|
|
println!("{}", *r);
|
|
},
|
|
_ => {},
|
|
}
|
|
//~^^^^^^^ single_match
|
|
|
|
match bar {
|
|
#[rustfmt::skip]
|
|
Some(v) => {
|
|
unsafe {
|
|
let r = &v as *const i32;
|
|
println!("{}", *r);
|
|
}
|
|
},
|
|
_ => {},
|
|
}
|
|
//~^^^^^^^^^^ single_match
|
|
}
|
|
|
|
mod issue8634 {
|
|
struct SomeError(i32, i32);
|
|
|
|
fn foo(x: Result<i32, ()>) {
|
|
match x {
|
|
Ok(y) => {
|
|
println!("Yay! {y}");
|
|
},
|
|
Err(()) => {
|
|
// Ignore this error because blah blah blah.
|
|
},
|
|
}
|
|
}
|
|
|
|
fn bar(x: Result<i32, SomeError>) {
|
|
match x {
|
|
Ok(y) => {
|
|
println!("Yay! {y}");
|
|
},
|
|
Err(_) => {
|
|
// TODO: Process the error properly.
|
|
},
|
|
}
|
|
}
|
|
|
|
fn block_comment(x: Result<i32, SomeError>) {
|
|
match x {
|
|
Ok(y) => {
|
|
println!("Yay! {y}");
|
|
},
|
|
Err(_) => {
|
|
/*
|
|
let's make sure that this also
|
|
does not lint block comments.
|
|
*/
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
fn issue11365() {
|
|
enum Foo {
|
|
A,
|
|
B,
|
|
C,
|
|
}
|
|
use Foo::{A, B, C};
|
|
|
|
match Some(A) {
|
|
Some(A | B | C) => println!(),
|
|
None => {},
|
|
}
|
|
|
|
match Some(A) {
|
|
Some(A | B) => println!(),
|
|
Some { 0: C } | None => {},
|
|
}
|
|
|
|
match [A, A] {
|
|
[A, _] => println!(),
|
|
[_, A | B | C] => {},
|
|
}
|
|
|
|
match Ok::<_, u32>(Some(A)) {
|
|
Ok(Some(A)) => println!(),
|
|
Err(_) | Ok(None | Some(B | C)) => {},
|
|
}
|
|
|
|
match Ok::<_, u32>(Some(A)) {
|
|
Ok(Some(A)) => println!(),
|
|
Err(_) | Ok(None | Some(_)) => {},
|
|
}
|
|
//~^^^^ single_match
|
|
|
|
match &Some(A) {
|
|
Some(A | B | C) => println!(),
|
|
None => {},
|
|
}
|
|
|
|
match &Some(A) {
|
|
&Some(A | B | C) => println!(),
|
|
None => {},
|
|
}
|
|
|
|
match &Some(A) {
|
|
Some(A | B) => println!(),
|
|
None | Some(_) => {},
|
|
}
|
|
//~^^^^ single_match
|
|
}
|
|
|
|
fn issue12758(s: &[u8]) {
|
|
match &s[0..3] {
|
|
b"foo" => println!(),
|
|
_ => {},
|
|
}
|
|
//~^^^^ single_match
|
|
}
|
|
|
|
#[derive(Eq, PartialEq)]
|
|
pub struct Data([u8; 4]);
|
|
|
|
const DATA: Data = Data([1, 2, 3, 4]);
|
|
const CONST_I32: i32 = 1;
|
|
|
|
fn irrefutable_match() {
|
|
match DATA {
|
|
DATA => println!(),
|
|
_ => {},
|
|
}
|
|
//~^^^^ single_match
|
|
|
|
match CONST_I32 {
|
|
CONST_I32 => println!(),
|
|
_ => {},
|
|
}
|
|
//~^^^^ single_match
|
|
|
|
let i = 0;
|
|
match i {
|
|
i => {
|
|
let a = 1;
|
|
let b = 2;
|
|
},
|
|
_ => {},
|
|
}
|
|
//~^^^^^^^ single_match
|
|
|
|
match i {
|
|
i => {},
|
|
_ => {},
|
|
}
|
|
//~^^^^ single_match
|
|
|
|
match i {
|
|
i => (),
|
|
_ => (),
|
|
}
|
|
//~^^^^ single_match
|
|
|
|
match CONST_I32 {
|
|
CONST_I32 => println!(),
|
|
_ => {},
|
|
}
|
|
//~^^^^ single_match
|
|
|
|
let mut x = vec![1i8];
|
|
|
|
match x.pop() {
|
|
// bla
|
|
Some(u) => println!("{u}"),
|
|
// more comments!
|
|
None => {},
|
|
}
|
|
//~^^^^^^ single_match
|
|
//~| NOTE: you might want to preserve the comments from inside the `match`
|
|
|
|
match x.pop() {
|
|
// bla
|
|
Some(u) => {
|
|
// bla
|
|
println!("{u}");
|
|
},
|
|
// bla
|
|
None => {},
|
|
}
|
|
//~^^^^^^^^^ single_match
|
|
//~| NOTE: you might want to preserve the comments from inside the `match`
|
|
}
|
|
|
|
fn issue_14493() {
|
|
macro_rules! mac {
|
|
(some) => {
|
|
Some(42)
|
|
};
|
|
(any) => {
|
|
_
|
|
};
|
|
(str) => {
|
|
"foo"
|
|
};
|
|
}
|
|
|
|
match mac!(some) {
|
|
Some(u) => println!("{u}"),
|
|
_ => (),
|
|
}
|
|
//~^^^^ single_match
|
|
|
|
// When scrutinee comes from macro, do not tell that arm will always match
|
|
// and suggest an equality check instead.
|
|
match mac!(str) {
|
|
"foo" => println!("eq"),
|
|
_ => (),
|
|
}
|
|
//~^^^^ ERROR: for an equality check
|
|
|
|
// Do not lint if any match arm come from expansion
|
|
match Some(0) {
|
|
mac!(some) => println!("eq"),
|
|
mac!(any) => println!("neq"),
|
|
}
|
|
match Some(0) {
|
|
Some(42) => println!("eq"),
|
|
mac!(any) => println!("neq"),
|
|
}
|
|
match Some(0) {
|
|
mac!(some) => println!("eq"),
|
|
_ => println!("neq"),
|
|
}
|
|
}
|