]> git.proxmox.com Git - rustc.git/blame - src/tools/clippy/clippy_lints/src/ptr_eq.rs
New upstream version 1.52.1+dfsg1
[rustc.git] / src / tools / clippy / clippy_lints / src / ptr_eq.rs
CommitLineData
f20569fa
XL
1use crate::utils;
2use if_chain::if_chain;
3use rustc_errors::Applicability;
4use rustc_hir::{BinOpKind, Expr, ExprKind};
5use rustc_lint::{LateContext, LateLintPass};
6use rustc_session::{declare_lint_pass, declare_tool_lint};
7
8declare_clippy_lint! {
9 /// **What it does:** Use `std::ptr::eq` when applicable
10 ///
11 /// **Why is this bad?** `ptr::eq` can be used to compare `&T` references
12 /// (which coerce to `*const T` implicitly) by their address rather than
13 /// comparing the values they point to.
14 ///
15 /// **Known problems:** None.
16 ///
17 /// **Example:**
18 ///
19 /// ```rust
20 /// let a = &[1, 2, 3];
21 /// let b = &[1, 2, 3];
22 ///
23 /// assert!(a as *const _ as usize == b as *const _ as usize);
24 /// ```
25 /// Use instead:
26 /// ```rust
27 /// let a = &[1, 2, 3];
28 /// let b = &[1, 2, 3];
29 ///
30 /// assert!(std::ptr::eq(a, b));
31 /// ```
32 pub PTR_EQ,
33 style,
34 "use `std::ptr::eq` when comparing raw pointers"
35}
36
37declare_lint_pass!(PtrEq => [PTR_EQ]);
38
39static LINT_MSG: &str = "use `std::ptr::eq` when comparing raw pointers";
40
41impl LateLintPass<'_> for PtrEq {
42 fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
43 if utils::in_macro(expr.span) {
44 return;
45 }
46
47 if let ExprKind::Binary(ref op, ref left, ref right) = expr.kind {
48 if BinOpKind::Eq == op.node {
49 let (left, right) = match (expr_as_cast_to_usize(cx, left), expr_as_cast_to_usize(cx, right)) {
50 (Some(lhs), Some(rhs)) => (lhs, rhs),
51 _ => (&**left, &**right),
52 };
53
54 if_chain! {
55 if let Some(left_var) = expr_as_cast_to_raw_pointer(cx, left);
56 if let Some(right_var) = expr_as_cast_to_raw_pointer(cx, right);
57 if let Some(left_snip) = utils::snippet_opt(cx, left_var.span);
58 if let Some(right_snip) = utils::snippet_opt(cx, right_var.span);
59 then {
60 utils::span_lint_and_sugg(
61 cx,
62 PTR_EQ,
63 expr.span,
64 LINT_MSG,
65 "try",
66 format!("std::ptr::eq({}, {})", left_snip, right_snip),
67 Applicability::MachineApplicable,
68 );
69 }
70 }
71 }
72 }
73 }
74}
75
76// If the given expression is a cast to an usize, return the lhs of the cast
77// E.g., `foo as *const _ as usize` returns `foo as *const _`.
78fn expr_as_cast_to_usize<'tcx>(cx: &LateContext<'tcx>, cast_expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
79 if cx.typeck_results().expr_ty(cast_expr) == cx.tcx.types.usize {
80 if let ExprKind::Cast(ref expr, _) = cast_expr.kind {
81 return Some(expr);
82 }
83 }
84 None
85}
86
87// If the given expression is a cast to a `*const` pointer, return the lhs of the cast
88// E.g., `foo as *const _` returns `foo`.
89fn expr_as_cast_to_raw_pointer<'tcx>(cx: &LateContext<'tcx>, cast_expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
90 if cx.typeck_results().expr_ty(cast_expr).is_unsafe_ptr() {
91 if let ExprKind::Cast(ref expr, _) = cast_expr.kind {
92 return Some(expr);
93 }
94 }
95 None
96}