Skip to content

Commit 013adec

Browse files
committed
New lint: decimal_bit_mask
1 parent b28049d commit 013adec

File tree

6 files changed

+254
-0
lines changed

6 files changed

+254
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5791,6 +5791,7 @@ Released 2018-09-13
57915791
[`cyclomatic_complexity`]: https://rust-lang.github.io/rust-clippy/master/index.html#cyclomatic_complexity
57925792
[`dbg_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#dbg_macro
57935793
[`debug_assert_with_mut_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#debug_assert_with_mut_call
5794+
[`decimal_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#decimal_bit_mask
57945795
[`decimal_literal_representation`]: https://rust-lang.github.io/rust-clippy/master/index.html#decimal_literal_representation
57955796
[`declare_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#declare_interior_mutable_const
57965797
[`default_constructed_unit_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_constructed_unit_structs
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
use clippy_utils::diagnostics::span_lint;
2+
use clippy_utils::source::snippet_opt;
3+
use rustc_hir::*;
4+
use rustc_lint::{LateContext, LateLintPass};
5+
use rustc_session::declare_lint_pass;
6+
use rustc_span::source_map::Spanned;
7+
8+
declare_clippy_lint! {
9+
/// ### What it does
10+
/// Checks for decimal literals used as bit masks in bitwise operations.
11+
///
12+
/// ### Why is this bad?
13+
/// Using decimal literals for bit masks can make the code less readable and obscure the intended bit pattern.
14+
/// Binary or hexadecimal literals make the bit pattern more explicit and easier to understand at a glance.
15+
///
16+
/// ### Example
17+
/// ```rust,no_run
18+
/// let a = 15 & 6; // Bit pattern is not immediately clear
19+
/// ```
20+
/// Use instead:
21+
/// ```rust,no_run
22+
/// let a = 0b1111 & 0b0110;
23+
/// ```
24+
#[clippy::version = "1.87.0"]
25+
pub DECIMAL_BIT_MASK,
26+
nursery,
27+
"default lint description"
28+
}
29+
30+
declare_lint_pass!(DecimalBitMask => [DECIMAL_BIT_MASK]);
31+
32+
impl<'tcx> LateLintPass<'tcx> for DecimalBitMask {
33+
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
34+
if let ExprKind::Binary(
35+
Spanned {
36+
node: BinOpKind::BitAnd | BinOpKind::BitOr | BinOpKind::BitXor,
37+
..
38+
},
39+
Expr {
40+
kind: kind1,
41+
span: span1,
42+
..
43+
},
44+
Expr {
45+
kind: kind2,
46+
span: span2,
47+
..
48+
},
49+
) = &e.kind
50+
{
51+
if let ExprKind::Lit(_) = kind1
52+
&& let Some(snippet) = snippet_opt(cx, *span1)
53+
&& !snippet.starts_with("0b")
54+
&& !snippet.starts_with("0x")
55+
{
56+
span_lint(
57+
cx,
58+
DECIMAL_BIT_MASK,
59+
e.span,
60+
"Using decimal literal for bit mask. Consider using binary (0b...) or hexadecimal (0x...) notation for better readability.",
61+
);
62+
}
63+
64+
if let ExprKind::Lit(_) = kind2
65+
&& let Some(snippet) = snippet_opt(cx, *span2)
66+
&& !snippet.starts_with("0b")
67+
&& !snippet.starts_with("0x")
68+
{
69+
span_lint(
70+
cx,
71+
DECIMAL_BIT_MASK,
72+
e.span,
73+
"Using decimal literal for bit mask. Consider using binary (0b...) or hexadecimal (0x...) notation for better readability.",
74+
);
75+
}
76+
}
77+
if let ExprKind::AssignOp(
78+
Spanned {
79+
node: AssignOpKind::BitAndAssign | AssignOpKind::BitOrAssign | AssignOpKind::BitXorAssign,
80+
..
81+
},
82+
_,
83+
Expr {
84+
kind: ExprKind::Lit(_),
85+
span,
86+
..
87+
},
88+
) = &e.kind
89+
{
90+
if let Some(snippet) = snippet_opt(cx, *span)
91+
&& !snippet.starts_with("0b")
92+
&& !snippet.starts_with("0x")
93+
{
94+
span_lint(
95+
cx,
96+
DECIMAL_BIT_MASK,
97+
e.span,
98+
"Using decimal literal for bit mask. Consider using binary (0b...) or hexadecimal (0x...) notation for better readability.",
99+
);
100+
}
101+
}
102+
}
103+
}

clippy_lints/src/declared_lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[
9191
crate::crate_in_macro_def::CRATE_IN_MACRO_DEF_INFO,
9292
crate::create_dir::CREATE_DIR_INFO,
9393
crate::dbg_macro::DBG_MACRO_INFO,
94+
crate::decimal_bit_mask::DECIMAL_BIT_MASK_INFO,
9495
crate::default::DEFAULT_TRAIT_ACCESS_INFO,
9596
crate::default::FIELD_REASSIGN_WITH_DEFAULT_INFO,
9697
crate::default_constructed_unit_structs::DEFAULT_CONSTRUCTED_UNIT_STRUCTS_INFO,

clippy_lints/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ mod copy_iterator;
105105
mod crate_in_macro_def;
106106
mod create_dir;
107107
mod dbg_macro;
108+
mod decimal_bit_mask;
108109
mod default;
109110
mod default_constructed_unit_structs;
110111
mod default_instead_of_iter_empty;
@@ -830,5 +831,6 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co
830831
store.register_late_pass(|_| Box::new(cloned_ref_to_slice_refs::ClonedRefToSliceRefs::new(conf)));
831832
store.register_late_pass(|_| Box::new(infallible_try_from::InfallibleTryFrom));
832833
store.register_late_pass(|_| Box::new(coerce_container_to_any::CoerceContainerToAny));
834+
store.register_late_pass(|_| Box::new(decimal_bit_mask::DecimalBitMask));
833835
// add lints here, do not remove this comment, it's used in `new_lint`
834836
}

tests/ui/decimal_bit_mask.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#![allow(clippy::no_effect)]
2+
#![warn(clippy::decimal_bit_mask)]
3+
fn main() {
4+
let mut x = 0;
5+
// BAD: Bitwise operation, decimal literal, one literal
6+
x & 99; //~ decimal_bit_mask
7+
x | 99; //~ decimal_bit_mask
8+
x ^ 99; //~ decimal_bit_mask
9+
x &= 99; //~ decimal_bit_mask
10+
x |= 99; //~ decimal_bit_mask
11+
x ^= 99; //~ decimal_bit_mask
12+
13+
// BAD: Bitwise operation, decimal literal, two literals
14+
0b1010 & 99; //~ decimal_bit_mask
15+
0b1010 | 99; //~ decimal_bit_mask
16+
0b1010 ^ 99; //~ decimal_bit_mask
17+
99 & 0b1010; //~ decimal_bit_mask
18+
99 | 0b1010; //~ decimal_bit_mask
19+
99 ^ 0b1010; //~ decimal_bit_mask
20+
0xD | 99; //~ decimal_bit_mask
21+
88 & 99; //~ decimal_bit_mask
22+
23+
// GOOD: Bitwise operation, binary/hex literal, one literal
24+
x & 0b1010;
25+
x | 0b1010;
26+
x ^ 0b1010;
27+
x &= 0b1010;
28+
x |= 0b1010;
29+
x ^= 0b1010;
30+
x & 0xD;
31+
32+
// GOOD: Bitwise operation, binary/hex literal, two literals
33+
0b1010 & 0b1101;
34+
0xD ^ 0xF;
35+
36+
// GOOD: Numeric operations, any literal
37+
x += 99;
38+
x -= 0b1010;
39+
x *= 0xD;
40+
99 + 99;
41+
0b1010 - 0b1101;
42+
0xD * 0xD;
43+
44+
// GOOD: Bitwise operations, variables only
45+
let y = 0;
46+
x & y;
47+
x &= y;
48+
x + y;
49+
x += y;
50+
}

tests/ui/decimal_bit_mask.stderr

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
error: Using decimal literal for bit mask. Consider using binary (0b...) or hexadecimal (0x...) notation for better readability.
2+
--> tests/ui/decimal_bit_mask.rs:6:5
3+
|
4+
LL | x & 99;
5+
| ^^^^^^
6+
|
7+
= note: `-D clippy::decimal-bit-mask` implied by `-D warnings`
8+
= help: to override `-D warnings` add `#[allow(clippy::decimal_bit_mask)]`
9+
10+
error: Using decimal literal for bit mask. Consider using binary (0b...) or hexadecimal (0x...) notation for better readability.
11+
--> tests/ui/decimal_bit_mask.rs:7:5
12+
|
13+
LL | x | 99;
14+
| ^^^^^^
15+
16+
error: Using decimal literal for bit mask. Consider using binary (0b...) or hexadecimal (0x...) notation for better readability.
17+
--> tests/ui/decimal_bit_mask.rs:8:5
18+
|
19+
LL | x ^ 99;
20+
| ^^^^^^
21+
22+
error: Using decimal literal for bit mask. Consider using binary (0b...) or hexadecimal (0x...) notation for better readability.
23+
--> tests/ui/decimal_bit_mask.rs:9:5
24+
|
25+
LL | x &= 99;
26+
| ^^^^^^^
27+
28+
error: Using decimal literal for bit mask. Consider using binary (0b...) or hexadecimal (0x...) notation for better readability.
29+
--> tests/ui/decimal_bit_mask.rs:10:5
30+
|
31+
LL | x |= 99;
32+
| ^^^^^^^
33+
34+
error: Using decimal literal for bit mask. Consider using binary (0b...) or hexadecimal (0x...) notation for better readability.
35+
--> tests/ui/decimal_bit_mask.rs:11:5
36+
|
37+
LL | x ^= 99;
38+
| ^^^^^^^
39+
40+
error: Using decimal literal for bit mask. Consider using binary (0b...) or hexadecimal (0x...) notation for better readability.
41+
--> tests/ui/decimal_bit_mask.rs:14:5
42+
|
43+
LL | 0b1010 & 99;
44+
| ^^^^^^^^^^^
45+
46+
error: Using decimal literal for bit mask. Consider using binary (0b...) or hexadecimal (0x...) notation for better readability.
47+
--> tests/ui/decimal_bit_mask.rs:15:5
48+
|
49+
LL | 0b1010 | 99;
50+
| ^^^^^^^^^^^
51+
52+
error: Using decimal literal for bit mask. Consider using binary (0b...) or hexadecimal (0x...) notation for better readability.
53+
--> tests/ui/decimal_bit_mask.rs:16:5
54+
|
55+
LL | 0b1010 ^ 99;
56+
| ^^^^^^^^^^^
57+
58+
error: Using decimal literal for bit mask. Consider using binary (0b...) or hexadecimal (0x...) notation for better readability.
59+
--> tests/ui/decimal_bit_mask.rs:17:5
60+
|
61+
LL | 99 & 0b1010;
62+
| ^^^^^^^^^^^
63+
64+
error: Using decimal literal for bit mask. Consider using binary (0b...) or hexadecimal (0x...) notation for better readability.
65+
--> tests/ui/decimal_bit_mask.rs:18:5
66+
|
67+
LL | 99 | 0b1010;
68+
| ^^^^^^^^^^^
69+
70+
error: Using decimal literal for bit mask. Consider using binary (0b...) or hexadecimal (0x...) notation for better readability.
71+
--> tests/ui/decimal_bit_mask.rs:19:5
72+
|
73+
LL | 99 ^ 0b1010;
74+
| ^^^^^^^^^^^
75+
76+
error: Using decimal literal for bit mask. Consider using binary (0b...) or hexadecimal (0x...) notation for better readability.
77+
--> tests/ui/decimal_bit_mask.rs:20:5
78+
|
79+
LL | 0xD | 99;
80+
| ^^^^^^^^
81+
82+
error: Using decimal literal for bit mask. Consider using binary (0b...) or hexadecimal (0x...) notation for better readability.
83+
--> tests/ui/decimal_bit_mask.rs:21:5
84+
|
85+
LL | 88 & 99;
86+
| ^^^^^^^
87+
88+
error: Using decimal literal for bit mask. Consider using binary (0b...) or hexadecimal (0x...) notation for better readability.
89+
--> tests/ui/decimal_bit_mask.rs:21:5
90+
|
91+
LL | 88 & 99;
92+
| ^^^^^^^
93+
|
94+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
95+
96+
error: aborting due to 15 previous errors
97+

0 commit comments

Comments
 (0)