]> git.lizzy.rs Git - rust.git/blobdiff - clippy_lints/src/fallible_impl_from.rs
Rustup
[rust.git] / clippy_lints / src / fallible_impl_from.rs
index bdcda99124c62a77d70fd2f26c937b9085b06374..64cdc05b44de33fc9e978fb597885878f49de23d 100644 (file)
@@ -2,8 +2,8 @@
 use rustc::hir;
 use rustc::ty;
 use syntax_pos::Span;
-use utils::{method_chain_args, match_def_path, span_lint_and_then, walk_ptrs_ty};
-use utils::paths::{BEGIN_PANIC, BEGIN_PANIC_FMT, FROM_TRAIT, OPTION, RESULT};
+use crate::utils::{match_def_path, method_chain_args, span_lint_and_then, walk_ptrs_ty, is_expn_of, opt_def_id};
+use crate::utils::paths::{BEGIN_PANIC, BEGIN_PANIC_FMT, FROM_TRAIT, OPTION, RESULT};
 
 /// **What it does:** Checks for impls of `From<..>` that contain `panic!()` or `unwrap()`
 ///
@@ -20,8 +20,9 @@
 ///     }
 /// }
 /// ```
-declare_lint! {
-    pub FALLIBLE_IMPL_FROM, Allow,
+declare_clippy_lint! {
+    pub FALLIBLE_IMPL_FROM,
+    nursery,
     "Warn on impls of `From<..>` that contain `panic!()` or `unwrap()`"
 }
 
@@ -37,13 +38,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for FallibleImplFrom {
     fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item) {
         // check for `impl From<???> for ..`
         let impl_def_id = cx.tcx.hir.local_def_id(item.id);
-        if_let_chain!{[
-            let hir::ItemImpl(.., ref impl_items) = item.node,
-            let Some(impl_trait_ref) = cx.tcx.impl_trait_ref(impl_def_id),
-            match_def_path(cx.tcx, impl_trait_ref.def_id, &FROM_TRAIT),
-        ], {
-            lint_impl_body(cx, item.span, impl_items);
-        }}
+        if_chain! {
+            if let hir::ItemImpl(.., ref impl_items) = item.node;
+            if let Some(impl_trait_ref) = cx.tcx.impl_trait_ref(impl_def_id);
+            if match_def_path(cx.tcx, impl_trait_ref.def_id, &FROM_TRAIT);
+            then {
+                lint_impl_body(cx, item.span, impl_items);
+            }
+        }
     }
 }
 
@@ -60,21 +62,22 @@ struct FindPanicUnwrap<'a, 'tcx: 'a> {
     impl<'a, 'tcx: 'a> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> {
         fn visit_expr(&mut self, expr: &'tcx Expr) {
             // check for `begin_panic`
-            if_let_chain!{[
-                let ExprCall(ref func_expr, _) = expr.node,
-                let ExprPath(QPath::Resolved(_, ref path)) = func_expr.node,
-                match_def_path(self.tcx, path.def.def_id(), &BEGIN_PANIC) ||
-                    match_def_path(self.tcx, path.def.def_id(), &BEGIN_PANIC_FMT),
-            ], {
-                self.result.push(expr.span);
-            }}
+            if_chain! {
+                if let ExprCall(ref func_expr, _) = expr.node;
+                if let ExprPath(QPath::Resolved(_, ref path)) = func_expr.node;
+                if let Some(path_def_id) = opt_def_id(path.def);
+                if match_def_path(self.tcx, path_def_id, &BEGIN_PANIC) ||
+                    match_def_path(self.tcx, path_def_id, &BEGIN_PANIC_FMT);
+                if is_expn_of(expr.span, "unreachable").is_none();
+                then {
+                    self.result.push(expr.span);
+                }
+            }
 
             // check for `unwrap`
             if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
                 let reciever_ty = walk_ptrs_ty(self.tables.expr_ty(&arglists[0][0]));
-                if match_type(self.tcx, reciever_ty, &OPTION) ||
-                    match_type(self.tcx, reciever_ty, &RESULT)
-                {
+                if match_type(self.tcx, reciever_ty, &OPTION) || match_type(self.tcx, reciever_ty, &RESULT) {
                     self.result.push(expr.span);
                 }
             }
@@ -89,36 +92,37 @@ fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
     }
 
     for impl_item in impl_items {
-        if_let_chain!{[
-            impl_item.name == "from",
-            let ImplItemKind::Method(_, body_id) =
-                cx.tcx.hir.impl_item(impl_item.id).node,
-        ], {
-            // check the body for `begin_panic` or `unwrap`
-            let body = cx.tcx.hir.body(body_id);
-            let impl_item_def_id = cx.tcx.hir.local_def_id(impl_item.id.node_id);
-            let mut fpu = FindPanicUnwrap {
-                tcx: cx.tcx,
-                tables: cx.tcx.typeck_tables_of(impl_item_def_id),
-                result: Vec::new(),
-            };
-            fpu.visit_expr(&body.value);
+        if_chain! {
+            if impl_item.ident.name == "from";
+            if let ImplItemKind::Method(_, body_id) =
+                cx.tcx.hir.impl_item(impl_item.id).node;
+            then {
+                // check the body for `begin_panic` or `unwrap`
+                let body = cx.tcx.hir.body(body_id);
+                let impl_item_def_id = cx.tcx.hir.local_def_id(impl_item.id.node_id);
+                let mut fpu = FindPanicUnwrap {
+                    tcx: cx.tcx,
+                    tables: cx.tcx.typeck_tables_of(impl_item_def_id),
+                    result: Vec::new(),
+                };
+                fpu.visit_expr(&body.value);
 
-            // if we've found one, lint
-            if !fpu.result.is_empty() {
-                span_lint_and_then(
-                    cx,
-                    FALLIBLE_IMPL_FROM,
-                    impl_span,
-                    "consider implementing `TryFrom` instead",
-                    move |db| {
-                        db.help(
-                            "`From` is intended for infallible conversions only. \
-                             Use `TryFrom` if there's a possibility for the conversion to fail.");
-                        db.span_note(fpu.result, "potential failure(s)");
-                    });
+                // if we've found one, lint
+                if !fpu.result.is_empty() {
+                    span_lint_and_then(
+                        cx,
+                        FALLIBLE_IMPL_FROM,
+                        impl_span,
+                        "consider implementing `TryFrom` instead",
+                        move |db| {
+                            db.help(
+                                "`From` is intended for infallible conversions only. \
+                                 Use `TryFrom` if there's a possibility for the conversion to fail.");
+                            db.span_note(fpu.result, "potential failure(s)");
+                        });
+                }
             }
-        }}
+        }
     }
 }