]> git.lizzy.rs Git - rust.git/blob - src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs
Move `{core,std}::stream::Stream` to `{core,std}::async_iter::AsyncIterator`.
[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     args: &'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                 span_lint_and_sugg(
36                     cx,
37                     TRANSMUTE_BYTES_TO_STR,
38                     e.span,
39                     &format!("transmute from a `{}` to a `{}`", from_ty, to_ty),
40                     "consider using",
41                     format!(
42                         "std::str::from_utf8{}({}).unwrap()",
43                         postfix,
44                         snippet(cx, args[0].span, ".."),
45                     ),
46                     Applicability::Unspecified,
47                 );
48                 triggered = true;
49             } else {
50                 if (cx.tcx.erase_regions(from_ty) != cx.tcx.erase_regions(to_ty))
51                     && !const_context {
52                     span_lint_and_then(
53                         cx,
54                         TRANSMUTE_PTR_TO_PTR,
55                         e.span,
56                         "transmute from a reference to a reference",
57                         |diag| if let Some(arg) = sugg::Sugg::hir_opt(cx, &args[0]) {
58                             let ty_from_and_mut = ty::TypeAndMut {
59                                 ty: ty_from,
60                                 mutbl: *from_mutbl
61                             };
62                             let ty_to_and_mut = ty::TypeAndMut { ty: ty_to, mutbl: *to_mutbl };
63                             let sugg_paren = arg
64                                 .as_ty(cx.tcx.mk_ptr(ty_from_and_mut))
65                                 .as_ty(cx.tcx.mk_ptr(ty_to_and_mut));
66                             let sugg = if *to_mutbl == Mutability::Mut {
67                                 sugg_paren.mut_addr_deref()
68                             } else {
69                                 sugg_paren.addr_deref()
70                             };
71                             diag.span_suggestion(
72                                 e.span,
73                                 "try",
74                                 sugg.to_string(),
75                                 Applicability::Unspecified,
76                             );
77                         },
78                     );
79
80                     triggered = true;
81                 }
82             }
83         }
84     }
85
86     triggered
87 }