1 use crate::{lints::PtrNullChecksDiag, LateContext, LateLintPass, LintContext}
;
2 use rustc_ast
::LitKind
;
3 use rustc_hir
::{BinOpKind, Expr, ExprKind, TyKind}
;
4 use rustc_session
::{declare_lint, declare_lint_pass}
;
8 /// The `useless_ptr_null_checks` lint checks for useless null checks against pointers
9 /// obtained from non-null types.
15 /// let fn_ptr: fn() = /* somehow obtained nullable function pointer */
18 /// if (fn_ptr as *const ()).is_null() { /* ... */ }
25 /// Function pointers and references are assumed to be non-null, checking them for null
26 /// will always return false.
27 USELESS_PTR_NULL_CHECKS
,
29 "useless checking of non-null-typed pointer"
32 declare_lint_pass
!(PtrNullChecks
=> [USELESS_PTR_NULL_CHECKS
]);
34 /// This function detects and returns the original expression from a series of consecutive casts,
35 /// ie. `(my_fn as *const _ as *mut _).cast_mut()` would return the expression for `my_fn`.
36 fn ptr_cast_chain
<'a
>(cx
: &'a LateContext
<'_
>, mut e
: &'a Expr
<'a
>) -> Option
<&'a Expr
<'a
>> {
37 let mut had_at_least_one_cast
= false;
40 e
= if let ExprKind
::Cast(expr
, t
) = e
.kind
41 && let TyKind
::Ptr(_
) = t
.kind
{
42 had_at_least_one_cast
= true;
44 } else if let ExprKind
::MethodCall(_
, expr
, [], _
) = e
.kind
45 && let Some(def_id
) = cx
.typeck_results().type_dependent_def_id(e
.hir_id
)
46 && matches
!(cx
.tcx
.get_diagnostic_name(def_id
), Some(sym
::ptr_cast
| sym
::ptr_cast_mut
)) {
47 had_at_least_one_cast
= true;
49 } else if let ExprKind
::Call(path
, [arg
]) = e
.kind
50 && let ExprKind
::Path(ref qpath
) = path
.kind
51 && let Some(def_id
) = cx
.qpath_res(qpath
, path
.hir_id
).opt_def_id()
52 && matches
!(cx
.tcx
.get_diagnostic_name(def_id
), Some(sym
::ptr_from_ref
| sym
::ptr_from_mut
)) {
53 had_at_least_one_cast
= true;
55 } else if had_at_least_one_cast
{
63 fn incorrect_check
<'a
>(cx
: &LateContext
<'a
>, expr
: &Expr
<'_
>) -> Option
<PtrNullChecksDiag
<'a
>> {
64 let expr
= ptr_cast_chain(cx
, expr
)?
;
66 let orig_ty
= cx
.typeck_results().expr_ty(expr
);
68 Some(PtrNullChecksDiag
::FnPtr { orig_ty, label: expr.span }
)
69 } else if orig_ty
.is_ref() {
70 Some(PtrNullChecksDiag
::Ref { orig_ty, label: expr.span }
)
76 impl<'tcx
> LateLintPass
<'tcx
> for PtrNullChecks
{
77 fn check_expr(&mut self, cx
: &LateContext
<'tcx
>, expr
: &'tcx Expr
<'_
>) {
80 // <*<const/mut> <ty>>::is_null(fn_ptr as *<const/mut> <ty>)
81 ExprKind
::Call(path
, [arg
])
82 if let ExprKind
::Path(ref qpath
) = path
.kind
83 && let Some(def_id
) = cx
.qpath_res(qpath
, path
.hir_id
).opt_def_id()
85 cx
.tcx
.get_diagnostic_name(def_id
),
86 Some(sym
::ptr_const_is_null
| sym
::ptr_is_null
)
88 && let Some(diag
) = incorrect_check(cx
, arg
) =>
90 cx
.emit_spanned_lint(USELESS_PTR_NULL_CHECKS
, expr
.span
, diag
)
94 // (fn_ptr as *<const/mut> <ty>).is_null()
95 ExprKind
::MethodCall(_
, receiver
, _
, _
)
96 if let Some(def_id
) = cx
.typeck_results().type_dependent_def_id(expr
.hir_id
)
98 cx
.tcx
.get_diagnostic_name(def_id
),
99 Some(sym
::ptr_const_is_null
| sym
::ptr_is_null
)
101 && let Some(diag
) = incorrect_check(cx
, receiver
) =>
103 cx
.emit_spanned_lint(USELESS_PTR_NULL_CHECKS
, expr
.span
, diag
)
106 ExprKind
::Binary(op
, left
, right
) if matches
!(op
.node
, BinOpKind
::Eq
) => {
107 let to_check
: &Expr
<'_
>;
108 let diag
: PtrNullChecksDiag
<'_
>;
109 if let Some(ddiag
) = incorrect_check(cx
, left
) {
112 } else if let Some(ddiag
) = incorrect_check(cx
, right
) {
119 match to_check
.kind
{
121 // (fn_ptr as *<const/mut> <ty>) == (0 as <ty>)
122 ExprKind
::Cast(cast_expr
, _
)
123 if let ExprKind
::Lit(spanned
) = cast_expr
.kind
124 && let LitKind
::Int(v
, _
) = spanned
.node
&& v
== 0 =>
126 cx
.emit_spanned_lint(USELESS_PTR_NULL_CHECKS
, expr
.span
, diag
)
130 // (fn_ptr as *<const/mut> <ty>) == std::ptr::null()
131 ExprKind
::Call(path
, [])
132 if let ExprKind
::Path(ref qpath
) = path
.kind
133 && let Some(def_id
) = cx
.qpath_res(qpath
, path
.hir_id
).opt_def_id()
134 && let Some(diag_item
) = cx
.tcx
.get_diagnostic_name(def_id
)
135 && (diag_item
== sym
::ptr_null
|| diag_item
== sym
::ptr_null_mut
) =>
137 cx
.emit_spanned_lint(USELESS_PTR_NULL_CHECKS
, expr
.span
, diag
)