Suggest naming types before using explicit type names

`missing_transmute_annotations` will suggest naming the origin and
destination types if they do not have explicit names already.

Co-authored-by: Alejandra González <blyxyas@gmail.com>
This commit is contained in:
Samuel Tardieu
2025-06-06 11:43:28 +02:00
parent 6bb0c97409
commit a7ff2b0126
4 changed files with 113 additions and 9 deletions
@@ -1,8 +1,12 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use std::borrow::Cow;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::{HasSession, SpanRangeExt as _};
use rustc_errors::Applicability;
use rustc_hir::{GenericArg, HirId, LetStmt, Node, Path, TyKind};
use rustc_hir::{Expr, GenericArg, HirId, LetStmt, Node, Path, TyKind};
use rustc_lint::LateContext;
use rustc_middle::ty::Ty;
use rustc_middle::ty::{self, Ty};
use rustc_span::Span;
use crate::transmute::MISSING_TRANSMUTE_ANNOTATIONS;
@@ -38,6 +42,7 @@ fn is_function_block(cx: &LateContext<'_>, expr_hir_id: HirId) -> bool {
pub(super) fn check<'tcx>(
cx: &LateContext<'tcx>,
path: &Path<'tcx>,
arg: &Expr<'tcx>,
from_ty: Ty<'tcx>,
to_ty: Ty<'tcx>,
expr_hir_id: HirId,
@@ -68,14 +73,48 @@ pub(super) fn check<'tcx>(
} else if is_function_block(cx, expr_hir_id) {
return false;
}
span_lint_and_sugg(
let span = last.ident.span.with_hi(path.span.hi());
span_lint_and_then(
cx,
MISSING_TRANSMUTE_ANNOTATIONS,
last.ident.span.with_hi(path.span.hi()),
span,
"transmute used without annotations",
"consider adding missing annotations",
format!("{}::<{from_ty}, {to_ty}>", last.ident),
Applicability::MaybeIncorrect,
|diag| {
let from_ty_no_name = ty_cannot_be_named(from_ty);
let to_ty_no_name = ty_cannot_be_named(to_ty);
if from_ty_no_name || to_ty_no_name {
let to_name = match (from_ty_no_name, to_ty_no_name) {
(true, false) => maybe_name_by_expr(cx, arg.span, "the origin type"),
(false, true) => "the destination type".into(),
_ => "the source and destination types".into(),
};
diag.help(format!(
"consider giving {to_name} a name, and adding missing type annotations"
));
} else {
diag.span_suggestion(
span,
"consider adding missing annotations",
format!("{}::<{from_ty}, {to_ty}>", last.ident),
Applicability::MaybeIncorrect,
);
}
},
);
true
}
fn ty_cannot_be_named(ty: Ty<'_>) -> bool {
matches!(
ty.kind(),
ty::Alias(ty::AliasTyKind::Opaque | ty::AliasTyKind::Inherent, _)
)
}
fn maybe_name_by_expr<'a>(sess: &impl HasSession, span: Span, default: &'a str) -> Cow<'a, str> {
span.with_source_text(sess, |name| {
(name.len() + 9 < default.len()).then_some(format!("`{name}`'s type").into())
})
.flatten()
.unwrap_or(default.into())
}
+1 -1
View File
@@ -520,7 +520,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
| transmuting_null::check(cx, e, arg, to_ty)
| transmute_null_to_fn::check(cx, e, arg, to_ty)
| transmute_ptr_to_ref::check(cx, e, from_ty, to_ty, arg, path, self.msrv)
| missing_transmute_annotations::check(cx, path, from_ty, to_ty, e.hir_id)
| missing_transmute_annotations::check(cx, path, arg, from_ty, to_ty, e.hir_id)
| transmute_ref_to_ref::check(cx, e, from_ty, to_ty, arg, const_context)
| transmute_ptr_to_ptr::check(cx, e, from_ty, to_ty, arg, self.msrv)
| transmute_int_to_bool::check(cx, e, from_ty, to_ty, arg)
@@ -0,0 +1,29 @@
//@no-rustfix
fn issue14984() {
async fn e() {}
async fn x() -> u32 {
0
}
async fn y() -> f32 {
0.0
};
let mut yy = unsafe { std::ptr::read(&y()) };
yy = unsafe { std::mem::transmute(std::ptr::read(&x())) };
//~^ missing_transmute_annotations
let mut zz = 0u8;
zz = unsafe { std::mem::transmute(std::ptr::read(&x())) };
//~^ missing_transmute_annotations
yy = unsafe { std::mem::transmute(zz) };
//~^ missing_transmute_annotations
fn a() -> impl Sized {
0u32
}
let mut b: f32 = 0.0;
b = unsafe { std::mem::transmute(a()) };
//~^ missing_transmute_annotations
}
@@ -0,0 +1,36 @@
error: transmute used without annotations
--> tests/ui/missing_transmute_annotations_unfixable.rs:12:29
|
LL | yy = unsafe { std::mem::transmute(std::ptr::read(&x())) };
| ^^^^^^^^^
|
= help: consider giving the source and destination types a name, and adding missing type annotations
= note: `-D clippy::missing-transmute-annotations` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::missing_transmute_annotations)]`
error: transmute used without annotations
--> tests/ui/missing_transmute_annotations_unfixable.rs:16:29
|
LL | zz = unsafe { std::mem::transmute(std::ptr::read(&x())) };
| ^^^^^^^^^
|
= help: consider giving the origin type a name, and adding missing type annotations
error: transmute used without annotations
--> tests/ui/missing_transmute_annotations_unfixable.rs:19:29
|
LL | yy = unsafe { std::mem::transmute(zz) };
| ^^^^^^^^^
|
= help: consider giving the destination type a name, and adding missing type annotations
error: transmute used without annotations
--> tests/ui/missing_transmute_annotations_unfixable.rs:27:28
|
LL | b = unsafe { std::mem::transmute(a()) };
| ^^^^^^^^^
|
= help: consider giving `a()`'s type a name, and adding missing type annotations
error: aborting due to 4 previous errors