]> git.lizzy.rs Git - rust.git/blobdiff - clippy_lints/src/matches.rs
Auto merge of #3985 - phansch:move_some_cast_tests, r=flip1995
[rust.git] / clippy_lints / src / matches.rs
index 583cdee843f70a2c09a5f625770a19f73fc673cf..bcd3119b7bc58b86beae72ab7f8c336b599f33ae 100644 (file)
-// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-
-use crate::rustc::hir::*;
-use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, in_external_macro, LintContext};
-use crate::rustc::{declare_tool_lint, lint_array};
+use crate::consts::{constant, Constant};
+use crate::utils::paths;
+use crate::utils::sugg::Sugg;
+use crate::utils::{
+    expr_block, in_macro, is_allowed, is_expn_of, match_qpath, match_type, multispan_sugg, remove_blocks, snippet,
+    snippet_with_applicability, span_lint_and_sugg, span_lint_and_then, span_note_and_lint, walk_ptrs_ty,
+};
 use if_chain::if_chain;
-use crate::rustc::ty::{self, Ty};
+use rustc::hir::def::CtorKind;
+use rustc::hir::*;
+use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
+use rustc::ty::{self, Ty};
+use rustc::{declare_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
 use std::cmp::Ordering;
 use std::collections::Bound;
-use crate::syntax::ast::LitKind;
-use crate::syntax::source_map::Span;
-use crate::utils::paths;
-use crate::utils::{expr_block, in_macro, is_allowed, is_expn_of, match_qpath, match_type,
-    multispan_sugg, remove_blocks, snippet, snippet_with_applicability, span_lint_and_sugg, span_lint_and_then,
-    span_note_and_lint, walk_ptrs_ty};
-use crate::utils::sugg::Sugg;
-use crate::consts::{constant, Constant};
-use crate::rustc_errors::Applicability;
-
-/// **What it does:** Checks for matches with a single arm where an `if let`
-/// will usually suffice.
-///
-/// **Why is this bad?** Just readability – `if let` nests less than a `match`.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// match x {
-///     Some(ref foo) => bar(foo),
-///     _ => ()
-/// }
-/// ```
+use std::ops::Deref;
+use syntax::ast::LitKind;
+use syntax::source_map::Span;
+
 declare_clippy_lint! {
+    /// **What it does:** Checks for matches with a single arm where an `if let`
+    /// will usually suffice.
+    ///
+    /// **Why is this bad?** Just readability – `if let` nests less than a `match`.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// # fn bar(stool: &str) {}
+    /// # let x = Some("abc");
+    /// match x {
+    ///     Some(ref foo) => bar(foo),
+    ///     _ => (),
+    /// }
+    /// ```
     pub SINGLE_MATCH,
     style,
-    "a match statement with a single nontrivial arm (i.e. where the other arm \
-     is `_ => {}`) instead of `if let`"
+    "a match statement with a single nontrivial arm (i.e., where the other arm is `_ => {}`) instead of `if let`"
 }
 
-/// **What it does:** Checks for matches with a two arms where an `if let` will
-/// usually suffice.
-///
-/// **Why is this bad?** Just readability – `if let` nests less than a `match`.
-///
-/// **Known problems:** Personal style preferences may differ.
-///
-/// **Example:**
-/// ```rust
-/// match x {
-///     Some(ref foo) => bar(foo),
-///     _ => bar(other_ref),
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for matches with a two arms where an `if let else` will
+    /// usually suffice.
+    ///
+    /// **Why is this bad?** Just readability – `if let` nests less than a `match`.
+    ///
+    /// **Known problems:** Personal style preferences may differ.
+    ///
+    /// **Example:**
+    ///
+    /// Using `match`:
+    ///
+    /// ```rust
+    /// match x {
+    ///     Some(ref foo) => bar(foo),
+    ///     _ => bar(other_ref),
+    /// }
+    /// ```
+    ///
+    /// Using `if let` with `else`:
+    ///
+    /// ```rust
+    /// if let Some(ref foo) = x {
+    ///     bar(foo);
+    /// } else {
+    ///     bar(other_ref);
+    /// }
+    /// ```
     pub SINGLE_MATCH_ELSE,
     pedantic,
-    "a match statement with a two arms where the second arm's pattern is a wildcard \
-     instead of `if let`"
+    "a match statement with a two arms where the second arm's pattern is a placeholder instead of a specific match pattern"
 }
 
-/// **What it does:** Checks for matches where all arms match a reference,
-/// suggesting to remove the reference and deref the matched expression
-/// instead. It also checks for `if let &foo = bar` blocks.
-///
-/// **Why is this bad?** It just makes the code less readable. That reference
-/// destructuring adds nothing to the code.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// match x {
-///     &A(ref y) => foo(y),
-///     &B => bar(),
-///     _ => frob(&x),
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for matches where all arms match a reference,
+    /// suggesting to remove the reference and deref the matched expression
+    /// instead. It also checks for `if let &foo = bar` blocks.
+    ///
+    /// **Why is this bad?** It just makes the code less readable. That reference
+    /// destructuring adds nothing to the code.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust,ignore
+    /// match x {
+    ///     &A(ref y) => foo(y),
+    ///     &B => bar(),
+    ///     _ => frob(&x),
+    /// }
+    /// ```
     pub MATCH_REF_PATS,
     style,
     "a match or `if let` with all arms prefixed with `&` instead of deref-ing the match expression"
 }
 
-/// **What it does:** Checks for matches where match expression is a `bool`. It
-/// suggests to replace the expression with an `if...else` block.
-///
-/// **Why is this bad?** It makes the code less readable.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// let condition: bool = true;
-/// match condition {
-///     true => foo(),
-///     false => bar(),
-/// }
-/// ```
-/// Use if/else instead:
-/// ```rust
-/// let condition: bool = true;
-/// if condition {
-///     foo();
-/// } else {
-///     bar();
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for matches where match expression is a `bool`. It
+    /// suggests to replace the expression with an `if...else` block.
+    ///
+    /// **Why is this bad?** It makes the code less readable.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// # fn foo() {}
+    /// # fn bar() {}
+    /// let condition: bool = true;
+    /// match condition {
+    ///     true => foo(),
+    ///     false => bar(),
+    /// }
+    /// ```
+    /// Use if/else instead:
+    /// ```rust
+    /// # fn foo() {}
+    /// # fn bar() {}
+    /// let condition: bool = true;
+    /// if condition {
+    ///     foo();
+    /// } else {
+    ///     bar();
+    /// }
+    /// ```
     pub MATCH_BOOL,
     style,
     "a match on a boolean expression instead of an `if..else` block"
 }
 
-/// **What it does:** Checks for overlapping match arms.
-///
-/// **Why is this bad?** It is likely to be an error and if not, makes the code
-/// less obvious.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// let x = 5;
-/// match x {
-///     1 ... 10 => println!("1 ... 10"),
-///     5 ... 15 => println!("5 ... 15"),
-///     _ => (),
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for overlapping match arms.
+    ///
+    /// **Why is this bad?** It is likely to be an error and if not, makes the code
+    /// less obvious.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let x = 5;
+    /// match x {
+    ///     1...10 => println!("1 ... 10"),
+    ///     5...15 => println!("5 ... 15"),
+    ///     _ => (),
+    /// }
+    /// ```
     pub MATCH_OVERLAPPING_ARM,
     style,
     "a match with overlapping arms"
 }
 
-/// **What it does:** Checks for arm which matches all errors with `Err(_)`
-/// and take drastic actions like `panic!`.
-///
-/// **Why is this bad?** It is generally a bad practice, just like
-/// catching all exceptions in java with `catch(Exception)`
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// let x : Result(i32, &str) = Ok(3);
-/// match x {
-///     Ok(_) => println!("ok"),
-///     Err(_) => panic!("err"),
-/// }
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for arm which matches all errors with `Err(_)`
+    /// and take drastic actions like `panic!`.
+    ///
+    /// **Why is this bad?** It is generally a bad practice, just like
+    /// catching all exceptions in java with `catch(Exception)`
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let x: Result<i32, &str> = Ok(3);
+    /// match x {
+    ///     Ok(_) => println!("ok"),
+    ///     Err(_) => panic!("err"),
+    /// }
+    /// ```
     pub MATCH_WILD_ERR_ARM,
     style,
     "a match with `Err(_)` arm and take drastic actions"
 }
 
-/// **What it does:** Checks for match which is used to add a reference to an
-/// `Option` value.
-///
-/// **Why is this bad?** Using `as_ref()` or `as_mut()` instead is shorter.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust
-/// let x: Option<()> = None;
-/// let r: Option<&()> = match x {
-///   None => None,
-///   Some(ref v) => Some(v),
-/// };
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for match which is used to add a reference to an
+    /// `Option` value.
+    ///
+    /// **Why is this bad?** Using `as_ref()` or `as_mut()` instead is shorter.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let x: Option<()> = None;
+    /// let r: Option<&()> = match x {
+    ///     None => None,
+    ///     Some(ref v) => Some(v),
+    /// };
+    /// ```
     pub MATCH_AS_REF,
     complexity,
     "a match on an Option value instead of using `as_ref()` or `as_mut`"
 }
 
-#[allow(missing_copy_implementations)]
-pub struct MatchPass;
-
-impl LintPass for MatchPass {
-    fn get_lints(&self) -> LintArray {
-        lint_array!(
-            SINGLE_MATCH,
-            MATCH_REF_PATS,
-            MATCH_BOOL,
-            SINGLE_MATCH_ELSE,
-            MATCH_OVERLAPPING_ARM,
-            MATCH_WILD_ERR_ARM,
-            MATCH_AS_REF
-        )
-    }
+declare_clippy_lint! {
+    /// **What it does:** Checks for wildcard enum matches using `_`.
+    ///
+    /// **Why is this bad?** New enum variants added by library updates can be missed.
+    ///
+    /// **Known problems:** Suggested replacements may be incorrect if guards exhaustively cover some
+    /// variants, and also may not use correct path to enum if it's not present in the current scope.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// match x {
+    ///     A => {},
+    ///     _ => {},
+    /// }
+    /// ```
+    pub WILDCARD_ENUM_MATCH_ARM,
+    restriction,
+    "a wildcard enum match arm using `_`"
 }
 
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MatchPass {
+declare_lint_pass!(Matches => [
+    SINGLE_MATCH,
+    MATCH_REF_PATS,
+    MATCH_BOOL,
+    SINGLE_MATCH_ELSE,
+    MATCH_OVERLAPPING_ARM,
+    MATCH_WILD_ERR_ARM,
+    MATCH_AS_REF,
+    WILDCARD_ENUM_MATCH_ARM
+]);
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Matches {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
         if in_external_macro(cx.sess(), expr.span) {
             return;
@@ -212,6 +236,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
             check_match_bool(cx, ex, arms, expr);
             check_overlapping_arms(cx, ex, arms);
             check_wild_err_arm(cx, ex, arms);
+            check_wild_enum_match(cx, ex, arms);
             check_match_as_ref(cx, ex, arms, expr);
         }
         if let ExprKind::Match(ref ex, ref arms, _) = expr.node {
@@ -236,26 +261,36 @@ fn check_single_match(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: &
             return;
         };
         let ty = cx.tables.expr_ty(ex);
-        if ty.sty != ty::Bool || is_allowed(cx, MATCH_BOOL, ex.id) {
+        if ty.sty != ty::Bool || is_allowed(cx, MATCH_BOOL, ex.hir_id) {
             check_single_match_single_pattern(cx, ex, arms, expr, els);
             check_single_match_opt_like(cx, ex, arms, expr, ty, els);
         }
     }
 }
 
-fn check_single_match_single_pattern(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: &Expr, els: Option<&Expr>) {
+fn check_single_match_single_pattern(
+    cx: &LateContext<'_, '_>,
+    ex: &Expr,
+    arms: &[Arm],
+    expr: &Expr,
+    els: Option<&Expr>,
+) {
     if is_wild(&arms[1].pats[0]) {
         report_single_match_single_pattern(cx, ex, arms, expr, els);
     }
 }
 
-fn report_single_match_single_pattern(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: &Expr, els: Option<&Expr>) {
-    let lint = if els.is_some() {
-        SINGLE_MATCH_ELSE
-    } else {
-        SINGLE_MATCH
-    };
-    let els_str = els.map_or(String::new(), |els| format!(" else {}", expr_block(cx, els, None, "..")));
+fn report_single_match_single_pattern(
+    cx: &LateContext<'_, '_>,
+    ex: &Expr,
+    arms: &[Arm],
+    expr: &Expr,
+    els: Option<&Expr>,
+) {
+    let lint = if els.is_some() { SINGLE_MATCH_ELSE } else { SINGLE_MATCH };
+    let els_str = els.map_or(String::new(), |els| {
+        format!(" else {}", expr_block(cx, els, None, ".."))
+    });
     span_lint_and_sugg(
         cx,
         lint,
@@ -274,8 +309,15 @@ fn report_single_match_single_pattern(cx: &LateContext<'_, '_>, ex: &Expr, arms:
     );
 }
 
-fn check_single_match_opt_like(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: &Expr, ty: Ty<'_>, els: Option<&Expr>) {
-    // list of candidate Enums we know will never get any more members
+fn check_single_match_opt_like(
+    cx: &LateContext<'_, '_>,
+    ex: &Expr,
+    arms: &[Arm],
+    expr: &Expr,
+    ty: Ty<'_>,
+    els: Option<&Expr>,
+) {
+    // list of candidate `Enum`s we know will never get any more members
     let candidates = &[
         (&paths::COW, "Borrowed"),
         (&paths::COW, "Cow::Borrowed"),
@@ -288,13 +330,13 @@ fn check_single_match_opt_like(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm]
 
     let path = match arms[1].pats[0].node {
         PatKind::TupleStruct(ref path, ref inner, _) => {
-            // contains any non wildcard patterns? e.g. Err(err)
+            // Contains any non wildcard patterns (e.g., `Err(err)`)?
             if !inner.iter().all(is_wild) {
                 return;
             }
             print::to_string(print::NO_ANN, |s| s.print_qpath(path, false))
         },
-        PatKind::Binding(BindingAnnotation::Unannotated, _, ident, None) => ident.to_string(),
+        PatKind::Binding(BindingAnnotation::Unannotated, .., ident, None) => ident.to_string(),
         PatKind::Path(ref path) => print::to_string(print::NO_ANN, |s| s.print_qpath(path, false)),
         _ => return,
     };
@@ -307,7 +349,7 @@ fn check_single_match_opt_like(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm]
 }
 
 fn check_match_bool(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: &Expr) {
-    // type of expression == bool
+    // Type of expression is `bool`.
     if cx.tables.expr_ty(ex).sty == ty::Bool {
         span_lint_and_then(
             cx,
@@ -352,7 +394,7 @@ fn check_match_bool(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: &Ex
                         };
 
                         if let Some(sugg) = sugg {
-                            db.span_suggestion_with_applicability(
+                            db.span_suggestion(
                                 expr.span,
                                 "consider using an if/else expression",
                                 sugg,
@@ -419,6 +461,93 @@ fn check_wild_err_arm(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm]) {
     }
 }
 
+fn check_wild_enum_match(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm]) {
+    let ty = cx.tables.expr_ty(ex);
+    if !ty.is_enum() {
+        // If there isn't a nice closed set of possible values that can be conveniently enumerated,
+        // don't complain about not enumerating the mall.
+        return;
+    }
+
+    // First pass - check for violation, but don't do much book-keeping because this is hopefully
+    // the uncommon case, and the book-keeping is slightly expensive.
+    let mut wildcard_span = None;
+    let mut wildcard_ident = None;
+    for arm in arms {
+        for pat in &arm.pats {
+            if let PatKind::Wild = pat.node {
+                wildcard_span = Some(pat.span);
+            } else if let PatKind::Binding(_, _, ident, None) = pat.node {
+                wildcard_span = Some(pat.span);
+                wildcard_ident = Some(ident);
+            }
+        }
+    }
+
+    if let Some(wildcard_span) = wildcard_span {
+        // Accumulate the variants which should be put in place of the wildcard because they're not
+        // already covered.
+
+        let mut missing_variants = vec![];
+        if let ty::Adt(def, _) = ty.sty {
+            for variant in &def.variants {
+                missing_variants.push(variant);
+            }
+        }
+
+        for arm in arms {
+            if arm.guard.is_some() {
+                // Guards mean that this case probably isn't exhaustively covered. Technically
+                // this is incorrect, as we should really check whether each variant is exhaustively
+                // covered by the set of guards that cover it, but that's really hard to do.
+                continue;
+            }
+            for pat in &arm.pats {
+                if let PatKind::Path(ref path) = pat.deref().node {
+                    if let QPath::Resolved(_, p) = path {
+                        missing_variants.retain(|e| e.ctor_def_id != Some(p.def.def_id()));
+                    }
+                } else if let PatKind::TupleStruct(ref path, ..) = pat.deref().node {
+                    if let QPath::Resolved(_, p) = path {
+                        missing_variants.retain(|e| e.ctor_def_id != Some(p.def.def_id()));
+                    }
+                }
+            }
+        }
+
+        let suggestion: Vec<String> = missing_variants
+            .iter()
+            .map(|v| {
+                let suffix = match v.ctor_kind {
+                    CtorKind::Fn => "(..)",
+                    CtorKind::Const | CtorKind::Fictive => "",
+                };
+                let ident_str = if let Some(ident) = wildcard_ident {
+                    format!("{} @ ", ident.name)
+                } else {
+                    String::new()
+                };
+                // This path assumes that the enum type is imported into scope.
+                format!("{}{}{}", ident_str, cx.tcx.def_path_str(v.def_id), suffix)
+            })
+            .collect();
+
+        if suggestion.is_empty() {
+            return;
+        }
+
+        span_lint_and_sugg(
+            cx,
+            WILDCARD_ENUM_MATCH_ARM,
+            wildcard_span,
+            "wildcard match will miss any future added variants.",
+            "try this",
+            suggestion.join(" | "),
+            Applicability::MachineApplicable,
+        )
+    }
+}
+
 // If the block contains only a `panic!` macro (as expression or statement)
 fn is_panic_block(block: &Block) -> bool {
     match (&block.expr, block.stmts.len(), block.stmts.first()) {
@@ -436,13 +565,15 @@ fn check_match_ref_pats(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr:
     if has_only_ref_pats(arms) {
         let mut suggs = Vec::new();
         let (title, msg) = if let ExprKind::AddrOf(Mutability::MutImmutable, ref inner) = ex.node {
-            suggs.push((ex.span, Sugg::hir(cx, inner, "..").to_string()));
+            let span = ex.span.source_callsite();
+            suggs.push((span, Sugg::hir_with_macro_callsite(cx, inner, "..").to_string()));
             (
                 "you don't need to add `&` to both the expression and the patterns",
                 "try",
             )
         } else {
-            suggs.push((ex.span, Sugg::hir(cx, ex, "..").deref().to_string()));
+            let span = ex.span.source_callsite();
+            suggs.push((span, Sugg::hir_with_macro_callsite(cx, ex, "..").deref().to_string()));
             (
                 "you don't need to add `&` to all patterns",
                 "instead of prefixing all patterns with `&`, you can dereference the expression",
@@ -466,9 +597,12 @@ fn check_match_ref_pats(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr:
 }
 
 fn check_match_as_ref(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: &Expr) {
-    if arms.len() == 2 &&
-        arms[0].pats.len() == 1 && arms[0].guard.is_none() &&
-        arms[1].pats.len() == 1 && arms[1].guard.is_none() {
+    if arms.len() == 2
+        && arms[0].pats.len() == 1
+        && arms[0].guard.is_none()
+        && arms[1].pats.len() == 1
+        && arms[1].guard.is_none()
+    {
         let arm_ref: Option<BindingAnnotation> = if is_none_arm(&arms[0]) {
             is_ref_some_arm(&arms[1])
         } else if is_none_arm(&arms[1]) {
@@ -477,7 +611,11 @@ fn check_match_as_ref(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: &
             None
         };
         if let Some(rb) = arm_ref {
-            let suggestion = if rb == BindingAnnotation::Ref { "as_ref" } else { "as_mut" };
+            let suggestion = if rb == BindingAnnotation::Ref {
+                "as_ref"
+            } else {
+                "as_mut"
+            };
             let mut applicability = Applicability::MachineApplicable;
             span_lint_and_sugg(
                 cx,
@@ -485,30 +623,30 @@ fn check_match_as_ref(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: &
                 expr.span,
                 &format!("use {}() instead", suggestion),
                 "try this",
-                format!("{}.{}()", snippet_with_applicability(cx, ex.span, "_", &mut applicability), suggestion),
+                format!(
+                    "{}.{}()",
+                    snippet_with_applicability(cx, ex.span, "_", &mut applicability),
+                    suggestion
+                ),
                 applicability,
             )
         }
     }
 }
 
-/// Get all arms that are unbounded `PatRange`s.
-fn all_ranges<'a, 'tcx>(
-    cx: &LateContext<'a, 'tcx>,
-    arms: &'tcx [Arm],
-) -> Vec<SpannedRange<Constant>> {
+/// Gets all arms that are unbounded `PatRange`s.
+fn all_ranges<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, arms: &'tcx [Arm]) -> Vec<SpannedRange<Constant>> {
     arms.iter()
         .flat_map(|arm| {
             if let Arm {
-                ref pats,
-                guard: None,
-                ..
+                ref pats, guard: None, ..
             } = *arm
             {
                 pats.iter()
             } else {
                 [].iter()
-            }.filter_map(|pat| {
+            }
+            .filter_map(|pat| {
                 if let PatKind::Range(ref lhs, ref rhs, ref range_end) = pat.node {
                     let lhs = constant(cx, cx.tables, lhs)?.0;
                     let rhs = constant(cx, cx.tables, rhs)?.0;
@@ -516,12 +654,18 @@ fn all_ranges<'a, 'tcx>(
                         RangeEnd::Included => Bound::Included(rhs),
                         RangeEnd::Excluded => Bound::Excluded(rhs),
                     };
-                    return Some(SpannedRange { span: pat.span, node: (lhs, rhs) });
+                    return Some(SpannedRange {
+                        span: pat.span,
+                        node: (lhs, rhs),
+                    });
                 }
 
                 if let PatKind::Lit(ref value) = pat.node {
                     let value = constant(cx, cx.tables, value)?.0;
-                    return Some(SpannedRange { span: pat.span, node: (value.clone(), Bound::Included(value)) });
+                    return Some(SpannedRange {
+                        span: pat.span,
+                        node: (value.clone(), Bound::Included(value)),
+                    });
                 }
 
                 None
@@ -538,31 +682,22 @@ pub struct SpannedRange<T> {
 
 type TypedRanges = Vec<SpannedRange<u128>>;
 
-/// Get all `Int` ranges or all `Uint` ranges. Mixed types are an error anyway
+/// Gets all `Int` ranges or all `Uint` ranges. Mixed types are an error anyway
 /// and other types than
 /// `Uint` and `Int` probably don't make sense.
 fn type_ranges(ranges: &[SpannedRange<Constant>]) -> TypedRanges {
     ranges
         .iter()
         .filter_map(|range| match range.node {
-            (
-                Constant::Int(start),
-                Bound::Included(Constant::Int(end)),
-            ) => Some(SpannedRange {
+            (Constant::Int(start), Bound::Included(Constant::Int(end))) => Some(SpannedRange {
                 span: range.span,
                 node: (start, Bound::Included(end)),
             }),
-            (
-                Constant::Int(start),
-                Bound::Excluded(Constant::Int(end)),
-            ) => Some(SpannedRange {
+            (Constant::Int(start), Bound::Excluded(Constant::Int(end))) => Some(SpannedRange {
                 span: range.span,
                 node: (start, Bound::Excluded(end)),
             }),
-            (
-                Constant::Int(start),
-                Bound::Unbounded,
-            ) => Some(SpannedRange {
+            (Constant::Int(start), Bound::Unbounded) => Some(SpannedRange {
                 span: range.span,
                 node: (start, Bound::Unbounded),
             }),
@@ -592,7 +727,7 @@ fn is_ref_some_arm(arm: &Arm) -> Option<BindingAnnotation> {
     if_chain! {
         if let PatKind::TupleStruct(ref path, ref pats, _) = arm.pats[0].node;
         if pats.len() == 1 && match_qpath(path, &paths::OPTION_SOME);
-        if let PatKind::Binding(rb, _, ident, _) = pats[0].node;
+        if let PatKind::Binding(rb, .., ident, _) = pats[0].node;
         if rb == BindingAnnotation::Ref || rb == BindingAnnotation::RefMut;
         if let ExprKind::Call(ref e, ref args) = remove_blocks(&arm.body).node;
         if let ExprKind::Path(ref some_path) = e.node;
@@ -608,7 +743,8 @@ fn is_ref_some_arm(arm: &Arm) -> Option<BindingAnnotation> {
 }
 
 fn has_only_ref_pats(arms: &[Arm]) -> bool {
-    let mapped = arms.iter()
+    let mapped = arms
+        .iter()
         .flat_map(|a| &a.pats)
         .map(|p| {
             match p.node {
@@ -682,8 +818,10 @@ fn cmp(&self, other: &Self) -> Ordering {
 
     for (a, b) in values.iter().zip(values.iter().skip(1)) {
         match (a, b) {
-            (&Kind::Start(_, ra), &Kind::End(_, rb)) => if ra.node != rb.node {
-                return Some((ra, rb));
+            (&Kind::Start(_, ra), &Kind::End(_, rb)) => {
+                if ra.node != rb.node {
+                    return Some((ra, rb));
+                }
             },
             (&Kind::End(a, _), &Kind::Start(b, _)) if a != Bound::Included(b) => (),
             _ => return Some((a.range(), b.range())),