Skip to content

Commit bb52c83

Browse files
committed
Handle null pointer constness cast through methods
This covers two cases: - `core::ptr::null::<T>().cast_mut()` -> `core::ptr::null_mut::<T>()` - `core::ptr::null_mut::<T>().cast_const()` -> `core::ptr::null::<T>()`
1 parent fbf67e3 commit bb52c83

File tree

5 files changed

+62
-2
lines changed

5 files changed

+62
-2
lines changed

clippy_lints/src/casts/mod.rs

+5
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,8 @@ declare_clippy_lint! {
419419
/// let ptr = mut_ptr as *const u32;
420420
/// let ptr1 = std::ptr::null::<u32>() as *mut u32;
421421
/// let ptr2 = std::ptr::null_mut::<u32>() as *const u32;
422+
/// let ptr3 = str::ptr::null::<u32>().cast_mut();
423+
/// let ptr4 = str::ptr::null_mut::<u32>().cast_const();
422424
/// ```
423425
/// Use instead:
424426
/// ```no_run
@@ -427,6 +429,8 @@ declare_clippy_lint! {
427429
/// let ptr = mut_ptr.cast_const();
428430
/// let ptr1 = std::ptr::null_mut::<u32>();
429431
/// let ptr2 = std::ptr::null::<u32>();
432+
/// let ptr3 = std::ptr::null_mut::<u32>();
433+
/// let ptr4 = std::ptr::null::<u32>();
430434
/// ```
431435
#[clippy::version = "1.72.0"]
432436
pub PTR_CAST_CONSTNESS,
@@ -813,6 +817,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
813817
char_lit_as_u8::check(cx, expr);
814818
ptr_as_ptr::check(cx, expr, &self.msrv);
815819
cast_slice_different_sizes::check(cx, expr, &self.msrv);
820+
ptr_cast_constness::check_null_ptr_cast_method(cx, expr);
816821
}
817822

818823
extract_msrv_attr!(LateContext);

clippy_lints/src/casts/ptr_cast_constness.rs

+27
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,30 @@ pub(super) fn check<'tcx>(
7474
}
7575
}
7676
}
77+
78+
pub(super) fn check_null_ptr_cast_method(cx: &LateContext<'_>, expr: &Expr<'_>) {
79+
if let ExprKind::MethodCall(method, cast_expr, [], _) = expr.kind
80+
&& let ExprKind::Call(func, []) = cast_expr.kind
81+
&& let ExprKind::Path(QPath::Resolved(None, path)) = func.kind
82+
&& let Some(defid) = path.res.opt_def_id()
83+
&& let method = match (cx.tcx.get_diagnostic_name(defid), method.ident.as_str()) {
84+
(Some(sym::ptr_null), "cast_mut") => "null_mut",
85+
(Some(sym::ptr_null_mut), "cast_const") => "null",
86+
_ => return,
87+
}
88+
&& let Some(prefix) = std_or_core(cx)
89+
&& let mut app = Applicability::MachineApplicable
90+
&& let sugg = format!("{}", Sugg::hir_with_applicability(cx, cast_expr, "_", &mut app))
91+
&& let Some((_, after_lt)) = sugg.split_once("::<")
92+
{
93+
span_lint_and_sugg(
94+
cx,
95+
PTR_CAST_CONSTNESS,
96+
expr.span,
97+
"changing constness of a null pointer",
98+
format!("use `{method}()` directly instead"),
99+
format!("{prefix}::ptr::{method}::<{after_lt}"),
100+
app,
101+
);
102+
}
103+
}

tests/ui/ptr_cast_constness.fixed

+4
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,14 @@ fn null_pointers() {
7474
use std::ptr;
7575
let _ = std::ptr::null_mut::<String>();
7676
let _ = std::ptr::null::<u32>();
77+
let _ = std::ptr::null_mut::<u32>();
78+
let _ = std::ptr::null::<u32>();
7779

7880
// Make sure the lint is triggered inside a macro
7981
let _ = inline!(std::ptr::null_mut::<u32>());
82+
let _ = inline!(std::ptr::null_mut::<u32>());
8083

8184
// Do not lint inside macros from external crates
8285
let _ = external!(ptr::null::<u32>() as *mut u32);
86+
let _ = external!(ptr::null::<u32>().cast_mut());
8387
}

tests/ui/ptr_cast_constness.rs

+4
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,14 @@ fn null_pointers() {
7474
use std::ptr;
7575
let _ = ptr::null::<String>() as *mut String;
7676
let _ = ptr::null_mut::<u32>() as *const u32;
77+
let _ = ptr::null::<u32>().cast_mut();
78+
let _ = ptr::null_mut::<u32>().cast_const();
7779

7880
// Make sure the lint is triggered inside a macro
7981
let _ = inline!(ptr::null::<u32>() as *mut u32);
82+
let _ = inline!(ptr::null::<u32>().cast_mut());
8083

8184
// Do not lint inside macros from external crates
8285
let _ = external!(ptr::null::<u32>() as *mut u32);
86+
let _ = external!(ptr::null::<u32>().cast_mut());
8387
}

tests/ui/ptr_cast_constness.stderr

+22-2
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,33 @@ error: `as` casting to make a mutable null pointer into a const null pointer
5555
LL | let _ = ptr::null_mut::<u32>() as *const u32;
5656
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `null()` directly instead: `std::ptr::null::<u32>()`
5757

58+
error: changing constness of a null pointer
59+
--> tests/ui/ptr_cast_constness.rs:77:13
60+
|
61+
LL | let _ = ptr::null::<u32>().cast_mut();
62+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `null_mut()` directly instead: `std::ptr::null_mut::<u32>()`
63+
64+
error: changing constness of a null pointer
65+
--> tests/ui/ptr_cast_constness.rs:78:13
66+
|
67+
LL | let _ = ptr::null_mut::<u32>().cast_const();
68+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `null()` directly instead: `std::ptr::null::<u32>()`
69+
5870
error: `as` casting to make a const null pointer into a mutable null pointer
59-
--> tests/ui/ptr_cast_constness.rs:79:21
71+
--> tests/ui/ptr_cast_constness.rs:81:21
6072
|
6173
LL | let _ = inline!(ptr::null::<u32>() as *mut u32);
6274
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `null_mut()` directly instead: `std::ptr::null_mut::<u32>()`
6375
|
6476
= note: this error originates in the macro `__inline_mac_fn_null_pointers` (in Nightly builds, run with -Z macro-backtrace for more info)
6577

66-
error: aborting due to 10 previous errors
78+
error: changing constness of a null pointer
79+
--> tests/ui/ptr_cast_constness.rs:82:21
80+
|
81+
LL | let _ = inline!(ptr::null::<u32>().cast_mut());
82+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `null_mut()` directly instead: `std::ptr::null_mut::<u32>()`
83+
|
84+
= note: this error originates in the macro `__inline_mac_fn_null_pointers` (in Nightly builds, run with -Z macro-backtrace for more info)
85+
86+
error: aborting due to 13 previous errors
6787

0 commit comments

Comments
 (0)