]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/infallible_destructuring_match.rs
Merge pull request #2684 from 17cupsofcoffee/infallible-destructuring-match
[rust.git] / clippy_lints / src / infallible_destructuring_match.rs
1 use super::utils::{get_arg_name, match_var, remove_blocks, snippet, span_lint_and_sugg};
2 use rustc::hir::*;
3 use rustc::lint::*;
4
5 /// **What it does:** Checks for matches being used to destructure a single-variant enum
6 /// or tuple struct where a `let` will suffice.
7 ///
8 /// **Why is this bad?** Just readability – `let` doesn't nest, whereas a `match` does.
9 ///
10 /// **Known problems:** None.
11 ///
12 /// **Example:**
13 /// ```rust
14 /// enum Wrapper {
15 ///     Data(i32),
16 /// }
17 ///
18 /// let wrapper = Wrapper::Data(42);
19 ///
20 /// let data = match wrapper {
21 ///     Wrapper::Data(i) => i,
22 /// };
23 /// ```
24 ///
25 /// The correct use would be:
26 /// ```rust
27 /// enum Wrapper {
28 ///     Data(i32),
29 /// }
30 ///
31 /// let wrapper = Wrapper::Data(42);
32 /// let Wrapper::Data(data) = wrapper;
33 /// ```
34 declare_clippy_lint! {
35     pub INFALLIBLE_DESTRUCTURING_MATCH,
36     style,
37     "a match statement with a single infallible arm instead of a `let`"
38 }
39
40 #[derive(Copy, Clone, Default)]
41 pub struct Pass;
42
43 impl LintPass for Pass {
44     fn get_lints(&self) -> LintArray {
45         lint_array!(INFALLIBLE_DESTRUCTURING_MATCH)
46     }
47 }
48
49 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
50     fn check_local(&mut self, cx: &LateContext<'a, 'tcx>, local: &'tcx Local) {
51         if_chain! {
52             if let Some(ref expr) = local.init;
53             if let Expr_::ExprMatch(ref target, ref arms, MatchSource::Normal) = expr.node;
54             if arms.len() == 1 && arms[0].pats.len() == 1 && arms[0].guard.is_none();
55             if let PatKind::TupleStruct(QPath::Resolved(None, ref variant_name), ref args, _) = arms[0].pats[0].node;
56             if args.len() == 1;
57             if let Some(arg) = get_arg_name(&args[0]);
58             let body = remove_blocks(&arms[0].body);
59             if match_var(body, arg);
60
61             then {
62                 span_lint_and_sugg(
63                     cx,
64                     INFALLIBLE_DESTRUCTURING_MATCH,
65                     local.span,
66                     "you seem to be trying to use match to destructure a single infallible pattern. \
67                      Consider using `let`",
68                     "try this",
69                     format!(
70                         "let {}({}) = {};",
71                         snippet(cx, variant_name.span, ".."),
72                         snippet(cx, local.pat.span, ".."),
73                         snippet(cx, target.span, ".."),
74                     ),
75                 );
76             }
77         }
78     }
79 }