|
1 | 1 | use clippy_utils::diagnostics::span_lint_and_sugg; |
2 | | -use clippy_utils::source::snippet_opt; |
3 | | -use clippy_utils::{meets_msrv, msrvs}; |
| 2 | +use clippy_utils::source::snippet_with_applicability; |
| 3 | +use clippy_utils::{get_parent_expr, meets_msrv, msrvs}; |
4 | 4 | use rustc_ast::ast::LitKind; |
5 | 5 | use rustc_errors::Applicability; |
6 | 6 | use rustc_hir::{BinOpKind, Expr, ExprKind, GenericArg, QPath}; |
@@ -59,16 +59,19 @@ impl<'tcx> LateLintPass<'tcx> for ManualBits { |
59 | 59 | if matches!(resolved_ty.kind(), ty::Int(_) | ty::Uint(_)); |
60 | 60 | if let ExprKind::Lit(lit) = &other_expr.kind; |
61 | 61 | if let LitKind::Int(8, _) = lit.node; |
62 | | - |
63 | 62 | then { |
| 63 | + let mut app = Applicability::MachineApplicable; |
| 64 | + let ty_snip = snippet_with_applicability(cx, real_ty.span, "..", &mut app); |
| 65 | + let sugg = create_sugg(cx, expr, format!("{ty_snip}::BITS")); |
| 66 | + |
64 | 67 | span_lint_and_sugg( |
65 | 68 | cx, |
66 | 69 | MANUAL_BITS, |
67 | 70 | expr.span, |
68 | 71 | "usage of `mem::size_of::<T>()` to obtain the size of `T` in bits", |
69 | 72 | "consider using", |
70 | | - format!("{}::BITS", snippet_opt(cx, real_ty.span).unwrap()), |
71 | | - Applicability::MachineApplicable, |
| 73 | + sugg, |
| 74 | + app, |
72 | 75 | ); |
73 | 76 | } |
74 | 77 | } |
@@ -108,3 +111,36 @@ fn get_size_of_ty<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option< |
108 | 111 | } |
109 | 112 | } |
110 | 113 | } |
| 114 | + |
| 115 | +fn create_sugg(cx: &LateContext<'_>, expr: &Expr<'_>, base_sugg: String) -> String { |
| 116 | + if let Some(parent_expr) = get_parent_expr(cx, expr) { |
| 117 | + if is_ty_conversion(parent_expr) { |
| 118 | + return base_sugg; |
| 119 | + } |
| 120 | + |
| 121 | + // These expressions have precedence over casts, the suggestion therefore |
| 122 | + // needs to be wrapped into parentheses |
| 123 | + match parent_expr.kind { |
| 124 | + ExprKind::Unary(..) | ExprKind::AddrOf(..) | ExprKind::MethodCall(..) => { |
| 125 | + return format!("({base_sugg} as usize)"); |
| 126 | + }, |
| 127 | + _ => {}, |
| 128 | + } |
| 129 | + } |
| 130 | + |
| 131 | + format!("{base_sugg} as usize") |
| 132 | +} |
| 133 | + |
| 134 | +fn is_ty_conversion(expr: &Expr<'_>) -> bool { |
| 135 | + if let ExprKind::Cast(..) = expr.kind { |
| 136 | + true |
| 137 | + } else if let ExprKind::MethodCall(path, [_], _) = expr.kind |
| 138 | + && path.ident.name == rustc_span::sym::try_into |
| 139 | + { |
| 140 | + // This is only called for `usize` which implements `TryInto`. Therefore, |
| 141 | + // we don't have to check here if `self` implements the `TryInto` trait. |
| 142 | + true |
| 143 | + } else { |
| 144 | + false |
| 145 | + } |
| 146 | +} |
0 commit comments