1 use clippy_utils::diagnostics::span_lint_and_sugg;
2 use clippy_utils::source::snippet_opt;
3 use if_chain::if_chain;
4 use rustc_errors::Applicability;
5 use rustc_hir::{BinOpKind, Expr, ExprKind};
6 use rustc_lint::{LateContext, LateLintPass};
7 use rustc_session::{declare_lint_pass, declare_tool_lint};
11 /// Use `std::ptr::eq` when applicable
13 /// ### Why is this bad?
14 /// `ptr::eq` can be used to compare `&T` references
15 /// (which coerce to `*const T` implicitly) by their address rather than
16 /// comparing the values they point to.
20 /// let a = &[1, 2, 3];
21 /// let b = &[1, 2, 3];
23 /// assert!(a as *const _ as usize == b as *const _ as usize);
27 /// let a = &[1, 2, 3];
28 /// let b = &[1, 2, 3];
30 /// assert!(std::ptr::eq(a, b));
32 #[clippy::version = "1.49.0"]
35 "use `std::ptr::eq` when comparing raw pointers"
38 declare_lint_pass!(PtrEq => [PTR_EQ]);
40 static LINT_MSG: &str = "use `std::ptr::eq` when comparing raw pointers";
42 impl LateLintPass<'_> for PtrEq {
43 fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
44 if expr.span.from_expansion() {
48 if let ExprKind::Binary(ref op, left, right) = expr.kind {
49 if BinOpKind::Eq == op.node {
50 let (left, right) = match (expr_as_cast_to_usize(cx, left), expr_as_cast_to_usize(cx, right)) {
51 (Some(lhs), Some(rhs)) => (lhs, rhs),
56 if let Some(left_var) = expr_as_cast_to_raw_pointer(cx, left);
57 if let Some(right_var) = expr_as_cast_to_raw_pointer(cx, right);
58 if let Some(left_snip) = snippet_opt(cx, left_var.span);
59 if let Some(right_snip) = snippet_opt(cx, right_var.span);
67 format!("std::ptr::eq({}, {})", left_snip, right_snip),
68 Applicability::MachineApplicable,
77 // If the given expression is a cast to a usize, return the lhs of the cast
78 // E.g., `foo as *const _ as usize` returns `foo as *const _`.
79 fn expr_as_cast_to_usize<'tcx>(cx: &LateContext<'tcx>, cast_expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
80 if cx.typeck_results().expr_ty(cast_expr) == cx.tcx.types.usize {
81 if let ExprKind::Cast(expr, _) = cast_expr.kind {
88 // If the given expression is a cast to a `*const` pointer, return the lhs of the cast
89 // E.g., `foo as *const _` returns `foo`.
90 fn expr_as_cast_to_raw_pointer<'tcx>(cx: &LateContext<'tcx>, cast_expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
91 if cx.typeck_results().expr_ty(cast_expr).is_unsafe_ptr() {
92 if let ExprKind::Cast(expr, _) = cast_expr.kind {