rust/clippy_lints/src/casts/ptr_cast_constness.rs
2024-11-28 19:38:59 +01:00

100 lines
3.8 KiB
Rust

use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::std_or_core;
use clippy_utils::sugg::Sugg;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, Mutability, QPath};
use rustc_lint::LateContext;
use rustc_middle::ty::{self, Ty, TypeVisitableExt};
use rustc_span::sym;
use super::PTR_CAST_CONSTNESS;
pub(super) fn check<'tcx>(
cx: &LateContext<'_>,
expr: &Expr<'_>,
cast_expr: &Expr<'_>,
cast_from: Ty<'tcx>,
cast_to: Ty<'tcx>,
msrv: &Msrv,
) {
if let ty::RawPtr(from_ty, from_mutbl) = cast_from.kind()
&& let ty::RawPtr(to_ty, to_mutbl) = cast_to.kind()
&& matches!(
(from_mutbl, to_mutbl),
(Mutability::Not, Mutability::Mut) | (Mutability::Mut, Mutability::Not)
)
&& from_ty == to_ty
&& !from_ty.has_erased_regions()
{
if let ExprKind::Call(func, []) = cast_expr.kind
&& let ExprKind::Path(QPath::Resolved(None, path)) = func.kind
&& let Some(defid) = path.res.opt_def_id()
&& let Some(prefix) = std_or_core(cx)
&& let mut app = Applicability::MachineApplicable
&& let sugg = format!("{}", Sugg::hir_with_applicability(cx, cast_expr, "_", &mut app))
&& let Some((_, after_lt)) = sugg.split_once("::<")
&& let Some((source, target, target_func)) = match cx.tcx.get_diagnostic_name(defid) {
Some(sym::ptr_null) => Some(("const", "mutable", "null_mut")),
Some(sym::ptr_null_mut) => Some(("mutable", "const", "null")),
_ => None,
}
{
span_lint_and_sugg(
cx,
PTR_CAST_CONSTNESS,
expr.span,
format!("`as` casting to make a {source} null pointer into a {target} null pointer"),
format!("use `{target_func}()` directly instead"),
format!("{prefix}::ptr::{target_func}::<{after_lt}"),
app,
);
return;
}
if msrv.meets(msrvs::POINTER_CAST_CONSTNESS) {
let sugg = Sugg::hir(cx, cast_expr, "_");
let constness = match *to_mutbl {
Mutability::Not => "const",
Mutability::Mut => "mut",
};
span_lint_and_sugg(
cx,
PTR_CAST_CONSTNESS,
expr.span,
"`as` casting between raw pointers while changing only its constness",
format!("try `pointer::cast_{constness}`, a safer alternative"),
format!("{}.cast_{constness}()", sugg.maybe_par()),
Applicability::MachineApplicable,
);
}
}
}
pub(super) fn check_null_ptr_cast_method(cx: &LateContext<'_>, expr: &Expr<'_>) {
if let ExprKind::MethodCall(method, cast_expr, [], _) = expr.kind
&& let ExprKind::Call(func, []) = cast_expr.kind
&& let ExprKind::Path(QPath::Resolved(None, path)) = func.kind
&& let Some(defid) = path.res.opt_def_id()
&& let method = match (cx.tcx.get_diagnostic_name(defid), method.ident.as_str()) {
(Some(sym::ptr_null), "cast_mut") => "null_mut",
(Some(sym::ptr_null_mut), "cast_const") => "null",
_ => return,
}
&& let Some(prefix) = std_or_core(cx)
&& let mut app = Applicability::MachineApplicable
&& let sugg = format!("{}", Sugg::hir_with_applicability(cx, cast_expr, "_", &mut app))
&& let Some((_, after_lt)) = sugg.split_once("::<")
{
span_lint_and_sugg(
cx,
PTR_CAST_CONSTNESS,
expr.span,
"changing constness of a null pointer",
format!("use `{method}()` directly instead"),
format!("{prefix}::ptr::{method}::<{after_lt}"),
app,
);
}
}