]> git.lizzy.rs Git - rust.git/blob - src/tools/clippy/clippy_lints/src/unnamed_address.rs
Auto merge of #71780 - jcotton42:string_remove_matches, r=joshtriplett
[rust.git] / src / tools / clippy / 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             matches!(
62                 binop,
63                 BinOpKind::Eq | BinOpKind::Lt | BinOpKind::Le | BinOpKind::Ne | BinOpKind::Ge | BinOpKind::Gt
64             )
65         }
66
67         fn is_trait_ptr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
68             match cx.typeck_results().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             matches!(cx.typeck_results().expr_ty(expr).kind(), ty::FnDef(..))
76         }
77
78         if_chain! {
79             if let ExprKind::Binary(binop, ref left, ref right) = expr.kind;
80             if is_comparison(binop.node);
81             if is_trait_ptr(cx, left) && is_trait_ptr(cx, right);
82             then {
83                 span_lint_and_help(
84                     cx,
85                     VTABLE_ADDRESS_COMPARISONS,
86                     expr.span,
87                     "comparing trait object pointers compares a non-unique vtable address",
88                     None,
89                     "consider extracting and comparing data pointers only",
90                 );
91             }
92         }
93
94         if_chain! {
95             if let ExprKind::Call(ref func, [ref _left, ref _right]) = expr.kind;
96             if let ExprKind::Path(ref func_qpath) = func.kind;
97             if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id();
98             if match_def_path(cx, def_id, &paths::PTR_EQ) ||
99                 match_def_path(cx, def_id, &paths::RC_PTR_EQ) ||
100                 match_def_path(cx, def_id, &paths::ARC_PTR_EQ);
101             let ty_param = cx.typeck_results().node_substs(func.hir_id).type_at(0);
102             if ty_param.is_trait();
103             then {
104                 span_lint_and_help(
105                     cx,
106                     VTABLE_ADDRESS_COMPARISONS,
107                     expr.span,
108                     "comparing trait object pointers compares a non-unique vtable address",
109                     None,
110                     "consider extracting and comparing data pointers only",
111                 );
112             }
113         }
114
115         if_chain! {
116             if let ExprKind::Binary(binop, ref left, ref right) = expr.kind;
117             if is_comparison(binop.node);
118             if cx.typeck_results().expr_ty_adjusted(left).is_fn_ptr() &&
119                 cx.typeck_results().expr_ty_adjusted(right).is_fn_ptr();
120             if is_fn_def(cx, left) || is_fn_def(cx, right);
121             then {
122                 span_lint(
123                     cx,
124                     FN_ADDRESS_COMPARISONS,
125                     expr.span,
126                     "comparing with a non-unique address of a function item",
127                 );
128             }
129         }
130     }
131 }