Skip to content

Commit e64236c

Browse files
committed
Auto merge of #13044 - Jarcho:bool_int, r=Manishearth
Refactor `bool_to_int_with_if` Rearranges things to check the HIR tree first and simplifies how the literals are read. changelog: None
2 parents 058e6ea + 9d8a177 commit e64236c

File tree

1 file changed

+58
-76
lines changed

1 file changed

+58
-76
lines changed

clippy_lints/src/bool_to_int_with_if.rs

+58-76
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
1-
use clippy_utils::higher::If;
2-
use rustc_ast::LitKind;
3-
use rustc_hir::{Block, ExprKind};
4-
use rustc_lint::{LateContext, LateLintPass};
5-
use rustc_session::declare_lint_pass;
6-
71
use clippy_utils::diagnostics::span_lint_and_then;
82
use clippy_utils::sugg::Sugg;
9-
use clippy_utils::{in_constant, is_else_clause, is_integer_literal};
3+
use clippy_utils::{in_constant, is_else_clause};
4+
use rustc_ast::LitKind;
105
use rustc_errors::Applicability;
6+
use rustc_hir::{Expr, ExprKind};
7+
use rustc_lint::{LateContext, LateLintPass};
8+
use rustc_session::declare_lint_pass;
119

1210
declare_clippy_lint! {
1311
/// ### What it does
@@ -47,80 +45,64 @@ declare_clippy_lint! {
4745
declare_lint_pass!(BoolToIntWithIf => [BOOL_TO_INT_WITH_IF]);
4846

4947
impl<'tcx> LateLintPass<'tcx> for BoolToIntWithIf {
50-
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) {
51-
if !expr.span.from_expansion() && !in_constant(cx, expr.hir_id) {
52-
check_if_else(cx, expr);
53-
}
54-
}
55-
}
56-
57-
fn check_if_else<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) {
58-
if let Some(If {
59-
cond,
60-
then,
61-
r#else: Some(r#else),
62-
}) = If::hir(expr)
63-
&& let Some(then_lit) = int_literal(then)
64-
&& let Some(else_lit) = int_literal(r#else)
65-
{
66-
let inverted = if is_integer_literal(then_lit, 1) && is_integer_literal(else_lit, 0) {
67-
false
68-
} else if is_integer_literal(then_lit, 0) && is_integer_literal(else_lit, 1) {
69-
true
70-
} else {
71-
// Expression isn't boolean, exit
72-
return;
73-
};
74-
let mut applicability = Applicability::MachineApplicable;
75-
let snippet = {
76-
let mut sugg = Sugg::hir_with_applicability(cx, cond, "..", &mut applicability);
77-
if inverted {
78-
sugg = !sugg;
79-
}
80-
sugg
81-
};
82-
83-
let ty = cx.typeck_results().expr_ty(then_lit); // then and else must be of same type
48+
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
49+
if let ExprKind::If(cond, then, Some(else_)) = expr.kind
50+
&& matches!(cond.kind, ExprKind::DropTemps(_))
51+
&& let Some(then_lit) = as_int_bool_lit(then)
52+
&& let Some(else_lit) = as_int_bool_lit(else_)
53+
&& then_lit != else_lit
54+
&& !expr.span.from_expansion()
55+
&& !in_constant(cx, expr.hir_id)
56+
{
57+
let ty = cx.typeck_results().expr_ty(then);
58+
let mut applicability = Applicability::MachineApplicable;
59+
let snippet = {
60+
let mut sugg = Sugg::hir_with_applicability(cx, cond, "..", &mut applicability);
61+
if !then_lit {
62+
sugg = !sugg;
63+
}
64+
sugg
65+
};
66+
let suggestion = {
67+
let mut s = Sugg::NonParen(format!("{ty}::from({snippet})").into());
68+
// when used in else clause if statement should be wrapped in curly braces
69+
if is_else_clause(cx.tcx, expr) {
70+
s = s.blockify();
71+
}
72+
s
73+
};
8474

85-
let suggestion = {
86-
let wrap_in_curly = is_else_clause(cx.tcx, expr);
87-
let mut s = Sugg::NonParen(format!("{ty}::from({snippet})").into());
88-
if wrap_in_curly {
89-
s = s.blockify();
90-
}
91-
s
92-
}; // when used in else clause if statement should be wrapped in curly braces
75+
let into_snippet = snippet.clone().maybe_par();
76+
let as_snippet = snippet.as_ty(ty);
9377

94-
let into_snippet = snippet.clone().maybe_par();
95-
let as_snippet = snippet.as_ty(ty);
96-
97-
span_lint_and_then(
98-
cx,
99-
BOOL_TO_INT_WITH_IF,
100-
expr.span,
101-
"boolean to int conversion using if",
102-
|diag| {
103-
diag.span_suggestion(expr.span, "replace with from", suggestion, applicability);
104-
diag.note(format!(
105-
"`{as_snippet}` or `{into_snippet}.into()` can also be valid options"
106-
));
107-
},
108-
);
109-
};
78+
span_lint_and_then(
79+
cx,
80+
BOOL_TO_INT_WITH_IF,
81+
expr.span,
82+
"boolean to int conversion using if",
83+
|diag| {
84+
diag.span_suggestion(expr.span, "replace with from", suggestion, applicability);
85+
diag.note(format!(
86+
"`{as_snippet}` or `{into_snippet}.into()` can also be valid options"
87+
));
88+
},
89+
);
90+
}
91+
}
11092
}
11193

112-
// If block contains only a int literal expression, return literal expression
113-
fn int_literal<'tcx>(expr: &'tcx rustc_hir::Expr<'tcx>) -> Option<&'tcx rustc_hir::Expr<'tcx>> {
114-
if let ExprKind::Block(block, _) = expr.kind
115-
&& let Block {
116-
stmts: [], // Shouldn't lint if statements with side effects
117-
expr: Some(expr),
118-
..
119-
} = block
120-
&& let ExprKind::Lit(lit) = &expr.kind
121-
&& let LitKind::Int(_, _) = lit.node
94+
fn as_int_bool_lit(e: &Expr<'_>) -> Option<bool> {
95+
if let ExprKind::Block(b, _) = e.kind
96+
&& b.stmts.is_empty()
97+
&& let Some(e) = b.expr
98+
&& let ExprKind::Lit(lit) = e.kind
99+
&& let LitKind::Int(x, _) = lit.node
122100
{
123-
Some(expr)
101+
match x.get() {
102+
0 => Some(false),
103+
1 => Some(true),
104+
_ => None,
105+
}
124106
} else {
125107
None
126108
}

0 commit comments

Comments
 (0)