mod absurd_extreme_comparisons; mod assign_op_pattern; mod bit_mask; mod cmp_owned; mod const_comparisons; mod decimal_bitwise_operands; 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 integer_division_remainder_used; mod invalid_upcast_comparisons; mod manual_div_ceil; 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 = 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 `_ m /// c` (where `` is one of {`&`, `|`} and `` 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`. Note 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 /// ``` /// /// NOTE: 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 /// ``` /// /// NOTE: 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.90.0"] pub MANUAL_IS_MULTIPLE_OF, complexity, "manual implementation of `.is_multiple_of()`" } declare_clippy_lint! { /// ### What it does /// Checks for an expression like `(x + (y - 1)) / y` which is a common manual reimplementation /// of `x.div_ceil(y)`. /// /// ### Why is this bad? /// It's simpler, clearer and more readable. /// /// ### Example /// ```no_run /// let x: i32 = 7; /// let y: i32 = 4; /// let div = (x + (y - 1)) / y; /// ``` /// Use instead: /// ```no_run /// #![feature(int_roundings)] /// let x: i32 = 7; /// let y: i32 = 4; /// let div = x.div_ceil(y); /// ``` #[clippy::version = "1.83.0"] pub MANUAL_DIV_CEIL, complexity, "manually reimplementing `div_ceil`" } declare_clippy_lint! { /// ### What it does /// Checks for comparisons where the relation is always either /// true or false, but where one side has been upcast so that the comparison is /// necessary. Only integer types are checked. /// /// ### Why is this bad? /// An expression like `let x : u8 = ...; (x as u32) > 300` /// will mistakenly imply that it is possible for `x` to be outside the range of /// `u8`. /// /// ### Example /// ```no_run /// let x: u8 = 1; /// (x as u32) > 300; /// ``` #[clippy::version = "pre 1.29.0"] pub INVALID_UPCAST_COMPARISONS, pedantic, "a comparison involving an upcast which is always true or false" } declare_clippy_lint! { /// ### What it does /// Checks for the usage of division (`/`) and remainder (`%`) operations /// when performed on any integer types using the default `Div` and `Rem` trait implementations. /// /// ### Why restrict this? /// In cryptographic contexts, division can result in timing sidechannel vulnerabilities, /// and needs to be replaced with constant-time code instead (e.g. Barrett reduction). /// /// ### Example /// ```no_run /// let my_div = 10 / 2; /// ``` /// Use instead: /// ```no_run /// let my_div = 10 >> 1; /// ``` #[clippy::version = "1.79.0"] pub INTEGER_DIVISION_REMAINDER_USED, restriction, "use of disallowed default division and remainder operations" } declare_clippy_lint! { /// ### What it does /// Checks for decimal literals used as bit masks in bitwise operations. /// /// ### Why is this bad? /// Using decimal literals for bit masks can make the code less readable and obscure the intended bit pattern. /// Binary, hexadecimal, or octal literals make the bit pattern more explicit and easier to understand at a glance. /// /// ### Example /// ```rust,no_run /// let a = 14 & 6; // Bit pattern is not immediately clear /// ``` /// Use instead: /// ```rust,no_run /// let a = 0b1110 & 0b0110; /// ``` #[clippy::version = "1.93.0"] pub DECIMAL_BITWISE_OPERANDS, pedantic, "use binary, hex, or octal literals for bitwise operations" } 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, INTEGER_DIVISION_REMAINDER_USED, CMP_OWNED, FLOAT_CMP, FLOAT_CMP_CONST, MODULO_ONE, MODULO_ARITHMETIC, NEEDLESS_BITWISE_BOOL, SELF_ASSIGNMENT, MANUAL_MIDPOINT, MANUAL_IS_MULTIPLE_OF, MANUAL_DIV_CEIL, INVALID_UPCAST_COMPARISONS, DECIMAL_BITWISE_OPERANDS ]); 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); invalid_upcast_comparisons::check(cx, op.node, lhs, rhs, e.span); 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); decimal_bitwise_operands::check(cx, op.node, lhs, rhs); } 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); integer_division_remainder_used::check(cx, op.node, lhs, rhs, e.span); 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, ); manual_div_ceil::check(cx, e, op.node, lhs, rhs, self.msrv); }, ExprKind::AssignOp(op, lhs, rhs) => { let bin_op = op.node.into(); if !e.span.from_expansion() { decimal_bitwise_operands::check(cx, bin_op, lhs, rhs); } 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 } }