1
Fork 0

Expand incorrect_fn_null_check lint with reference null checking

This commit is contained in:
Urgau 2023-07-12 16:17:58 +02:00
parent c435af0d5c
commit 743ae5a2eb
5 changed files with 133 additions and 23 deletions

View file

@ -31,7 +31,7 @@ declare_lint! {
declare_lint_pass!(IncorrectFnNullChecks => [INCORRECT_FN_NULL_CHECKS]);
fn is_fn_ptr_cast(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
fn incorrect_check<'a>(cx: &LateContext<'a>, expr: &Expr<'_>) -> Option<FnNullCheckDiag<'a>> {
let mut expr = expr.peel_blocks();
let mut had_at_least_one_cast = false;
while let ExprKind::Cast(cast_expr, cast_ty) = expr.kind
@ -39,7 +39,18 @@ fn is_fn_ptr_cast(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
expr = cast_expr.peel_blocks();
had_at_least_one_cast = true;
}
had_at_least_one_cast && cx.typeck_results().expr_ty_adjusted(expr).is_fn()
if !had_at_least_one_cast {
None
} else {
let orig_ty = cx.typeck_results().expr_ty(expr);
if orig_ty.is_fn() {
Some(FnNullCheckDiag::FnPtr)
} else if orig_ty.is_ref() {
Some(FnNullCheckDiag::Ref { orig_ty, label: expr.span })
} else {
None
}
}
}
impl<'tcx> LateLintPass<'tcx> for IncorrectFnNullChecks {
@ -54,9 +65,9 @@ impl<'tcx> LateLintPass<'tcx> for IncorrectFnNullChecks {
cx.tcx.get_diagnostic_name(def_id),
Some(sym::ptr_const_is_null | sym::ptr_is_null)
)
&& is_fn_ptr_cast(cx, arg) =>
&& let Some(diag) = incorrect_check(cx, arg) =>
{
cx.emit_spanned_lint(INCORRECT_FN_NULL_CHECKS, expr.span, FnNullCheckDiag)
cx.emit_spanned_lint(INCORRECT_FN_NULL_CHECKS, expr.span, diag)
}
// Catching:
@ -67,17 +78,20 @@ impl<'tcx> LateLintPass<'tcx> for IncorrectFnNullChecks {
cx.tcx.get_diagnostic_name(def_id),
Some(sym::ptr_const_is_null | sym::ptr_is_null)
)
&& is_fn_ptr_cast(cx, receiver) =>
&& let Some(diag) = incorrect_check(cx, receiver) =>
{
cx.emit_spanned_lint(INCORRECT_FN_NULL_CHECKS, expr.span, FnNullCheckDiag)
cx.emit_spanned_lint(INCORRECT_FN_NULL_CHECKS, expr.span, diag)
}
ExprKind::Binary(op, left, right) if matches!(op.node, BinOpKind::Eq) => {
let to_check: &Expr<'_>;
if is_fn_ptr_cast(cx, left) {
let diag: FnNullCheckDiag<'_>;
if let Some(ddiag) = incorrect_check(cx, left) {
to_check = right;
} else if is_fn_ptr_cast(cx, right) {
diag = ddiag;
} else if let Some(ddiag) = incorrect_check(cx, right) {
to_check = left;
diag = ddiag;
} else {
return;
}
@ -89,7 +103,7 @@ impl<'tcx> LateLintPass<'tcx> for IncorrectFnNullChecks {
if let ExprKind::Lit(spanned) = cast_expr.kind
&& let LitKind::Int(v, _) = spanned.node && v == 0 =>
{
cx.emit_spanned_lint(INCORRECT_FN_NULL_CHECKS, expr.span, FnNullCheckDiag)
cx.emit_spanned_lint(INCORRECT_FN_NULL_CHECKS, expr.span, diag)
},
// Catching:
@ -100,7 +114,7 @@ impl<'tcx> LateLintPass<'tcx> for IncorrectFnNullChecks {
&& let Some(diag_item) = cx.tcx.get_diagnostic_name(def_id)
&& (diag_item == sym::ptr_null || diag_item == sym::ptr_null_mut) =>
{
cx.emit_spanned_lint(INCORRECT_FN_NULL_CHECKS, expr.span, FnNullCheckDiag)
cx.emit_spanned_lint(INCORRECT_FN_NULL_CHECKS, expr.span, diag)
},
_ => {},

View file

@ -615,9 +615,17 @@ pub struct ExpectationNote {
// fn_null_check.rs
#[derive(LintDiagnostic)]
#[diag(lint_fn_null_check)]
#[help]
pub struct FnNullCheckDiag;
pub enum FnNullCheckDiag<'a> {
#[diag(lint_fn_null_check_fn_ptr)]
#[help(lint_help)]
FnPtr,
#[diag(lint_fn_null_check_ref)]
Ref {
orig_ty: Ty<'a>,
#[label]
label: Span,
},
}
// for_loops_over_fallibles.rs
#[derive(LintDiagnostic)]