|  | 
|  | 1 | +use clippy_utils::diagnostics::span_lint_and_sugg; | 
|  | 2 | +use clippy_utils::is_no_std_crate; | 
|  | 3 | +use clippy_utils::source::snippet_opt; | 
|  | 4 | +use clippy_utils::{meets_msrv, msrvs}; | 
|  | 5 | +use if_chain::if_chain; | 
|  | 6 | +use rustc_errors::Applicability; | 
|  | 7 | +use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, TyKind}; | 
|  | 8 | +use rustc_lint::{LateContext, LateLintPass}; | 
|  | 9 | +use rustc_semver::RustcVersion; | 
|  | 10 | +use rustc_session::{declare_tool_lint, impl_lint_pass}; | 
|  | 11 | + | 
|  | 12 | +declare_clippy_lint! { | 
|  | 13 | + /// ### What it does | 
|  | 14 | + /// Checks for the usage of `&expr as *const T` or | 
|  | 15 | + /// `&mut expr as *mut T`, and suggest using `ptr::addr_of` or | 
|  | 16 | + /// `ptr::addr_of_mut` instead. | 
|  | 17 | + /// | 
|  | 18 | + /// ### Why is this bad? | 
|  | 19 | + /// This would improve readability and avoid creating a reference | 
|  | 20 | + /// that points to an uninitialized value or unaligned place. | 
|  | 21 | + /// Read the `ptr::addr_of` docs for more information. | 
|  | 22 | + /// | 
|  | 23 | + /// ### Example | 
|  | 24 | + /// ```rust | 
|  | 25 | + /// let val = 1; | 
|  | 26 | + /// let p = &val as *const i32; | 
|  | 27 | + /// | 
|  | 28 | + /// let mut val_mut = 1; | 
|  | 29 | + /// let p_mut = &mut val_mut as *mut i32; | 
|  | 30 | + /// ``` | 
|  | 31 | + /// Use instead: | 
|  | 32 | + /// ```rust | 
|  | 33 | + /// let val = 1; | 
|  | 34 | + /// let p = std::ptr::addr_of!(val); | 
|  | 35 | + /// | 
|  | 36 | + /// let mut val_mut = 1; | 
|  | 37 | + /// let p_mut = std::ptr::addr_of_mut!(val_mut); | 
|  | 38 | + /// ``` | 
|  | 39 | + #[clippy::version = "1.60.0"] | 
|  | 40 | + pub BORROW_AS_PTR, | 
|  | 41 | + pedantic, | 
|  | 42 | + "borrowing just to cast to a raw pointer" | 
|  | 43 | +} | 
|  | 44 | + | 
|  | 45 | +impl_lint_pass!(BorrowAsPtr => [BORROW_AS_PTR]); | 
|  | 46 | + | 
|  | 47 | +pub struct BorrowAsPtr { | 
|  | 48 | + msrv: Option<RustcVersion>, | 
|  | 49 | +} | 
|  | 50 | + | 
|  | 51 | +impl BorrowAsPtr { | 
|  | 52 | + #[must_use] | 
|  | 53 | + pub fn new(msrv: Option<RustcVersion>) -> Self { | 
|  | 54 | + Self { msrv } | 
|  | 55 | + } | 
|  | 56 | +} | 
|  | 57 | + | 
|  | 58 | +impl<'tcx> LateLintPass<'tcx> for BorrowAsPtr { | 
|  | 59 | + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { | 
|  | 60 | + if !meets_msrv(self.msrv.as_ref(), &msrvs::BORROW_AS_PTR) { | 
|  | 61 | + return; | 
|  | 62 | + } | 
|  | 63 | + | 
|  | 64 | + if expr.span.from_expansion() { | 
|  | 65 | + return; | 
|  | 66 | + } | 
|  | 67 | + | 
|  | 68 | + if_chain! { | 
|  | 69 | + if let ExprKind::Cast(left_expr, ty) = &expr.kind; | 
|  | 70 | + if let TyKind::Ptr(_) = ty.kind; | 
|  | 71 | + if let ExprKind::AddrOf(BorrowKind::Ref, mutability, e) = &left_expr.kind; | 
|  | 72 | + | 
|  | 73 | + then { | 
|  | 74 | + let core_or_std = if is_no_std_crate(cx) { "core" } else { "std" }; | 
|  | 75 | + let macro_name = match mutability { | 
|  | 76 | + Mutability::Not => "addr_of", | 
|  | 77 | + Mutability::Mut => "addr_of_mut", | 
|  | 78 | + }; | 
|  | 79 | + | 
|  | 80 | + span_lint_and_sugg( | 
|  | 81 | + cx, | 
|  | 82 | + BORROW_AS_PTR, | 
|  | 83 | + expr.span, | 
|  | 84 | + "borrow as raw pointer", | 
|  | 85 | + "try", | 
|  | 86 | + format!( | 
|  | 87 | + "{}::ptr::{}!({})", | 
|  | 88 | + core_or_std, | 
|  | 89 | + macro_name, | 
|  | 90 | + snippet_opt(cx, e.span).unwrap() | 
|  | 91 | + ), | 
|  | 92 | + Applicability::MachineApplicable, | 
|  | 93 | + ); | 
|  | 94 | + } | 
|  | 95 | + } | 
|  | 96 | + } | 
|  | 97 | +} | 
0 commit comments