2 use syntax::codemap::Spanned;
4 use syntax::ast_util::binop_to_string;
6 use utils::{span_lint, snippet};
8 declare_lint!(pub PRECEDENCE, Warn,
9 "catches operations where precedence may be unclear. See the wiki for a \
10 list of cases caught");
13 pub struct Precedence;
15 impl LintPass for Precedence {
16 fn get_lints(&self) -> LintArray {
17 lint_array!(PRECEDENCE)
21 impl EarlyLintPass for Precedence {
22 fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) {
23 if let ExprBinary(Spanned { node: op, ..}, ref left, ref right) = expr.node {
24 if !is_bit_op(op) { return; }
25 match (is_arith_expr(left), is_arith_expr(right)) {
26 (true, true) => span_lint(cx, PRECEDENCE, expr.span,
27 &format!("operator precedence can trip the unwary. \
28 Consider parenthesizing your expression:\
29 `({}) {} ({})`", snippet(cx, left.span, ".."),
30 binop_to_string(op), snippet(cx, right.span, ".."))),
31 (true, false) => span_lint(cx, PRECEDENCE, expr.span,
32 &format!("operator precedence can trip the unwary. \
33 Consider parenthesizing your expression:\
34 `({}) {} {}`", snippet(cx, left.span, ".."),
35 binop_to_string(op), snippet(cx, right.span, ".."))),
36 (false, true) => span_lint(cx, PRECEDENCE, expr.span,
37 &format!("operator precedence can trip the unwary. \
38 Consider parenthesizing your expression:\
39 `{} {} ({})`", snippet(cx, left.span, ".."),
40 binop_to_string(op), snippet(cx, right.span, ".."))),
45 if let ExprUnary(UnNeg, ref rhs) = expr.node {
46 if let ExprMethodCall(_, _, ref args) = rhs.node {
47 if let Some(slf) = args.first() {
48 if let ExprLit(ref lit) = slf.node {
50 LitInt(..) | LitFloat(..) | LitFloatUnsuffixed(..) =>
51 span_lint(cx, PRECEDENCE, expr.span, &format!(
52 "unary minus has lower precedence than \
53 method call. Consider adding parentheses \
54 to clarify your intent: -({})",
55 snippet(cx, rhs.span, ".."))),
65 fn is_arith_expr(expr : &Expr) -> bool {
67 ExprBinary(Spanned { node: op, ..}, _, _) => is_arith_op(op),
72 fn is_bit_op(op : BinOp_) -> bool {
74 BiBitXor | BiBitAnd | BiBitOr | BiShl | BiShr => true,
79 fn is_arith_op(op : BinOp_) -> bool {
81 BiAdd | BiSub | BiMul | BiDiv | BiRem => true,