1- use clippy_utils:: SpanlessEq ;
21use clippy_utils:: diagnostics:: span_lint_and_sugg;
3- use clippy_utils:: source:: snippet_with_applicability;
4- use rustc_ast:: LitKind ;
5- use rustc_data_structures:: packed:: Pu128 ;
2+ use clippy_utils:: sugg:: Sugg ;
3+ use clippy_utils:: { SpanlessEq , is_integer_literal} ;
64use rustc_errors:: Applicability ;
75use rustc_hir:: { BinOpKind , Expr , ExprKind } ;
86use rustc_lint:: { LateContext , LateLintPass } ;
9- use rustc_middle:: ty:: Uint ;
7+ use rustc_middle:: ty;
108use rustc_session:: declare_lint_pass;
119
1210declare_clippy_lint ! {
@@ -35,88 +33,35 @@ declare_clippy_lint! {
3533
3634declare_lint_pass ! ( ManualIsPowerOfTwo => [ MANUAL_IS_POWER_OF_TWO ] ) ;
3735
38- impl LateLintPass < ' _ > for ManualIsPowerOfTwo {
39- fn check_expr ( & mut self , cx : & LateContext < ' _ > , expr : & Expr < ' _ > ) {
40- let mut applicability = Applicability :: MachineApplicable ;
41-
42- if let ExprKind :: Binary ( bin_op, left, right) = expr. kind
36+ impl < ' tcx > LateLintPass < ' tcx > for ManualIsPowerOfTwo {
37+ fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & Expr < ' tcx > ) {
38+ if let ExprKind :: Binary ( bin_op, lhs, rhs) = expr. kind
4339 && bin_op. node == BinOpKind :: Eq
4440 {
45- // a.count_ones() == 1
46- if let ExprKind :: MethodCall ( method_name, receiver, [ ] , _) = left. kind
47- && method_name. ident . as_str ( ) == "count_ones"
48- && let & Uint ( _) = cx. typeck_results ( ) . expr_ty ( receiver) . kind ( )
49- && check_lit ( right, 1 )
41+ if let Some ( a) = count_ones_receiver ( cx, lhs)
42+ && is_integer_literal ( rhs, 1 )
5043 {
51- build_sugg ( cx, expr, receiver, & mut applicability) ;
52- }
53-
54- // 1 == a.count_ones()
55- if let ExprKind :: MethodCall ( method_name, receiver, [ ] , _) = right. kind
56- && method_name. ident . as_str ( ) == "count_ones"
57- && let & Uint ( _) = cx. typeck_results ( ) . expr_ty ( receiver) . kind ( )
58- && check_lit ( left, 1 )
59- {
60- build_sugg ( cx, expr, receiver, & mut applicability) ;
61- }
62-
63- // a & (a - 1) == 0
64- if let ExprKind :: Binary ( op1, left1, right1) = left. kind
65- && op1. node == BinOpKind :: BitAnd
66- && let ExprKind :: Binary ( op2, left2, right2) = right1. kind
67- && op2. node == BinOpKind :: Sub
68- && check_eq_expr ( cx, left1, left2)
69- && let & Uint ( _) = cx. typeck_results ( ) . expr_ty ( left1) . kind ( )
70- && check_lit ( right2, 1 )
71- && check_lit ( right, 0 )
44+ build_sugg ( cx, expr, a) ;
45+ } else if let Some ( a) = count_ones_receiver ( cx, rhs)
46+ && is_integer_literal ( lhs, 1 )
7247 {
73- build_sugg ( cx, expr, left1, & mut applicability) ;
74- }
75-
76- // (a - 1) & a == 0;
77- if let ExprKind :: Binary ( op1, left1, right1) = left. kind
78- && op1. node == BinOpKind :: BitAnd
79- && let ExprKind :: Binary ( op2, left2, right2) = left1. kind
80- && op2. node == BinOpKind :: Sub
81- && check_eq_expr ( cx, right1, left2)
82- && let & Uint ( _) = cx. typeck_results ( ) . expr_ty ( right1) . kind ( )
83- && check_lit ( right2, 1 )
84- && check_lit ( right, 0 )
48+ build_sugg ( cx, expr, a) ;
49+ } else if is_integer_literal ( rhs, 0 )
50+ && let Some ( a) = is_and_minus_one ( cx, lhs)
8551 {
86- build_sugg ( cx, expr, right1, & mut applicability) ;
87- }
88-
89- // 0 == a & (a - 1);
90- if let ExprKind :: Binary ( op1, left1, right1) = right. kind
91- && op1. node == BinOpKind :: BitAnd
92- && let ExprKind :: Binary ( op2, left2, right2) = right1. kind
93- && op2. node == BinOpKind :: Sub
94- && check_eq_expr ( cx, left1, left2)
95- && let & Uint ( _) = cx. typeck_results ( ) . expr_ty ( left1) . kind ( )
96- && check_lit ( right2, 1 )
97- && check_lit ( left, 0 )
52+ build_sugg ( cx, expr, a) ;
53+ } else if is_integer_literal ( lhs, 0 )
54+ && let Some ( a) = is_and_minus_one ( cx, rhs)
9855 {
99- build_sugg ( cx, expr, left1, & mut applicability) ;
100- }
101-
102- // 0 == (a - 1) & a
103- if let ExprKind :: Binary ( op1, left1, right1) = right. kind
104- && op1. node == BinOpKind :: BitAnd
105- && let ExprKind :: Binary ( op2, left2, right2) = left1. kind
106- && op2. node == BinOpKind :: Sub
107- && check_eq_expr ( cx, right1, left2)
108- && let & Uint ( _) = cx. typeck_results ( ) . expr_ty ( right1) . kind ( )
109- && check_lit ( right2, 1 )
110- && check_lit ( left, 0 )
111- {
112- build_sugg ( cx, expr, right1, & mut applicability) ;
56+ build_sugg ( cx, expr, a) ;
11357 }
11458 }
11559 }
11660}
11761
118- fn build_sugg ( cx : & LateContext < ' _ > , expr : & Expr < ' _ > , receiver : & Expr < ' _ > , applicability : & mut Applicability ) {
119- let snippet = snippet_with_applicability ( cx, receiver. span , ".." , applicability) ;
62+ fn build_sugg ( cx : & LateContext < ' _ > , expr : & Expr < ' _ > , receiver : & Expr < ' _ > ) {
63+ let mut applicability = Applicability :: MachineApplicable ;
64+ let snippet = Sugg :: hir_with_applicability ( cx, receiver, "_" , & mut applicability) ;
12065
12166 span_lint_and_sugg (
12267 cx,
@@ -125,20 +70,47 @@ fn build_sugg(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, applic
12570 "manually reimplementing `is_power_of_two`" ,
12671 "consider using `.is_power_of_two()`" ,
12772 format ! ( "{snippet}.is_power_of_two()" ) ,
128- * applicability,
73+ applicability,
12974 ) ;
13075}
13176
132- fn check_lit ( expr : & Expr < ' _ > , expected_num : u128 ) -> bool {
133- if let ExprKind :: Lit ( lit) = expr. kind
134- && let LitKind :: Int ( Pu128 ( num) , _) = lit. node
135- && num == expected_num
77+ /// Return the unsigned integer receiver of `.count_ones()`
78+ fn count_ones_receiver < ' tcx > ( cx : & LateContext < ' tcx > , expr : & Expr < ' tcx > ) -> Option < & ' tcx Expr < ' tcx > > {
79+ if let ExprKind :: MethodCall ( method_name, receiver, [ ] , _) = expr. kind
80+ && method_name. ident . as_str ( ) == "count_ones"
81+ && matches ! ( cx. typeck_results( ) . expr_ty_adjusted( receiver) . kind( ) , ty:: Uint ( _) )
13682 {
137- return true ;
83+ Some ( receiver)
84+ } else {
85+ None
13886 }
139- false
14087}
14188
142- fn check_eq_expr ( cx : & LateContext < ' _ > , lhs : & Expr < ' _ > , rhs : & Expr < ' _ > ) -> bool {
143- SpanlessEq :: new ( cx) . eq_expr ( lhs, rhs)
89+ /// Return `greater` if `smaller == greater - 1`
90+ fn is_one_less < ' tcx > (
91+ cx : & LateContext < ' tcx > ,
92+ greater : & ' tcx Expr < ' tcx > ,
93+ smaller : & Expr < ' tcx > ,
94+ ) -> Option < & ' tcx Expr < ' tcx > > {
95+ if let ExprKind :: Binary ( op, lhs, rhs) = smaller. kind
96+ && op. node == BinOpKind :: Sub
97+ && SpanlessEq :: new ( cx) . eq_expr ( greater, lhs)
98+ && is_integer_literal ( rhs, 1 )
99+ && matches ! ( cx. typeck_results( ) . expr_ty_adjusted( greater) . kind( ) , ty:: Uint ( _) )
100+ {
101+ Some ( greater)
102+ } else {
103+ None
104+ }
105+ }
106+
107+ /// Return `v` if `expr` is `v & (v - 1)` or `(v - 1) & v`
108+ fn is_and_minus_one < ' tcx > ( cx : & LateContext < ' tcx > , expr : & Expr < ' tcx > ) -> Option < & ' tcx Expr < ' tcx > > {
109+ if let ExprKind :: Binary ( op, lhs, rhs) = expr. kind
110+ && op. node == BinOpKind :: BitAnd
111+ {
112+ is_one_less ( cx, lhs, rhs) . or_else ( || is_one_less ( cx, rhs, lhs) )
113+ } else {
114+ None
115+ }
144116}
0 commit comments