Add ref_as_ptr lint

Author:    Marcin Serwin <marcin.serwin0@protonmail.com>
This commit is contained in:
Marcin Serwin 2024-01-02 22:54:17 +01:00 committed by blyxyas
parent bc962c246a
commit a3baebcb31
No known key found for this signature in database
GPG key ID: 9698805551971573
17 changed files with 588 additions and 10 deletions

View file

@ -18,6 +18,7 @@ mod fn_to_numeric_cast_any;
mod fn_to_numeric_cast_with_truncation;
mod ptr_as_ptr;
mod ptr_cast_constness;
mod ref_as_ptr;
mod unnecessary_cast;
mod utils;
mod zero_ptr;
@ -689,6 +690,30 @@ declare_clippy_lint! {
"using `0 as *{const, mut} T`"
}
declare_clippy_lint! {
/// ### What it does
/// Checks for casts of references to pointer using `as`
/// and suggests `std::ptr::from_ref` and `std::ptr::from_mut` instead.
///
/// ### Why is this bad?
/// Using `as` casts may result in silently changing mutability or type.
///
/// ### Example
/// ```no_run
/// let a_ref = &1;
/// let a_ptr = a_ref as *const _;
/// ```
/// Use instead:
/// ```no_run
/// let a_ref = &1;
/// let a_ptr = std::ptr::from_ref(a_ref);
/// ```
#[clippy::version = "1.77.0"]
pub REF_AS_PTR,
pedantic,
"using `as` to cast a reference to pointer"
}
pub struct Casts {
msrv: Msrv,
}
@ -724,6 +749,7 @@ impl_lint_pass!(Casts => [
AS_PTR_CAST_MUT,
CAST_NAN_TO_INT,
ZERO_PTR,
REF_AS_PTR,
]);
impl<'tcx> LateLintPass<'tcx> for Casts {
@ -771,7 +797,9 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
as_underscore::check(cx, expr, cast_to_hir);
if self.msrv.meets(msrvs::BORROW_AS_PTR) {
if self.msrv.meets(msrvs::PTR_FROM_REF) {
ref_as_ptr::check(cx, expr, cast_expr, cast_to_hir);
} else if self.msrv.meets(msrvs::BORROW_AS_PTR) {
borrow_as_ptr::check(cx, expr, cast_expr, cast_to_hir);
}
}

View file

@ -0,0 +1,55 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::is_no_std_crate;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::sugg::Sugg;
use rustc_errors::Applicability;
use rustc_hir::{Expr, Mutability, Ty, TyKind};
use rustc_lint::LateContext;
use rustc_middle::ty::{self, TypeAndMut};
use super::REF_AS_PTR;
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_to_hir_ty: &Ty<'_>) {
let (cast_from, cast_to) = (
cx.typeck_results().expr_ty(cast_expr),
cx.typeck_results().expr_ty(expr),
);
if matches!(cast_from.kind(), ty::Ref(..))
&& let ty::RawPtr(TypeAndMut { mutbl: to_mutbl, .. }) = cast_to.kind()
{
let core_or_std = if is_no_std_crate(cx) { "core" } else { "std" };
let fn_name = match to_mutbl {
Mutability::Not => "from_ref",
Mutability::Mut => "from_mut",
};
let mut app = Applicability::MachineApplicable;
let turbofish = match &cast_to_hir_ty.kind {
TyKind::Infer => String::new(),
TyKind::Ptr(mut_ty) => {
if matches!(mut_ty.ty.kind, TyKind::Infer) {
String::new()
} else {
format!(
"::<{}>",
snippet_with_applicability(cx, mut_ty.ty.span, "/* type */", &mut app)
)
}
},
_ => return,
};
let cast_expr_sugg = Sugg::hir_with_applicability(cx, cast_expr, "_", &mut app);
span_lint_and_sugg(
cx,
REF_AS_PTR,
expr.span,
"reference as raw pointer",
"try",
format!("{core_or_std}::ptr::{fn_name}{turbofish}({cast_expr_sugg})"),
app,
);
}
}

View file

@ -96,6 +96,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION_INFO,
crate::casts::PTR_AS_PTR_INFO,
crate::casts::PTR_CAST_CONSTNESS_INFO,
crate::casts::REF_AS_PTR_INFO,
crate::casts::UNNECESSARY_CAST_INFO,
crate::casts::ZERO_PTR_INFO,
crate::checked_conversions::CHECKED_CONVERSIONS_INFO,

View file

@ -252,7 +252,7 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
{
(
trait_item_id,
FnKind::ImplTraitFn(cx.tcx.erase_regions(trait_ref.args) as *const _ as usize),
FnKind::ImplTraitFn(std::ptr::from_ref(cx.tcx.erase_regions(trait_ref.args)) as usize),
usize::from(sig.decl.implicit_self.has_implicit_self()),
)
} else {
@ -390,7 +390,6 @@ fn has_matching_args(kind: FnKind, args: GenericArgsRef<'_>) -> bool {
GenericArgKind::Type(ty) => matches!(*ty.kind(), ty::Param(ty) if ty.index as usize == idx),
GenericArgKind::Const(c) => matches!(c.kind(), ConstKind::Param(c) if c.index as usize == idx),
}),
#[allow(trivial_casts)]
FnKind::ImplTraitFn(expected_args) => args as *const _ as usize == expected_args,
FnKind::ImplTraitFn(expected_args) => std::ptr::from_ref(args) as usize == expected_args,
}
}