3 use syntax
::codemap
::Spanned
;
4 use utils
::{in_macro, snippet, span_lint_and_sugg}
;
6 /// **What it does:** Checks for operations where precedence may be unclear
7 /// and suggests to add parentheses. Currently it catches the following:
8 /// * mixed usage of arithmetic and bit shifting/combining operators without
10 /// * a "negative" numeric literal (which is really a unary `-` followed by a
12 /// followed by a method call
14 /// **Why is this bad?** Not everyone knows the precedence of those operators by
15 /// heart, so expressions like these may trip others trying to reason about the
18 /// **Known problems:** None.
21 /// * `1 << 2 + 3` equals 32, while `(1 << 2) + 3` equals 7
22 /// * `-1i32.abs()` equals -1, while `(-1i32).abs()` equals 1
23 declare_clippy_lint
! {
26 "operations where precedence may be unclear"
29 #[derive(Copy, Clone)]
30 pub struct Precedence
;
32 impl LintPass
for Precedence
{
33 fn get_lints(&self) -> LintArray
{
34 lint_array
!(PRECEDENCE
)
38 impl EarlyLintPass
for Precedence
{
39 fn check_expr(&mut self, cx
: &EarlyContext
, expr
: &Expr
) {
40 if in_macro(expr
.span
) {
44 if let ExprKind
::Binary(Spanned { node: op, .. }
, ref left
, ref right
) = expr
.node
{
45 let span_sugg
= |expr
: &Expr
, sugg
| {
50 "operator precedence can trip the unwary",
51 "consider parenthesizing your expression",
59 match (is_arith_expr(left
), is_arith_expr(right
)) {
63 snippet(cx
, left
.span
, ".."),
65 snippet(cx
, right
.span
, "..")
67 span_sugg(expr
, sugg
);
72 snippet(cx
, left
.span
, ".."),
74 snippet(cx
, right
.span
, "..")
76 span_sugg(expr
, sugg
);
81 snippet(cx
, left
.span
, ".."),
83 snippet(cx
, right
.span
, "..")
85 span_sugg(expr
, sugg
);
91 if let ExprKind
::Unary(UnOp
::Neg
, ref rhs
) = expr
.node
{
92 if let ExprKind
::MethodCall(_
, ref args
) = rhs
.node
{
93 if let Some(slf
) = args
.first() {
94 if let ExprKind
::Lit(ref lit
) = slf
.node
{
96 LitKind
::Int(..) | LitKind
::Float(..) | LitKind
::FloatUnsuffixed(..) => {
101 "unary minus has lower precedence than method call",
102 "consider adding parentheses to clarify your intent",
103 format
!("-({})", snippet(cx
, rhs
.span
, "..")),
115 fn is_arith_expr(expr
: &Expr
) -> bool
{
117 ExprKind
::Binary(Spanned { node: op, .. }
, _
, _
) => is_arith_op(op
),
122 fn is_bit_op(op
: BinOpKind
) -> bool
{
123 use syntax
::ast
::BinOpKind
::*;
125 BitXor
| BitAnd
| BitOr
| Shl
| Shr
=> true,
130 fn is_arith_op(op
: BinOpKind
) -> bool
{
131 use syntax
::ast
::BinOpKind
::*;
133 Add
| Sub
| Mul
| Div
| Rem
=> true,