1
- use super :: utils:: get_type_snippet;
2
1
use super :: TRANSMUTE_PTR_TO_REF ;
3
2
use 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} ;
5
5
use rustc_errors:: Applicability ;
6
- use rustc_hir:: { Expr , Mutability , QPath } ;
6
+ use rustc_hir:: { self as hir , Expr , GenericArg , Mutability , Path , TyKind } ;
7
7
use rustc_lint:: LateContext ;
8
- use rustc_middle:: ty:: { self , Ty } ;
8
+ use rustc_middle:: ty:: { self , Ty , TypeFoldable } ;
9
+ use rustc_semver:: RustcVersion ;
9
10
10
11
/// Checks for `transmute_ptr_to_ref` lint.
11
12
/// Returns `true` if it's triggered, otherwise returns `false`.
@@ -15,7 +16,8 @@ pub(super) fn check<'tcx>(
15
16
from_ty : Ty < ' tcx > ,
16
17
to_ty : Ty < ' tcx > ,
17
18
arg : & ' tcx Expr < ' _ > ,
18
- qpath : & ' tcx QPath < ' _ > ,
19
+ path : & ' tcx Path < ' _ > ,
20
+ msrv : Option < RustcVersion > ,
19
21
) -> bool {
20
22
match ( & from_ty. kind ( ) , & to_ty. kind ( ) ) {
21
23
( ty:: RawPtr ( from_ptr_ty) , ty:: Ref ( _, to_ref_ty, mutbl) ) => {
@@ -34,23 +36,49 @@ pub(super) fn check<'tcx>(
34
36
} else {
35
37
( "&*" , "*const" )
36
38
} ;
39
+ let mut app = Applicability :: MachineApplicable ;
37
40
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
+ }
40
62
} 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 ( )
42
64
} ;
43
65
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) ;
50
67
} ,
51
68
) ;
52
69
true
53
70
} ,
54
71
_ => false ,
55
72
}
56
73
}
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