]> git.lizzy.rs Git - rust.git/blob - src/precedence.rs
Merge pull request #298 from birkenfeld/as_mut
[rust.git] / src / precedence.rs
1 use rustc::lint::*;
2 use rustc_front::hir::*;
3 use syntax::codemap::Spanned;
4
5 use utils::span_lint;
6
7 declare_lint!(pub PRECEDENCE, Warn,
8               "catches operations where precedence may be unclear. See the wiki for a \
9                list of cases caught");
10
11 #[derive(Copy,Clone)]
12 pub struct Precedence;
13
14 impl LintPass for Precedence {
15     fn get_lints(&self) -> LintArray {
16         lint_array!(PRECEDENCE)
17     }
18
19     fn check_expr(&mut self, cx: &Context, expr: &Expr) {
20         if let ExprBinary(Spanned { node: op, ..}, ref left, ref right) = expr.node {
21             if is_bit_op(op) && (is_arith_expr(left) || is_arith_expr(right)) {
22                 span_lint(cx, PRECEDENCE, expr.span,
23                     "operator precedence can trip the unwary. Consider adding parentheses \
24                      to the subexpression");
25             }
26         }
27
28         if let ExprUnary(UnNeg, ref rhs) = expr.node {
29             if let ExprMethodCall(_, _, ref args) = rhs.node {
30                 if let Some(slf) = args.first() {
31                     if let ExprLit(ref lit) = slf.node {
32                         match lit.node {
33                             LitInt(..) | LitFloat(..) | LitFloatUnsuffixed(..) =>
34                                 span_lint(cx, PRECEDENCE, expr.span,
35                                     "unary minus has lower precedence than method call. Consider \
36                                      adding parentheses to clarify your intent"),
37                                 _ => ()
38                         }
39                     }
40                 }
41             }
42         }
43     }
44 }
45
46 fn is_arith_expr(expr : &Expr) -> bool {
47     match expr.node {
48         ExprBinary(Spanned { node: op, ..}, _, _) => is_arith_op(op),
49         _ => false
50     }
51 }
52
53 fn is_bit_op(op : BinOp_) -> bool {
54     match op {
55         BiBitXor | BiBitAnd | BiBitOr | BiShl | BiShr => true,
56         _ => false
57     }
58 }
59
60 fn is_arith_op(op : BinOp_) -> bool {
61     match op {
62         BiAdd | BiSub | BiMul | BiDiv | BiRem => true,
63         _ => false
64     }
65 }