diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index ca3fb4017..86d1f2fb9 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -44,6 +44,13 @@ declare_lint! { "boolean expressions that contain terminals which can be eliminated" } +const METHODS_WITH_NEGATION: [(&str, &str); 4] = [ + ("is_some", "is_none"), + ("is_none", "is_some"), + ("is_err", "is_ok"), + ("is_ok", "is_err"), +]; + #[derive(Copy, Clone)] pub struct NonminimalBool; @@ -396,6 +403,28 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> { } } } + + fn handle_method_call_in_not(&mut self, e: &'tcx Expr, inner: &'tcx Expr) { + if let ExprMethodCall(ref path, _, _) = inner.node { + METHODS_WITH_NEGATION.iter().for_each(|&(method, negation_method)| { + if method == path.name.as_str() { + span_lint_and_then( + self.cx, + NONMINIMAL_BOOL, + e.span, + "this boolean expression can be simplified", + |db| { + db.span_suggestion( + e.span, + "try", + negation_method.to_owned() + ); + } + ) + } + }) + } + } } impl<'a, 'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'a, 'tcx> { @@ -406,6 +435,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'a, 'tcx> { match e.node { ExprBinary(binop, _, _) if binop.node == BiOr || binop.node == BiAnd => self.bool_expr(e), ExprUnary(UnNot, ref inner) => if self.cx.tables.node_types()[inner.hir_id].is_bool() { + self.handle_method_call_in_not(e, inner); self.bool_expr(e); } else { walk_expr(self, e); diff --git a/tests/ui/booleans.rs b/tests/ui/booleans.rs index 0434285a5..a3c37fecf 100644 --- a/tests/ui/booleans.rs +++ b/tests/ui/booleans.rs @@ -38,3 +38,17 @@ fn equality_stuff() { let _ = a > b && a == b; let _ = a != b || !(a != b || c == d); } + +#[allow(unused, many_single_char_names)] +fn methods_with_negation() { + let a: Option = unimplemented!(); + let b: Result = unimplemented!(); + let _ = a.is_some(); + let _ = !a.is_some(); + let _ = a.is_none(); + let _ = !a.is_none(); + let _ = b.is_err(); + let _ = !b.is_err(); + let _ = b.is_ok(); + let _ = !b.is_ok(); +} diff --git a/tests/ui/booleans.stderr b/tests/ui/booleans.stderr index 0311e95a4..b7256ee0f 100644 --- a/tests/ui/booleans.stderr +++ b/tests/ui/booleans.stderr @@ -130,3 +130,27 @@ help: try 39 | let _ = !(a == b && c == d); | ^^^^^^^^^^^^^^^^^^^ +error: this boolean expression can be simplified + --> $DIR/booleans.rs:47:13 + | +47 | let _ = !a.is_some(); + | ^^^^^^^^^^^^ help: try: `is_none` + +error: this boolean expression can be simplified + --> $DIR/booleans.rs:49:13 + | +49 | let _ = !a.is_none(); + | ^^^^^^^^^^^^ help: try: `is_some` + +error: this boolean expression can be simplified + --> $DIR/booleans.rs:51:13 + | +51 | let _ = !b.is_err(); + | ^^^^^^^^^^^ help: try: `is_ok` + +error: this boolean expression can be simplified + --> $DIR/booleans.rs:53:13 + | +53 | let _ = !b.is_ok(); + | ^^^^^^^^^^ help: try: `is_err` +