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