]> git.proxmox.com Git - rustc.git/blame - src/tools/clippy/clippy_lints/src/unnamed_address.rs
Update upstream source from tag 'upstream/1.52.1+dfsg1'
[rustc.git] / src / tools / clippy / clippy_lints / src / unnamed_address.rs
CommitLineData
f20569fa
XL
1use crate::utils::{match_def_path, paths, span_lint, span_lint_and_help};
2use if_chain::if_chain;
3use rustc_hir::{BinOpKind, Expr, ExprKind};
4use rustc_lint::{LateContext, LateLintPass};
5use rustc_middle::ty;
6use rustc_session::{declare_lint_pass, declare_tool_lint};
7
8declare_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
32declare_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
56declare_lint_pass!(UnnamedAddress => [FN_ADDRESS_COMPARISONS, VTABLE_ADDRESS_COMPARISONS]);
57
58impl 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}