| mod absurd_extreme_comparisons; |
| mod assign_op_pattern; |
| mod bit_mask; |
| mod cmp_owned; |
| mod const_comparisons; |
| mod double_comparison; |
| mod duration_subsec; |
| mod eq_op; |
| mod erasing_op; |
| mod float_cmp; |
| mod float_equality_without_abs; |
| mod identity_op; |
| mod integer_division; |
| mod manual_is_multiple_of; |
| mod manual_midpoint; |
| mod misrefactored_assign_op; |
| mod modulo_arithmetic; |
| mod modulo_one; |
| mod needless_bitwise_bool; |
| mod numeric_arithmetic; |
| mod op_ref; |
| mod self_assignment; |
| mod verbose_bit_mask; |
| |
| pub(crate) mod arithmetic_side_effects; |
| |
| use clippy_config::Conf; |
| use clippy_utils::msrvs::Msrv; |
| use rustc_hir::{Body, Expr, ExprKind, UnOp}; |
| use rustc_lint::{LateContext, LateLintPass}; |
| use rustc_session::impl_lint_pass; |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for comparisons where one side of the relation is |
| /// either the minimum or maximum value for its type and warns if it involves a |
| /// case that is always true or always false. Only integer and boolean types are |
| /// checked. |
| /// |
| /// ### Why is this bad? |
| /// An expression like `min <= x` may misleadingly imply |
| /// that it is possible for `x` to be less than the minimum. Expressions like |
| /// `max < x` are probably mistakes. |
| /// |
| /// ### Known problems |
| /// For `usize` the size of the current compile target will |
| /// be assumed (e.g., 64 bits on 64 bit systems). This means code that uses such |
| /// a comparison to detect target pointer width will trigger this lint. One can |
| /// use `mem::sizeof` and compare its value or conditional compilation |
| /// attributes |
| /// like `#[cfg(target_pointer_width = "64")] ..` instead. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// let vec: Vec<isize> = Vec::new(); |
| /// if vec.len() <= 0 {} |
| /// if 100 > i32::MAX {} |
| /// ``` |
| #[clippy::version = "pre 1.29.0"] |
| pub ABSURD_EXTREME_COMPARISONS, |
| correctness, |
| "a comparison with a maximum or minimum value that is always true or false" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks any kind of arithmetic operation of any type. |
| /// |
| /// Operators like `+`, `-`, `*` or `<<` are usually capable of overflowing according to the [Rust |
| /// Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow), |
| /// or can panic (`/`, `%`). |
| /// |
| /// Known safe built-in types like `Wrapping` or `Saturating`, floats, operations in constant |
| /// environments, allowed types and non-constant operations that won't overflow are ignored. |
| /// |
| /// ### Why restrict this? |
| /// For integers, overflow will trigger a panic in debug builds or wrap the result in |
| /// release mode; division by zero will cause a panic in either mode. As a result, it is |
| /// desirable to explicitly call checked, wrapping or saturating arithmetic methods. |
| /// |
| /// #### Example |
| /// ```no_run |
| /// // `n` can be any number, including `i32::MAX`. |
| /// fn foo(n: i32) -> i32 { |
| /// n + 1 |
| /// } |
| /// ``` |
| /// |
| /// Third-party types can also overflow or present unwanted side-effects. |
| /// |
| /// #### Example |
| /// ```ignore,rust |
| /// use rust_decimal::Decimal; |
| /// let _n = Decimal::MAX + Decimal::MAX; |
| /// ``` |
| #[clippy::version = "1.64.0"] |
| pub ARITHMETIC_SIDE_EFFECTS, |
| restriction, |
| "any arithmetic expression that can cause side effects like overflows or panics" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for float arithmetic. |
| /// |
| /// ### Why restrict this? |
| /// For some embedded systems or kernel development, it |
| /// can be useful to rule out floating-point numbers. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// # let a = 0.0; |
| /// a + 1.0; |
| /// ``` |
| #[clippy::version = "pre 1.29.0"] |
| pub FLOAT_ARITHMETIC, |
| restriction, |
| "any floating-point arithmetic statement" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for `a = a op b` or `a = b commutative_op a` |
| /// patterns. |
| /// |
| /// ### Why is this bad? |
| /// These can be written as the shorter `a op= b`. |
| /// |
| /// ### Known problems |
| /// While forbidden by the spec, `OpAssign` traits may have |
| /// implementations that differ from the regular `Op` impl. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// let mut a = 5; |
| /// let b = 0; |
| /// // ... |
| /// |
| /// a = a + b; |
| /// ``` |
| /// |
| /// Use instead: |
| /// ```no_run |
| /// let mut a = 5; |
| /// let b = 0; |
| /// // ... |
| /// |
| /// a += b; |
| /// ``` |
| #[clippy::version = "pre 1.29.0"] |
| pub ASSIGN_OP_PATTERN, |
| style, |
| "assigning the result of an operation on a variable to that same variable" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for `a op= a op b` or `a op= b op a` patterns. |
| /// |
| /// ### Why is this bad? |
| /// Most likely these are bugs where one meant to write `a |
| /// op= b`. |
| /// |
| /// ### Known problems |
| /// Clippy cannot know for sure if `a op= a op b` should have |
| /// been `a = a op a op b` or `a = a op b`/`a op= b`. Therefore, it suggests both. |
| /// If `a op= a op b` is really the correct behavior it should be |
| /// written as `a = a op a op b` as it's less confusing. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// let mut a = 5; |
| /// let b = 2; |
| /// // ... |
| /// a += a + b; |
| /// ``` |
| #[clippy::version = "pre 1.29.0"] |
| pub MISREFACTORED_ASSIGN_OP, |
| suspicious, |
| "having a variable on both sides of an assign op" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for incompatible bit masks in comparisons. |
| /// |
| /// The formula for detecting if an expression of the type `_ <bit_op> m |
| /// <cmp_op> c` (where `<bit_op>` is one of {`&`, `|`} and `<cmp_op>` is one of |
| /// {`!=`, `>=`, `>`, `!=`, `>=`, `>`}) can be determined from the following |
| /// table: |
| /// |
| /// |Comparison |Bit Op|Example |is always|Formula | |
| /// |------------|------|-------------|---------|----------------------| |
| /// |`==` or `!=`| `&` |`x & 2 == 3` |`false` |`c & m != c` | |
| /// |`<` or `>=`| `&` |`x & 2 < 3` |`true` |`m < c` | |
| /// |`>` or `<=`| `&` |`x & 1 > 1` |`false` |`m <= c` | |
| /// |`==` or `!=`| `\|` |`x \| 1 == 0`|`false` |`c \| m != c` | |
| /// |`<` or `>=`| `\|` |`x \| 1 < 1` |`false` |`m >= c` | |
| /// |`<=` or `>` | `\|` |`x \| 1 > 0` |`true` |`m > c` | |
| /// |
| /// ### Why is this bad? |
| /// If the bits that the comparison cares about are always |
| /// set to zero or one by the bit mask, the comparison is constant `true` or |
| /// `false` (depending on mask, compared value, and operators). |
| /// |
| /// So the code is actively misleading, and the only reason someone would write |
| /// this intentionally is to win an underhanded Rust contest or create a |
| /// test-case for this lint. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// # let x = 1; |
| /// if (x & 1 == 2) { } |
| /// ``` |
| #[clippy::version = "pre 1.29.0"] |
| pub BAD_BIT_MASK, |
| correctness, |
| "expressions of the form `_ & mask == select` that will only ever return `true` or `false`" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for bit masks in comparisons which can be removed |
| /// without changing the outcome. The basic structure can be seen in the |
| /// following table: |
| /// |
| /// |Comparison| Bit Op |Example |equals | |
| /// |----------|----------|------------|-------| |
| /// |`>` / `<=`|`\|` / `^`|`x \| 2 > 3`|`x > 3`| |
| /// |`<` / `>=`|`\|` / `^`|`x ^ 1 < 4` |`x < 4`| |
| /// |
| /// ### Why is this bad? |
| /// Not equally evil as [`bad_bit_mask`](#bad_bit_mask), |
| /// but still a bit misleading, because the bit mask is ineffective. |
| /// |
| /// ### Known problems |
| /// False negatives: This lint will only match instances |
| /// where we have figured out the math (which is for a power-of-two compared |
| /// value). This means things like `x | 1 >= 7` (which would be better written |
| /// as `x >= 6`) will not be reported (but bit masks like this are fairly |
| /// uncommon). |
| /// |
| /// ### Example |
| /// ```no_run |
| /// # let x = 1; |
| /// if (x | 1 > 3) { } |
| /// ``` |
| /// |
| /// Use instead: |
| /// |
| /// ```no_run |
| /// # let x = 1; |
| /// if (x >= 2) { } |
| /// ``` |
| #[clippy::version = "pre 1.29.0"] |
| pub INEFFECTIVE_BIT_MASK, |
| correctness, |
| "expressions where a bit mask will be rendered useless by a comparison, e.g., `(x | 1) > 2`" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for bit masks that can be replaced by a call |
| /// to `trailing_zeros` |
| /// |
| /// ### Why is this bad? |
| /// `x.trailing_zeros() >= 4` is much clearer than `x & 15 |
| /// == 0` |
| /// |
| /// ### Example |
| /// ```no_run |
| /// # let x = 1; |
| /// if x & 0b1111 == 0 { } |
| /// ``` |
| /// |
| /// Use instead: |
| /// |
| /// ```no_run |
| /// # let x: i32 = 1; |
| /// if x.trailing_zeros() >= 4 { } |
| /// ``` |
| #[clippy::version = "pre 1.29.0"] |
| pub VERBOSE_BIT_MASK, |
| pedantic, |
| "expressions where a bit mask is less readable than the corresponding method call" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for double comparisons that could be simplified to a single expression. |
| /// |
| /// |
| /// ### Why is this bad? |
| /// Readability. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// # let x = 1; |
| /// # let y = 2; |
| /// if x == y || x < y {} |
| /// ``` |
| /// |
| /// Use instead: |
| /// |
| /// ```no_run |
| /// # let x = 1; |
| /// # let y = 2; |
| /// if x <= y {} |
| /// ``` |
| #[clippy::version = "pre 1.29.0"] |
| pub DOUBLE_COMPARISONS, |
| complexity, |
| "unnecessary double comparisons that can be simplified" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for double comparisons that can never succeed |
| /// |
| /// ### Why is this bad? |
| /// The whole expression can be replaced by `false`, |
| /// which is probably not the programmer's intention |
| /// |
| /// ### Example |
| /// ```no_run |
| /// # let status_code = 200; |
| /// if status_code <= 400 && status_code > 500 {} |
| /// ``` |
| #[clippy::version = "1.73.0"] |
| pub IMPOSSIBLE_COMPARISONS, |
| correctness, |
| "double comparisons that will never evaluate to `true`" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for ineffective double comparisons against constants. |
| /// |
| /// ### Why is this bad? |
| /// Only one of the comparisons has any effect on the result, the programmer |
| /// probably intended to flip one of the comparison operators, or compare a |
| /// different value entirely. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// # let status_code = 200; |
| /// if status_code <= 400 && status_code < 500 {} |
| /// ``` |
| #[clippy::version = "1.73.0"] |
| pub REDUNDANT_COMPARISONS, |
| correctness, |
| "double comparisons where one of them can be removed" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for calculation of subsecond microseconds or milliseconds |
| /// from other `Duration` methods. |
| /// |
| /// ### Why is this bad? |
| /// It's more concise to call `Duration::subsec_micros()` or |
| /// `Duration::subsec_millis()` than to calculate them. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// # use std::time::Duration; |
| /// # let duration = Duration::new(5, 0); |
| /// let micros = duration.subsec_nanos() / 1_000; |
| /// let millis = duration.subsec_nanos() / 1_000_000; |
| /// ``` |
| /// |
| /// Use instead: |
| /// ```no_run |
| /// # use std::time::Duration; |
| /// # let duration = Duration::new(5, 0); |
| /// let micros = duration.subsec_micros(); |
| /// let millis = duration.subsec_millis(); |
| /// ``` |
| #[clippy::version = "pre 1.29.0"] |
| pub DURATION_SUBSEC, |
| complexity, |
| "checks for calculation of subsecond microseconds or milliseconds" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for equal operands to comparison, logical and |
| /// bitwise, difference and division binary operators (`==`, `>`, etc., `&&`, |
| /// `||`, `&`, `|`, `^`, `-` and `/`). |
| /// |
| /// ### Why is this bad? |
| /// This is usually just a typo or a copy and paste error. |
| /// |
| /// ### Known problems |
| /// False negatives: We had some false positives regarding |
| /// calls (notably [racer](https://github.com/phildawes/racer) had one instance |
| /// of `x.pop() && x.pop()`), so we removed matching any function or method |
| /// calls. We may introduce a list of known pure functions in the future. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// # let x = 1; |
| /// if x + 1 == x + 1 {} |
| /// |
| /// // or |
| /// |
| /// # let a = 3; |
| /// # let b = 4; |
| /// assert_eq!(a, a); |
| /// ``` |
| #[clippy::version = "pre 1.29.0"] |
| pub EQ_OP, |
| correctness, |
| "equal operands on both sides of a comparison or bitwise combination (e.g., `x == x`)" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for arguments to `==` which have their address |
| /// taken to satisfy a bound |
| /// and suggests to dereference the other argument instead |
| /// |
| /// ### Why is this bad? |
| /// It is more idiomatic to dereference the other argument. |
| /// |
| /// ### Example |
| /// ```rust,ignore |
| /// &x == y |
| /// ``` |
| /// |
| /// Use instead: |
| /// ```rust,ignore |
| /// x == *y |
| /// ``` |
| #[clippy::version = "pre 1.29.0"] |
| pub OP_REF, |
| style, |
| "taking a reference to satisfy the type constraints on `==`" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for erasing operations, e.g., `x * 0`. |
| /// |
| /// ### Why is this bad? |
| /// The whole expression can be replaced by zero. |
| /// This is most likely not the intended outcome and should probably be |
| /// corrected |
| /// |
| /// ### Example |
| /// ```no_run |
| /// let x = 1; |
| /// 0 / x; |
| /// 0 * x; |
| /// x & 0; |
| /// ``` |
| #[clippy::version = "pre 1.29.0"] |
| pub ERASING_OP, |
| correctness, |
| "using erasing operations, e.g., `x * 0` or `y & 0`" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for statements of the form `(a - b) < f32::EPSILON` or |
| /// `(a - b) < f64::EPSILON`. Notes the missing `.abs()`. |
| /// |
| /// ### Why is this bad? |
| /// The code without `.abs()` is more likely to have a bug. |
| /// |
| /// ### Known problems |
| /// If the user can ensure that b is larger than a, the `.abs()` is |
| /// technically unnecessary. However, it will make the code more robust and doesn't have any |
| /// large performance implications. If the abs call was deliberately left out for performance |
| /// reasons, it is probably better to state this explicitly in the code, which then can be done |
| /// with an allow. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// pub fn is_roughly_equal(a: f32, b: f32) -> bool { |
| /// (a - b) < f32::EPSILON |
| /// } |
| /// ``` |
| /// Use instead: |
| /// ```no_run |
| /// pub fn is_roughly_equal(a: f32, b: f32) -> bool { |
| /// (a - b).abs() < f32::EPSILON |
| /// } |
| /// ``` |
| #[clippy::version = "1.48.0"] |
| pub FLOAT_EQUALITY_WITHOUT_ABS, |
| suspicious, |
| "float equality check without `.abs()`" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for identity operations, e.g., `x + 0`. |
| /// |
| /// ### Why is this bad? |
| /// This code can be removed without changing the |
| /// meaning. So it just obscures what's going on. Delete it mercilessly. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// # let x = 1; |
| /// x / 1 + 0 * 1 - 0 | 0; |
| /// ``` |
| #[clippy::version = "pre 1.29.0"] |
| pub IDENTITY_OP, |
| complexity, |
| "using identity operations, e.g., `x + 0` or `y / 1`" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for division of integers |
| /// |
| /// ### Why restrict this? |
| /// When outside of some very specific algorithms, |
| /// integer division is very often a mistake because it discards the |
| /// remainder. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// let x = 3 / 2; |
| /// println!("{}", x); |
| /// ``` |
| /// |
| /// Use instead: |
| /// ```no_run |
| /// let x = 3f32 / 2f32; |
| /// println!("{}", x); |
| /// ``` |
| #[clippy::version = "1.37.0"] |
| pub INTEGER_DIVISION, |
| restriction, |
| "integer division may cause loss of precision" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for conversions to owned values just for the sake |
| /// of a comparison. |
| /// |
| /// ### Why is this bad? |
| /// The comparison can operate on a reference, so creating |
| /// an owned value effectively throws it away directly afterwards, which is |
| /// needlessly consuming code and heap space. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// # let x = "foo"; |
| /// # let y = String::from("foo"); |
| /// if x.to_owned() == y {} |
| /// ``` |
| /// |
| /// Use instead: |
| /// ```no_run |
| /// # let x = "foo"; |
| /// # let y = String::from("foo"); |
| /// if x == y {} |
| /// ``` |
| #[clippy::version = "pre 1.29.0"] |
| pub CMP_OWNED, |
| perf, |
| "creating owned instances for comparing with others, e.g., `x == \"foo\".to_string()`" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for (in-)equality comparisons on floating-point |
| /// values (apart from zero), except in functions called `*eq*` (which probably |
| /// implement equality for a type involving floats). |
| /// |
| /// ### Why is this bad? |
| /// Floating point calculations are usually imprecise, so asking if two values are *exactly* |
| /// equal is asking for trouble because arriving at the same logical result via different |
| /// routes (e.g. calculation versus constant) may yield different values. |
| /// |
| /// ### Example |
| /// |
| /// ```no_run |
| /// let a: f64 = 1000.1; |
| /// let b: f64 = 0.2; |
| /// let x = a + b; |
| /// let y = 1000.3; // Expected value. |
| /// |
| /// // Actual value: 1000.3000000000001 |
| /// println!("{x}"); |
| /// |
| /// let are_equal = x == y; |
| /// println!("{are_equal}"); // false |
| /// ``` |
| /// |
| /// The correct way to compare floating point numbers is to define an allowed error margin. This |
| /// may be challenging if there is no "natural" error margin to permit. Broadly speaking, there |
| /// are two cases: |
| /// |
| /// 1. If your values are in a known range and you can define a threshold for "close enough to |
| /// be equal", it may be appropriate to define an absolute error margin. For example, if your |
| /// data is "length of vehicle in centimeters", you may consider 0.1 cm to be "close enough". |
| /// 1. If your code is more general and you do not know the range of values, you should use a |
| /// relative error margin, accepting e.g. 0.1% of error regardless of specific values. |
| /// |
| /// For the scenario where you can define a meaningful absolute error margin, consider using: |
| /// |
| /// ```no_run |
| /// let a: f64 = 1000.1; |
| /// let b: f64 = 0.2; |
| /// let x = a + b; |
| /// let y = 1000.3; // Expected value. |
| /// |
| /// const ALLOWED_ERROR_VEHICLE_LENGTH_CM: f64 = 0.1; |
| /// let within_tolerance = (x - y).abs() < ALLOWED_ERROR_VEHICLE_LENGTH_CM; |
| /// println!("{within_tolerance}"); // true |
| /// ``` |
| /// |
| /// NB! Do not use `f64::EPSILON` - while the error margin is often called "epsilon", this is |
| /// a different use of the term that is not suitable for floating point equality comparison. |
| /// Indeed, for the example above using `f64::EPSILON` as the allowed error would return `false`. |
| /// |
| /// For the scenario where no meaningful absolute error can be defined, refer to |
| /// [the floating point guide](https://www.floating-point-gui.de/errors/comparison) |
| /// for a reference implementation of relative error based comparison of floating point values. |
| /// `MIN_NORMAL` in the reference implementation is equivalent to `MIN_POSITIVE` in Rust. |
| #[clippy::version = "pre 1.29.0"] |
| pub FLOAT_CMP, |
| pedantic, |
| "using `==` or `!=` on float values instead of comparing difference with an allowed error" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for (in-)equality comparisons on constant floating-point |
| /// values (apart from zero), except in functions called `*eq*` (which probably |
| /// implement equality for a type involving floats). |
| /// |
| /// ### Why restrict this? |
| /// Floating point calculations are usually imprecise, so asking if two values are *exactly* |
| /// equal is asking for trouble because arriving at the same logical result via different |
| /// routes (e.g. calculation versus constant) may yield different values. |
| /// |
| /// ### Example |
| /// |
| /// ```no_run |
| /// let a: f64 = 1000.1; |
| /// let b: f64 = 0.2; |
| /// let x = a + b; |
| /// const Y: f64 = 1000.3; // Expected value. |
| /// |
| /// // Actual value: 1000.3000000000001 |
| /// println!("{x}"); |
| /// |
| /// let are_equal = x == Y; |
| /// println!("{are_equal}"); // false |
| /// ``` |
| /// |
| /// The correct way to compare floating point numbers is to define an allowed error margin. This |
| /// may be challenging if there is no "natural" error margin to permit. Broadly speaking, there |
| /// are two cases: |
| /// |
| /// 1. If your values are in a known range and you can define a threshold for "close enough to |
| /// be equal", it may be appropriate to define an absolute error margin. For example, if your |
| /// data is "length of vehicle in centimeters", you may consider 0.1 cm to be "close enough". |
| /// 1. If your code is more general and you do not know the range of values, you should use a |
| /// relative error margin, accepting e.g. 0.1% of error regardless of specific values. |
| /// |
| /// For the scenario where you can define a meaningful absolute error margin, consider using: |
| /// |
| /// ```no_run |
| /// let a: f64 = 1000.1; |
| /// let b: f64 = 0.2; |
| /// let x = a + b; |
| /// const Y: f64 = 1000.3; // Expected value. |
| /// |
| /// const ALLOWED_ERROR_VEHICLE_LENGTH_CM: f64 = 0.1; |
| /// let within_tolerance = (x - Y).abs() < ALLOWED_ERROR_VEHICLE_LENGTH_CM; |
| /// println!("{within_tolerance}"); // true |
| /// ``` |
| /// |
| /// NB! Do not use `f64::EPSILON` - while the error margin is often called "epsilon", this is |
| /// a different use of the term that is not suitable for floating point equality comparison. |
| /// Indeed, for the example above using `f64::EPSILON` as the allowed error would return `false`. |
| /// |
| /// For the scenario where no meaningful absolute error can be defined, refer to |
| /// [the floating point guide](https://www.floating-point-gui.de/errors/comparison) |
| /// for a reference implementation of relative error based comparison of floating point values. |
| /// `MIN_NORMAL` in the reference implementation is equivalent to `MIN_POSITIVE` in Rust. |
| #[clippy::version = "pre 1.29.0"] |
| pub FLOAT_CMP_CONST, |
| restriction, |
| "using `==` or `!=` on float constants instead of comparing difference with an allowed error" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for getting the remainder of integer division by one or minus |
| /// one. |
| /// |
| /// ### Why is this bad? |
| /// The result for a divisor of one can only ever be zero; for |
| /// minus one it can cause panic/overflow (if the left operand is the minimal value of |
| /// the respective integer type) or results in zero. No one will write such code |
| /// deliberately, unless trying to win an Underhanded Rust Contest. Even for that |
| /// contest, it's probably a bad idea. Use something more underhanded. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// # let x = 1; |
| /// let a = x % 1; |
| /// let a = x % -1; |
| /// ``` |
| #[clippy::version = "pre 1.29.0"] |
| pub MODULO_ONE, |
| correctness, |
| "taking an integer modulo +/-1, which can either panic/overflow or always returns 0" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for modulo arithmetic. |
| /// |
| /// ### Why restrict this? |
| /// The results of modulo (`%`) operation might differ |
| /// depending on the language, when negative numbers are involved. |
| /// If you interop with different languages it might be beneficial |
| /// to double check all places that use modulo arithmetic. |
| /// |
| /// For example, in Rust `17 % -3 = 2`, but in Python `17 % -3 = -1`. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// let x = -17 % 3; |
| /// ``` |
| #[clippy::version = "1.42.0"] |
| pub MODULO_ARITHMETIC, |
| restriction, |
| "any modulo arithmetic statement" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for usage of bitwise and/or operators between booleans, where performance may be improved by using |
| /// a lazy and. |
| /// |
| /// ### Why is this bad? |
| /// The bitwise operators do not support short-circuiting, so it may hinder code performance. |
| /// Additionally, boolean logic "masked" as bitwise logic is not caught by lints like `unnecessary_fold` |
| /// |
| /// ### Known problems |
| /// This lint evaluates only when the right side is determined to have no side effects. At this time, that |
| /// determination is quite conservative. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// let (x,y) = (true, false); |
| /// if x & !y {} // where both x and y are booleans |
| /// ``` |
| /// Use instead: |
| /// ```no_run |
| /// let (x,y) = (true, false); |
| /// if x && !y {} |
| /// ``` |
| #[clippy::version = "1.54.0"] |
| pub NEEDLESS_BITWISE_BOOL, |
| pedantic, |
| "Boolean expressions that use bitwise rather than lazy operators" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for explicit self-assignments. |
| /// |
| /// ### Why is this bad? |
| /// Self-assignments are redundant and unlikely to be |
| /// intentional. |
| /// |
| /// ### Known problems |
| /// If expression contains any deref coercions or |
| /// indexing operations they are assumed not to have any side effects. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// struct Event { |
| /// x: i32, |
| /// } |
| /// |
| /// fn copy_position(a: &mut Event, b: &Event) { |
| /// a.x = a.x; |
| /// } |
| /// ``` |
| /// |
| /// Should be: |
| /// ```no_run |
| /// struct Event { |
| /// x: i32, |
| /// } |
| /// |
| /// fn copy_position(a: &mut Event, b: &Event) { |
| /// a.x = b.x; |
| /// } |
| /// ``` |
| #[clippy::version = "1.48.0"] |
| pub SELF_ASSIGNMENT, |
| correctness, |
| "explicit self-assignment" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for manual implementation of `midpoint`. |
| /// |
| /// ### Why is this bad? |
| /// Using `(x + y) / 2` might cause an overflow on the intermediate |
| /// addition result. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// # let a: u32 = 0; |
| /// let c = (a + 10) / 2; |
| /// ``` |
| /// Use instead: |
| /// ```no_run |
| /// # let a: u32 = 0; |
| /// let c = u32::midpoint(a, 10); |
| /// ``` |
| #[clippy::version = "1.87.0"] |
| pub MANUAL_MIDPOINT, |
| pedantic, |
| "manual implementation of `midpoint` which can overflow" |
| } |
| |
| declare_clippy_lint! { |
| /// ### What it does |
| /// Checks for manual implementation of `.is_multiple_of()` on |
| /// unsigned integer types. |
| /// |
| /// ### Why is this bad? |
| /// `a.is_multiple_of(b)` is a clearer way to check for divisibility |
| /// of `a` by `b`. This expression can never panic. |
| /// |
| /// ### Example |
| /// ```no_run |
| /// # let (a, b) = (3u64, 4u64); |
| /// if a % b == 0 { |
| /// println!("{a} is divisible by {b}"); |
| /// } |
| /// ``` |
| /// Use instead: |
| /// ```no_run |
| /// # let (a, b) = (3u64, 4u64); |
| /// if a.is_multiple_of(b) { |
| /// println!("{a} is divisible by {b}"); |
| /// } |
| /// ``` |
| #[clippy::version = "1.89.0"] |
| pub MANUAL_IS_MULTIPLE_OF, |
| complexity, |
| "manual implementation of `.is_multiple_of()`" |
| } |
| |
| pub struct Operators { |
| arithmetic_context: numeric_arithmetic::Context, |
| verbose_bit_mask_threshold: u64, |
| modulo_arithmetic_allow_comparison_to_zero: bool, |
| msrv: Msrv, |
| } |
| |
| impl Operators { |
| pub fn new(conf: &'static Conf) -> Self { |
| Self { |
| arithmetic_context: numeric_arithmetic::Context::default(), |
| verbose_bit_mask_threshold: conf.verbose_bit_mask_threshold, |
| modulo_arithmetic_allow_comparison_to_zero: conf.allow_comparison_to_zero, |
| msrv: conf.msrv, |
| } |
| } |
| } |
| |
| impl_lint_pass!(Operators => [ |
| ABSURD_EXTREME_COMPARISONS, |
| ARITHMETIC_SIDE_EFFECTS, |
| FLOAT_ARITHMETIC, |
| ASSIGN_OP_PATTERN, |
| MISREFACTORED_ASSIGN_OP, |
| BAD_BIT_MASK, |
| INEFFECTIVE_BIT_MASK, |
| VERBOSE_BIT_MASK, |
| DOUBLE_COMPARISONS, |
| IMPOSSIBLE_COMPARISONS, |
| REDUNDANT_COMPARISONS, |
| DURATION_SUBSEC, |
| EQ_OP, |
| OP_REF, |
| ERASING_OP, |
| FLOAT_EQUALITY_WITHOUT_ABS, |
| IDENTITY_OP, |
| INTEGER_DIVISION, |
| CMP_OWNED, |
| FLOAT_CMP, |
| FLOAT_CMP_CONST, |
| MODULO_ONE, |
| MODULO_ARITHMETIC, |
| NEEDLESS_BITWISE_BOOL, |
| SELF_ASSIGNMENT, |
| MANUAL_MIDPOINT, |
| MANUAL_IS_MULTIPLE_OF, |
| ]); |
| |
| impl<'tcx> LateLintPass<'tcx> for Operators { |
| fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { |
| eq_op::check_assert(cx, e); |
| match e.kind { |
| ExprKind::Binary(op, lhs, rhs) => { |
| if !e.span.from_expansion() { |
| absurd_extreme_comparisons::check(cx, e, op.node, lhs, rhs); |
| if !(macro_with_not_op(lhs) || macro_with_not_op(rhs)) { |
| eq_op::check(cx, e, op.node, lhs, rhs); |
| op_ref::check(cx, e, op.node, lhs, rhs); |
| } |
| erasing_op::check(cx, e, op.node, lhs, rhs); |
| identity_op::check(cx, e, op.node, lhs, rhs); |
| needless_bitwise_bool::check(cx, e, op.node, lhs, rhs); |
| manual_midpoint::check(cx, e, op.node, lhs, rhs, self.msrv); |
| manual_is_multiple_of::check(cx, e, op.node, lhs, rhs, self.msrv); |
| } |
| self.arithmetic_context.check_binary(cx, e, op.node, lhs, rhs); |
| bit_mask::check(cx, e, op.node, lhs, rhs); |
| verbose_bit_mask::check(cx, e, op.node, lhs, rhs, self.verbose_bit_mask_threshold); |
| double_comparison::check(cx, op.node, lhs, rhs, e.span); |
| const_comparisons::check(cx, op, lhs, rhs, e.span); |
| duration_subsec::check(cx, e, op.node, lhs, rhs); |
| float_equality_without_abs::check(cx, e, op.node, lhs, rhs); |
| integer_division::check(cx, e, op.node, lhs, rhs); |
| cmp_owned::check(cx, op.node, lhs, rhs); |
| float_cmp::check(cx, e, op.node, lhs, rhs); |
| modulo_one::check(cx, e, op.node, rhs); |
| modulo_arithmetic::check( |
| cx, |
| e, |
| op.node, |
| lhs, |
| rhs, |
| self.modulo_arithmetic_allow_comparison_to_zero, |
| ); |
| }, |
| ExprKind::AssignOp(op, lhs, rhs) => { |
| let bin_op = op.node.into(); |
| self.arithmetic_context.check_binary(cx, e, bin_op, lhs, rhs); |
| misrefactored_assign_op::check(cx, e, bin_op, lhs, rhs); |
| modulo_arithmetic::check(cx, e, bin_op, lhs, rhs, false); |
| }, |
| ExprKind::Assign(lhs, rhs, _) => { |
| assign_op_pattern::check(cx, e, lhs, rhs, self.msrv); |
| self_assignment::check(cx, e, 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: &Body<'_>) { |
| self.arithmetic_context.enter_body(cx, b); |
| } |
| |
| fn check_body_post(&mut self, cx: &LateContext<'tcx>, b: &Body<'_>) { |
| self.arithmetic_context.body_post(cx, b); |
| } |
| } |
| |
| fn macro_with_not_op(e: &Expr<'_>) -> bool { |
| if let ExprKind::Unary(_, e) = e.kind { |
| e.span.from_expansion() |
| } else { |
| false |
| } |
| } |