|
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 | | - |
7 | 1 | use clippy_utils::diagnostics::span_lint_and_then; |
8 | 2 | 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; |
10 | 5 | use rustc_errors::Applicability; |
| 6 | +use rustc_hir::{Expr, ExprKind}; |
| 7 | +use rustc_lint::{LateContext, LateLintPass}; |
| 8 | +use rustc_session::declare_lint_pass; |
11 | 9 |
|
12 | 10 | declare_clippy_lint! { |
13 | 11 | /// ### What it does |
@@ -47,80 +45,64 @@ declare_clippy_lint! { |
47 | 45 | declare_lint_pass!(BoolToIntWithIf => [BOOL_TO_INT_WITH_IF]); |
48 | 46 |
|
49 | 47 | 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 | + }; |
84 | 74 |
|
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); |
93 | 77 |
|
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 | + } |
110 | 92 | } |
111 | 93 |
|
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 |
122 | 100 | { |
123 | | - Some(expr) |
| 101 | + match x.get() { |
| 102 | + 0 => Some(false), |
| 103 | + 1 => Some(true), |
| 104 | + _ => None, |
| 105 | + } |
124 | 106 | } else { |
125 | 107 | None |
126 | 108 | } |
|
0 commit comments