bool_to_int_with_if: properly handle macros (#14629)
- Do not replace macro results in then/else branches - Extract condition snippet from the right context - Make suggestion `MaybeIncorrect` if it would lead to losing comments changelog: [`bool_to_int_with_if`]: properly handle macros Fixes rust-lang/rust-clippy#14628
This commit is contained in:
commit
949b3bcfb5
4 changed files with 83 additions and 10 deletions
|
|
@ -1,6 +1,7 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::source::HasSession;
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::{is_else_clause, is_in_const_context};
|
||||
use clippy_utils::{higher, is_else_clause, is_in_const_context, span_contains_comment};
|
||||
use rustc_ast::LitKind;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
|
|
@ -46,18 +47,25 @@ declare_lint_pass!(BoolToIntWithIf => [BOOL_TO_INT_WITH_IF]);
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for BoolToIntWithIf {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
|
||||
if let ExprKind::If(cond, then, Some(else_)) = expr.kind
|
||||
&& matches!(cond.kind, ExprKind::DropTemps(_))
|
||||
if !expr.span.from_expansion()
|
||||
&& let Some(higher::If {
|
||||
cond,
|
||||
then,
|
||||
r#else: Some(r#else),
|
||||
}) = higher::If::hir(expr)
|
||||
&& let Some(then_lit) = as_int_bool_lit(then)
|
||||
&& let Some(else_lit) = as_int_bool_lit(else_)
|
||||
&& let Some(else_lit) = as_int_bool_lit(r#else)
|
||||
&& then_lit != else_lit
|
||||
&& !expr.span.from_expansion()
|
||||
&& !is_in_const_context(cx)
|
||||
{
|
||||
let ty = cx.typeck_results().expr_ty(then);
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let mut applicability = if span_contains_comment(cx.sess().source_map(), expr.span) {
|
||||
Applicability::MaybeIncorrect
|
||||
} else {
|
||||
Applicability::MachineApplicable
|
||||
};
|
||||
let snippet = {
|
||||
let mut sugg = Sugg::hir_with_applicability(cx, cond, "..", &mut applicability);
|
||||
let mut sugg = Sugg::hir_with_context(cx, cond, expr.span.ctxt(), "..", &mut applicability);
|
||||
if !then_lit {
|
||||
sugg = !sugg;
|
||||
}
|
||||
|
|
@ -91,10 +99,11 @@ impl<'tcx> LateLintPass<'tcx> for BoolToIntWithIf {
|
|||
}
|
||||
}
|
||||
|
||||
fn as_int_bool_lit(e: &Expr<'_>) -> Option<bool> {
|
||||
if let ExprKind::Block(b, _) = e.kind
|
||||
fn as_int_bool_lit(expr: &Expr<'_>) -> Option<bool> {
|
||||
if let ExprKind::Block(b, _) = expr.kind
|
||||
&& b.stmts.is_empty()
|
||||
&& let Some(e) = b.expr
|
||||
&& !e.span.from_expansion()
|
||||
&& let ExprKind::Lit(lit) = e.kind
|
||||
&& let LitKind::Int(x, _) = lit.node
|
||||
{
|
||||
|
|
|
|||
|
|
@ -117,3 +117,27 @@ fn if_let(a: Enum, b: Enum) {
|
|||
0
|
||||
};
|
||||
}
|
||||
|
||||
fn issue14628() {
|
||||
macro_rules! mac {
|
||||
(if $cond:expr, $then:expr, $else:expr) => {
|
||||
if $cond { $then } else { $else }
|
||||
};
|
||||
(zero) => {
|
||||
0
|
||||
};
|
||||
(one) => {
|
||||
1
|
||||
};
|
||||
}
|
||||
|
||||
let _ = i32::from(dbg!(4 > 0));
|
||||
//~^ bool_to_int_with_if
|
||||
|
||||
let _ = dbg!(i32::from(4 > 0));
|
||||
//~^ bool_to_int_with_if
|
||||
|
||||
let _ = mac!(if 4 > 0, 1, 0);
|
||||
let _ = if 4 > 0 { mac!(one) } else { 0 };
|
||||
let _ = if 4 > 0 { 1 } else { mac!(zero) };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -157,3 +157,27 @@ fn if_let(a: Enum, b: Enum) {
|
|||
0
|
||||
};
|
||||
}
|
||||
|
||||
fn issue14628() {
|
||||
macro_rules! mac {
|
||||
(if $cond:expr, $then:expr, $else:expr) => {
|
||||
if $cond { $then } else { $else }
|
||||
};
|
||||
(zero) => {
|
||||
0
|
||||
};
|
||||
(one) => {
|
||||
1
|
||||
};
|
||||
}
|
||||
|
||||
let _ = if dbg!(4 > 0) { 1 } else { 0 };
|
||||
//~^ bool_to_int_with_if
|
||||
|
||||
let _ = dbg!(if 4 > 0 { 1 } else { 0 });
|
||||
//~^ bool_to_int_with_if
|
||||
|
||||
let _ = mac!(if 4 > 0, 1, 0);
|
||||
let _ = if 4 > 0 { mac!(one) } else { 0 };
|
||||
let _ = if 4 > 0 { 1 } else { mac!(zero) };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -114,5 +114,21 @@ LL | if a { 1 } else { 0 }
|
|||
|
|
||||
= note: `a as u8` or `a.into()` can also be valid options
|
||||
|
||||
error: aborting due to 9 previous errors
|
||||
error: boolean to int conversion using if
|
||||
--> tests/ui/bool_to_int_with_if.rs:174:13
|
||||
|
|
||||
LL | let _ = if dbg!(4 > 0) { 1 } else { 0 };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with from: `i32::from(dbg!(4 > 0))`
|
||||
|
|
||||
= note: `dbg!(4 > 0) as i32` or `dbg!(4 > 0).into()` can also be valid options
|
||||
|
||||
error: boolean to int conversion using if
|
||||
--> tests/ui/bool_to_int_with_if.rs:177:18
|
||||
|
|
||||
LL | let _ = dbg!(if 4 > 0 { 1 } else { 0 });
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with from: `i32::from(4 > 0)`
|
||||
|
|
||||
= note: `(4 > 0) as i32` or `(4 > 0).into()` can also be valid options
|
||||
|
||||
error: aborting due to 11 previous errors
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue