]> git.lizzy.rs Git - rust.git/blobdiff - clippy_lints/src/precedence.rs
Merge commit '0e87918536b9833bbc6c683d1f9d51ee2bf03ef1' into clippyup
[rust.git] / clippy_lints / src / precedence.rs
index 52c11cacaac02f402b48c5af87139531e895fad8..9cf00c953b95f16afd34ec6e047f944d534c840e 100644 (file)
@@ -1,9 +1,28 @@
-use crate::utils::{in_macro, snippet_with_applicability, span_lint_and_sugg};
-use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
-use rustc::{declare_lint_pass, declare_tool_lint};
+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 syntax::ast::*;
-use syntax::source_map::Spanned;
+use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::source_map::Spanned;
+
+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
 
 impl EarlyLintPass for Precedence {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
-        if in_macro(expr.span) {
+        if expr.span.from_expansion() {
             return;
         }
 
-        if let ExprKind::Binary(Spanned { node: op, .. }, ref left, ref right) = expr.node {
+        if let ExprKind::Binary(Spanned { node: op, .. }, ref left, ref right) = expr.kind {
             let span_sugg = |expr: &Expr, sugg, appl| {
                 span_lint_and_sugg(
                     cx,
@@ -85,29 +104,36 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
             }
         }
 
-        if let ExprKind::Unary(UnOp::Neg, ref rhs) = expr.node {
-            if let ExprKind::MethodCall(_, ref args) = rhs.node {
-                if let Some(slf) = args.first() {
-                    if let ExprKind::Lit(ref lit) = slf.node {
-                        match lit.node {
-                            LitKind::Int(..) | LitKind::Float(..) | LitKind::FloatUnsuffixed(..) => {
-                                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, args, _) = &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 = args.first().expect("A method always has a 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,
+                    );
                 }
             }
         }
@@ -115,24 +141,20 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
 }
 
 fn is_arith_expr(expr: &Expr) -> bool {
-    match expr.node {
+    match expr.kind {
         ExprKind::Binary(Spanned { node: op, .. }, _, _) => is_arith_op(op),
         _ => false,
     }
 }
 
+#[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)
 }