about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJason Newcomb <jsnewcomb@pm.me>2022-05-31 21:27:29 -0400
committerJason Newcomb <jsnewcomb@pm.me>2022-06-28 12:51:00 -0400
commit448b6f45bd1175e3ea7f696e1ff7b9702d8a7cc6 (patch)
tree0495f5567c8b9126f70fbe4355b65501de626c99
parentdd78ce7bbe70fcb87ecc4f0ce11611be0b3a7e59 (diff)
downloadrust-448b6f45bd1175e3ea7f696e1ff7b9702d8a7cc6.tar.gz
rust-448b6f45bd1175e3ea7f696e1ff7b9702d8a7cc6.zip
Move `Arithmetic` into `Operators` lint pass
-rw-r--r--clippy_lints/src/lib.register_lints.rs4
-rw-r--r--clippy_lints/src/lib.register_restriction.rs4
-rw-r--r--clippy_lints/src/lib.rs4
-rw-r--r--clippy_lints/src/numeric_arithmetic.rs170
-rw-r--r--clippy_lints/src/operators/mod.rs87
-rw-r--r--clippy_lints/src/operators/numeric_arithmetic.rs127
6 files changed, 213 insertions, 183 deletions
diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs
index f0ce0db65a7..787ae1e79ec 100644
--- a/clippy_lints/src/lib.register_lints.rs
+++ b/clippy_lints/src/lib.register_lints.rs
@@ -431,12 +431,12 @@ store.register_lints(&[
     non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS,
     non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY,
     nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES,
-    numeric_arithmetic::FLOAT_ARITHMETIC,
-    numeric_arithmetic::INTEGER_ARITHMETIC,
     octal_escapes::OCTAL_ESCAPES,
     only_used_in_recursion::ONLY_USED_IN_RECURSION,
     open_options::NONSENSICAL_OPEN_OPTIONS,
     operators::ABSURD_EXTREME_COMPARISONS,
+    operators::FLOAT_ARITHMETIC,
+    operators::INTEGER_ARITHMETIC,
     option_env_unwrap::OPTION_ENV_UNWRAP,
     option_if_let_else::OPTION_IF_LET_ELSE,
     overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL,
diff --git a/clippy_lints/src/lib.register_restriction.rs b/clippy_lints/src/lib.register_restriction.rs
index 3695012f552..b7441385230 100644
--- a/clippy_lints/src/lib.register_restriction.rs
+++ b/clippy_lints/src/lib.register_restriction.rs
@@ -50,8 +50,8 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve
     LintId::of(module_style::MOD_MODULE_FILES),
     LintId::of(module_style::SELF_NAMED_MODULE_FILES),
     LintId::of(modulo_arithmetic::MODULO_ARITHMETIC),
-    LintId::of(numeric_arithmetic::FLOAT_ARITHMETIC),
-    LintId::of(numeric_arithmetic::INTEGER_ARITHMETIC),
+    LintId::of(operators::FLOAT_ARITHMETIC),
+    LintId::of(operators::INTEGER_ARITHMETIC),
     LintId::of(panic_in_result_fn::PANIC_IN_RESULT_FN),
     LintId::of(panic_unimplemented::PANIC),
     LintId::of(panic_unimplemented::TODO),
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index 16e72400fbf..f1d28201309 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -331,7 +331,6 @@ mod non_expressive_names;
 mod non_octal_unix_permissions;
 mod non_send_fields_in_send_ty;
 mod nonstandard_macro_braces;
-mod numeric_arithmetic;
 mod octal_escapes;
 mod only_used_in_recursion;
 mod open_options;
@@ -705,7 +704,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(move || Box::new(doc::DocMarkdown::new(doc_valid_idents.clone())));
     store.register_late_pass(|| Box::new(neg_multiply::NegMultiply));
     store.register_late_pass(|| Box::new(mem_forget::MemForget));
-    store.register_late_pass(|| Box::new(numeric_arithmetic::NumericArithmetic::default()));
     store.register_late_pass(|| Box::new(assign_ops::AssignOps));
     store.register_late_pass(|| Box::new(let_if_seq::LetIfSeq));
     store.register_late_pass(|| Box::new(mixed_read_write_in_expression::EvalOrderDependence));
@@ -940,7 +938,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| Box::new(default_instead_of_iter_empty::DefaultIterEmpty));
     store.register_late_pass(move || Box::new(manual_rem_euclid::ManualRemEuclid::new(msrv)));
     store.register_late_pass(move || Box::new(manual_retain::ManualRetain::new(msrv)));
-    store.register_late_pass(|| Box::new(operators::Operators));
+    store.register_late_pass(|| Box::new(operators::Operators::default()));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
diff --git a/clippy_lints/src/numeric_arithmetic.rs b/clippy_lints/src/numeric_arithmetic.rs
deleted file mode 100644
index 5c4de338149..00000000000
--- a/clippy_lints/src/numeric_arithmetic.rs
+++ /dev/null
@@ -1,170 +0,0 @@
-use clippy_utils::consts::constant_simple;
-use clippy_utils::diagnostics::span_lint;
-use rustc_hir as hir;
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::source_map::Span;
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for integer arithmetic operations which could overflow or panic.
-    ///
-    /// Specifically, checks for any operators (`+`, `-`, `*`, `<<`, etc) which are capable
-    /// of overflowing according to the [Rust
-    /// Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow),
-    /// or which can panic (`/`, `%`). No bounds analysis or sophisticated reasoning is
-    /// attempted.
-    ///
-    /// ### Why is this bad?
-    /// Integer overflow will trigger a panic in debug builds or will wrap in
-    /// release mode. Division by zero will cause a panic in either mode. In some applications one
-    /// wants explicitly checked, wrapping or saturating arithmetic.
-    ///
-    /// ### Example
-    /// ```rust
-    /// # let a = 0;
-    /// a + 1;
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub INTEGER_ARITHMETIC,
-    restriction,
-    "any integer arithmetic expression which could overflow or panic"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for float arithmetic.
-    ///
-    /// ### Why is this bad?
-    /// For some embedded systems or kernel development, it
-    /// can be useful to rule out floating-point numbers.
-    ///
-    /// ### Example
-    /// ```rust
-    /// # let a = 0.0;
-    /// a + 1.0;
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub FLOAT_ARITHMETIC,
-    restriction,
-    "any floating-point arithmetic statement"
-}
-
-#[derive(Copy, Clone, Default)]
-pub struct NumericArithmetic {
-    expr_span: Option<Span>,
-    /// This field is used to check whether expressions are constants, such as in enum discriminants
-    /// and consts
-    const_span: Option<Span>,
-}
-
-impl_lint_pass!(NumericArithmetic => [INTEGER_ARITHMETIC, FLOAT_ARITHMETIC]);
-
-impl<'tcx> LateLintPass<'tcx> for NumericArithmetic {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
-        if self.expr_span.is_some() {
-            return;
-        }
-
-        if let Some(span) = self.const_span {
-            if span.contains(expr.span) {
-                return;
-            }
-        }
-        match &expr.kind {
-            hir::ExprKind::Binary(op, l, r) | hir::ExprKind::AssignOp(op, l, r) => {
-                match op.node {
-                    hir::BinOpKind::And
-                    | hir::BinOpKind::Or
-                    | hir::BinOpKind::BitAnd
-                    | hir::BinOpKind::BitOr
-                    | hir::BinOpKind::BitXor
-                    | hir::BinOpKind::Eq
-                    | hir::BinOpKind::Lt
-                    | hir::BinOpKind::Le
-                    | hir::BinOpKind::Ne
-                    | hir::BinOpKind::Ge
-                    | hir::BinOpKind::Gt => return,
-                    _ => (),
-                }
-
-                let (l_ty, r_ty) = (cx.typeck_results().expr_ty(l), cx.typeck_results().expr_ty(r));
-                if l_ty.peel_refs().is_integral() && r_ty.peel_refs().is_integral() {
-                    match op.node {
-                        hir::BinOpKind::Div | hir::BinOpKind::Rem => match &r.kind {
-                            hir::ExprKind::Lit(_lit) => (),
-                            hir::ExprKind::Unary(hir::UnOp::Neg, expr) => {
-                                if let hir::ExprKind::Lit(lit) = &expr.kind {
-                                    if let rustc_ast::ast::LitKind::Int(1, _) = lit.node {
-                                        span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected");
-                                        self.expr_span = Some(expr.span);
-                                    }
-                                }
-                            },
-                            _ => {
-                                span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected");
-                                self.expr_span = Some(expr.span);
-                            },
-                        },
-                        _ => {
-                            span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected");
-                            self.expr_span = Some(expr.span);
-                        },
-                    }
-                } else if r_ty.peel_refs().is_floating_point() && r_ty.peel_refs().is_floating_point() {
-                    span_lint(cx, FLOAT_ARITHMETIC, expr.span, "floating-point arithmetic detected");
-                    self.expr_span = Some(expr.span);
-                }
-            },
-            hir::ExprKind::Unary(hir::UnOp::Neg, arg) => {
-                let ty = cx.typeck_results().expr_ty(arg);
-                if constant_simple(cx, cx.typeck_results(), expr).is_none() {
-                    if ty.is_integral() {
-                        span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected");
-                        self.expr_span = Some(expr.span);
-                    } else if ty.is_floating_point() {
-                        span_lint(cx, FLOAT_ARITHMETIC, expr.span, "floating-point arithmetic detected");
-                        self.expr_span = Some(expr.span);
-                    }
-                }
-            },
-            _ => (),
-        }
-    }
-
-    fn check_expr_post(&mut self, _: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
-        if Some(expr.span) == self.expr_span {
-            self.expr_span = None;
-        }
-    }
-
-    fn check_body(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) {
-        let body_owner = cx.tcx.hir().body_owner_def_id(body.id());
-
-        match cx.tcx.hir().body_owner_kind(body_owner) {
-            hir::BodyOwnerKind::Static(_) | hir::BodyOwnerKind::Const => {
-                let body_span = cx.tcx.def_span(body_owner);
-
-                if let Some(span) = self.const_span {
-                    if span.contains(body_span) {
-                        return;
-                    }
-                }
-                self.const_span = Some(body_span);
-            },
-            hir::BodyOwnerKind::Fn | hir::BodyOwnerKind::Closure => (),
-        }
-    }
-
-    fn check_body_post(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) {
-        let body_owner = cx.tcx.hir().body_owner(body.id());
-        let body_span = cx.tcx.hir().span(body_owner);
-
-        if let Some(span) = self.const_span {
-            if span.contains(body_span) {
-                return;
-            }
-        }
-        self.const_span = None;
-    }
-}
diff --git a/clippy_lints/src/operators/mod.rs b/clippy_lints/src/operators/mod.rs
index 6f5a1647277..a7495f042da 100644
--- a/clippy_lints/src/operators/mod.rs
+++ b/clippy_lints/src/operators/mod.rs
@@ -1,8 +1,9 @@
-use rustc_hir::{Expr, ExprKind};
+use rustc_hir::{Body, Expr, ExprKind, UnOp};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 
 mod absurd_extreme_comparisons;
+mod numeric_arithmetic;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -36,16 +37,90 @@ declare_clippy_lint! {
     "a comparison with a maximum or minimum value that is always true or false"
 }
 
-pub struct Operators;
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for integer arithmetic operations which could overflow or panic.
+    ///
+    /// Specifically, checks for any operators (`+`, `-`, `*`, `<<`, etc) which are capable
+    /// of overflowing according to the [Rust
+    /// Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow),
+    /// or which can panic (`/`, `%`). No bounds analysis or sophisticated reasoning is
+    /// attempted.
+    ///
+    /// ### Why is this bad?
+    /// Integer overflow will trigger a panic in debug builds or will wrap in
+    /// release mode. Division by zero will cause a panic in either mode. In some applications one
+    /// wants explicitly checked, wrapping or saturating arithmetic.
+    ///
+    /// ### Example
+    /// ```rust
+    /// # let a = 0;
+    /// a + 1;
+    /// ```
+    #[clippy::version = "pre 1.29.0"]
+    pub INTEGER_ARITHMETIC,
+    restriction,
+    "any integer arithmetic expression which could overflow or panic"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for float arithmetic.
+    ///
+    /// ### Why is this bad?
+    /// For some embedded systems or kernel development, it
+    /// can be useful to rule out floating-point numbers.
+    ///
+    /// ### Example
+    /// ```rust
+    /// # let a = 0.0;
+    /// a + 1.0;
+    /// ```
+    #[clippy::version = "pre 1.29.0"]
+    pub FLOAT_ARITHMETIC,
+    restriction,
+    "any floating-point arithmetic statement"
+}
+
+#[derive(Default)]
+pub struct Operators {
+    arithmetic_context: numeric_arithmetic::Context,
+}
 impl_lint_pass!(Operators => [
     ABSURD_EXTREME_COMPARISONS,
+    INTEGER_ARITHMETIC,
+    FLOAT_ARITHMETIC,
 ]);
 impl<'tcx> LateLintPass<'tcx> for Operators {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
-        if let ExprKind::Binary(op, lhs, rhs) = e.kind {
-            if !e.span.from_expansion() {
-                absurd_extreme_comparisons::check(cx, e, op.node, lhs, rhs);
-            }
+        match e.kind {
+            ExprKind::Binary(op, lhs, rhs) => {
+                if !e.span.from_expansion() {
+                    absurd_extreme_comparisons::check(cx, e, op.node, lhs, rhs);
+                }
+                self.arithmetic_context.check_binary(cx, e, op.node, lhs, rhs);
+            },
+            ExprKind::AssignOp(op, lhs, rhs) => {
+                self.arithmetic_context.check_binary(cx, e, op.node, lhs, rhs);
+            },
+            ExprKind::Unary(op, arg) => {
+                if op == UnOp::Neg {
+                    self.arithmetic_context.check_negate(cx, e, arg);
+                }
+            },
+            _ => (),
         }
     }
+
+    fn check_expr_post(&mut self, _: &LateContext<'_>, e: &Expr<'_>) {
+        self.arithmetic_context.expr_post(e.hir_id);
+    }
+
+    fn check_body(&mut self, cx: &LateContext<'tcx>, b: &'tcx Body<'_>) {
+        self.arithmetic_context.enter_body(cx, b);
+    }
+
+    fn check_body_post(&mut self, cx: &LateContext<'tcx>, b: &'tcx Body<'_>) {
+        self.arithmetic_context.body_post(cx, b);
+    }
 }
diff --git a/clippy_lints/src/operators/numeric_arithmetic.rs b/clippy_lints/src/operators/numeric_arithmetic.rs
new file mode 100644
index 00000000000..82f454d02f7
--- /dev/null
+++ b/clippy_lints/src/operators/numeric_arithmetic.rs
@@ -0,0 +1,127 @@
+use clippy_utils::consts::constant_simple;
+use clippy_utils::diagnostics::span_lint;
+use rustc_hir as hir;
+use rustc_lint::LateContext;
+use rustc_span::source_map::Span;
+
+use super::{FLOAT_ARITHMETIC, INTEGER_ARITHMETIC};
+
+#[derive(Default)]
+pub struct Context {
+    expr_id: Option<hir::HirId>,
+    /// This field is used to check whether expressions are constants, such as in enum discriminants
+    /// and consts
+    const_span: Option<Span>,
+}
+impl Context {
+    fn skip_expr(&mut self, e: &hir::Expr<'_>) -> bool {
+        self.expr_id.is_some() || self.const_span.map_or(false, |span| span.contains(e.span))
+    }
+
+    pub fn check_binary<'tcx>(
+        &mut self,
+        cx: &LateContext<'tcx>,
+        expr: &'tcx hir::Expr<'_>,
+        op: hir::BinOpKind,
+        l: &'tcx hir::Expr<'_>,
+        r: &'tcx hir::Expr<'_>,
+    ) {
+        if self.skip_expr(expr) {
+            return;
+        }
+        match op {
+            hir::BinOpKind::And
+            | hir::BinOpKind::Or
+            | hir::BinOpKind::BitAnd
+            | hir::BinOpKind::BitOr
+            | hir::BinOpKind::BitXor
+            | hir::BinOpKind::Eq
+            | hir::BinOpKind::Lt
+            | hir::BinOpKind::Le
+            | hir::BinOpKind::Ne
+            | hir::BinOpKind::Ge
+            | hir::BinOpKind::Gt => return,
+            _ => (),
+        }
+
+        let (l_ty, r_ty) = (cx.typeck_results().expr_ty(l), cx.typeck_results().expr_ty(r));
+        if l_ty.peel_refs().is_integral() && r_ty.peel_refs().is_integral() {
+            match op {
+                hir::BinOpKind::Div | hir::BinOpKind::Rem => match &r.kind {
+                    hir::ExprKind::Lit(_lit) => (),
+                    hir::ExprKind::Unary(hir::UnOp::Neg, expr) => {
+                        if let hir::ExprKind::Lit(lit) = &expr.kind {
+                            if let rustc_ast::ast::LitKind::Int(1, _) = lit.node {
+                                span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected");
+                                self.expr_id = Some(expr.hir_id);
+                            }
+                        }
+                    },
+                    _ => {
+                        span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected");
+                        self.expr_id = Some(expr.hir_id);
+                    },
+                },
+                _ => {
+                    span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected");
+                    self.expr_id = Some(expr.hir_id);
+                },
+            }
+        } else if r_ty.peel_refs().is_floating_point() && r_ty.peel_refs().is_floating_point() {
+            span_lint(cx, FLOAT_ARITHMETIC, expr.span, "floating-point arithmetic detected");
+            self.expr_id = Some(expr.hir_id);
+        }
+    }
+
+    pub fn check_negate<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, arg: &'tcx hir::Expr<'_>) {
+        if self.skip_expr(expr) {
+            return;
+        }
+        let ty = cx.typeck_results().expr_ty(arg);
+        if constant_simple(cx, cx.typeck_results(), expr).is_none() {
+            if ty.is_integral() {
+                span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected");
+                self.expr_id = Some(expr.hir_id);
+            } else if ty.is_floating_point() {
+                span_lint(cx, FLOAT_ARITHMETIC, expr.span, "floating-point arithmetic detected");
+                self.expr_id = Some(expr.hir_id);
+            }
+        }
+    }
+
+    pub fn expr_post(&mut self, id: hir::HirId) {
+        if Some(id) == self.expr_id {
+            self.expr_id = None;
+        }
+    }
+
+    pub fn enter_body(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) {
+        let body_owner = cx.tcx.hir().body_owner_def_id(body.id());
+
+        match cx.tcx.hir().body_owner_kind(body_owner) {
+            hir::BodyOwnerKind::Static(_) | hir::BodyOwnerKind::Const => {
+                let body_span = cx.tcx.def_span(body_owner);
+
+                if let Some(span) = self.const_span {
+                    if span.contains(body_span) {
+                        return;
+                    }
+                }
+                self.const_span = Some(body_span);
+            },
+            hir::BodyOwnerKind::Fn | hir::BodyOwnerKind::Closure => (),
+        }
+    }
+
+    pub fn body_post(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) {
+        let body_owner = cx.tcx.hir().body_owner(body.id());
+        let body_span = cx.tcx.hir().span(body_owner);
+
+        if let Some(span) = self.const_span {
+            if span.contains(body_span) {
+                return;
+            }
+        }
+        self.const_span = None;
+    }
+}