]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/unnamed_address.rs
Allow UUID style formatting for `inconsistent_digit_grouping` lint
[rust.git] / clippy_lints / src / unnamed_address.rs
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};
5 use rustc_middle::ty;
6 use rustc_session::{declare_lint_pass, declare_tool_lint};
7
8 declare_clippy_lint! {
9     /// **What it does:** Checks for comparisons with an address of a function item.
10     ///
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.
14     ///
15     /// **Known problems:** None.
16     ///
17     /// **Example:**
18     ///
19     /// ```rust
20     /// type F = fn();
21     /// fn a() {}
22     /// let f: F = a;
23     /// if f == a {
24     ///     // ...
25     /// }
26     /// ```
27     pub FN_ADDRESS_COMPARISONS,
28     correctness,
29     "comparison with an address of a function item"
30 }
31
32 declare_clippy_lint! {
33     /// **What it does:** Checks for comparisons with an address of a trait vtable.
34     ///
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
38     /// together.
39     ///
40     /// **Known problems:** None.
41     ///
42     /// **Example:**
43     ///
44     /// ```rust,ignore
45     /// let a: Rc<dyn Trait> = ...
46     /// let b: Rc<dyn Trait> = ...
47     /// if Rc::ptr_eq(&a, &b) {
48     ///     ...
49     /// }
50     /// ```
51     pub VTABLE_ADDRESS_COMPARISONS,
52     correctness,
53     "comparison with an address of a trait vtable"
54 }
55
56 declare_lint_pass!(UnnamedAddress => [FN_ADDRESS_COMPARISONS, VTABLE_ADDRESS_COMPARISONS]);
57
58 impl LateLintPass<'_, '_> for UnnamedAddress {
59     fn check_expr(&mut self, cx: &LateContext<'_, '_>, expr: &Expr<'_>) {
60         fn is_comparison(binop: BinOpKind) -> bool {
61             match binop {
62                 BinOpKind::Eq | BinOpKind::Lt | BinOpKind::Le | BinOpKind::Ne | BinOpKind::Ge | BinOpKind::Gt => true,
63                 _ => false,
64             }
65         }
66
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(),
70                 _ => false,
71             }
72         }
73
74         fn is_fn_def(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
75             if let ty::FnDef(..) = cx.tables.expr_ty(expr).kind {
76                 true
77             } else {
78                 false
79             }
80         }
81
82         if_chain! {
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);
86             then {
87                 span_lint_and_help(
88                     cx,
89                     VTABLE_ADDRESS_COMPARISONS,
90                     expr.span,
91                     "comparing trait object pointers compares a non-unique vtable address",
92                     "consider extracting and comparing data pointers only",
93                 );
94             }
95         }
96
97         if_chain! {
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();
106             then {
107                 span_lint_and_help(
108                     cx,
109                     VTABLE_ADDRESS_COMPARISONS,
110                     expr.span,
111                     "comparing trait object pointers compares a non-unique vtable address",
112                     "consider extracting and comparing data pointers only",
113                 );
114             }
115         }
116
117         if_chain! {
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);
123             then {
124                 span_lint(
125                     cx,
126                     FN_ADDRESS_COMPARISONS,
127                     expr.span,
128                     "comparing with a non-unique address of a function item",
129                 );
130             }
131         }
132     }
133 }