X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=clippy_lints%2Fsrc%2Fprecedence.rs;h=e6e3ad05ad70abbee15e673653f9b076a43affff;hb=a85c8f33ff0da5192bb44ac52cb838f638ad7c03;hp=6ffdf048f4e41126d65ce91596a9fb3782bc7bbf;hpb=39947992b57239de6581c9761dfad7ac3cf001c8;p=rust.git diff --git a/clippy_lints/src/precedence.rs b/clippy_lints/src/precedence.rs index 6ffdf048f4e..e6e3ad05ad7 100644 --- a/clippy_lints/src/precedence.rs +++ b/clippy_lints/src/precedence.rs @@ -1,12 +1,32 @@ -use crate::utils::{snippet_with_applicability, span_lint_and_sugg}; -use rustc::lint::{EarlyContext, EarlyLintPass}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use if_chain::if_chain; +use rustc_ast::ast::{BinOpKind, Expr, ExprKind, LitKind, UnOp}; use rustc_errors::Applicability; +use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Spanned; -use syntax::ast::*; + +const ALLOWED_ODD_FUNCTIONS: [&str; 14] = [ + "asin", + "asinh", + "atan", + "atanh", + "cbrt", + "fract", + "round", + "signum", + "sin", + "sinh", + "tan", + "tanh", + "to_degrees", + "to_radians", +]; declare_clippy_lint! { - /// **What it does:** Checks for operations where precedence may be unclear + /// ### What it does + /// Checks for operations where precedence may be unclear /// and suggests to add parentheses. Currently it catches the following: /// * mixed usage of arithmetic and bit shifting/combining operators without /// parentheses @@ -14,15 +34,15 @@ /// numeric literal) /// followed by a method call /// - /// **Why is this bad?** Not everyone knows the precedence of those operators by + /// ### Why is this bad? + /// Not everyone knows the precedence of those operators by /// heart, so expressions like these may trip others trying to reason about the /// code. /// - /// **Known problems:** None. - /// - /// **Example:** + /// ### Example /// * `1 << 2 + 3` equals 32, while `(1 << 2) + 3` equals 7 /// * `-1i32.abs()` equals -1, while `(-1i32).abs()` equals 1 + #[clippy::version = "pre 1.29.0"] pub PRECEDENCE, complexity, "operations where precedence may be unclear" @@ -85,29 +105,36 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { } } - if let ExprKind::Unary(UnOp::Neg, ref rhs) = expr.kind { - if let ExprKind::MethodCall(_, ref args) = rhs.kind { - if let Some(slf) = args.first() { - if let ExprKind::Lit(ref lit) = slf.kind { - match lit.kind { - LitKind::Int(..) | LitKind::Float(..) => { - let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - PRECEDENCE, - expr.span, - "unary minus has lower precedence than method call", - "consider adding parentheses to clarify your intent", - format!( - "-({})", - snippet_with_applicability(cx, rhs.span, "..", &mut applicability) - ), - applicability, - ); - }, - _ => (), - } - } + if let ExprKind::Unary(UnOp::Neg, operand) = &expr.kind { + let mut arg = operand; + + let mut all_odd = true; + while let ExprKind::MethodCall(path_segment, receiver, _, _) = &arg.kind { + let path_segment_str = path_segment.ident.name.as_str(); + all_odd &= ALLOWED_ODD_FUNCTIONS + .iter() + .any(|odd_function| **odd_function == *path_segment_str); + arg = receiver; + } + + if_chain! { + if !all_odd; + if let ExprKind::Lit(lit) = &arg.kind; + if let LitKind::Int(..) | LitKind::Float(..) = &lit.kind; + then { + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + PRECEDENCE, + expr.span, + "unary minus has lower precedence than method call", + "consider adding parentheses to clarify your intent", + format!( + "-({})", + snippet_with_applicability(cx, operand.span, "..", &mut applicability) + ), + applicability, + ); } } } @@ -123,18 +150,12 @@ fn is_arith_expr(expr: &Expr) -> bool { #[must_use] fn is_bit_op(op: BinOpKind) -> bool { - use syntax::ast::BinOpKind::*; - match op { - BitXor | BitAnd | BitOr | Shl | Shr => true, - _ => false, - } + use rustc_ast::ast::BinOpKind::{BitAnd, BitOr, BitXor, Shl, Shr}; + matches!(op, BitXor | BitAnd | BitOr | Shl | Shr) } #[must_use] fn is_arith_op(op: BinOpKind) -> bool { - use syntax::ast::BinOpKind::*; - match op { - Add | Sub | Mul | Div | Rem => true, - _ => false, - } + use rustc_ast::ast::BinOpKind::{Add, Div, Mul, Rem, Sub}; + matches!(op, Add | Sub | Mul | Div | Rem) }