Move zero_ptr to the casts module
This commit is contained in:
parent
c92de58692
commit
b06b915dc0
@ -20,6 +20,7 @@
|
||||
mod ptr_cast_constness;
|
||||
mod unnecessary_cast;
|
||||
mod utils;
|
||||
mod zero_ptr;
|
||||
|
||||
use clippy_utils::is_hir_ty_cfg_dependant;
|
||||
use clippy_utils::msrvs::{self, Msrv};
|
||||
@ -665,6 +666,29 @@
|
||||
"casting a known floating-point NaN into an integer"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Catch casts from `0` to some pointer type
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// This generally means `null` and is better expressed as
|
||||
/// {`std`, `core`}`::ptr::`{`null`, `null_mut`}.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// let a = 0 as *const u32;
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// let a = std::ptr::null::<u32>();
|
||||
/// ```
|
||||
#[clippy::version = "pre 1.29.0"]
|
||||
pub ZERO_PTR,
|
||||
style,
|
||||
"using `0 as *{const, mut} T`"
|
||||
}
|
||||
|
||||
pub struct Casts {
|
||||
msrv: Msrv,
|
||||
}
|
||||
@ -699,6 +723,7 @@ pub fn new(msrv: Msrv) -> Self {
|
||||
CAST_SLICE_FROM_RAW_PARTS,
|
||||
AS_PTR_CAST_MUT,
|
||||
CAST_NAN_TO_INT,
|
||||
ZERO_PTR,
|
||||
]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for Casts {
|
||||
@ -729,6 +754,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
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);
|
||||
zero_ptr::check(cx, expr, cast_expr, cast_to_hir);
|
||||
|
||||
if cast_to.is_numeric() && !in_external_macro(cx.sess(), expr.span) {
|
||||
cast_possible_truncation::check(cx, expr, cast_expr, cast_from, cast_to, cast_to_hir.span);
|
||||
|
39
clippy_lints/src/casts/zero_ptr.rs
Normal file
39
clippy_lints/src/casts/zero_ptr.rs
Normal file
@ -0,0 +1,39 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::{in_constant, is_integer_literal, std_or_core};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, Mutability, Ty, TyKind};
|
||||
use rustc_lint::LateContext;
|
||||
|
||||
use super::ZERO_PTR;
|
||||
|
||||
pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, from: &Expr<'_>, to: &Ty<'_>) {
|
||||
if let TyKind::Ptr(ref mut_ty) = to.kind
|
||||
&& is_integer_literal(from, 0)
|
||||
&& !in_constant(cx, from.hir_id)
|
||||
&& let Some(std_or_core) = std_or_core(cx)
|
||||
{
|
||||
let (msg, sugg_fn) = match mut_ty.mutbl {
|
||||
Mutability::Mut => ("`0 as *mut _` detected", "ptr::null_mut"),
|
||||
Mutability::Not => ("`0 as *const _` detected", "ptr::null"),
|
||||
};
|
||||
|
||||
let sugg = if let TyKind::Infer = mut_ty.ty.kind {
|
||||
format!("{std_or_core}::{sugg_fn}()")
|
||||
} else if let Some(mut_ty_snip) = snippet_opt(cx, mut_ty.ty.span) {
|
||||
format!("{std_or_core}::{sugg_fn}::<{mut_ty_snip}>()")
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
ZERO_PTR,
|
||||
expr.span,
|
||||
msg,
|
||||
"try",
|
||||
sugg,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
@ -97,6 +97,7 @@
|
||||
crate::casts::PTR_AS_PTR_INFO,
|
||||
crate::casts::PTR_CAST_CONSTNESS_INFO,
|
||||
crate::casts::UNNECESSARY_CAST_INFO,
|
||||
crate::casts::ZERO_PTR_INFO,
|
||||
crate::checked_conversions::CHECKED_CONVERSIONS_INFO,
|
||||
crate::cognitive_complexity::COGNITIVE_COMPLEXITY_INFO,
|
||||
crate::collapsible_if::COLLAPSIBLE_ELSE_IF_INFO,
|
||||
@ -442,7 +443,6 @@
|
||||
crate::misc::SHORT_CIRCUIT_STATEMENT_INFO,
|
||||
crate::misc::TOPLEVEL_REF_ARG_INFO,
|
||||
crate::misc::USED_UNDERSCORE_BINDING_INFO,
|
||||
crate::misc::ZERO_PTR_INFO,
|
||||
crate::misc_early::BUILTIN_TYPE_SHADOW_INFO,
|
||||
crate::misc_early::DOUBLE_NEG_INFO,
|
||||
crate::misc_early::DUPLICATE_UNDERSCORE_ARGUMENT_INFO,
|
||||
|
@ -637,7 +637,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
store.register_late_pass(|_| Box::new(needless_bool::NeedlessBool));
|
||||
store.register_late_pass(|_| Box::new(needless_bool::BoolComparison));
|
||||
store.register_late_pass(|_| Box::new(needless_for_each::NeedlessForEach));
|
||||
store.register_late_pass(|_| Box::<misc::LintPass>::default());
|
||||
store.register_late_pass(|_| Box::new(misc::LintPass));
|
||||
store.register_late_pass(|_| Box::new(eta_reduction::EtaReduction));
|
||||
store.register_late_pass(|_| Box::new(mut_mut::MutMut));
|
||||
store.register_late_pass(|_| Box::new(mut_reference::UnnecessaryMutPassed));
|
||||
|
@ -1,21 +1,20 @@
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then, span_lint_hir_and_then};
|
||||
use clippy_utils::source::{snippet, snippet_opt, snippet_with_context};
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_then, span_lint_hir_and_then};
|
||||
use clippy_utils::source::{snippet, snippet_with_context};
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::{
|
||||
any_parent_is_automatically_derived, fulfill_or_allowed, get_parent_expr, in_constant, is_integer_literal,
|
||||
is_lint_allowed, is_no_std_crate, iter_input_pats, last_path_segment, SpanlessEq,
|
||||
any_parent_is_automatically_derived, fulfill_or_allowed, get_parent_expr, is_lint_allowed, iter_input_pats,
|
||||
last_path_segment, SpanlessEq,
|
||||
};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::intravisit::FnKind;
|
||||
use rustc_hir::{
|
||||
BinOpKind, BindingAnnotation, Body, ByRef, Expr, ExprKind, FnDecl, Mutability, PatKind, QPath, Stmt, StmtKind, Ty,
|
||||
TyKind,
|
||||
BinOpKind, BindingAnnotation, Body, ByRef, Expr, ExprKind, FnDecl, Mutability, PatKind, QPath, Stmt, StmtKind,
|
||||
};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::source_map::Span;
|
||||
|
||||
@ -55,6 +54,7 @@
|
||||
style,
|
||||
"an entire binding declared as `ref`, in a function argument or a `let` statement"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for the use of bindings with a single leading
|
||||
@ -102,51 +102,13 @@
|
||||
"using a short circuit boolean condition as a statement"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Catch casts from `0` to some pointer type
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// This generally means `null` and is better expressed as
|
||||
/// {`std`, `core`}`::ptr::`{`null`, `null_mut`}.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// let a = 0 as *const u32;
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// let a = std::ptr::null::<u32>();
|
||||
/// ```
|
||||
#[clippy::version = "pre 1.29.0"]
|
||||
pub ZERO_PTR,
|
||||
style,
|
||||
"using `0 as *{const, mut} T`"
|
||||
}
|
||||
|
||||
pub struct LintPass {
|
||||
std_or_core: &'static str,
|
||||
}
|
||||
impl Default for LintPass {
|
||||
fn default() -> Self {
|
||||
Self { std_or_core: "std" }
|
||||
}
|
||||
}
|
||||
impl_lint_pass!(LintPass => [
|
||||
declare_lint_pass!(LintPass => [
|
||||
TOPLEVEL_REF_ARG,
|
||||
USED_UNDERSCORE_BINDING,
|
||||
SHORT_CIRCUIT_STATEMENT,
|
||||
ZERO_PTR,
|
||||
]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for LintPass {
|
||||
fn check_crate(&mut self, cx: &LateContext<'_>) {
|
||||
if is_no_std_crate(cx) {
|
||||
self.std_or_core = "core";
|
||||
}
|
||||
}
|
||||
|
||||
fn check_fn(
|
||||
&mut self,
|
||||
cx: &LateContext<'tcx>,
|
||||
@ -252,10 +214,6 @@ fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
|
||||
}
|
||||
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
if let ExprKind::Cast(e, ty) = expr.kind {
|
||||
self.check_cast(cx, expr.span, e, ty);
|
||||
return;
|
||||
}
|
||||
if in_external_macro(cx.sess(), expr.span)
|
||||
|| expr.span.desugaring_kind().is_some()
|
||||
|| any_parent_is_automatically_derived(cx.tcx, expr.hir_id)
|
||||
@ -320,29 +278,3 @@ fn is_used(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||
_ => is_used(cx, parent),
|
||||
})
|
||||
}
|
||||
|
||||
impl LintPass {
|
||||
fn check_cast(&self, cx: &LateContext<'_>, span: Span, e: &Expr<'_>, ty: &Ty<'_>) {
|
||||
if_chain! {
|
||||
if let TyKind::Ptr(ref mut_ty) = ty.kind;
|
||||
if is_integer_literal(e, 0);
|
||||
if !in_constant(cx, e.hir_id);
|
||||
then {
|
||||
let (msg, sugg_fn) = match mut_ty.mutbl {
|
||||
Mutability::Mut => ("`0 as *mut _` detected", "ptr::null_mut"),
|
||||
Mutability::Not => ("`0 as *const _` detected", "ptr::null"),
|
||||
};
|
||||
|
||||
let (sugg, appl) = if let TyKind::Infer = mut_ty.ty.kind {
|
||||
(format!("{}::{sugg_fn}()", self.std_or_core), Applicability::MachineApplicable)
|
||||
} else if let Some(mut_ty_snip) = snippet_opt(cx, mut_ty.ty.span) {
|
||||
(format!("{}::{sugg_fn}::<{mut_ty_snip}>()", self.std_or_core), Applicability::MachineApplicable)
|
||||
} else {
|
||||
// `MaybeIncorrect` as type inference may not work with the suggested code
|
||||
(format!("{}::{sugg_fn}()", self.std_or_core), Applicability::MaybeIncorrect)
|
||||
};
|
||||
span_lint_and_sugg(cx, ZERO_PTR, span, msg, "try", sugg, appl);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user