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.
368 lines
7.1 KiB
Rust
368 lines
7.1 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);
|
|
|
|
if let Some(y) = x {
|
|
println!("{:?}", y);
|
|
};
|
|
//~^^^^^^ single_match
|
|
|
|
let x = Some(1u8);
|
|
if let Some(y) = x { println!("{:?}", y) }
|
|
//~^^^^^^^ single_match
|
|
//~| NOTE: you might want to preserve the comments from inside the `match`
|
|
|
|
let z = (1u8, 1u8);
|
|
if let (2..=3, 7..=9) = z { 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);
|
|
|
|
if let Some(y) = x { dummy() };
|
|
//~^^^^ single_match
|
|
|
|
if let Ok(y) = y { dummy() };
|
|
//~^^^^ single_match
|
|
|
|
let c = Cow::Borrowed("");
|
|
|
|
if let Cow::Borrowed(..) = c { dummy() };
|
|
//~^^^^ 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";
|
|
if x == "test" { println!() }
|
|
//~^^^^ single_match
|
|
|
|
#[derive(PartialEq, Eq)]
|
|
enum Foo {
|
|
A,
|
|
B,
|
|
C(u32),
|
|
}
|
|
|
|
let x = Foo::A;
|
|
if x == Foo::A { println!() }
|
|
//~^^^^ single_match
|
|
|
|
const FOO_C: Foo = Foo::C(0);
|
|
if x == FOO_C { println!() }
|
|
//~^^^^ single_match
|
|
|
|
if x == Foo::A { println!() }
|
|
//~^^^^ single_match
|
|
|
|
let x = &x;
|
|
if 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;
|
|
if let Bar::A = x { println!() }
|
|
//~^^^^ single_match
|
|
|
|
// issue #7038
|
|
struct X;
|
|
let x = Some(X);
|
|
if let None = x { 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
|
|
if let (Some(_), _) = x {}
|
|
//~^^^^ single_match
|
|
|
|
// lint
|
|
if let (Some(E::V), _) = x { todo!() }
|
|
//~^^^^ single_match
|
|
|
|
// lint
|
|
if let (.., Some(E::V), _) = (Some(42), Some(E::V), Some(42)) {}
|
|
//~^^^^ 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>) {
|
|
if let Some(v) = bar { unsafe {
|
|
let r = &v as *const i32;
|
|
println!("{}", *r);
|
|
} }
|
|
//~^^^^^^^ single_match
|
|
|
|
if let Some(v) = bar {
|
|
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)) => {},
|
|
}
|
|
|
|
if let Ok(Some(A)) = Ok::<_, u32>(Some(A)) { println!() }
|
|
//~^^^^ single_match
|
|
|
|
match &Some(A) {
|
|
Some(A | B | C) => println!(),
|
|
None => {},
|
|
}
|
|
|
|
match &Some(A) {
|
|
&Some(A | B | C) => println!(),
|
|
None => {},
|
|
}
|
|
|
|
if let Some(A | B) = &Some(A) { println!() }
|
|
//~^^^^ single_match
|
|
}
|
|
|
|
fn issue12758(s: &[u8]) {
|
|
if &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() {
|
|
println!();
|
|
//~^^^^ single_match
|
|
|
|
println!();
|
|
//~^^^^ single_match
|
|
|
|
let i = 0;
|
|
{
|
|
let a = 1;
|
|
let b = 2;
|
|
}
|
|
//~^^^^^^^ single_match
|
|
|
|
|
|
//~^^^^ single_match
|
|
|
|
|
|
//~^^^^ single_match
|
|
|
|
println!();
|
|
//~^^^^ single_match
|
|
|
|
let mut x = vec![1i8];
|
|
|
|
if let Some(u) = x.pop() { println!("{u}") }
|
|
//~^^^^^^ single_match
|
|
//~| NOTE: you might want to preserve the comments from inside the `match`
|
|
|
|
if let Some(u) = x.pop() {
|
|
// bla
|
|
println!("{u}");
|
|
}
|
|
//~^^^^^^^^^ single_match
|
|
//~| NOTE: you might want to preserve the comments from inside the `match`
|
|
}
|