]>
Commit | Line | Data |
---|---|---|
cdc7bbd5 XL |
1 | use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; |
2 | use clippy_utils::{match_def_path, paths}; | |
f20569fa XL |
3 | use if_chain::if_chain; |
4 | use rustc_hir::{BinOpKind, Expr, ExprKind}; | |
5 | use rustc_lint::{LateContext, LateLintPass}; | |
6 | use rustc_middle::ty; | |
7 | use rustc_session::{declare_lint_pass, declare_tool_lint}; | |
8 | ||
9 | declare_clippy_lint! { | |
94222f64 XL |
10 | /// ### What it does |
11 | /// Checks for comparisons with an address of a function item. | |
f20569fa | 12 | /// |
94222f64 XL |
13 | /// ### Why is this bad? |
14 | /// Function item address is not guaranteed to be unique and could vary | |
f20569fa XL |
15 | /// between different code generation units. Furthermore different function items could have |
16 | /// the same address after being merged together. | |
17 | /// | |
94222f64 | 18 | /// ### Example |
f20569fa XL |
19 | /// ```rust |
20 | /// type F = fn(); | |
21 | /// fn a() {} | |
22 | /// let f: F = a; | |
23 | /// if f == a { | |
24 | /// // ... | |
25 | /// } | |
26 | /// ``` | |
a2a8927a | 27 | #[clippy::version = "1.44.0"] |
f20569fa XL |
28 | pub FN_ADDRESS_COMPARISONS, |
29 | correctness, | |
30 | "comparison with an address of a function item" | |
31 | } | |
32 | ||
33 | declare_clippy_lint! { | |
94222f64 XL |
34 | /// ### What it does |
35 | /// Checks for comparisons with an address of a trait vtable. | |
f20569fa | 36 | /// |
94222f64 XL |
37 | /// ### Why is this bad? |
38 | /// Comparing trait objects pointers compares an vtable addresses which | |
f20569fa XL |
39 | /// are not guaranteed to be unique and could vary between different code generation units. |
40 | /// Furthermore vtables for different types could have the same address after being merged | |
41 | /// together. | |
42 | /// | |
94222f64 | 43 | /// ### Example |
f20569fa XL |
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 | /// ``` | |
a2a8927a | 51 | #[clippy::version = "1.44.0"] |
f20569fa XL |
52 | pub VTABLE_ADDRESS_COMPARISONS, |
53 | correctness, | |
54 | "comparison with an address of a trait vtable" | |
55 | } | |
56 | ||
57 | declare_lint_pass!(UnnamedAddress => [FN_ADDRESS_COMPARISONS, VTABLE_ADDRESS_COMPARISONS]); | |
58 | ||
59 | impl LateLintPass<'_> for UnnamedAddress { | |
60 | fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { | |
61 | fn is_comparison(binop: BinOpKind) -> bool { | |
62 | matches!( | |
63 | binop, | |
64 | BinOpKind::Eq | BinOpKind::Lt | BinOpKind::Le | BinOpKind::Ne | BinOpKind::Ge | BinOpKind::Gt | |
65 | ) | |
66 | } | |
67 | ||
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(), | |
71 | _ => false, | |
72 | } | |
73 | } | |
74 | ||
75 | fn is_fn_def(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { | |
76 | matches!(cx.typeck_results().expr_ty(expr).kind(), ty::FnDef(..)) | |
77 | } | |
78 | ||
79 | if_chain! { | |
cdc7bbd5 | 80 | if let ExprKind::Binary(binop, left, right) = expr.kind; |
f20569fa XL |
81 | if is_comparison(binop.node); |
82 | if is_trait_ptr(cx, left) && is_trait_ptr(cx, right); | |
83 | then { | |
84 | span_lint_and_help( | |
85 | cx, | |
86 | VTABLE_ADDRESS_COMPARISONS, | |
87 | expr.span, | |
88 | "comparing trait object pointers compares a non-unique vtable address", | |
89 | None, | |
90 | "consider extracting and comparing data pointers only", | |
91 | ); | |
92 | } | |
93 | } | |
94 | ||
95 | if_chain! { | |
cdc7bbd5 | 96 | if let ExprKind::Call(func, [ref _left, ref _right]) = expr.kind; |
f20569fa XL |
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(); | |
fe692bf9 | 99 | if match_def_path(cx, def_id, &paths::PTR_EQ); |
f20569fa XL |
100 | let ty_param = cx.typeck_results().node_substs(func.hir_id).type_at(0); |
101 | if ty_param.is_trait(); | |
102 | then { | |
103 | span_lint_and_help( | |
104 | cx, | |
105 | VTABLE_ADDRESS_COMPARISONS, | |
106 | expr.span, | |
107 | "comparing trait object pointers compares a non-unique vtable address", | |
108 | None, | |
109 | "consider extracting and comparing data pointers only", | |
110 | ); | |
111 | } | |
112 | } | |
113 | ||
114 | if_chain! { | |
cdc7bbd5 | 115 | if let ExprKind::Binary(binop, left, right) = expr.kind; |
f20569fa | 116 | if is_comparison(binop.node); |
cdc7bbd5 XL |
117 | if cx.typeck_results().expr_ty_adjusted(left).is_fn_ptr(); |
118 | if cx.typeck_results().expr_ty_adjusted(right).is_fn_ptr(); | |
f20569fa XL |
119 | if is_fn_def(cx, left) || is_fn_def(cx, right); |
120 | then { | |
121 | span_lint( | |
122 | cx, | |
123 | FN_ADDRESS_COMPARISONS, | |
124 | expr.span, | |
125 | "comparing with a non-unique address of a function item", | |
126 | ); | |
127 | } | |
128 | } | |
129 | } | |
130 | } |