1 use crate::utils::{match_def_path, paths, span_lint, span_lint_and_help};
2 use if_chain::if_chain;
3 use rustc_hir::{BinOpKind, Expr, ExprKind};
4 use rustc_lint::{LateContext, LateLintPass};
6 use rustc_session::{declare_lint_pass, declare_tool_lint};
9 /// **What it does:** Checks for comparisons with an address of a function item.
11 /// **Why is this bad?** Function item address is not guaranteed to be unique and could vary
12 /// between different code generation units. Furthermore different function items could have
13 /// the same address after being merged together.
15 /// **Known problems:** None.
27 pub FN_ADDRESS_COMPARISONS,
29 "comparison with an address of a function item"
32 declare_clippy_lint! {
33 /// **What it does:** Checks for comparisons with an address of a trait vtable.
35 /// **Why is this bad?** Comparing trait objects pointers compares an vtable addresses which
36 /// are not guaranteed to be unique and could vary between different code generation units.
37 /// Furthermore vtables for different types could have the same address after being merged
40 /// **Known problems:** None.
45 /// let a: Rc<dyn Trait> = ...
46 /// let b: Rc<dyn Trait> = ...
47 /// if Rc::ptr_eq(&a, &b) {
51 pub VTABLE_ADDRESS_COMPARISONS,
53 "comparison with an address of a trait vtable"
56 declare_lint_pass!(UnnamedAddress => [FN_ADDRESS_COMPARISONS, VTABLE_ADDRESS_COMPARISONS]);
58 impl LateLintPass<'_, '_> for UnnamedAddress {
59 fn check_expr(&mut self, cx: &LateContext<'_, '_>, expr: &Expr<'_>) {
60 fn is_comparison(binop: BinOpKind) -> bool {
62 BinOpKind::Eq | BinOpKind::Lt | BinOpKind::Le | BinOpKind::Ne | BinOpKind::Ge | BinOpKind::Gt => true,
67 fn is_trait_ptr(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
68 match cx.tables.expr_ty_adjusted(expr).kind {
69 ty::RawPtr(ty::TypeAndMut { ty, .. }) => ty.is_trait(),
74 fn is_fn_def(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
75 if let ty::FnDef(..) = cx.tables.expr_ty(expr).kind {
83 if let ExprKind::Binary(binop, ref left, ref right) = expr.kind;
84 if is_comparison(binop.node);
85 if is_trait_ptr(cx, left) && is_trait_ptr(cx, right);
89 VTABLE_ADDRESS_COMPARISONS,
91 "comparing trait object pointers compares a non-unique vtable address",
92 "consider extracting and comparing data pointers only",
98 if let ExprKind::Call(ref func, [ref _left, ref _right]) = expr.kind;
99 if let ExprKind::Path(ref func_qpath) = func.kind;
100 if let Some(def_id) = cx.tables.qpath_res(func_qpath, func.hir_id).opt_def_id();
101 if match_def_path(cx, def_id, &paths::PTR_EQ) ||
102 match_def_path(cx, def_id, &paths::RC_PTR_EQ) ||
103 match_def_path(cx, def_id, &paths::ARC_PTR_EQ);
104 let ty_param = cx.tables.node_substs(func.hir_id).type_at(0);
105 if ty_param.is_trait();
109 VTABLE_ADDRESS_COMPARISONS,
111 "comparing trait object pointers compares a non-unique vtable address",
112 "consider extracting and comparing data pointers only",
118 if let ExprKind::Binary(binop, ref left, ref right) = expr.kind;
119 if is_comparison(binop.node);
120 if cx.tables.expr_ty_adjusted(left).is_fn_ptr() &&
121 cx.tables.expr_ty_adjusted(right).is_fn_ptr();
122 if is_fn_def(cx, left) || is_fn_def(cx, right);
126 FN_ADDRESS_COMPARISONS,
128 "comparing with a non-unique address of a function item",