diff --git a/clippy_lints/src/casts/ptr_as_ptr.rs b/clippy_lints/src/casts/ptr_as_ptr.rs index 0c555c1ac..35e36e9ef 100644 --- a/clippy_lints/src/casts/ptr_as_ptr.rs +++ b/clippy_lints/src/casts/ptr_as_ptr.rs @@ -3,12 +3,29 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, Mutability, TyKind}; +use rustc_hir::{Expr, ExprKind, Mutability, QPath, TyKind}; +use rustc_hir_pretty::qpath_to_string; use rustc_lint::LateContext; use rustc_middle::ty::{self, TypeAndMut}; +use rustc_span::sym; use super::PTR_AS_PTR; +enum OmitFollowedCastReason<'a> { + None, + Null(&'a QPath<'a>), + NullMut(&'a QPath<'a>), +} + +impl OmitFollowedCastReason<'_> { + fn corresponding_item(&self) -> Option<&QPath<'_>> { + match self { + OmitFollowedCastReason::None => None, + OmitFollowedCastReason::Null(x) | OmitFollowedCastReason::NullMut(x) => Some(*x), + } + } +} + pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Msrv) { if !msrv.meets(msrvs::POINTER_CAST) { return; @@ -25,7 +42,6 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Msrv) { && to_pointee_ty.is_sized(cx.tcx, cx.param_env) { let mut app = Applicability::MachineApplicable; - let cast_expr_sugg = Sugg::hir_with_applicability(cx, cast_expr, "_", &mut app); let turbofish = match &cast_to_hir_ty.kind { TyKind::Infer => String::new(), TyKind::Ptr(mut_ty) => { @@ -41,13 +57,44 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Msrv) { _ => return, }; + // following `cast` does not compile because it fails to infer what type is expected + // as type argument to `std::ptr::ptr_null` or `std::ptr::ptr_null_mut`, so + // we omit following `cast`: + let omit_cast = if let ExprKind::Call(func, []) = cast_expr.kind + && let ExprKind::Path(ref qpath @ QPath::Resolved(None, path)) = func.kind + { + let method_defid = path.res.def_id(); + if cx.tcx.is_diagnostic_item(sym::ptr_null, method_defid) { + OmitFollowedCastReason::Null(qpath) + } else if cx.tcx.is_diagnostic_item(sym::ptr_null_mut, method_defid) { + OmitFollowedCastReason::NullMut(qpath) + } else { + OmitFollowedCastReason::None + } + } else { + OmitFollowedCastReason::None + }; + + let (help, final_suggestion) = if let Some(method) = omit_cast.corresponding_item() { + // don't force absolute path + let method = qpath_to_string(method); + ("try call directly", format!("{method}{turbofish}()")) + } else { + let cast_expr_sugg = Sugg::hir_with_applicability(cx, cast_expr, "_", &mut app); + + ( + "try `pointer::cast`, a safer alternative", + format!("{}.cast{turbofish}()", cast_expr_sugg.maybe_par()), + ) + }; + span_lint_and_sugg( cx, PTR_AS_PTR, expr.span, "`as` casting between raw pointers without changing its mutability", - "try `pointer::cast`, a safer alternative", - format!("{}.cast{turbofish}()", cast_expr_sugg.maybe_par()), + help, + final_suggestion, app, ); } diff --git a/tests/ui/ptr_as_ptr.fixed b/tests/ui/ptr_as_ptr.fixed index ca13b52ae..fa15c3235 100644 --- a/tests/ui/ptr_as_ptr.fixed +++ b/tests/ui/ptr_as_ptr.fixed @@ -71,3 +71,118 @@ fn _msrv_1_38() { let _ = ptr.cast::(); let _ = mut_ptr.cast::(); } + +#[allow(clippy::unnecessary_cast)] +mod null { + fn use_path_mut() -> *mut u32 { + use std::ptr; + ptr::null_mut::() + } + + fn full_path_mut() -> *mut u32 { + std::ptr::null_mut::() + } + + fn core_path_mut() -> *mut u32 { + use core::ptr; + ptr::null_mut::() + } + + fn full_core_path_mut() -> *mut u32 { + core::ptr::null_mut::() + } + + fn use_path() -> *const u32 { + use std::ptr; + ptr::null::() + } + + fn full_path() -> *const u32 { + std::ptr::null::() + } + + fn core_path() -> *const u32 { + use core::ptr; + ptr::null::() + } + + fn full_core_path() -> *const u32 { + core::ptr::null::() + } +} + +mod null_ptr_infer { + fn use_path_mut() -> *mut u32 { + use std::ptr; + ptr::null_mut() + } + + fn full_path_mut() -> *mut u32 { + std::ptr::null_mut() + } + + fn core_path_mut() -> *mut u32 { + use core::ptr; + ptr::null_mut() + } + + fn full_core_path_mut() -> *mut u32 { + core::ptr::null_mut() + } + + fn use_path() -> *const u32 { + use std::ptr; + ptr::null() + } + + fn full_path() -> *const u32 { + std::ptr::null() + } + + fn core_path() -> *const u32 { + use core::ptr; + ptr::null() + } + + fn full_core_path() -> *const u32 { + core::ptr::null() + } +} + +mod null_entire_infer { + fn use_path_mut() -> *mut u32 { + use std::ptr; + ptr::null_mut() + } + + fn full_path_mut() -> *mut u32 { + std::ptr::null_mut() + } + + fn core_path_mut() -> *mut u32 { + use core::ptr; + ptr::null_mut() + } + + fn full_core_path_mut() -> *mut u32 { + core::ptr::null_mut() + } + + fn use_path() -> *const u32 { + use std::ptr; + ptr::null() + } + + fn full_path() -> *const u32 { + std::ptr::null() + } + + fn core_path() -> *const u32 { + use core::ptr; + ptr::null() + } + + fn full_core_path() -> *const u32 { + core::ptr::null() + } +} diff --git a/tests/ui/ptr_as_ptr.rs b/tests/ui/ptr_as_ptr.rs index 942c87344..7ab52e63d 100644 --- a/tests/ui/ptr_as_ptr.rs +++ b/tests/ui/ptr_as_ptr.rs @@ -71,3 +71,118 @@ fn _msrv_1_38() { let _ = ptr as *const i32; let _ = mut_ptr as *mut i32; } + +#[allow(clippy::unnecessary_cast)] +mod null { + fn use_path_mut() -> *mut u32 { + use std::ptr; + ptr::null_mut() as *mut u32 + } + + fn full_path_mut() -> *mut u32 { + std::ptr::null_mut() as *mut u32 + } + + fn core_path_mut() -> *mut u32 { + use core::ptr; + ptr::null_mut() as *mut u32 + } + + fn full_core_path_mut() -> *mut u32 { + core::ptr::null_mut() as *mut u32 + } + + fn use_path() -> *const u32 { + use std::ptr; + ptr::null() as *const u32 + } + + fn full_path() -> *const u32 { + std::ptr::null() as *const u32 + } + + fn core_path() -> *const u32 { + use core::ptr; + ptr::null() as *const u32 + } + + fn full_core_path() -> *const u32 { + core::ptr::null() as *const u32 + } +} + +mod null_ptr_infer { + fn use_path_mut() -> *mut u32 { + use std::ptr; + ptr::null_mut() as *mut _ + } + + fn full_path_mut() -> *mut u32 { + std::ptr::null_mut() as *mut _ + } + + fn core_path_mut() -> *mut u32 { + use core::ptr; + ptr::null_mut() as *mut _ + } + + fn full_core_path_mut() -> *mut u32 { + core::ptr::null_mut() as *mut _ + } + + fn use_path() -> *const u32 { + use std::ptr; + ptr::null() as *const _ + } + + fn full_path() -> *const u32 { + std::ptr::null() as *const _ + } + + fn core_path() -> *const u32 { + use core::ptr; + ptr::null() as *const _ + } + + fn full_core_path() -> *const u32 { + core::ptr::null() as *const _ + } +} + +mod null_entire_infer { + fn use_path_mut() -> *mut u32 { + use std::ptr; + ptr::null_mut() as _ + } + + fn full_path_mut() -> *mut u32 { + std::ptr::null_mut() as _ + } + + fn core_path_mut() -> *mut u32 { + use core::ptr; + ptr::null_mut() as _ + } + + fn full_core_path_mut() -> *mut u32 { + core::ptr::null_mut() as _ + } + + fn use_path() -> *const u32 { + use std::ptr; + ptr::null() as _ + } + + fn full_path() -> *const u32 { + std::ptr::null() as _ + } + + fn core_path() -> *const u32 { + use core::ptr; + ptr::null() as _ + } + + fn full_core_path() -> *const u32 { + core::ptr::null() as _ + } +} diff --git a/tests/ui/ptr_as_ptr.stderr b/tests/ui/ptr_as_ptr.stderr index c0ce69b43..ef64347e9 100644 --- a/tests/ui/ptr_as_ptr.stderr +++ b/tests/ui/ptr_as_ptr.stderr @@ -57,5 +57,149 @@ error: `as` casting between raw pointers without changing its mutability LL | let _ = mut_ptr as *mut i32; | ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::()` -error: aborting due to 9 previous errors +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:79:9 + | +LL | ptr::null_mut() as *mut u32 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut::()` + +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:83:9 + | +LL | std::ptr::null_mut() as *mut u32 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut::()` + +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:88:9 + | +LL | ptr::null_mut() as *mut u32 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut::()` + +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:92:9 + | +LL | core::ptr::null_mut() as *mut u32 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut::()` + +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:97:9 + | +LL | ptr::null() as *const u32 + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null::()` + +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:101:9 + | +LL | std::ptr::null() as *const u32 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null::()` + +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:106:9 + | +LL | ptr::null() as *const u32 + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null::()` + +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:110:9 + | +LL | core::ptr::null() as *const u32 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null::()` + +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:117:9 + | +LL | ptr::null_mut() as *mut _ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` + +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:121:9 + | +LL | std::ptr::null_mut() as *mut _ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut()` + +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:126:9 + | +LL | ptr::null_mut() as *mut _ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` + +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:130:9 + | +LL | core::ptr::null_mut() as *mut _ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut()` + +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:135:9 + | +LL | ptr::null() as *const _ + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` + +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:139:9 + | +LL | std::ptr::null() as *const _ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null()` + +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:144:9 + | +LL | ptr::null() as *const _ + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` + +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:148:9 + | +LL | core::ptr::null() as *const _ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null()` + +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:155:9 + | +LL | ptr::null_mut() as _ + | ^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` + +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:159:9 + | +LL | std::ptr::null_mut() as _ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut()` + +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:164:9 + | +LL | ptr::null_mut() as _ + | ^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` + +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:168:9 + | +LL | core::ptr::null_mut() as _ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut()` + +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:173:9 + | +LL | ptr::null() as _ + | ^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` + +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:177:9 + | +LL | std::ptr::null() as _ + | ^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null()` + +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:182:9 + | +LL | ptr::null() as _ + | ^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` + +error: `as` casting between raw pointers without changing its mutability + --> $DIR/ptr_as_ptr.rs:186:9 + | +LL | core::ptr::null() as _ + | ^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null()` + +error: aborting due to 33 previous errors