summaryrefslogtreecommitdiffstats
path: root/src/tools/clippy/clippy_lints/src/casts
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/clippy/clippy_lints/src/casts')
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/as_underscore.rs25
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/borrow_as_ptr.rs37
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs63
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/mod.rs109
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs9
9 files changed, 246 insertions, 15 deletions
diff --git a/src/tools/clippy/clippy_lints/src/casts/as_underscore.rs b/src/tools/clippy/clippy_lints/src/casts/as_underscore.rs
new file mode 100644
index 000000000..56e894c62
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/casts/as_underscore.rs
@@ -0,0 +1,25 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, Ty, TyKind};
+use rustc_lint::LateContext;
+use rustc_middle::ty;
+
+use super::AS_UNDERSCORE;
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, ty: &'tcx Ty<'_>) {
+ if matches!(ty.kind, TyKind::Infer) {
+ span_lint_and_then(cx, AS_UNDERSCORE, expr.span, "using `as _` conversion", |diag| {
+ let ty_resolved = cx.typeck_results().expr_ty(expr);
+ if let ty::Error(_) = ty_resolved.kind() {
+ diag.help("consider giving the type explicitly");
+ } else {
+ diag.span_suggestion(
+ ty.span,
+ "consider giving the type explicitly",
+ ty_resolved,
+ Applicability::MachineApplicable,
+ );
+ }
+ });
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/casts/borrow_as_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/borrow_as_ptr.rs
new file mode 100644
index 000000000..6e1f8cd64
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/casts/borrow_as_ptr.rs
@@ -0,0 +1,37 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::is_no_std_crate;
+use clippy_utils::source::snippet_with_context;
+use rustc_errors::Applicability;
+use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Ty, TyKind};
+use rustc_lint::LateContext;
+
+use super::BORROW_AS_PTR;
+
+pub(super) fn check<'tcx>(
+ cx: &LateContext<'tcx>,
+ expr: &'tcx Expr<'_>,
+ cast_expr: &'tcx Expr<'_>,
+ cast_to: &'tcx Ty<'_>,
+) {
+ if matches!(cast_to.kind, TyKind::Ptr(_))
+ && let ExprKind::AddrOf(BorrowKind::Ref, mutability, e) = cast_expr.kind
+ {
+ let core_or_std = if is_no_std_crate(cx) { "core" } else { "std" };
+ let macro_name = match mutability {
+ Mutability::Not => "addr_of",
+ Mutability::Mut => "addr_of_mut",
+ };
+ let mut app = Applicability::MachineApplicable;
+ let snip = snippet_with_context(cx, e.span, cast_expr.span.ctxt(), "..", &mut app).0;
+
+ span_lint_and_sugg(
+ cx,
+ BORROW_AS_PTR,
+ expr.span,
+ "borrow as raw pointer",
+ "try",
+ format!("{}::ptr::{}!({})", core_or_std, macro_name, snip),
+ Applicability::MachineApplicable,
+ );
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs b/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs
index 64ea326b7..3f1edabe6 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs
@@ -20,7 +20,7 @@ pub(super) fn check(
if meets_msrv(msrv, msrvs::UNSIGNED_ABS)
&& let ty::Int(from) = cast_from.kind()
&& let ty::Uint(to) = cast_to.kind()
- && let ExprKind::MethodCall(method_path, args, _) = cast_expr.kind
+ && let ExprKind::MethodCall(method_path, receiver, ..) = cast_expr.kind
&& method_path.ident.name.as_str() == "abs"
{
let span = if from.bit_width() == to.bit_width() {
@@ -37,7 +37,7 @@ pub(super) fn check(
span,
&format!("casting the result of `{cast_from}::abs()` to {cast_to}"),
"replace with",
- format!("{}.unsigned_abs()", Sugg::hir(cx, &args[0], "..")),
+ format!("{}.unsigned_abs()", Sugg::hir(cx, receiver, "..").maybe_par()),
Applicability::MachineApplicable,
);
}
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
index 64f87c80f..406547a44 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
@@ -44,7 +44,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b
.saturating_sub(constant_int(cx, right).map_or(0, |s| u64::try_from(s).expect("shift too high"))),
_ => nbits,
},
- ExprKind::MethodCall(method, [left, right], _) => {
+ ExprKind::MethodCall(method, left, [right], _) => {
if signed {
return nbits;
}
@@ -55,7 +55,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b
};
apply_reductions(cx, nbits, left, signed).min(max_bits.unwrap_or(u64::max_value()))
},
- ExprKind::MethodCall(method, [_, lo, hi], _) => {
+ ExprKind::MethodCall(method, _, [lo, hi], _) => {
if method.ident.as_str() == "clamp" {
//FIXME: make this a diagnostic item
if let (Some(lo_bits), Some(hi_bits)) = (get_constant_bits(cx, lo), get_constant_bits(cx, hi)) {
@@ -64,7 +64,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b
}
nbits
},
- ExprKind::MethodCall(method, [_value], _) => {
+ ExprKind::MethodCall(method, _value, [], _) => {
if method.ident.name.as_str() == "signum" {
0 // do not lint if cast comes from a `signum` function
} else {
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs
index d476a1a76..da7b12f67 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs
@@ -18,7 +18,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
cx.typeck_results().expr_ty(expr),
);
lint_cast_ptr_alignment(cx, expr, cast_from, cast_to);
- } else if let ExprKind::MethodCall(method_path, [self_arg, ..], _) = &expr.kind {
+ } else if let ExprKind::MethodCall(method_path, self_arg, ..) = &expr.kind {
if method_path.ident.name == sym!(cast)
&& let Some(generic_args) = method_path.args
&& let [GenericArg::Type(cast_to)] = generic_args.args
@@ -64,7 +64,7 @@ fn is_used_as_unaligned(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
return false;
};
match parent.kind {
- ExprKind::MethodCall(name, [self_arg, ..], _) if self_arg.hir_id == e.hir_id => {
+ ExprKind::MethodCall(name, self_arg, ..) if self_arg.hir_id == e.hir_id => {
if matches!(name.ident.as_str(), "read_unaligned" | "write_unaligned")
&& let Some(def_id) = cx.typeck_results().type_dependent_def_id(parent.hir_id)
&& let Some(def_id) = cx.tcx.impl_of_method(def_id)
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
index 75f70b77e..5b59350be 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
@@ -41,14 +41,14 @@ fn should_lint(cx: &LateContext<'_>, cast_op: &Expr<'_>, cast_from: Ty<'_>, cast
}
// Don't lint for the result of methods that always return non-negative values.
- if let ExprKind::MethodCall(path, _, _) = cast_op.kind {
+ if let ExprKind::MethodCall(path, ..) = cast_op.kind {
let mut method_name = path.ident.name.as_str();
let allowed_methods = ["abs", "checked_abs", "rem_euclid", "checked_rem_euclid"];
if_chain! {
if method_name == "unwrap";
if let Some(arglist) = method_chain_args(cast_op, &["unwrap"]);
- if let ExprKind::MethodCall(inner_path, _, _) = &arglist[0][0].kind;
+ if let ExprKind::MethodCall(inner_path, ..) = &arglist[0].0.kind;
then {
method_name = inner_path.ident.name.as_str();
}
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs b/src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs
new file mode 100644
index 000000000..284ef1659
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs
@@ -0,0 +1,63 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::{match_def_path, meets_msrv, msrvs, paths};
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir::{def_id::DefId, Expr, ExprKind};
+use rustc_lint::LateContext;
+use rustc_middle::ty::{self, Ty};
+use rustc_semver::RustcVersion;
+
+use super::CAST_SLICE_FROM_RAW_PARTS;
+
+enum RawPartsKind {
+ Immutable,
+ Mutable,
+}
+
+fn raw_parts_kind(cx: &LateContext<'_>, did: DefId) -> Option<RawPartsKind> {
+ if match_def_path(cx, did, &paths::SLICE_FROM_RAW_PARTS) {
+ Some(RawPartsKind::Immutable)
+ } else if match_def_path(cx, did, &paths::SLICE_FROM_RAW_PARTS_MUT) {
+ Some(RawPartsKind::Mutable)
+ } else {
+ None
+ }
+}
+
+pub(super) fn check(
+ cx: &LateContext<'_>,
+ expr: &Expr<'_>,
+ cast_expr: &Expr<'_>,
+ cast_to: Ty<'_>,
+ msrv: Option<RustcVersion>,
+) {
+ if_chain! {
+ if meets_msrv(msrv, msrvs::PTR_SLICE_RAW_PARTS);
+ if let ty::RawPtr(ptrty) = cast_to.kind();
+ if let ty::Slice(_) = ptrty.ty.kind();
+ if let ExprKind::Call(fun, [ptr_arg, len_arg]) = cast_expr.peel_blocks().kind;
+ if let ExprKind::Path(ref qpath) = fun.kind;
+ if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id();
+ if let Some(rpk) = raw_parts_kind(cx, fun_def_id);
+ then {
+ let func = match rpk {
+ RawPartsKind::Immutable => "from_raw_parts",
+ RawPartsKind::Mutable => "from_raw_parts_mut"
+ };
+ let span = expr.span;
+ let mut applicability = Applicability::MachineApplicable;
+ let ptr = snippet_with_applicability(cx, ptr_arg.span, "ptr", &mut applicability);
+ let len = snippet_with_applicability(cx, len_arg.span, "len", &mut applicability);
+ span_lint_and_sugg(
+ cx,
+ CAST_SLICE_FROM_RAW_PARTS,
+ span,
+ &format!("casting the result of `{func}` to {cast_to}"),
+ "replace with",
+ format!("core::ptr::slice_{func}({ptr}, {len})"),
+ applicability
+ );
+ }
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs
index af3798a0c..cc5d346b9 100644
--- a/src/tools/clippy/clippy_lints/src/casts/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs
@@ -1,3 +1,5 @@
+mod as_underscore;
+mod borrow_as_ptr;
mod cast_abs_to_unsigned;
mod cast_enum_constructor;
mod cast_lossless;
@@ -8,6 +10,7 @@ mod cast_ptr_alignment;
mod cast_ref_to_mut;
mod cast_sign_loss;
mod cast_slice_different_sizes;
+mod cast_slice_from_raw_parts;
mod char_lit_as_u8;
mod fn_to_numeric_cast;
mod fn_to_numeric_cast_any;
@@ -16,7 +19,7 @@ mod ptr_as_ptr;
mod unnecessary_cast;
mod utils;
-use clippy_utils::is_hir_ty_cfg_dependant;
+use clippy_utils::{is_hir_ty_cfg_dependant, meets_msrv, msrvs};
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
@@ -506,6 +509,93 @@ declare_clippy_lint! {
"casting the result of `abs()` to an unsigned integer can panic"
}
+declare_clippy_lint! {
+ /// ### What it does
+ /// Check for the usage of `as _` conversion using inferred type.
+ ///
+ /// ### Why is this bad?
+ /// The conversion might include lossy conversion and dangerous cast that might go
+ /// undetected due to the type being inferred.
+ ///
+ /// The lint is allowed by default as using `_` is less wordy than always specifying the type.
+ ///
+ /// ### Example
+ /// ```rust
+ /// fn foo(n: usize) {}
+ /// let n: u16 = 256;
+ /// foo(n as _);
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// fn foo(n: usize) {}
+ /// let n: u16 = 256;
+ /// foo(n as usize);
+ /// ```
+ #[clippy::version = "1.63.0"]
+ pub AS_UNDERSCORE,
+ restriction,
+ "detects `as _` conversion"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for the usage of `&expr as *const T` or
+ /// `&mut expr as *mut T`, and suggest using `ptr::addr_of` or
+ /// `ptr::addr_of_mut` instead.
+ ///
+ /// ### Why is this bad?
+ /// This would improve readability and avoid creating a reference
+ /// that points to an uninitialized value or unaligned place.
+ /// Read the `ptr::addr_of` docs for more information.
+ ///
+ /// ### Example
+ /// ```rust
+ /// let val = 1;
+ /// let p = &val as *const i32;
+ ///
+ /// let mut val_mut = 1;
+ /// let p_mut = &mut val_mut as *mut i32;
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// let val = 1;
+ /// let p = std::ptr::addr_of!(val);
+ ///
+ /// let mut val_mut = 1;
+ /// let p_mut = std::ptr::addr_of_mut!(val_mut);
+ /// ```
+ #[clippy::version = "1.60.0"]
+ pub BORROW_AS_PTR,
+ pedantic,
+ "borrowing just to cast to a raw pointer"
+}
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for a raw slice being cast to a slice pointer
+ ///
+ /// ### Why is this bad?
+ /// This can result in multiple `&mut` references to the same location when only a pointer is
+ /// required.
+ /// `ptr::slice_from_raw_parts` is a safe alternative that doesn't require
+ /// the same [safety requirements] to be upheld.
+ ///
+ /// ### Example
+ /// ```rust,ignore
+ /// let _: *const [u8] = std::slice::from_raw_parts(ptr, len) as *const _;
+ /// let _: *mut [u8] = std::slice::from_raw_parts_mut(ptr, len) as *mut _;
+ /// ```
+ /// Use instead:
+ /// ```rust,ignore
+ /// let _: *const [u8] = std::ptr::slice_from_raw_parts(ptr, len);
+ /// let _: *mut [u8] = std::ptr::slice_from_raw_parts_mut(ptr, len);
+ /// ```
+ /// [safety requirements]: https://doc.rust-lang.org/std/slice/fn.from_raw_parts.html#safety
+ #[clippy::version = "1.64.0"]
+ pub CAST_SLICE_FROM_RAW_PARTS,
+ suspicious,
+ "casting a slice created from a pointer and length to a slice pointer"
+}
+
pub struct Casts {
msrv: Option<RustcVersion>,
}
@@ -534,7 +624,10 @@ impl_lint_pass!(Casts => [
PTR_AS_PTR,
CAST_ENUM_TRUNCATION,
CAST_ENUM_CONSTRUCTOR,
- CAST_ABS_TO_UNSIGNED
+ CAST_ABS_TO_UNSIGNED,
+ AS_UNDERSCORE,
+ BORROW_AS_PTR,
+ CAST_SLICE_FROM_RAW_PARTS
]);
impl<'tcx> LateLintPass<'tcx> for Casts {
@@ -547,8 +640,8 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
return;
}
- if let ExprKind::Cast(cast_expr, cast_to) = expr.kind {
- if is_hir_ty_cfg_dependant(cx, cast_to) {
+ if let ExprKind::Cast(cast_expr, cast_to_hir) = expr.kind {
+ if is_hir_ty_cfg_dependant(cx, cast_to_hir) {
return;
}
let (cast_from, cast_to) = (
@@ -559,7 +652,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
if unnecessary_cast::check(cx, expr, cast_expr, cast_from, cast_to) {
return;
}
-
+ cast_slice_from_raw_parts::check(cx, expr, cast_expr, cast_to, self.msrv);
fn_to_numeric_cast_any::check(cx, expr, cast_expr, cast_from, cast_to);
fn_to_numeric_cast::check(cx, expr, cast_expr, cast_from, cast_to);
fn_to_numeric_cast_with_truncation::check(cx, expr, cast_expr, cast_from, cast_to);
@@ -575,6 +668,12 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to, self.msrv);
cast_enum_constructor::check(cx, expr, cast_expr, cast_from);
}
+
+ as_underscore::check(cx, expr, cast_to_hir);
+
+ if meets_msrv(self.msrv, msrvs::BORROW_AS_PTR) {
+ borrow_as_ptr::check(cx, expr, cast_expr, cast_to_hir);
+ }
}
cast_ref_to_mut::check(cx, expr);
diff --git a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
index fff7da8e3..19d2e6e1d 100644
--- a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
@@ -90,13 +90,20 @@ pub(super) fn check<'tcx>(
fn lint_unnecessary_cast(cx: &LateContext<'_>, expr: &Expr<'_>, literal_str: &str, cast_from: Ty<'_>, cast_to: Ty<'_>) {
let literal_kind_name = if cast_from.is_integral() { "integer" } else { "float" };
+ let replaced_literal;
+ let matchless = if literal_str.contains(['(', ')']) {
+ replaced_literal = literal_str.replace(['(', ')'], "");
+ &replaced_literal
+ } else {
+ literal_str
+ };
span_lint_and_sugg(
cx,
UNNECESSARY_CAST,
expr.span,
&format!("casting {} literal to `{}` is unnecessary", literal_kind_name, cast_to),
"try",
- format!("{}_{}", literal_str.trim_end_matches('.'), cast_to),
+ format!("{}_{}", matchless.trim_end_matches('.'), cast_to),
Applicability::MachineApplicable,
);
}