]> git.lizzy.rs Git - rust.git/blob - src/identity_op.rs
56d01c52b1d836713392a25f4f2277b5eb1537ff
[rust.git] / src / identity_op.rs
1 use rustc::plugin::Registry;
2 use rustc::lint::*;
3 use rustc::middle::const_eval::lookup_const_by_id;
4 use rustc::middle::def::*;
5 use syntax::ast::*;
6 use syntax::ast_util::{is_comparison_binop, binop_to_string};
7 use syntax::ptr::P;
8 use syntax::codemap::Span;
9
10 use utils::{span_lint, snippet};
11
12 declare_lint! { pub IDENTITY_OP, Warn,
13     "Warn on identity operations, e.g. '_ + 0'"}
14
15 #[derive(Copy,Clone)]
16 pub struct IdentityOp;
17
18 impl LintPass for IdentityOp {
19     fn get_lints(&self) -> LintArray {
20         lint_array!(IDENTITY_OP)
21     }
22
23     fn check_expr(&mut self, cx: &Context, e: &Expr) {
24         if let ExprBinary(ref cmp, ref left, ref right) = e.node {
25             match cmp.node {
26                 BiAdd | BiBitOr | BiBitXor => {
27                     check(cx, left, 0, e.span, right.span);
28                     check(cx, right, 0, e.span, left.span);
29                 },
30                 BiShl | BiShr | BiSub =>
31                     check(cx, right, 0, e.span, left.span),
32                 BiMul => {
33                     check(cx, left, 1, e.span, right.span);
34                     check(cx, right, 1, e.span, left.span);
35                 },
36                 BiDiv =>
37                     check(cx, right, 1, e.span, left.span),
38                 BiBitAnd => {
39                     check(cx, left, -1, e.span, right.span);
40                     check(cx, right, -1, e.span, left.span);
41                 },
42                 _ => ()
43             }
44         }
45     }
46 }
47
48
49 fn check(cx: &Context, e: &Expr, m: i8, span: Span, arg: Span) {
50     if have_lit(cx, e, m) {
51         span_lint(cx, IDENTITY_OP, span, &format!(
52             "The operation is ineffective. Consider reducing it to '{}'",
53            snippet(cx, arg, "..")));
54     }
55 }
56
57 fn have_lit(cx: &Context, e : &Expr, m: i8) -> bool {
58     match &e.node {
59         &ExprUnary(UnNeg, ref litexp) => have_lit(cx, litexp, -m),
60         &ExprLit(ref lit) => {
61             match (&lit.node, m) {
62                 (&LitInt(0, _), 0) => true,
63                 (&LitInt(1, SignedIntLit(_, Plus)), 1) => true,
64                 (&LitInt(1, UnsuffixedIntLit(Plus)), 1) => true,
65                 (&LitInt(1, SignedIntLit(_, Minus)), -1) => true,
66                 (&LitInt(1, UnsuffixedIntLit(Minus)), -1) => true,
67                 _ => false
68             }
69         },
70         &ExprParen(ref p) => have_lit(cx, p, m),
71         &ExprPath(_, _) => {
72             match cx.tcx.def_map.borrow().get(&e.id) {
73                 Some(&PathResolution { base_def: DefConst(id), ..}) =>
74                         lookup_const_by_id(cx.tcx, id, Option::None)
75                         .map_or(false, |l| have_lit(cx, l, m)),
76                 _ => false
77             }
78         },
79         _ => false
80     }
81 }