1 use crate::utils::{match_def_path, paths};
2 use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
3 use if_chain::if_chain;
4 use rustc_hir::{BinOpKind, Expr, ExprKind};
5 use rustc_lint::{LateContext, LateLintPass};
7 use rustc_session::{declare_lint_pass, declare_tool_lint};
10 /// **What it does:** Checks for comparisons with an address of a function item.
12 /// **Why is this bad?** Function item address is not guaranteed to be unique and could vary
13 /// between different code generation units. Furthermore different function items could have
14 /// the same address after being merged together.
16 /// **Known problems:** None.
28 pub FN_ADDRESS_COMPARISONS,
30 "comparison with an address of a function item"
33 declare_clippy_lint! {
34 /// **What it does:** Checks for comparisons with an address of a trait vtable.
36 /// **Why is this bad?** Comparing trait objects pointers compares an vtable addresses which
37 /// are not guaranteed to be unique and could vary between different code generation units.
38 /// Furthermore vtables for different types could have the same address after being merged
41 /// **Known problems:** None.
46 /// let a: Rc<dyn Trait> = ...
47 /// let b: Rc<dyn Trait> = ...
48 /// if Rc::ptr_eq(&a, &b) {
52 pub VTABLE_ADDRESS_COMPARISONS,
54 "comparison with an address of a trait vtable"
57 declare_lint_pass!(UnnamedAddress => [FN_ADDRESS_COMPARISONS, VTABLE_ADDRESS_COMPARISONS]);
59 impl LateLintPass<'_> for UnnamedAddress {
60 fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
61 fn is_comparison(binop: BinOpKind) -> bool {
64 BinOpKind::Eq | BinOpKind::Lt | BinOpKind::Le | BinOpKind::Ne | BinOpKind::Ge | BinOpKind::Gt
68 fn is_trait_ptr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
69 match cx.typeck_results().expr_ty_adjusted(expr).kind() {
70 ty::RawPtr(ty::TypeAndMut { ty, .. }) => ty.is_trait(),
75 fn is_fn_def(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
76 matches!(cx.typeck_results().expr_ty(expr).kind(), ty::FnDef(..))
80 if let ExprKind::Binary(binop, ref left, ref right) = expr.kind;
81 if is_comparison(binop.node);
82 if is_trait_ptr(cx, left) && is_trait_ptr(cx, right);
86 VTABLE_ADDRESS_COMPARISONS,
88 "comparing trait object pointers compares a non-unique vtable address",
90 "consider extracting and comparing data pointers only",
96 if let ExprKind::Call(ref func, [ref _left, ref _right]) = expr.kind;
97 if let ExprKind::Path(ref func_qpath) = func.kind;
98 if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id();
99 if match_def_path(cx, def_id, &paths::PTR_EQ) ||
100 match_def_path(cx, def_id, &paths::RC_PTR_EQ) ||
101 match_def_path(cx, def_id, &paths::ARC_PTR_EQ);
102 let ty_param = cx.typeck_results().node_substs(func.hir_id).type_at(0);
103 if ty_param.is_trait();
107 VTABLE_ADDRESS_COMPARISONS,
109 "comparing trait object pointers compares a non-unique vtable address",
111 "consider extracting and comparing data pointers only",
117 if let ExprKind::Binary(binop, ref left, ref right) = expr.kind;
118 if is_comparison(binop.node);
119 if cx.typeck_results().expr_ty_adjusted(left).is_fn_ptr() &&
120 cx.typeck_results().expr_ty_adjusted(right).is_fn_ptr();
121 if is_fn_def(cx, left) || is_fn_def(cx, right);
125 FN_ADDRESS_COMPARISONS,
127 "comparing with a non-unique address of a function item",