1
- use clippy_utils:: SpanlessEq ;
2
1
use 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} ;
6
4
use rustc_errors:: Applicability ;
7
5
use rustc_hir:: { BinOpKind , Expr , ExprKind } ;
8
6
use rustc_lint:: { LateContext , LateLintPass } ;
9
- use rustc_middle:: ty:: Uint ;
7
+ use rustc_middle:: ty;
10
8
use rustc_session:: declare_lint_pass;
11
9
12
10
declare_clippy_lint ! {
@@ -35,88 +33,35 @@ declare_clippy_lint! {
35
33
36
34
declare_lint_pass ! ( ManualIsPowerOfTwo => [ MANUAL_IS_POWER_OF_TWO ] ) ;
37
35
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
43
39
&& bin_op. node == BinOpKind :: Eq
44
40
{
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 )
50
43
{
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 )
72
47
{
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)
85
51
{
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)
98
55
{
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) ;
113
57
}
114
58
}
115
59
}
116
60
}
117
61
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) ;
120
65
121
66
span_lint_and_sugg (
122
67
cx,
@@ -125,20 +70,47 @@ fn build_sugg(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, applic
125
70
"manually reimplementing `is_power_of_two`" ,
126
71
"consider using `.is_power_of_two()`" ,
127
72
format ! ( "{snippet}.is_power_of_two()" ) ,
128
- * applicability,
73
+ applicability,
129
74
) ;
130
75
}
131
76
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 ( _) )
136
82
{
137
- return true ;
83
+ Some ( receiver)
84
+ } else {
85
+ None
138
86
}
139
- false
140
87
}
141
88
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
+ }
144
116
}
0 commit comments