Skip to content

Commit

Permalink
Handle null pointer constness cast through methods
Browse files Browse the repository at this point in the history
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>()`
  • Loading branch information
samueltardieu committed Sep 7, 2024
1 parent ed60394 commit ca93ebd
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 2 deletions.
1 change: 1 addition & 0 deletions clippy_lints/src/casts/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
char_lit_as_u8::check(cx, expr);
ptr_as_ptr::check(cx, expr, &self.msrv);
cast_slice_different_sizes::check(cx, expr, &self.msrv);
ptr_cast_constness::check_null_ptr_cast_method(cx, expr);
}

extract_msrv_attr!(LateContext);
Expand Down
30 changes: 30 additions & 0 deletions clippy_lints/src/casts/ptr_cast_constness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,33 @@ pub(super) fn check<'tcx>(
}
}
}

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 mutable = method.ident.as_str() == "cast_mut";
if (cx.tcx.is_diagnostic_item(sym::ptr_null, defid) && mutable)
|| (cx.tcx.is_diagnostic_item(sym::ptr_null_mut, defid) && method.ident.as_str() == "cast_const")
{
let mut app = Applicability::MachineApplicable;
let sugg = Sugg::hir_with_applicability(cx, cast_expr, "_", &mut app).to_string();
let Some((_, after_lt)) = sugg.split_once("::<") else {
return;
};
let method = if mutable { "null_mut" } else { "null" };
let prefix = std_or_core(cx).unwrap_or("::core");
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,
);
}
}
}
4 changes: 4 additions & 0 deletions tests/ui/ptr_cast_constness.fixed
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,14 @@ fn null_pointers() {
use std::ptr;
let _ = std::ptr::null_mut::<String>();
let _ = std::ptr::null::<u32>();
let _ = std::ptr::null_mut::<u32>();
let _ = std::ptr::null::<u32>();

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

// Do not lint inside macros from external crates
let _ = external!(ptr::null::<u32>() as *mut u32);
let _ = external!(ptr::null::<u32>().cast_mut());
}
4 changes: 4 additions & 0 deletions tests/ui/ptr_cast_constness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,14 @@ fn null_pointers() {
use std::ptr;
let _ = ptr::null::<String>() as *mut String;
let _ = ptr::null_mut::<u32>() as *const u32;
let _ = ptr::null::<u32>().cast_mut();
let _ = ptr::null_mut::<u32>().cast_const();

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

// Do not lint inside macros from external crates
let _ = external!(ptr::null::<u32>() as *mut u32);
let _ = external!(ptr::null::<u32>().cast_mut());
}
24 changes: 22 additions & 2 deletions tests/ui/ptr_cast_constness.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,33 @@ error: `as` casting to make a mutable null pointer into an immutable null pointe
LL | let _ = ptr::null_mut::<u32>() as *const u32;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `null()` directly instead: `std::ptr::null::<u32>()`

error: changing constness of a null pointer
--> tests/ui/ptr_cast_constness.rs:77:13
|
LL | let _ = ptr::null::<u32>().cast_mut();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `null_mut()` directly instead: `std::ptr::null_mut::<u32>()`

error: changing constness of a null pointer
--> tests/ui/ptr_cast_constness.rs:78:13
|
LL | let _ = ptr::null_mut::<u32>().cast_const();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `null()` directly instead: `std::ptr::null::<u32>()`

error: `as` casting to make a const null pointer into a mutable null pointer
--> tests/ui/ptr_cast_constness.rs:79:21
--> tests/ui/ptr_cast_constness.rs:81:21
|
LL | let _ = inline!(ptr::null::<u32>() as *mut u32);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `null_mut()` directly instead: `std::ptr::null_mut::<u32>()`
|
= note: this error originates in the macro `__inline_mac_fn_null_pointers` (in Nightly builds, run with -Z macro-backtrace for more info)

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

error: aborting due to 13 previous errors

0 comments on commit ca93ebd

Please sign in to comment.