rust-clippy/clippy_lints/src/unnamed_address.rs
2023-12-06 09:03:48 +01:00

60 lines
1.9 KiB
Rust

use clippy_utils::diagnostics::span_lint;
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::declare_lint_pass;
declare_clippy_lint! {
/// ### What it does
/// Checks for comparisons with an address of a function item.
///
/// ### Why is this bad?
/// Function item address is not guaranteed to be unique and could vary
/// between different code generation units. Furthermore different function items could have
/// the same address after being merged together.
///
/// ### Example
/// ```no_run
/// type F = fn();
/// fn a() {}
/// let f: F = a;
/// if f == a {
/// // ...
/// }
/// ```
#[clippy::version = "1.44.0"]
pub FN_ADDRESS_COMPARISONS,
correctness,
"comparison with an address of a function item"
}
declare_lint_pass!(UnnamedAddress => [FN_ADDRESS_COMPARISONS]);
impl LateLintPass<'_> for UnnamedAddress {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
fn is_comparison(binop: BinOpKind) -> bool {
matches!(
binop,
BinOpKind::Eq | BinOpKind::Lt | BinOpKind::Le | BinOpKind::Ne | BinOpKind::Ge | BinOpKind::Gt
)
}
fn is_fn_def(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
matches!(cx.typeck_results().expr_ty(expr).kind(), ty::FnDef(..))
}
if let ExprKind::Binary(binop, left, right) = expr.kind
&& is_comparison(binop.node)
&& cx.typeck_results().expr_ty_adjusted(left).is_fn_ptr()
&& cx.typeck_results().expr_ty_adjusted(right).is_fn_ptr()
&& (is_fn_def(cx, left) || is_fn_def(cx, right))
{
span_lint(
cx,
FN_ADDRESS_COMPARISONS,
expr.span,
"comparing with a non-unique address of a function item",
);
}
}
}