|
| 1 | +use crate::methods::TYPE_ID_ON_BOX; |
| 2 | +use clippy_utils::diagnostics::span_lint_and_then; |
| 3 | +use clippy_utils::source::snippet; |
| 4 | +use rustc_errors::Applicability; |
| 5 | +use rustc_hir::Expr; |
| 6 | +use rustc_lint::LateContext; |
| 7 | +use rustc_middle::ty::adjustment::Adjust; |
| 8 | +use rustc_middle::ty::adjustment::Adjustment; |
| 9 | +use rustc_middle::ty::Ty; |
| 10 | +use rustc_middle::ty::{self, ExistentialPredicate}; |
| 11 | +use rustc_span::{sym, Span}; |
| 12 | + |
| 13 | +fn is_dyn_any(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { |
| 14 | + if let ty::Dynamic(preds, ..) = ty.kind() { |
| 15 | + preds.iter().any(|p| match p.skip_binder() { |
| 16 | + ExistentialPredicate::Trait(tr) => cx.tcx.is_diagnostic_item(sym::Any, tr.def_id), |
| 17 | + _ => false, |
| 18 | + }) |
| 19 | + } else { |
| 20 | + false |
| 21 | + } |
| 22 | +} |
| 23 | + |
| 24 | +pub(super) fn check(cx: &LateContext<'_>, receiver: &Expr<'_>, call_span: Span) { |
| 25 | + let recv_adjusts = cx.typeck_results().expr_adjustments(receiver); |
| 26 | + |
| 27 | + if let Some(Adjustment { target: recv_ty, .. }) = recv_adjusts.last() |
| 28 | + && let ty::Ref(_, ty, _) = recv_ty.kind() |
| 29 | + && let ty::Adt(adt, substs) = ty.kind() |
| 30 | + && adt.is_box() |
| 31 | + && is_dyn_any(cx, substs.type_at(0)) |
| 32 | + { |
| 33 | + span_lint_and_then( |
| 34 | + cx, |
| 35 | + TYPE_ID_ON_BOX, |
| 36 | + call_span, |
| 37 | + "calling `.type_id()` on a `Box<dyn Any>`", |
| 38 | + |diag| { |
| 39 | + let derefs = recv_adjusts |
| 40 | + .iter() |
| 41 | + .filter(|adj| matches!(adj.kind, Adjust::Deref(None))) |
| 42 | + .count(); |
| 43 | + |
| 44 | + let mut sugg = "*".repeat(derefs + 1); |
| 45 | + sugg += &snippet(cx, receiver.span, "<expr>"); |
| 46 | + |
| 47 | + diag.note( |
| 48 | + "this returns the type id of the literal type `Box<dyn Any>` instead of the \ |
| 49 | + type id of the boxed value, which is most likely not what you want" |
| 50 | + ) |
| 51 | + .note( |
| 52 | + "if this is intentional, use `TypeId::of::<Box<dyn Any>>()` instead, \ |
| 53 | + which makes it more clear" |
| 54 | + ) |
| 55 | + .span_suggestion( |
| 56 | + receiver.span, |
| 57 | + "consider dereferencing first", |
| 58 | + format!("({sugg})"), |
| 59 | + Applicability::MaybeIncorrect, |
| 60 | + ); |
| 61 | + }, |
| 62 | + ); |
| 63 | + } |
| 64 | +} |
0 commit comments