]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/identity_op.rs
rustup https://github.com/rust-lang/rust/pull/67455
[rust.git] / clippy_lints / src / identity_op.rs
1 use rustc::declare_lint_pass;
2 use rustc::hir::*;
3 use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
4 use rustc::ty;
5 use rustc_session::declare_tool_lint;
6 use syntax::source_map::Span;
7
8 use crate::consts::{constant_simple, Constant};
9 use crate::utils::{clip, snippet, span_lint, unsext};
10
11 declare_clippy_lint! {
12     /// **What it does:** Checks for identity operations, e.g., `x + 0`.
13     ///
14     /// **Why is this bad?** This code can be removed without changing the
15     /// meaning. So it just obscures what's going on. Delete it mercilessly.
16     ///
17     /// **Known problems:** None.
18     ///
19     /// **Example:**
20     /// ```rust
21     /// # let x = 1;
22     /// x / 1 + 0 * 1 - 0 | 0;
23     /// ```
24     pub IDENTITY_OP,
25     complexity,
26     "using identity operations, e.g., `x + 0` or `y / 1`"
27 }
28
29 declare_lint_pass!(IdentityOp => [IDENTITY_OP]);
30
31 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IdentityOp {
32     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
33         if e.span.from_expansion() {
34             return;
35         }
36         if let ExprKind::Binary(ref cmp, ref left, ref right) = e.kind {
37             match cmp.node {
38                 BinOpKind::Add | BinOpKind::BitOr | BinOpKind::BitXor => {
39                     check(cx, left, 0, e.span, right.span);
40                     check(cx, right, 0, e.span, left.span);
41                 },
42                 BinOpKind::Shl | BinOpKind::Shr | BinOpKind::Sub => check(cx, right, 0, e.span, left.span),
43                 BinOpKind::Mul => {
44                     check(cx, left, 1, e.span, right.span);
45                     check(cx, right, 1, e.span, left.span);
46                 },
47                 BinOpKind::Div => check(cx, right, 1, e.span, left.span),
48                 BinOpKind::BitAnd => {
49                     check(cx, left, -1, e.span, right.span);
50                     check(cx, right, -1, e.span, left.span);
51                 },
52                 _ => (),
53             }
54         }
55     }
56 }
57
58 #[allow(clippy::cast_possible_wrap)]
59 fn check(cx: &LateContext<'_, '_>, e: &Expr, m: i8, span: Span, arg: Span) {
60     if let Some(Constant::Int(v)) = constant_simple(cx, cx.tables, e) {
61         let check = match cx.tables.expr_ty(e).kind {
62             ty::Int(ity) => unsext(cx.tcx, -1_i128, ity),
63             ty::Uint(uty) => clip(cx.tcx, !0, uty),
64             _ => return,
65         };
66         if match m {
67             0 => v == 0,
68             -1 => v == check,
69             1 => v == 1,
70             _ => unreachable!(),
71         } {
72             span_lint(
73                 cx,
74                 IDENTITY_OP,
75                 span,
76                 &format!(
77                     "the operation is ineffective. Consider reducing it to `{}`",
78                     snippet(cx, arg, "..")
79                 ),
80             );
81         }
82     }
83 }