]> git.lizzy.rs Git - rust.git/blobdiff - clippy_lints/src/transmute/transmute_ptr_to_ref.rs
remove the `Subst` trait, always use `EarlyBinder`
[rust.git] / clippy_lints / src / transmute / transmute_ptr_to_ref.rs
index f3653199b3758b2ecf4d68ef22832da4c298e8c6..5eb03275b8ec1663e5061618c95dd9d63e1e9443 100644 (file)
@@ -1,11 +1,12 @@
-use super::utils::get_type_snippet;
 use super::TRANSMUTE_PTR_TO_REF;
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::sugg;
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::{meets_msrv, msrvs, sugg};
 use rustc_errors::Applicability;
-use rustc_hir::{Expr, Mutability, QPath};
+use rustc_hir::{self as hir, Expr, GenericArg, Mutability, Path, TyKind};
 use rustc_lint::LateContext;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{self, Ty, TypeVisitable};
+use rustc_semver::RustcVersion;
 
 /// Checks for `transmute_ptr_to_ref` lint.
 /// Returns `true` if it's triggered, otherwise returns `false`.
@@ -15,7 +16,8 @@ pub(super) fn check<'tcx>(
     from_ty: Ty<'tcx>,
     to_ty: Ty<'tcx>,
     arg: &'tcx Expr<'_>,
-    qpath: &'tcx QPath<'_>,
+    path: &'tcx Path<'_>,
+    msrv: Option<RustcVersion>,
 ) -> bool {
     match (&from_ty.kind(), &to_ty.kind()) {
         (ty::RawPtr(from_ptr_ty), ty::Ref(_, to_ref_ty, mutbl)) => {
@@ -34,19 +36,34 @@ pub(super) fn check<'tcx>(
                     } else {
                         ("&*", "*const")
                     };
+                    let mut app = Applicability::MachineApplicable;
 
-                    let arg = if from_ptr_ty.ty == *to_ref_ty {
-                        arg
+                    let sugg = if let Some(ty) = get_explicit_type(path) {
+                        let ty_snip = snippet_with_applicability(cx, ty.span, "..", &mut app);
+                        if meets_msrv(msrv, msrvs::POINTER_CAST) {
+                            format!("{}{}.cast::<{}>()", deref, arg.maybe_par(), ty_snip)
+                        } else if from_ptr_ty.has_erased_regions() {
+                            sugg::make_unop(deref, arg.as_ty(format!("{} () as {} {}", cast, cast, ty_snip)))
+                                .to_string()
+                        } else {
+                            sugg::make_unop(deref, arg.as_ty(format!("{} {}", cast, ty_snip))).to_string()
+                        }
+                    } else if from_ptr_ty.ty == *to_ref_ty {
+                        if from_ptr_ty.has_erased_regions() {
+                            if meets_msrv(msrv, msrvs::POINTER_CAST) {
+                                format!("{}{}.cast::<{}>()", deref, arg.maybe_par(), to_ref_ty)
+                            } else {
+                                sugg::make_unop(deref, arg.as_ty(format!("{} () as {} {}", cast, cast, to_ref_ty)))
+                                    .to_string()
+                            }
+                        } else {
+                            sugg::make_unop(deref, arg).to_string()
+                        }
                     } else {
-                        arg.as_ty(&format!("{} {}", cast, get_type_snippet(cx, qpath, *to_ref_ty)))
+                        sugg::make_unop(deref, arg.as_ty(format!("{} {}", cast, to_ref_ty))).to_string()
                     };
 
-                    diag.span_suggestion(
-                        e.span,
-                        "try",
-                        sugg::make_unop(deref, arg).to_string(),
-                        Applicability::Unspecified,
-                    );
+                    diag.span_suggestion(e.span, "try", sugg, app);
                 },
             );
             true
@@ -54,3 +71,14 @@ pub(super) fn check<'tcx>(
         _ => false,
     }
 }
+
+/// Gets the type `Bar` in `…::transmute<Foo, &Bar>`.
+fn get_explicit_type<'tcx>(path: &'tcx Path<'tcx>) -> Option<&'tcx hir::Ty<'tcx>> {
+    if let GenericArg::Type(ty) = path.segments.last()?.args?.args.get(1)?
+        && let TyKind::Rptr(_, ty) = &ty.kind
+    {
+        Some(ty.ty)
+    } else {
+        None
+    }
+}