mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-12-01 00:49:30 +00:00
60 lines
1.9 KiB
Rust
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",
|
|
);
|
|
}
|
|
}
|
|
}
|