|
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