1 mod absurd_extreme_comparisons;
11 mod float_equality_without_abs;
14 mod misrefactored_assign_op;
15 mod modulo_arithmetic;
17 mod needless_bitwise_bool;
18 mod numeric_arithmetic;
24 pub(crate) mod arithmetic_side_effects;
26 use rustc_hir::{Body, Expr, ExprKind, UnOp};
27 use rustc_lint::{LateContext, LateLintPass};
28 use rustc_session::{declare_tool_lint, impl_lint_pass};
30 declare_clippy_lint! {
32 /// Checks for comparisons where one side of the relation is
33 /// either the minimum or maximum value for its type and warns if it involves a
34 /// case that is always true or always false. Only integer and boolean types are
37 /// ### Why is this bad?
38 /// An expression like `min <= x` may misleadingly imply
39 /// that it is possible for `x` to be less than the minimum. Expressions like
40 /// `max < x` are probably mistakes.
42 /// ### Known problems
43 /// For `usize` the size of the current compile target will
44 /// be assumed (e.g., 64 bits on 64 bit systems). This means code that uses such
45 /// a comparison to detect target pointer width will trigger this lint. One can
46 /// use `mem::sizeof` and compare its value or conditional compilation
48 /// like `#[cfg(target_pointer_width = "64")] ..` instead.
52 /// let vec: Vec<isize> = Vec::new();
53 /// if vec.len() <= 0 {}
54 /// if 100 > i32::MAX {}
56 #[clippy::version = "pre 1.29.0"]
57 pub ABSURD_EXTREME_COMPARISONS,
59 "a comparison with a maximum or minimum value that is always true or false"
62 declare_clippy_lint! {
64 /// Checks any kind of arithmetic operation of any type.
66 /// Operators like `+`, `-`, `*` or `<<` are usually capable of overflowing according to the [Rust
67 /// Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow),
68 /// or can panic (`/`, `%`).
70 /// Known safe built-in types like `Wrapping` or `Saturating`, floats, operations in constant
71 /// environments, allowed types and non-constant operations that won't overflow are ignored.
73 /// ### Why is this bad?
74 /// For integers, overflow will trigger a panic in debug builds or wrap the result in
75 /// release mode; division by zero will cause a panic in either mode. As a result, it is
76 /// desirable to explicitly call checked, wrapping or saturating arithmetic methods.
80 /// // `n` can be any number, including `i32::MAX`.
81 /// fn foo(n: i32) -> i32 {
86 /// Third-party types can also overflow or present unwanted side-effects.
90 /// use rust_decimal::Decimal;
91 /// let _n = Decimal::MAX + Decimal::MAX;
95 /// Custom allowed types can be specified through the "arithmetic-side-effects-allowed" filter.
96 #[clippy::version = "1.64.0"]
97 pub ARITHMETIC_SIDE_EFFECTS,
99 "any arithmetic expression that can cause side effects like overflows or panics"
102 declare_clippy_lint! {
104 /// Checks for integer arithmetic operations which could overflow or panic.
106 /// Specifically, checks for any operators (`+`, `-`, `*`, `<<`, etc) which are capable
107 /// of overflowing according to the [Rust
108 /// Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow),
109 /// or which can panic (`/`, `%`). No bounds analysis or sophisticated reasoning is
112 /// ### Why is this bad?
113 /// Integer overflow will trigger a panic in debug builds or will wrap in
114 /// release mode. Division by zero will cause a panic in either mode. In some applications one
115 /// wants explicitly checked, wrapping or saturating arithmetic.
122 #[clippy::version = "pre 1.29.0"]
123 pub INTEGER_ARITHMETIC,
125 "any integer arithmetic expression which could overflow or panic"
128 declare_clippy_lint! {
130 /// Checks for float arithmetic.
132 /// ### Why is this bad?
133 /// For some embedded systems or kernel development, it
134 /// can be useful to rule out floating-point numbers.
141 #[clippy::version = "pre 1.29.0"]
142 pub FLOAT_ARITHMETIC,
144 "any floating-point arithmetic statement"
147 declare_clippy_lint! {
149 /// Checks for `a = a op b` or `a = b commutative_op a`
152 /// ### Why is this bad?
153 /// These can be written as the shorter `a op= b`.
155 /// ### Known problems
156 /// While forbidden by the spec, `OpAssign` traits may have
157 /// implementations that differ from the regular `Op` impl.
176 #[clippy::version = "pre 1.29.0"]
177 pub ASSIGN_OP_PATTERN,
179 "assigning the result of an operation on a variable to that same variable"
182 declare_clippy_lint! {
184 /// Checks for `a op= a op b` or `a op= b op a` patterns.
186 /// ### Why is this bad?
187 /// Most likely these are bugs where one meant to write `a
190 /// ### Known problems
191 /// Clippy cannot know for sure if `a op= a op b` should have
192 /// been `a = a op a op b` or `a = a op b`/`a op= b`. Therefore, it suggests both.
193 /// If `a op= a op b` is really the correct behavior it should be
194 /// written as `a = a op a op b` as it's less confusing.
203 #[clippy::version = "pre 1.29.0"]
204 pub MISREFACTORED_ASSIGN_OP,
206 "having a variable on both sides of an assign op"
209 declare_clippy_lint! {
211 /// Checks for incompatible bit masks in comparisons.
213 /// The formula for detecting if an expression of the type `_ <bit_op> m
214 /// <cmp_op> c` (where `<bit_op>` is one of {`&`, `|`} and `<cmp_op>` is one of
215 /// {`!=`, `>=`, `>`, `!=`, `>=`, `>`}) can be determined from the following
218 /// |Comparison |Bit Op|Example |is always|Formula |
219 /// |------------|------|-------------|---------|----------------------|
220 /// |`==` or `!=`| `&` |`x & 2 == 3` |`false` |`c & m != c` |
221 /// |`<` or `>=`| `&` |`x & 2 < 3` |`true` |`m < c` |
222 /// |`>` or `<=`| `&` |`x & 1 > 1` |`false` |`m <= c` |
223 /// |`==` or `!=`| `\|` |`x \| 1 == 0`|`false` |`c \| m != c` |
224 /// |`<` or `>=`| `\|` |`x \| 1 < 1` |`false` |`m >= c` |
225 /// |`<=` or `>` | `\|` |`x \| 1 > 0` |`true` |`m > c` |
227 /// ### Why is this bad?
228 /// If the bits that the comparison cares about are always
229 /// set to zero or one by the bit mask, the comparison is constant `true` or
230 /// `false` (depending on mask, compared value, and operators).
232 /// So the code is actively misleading, and the only reason someone would write
233 /// this intentionally is to win an underhanded Rust contest or create a
234 /// test-case for this lint.
239 /// if (x & 1 == 2) { }
241 #[clippy::version = "pre 1.29.0"]
244 "expressions of the form `_ & mask == select` that will only ever return `true` or `false`"
247 declare_clippy_lint! {
249 /// Checks for bit masks in comparisons which can be removed
250 /// without changing the outcome. The basic structure can be seen in the
253 /// |Comparison| Bit Op |Example |equals |
254 /// |----------|----------|------------|-------|
255 /// |`>` / `<=`|`\|` / `^`|`x \| 2 > 3`|`x > 3`|
256 /// |`<` / `>=`|`\|` / `^`|`x ^ 1 < 4` |`x < 4`|
258 /// ### Why is this bad?
259 /// Not equally evil as [`bad_bit_mask`](#bad_bit_mask),
260 /// but still a bit misleading, because the bit mask is ineffective.
262 /// ### Known problems
263 /// False negatives: This lint will only match instances
264 /// where we have figured out the math (which is for a power-of-two compared
265 /// value). This means things like `x | 1 >= 7` (which would be better written
266 /// as `x >= 6`) will not be reported (but bit masks like this are fairly
272 /// if (x | 1 > 3) { }
274 #[clippy::version = "pre 1.29.0"]
275 pub INEFFECTIVE_BIT_MASK,
277 "expressions where a bit mask will be rendered useless by a comparison, e.g., `(x | 1) > 2`"
280 declare_clippy_lint! {
282 /// Checks for bit masks that can be replaced by a call
283 /// to `trailing_zeros`
285 /// ### Why is this bad?
286 /// `x.trailing_zeros() > 4` is much clearer than `x & 15
289 /// ### Known problems
290 /// llvm generates better code for `x & 15 == 0` on x86
295 /// if x & 0b1111 == 0 { }
297 #[clippy::version = "pre 1.29.0"]
298 pub VERBOSE_BIT_MASK,
300 "expressions where a bit mask is less readable than the corresponding method call"
303 declare_clippy_lint! {
305 /// Checks for double comparisons that could be simplified to a single expression.
308 /// ### Why is this bad?
315 /// if x == y || x < y {}
325 #[clippy::version = "pre 1.29.0"]
326 pub DOUBLE_COMPARISONS,
328 "unnecessary double comparisons that can be simplified"
331 declare_clippy_lint! {
333 /// Checks for calculation of subsecond microseconds or milliseconds
334 /// from other `Duration` methods.
336 /// ### Why is this bad?
337 /// It's more concise to call `Duration::subsec_micros()` or
338 /// `Duration::subsec_millis()` than to calculate them.
342 /// # use std::time::Duration;
343 /// # let duration = Duration::new(5, 0);
344 /// let micros = duration.subsec_nanos() / 1_000;
345 /// let millis = duration.subsec_nanos() / 1_000_000;
350 /// # use std::time::Duration;
351 /// # let duration = Duration::new(5, 0);
352 /// let micros = duration.subsec_micros();
353 /// let millis = duration.subsec_millis();
355 #[clippy::version = "pre 1.29.0"]
358 "checks for calculation of subsecond microseconds or milliseconds"
361 declare_clippy_lint! {
363 /// Checks for equal operands to comparison, logical and
364 /// bitwise, difference and division binary operators (`==`, `>`, etc., `&&`,
365 /// `||`, `&`, `|`, `^`, `-` and `/`).
367 /// ### Why is this bad?
368 /// This is usually just a typo or a copy and paste error.
370 /// ### Known problems
371 /// False negatives: We had some false positives regarding
372 /// calls (notably [racer](https://github.com/phildawes/racer) had one instance
373 /// of `x.pop() && x.pop()`), so we removed matching any function or method
374 /// calls. We may introduce a list of known pure functions in the future.
379 /// if x + 1 == x + 1 {}
385 /// assert_eq!(a, a);
387 #[clippy::version = "pre 1.29.0"]
390 "equal operands on both sides of a comparison or bitwise combination (e.g., `x == x`)"
393 declare_clippy_lint! {
395 /// Checks for arguments to `==` which have their address
396 /// taken to satisfy a bound
397 /// and suggests to dereference the other argument instead
399 /// ### Why is this bad?
400 /// It is more idiomatic to dereference the other argument.
411 #[clippy::version = "pre 1.29.0"]
414 "taking a reference to satisfy the type constraints on `==`"
417 declare_clippy_lint! {
419 /// Checks for erasing operations, e.g., `x * 0`.
421 /// ### Why is this bad?
422 /// The whole expression can be replaced by zero.
423 /// This is most likely not the intended outcome and should probably be
433 #[clippy::version = "pre 1.29.0"]
436 "using erasing operations, e.g., `x * 0` or `y & 0`"
439 declare_clippy_lint! {
441 /// Checks for statements of the form `(a - b) < f32::EPSILON` or
442 /// `(a - b) < f64::EPSILON`. Notes the missing `.abs()`.
444 /// ### Why is this bad?
445 /// The code without `.abs()` is more likely to have a bug.
447 /// ### Known problems
448 /// If the user can ensure that b is larger than a, the `.abs()` is
449 /// technically unnecessary. However, it will make the code more robust and doesn't have any
450 /// large performance implications. If the abs call was deliberately left out for performance
451 /// reasons, it is probably better to state this explicitly in the code, which then can be done
456 /// pub fn is_roughly_equal(a: f32, b: f32) -> bool {
457 /// (a - b) < f32::EPSILON
462 /// pub fn is_roughly_equal(a: f32, b: f32) -> bool {
463 /// (a - b).abs() < f32::EPSILON
466 #[clippy::version = "1.48.0"]
467 pub FLOAT_EQUALITY_WITHOUT_ABS,
469 "float equality check without `.abs()`"
472 declare_clippy_lint! {
474 /// Checks for identity operations, e.g., `x + 0`.
476 /// ### Why is this bad?
477 /// This code can be removed without changing the
478 /// meaning. So it just obscures what's going on. Delete it mercilessly.
483 /// x / 1 + 0 * 1 - 0 | 0;
485 #[clippy::version = "pre 1.29.0"]
488 "using identity operations, e.g., `x + 0` or `y / 1`"
491 declare_clippy_lint! {
493 /// Checks for division of integers
495 /// ### Why is this bad?
496 /// When outside of some very specific algorithms,
497 /// integer division is very often a mistake because it discards the
503 /// println!("{}", x);
508 /// let x = 3f32 / 2f32;
509 /// println!("{}", x);
511 #[clippy::version = "1.37.0"]
512 pub INTEGER_DIVISION,
514 "integer division may cause loss of precision"
517 declare_clippy_lint! {
519 /// Checks for comparisons to NaN.
521 /// ### Why is this bad?
522 /// NaN does not compare meaningfully to anything – not
523 /// even itself – so those comparisons are simply wrong.
528 /// if x == f32::NAN { }
533 /// # let x = 1.0f32;
534 /// if x.is_nan() { }
536 #[clippy::version = "pre 1.29.0"]
539 "comparisons to `NAN`, which will always return false, probably not intended"
542 declare_clippy_lint! {
544 /// Checks for conversions to owned values just for the sake
547 /// ### Why is this bad?
548 /// The comparison can operate on a reference, so creating
549 /// an owned value effectively throws it away directly afterwards, which is
550 /// needlessly consuming code and heap space.
555 /// # let y = String::from("foo");
556 /// if x.to_owned() == y {}
562 /// # let y = String::from("foo");
565 #[clippy::version = "pre 1.29.0"]
568 "creating owned instances for comparing with others, e.g., `x == \"foo\".to_string()`"
571 declare_clippy_lint! {
573 /// Checks for (in-)equality comparisons on floating-point
574 /// values (apart from zero), except in functions called `*eq*` (which probably
575 /// implement equality for a type involving floats).
577 /// ### Why is this bad?
578 /// Floating point calculations are usually imprecise, so
579 /// asking if two values are *exactly* equal is asking for trouble. For a good
580 /// guide on what to do, see [the floating point
581 /// guide](http://www.floating-point-gui.de/errors/comparison).
585 /// let x = 1.2331f64;
586 /// let y = 1.2332f64;
588 /// if y == 1.23f64 { }
589 /// if y != x {} // where both are floats
594 /// # let x = 1.2331f64;
595 /// # let y = 1.2332f64;
596 /// let error_margin = f64::EPSILON; // Use an epsilon for comparison
597 /// // Or, if Rust <= 1.42, use `std::f64::EPSILON` constant instead.
598 /// // let error_margin = std::f64::EPSILON;
599 /// if (y - 1.23f64).abs() < error_margin { }
600 /// if (y - x).abs() > error_margin { }
602 #[clippy::version = "pre 1.29.0"]
605 "using `==` or `!=` on float values instead of comparing difference with an epsilon"
608 declare_clippy_lint! {
610 /// Checks for (in-)equality comparisons on floating-point
611 /// value and constant, except in functions called `*eq*` (which probably
612 /// implement equality for a type involving floats).
614 /// ### Why is this bad?
615 /// Floating point calculations are usually imprecise, so
616 /// asking if two values are *exactly* equal is asking for trouble. For a good
617 /// guide on what to do, see [the floating point
618 /// guide](http://www.floating-point-gui.de/errors/comparison).
622 /// let x: f64 = 1.0;
623 /// const ONE: f64 = 1.00;
625 /// if x == ONE { } // where both are floats
630 /// # let x: f64 = 1.0;
631 /// # const ONE: f64 = 1.00;
632 /// let error_margin = f64::EPSILON; // Use an epsilon for comparison
633 /// // Or, if Rust <= 1.42, use `std::f64::EPSILON` constant instead.
634 /// // let error_margin = std::f64::EPSILON;
635 /// if (x - ONE).abs() < error_margin { }
637 #[clippy::version = "pre 1.29.0"]
640 "using `==` or `!=` on float constants instead of comparing difference with an epsilon"
643 declare_clippy_lint! {
645 /// Checks for getting the remainder of a division by one or minus
648 /// ### Why is this bad?
649 /// The result for a divisor of one can only ever be zero; for
650 /// minus one it can cause panic/overflow (if the left operand is the minimal value of
651 /// the respective integer type) or results in zero. No one will write such code
652 /// deliberately, unless trying to win an Underhanded Rust Contest. Even for that
653 /// contest, it's probably a bad idea. Use something more underhanded.
661 #[clippy::version = "pre 1.29.0"]
664 "taking a number modulo +/-1, which can either panic/overflow or always returns 0"
667 declare_clippy_lint! {
669 /// Checks for modulo arithmetic.
671 /// ### Why is this bad?
672 /// The results of modulo (%) operation might differ
673 /// depending on the language, when negative numbers are involved.
674 /// If you interop with different languages it might be beneficial
675 /// to double check all places that use modulo arithmetic.
677 /// For example, in Rust `17 % -3 = 2`, but in Python `17 % -3 = -1`.
683 #[clippy::version = "1.42.0"]
684 pub MODULO_ARITHMETIC,
686 "any modulo arithmetic statement"
689 declare_clippy_lint! {
691 /// Checks for uses of bitwise and/or operators between booleans, where performance may be improved by using
694 /// ### Why is this bad?
695 /// The bitwise operators do not support short-circuiting, so it may hinder code performance.
696 /// Additionally, boolean logic "masked" as bitwise logic is not caught by lints like `unnecessary_fold`
698 /// ### Known problems
699 /// This lint evaluates only when the right side is determined to have no side effects. At this time, that
700 /// determination is quite conservative.
704 /// let (x,y) = (true, false);
705 /// if x & !y {} // where both x and y are booleans
709 /// let (x,y) = (true, false);
712 #[clippy::version = "1.54.0"]
713 pub NEEDLESS_BITWISE_BOOL,
715 "Boolean expressions that use bitwise rather than lazy operators"
718 declare_clippy_lint! {
720 /// Use `std::ptr::eq` when applicable
722 /// ### Why is this bad?
723 /// `ptr::eq` can be used to compare `&T` references
724 /// (which coerce to `*const T` implicitly) by their address rather than
725 /// comparing the values they point to.
729 /// let a = &[1, 2, 3];
730 /// let b = &[1, 2, 3];
732 /// assert!(a as *const _ as usize == b as *const _ as usize);
736 /// let a = &[1, 2, 3];
737 /// let b = &[1, 2, 3];
739 /// assert!(std::ptr::eq(a, b));
741 #[clippy::version = "1.49.0"]
744 "use `std::ptr::eq` when comparing raw pointers"
747 declare_clippy_lint! {
749 /// Checks for explicit self-assignments.
751 /// ### Why is this bad?
752 /// Self-assignments are redundant and unlikely to be
755 /// ### Known problems
756 /// If expression contains any deref coercions or
757 /// indexing operations they are assumed not to have any side effects.
765 /// fn copy_position(a: &mut Event, b: &Event) {
776 /// fn copy_position(a: &mut Event, b: &Event) {
780 #[clippy::version = "1.48.0"]
783 "explicit self-assignment"
786 pub struct Operators {
787 arithmetic_context: numeric_arithmetic::Context,
788 verbose_bit_mask_threshold: u64,
790 impl_lint_pass!(Operators => [
791 ABSURD_EXTREME_COMPARISONS,
792 ARITHMETIC_SIDE_EFFECTS,
796 MISREFACTORED_ASSIGN_OP,
798 INEFFECTIVE_BIT_MASK,
805 FLOAT_EQUALITY_WITHOUT_ABS,
814 NEEDLESS_BITWISE_BOOL,
819 pub fn new(verbose_bit_mask_threshold: u64) -> Self {
821 arithmetic_context: numeric_arithmetic::Context::default(),
822 verbose_bit_mask_threshold,
826 impl<'tcx> LateLintPass<'tcx> for Operators {
827 fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
828 eq_op::check_assert(cx, e);
830 ExprKind::Binary(op, lhs, rhs) => {
831 if !e.span.from_expansion() {
832 absurd_extreme_comparisons::check(cx, e, op.node, lhs, rhs);
833 if !(macro_with_not_op(lhs) || macro_with_not_op(rhs)) {
834 eq_op::check(cx, e, op.node, lhs, rhs);
835 op_ref::check(cx, e, op.node, lhs, rhs);
837 erasing_op::check(cx, e, op.node, lhs, rhs);
838 identity_op::check(cx, e, op.node, lhs, rhs);
839 needless_bitwise_bool::check(cx, e, op.node, lhs, rhs);
840 ptr_eq::check(cx, e, op.node, lhs, rhs);
842 self.arithmetic_context.check_binary(cx, e, op.node, lhs, rhs);
843 bit_mask::check(cx, e, op.node, lhs, rhs);
844 verbose_bit_mask::check(cx, e, op.node, lhs, rhs, self.verbose_bit_mask_threshold);
845 double_comparison::check(cx, op.node, lhs, rhs, e.span);
846 duration_subsec::check(cx, e, op.node, lhs, rhs);
847 float_equality_without_abs::check(cx, e, op.node, lhs, rhs);
848 integer_division::check(cx, e, op.node, lhs, rhs);
849 cmp_nan::check(cx, e, op.node, lhs, rhs);
850 cmp_owned::check(cx, op.node, lhs, rhs);
851 float_cmp::check(cx, e, op.node, lhs, rhs);
852 modulo_one::check(cx, e, op.node, rhs);
853 modulo_arithmetic::check(cx, e, op.node, lhs, rhs);
855 ExprKind::AssignOp(op, lhs, rhs) => {
856 self.arithmetic_context.check_binary(cx, e, op.node, lhs, rhs);
857 misrefactored_assign_op::check(cx, e, op.node, lhs, rhs);
858 modulo_arithmetic::check(cx, e, op.node, lhs, rhs);
860 ExprKind::Assign(lhs, rhs, _) => {
861 assign_op_pattern::check(cx, e, lhs, rhs);
862 self_assignment::check(cx, e, lhs, rhs);
864 ExprKind::Unary(op, arg) => {
866 self.arithmetic_context.check_negate(cx, e, arg);
873 fn check_expr_post(&mut self, _: &LateContext<'_>, e: &Expr<'_>) {
874 self.arithmetic_context.expr_post(e.hir_id);
877 fn check_body(&mut self, cx: &LateContext<'tcx>, b: &'tcx Body<'_>) {
878 self.arithmetic_context.enter_body(cx, b);
881 fn check_body_post(&mut self, cx: &LateContext<'tcx>, b: &'tcx Body<'_>) {
882 self.arithmetic_context.body_post(cx, b);
886 fn macro_with_not_op(e: &Expr<'_>) -> bool {
887 if let ExprKind::Unary(_, e) = e.kind {
888 e.span.from_expansion()