@@ -84,28 +84,48 @@ impl LateLintPass<'_> for ManualRotate {
84
84
{
85
85
let const_eval = ConstEvalCtxt :: new ( cx) ;
86
86
87
- if let Some ( Constant :: Int ( l_amount_val) ) = const_eval. eval ( l_amount)
87
+ let ( shift_function , amount ) = if let Some ( Constant :: Int ( l_amount_val) ) = const_eval. eval ( l_amount)
88
88
&& let Some ( Constant :: Int ( r_amount_val) ) = const_eval. eval ( r_amount)
89
89
&& l_amount_val + r_amount_val == u128:: from ( bit_width)
90
90
{
91
- let ( shift_function , amount ) = if l_amount_val < r_amount_val {
91
+ if l_amount_val < r_amount_val {
92
92
( l_shift_dir, l_amount)
93
93
} else {
94
94
( r_shift_dir, r_amount)
95
+ }
96
+ } else {
97
+ let ( amount1, binop, minuend, amount2, shift_direction) = match ( l_amount. kind , r_amount. kind ) {
98
+ ( _, ExprKind :: Binary ( binop, minuend, other) ) => ( l_amount, binop, minuend, other, l_shift_dir) ,
99
+ ( ExprKind :: Binary ( binop, minuend, other) , _) => ( r_amount, binop, minuend, other, r_shift_dir) ,
100
+ _ => return ,
95
101
} ;
96
- let mut applicability = Applicability :: MachineApplicable ;
97
- let expr_sugg = sugg:: Sugg :: hir_with_applicability ( cx, l_expr, "_" , & mut applicability) . maybe_paren ( ) ;
98
- let amount = sugg:: Sugg :: hir_with_applicability ( cx, amount, "_" , & mut applicability) ;
99
- span_lint_and_sugg (
100
- cx,
101
- MANUAL_ROTATE ,
102
- expr. span ,
103
- "there is no need to manually implement bit rotation" ,
104
- "this expression can be rewritten as" ,
105
- format ! ( "{expr_sugg}.{shift_function}({amount})" ) ,
106
- Applicability :: MachineApplicable ,
107
- ) ;
108
- }
102
+
103
+ if let Some ( Constant :: Int ( minuend) ) = const_eval. eval_simple ( minuend)
104
+ && clippy_utils:: eq_expr_value ( cx, amount1, amount2)
105
+ // (x << s) | (x >> bit_width - s)
106
+ && ( ( binop. node == BinOpKind :: Sub && u128:: from ( bit_width) == minuend)
107
+ // (x << s) | (x >> (bit_width - 1) ^ s)
108
+ || ( binop. node == BinOpKind :: BitXor && u128:: from ( bit_width) . checked_sub ( minuend) == Some ( 1 ) ) )
109
+ {
110
+ // NOTE: we take these from the side that _doesn't_ have the binop, since it's probably simpler
111
+ ( shift_direction, amount1)
112
+ } else {
113
+ return ;
114
+ }
115
+ } ;
116
+
117
+ let mut applicability = Applicability :: MachineApplicable ;
118
+ let expr_sugg = sugg:: Sugg :: hir_with_applicability ( cx, l_expr, "_" , & mut applicability) . maybe_paren ( ) ;
119
+ let amount = sugg:: Sugg :: hir_with_applicability ( cx, amount, "_" , & mut applicability) ;
120
+ span_lint_and_sugg (
121
+ cx,
122
+ MANUAL_ROTATE ,
123
+ expr. span ,
124
+ "there is no need to manually implement bit rotation" ,
125
+ "this expression can be rewritten as" ,
126
+ format ! ( "{expr_sugg}.{shift_function}({amount})" ) ,
127
+ Applicability :: MachineApplicable ,
128
+ ) ;
109
129
}
110
130
}
111
131
}
0 commit comments