about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEduardo Broto <ebroto@tutanota.com>2020-05-12 22:05:56 +0200
committerEduardo Broto <ebroto@tutanota.com>2020-05-13 20:35:52 +0200
commite4cd8e7961b553cac44671d63bc6dfc2223ea66b (patch)
tree6afc0b883a63c34101cfc63a630814466945d2a5
parentb20a9cd474776277a7ad7435fa0ff7b36f829ddf (diff)
downloadrust-e4cd8e7961b553cac44671d63bc6dfc2223ea66b.tar.gz
rust-e4cd8e7961b553cac44671d63bc6dfc2223ea66b.zip
Fix ICE caused in unwrap module
-rw-r--r--clippy_lints/src/unwrap.rs12
-rw-r--r--tests/ui/checked_unwrap/simple_conditionals.rs21
2 files changed, 31 insertions, 2 deletions
diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs
index f3844c7d3b6..8b971e7064b 100644
--- a/clippy_lints/src/unwrap.rs
+++ b/clippy_lints/src/unwrap.rs
@@ -8,6 +8,7 @@ use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, HirId, Path, QPath, UnO
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::map::Map;
 use rustc_middle::lint::in_external_macro;
+use rustc_middle::ty::Ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
 
@@ -90,6 +91,14 @@ fn collect_unwrap_info<'a, 'tcx>(
     branch: &'tcx Expr<'_>,
     invert: bool,
 ) -> Vec<UnwrapInfo<'tcx>> {
+    fn is_relevant_option_call(cx: &LateContext<'_, '_>, ty: Ty<'_>, method_name: &str) -> bool {
+        is_type_diagnostic_item(cx, ty, sym!(option_type)) && ["is_some", "is_none"].contains(&method_name)
+    }
+
+    fn is_relevant_result_call(cx: &LateContext<'_, '_>, ty: Ty<'_>, method_name: &str) -> bool {
+        is_type_diagnostic_item(cx, ty, sym!(result_type)) && ["is_ok", "is_err"].contains(&method_name)
+    }
+
     if let ExprKind::Binary(op, left, right) = &expr.kind {
         match (invert, op.node) {
             (false, BinOpKind::And) | (false, BinOpKind::BitAnd) | (true, BinOpKind::Or) | (true, BinOpKind::BitOr) => {
@@ -106,9 +115,8 @@ fn collect_unwrap_info<'a, 'tcx>(
             if let ExprKind::MethodCall(method_name, _, args) = &expr.kind;
             if let ExprKind::Path(QPath::Resolved(None, path)) = &args[0].kind;
             let ty = cx.tables.expr_ty(&args[0]);
-            if is_type_diagnostic_item(cx, ty, sym!(option_type)) || is_type_diagnostic_item(cx, ty, sym!(result_type));
             let name = method_name.ident.as_str();
-            if ["is_some", "is_none", "is_ok", "is_err"].contains(&&*name);
+            if is_relevant_option_call(cx, ty, &name) || is_relevant_result_call(cx, ty, &name);
             then {
                 assert!(args.len() == 1);
                 let unwrappable = match name.as_ref() {
diff --git a/tests/ui/checked_unwrap/simple_conditionals.rs b/tests/ui/checked_unwrap/simple_conditionals.rs
index 3e7b4b390ba..49794e0c241 100644
--- a/tests/ui/checked_unwrap/simple_conditionals.rs
+++ b/tests/ui/checked_unwrap/simple_conditionals.rs
@@ -78,3 +78,24 @@ fn main() {
 
     assert!(x.is_ok(), "{:?}", x.unwrap_err()); // ok, it's a common test pattern
 }
+
+mod issue_5579 {
+    trait IsErr {
+        fn is_err(&self, err: &str) -> bool;
+    }
+
+    impl<T> IsErr for Option<T> {
+        fn is_err(&self, _err: &str) -> bool {
+            true
+        }
+    }
+
+    #[allow(unused)]
+    fn boom() {
+        let t = Some(1);
+
+        if t.is_err("") {
+            t.unwrap();
+        }
+    }
+}