Skip to content

Commit bd2cb6a

Browse files
committed
Do not repeat identical code
This is a refactoring of the existing code to remove repetitive code.
1 parent 97bb063 commit bd2cb6a

File tree

1 file changed

+57
-85
lines changed

1 file changed

+57
-85
lines changed
Lines changed: 57 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
use clippy_utils::SpanlessEq;
21
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};
64
use rustc_errors::Applicability;
75
use rustc_hir::{BinOpKind, Expr, ExprKind};
86
use rustc_lint::{LateContext, LateLintPass};
9-
use rustc_middle::ty::Uint;
7+
use rustc_middle::ty;
108
use rustc_session::declare_lint_pass;
119

1210
declare_clippy_lint! {
@@ -35,88 +33,35 @@ declare_clippy_lint! {
3533

3634
declare_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

Comments
 (0)