Commit efe3fe9b8c removed the ability for
`single_match` and `single_match_else` to trigger if comments were
present outside of the arms, as those comments would be lost while
rewriting the `match` expression.
This reinstates the lint, but prevents the suggestion from being applied
automatically in the presence of comments by using the `MaybeIncorrect`
applicability. Also, a note is added to the lint message to warn the
user about the need to preserve the comments if acting upon the
suggestion.
463 lines
8.5 KiB
Rust
463 lines
8.5 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`
|
|
}
|