@@ -3,9 +3,9 @@ use crate::utils::paths;
3
3
use crate :: utils:: sugg:: Sugg ;
4
4
use crate :: utils:: usage:: is_unused;
5
5
use crate :: utils:: {
6
- expr_block, is_allowed, is_expn_of, is_wild, match_qpath, match_type, multispan_sugg, remove_blocks, snippet ,
7
- snippet_with_applicability, span_help_and_lint, span_lint_and_sugg, span_lint_and_then, span_note_and_lint ,
8
- walk_ptrs_ty,
6
+ expr_block, in_macro , is_allowed, is_expn_of, is_wild, match_qpath, match_type, multispan_sugg, remove_blocks,
7
+ snippet , snippet_with_applicability, span_help_and_lint, span_lint_and_sugg, span_lint_and_then,
8
+ span_note_and_lint , walk_ptrs_ty,
9
9
} ;
10
10
use if_chain:: if_chain;
11
11
use rustc:: lint:: in_external_macro;
@@ -245,6 +245,33 @@ declare_clippy_lint! {
245
245
"a wildcard pattern used with others patterns in same match arm"
246
246
}
247
247
248
+ declare_clippy_lint ! {
249
+ /// **What it does:** Checks for useless match that binds to only one value.
250
+ ///
251
+ /// **Why is this bad?** Readability and needless complexity.
252
+ ///
253
+ /// **Known problems:** This situation frequently happen in macros, so can't lint there.
254
+ ///
255
+ /// **Example:**
256
+ /// ```rust
257
+ /// # let a = 1;
258
+ /// # let b = 2;
259
+ ///
260
+ /// // Bad
261
+ /// match (a, b) {
262
+ /// (c, d) => {
263
+ /// // useless match
264
+ /// }
265
+ /// }
266
+ ///
267
+ /// // Good
268
+ /// let (c, d) = (a, b);
269
+ /// ```
270
+ pub MATCH_SINGLE_BINDING ,
271
+ complexity,
272
+ "a match with a single binding instead of using `let` statement"
273
+ }
274
+
248
275
declare_lint_pass ! ( Matches => [
249
276
SINGLE_MATCH ,
250
277
MATCH_REF_PATS ,
@@ -254,7 +281,8 @@ declare_lint_pass!(Matches => [
254
281
MATCH_WILD_ERR_ARM ,
255
282
MATCH_AS_REF ,
256
283
WILDCARD_ENUM_MATCH_ARM ,
257
- WILDCARD_IN_OR_PATTERNS
284
+ WILDCARD_IN_OR_PATTERNS ,
285
+ MATCH_SINGLE_BINDING ,
258
286
] ) ;
259
287
260
288
impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for Matches {
@@ -270,6 +298,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Matches {
270
298
check_wild_enum_match ( cx, ex, arms) ;
271
299
check_match_as_ref ( cx, ex, arms, expr) ;
272
300
check_wild_in_or_pats ( cx, arms) ;
301
+ check_match_single_binding ( cx, ex, arms, expr) ;
273
302
}
274
303
if let ExprKind :: Match ( ref ex, ref arms, _) = expr. kind {
275
304
check_match_ref_pats ( cx, ex, arms, expr) ;
@@ -712,6 +741,29 @@ fn check_wild_in_or_pats(cx: &LateContext<'_, '_>, arms: &[Arm<'_>]) {
712
741
}
713
742
}
714
743
744
+ fn check_match_single_binding ( cx : & LateContext < ' _ , ' _ > , ex : & Expr < ' _ > , arms : & [ Arm < ' _ > ] , expr : & Expr < ' _ > ) {
745
+ if in_macro ( expr. span ) {
746
+ return ;
747
+ }
748
+ if arms. len ( ) == 1 {
749
+ let bind_names = arms[ 0 ] . pat . span ;
750
+ let matched_vars = ex. span ;
751
+ span_lint_and_sugg (
752
+ cx,
753
+ MATCH_SINGLE_BINDING ,
754
+ expr. span ,
755
+ "this match could be written as a `let` statement" ,
756
+ "try this" ,
757
+ format ! (
758
+ "let {} = {};" ,
759
+ snippet( cx, bind_names, ".." ) ,
760
+ snippet( cx, matched_vars, ".." )
761
+ ) ,
762
+ Applicability :: HasPlaceholders ,
763
+ ) ;
764
+ }
765
+ }
766
+
715
767
/// Gets all arms that are unbounded `PatRange`s.
716
768
fn all_ranges < ' a , ' tcx > (
717
769
cx : & LateContext < ' a , ' tcx > ,
0 commit comments