|
1 |
| -use clippy_utils::diagnostics::span_lint_and_sugg; |
| 1 | +use std::borrow::Cow; |
| 2 | + |
| 3 | +use clippy_utils::diagnostics::span_lint_and_then; |
| 4 | +use clippy_utils::source::{HasSession, SpanRangeExt as _}; |
2 | 5 | use rustc_errors::Applicability;
|
3 |
| -use rustc_hir::{GenericArg, HirId, LetStmt, Node, Path, TyKind}; |
| 6 | +use rustc_hir::{Expr, GenericArg, HirId, LetStmt, Node, Path, TyKind}; |
4 | 7 | use rustc_lint::LateContext;
|
5 |
| -use rustc_middle::ty::Ty; |
| 8 | +use rustc_middle::ty::{self, Ty}; |
| 9 | +use rustc_span::Span; |
6 | 10 |
|
7 | 11 | use crate::transmute::MISSING_TRANSMUTE_ANNOTATIONS;
|
8 | 12 |
|
@@ -38,6 +42,7 @@ fn is_function_block(cx: &LateContext<'_>, expr_hir_id: HirId) -> bool {
|
38 | 42 | pub(super) fn check<'tcx>(
|
39 | 43 | cx: &LateContext<'tcx>,
|
40 | 44 | path: &Path<'tcx>,
|
| 45 | + arg: &Expr<'tcx>, |
41 | 46 | from_ty: Ty<'tcx>,
|
42 | 47 | to_ty: Ty<'tcx>,
|
43 | 48 | expr_hir_id: HirId,
|
@@ -68,14 +73,48 @@ pub(super) fn check<'tcx>(
|
68 | 73 | } else if is_function_block(cx, expr_hir_id) {
|
69 | 74 | return false;
|
70 | 75 | }
|
71 |
| - span_lint_and_sugg( |
| 76 | + let span = last.ident.span.with_hi(path.span.hi()); |
| 77 | + span_lint_and_then( |
72 | 78 | cx,
|
73 | 79 | MISSING_TRANSMUTE_ANNOTATIONS,
|
74 |
| - last.ident.span.with_hi(path.span.hi()), |
| 80 | + span, |
75 | 81 | "transmute used without annotations",
|
76 |
| - "consider adding missing annotations", |
77 |
| - format!("{}::<{from_ty}, {to_ty}>", last.ident), |
78 |
| - Applicability::MaybeIncorrect, |
| 82 | + |diag| { |
| 83 | + let from_ty_no_name = ty_cannot_be_named(from_ty); |
| 84 | + let to_ty_no_name = ty_cannot_be_named(to_ty); |
| 85 | + if from_ty_no_name || to_ty_no_name { |
| 86 | + let to_name = match (from_ty_no_name, to_ty_no_name) { |
| 87 | + (true, false) => maybe_name_by_expr(cx, arg.span, "the origin type"), |
| 88 | + (false, true) => "the destination type".into(), |
| 89 | + _ => "the source and destination types".into(), |
| 90 | + }; |
| 91 | + diag.help(format!( |
| 92 | + "consider giving {to_name} a name, and adding missing type annotations" |
| 93 | + )); |
| 94 | + } else { |
| 95 | + diag.span_suggestion( |
| 96 | + span, |
| 97 | + "consider adding missing annotations", |
| 98 | + format!("{}::<{from_ty}, {to_ty}>", last.ident), |
| 99 | + Applicability::MaybeIncorrect, |
| 100 | + ); |
| 101 | + } |
| 102 | + }, |
79 | 103 | );
|
80 | 104 | true
|
81 | 105 | }
|
| 106 | + |
| 107 | +fn ty_cannot_be_named(ty: Ty<'_>) -> bool { |
| 108 | + matches!( |
| 109 | + ty.kind(), |
| 110 | + ty::Alias(ty::AliasTyKind::Opaque | ty::AliasTyKind::Inherent, _) |
| 111 | + ) |
| 112 | +} |
| 113 | + |
| 114 | +fn maybe_name_by_expr<'a>(sess: &impl HasSession, span: Span, default: &'a str) -> Cow<'a, str> { |
| 115 | + span.with_source_text(sess, |name| { |
| 116 | + (name.len() + 9 < default.len()).then_some(format!("`{name}`'s type").into()) |
| 117 | + }) |
| 118 | + .flatten() |
| 119 | + .unwrap_or(default.into()) |
| 120 | +} |
0 commit comments