-
Couldn't load subscription status.
- Fork 1.8k
New lint: decimal_bit_mask
#15215
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
New lint: decimal_bit_mask
#15215
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,103 @@ | ||||||||||
| use clippy_utils::diagnostics::span_lint; | ||||||||||
| use clippy_utils::source::snippet_opt; | ||||||||||
| use rustc_hir::*; | ||||||||||
| use rustc_lint::{LateContext, LateLintPass}; | ||||||||||
| use rustc_session::declare_lint_pass; | ||||||||||
| use rustc_span::source_map::Spanned; | ||||||||||
|
|
||||||||||
| 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 or hexadecimal literals make the bit pattern more explicit and easier to understand at a glance. | ||||||||||
| /// | ||||||||||
| /// ### Example | ||||||||||
| /// ```rust,no_run | ||||||||||
| /// let a = 15 & 6; // Bit pattern is not immediately clear | ||||||||||
| /// ``` | ||||||||||
| /// Use instead: | ||||||||||
| /// ```rust,no_run | ||||||||||
| /// let a = 0b1111 & 0b0110; | ||||||||||
| /// ``` | ||||||||||
| #[clippy::version = "1.87.0"] | ||||||||||
| pub DECIMAL_BIT_MASK, | ||||||||||
| nursery, | ||||||||||
| "default lint description" | ||||||||||
| } | ||||||||||
|
|
||||||||||
| declare_lint_pass!(DecimalBitMask => [DECIMAL_BIT_MASK]); | ||||||||||
|
|
||||||||||
| impl<'tcx> LateLintPass<'tcx> for DecimalBitMask { | ||||||||||
| fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { | ||||||||||
| if let ExprKind::Binary( | ||||||||||
| Spanned { | ||||||||||
| node: BinOpKind::BitAnd | BinOpKind::BitOr | BinOpKind::BitXor, | ||||||||||
| .. | ||||||||||
| }, | ||||||||||
| Expr { | ||||||||||
| kind: kind1, | ||||||||||
| span: span1, | ||||||||||
| .. | ||||||||||
| }, | ||||||||||
| Expr { | ||||||||||
| kind: kind2, | ||||||||||
| span: span2, | ||||||||||
| .. | ||||||||||
| }, | ||||||||||
| ) = &e.kind | ||||||||||
| { | ||||||||||
| if let ExprKind::Lit(_) = kind1 | ||||||||||
| && let Some(snippet) = snippet_opt(cx, *span1) | ||||||||||
| && !snippet.starts_with("0b") | ||||||||||
| && !snippet.starts_with("0x") | ||||||||||
| { | ||||||||||
| span_lint( | ||||||||||
| cx, | ||||||||||
| DECIMAL_BIT_MASK, | ||||||||||
| e.span, | ||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can improve the output by pointing the lint at the exact operand that is decimal -- for example, here you would use |
||||||||||
| "Using decimal literal for bit mask. Consider using binary (0b...) or hexadecimal (0x...) notation for better readability.", | ||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The second sentence should be emitted separately, as a help message -- see https://doc.rust-lang.org/clippy/development/emitting_lints.html#emitting-a-lint-1 for more info. Try using |
||||||||||
| ); | ||||||||||
| } | ||||||||||
|
|
||||||||||
| if let ExprKind::Lit(_) = kind2 | ||||||||||
| && let Some(snippet) = snippet_opt(cx, *span2) | ||||||||||
| && !snippet.starts_with("0b") | ||||||||||
| && !snippet.starts_with("0x") | ||||||||||
|
Comment on lines
+65
to
+67
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can use && let Some(snippet) = span2.get_source_text(cx)In fact, since you're only using the snippet to check its contents, you can get away with
Suggested change
|
||||||||||
| { | ||||||||||
| span_lint( | ||||||||||
| cx, | ||||||||||
| DECIMAL_BIT_MASK, | ||||||||||
| e.span, | ||||||||||
| "Using decimal literal for bit mask. Consider using binary (0b...) or hexadecimal (0x...) notation for better readability.", | ||||||||||
| ); | ||||||||||
| } | ||||||||||
| } | ||||||||||
| if let ExprKind::AssignOp( | ||||||||||
| Spanned { | ||||||||||
| node: AssignOpKind::BitAndAssign | AssignOpKind::BitOrAssign | AssignOpKind::BitXorAssign, | ||||||||||
| .. | ||||||||||
| }, | ||||||||||
| _, | ||||||||||
| Expr { | ||||||||||
| kind: ExprKind::Lit(_), | ||||||||||
| span, | ||||||||||
| .. | ||||||||||
| }, | ||||||||||
| ) = &e.kind | ||||||||||
| { | ||||||||||
| if let Some(snippet) = snippet_opt(cx, *span) | ||||||||||
| && !snippet.starts_with("0b") | ||||||||||
| && !snippet.starts_with("0x") | ||||||||||
| { | ||||||||||
| span_lint( | ||||||||||
| cx, | ||||||||||
| DECIMAL_BIT_MASK, | ||||||||||
| e.span, | ||||||||||
| "Using decimal literal for bit mask. Consider using binary (0b...) or hexadecimal (0x...) notation for better readability.", | ||||||||||
| ); | ||||||||||
| } | ||||||||||
| } | ||||||||||
| } | ||||||||||
| } | ||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,50 @@ | ||||||||||
| #![allow(clippy::no_effect)] | ||||||||||
| #![warn(clippy::decimal_bit_mask)] | ||||||||||
| fn main() { | ||||||||||
| let mut x = 0; | ||||||||||
| // BAD: Bitwise operation, decimal literal, one literal | ||||||||||
| x & 99; //~ decimal_bit_mask | ||||||||||
| x | 99; //~ decimal_bit_mask | ||||||||||
| x ^ 99; //~ decimal_bit_mask | ||||||||||
| x &= 99; //~ decimal_bit_mask | ||||||||||
| x |= 99; //~ decimal_bit_mask | ||||||||||
| x ^= 99; //~ decimal_bit_mask | ||||||||||
|
|
||||||||||
| // BAD: Bitwise operation, decimal literal, two literals | ||||||||||
| 0b1010 & 99; //~ decimal_bit_mask | ||||||||||
| 0b1010 | 99; //~ decimal_bit_mask | ||||||||||
| 0b1010 ^ 99; //~ decimal_bit_mask | ||||||||||
| 99 & 0b1010; //~ decimal_bit_mask | ||||||||||
| 99 | 0b1010; //~ decimal_bit_mask | ||||||||||
| 99 ^ 0b1010; //~ decimal_bit_mask | ||||||||||
| 0xD | 99; //~ decimal_bit_mask | ||||||||||
| 88 & 99; //~ decimal_bit_mask | ||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
That's because in this case, you're firing the lint twice, once for each operand, so you'll need to add a second error mark. That's the easiest to do by bringing them to under the linted expression:
Suggested change
|
||||||||||
|
|
||||||||||
| // GOOD: Bitwise operation, binary/hex literal, one literal | ||||||||||
| x & 0b1010; | ||||||||||
| x | 0b1010; | ||||||||||
| x ^ 0b1010; | ||||||||||
| x &= 0b1010; | ||||||||||
| x |= 0b1010; | ||||||||||
| x ^= 0b1010; | ||||||||||
| x & 0xD; | ||||||||||
|
|
||||||||||
| // GOOD: Bitwise operation, binary/hex literal, two literals | ||||||||||
| 0b1010 & 0b1101; | ||||||||||
| 0xD ^ 0xF; | ||||||||||
|
|
||||||||||
| // GOOD: Numeric operations, any literal | ||||||||||
| x += 99; | ||||||||||
| x -= 0b1010; | ||||||||||
| x *= 0xD; | ||||||||||
| 99 + 99; | ||||||||||
| 0b1010 - 0b1101; | ||||||||||
| 0xD * 0xD; | ||||||||||
|
|
||||||||||
| // GOOD: Bitwise operations, variables only | ||||||||||
| let y = 0; | ||||||||||
| x & y; | ||||||||||
| x &= y; | ||||||||||
| x + y; | ||||||||||
| x += y; | ||||||||||
| } | ||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,97 @@ | ||
| error: Using decimal literal for bit mask. Consider using binary (0b...) or hexadecimal (0x...) notation for better readability. | ||
| --> tests/ui/decimal_bit_mask.rs:6:5 | ||
| | | ||
| LL | x & 99; | ||
| | ^^^^^^ | ||
| | | ||
| = note: `-D clippy::decimal-bit-mask` implied by `-D warnings` | ||
| = help: to override `-D warnings` add `#[allow(clippy::decimal_bit_mask)]` | ||
|
|
||
| error: Using decimal literal for bit mask. Consider using binary (0b...) or hexadecimal (0x...) notation for better readability. | ||
| --> tests/ui/decimal_bit_mask.rs:7:5 | ||
| | | ||
| LL | x | 99; | ||
| | ^^^^^^ | ||
|
|
||
| error: Using decimal literal for bit mask. Consider using binary (0b...) or hexadecimal (0x...) notation for better readability. | ||
| --> tests/ui/decimal_bit_mask.rs:8:5 | ||
| | | ||
| LL | x ^ 99; | ||
| | ^^^^^^ | ||
|
|
||
| error: Using decimal literal for bit mask. Consider using binary (0b...) or hexadecimal (0x...) notation for better readability. | ||
| --> tests/ui/decimal_bit_mask.rs:9:5 | ||
| | | ||
| LL | x &= 99; | ||
| | ^^^^^^^ | ||
|
|
||
| error: Using decimal literal for bit mask. Consider using binary (0b...) or hexadecimal (0x...) notation for better readability. | ||
| --> tests/ui/decimal_bit_mask.rs:10:5 | ||
| | | ||
| LL | x |= 99; | ||
| | ^^^^^^^ | ||
|
|
||
| error: Using decimal literal for bit mask. Consider using binary (0b...) or hexadecimal (0x...) notation for better readability. | ||
| --> tests/ui/decimal_bit_mask.rs:11:5 | ||
| | | ||
| LL | x ^= 99; | ||
| | ^^^^^^^ | ||
|
|
||
| error: Using decimal literal for bit mask. Consider using binary (0b...) or hexadecimal (0x...) notation for better readability. | ||
| --> tests/ui/decimal_bit_mask.rs:14:5 | ||
| | | ||
| LL | 0b1010 & 99; | ||
| | ^^^^^^^^^^^ | ||
|
|
||
| error: Using decimal literal for bit mask. Consider using binary (0b...) or hexadecimal (0x...) notation for better readability. | ||
| --> tests/ui/decimal_bit_mask.rs:15:5 | ||
| | | ||
| LL | 0b1010 | 99; | ||
| | ^^^^^^^^^^^ | ||
|
|
||
| error: Using decimal literal for bit mask. Consider using binary (0b...) or hexadecimal (0x...) notation for better readability. | ||
| --> tests/ui/decimal_bit_mask.rs:16:5 | ||
| | | ||
| LL | 0b1010 ^ 99; | ||
| | ^^^^^^^^^^^ | ||
|
|
||
| error: Using decimal literal for bit mask. Consider using binary (0b...) or hexadecimal (0x...) notation for better readability. | ||
| --> tests/ui/decimal_bit_mask.rs:17:5 | ||
| | | ||
| LL | 99 & 0b1010; | ||
| | ^^^^^^^^^^^ | ||
|
|
||
| error: Using decimal literal for bit mask. Consider using binary (0b...) or hexadecimal (0x...) notation for better readability. | ||
| --> tests/ui/decimal_bit_mask.rs:18:5 | ||
| | | ||
| LL | 99 | 0b1010; | ||
| | ^^^^^^^^^^^ | ||
|
|
||
| error: Using decimal literal for bit mask. Consider using binary (0b...) or hexadecimal (0x...) notation for better readability. | ||
| --> tests/ui/decimal_bit_mask.rs:19:5 | ||
| | | ||
| LL | 99 ^ 0b1010; | ||
| | ^^^^^^^^^^^ | ||
|
|
||
| error: Using decimal literal for bit mask. Consider using binary (0b...) or hexadecimal (0x...) notation for better readability. | ||
| --> tests/ui/decimal_bit_mask.rs:20:5 | ||
| | | ||
| LL | 0xD | 99; | ||
| | ^^^^^^^^ | ||
|
|
||
| error: Using decimal literal for bit mask. Consider using binary (0b...) or hexadecimal (0x...) notation for better readability. | ||
| --> tests/ui/decimal_bit_mask.rs:21:5 | ||
| | | ||
| LL | 88 & 99; | ||
| | ^^^^^^^ | ||
|
|
||
| error: Using decimal literal for bit mask. Consider using binary (0b...) or hexadecimal (0x...) notation for better readability. | ||
| --> tests/ui/decimal_bit_mask.rs:21:5 | ||
| | | ||
| LL | 88 & 99; | ||
| | ^^^^^^^ | ||
| | | ||
| = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` | ||
|
|
||
| error: aborting due to 15 previous errors | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be a bit more concise to have these simply as
leftandright, and then useleft.span,right.kindetc. throughout the code