]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/should_assert_eq.rs
93baab8634725abd2d106c012d5a13db4d96682e
[rust.git] / clippy_lints / src / should_assert_eq.rs
1 use rustc::lint::*;
2 use rustc::hir::*;
3 use utils::{is_direct_expn_of, is_expn_of, implements_trait, span_lint};
4
5 /// **What it does:** Checks for `assert!(x == y)` or `assert!(x != y)` which can be better written
6 /// using `assert_eq` or `assert_ne` if `x` and `y` implement `Debug` trait.
7 ///
8 /// **Why is this bad?** `assert_eq` and `assert_ne` provide better assertion failure reporting.
9 ///
10 /// **Known problems:** Hopefully none.
11 ///
12 /// **Example:**
13 /// ```rust
14 /// let (x, y) = (1, 2);
15 ///
16 /// assert!(x == y);  // assertion failed: x == y
17 /// assert_eq!(x, y); // assertion failed: `(left == right)` (left: `1`, right: `2`)
18 /// ```
19 declare_lint! {
20     pub SHOULD_ASSERT_EQ,
21     Warn,
22     "using `assert` macro for asserting equality"
23 }
24
25 pub struct ShouldAssertEq;
26
27 impl LintPass for ShouldAssertEq {
28     fn get_lints(&self) -> LintArray {
29         lint_array![SHOULD_ASSERT_EQ]
30     }
31 }
32
33 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ShouldAssertEq {
34     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
35         if_let_chain! {[
36             let ExprIf(ref cond, ..) = e.node,
37             let ExprUnary(UnOp::UnNot, ref cond) = cond.node,
38             let ExprBinary(ref binop, ref expr1, ref expr2) = cond.node,
39             is_direct_expn_of(e.span, "assert").is_some(),
40             let Some(debug_trait) = cx.tcx.lang_items.debug_trait(),
41         ], {
42             let debug = is_expn_of(e.span, "debug_assert").map_or("", |_| "debug_");
43             let sugg = match binop.node {
44                 BinOp_::BiEq => "assert_eq",
45                 BinOp_::BiNe => "assert_ne",
46                 _ => return,
47             };
48
49             let ty1 = cx.tables.expr_ty(expr1);
50             let ty2 = cx.tables.expr_ty(expr2);
51
52             let parent = cx.tcx.hir.get_parent(e.id);
53
54             if implements_trait(cx, ty1, debug_trait, &[], Some(parent)) &&
55                 implements_trait(cx, ty2, debug_trait, &[], Some(parent)) {
56                 span_lint(cx, SHOULD_ASSERT_EQ, e.span, &format!("use `{}{}` for better reporting", debug, sugg));
57             }
58         }}
59     }
60 }