]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/borrow_as_ptr.rs
Merge commit 'fdb84cbfd25908df5683f8f62388f663d9260e39' into clippyup
[rust.git] / clippy_lints / src / borrow_as_ptr.rs
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, 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
98     extract_msrv_attr!(LateContext);
99 }