diff --git a/CHANGELOG.md b/CHANGELOG.md
index eb3b518cd8f4..49de9df64694 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1217,6 +1217,7 @@ Released 2018-09-13
[`match_overlapping_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_overlapping_arm
[`match_ref_pats`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_ref_pats
[`match_same_arms`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_same_arms
+[`match_single_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_single_binding
[`match_wild_err_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wild_err_arm
[`maybe_infinite_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#maybe_infinite_iter
[`mem_discriminant_non_enum`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_discriminant_non_enum
diff --git a/README.md b/README.md
index b68eb3ed7fab..da02591f690d 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@
A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code.
-[There are 351 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
+[There are 352 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you:
diff --git a/clippy_lints/src/infallible_destructuring_match.rs b/clippy_lints/src/infallible_destructuring_match.rs
deleted file mode 100644
index 1d23dd115bc4..000000000000
--- a/clippy_lints/src/infallible_destructuring_match.rs
+++ /dev/null
@@ -1,77 +0,0 @@
-use super::utils::{get_arg_name, match_var, remove_blocks, snippet_with_applicability, span_lint_and_sugg};
-use if_chain::if_chain;
-use rustc_errors::Applicability;
-use rustc_hir::*;
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-
-declare_clippy_lint! {
- /// **What it does:** Checks for matches being used to destructure a single-variant enum
- /// or tuple struct where a `let` will suffice.
- ///
- /// **Why is this bad?** Just readability – `let` doesn't nest, whereas a `match` does.
- ///
- /// **Known problems:** None.
- ///
- /// **Example:**
- /// ```rust
- /// enum Wrapper {
- /// Data(i32),
- /// }
- ///
- /// let wrapper = Wrapper::Data(42);
- ///
- /// let data = match wrapper {
- /// Wrapper::Data(i) => i,
- /// };
- /// ```
- ///
- /// The correct use would be:
- /// ```rust
- /// enum Wrapper {
- /// Data(i32),
- /// }
- ///
- /// let wrapper = Wrapper::Data(42);
- /// let Wrapper::Data(data) = wrapper;
- /// ```
- pub INFALLIBLE_DESTRUCTURING_MATCH,
- style,
- "a `match` statement with a single infallible arm instead of a `let`"
-}
-
-declare_lint_pass!(InfallibleDestructingMatch => [INFALLIBLE_DESTRUCTURING_MATCH]);
-
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InfallibleDestructingMatch {
- fn check_local(&mut self, cx: &LateContext<'a, 'tcx>, local: &'tcx Local<'_>) {
- if_chain! {
- if let Some(ref expr) = local.init;
- if let ExprKind::Match(ref target, ref arms, MatchSource::Normal) = expr.kind;
- if arms.len() == 1 && arms[0].guard.is_none();
- if let PatKind::TupleStruct(QPath::Resolved(None, ref variant_name), ref args, _) = arms[0].pat.kind;
- if args.len() == 1;
- if let Some(arg) = get_arg_name(&args[0]);
- let body = remove_blocks(&arms[0].body);
- if match_var(body, arg);
-
- then {
- let mut applicability = Applicability::MachineApplicable;
- 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,
- );
- }
- }
- }
-}
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index fcf01ae48a11..45342cc7e007 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -218,7 +218,6 @@ pub mod if_let_some_result;
pub mod if_not_else;
pub mod implicit_return;
pub mod indexing_slicing;
-pub mod infallible_destructuring_match;
pub mod infinite_iter;
pub mod inherent_impl;
pub mod inherent_to_string;
@@ -555,7 +554,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
&implicit_return::IMPLICIT_RETURN,
&indexing_slicing::INDEXING_SLICING,
&indexing_slicing::OUT_OF_BOUNDS_INDEXING,
- &infallible_destructuring_match::INFALLIBLE_DESTRUCTURING_MATCH,
&infinite_iter::INFINITE_ITER,
&infinite_iter::MAYBE_INFINITE_ITER,
&inherent_impl::MULTIPLE_INHERENT_IMPL,
@@ -600,10 +598,12 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
&map_clone::MAP_CLONE,
&map_unit_fn::OPTION_MAP_UNIT_FN,
&map_unit_fn::RESULT_MAP_UNIT_FN,
+ &matches::INFALLIBLE_DESTRUCTURING_MATCH,
&matches::MATCH_AS_REF,
&matches::MATCH_BOOL,
&matches::MATCH_OVERLAPPING_ARM,
&matches::MATCH_REF_PATS,
+ &matches::MATCH_SINGLE_BINDING,
&matches::MATCH_WILD_ERR_ARM,
&matches::SINGLE_MATCH,
&matches::SINGLE_MATCH_ELSE,
@@ -864,7 +864,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|| box types::Casts);
let type_complexity_threshold = conf.type_complexity_threshold;
store.register_late_pass(move || box types::TypeComplexity::new(type_complexity_threshold));
- store.register_late_pass(|| box matches::Matches);
+ store.register_late_pass(|| box matches::Matches::default());
store.register_late_pass(|| box minmax::MinMaxPass);
store.register_late_pass(|| box open_options::OpenOptions);
store.register_late_pass(|| box zero_div_zero::ZeroDiv);
@@ -941,7 +941,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|| box question_mark::QuestionMark);
store.register_late_pass(|| box suspicious_trait_impl::SuspiciousImpl);
store.register_late_pass(|| box map_unit_fn::MapUnit);
- store.register_late_pass(|| box infallible_destructuring_match::InfallibleDestructingMatch);
store.register_late_pass(|| box inherent_impl::MultipleInherentImpl::default());
store.register_late_pass(|| box neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd);
store.register_late_pass(|| box unwrap::Unwrap);
@@ -1166,7 +1165,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&identity_op::IDENTITY_OP),
LintId::of(&if_let_some_result::IF_LET_SOME_RESULT),
LintId::of(&indexing_slicing::OUT_OF_BOUNDS_INDEXING),
- LintId::of(&infallible_destructuring_match::INFALLIBLE_DESTRUCTURING_MATCH),
LintId::of(&infinite_iter::INFINITE_ITER),
LintId::of(&inherent_to_string::INHERENT_TO_STRING),
LintId::of(&inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY),
@@ -1201,10 +1199,12 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&map_clone::MAP_CLONE),
LintId::of(&map_unit_fn::OPTION_MAP_UNIT_FN),
LintId::of(&map_unit_fn::RESULT_MAP_UNIT_FN),
+ LintId::of(&matches::INFALLIBLE_DESTRUCTURING_MATCH),
LintId::of(&matches::MATCH_AS_REF),
LintId::of(&matches::MATCH_BOOL),
LintId::of(&matches::MATCH_OVERLAPPING_ARM),
LintId::of(&matches::MATCH_REF_PATS),
+ LintId::of(&matches::MATCH_SINGLE_BINDING),
LintId::of(&matches::MATCH_WILD_ERR_ARM),
LintId::of(&matches::SINGLE_MATCH),
LintId::of(&matches::WILDCARD_IN_OR_PATTERNS),
@@ -1382,7 +1382,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&functions::DOUBLE_MUST_USE),
LintId::of(&functions::MUST_USE_UNIT),
LintId::of(&if_let_some_result::IF_LET_SOME_RESULT),
- LintId::of(&infallible_destructuring_match::INFALLIBLE_DESTRUCTURING_MATCH),
LintId::of(&inherent_to_string::INHERENT_TO_STRING),
LintId::of(&len_zero::LEN_WITHOUT_IS_EMPTY),
LintId::of(&len_zero::LEN_ZERO),
@@ -1395,6 +1394,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&loops::WHILE_LET_ON_ITERATOR),
LintId::of(&main_recursion::MAIN_RECURSION),
LintId::of(&map_clone::MAP_CLONE),
+ LintId::of(&matches::INFALLIBLE_DESTRUCTURING_MATCH),
LintId::of(&matches::MATCH_BOOL),
LintId::of(&matches::MATCH_OVERLAPPING_ARM),
LintId::of(&matches::MATCH_REF_PATS),
@@ -1483,6 +1483,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&map_unit_fn::OPTION_MAP_UNIT_FN),
LintId::of(&map_unit_fn::RESULT_MAP_UNIT_FN),
LintId::of(&matches::MATCH_AS_REF),
+ LintId::of(&matches::MATCH_SINGLE_BINDING),
LintId::of(&matches::WILDCARD_IN_OR_PATTERNS),
LintId::of(&methods::CHARS_NEXT_CMP),
LintId::of(&methods::CLONE_ON_COPY),
diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs
index 0fc7799c97a1..1d8c5ec9038d 100644
--- a/clippy_lints/src/matches.rs
+++ b/clippy_lints/src/matches.rs
@@ -3,9 +3,9 @@ use crate::utils::paths;
use crate::utils::sugg::Sugg;
use crate::utils::usage::is_unused;
use crate::utils::{
- expr_block, is_allowed, is_expn_of, is_wild, match_qpath, match_type, multispan_sugg, remove_blocks, snippet,
- snippet_with_applicability, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then,
- walk_ptrs_ty,
+ expr_block, get_arg_name, in_macro, is_allowed, is_expn_of, is_refutable, is_wild, match_qpath, match_type,
+ match_var, multispan_sugg, remove_blocks, snippet, snippet_block, snippet_with_applicability, span_lint_and_help,
+ span_lint_and_note, span_lint_and_sugg, span_lint_and_then, walk_ptrs_ty,
};
use if_chain::if_chain;
use rustc::lint::in_external_macro;
@@ -14,7 +14,7 @@ use rustc_errors::Applicability;
use rustc_hir::def::CtorKind;
use rustc_hir::*;
use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Span;
use std::cmp::Ordering;
use std::collections::Bound;
@@ -245,7 +245,75 @@ declare_clippy_lint! {
"a wildcard pattern used with others patterns in same match arm"
}
-declare_lint_pass!(Matches => [
+declare_clippy_lint! {
+ /// **What it does:** Checks for matches being used to destructure a single-variant enum
+ /// or tuple struct where a `let` will suffice.
+ ///
+ /// **Why is this bad?** Just readability – `let` doesn't nest, whereas a `match` does.
+ ///
+ /// **Known problems:** None.
+ ///
+ /// **Example:**
+ /// ```rust
+ /// enum Wrapper {
+ /// Data(i32),
+ /// }
+ ///
+ /// let wrapper = Wrapper::Data(42);
+ ///
+ /// let data = match wrapper {
+ /// Wrapper::Data(i) => i,
+ /// };
+ /// ```
+ ///
+ /// The correct use would be:
+ /// ```rust
+ /// enum Wrapper {
+ /// Data(i32),
+ /// }
+ ///
+ /// let wrapper = Wrapper::Data(42);
+ /// let Wrapper::Data(data) = wrapper;
+ /// ```
+ pub INFALLIBLE_DESTRUCTURING_MATCH,
+ style,
+ "a `match` statement with a single infallible arm instead of a `let`"
+}
+
+declare_clippy_lint! {
+ /// **What it does:** Checks for useless match that binds to only one value.
+ ///
+ /// **Why is this bad?** Readability and needless complexity.
+ ///
+ /// **Known problems:** Suggested replacements may be incorrect when `match`
+ /// is actually binding temporary value, bringing a 'dropped while borrowed' error.
+ ///
+ /// **Example:**
+ /// ```rust
+ /// # let a = 1;
+ /// # let b = 2;
+ ///
+ /// // Bad
+ /// match (a, b) {
+ /// (c, d) => {
+ /// // useless match
+ /// }
+ /// }
+ ///
+ /// // Good
+ /// let (c, d) = (a, b);
+ /// ```
+ pub MATCH_SINGLE_BINDING,
+ complexity,
+ "a match with a single binding instead of using `let` statement"
+}
+
+#[derive(Default)]
+pub struct Matches {
+ infallible_destructuring_match_linted: bool,
+}
+
+impl_lint_pass!(Matches => [
SINGLE_MATCH,
MATCH_REF_PATS,
MATCH_BOOL,
@@ -254,7 +322,9 @@ declare_lint_pass!(Matches => [
MATCH_WILD_ERR_ARM,
MATCH_AS_REF,
WILDCARD_ENUM_MATCH_ARM,
- WILDCARD_IN_OR_PATTERNS
+ WILDCARD_IN_OR_PATTERNS,
+ MATCH_SINGLE_BINDING,
+ INFALLIBLE_DESTRUCTURING_MATCH
]);
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Matches {
@@ -270,11 +340,51 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Matches {
check_wild_enum_match(cx, ex, arms);
check_match_as_ref(cx, ex, arms, expr);
check_wild_in_or_pats(cx, arms);
+
+ if self.infallible_destructuring_match_linted {
+ self.infallible_destructuring_match_linted = false;
+ } else {
+ check_match_single_binding(cx, ex, arms, expr);
+ }
}
if let ExprKind::Match(ref ex, ref arms, _) = expr.kind {
check_match_ref_pats(cx, ex, arms, expr);
}
}
+
+ fn check_local(&mut self, cx: &LateContext<'a, 'tcx>, local: &'tcx Local<'_>) {
+ if_chain! {
+ if let Some(ref expr) = local.init;
+ if let ExprKind::Match(ref target, ref arms, MatchSource::Normal) = expr.kind;
+ if arms.len() == 1 && arms[0].guard.is_none();
+ if let PatKind::TupleStruct(
+ QPath::Resolved(None, ref variant_name), ref args, _) = arms[0].pat.kind;
+ if args.len() == 1;
+ if let Some(arg) = get_arg_name(&args[0]);
+ let body = remove_blocks(&arms[0].body);
+ if match_var(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,
+ );
+ }
+ }
+ }
}
#[rustfmt::skip]
@@ -712,6 +822,68 @@ fn check_wild_in_or_pats(cx: &LateContext<'_, '_>, arms: &[Arm<'_>]) {
}
}
+fn check_match_single_binding(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
+ if in_macro(expr.span) || arms.len() != 1 || is_refutable(cx, arms[0].pat) {
+ return;
+ }
+ let matched_vars = ex.span;
+ let bind_names = arms[0].pat.span;
+ let match_body = remove_blocks(&arms[0].body);
+ let mut snippet_body = if match_body.span.from_expansion() {
+ Sugg::hir_with_macro_callsite(cx, match_body, "..").to_string()
+ } else {
+ snippet_block(cx, match_body.span, "..").to_owned().to_string()
+ };
+
+ // Do we need to add ';' to suggestion ?
+ match match_body.kind {
+ ExprKind::Block(block, _) => {
+ // macro + expr_ty(body) == ()
+ if block.span.from_expansion() && cx.tables.expr_ty(&match_body).is_unit() {
+ snippet_body.push(';');
+ }
+ },
+ _ => {
+ // expr_ty(body) == ()
+ if cx.tables.expr_ty(&match_body).is_unit() {
+ snippet_body.push(';');
+ }
+ },
+ }
+
+ let mut applicability = Applicability::MaybeIncorrect;
+ match arms[0].pat.kind {
+ PatKind::Binding(..) | PatKind::Tuple(_, _) | PatKind::Struct(..) => {
+ span_lint_and_sugg(
+ cx,
+ MATCH_SINGLE_BINDING,
+ expr.span,
+ "this match could be written as a `let` statement",
+ "consider using `let` statement",
+ format!(
+ "let {} = {};\n{}",
+ snippet_with_applicability(cx, bind_names, "..", &mut applicability),
+ snippet_with_applicability(cx, matched_vars, "..", &mut applicability),
+ snippet_body
+ ),
+ applicability,
+ );
+ },
+ PatKind::Wild => {
+ span_lint_and_sugg(
+ cx,
+ MATCH_SINGLE_BINDING,
+ expr.span,
+ "this match could be replaced by its body itself",
+ "consider using the match body instead",
+ snippet_body,
+ Applicability::MachineApplicable,
+ );
+ },
+ _ => (),
+ }
+}
+
/// Gets all arms that are unbounded `PatRange`s.
fn all_ranges<'a, 'tcx>(
cx: &LateContext<'a, 'tcx>,
diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs
index eaada9961b0c..7d2aedd667d7 100644
--- a/src/lintlist/mod.rs
+++ b/src/lintlist/mod.rs
@@ -6,7 +6,7 @@ pub use lint::Lint;
pub use lint::LINT_LEVELS;
// begin lint list, do not remove this comment, it’s used in `update_lints`
-pub const ALL_LINTS: [Lint; 351] = [
+pub const ALL_LINTS: [Lint; 352] = [
Lint {
name: "absurd_extreme_comparisons",
group: "correctness",
@@ -775,7 +775,7 @@ pub const ALL_LINTS: [Lint; 351] = [
group: "style",
desc: "a `match` statement with a single infallible arm instead of a `let`",
deprecation: None,
- module: "infallible_destructuring_match",
+ module: "matches",
},
Lint {
name: "infinite_iter",
@@ -1092,6 +1092,13 @@ pub const ALL_LINTS: [Lint; 351] = [
deprecation: None,
module: "copies",
},
+ Lint {
+ name: "match_single_binding",
+ group: "complexity",
+ desc: "a match with a single binding instead of using `let` statement",
+ deprecation: None,
+ module: "matches",
+ },
Lint {
name: "match_wild_err_arm",
group: "style",
diff --git a/tests/ui/escape_analysis.rs b/tests/ui/escape_analysis.rs
index d435484d3e3d..c0a52d832c00 100644
--- a/tests/ui/escape_analysis.rs
+++ b/tests/ui/escape_analysis.rs
@@ -3,7 +3,8 @@
clippy::borrowed_box,
clippy::needless_pass_by_value,
clippy::unused_unit,
- clippy::redundant_clone
+ clippy::redundant_clone,
+ clippy::match_single_binding
)]
#![warn(clippy::boxed_local)]
diff --git a/tests/ui/escape_analysis.stderr b/tests/ui/escape_analysis.stderr
index 19342fe1be74..c86a769a3da4 100644
--- a/tests/ui/escape_analysis.stderr
+++ b/tests/ui/escape_analysis.stderr
@@ -1,5 +1,5 @@
error: local variable doesn't need to be boxed here
- --> $DIR/escape_analysis.rs:39:13
+ --> $DIR/escape_analysis.rs:40:13
|
LL | fn warn_arg(x: Box) {
| ^
@@ -7,7 +7,7 @@ LL | fn warn_arg(x: Box) {
= note: `-D clippy::boxed-local` implied by `-D warnings`
error: local variable doesn't need to be boxed here
- --> $DIR/escape_analysis.rs:130:12
+ --> $DIR/escape_analysis.rs:131:12
|
LL | pub fn new(_needs_name: Box>) -> () {}
| ^^^^^^^^^^^
diff --git a/tests/ui/match_ref_pats.rs b/tests/ui/match_ref_pats.rs
index d26b59db91bc..5de43733ad33 100644
--- a/tests/ui/match_ref_pats.rs
+++ b/tests/ui/match_ref_pats.rs
@@ -26,6 +26,7 @@ fn ref_pats() {
}
// False positive: only wildcard pattern.
let w = Some(0);
+ #[allow(clippy::match_single_binding)]
match w {
_ => println!("none"),
}
diff --git a/tests/ui/match_ref_pats.stderr b/tests/ui/match_ref_pats.stderr
index 492f4b9ba206..52cb4a14b72b 100644
--- a/tests/ui/match_ref_pats.stderr
+++ b/tests/ui/match_ref_pats.stderr
@@ -47,7 +47,7 @@ LL | None => println!("none"),
|
error: you don't need to add `&` to all patterns
- --> $DIR/match_ref_pats.rs:34:5
+ --> $DIR/match_ref_pats.rs:35:5
|
LL | / if let &None = a {
LL | | println!("none");
@@ -60,7 +60,7 @@ LL | if let None = *a {
| ^^^^ ^^
error: you don't need to add `&` to both the expression and the patterns
- --> $DIR/match_ref_pats.rs:39:5
+ --> $DIR/match_ref_pats.rs:40:5
|
LL | / if let &None = &b {
LL | | println!("none");
@@ -73,7 +73,7 @@ LL | if let None = b {
| ^^^^ ^
error: you don't need to add `&` to all patterns
- --> $DIR/match_ref_pats.rs:66:9
+ --> $DIR/match_ref_pats.rs:67:9
|
LL | / match foo_variant!(0) {
LL | | &Foo::A => println!("A"),
diff --git a/tests/ui/match_single_binding.fixed b/tests/ui/match_single_binding.fixed
new file mode 100644
index 000000000000..8fb8dc323e43
--- /dev/null
+++ b/tests/ui/match_single_binding.fixed
@@ -0,0 +1,63 @@
+// run-rustfix
+
+#![warn(clippy::match_single_binding)]
+#![allow(clippy::many_single_char_names, clippy::toplevel_ref_arg)]
+
+struct Point {
+ x: i32,
+ y: i32,
+}
+
+fn main() {
+ let a = 1;
+ let b = 2;
+ let c = 3;
+ // Lint
+ let (x, y, z) = (a, b, c);
+{
+ println!("{} {} {}", x, y, z);
+}
+ // Lint
+ let (x, y, z) = (a, b, c);
+println!("{} {} {}", x, y, z);
+ // Ok
+ match a {
+ 2 => println!("2"),
+ _ => println!("Not 2"),
+ }
+ // Ok
+ let d = Some(5);
+ match d {
+ Some(d) => println!("{}", d),
+ _ => println!("None"),
+ }
+ // Lint
+ println!("whatever");
+ // Lint
+ {
+ let x = 29;
+ println!("x has a value of {}", x);
+}
+ // Lint
+ {
+ let e = 5 * a;
+ if e >= 5 {
+ println!("e is superior to 5");
+ }
+}
+ // Lint
+ let p = Point { x: 0, y: 7 };
+ let Point { x, y } = p;
+println!("Coords: ({}, {})", x, y);
+ // Lint
+ let Point { x: x1, y: y1 } = p;
+println!("Coords: ({}, {})", x1, y1);
+ // Lint
+ let x = 5;
+ let ref r = x;
+println!("Got a reference to {}", r);
+ // Lint
+ let mut x = 5;
+ let ref mut mr = x;
+println!("Got a mutable reference to {}", mr);
+}
diff --git a/tests/ui/match_single_binding.rs b/tests/ui/match_single_binding.rs
new file mode 100644
index 000000000000..55b0b09a0088
--- /dev/null
+++ b/tests/ui/match_single_binding.rs
@@ -0,0 +1,75 @@
+// run-rustfix
+
+#![warn(clippy::match_single_binding)]
+#![allow(clippy::many_single_char_names, clippy::toplevel_ref_arg)]
+
+struct Point {
+ x: i32,
+ y: i32,
+}
+
+fn main() {
+ let a = 1;
+ let b = 2;
+ let c = 3;
+ // Lint
+ match (a, b, c) {
+ (x, y, z) => {
+ println!("{} {} {}", x, y, z);
+ },
+ }
+ // Lint
+ match (a, b, c) {
+ (x, y, z) => println!("{} {} {}", x, y, z),
+ }
+ // Ok
+ match a {
+ 2 => println!("2"),
+ _ => println!("Not 2"),
+ }
+ // Ok
+ let d = Some(5);
+ match d {
+ Some(d) => println!("{}", d),
+ _ => println!("None"),
+ }
+ // Lint
+ match a {
+ _ => println!("whatever"),
+ }
+ // Lint
+ match a {
+ _ => {
+ let x = 29;
+ println!("x has a value of {}", x);
+ },
+ }
+ // Lint
+ match a {
+ _ => {
+ let e = 5 * a;
+ if e >= 5 {
+ println!("e is superior to 5");
+ }
+ },
+ }
+ // Lint
+ let p = Point { x: 0, y: 7 };
+ match p {
+ Point { x, y } => println!("Coords: ({}, {})", x, y),
+ }
+ // Lint
+ match p {
+ Point { x: x1, y: y1 } => println!("Coords: ({}, {})", x1, y1),
+ }
+ // Lint
+ let x = 5;
+ match x {
+ ref r => println!("Got a reference to {}", r),
+ }
+ // Lint
+ let mut x = 5;
+ match x {
+ ref mut mr => println!("Got a mutable reference to {}", mr),
+ }
+}
diff --git a/tests/ui/match_single_binding.stderr b/tests/ui/match_single_binding.stderr
new file mode 100644
index 000000000000..d76e229adff0
--- /dev/null
+++ b/tests/ui/match_single_binding.stderr
@@ -0,0 +1,140 @@
+error: this match could be written as a `let` statement
+ --> $DIR/match_single_binding.rs:16:5
+ |
+LL | / match (a, b, c) {
+LL | | (x, y, z) => {
+LL | | println!("{} {} {}", x, y, z);
+LL | | },
+LL | | }
+ | |_____^
+ |
+ = note: `-D clippy::match-single-binding` implied by `-D warnings`
+help: consider using `let` statement
+ |
+LL | let (x, y, z) = (a, b, c);
+LL | {
+LL | println!("{} {} {}", x, y, z);
+LL | }
+ |
+
+error: this match could be written as a `let` statement
+ --> $DIR/match_single_binding.rs:22:5
+ |
+LL | / match (a, b, c) {
+LL | | (x, y, z) => println!("{} {} {}", x, y, z),
+LL | | }
+ | |_____^
+ |
+help: consider using `let` statement
+ |
+LL | let (x, y, z) = (a, b, c);
+LL | println!("{} {} {}", x, y, z);
+ |
+
+error: this match could be replaced by its body itself
+ --> $DIR/match_single_binding.rs:37:5
+ |
+LL | / match a {
+LL | | _ => println!("whatever"),
+LL | | }
+ | |_____^ help: consider using the match body instead: `println!("whatever");`
+
+error: this match could be replaced by its body itself
+ --> $DIR/match_single_binding.rs:41:5
+ |
+LL | / match a {
+LL | | _ => {
+LL | | let x = 29;
+LL | | println!("x has a value of {}", x);
+LL | | },
+LL | | }
+ | |_____^
+ |
+help: consider using the match body instead
+ |
+LL | {
+LL | let x = 29;
+LL | println!("x has a value of {}", x);
+LL | }
+ |
+
+error: this match could be replaced by its body itself
+ --> $DIR/match_single_binding.rs:48:5
+ |
+LL | / match a {
+LL | | _ => {
+LL | | let e = 5 * a;
+LL | | if e >= 5 {
+... |
+LL | | },
+LL | | }
+ | |_____^
+ |
+help: consider using the match body instead
+ |
+LL | {
+LL | let e = 5 * a;
+LL | if e >= 5 {
+LL | println!("e is superior to 5");
+LL | }
+LL | }
+ |
+
+error: this match could be written as a `let` statement
+ --> $DIR/match_single_binding.rs:58:5
+ |
+LL | / match p {
+LL | | Point { x, y } => println!("Coords: ({}, {})", x, y),
+LL | | }
+ | |_____^
+ |
+help: consider using `let` statement
+ |
+LL | let Point { x, y } = p;
+LL | println!("Coords: ({}, {})", x, y);
+ |
+
+error: this match could be written as a `let` statement
+ --> $DIR/match_single_binding.rs:62:5
+ |
+LL | / match p {
+LL | | Point { x: x1, y: y1 } => println!("Coords: ({}, {})", x1, y1),
+LL | | }
+ | |_____^
+ |
+help: consider using `let` statement
+ |
+LL | let Point { x: x1, y: y1 } = p;
+LL | println!("Coords: ({}, {})", x1, y1);
+ |
+
+error: this match could be written as a `let` statement
+ --> $DIR/match_single_binding.rs:67:5
+ |
+LL | / match x {
+LL | | ref r => println!("Got a reference to {}", r),
+LL | | }
+ | |_____^
+ |
+help: consider using `let` statement
+ |
+LL | let ref r = x;
+LL | println!("Got a reference to {}", r);
+ |
+
+error: this match could be written as a `let` statement
+ --> $DIR/match_single_binding.rs:72:5
+ |
+LL | / match x {
+LL | | ref mut mr => println!("Got a mutable reference to {}", mr),
+LL | | }
+ | |_____^
+ |
+help: consider using `let` statement
+ |
+LL | let ref mut mr = x;
+LL | println!("Got a mutable reference to {}", mr);
+ |
+
+error: aborting due to 9 previous errors
+
diff --git a/tests/ui/println_empty_string.fixed b/tests/ui/println_empty_string.fixed
index 4e84511d7b0a..2b889b62ea99 100644
--- a/tests/ui/println_empty_string.fixed
+++ b/tests/ui/println_empty_string.fixed
@@ -1,4 +1,5 @@
// run-rustfix
+#![allow(clippy::match_single_binding)]
fn main() {
println!();
diff --git a/tests/ui/println_empty_string.rs b/tests/ui/println_empty_string.rs
index 9fdfb03a3669..890f5f684760 100644
--- a/tests/ui/println_empty_string.rs
+++ b/tests/ui/println_empty_string.rs
@@ -1,4 +1,5 @@
// run-rustfix
+#![allow(clippy::match_single_binding)]
fn main() {
println!();
diff --git a/tests/ui/println_empty_string.stderr b/tests/ui/println_empty_string.stderr
index 689624a0fa0f..23112b881689 100644
--- a/tests/ui/println_empty_string.stderr
+++ b/tests/ui/println_empty_string.stderr
@@ -1,5 +1,5 @@
error: using `println!("")`
- --> $DIR/println_empty_string.rs:5:5
+ --> $DIR/println_empty_string.rs:6:5
|
LL | println!("");
| ^^^^^^^^^^^^ help: replace it with: `println!()`
@@ -7,7 +7,7 @@ LL | println!("");
= note: `-D clippy::println-empty-string` implied by `-D warnings`
error: using `println!("")`
- --> $DIR/println_empty_string.rs:8:14
+ --> $DIR/println_empty_string.rs:9:14
|
LL | _ => println!(""),
| ^^^^^^^^^^^^ help: replace it with: `println!()`