1- use super :: utils:: get_type_snippet;
21use super :: TRANSMUTE_PTR_TO_REF ;
32use clippy_utils:: diagnostics:: span_lint_and_then;
4- use clippy_utils:: sugg;
3+ use clippy_utils:: source:: snippet_with_applicability;
4+ use clippy_utils:: { meets_msrv, msrvs, sugg} ;
55use rustc_errors:: Applicability ;
6- use rustc_hir:: { Expr , Mutability , QPath } ;
6+ use rustc_hir:: { self as hir , Expr , GenericArg , Mutability , Path , TyKind } ;
77use rustc_lint:: LateContext ;
8- use rustc_middle:: ty:: { self , Ty } ;
8+ use rustc_middle:: ty:: { self , Ty , TypeFoldable } ;
9+ use rustc_semver:: RustcVersion ;
910
1011/// Checks for `transmute_ptr_to_ref` lint.
1112/// Returns `true` if it's triggered, otherwise returns `false`.
@@ -15,7 +16,8 @@ pub(super) fn check<'tcx>(
1516 from_ty : Ty < ' tcx > ,
1617 to_ty : Ty < ' tcx > ,
1718 arg : & ' tcx Expr < ' _ > ,
18- qpath : & ' tcx QPath < ' _ > ,
19+ path : & ' tcx Path < ' _ > ,
20+ msrv : Option < RustcVersion > ,
1921) -> bool {
2022 match ( & from_ty. kind ( ) , & to_ty. kind ( ) ) {
2123 ( ty:: RawPtr ( from_ptr_ty) , ty:: Ref ( _, to_ref_ty, mutbl) ) => {
@@ -34,23 +36,49 @@ pub(super) fn check<'tcx>(
3436 } else {
3537 ( "&*" , "*const" )
3638 } ;
39+ let mut app = Applicability :: MachineApplicable ;
3740
38- let arg = if from_ptr_ty. ty == * to_ref_ty {
39- arg
41+ let sugg = if let Some ( ty) = get_explicit_type ( path) {
42+ let ty_snip = snippet_with_applicability ( cx, ty. span , ".." , & mut app) ;
43+ if meets_msrv ( msrv, msrvs:: POINTER_CAST ) {
44+ format ! ( "{}{}.cast::<{}>()" , deref, arg. maybe_par( ) , ty_snip)
45+ } else if from_ptr_ty. has_erased_regions ( ) {
46+ sugg:: make_unop ( deref, arg. as_ty ( format ! ( "{} () as {} {}" , cast, cast, ty_snip) ) )
47+ . to_string ( )
48+ } else {
49+ sugg:: make_unop ( deref, arg. as_ty ( format ! ( "{} {}" , cast, ty_snip) ) ) . to_string ( )
50+ }
51+ } else if from_ptr_ty. ty == * to_ref_ty {
52+ if from_ptr_ty. has_erased_regions ( ) {
53+ if meets_msrv ( msrv, msrvs:: POINTER_CAST ) {
54+ format ! ( "{}{}.cast::<{}>()" , deref, arg. maybe_par( ) , to_ref_ty)
55+ } else {
56+ sugg:: make_unop ( deref, arg. as_ty ( format ! ( "{} () as {} {}" , cast, cast, to_ref_ty) ) )
57+ . to_string ( )
58+ }
59+ } else {
60+ sugg:: make_unop ( deref, arg) . to_string ( )
61+ }
4062 } else {
41- arg. as_ty ( & format ! ( "{} {}" , cast, get_type_snippet ( cx , qpath , * to_ref_ty) ) )
63+ sugg :: make_unop ( deref , arg. as_ty ( format ! ( "{} {}" , cast, to_ref_ty) ) ) . to_string ( )
4264 } ;
4365
44- diag. span_suggestion (
45- e. span ,
46- "try" ,
47- sugg:: make_unop ( deref, arg) . to_string ( ) ,
48- Applicability :: Unspecified ,
49- ) ;
66+ diag. span_suggestion ( e. span , "try" , sugg, app) ;
5067 } ,
5168 ) ;
5269 true
5370 } ,
5471 _ => false ,
5572 }
5673}
74+
75+ /// Gets the type `Bar` in `…::transmute<Foo, &Bar>`.
76+ fn get_explicit_type < ' tcx > ( path : & ' tcx Path < ' tcx > ) -> Option < & ' tcx hir:: Ty < ' tcx > > {
77+ if let GenericArg :: Type ( ty) = path. segments . last ( ) ?. args ?. args . get ( 1 ) ?
78+ && let TyKind :: Rptr ( _, ty) = & ty. kind
79+ {
80+ Some ( ty. ty )
81+ } else {
82+ None
83+ }
84+ }
0 commit comments