@@ -85,28 +85,49 @@ impl LateLintPass<'_> for ManualRotate {
8585 let const_eval = ConstEvalCtxt :: new ( cx) ;
8686
8787 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)
8990 && let Some ( Constant :: Int ( r_amount_val) ) = const_eval. eval_local ( r_amount, ctxt)
9091 && l_amount_val + r_amount_val == u128:: from ( bit_width)
9192 {
92- let ( shift_function , amount ) = if l_amount_val < r_amount_val {
93+ if l_amount_val < r_amount_val {
9394 ( l_shift_dir, l_amount)
9495 } else {
9596 ( 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 ,
96103 } ;
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+ ) ;
110131 }
111132 }
112133}
0 commit comments