|
1 | 1 | use clippy_utils::consts::{constant, Constant};
|
2 |
| -use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; |
3 |
| -use clippy_utils::sugg::Sugg; |
4 |
| -use rustc_ast::ast::LitKind; |
5 |
| -use rustc_errors::Applicability; |
| 2 | +use clippy_utils::diagnostics::span_lint; |
6 | 3 | use rustc_hir::{BinOpKind, Expr, ExprKind};
|
7 |
| -use rustc_lint::{LateContext, LateLintPass}; |
8 |
| -use rustc_session::{declare_tool_lint, impl_lint_pass}; |
| 4 | +use rustc_lint::LateContext; |
9 | 5 | use rustc_span::source_map::Span;
|
10 | 6 |
|
11 |
| -declare_clippy_lint! { |
12 |
| - /// ### What it does |
13 |
| - /// Checks for incompatible bit masks in comparisons. |
14 |
| - /// |
15 |
| - /// The formula for detecting if an expression of the type `_ <bit_op> m |
16 |
| - /// <cmp_op> c` (where `<bit_op>` is one of {`&`, `|`} and `<cmp_op>` is one of |
17 |
| - /// {`!=`, `>=`, `>`, `!=`, `>=`, `>`}) can be determined from the following |
18 |
| - /// table: |
19 |
| - /// |
20 |
| - /// |Comparison |Bit Op|Example |is always|Formula | |
21 |
| - /// |------------|------|-------------|---------|----------------------| |
22 |
| - /// |`==` or `!=`| `&` |`x & 2 == 3` |`false` |`c & m != c` | |
23 |
| - /// |`<` or `>=`| `&` |`x & 2 < 3` |`true` |`m < c` | |
24 |
| - /// |`>` or `<=`| `&` |`x & 1 > 1` |`false` |`m <= c` | |
25 |
| - /// |`==` or `!=`| `\|` |`x \| 1 == 0`|`false` |`c \| m != c` | |
26 |
| - /// |`<` or `>=`| `\|` |`x \| 1 < 1` |`false` |`m >= c` | |
27 |
| - /// |`<=` or `>` | `\|` |`x \| 1 > 0` |`true` |`m > c` | |
28 |
| - /// |
29 |
| - /// ### Why is this bad? |
30 |
| - /// If the bits that the comparison cares about are always |
31 |
| - /// set to zero or one by the bit mask, the comparison is constant `true` or |
32 |
| - /// `false` (depending on mask, compared value, and operators). |
33 |
| - /// |
34 |
| - /// So the code is actively misleading, and the only reason someone would write |
35 |
| - /// this intentionally is to win an underhanded Rust contest or create a |
36 |
| - /// test-case for this lint. |
37 |
| - /// |
38 |
| - /// ### Example |
39 |
| - /// ```rust |
40 |
| - /// # let x = 1; |
41 |
| - /// if (x & 1 == 2) { } |
42 |
| - /// ``` |
43 |
| - #[clippy::version = "pre 1.29.0"] |
44 |
| - pub BAD_BIT_MASK, |
45 |
| - correctness, |
46 |
| - "expressions of the form `_ & mask == select` that will only ever return `true` or `false`" |
47 |
| -} |
48 |
| - |
49 |
| -declare_clippy_lint! { |
50 |
| - /// ### What it does |
51 |
| - /// Checks for bit masks in comparisons which can be removed |
52 |
| - /// without changing the outcome. The basic structure can be seen in the |
53 |
| - /// following table: |
54 |
| - /// |
55 |
| - /// |Comparison| Bit Op |Example |equals | |
56 |
| - /// |----------|----------|------------|-------| |
57 |
| - /// |`>` / `<=`|`\|` / `^`|`x \| 2 > 3`|`x > 3`| |
58 |
| - /// |`<` / `>=`|`\|` / `^`|`x ^ 1 < 4` |`x < 4`| |
59 |
| - /// |
60 |
| - /// ### Why is this bad? |
61 |
| - /// Not equally evil as [`bad_bit_mask`](#bad_bit_mask), |
62 |
| - /// but still a bit misleading, because the bit mask is ineffective. |
63 |
| - /// |
64 |
| - /// ### Known problems |
65 |
| - /// False negatives: This lint will only match instances |
66 |
| - /// where we have figured out the math (which is for a power-of-two compared |
67 |
| - /// value). This means things like `x | 1 >= 7` (which would be better written |
68 |
| - /// as `x >= 6`) will not be reported (but bit masks like this are fairly |
69 |
| - /// uncommon). |
70 |
| - /// |
71 |
| - /// ### Example |
72 |
| - /// ```rust |
73 |
| - /// # let x = 1; |
74 |
| - /// if (x | 1 > 3) { } |
75 |
| - /// ``` |
76 |
| - #[clippy::version = "pre 1.29.0"] |
77 |
| - pub INEFFECTIVE_BIT_MASK, |
78 |
| - correctness, |
79 |
| - "expressions where a bit mask will be rendered useless by a comparison, e.g., `(x | 1) > 2`" |
80 |
| -} |
81 |
| - |
82 |
| -declare_clippy_lint! { |
83 |
| - /// ### What it does |
84 |
| - /// Checks for bit masks that can be replaced by a call |
85 |
| - /// to `trailing_zeros` |
86 |
| - /// |
87 |
| - /// ### Why is this bad? |
88 |
| - /// `x.trailing_zeros() > 4` is much clearer than `x & 15 |
89 |
| - /// == 0` |
90 |
| - /// |
91 |
| - /// ### Known problems |
92 |
| - /// llvm generates better code for `x & 15 == 0` on x86 |
93 |
| - /// |
94 |
| - /// ### Example |
95 |
| - /// ```rust |
96 |
| - /// # let x = 1; |
97 |
| - /// if x & 0b1111 == 0 { } |
98 |
| - /// ``` |
99 |
| - #[clippy::version = "pre 1.29.0"] |
100 |
| - pub VERBOSE_BIT_MASK, |
101 |
| - pedantic, |
102 |
| - "expressions where a bit mask is less readable than the corresponding method call" |
103 |
| -} |
| 7 | +use super::{BAD_BIT_MASK, INEFFECTIVE_BIT_MASK}; |
104 | 8 |
|
105 |
| -#[derive(Copy, Clone)] |
106 |
| -pub struct BitMask { |
107 |
| - verbose_bit_mask_threshold: u64, |
108 |
| -} |
109 |
| - |
110 |
| -impl BitMask { |
111 |
| - #[must_use] |
112 |
| - pub fn new(verbose_bit_mask_threshold: u64) -> Self { |
113 |
| - Self { |
114 |
| - verbose_bit_mask_threshold, |
115 |
| - } |
116 |
| - } |
117 |
| -} |
118 |
| - |
119 |
| -impl_lint_pass!(BitMask => [BAD_BIT_MASK, INEFFECTIVE_BIT_MASK, VERBOSE_BIT_MASK]); |
120 |
| - |
121 |
| -impl<'tcx> LateLintPass<'tcx> for BitMask { |
122 |
| - fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { |
123 |
| - if let ExprKind::Binary(cmp, left, right) = &e.kind { |
124 |
| - if cmp.node.is_comparison() { |
125 |
| - if let Some(cmp_opt) = fetch_int_literal(cx, right) { |
126 |
| - check_compare(cx, left, cmp.node, cmp_opt, e.span); |
127 |
| - } else if let Some(cmp_val) = fetch_int_literal(cx, left) { |
128 |
| - check_compare(cx, right, invert_cmp(cmp.node), cmp_val, e.span); |
129 |
| - } |
130 |
| - } |
131 |
| - } |
132 |
| - |
133 |
| - if let ExprKind::Binary(op, left, right) = &e.kind |
134 |
| - && BinOpKind::Eq == op.node |
135 |
| - && let ExprKind::Binary(op1, left1, right1) = &left.kind |
136 |
| - && BinOpKind::BitAnd == op1.node |
137 |
| - && let ExprKind::Lit(lit) = &right1.kind |
138 |
| - && let LitKind::Int(n, _) = lit.node |
139 |
| - && let ExprKind::Lit(lit1) = &right.kind |
140 |
| - && let LitKind::Int(0, _) = lit1.node |
141 |
| - && n.leading_zeros() == n.count_zeros() |
142 |
| - && n > u128::from(self.verbose_bit_mask_threshold) |
143 |
| - { |
144 |
| - span_lint_and_then( |
145 |
| - cx, |
146 |
| - VERBOSE_BIT_MASK, |
147 |
| - e.span, |
148 |
| - "bit mask could be simplified with a call to `trailing_zeros`", |
149 |
| - |diag| { |
150 |
| - let sugg = Sugg::hir(cx, left1, "...").maybe_par(); |
151 |
| - diag.span_suggestion( |
152 |
| - e.span, |
153 |
| - "try", |
154 |
| - format!("{}.trailing_zeros() >= {}", sugg, n.count_ones()), |
155 |
| - Applicability::MaybeIncorrect, |
156 |
| - ); |
157 |
| - }, |
158 |
| - ); |
| 9 | +pub(super) fn check<'tcx>( |
| 10 | + cx: &LateContext<'tcx>, |
| 11 | + e: &'tcx Expr<'_>, |
| 12 | + op: BinOpKind, |
| 13 | + left: &'tcx Expr<'_>, |
| 14 | + right: &'tcx Expr<'_>, |
| 15 | +) { |
| 16 | + if op.is_comparison() { |
| 17 | + if let Some(cmp_opt) = fetch_int_literal(cx, right) { |
| 18 | + check_compare(cx, left, op, cmp_opt, e.span); |
| 19 | + } else if let Some(cmp_val) = fetch_int_literal(cx, left) { |
| 20 | + check_compare(cx, right, invert_cmp(op), cmp_val, e.span); |
159 | 21 | }
|
160 | 22 | }
|
161 | 23 | }
|
|
0 commit comments