Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 47 additions & 8 deletions clippy_lints/src/transmute/missing_transmute_annotations.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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())
}
2 changes: 1 addition & 1 deletion clippy_lints/src/transmute/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
| 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)
Expand Down
29 changes: 29 additions & 0 deletions tests/ui/missing_transmute_annotations_unfixable.rs
Original file line number Diff line number Diff line change
@@ -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
}
36 changes: 36 additions & 0 deletions tests/ui/missing_transmute_annotations_unfixable.stderr
Original file line number Diff line number Diff line change
@@ -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