]> git.lizzy.rs Git - rust.git/blob - src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs
Rollup merge of #97454 - Mark-Simulacrum:relnotes, r=Mark-Simulacrum
[rust.git] / src / tools / clippy / clippy_lints / src / transmute / transmute_ref_to_ref.rs
1 use super::{TRANSMUTE_BYTES_TO_STR, TRANSMUTE_PTR_TO_PTR};
2 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
3 use clippy_utils::source::snippet;
4 use clippy_utils::sugg;
5 use if_chain::if_chain;
6 use rustc_errors::Applicability;
7 use rustc_hir::{Expr, Mutability};
8 use rustc_lint::LateContext;
9 use rustc_middle::ty::{self, Ty};
10
11 /// Checks for `transmute_bytes_to_str` and `transmute_ptr_to_ptr` lints.
12 /// Returns `true` if either one triggered, otherwise returns `false`.
13 pub(super) fn check<'tcx>(
14     cx: &LateContext<'tcx>,
15     e: &'tcx Expr<'_>,
16     from_ty: Ty<'tcx>,
17     to_ty: Ty<'tcx>,
18     arg: &'tcx Expr<'_>,
19     const_context: bool,
20 ) -> bool {
21     let mut triggered = false;
22
23     if let (ty::Ref(_, ty_from, from_mutbl), ty::Ref(_, ty_to, to_mutbl)) = (&from_ty.kind(), &to_ty.kind()) {
24         if_chain! {
25             if let (&ty::Slice(slice_ty), &ty::Str) = (&ty_from.kind(), &ty_to.kind());
26             if let ty::Uint(ty::UintTy::U8) = slice_ty.kind();
27             if from_mutbl == to_mutbl;
28             then {
29                 let postfix = if *from_mutbl == Mutability::Mut {
30                     "_mut"
31                 } else {
32                     ""
33                 };
34
35                 let snippet = snippet(cx, arg.span, "..");
36
37                 span_lint_and_sugg(
38                     cx,
39                     TRANSMUTE_BYTES_TO_STR,
40                     e.span,
41                     &format!("transmute from a `{}` to a `{}`", from_ty, to_ty),
42                     "consider using",
43                     if const_context {
44                         format!("std::str::from_utf8_unchecked{postfix}({snippet})")
45                     } else {
46                         format!("std::str::from_utf8{postfix}({snippet}).unwrap()")
47                     },
48                     Applicability::MaybeIncorrect,
49                 );
50                 triggered = true;
51             } else {
52                 if (cx.tcx.erase_regions(from_ty) != cx.tcx.erase_regions(to_ty))
53                     && !const_context {
54                     span_lint_and_then(
55                         cx,
56                         TRANSMUTE_PTR_TO_PTR,
57                         e.span,
58                         "transmute from a reference to a reference",
59                         |diag| if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) {
60                             let ty_from_and_mut = ty::TypeAndMut {
61                                 ty: *ty_from,
62                                 mutbl: *from_mutbl
63                             };
64                             let ty_to_and_mut = ty::TypeAndMut { ty: *ty_to, mutbl: *to_mutbl };
65                             let sugg_paren = arg
66                                 .as_ty(cx.tcx.mk_ptr(ty_from_and_mut))
67                                 .as_ty(cx.tcx.mk_ptr(ty_to_and_mut));
68                             let sugg = if *to_mutbl == Mutability::Mut {
69                                 sugg_paren.mut_addr_deref()
70                             } else {
71                                 sugg_paren.addr_deref()
72                             };
73                             diag.span_suggestion(
74                                 e.span,
75                                 "try",
76                                 sugg,
77                                 Applicability::Unspecified,
78                             );
79                         },
80                     );
81
82                     triggered = true;
83                 }
84             }
85         }
86     }
87
88     triggered
89 }