1
1
use clippy_utils:: diagnostics:: span_lint_and_sugg;
2
- use clippy_utils:: source :: snippet ;
2
+ use clippy_utils:: sugg :: { self , Sugg } ;
3
3
use clippy_utils:: sym;
4
4
use rustc_errors:: Applicability ;
5
5
use rustc_hir:: { Expr , ExprKind } ;
6
6
use rustc_lint:: { LateContext , LateLintPass } ;
7
+ use rustc_middle:: ty:: adjustment:: { Adjust , PointerCoercion } ;
7
8
use rustc_middle:: ty:: { self , ExistentialPredicate , Ty , TyCtxt } ;
8
9
use rustc_session:: declare_lint_pass;
9
10
@@ -49,23 +50,18 @@ declare_lint_pass!(CoerceContainerToAny => [COERCE_CONTAINER_TO_ANY]);
49
50
50
51
impl < ' tcx > LateLintPass < ' tcx > for CoerceContainerToAny {
51
52
fn check_expr ( & mut self , cx : & LateContext < ' tcx > , e : & ' tcx Expr < ' _ > ) {
52
- // If this expression has an effective type of `&dyn Any` ...
53
- {
54
- let coerced_ty = cx. typeck_results ( ) . expr_ty_adjusted ( e) ;
55
-
56
- let ty:: Ref ( _, coerced_ref_ty, _) = * coerced_ty. kind ( ) else {
57
- return ;
58
- } ;
59
- if !is_dyn_any ( cx. tcx , coerced_ref_ty) {
60
- return ;
61
- }
53
+ // If this expression was coerced to `&dyn Any` ...
54
+ if !cx. typeck_results ( ) . expr_adjustments ( e) . last ( ) . is_some_and ( |adj| {
55
+ matches ! ( adj. kind, Adjust :: Pointer ( PointerCoercion :: Unsize ) ) && is_ref_dyn_any ( cx. tcx , adj. target )
56
+ } ) {
57
+ return ;
62
58
}
63
59
64
60
let expr_ty = cx. typeck_results ( ) . expr_ty ( e) ;
65
61
let ty:: Ref ( _, expr_ref_ty, _) = * expr_ty. kind ( ) else {
66
62
return ;
67
63
} ;
68
- // ... but only due to coercion ...
64
+ // ... but it's not actually `&dyn Any` ...
69
65
if is_dyn_any ( cx. tcx , expr_ref_ty) {
70
66
return ;
71
67
}
@@ -78,23 +74,37 @@ impl<'tcx> LateLintPass<'tcx> for CoerceContainerToAny {
78
74
}
79
75
80
76
// ... that's probably not intended.
81
- let ( span , deref_count) = match e. kind {
77
+ let ( target_expr , deref_count) = match e. kind {
82
78
// If `e` was already an `&` expression, skip `*&` in the suggestion
83
- ExprKind :: AddrOf ( _, _, referent) => ( referent. span , depth) ,
84
- _ => ( e. span , depth + 1 ) ,
79
+ ExprKind :: AddrOf ( _, _, referent) => ( referent, depth) ,
80
+ _ => ( e, depth + 1 ) ,
85
81
} ;
82
+ let ty:: Ref ( _, _, mutability) = * cx. typeck_results ( ) . expr_ty_adjusted ( e) . kind ( ) else {
83
+ return ;
84
+ } ;
85
+ let sugg = sugg:: make_unop (
86
+ & format ! ( "{}{}" , mutability. ref_prefix_str( ) , str :: repeat( "*" , deref_count) ) ,
87
+ Sugg :: hir ( cx, target_expr, ".." ) ,
88
+ ) ;
86
89
span_lint_and_sugg (
87
90
cx,
88
91
COERCE_CONTAINER_TO_ANY ,
89
92
e. span ,
90
- format ! ( "coercing `{expr_ty}` to `& dyn Any`" ) ,
93
+ format ! ( "coercing `{expr_ty}` to `{} dyn Any`" , mutability . ref_prefix_str ( ) ) ,
91
94
"consider dereferencing" ,
92
- format ! ( "&{}{}" , str :: repeat ( "*" , deref_count ) , snippet ( cx , span , "x" ) ) ,
95
+ sugg . to_string ( ) ,
93
96
Applicability :: MaybeIncorrect ,
94
97
) ;
95
98
}
96
99
}
97
100
101
+ fn is_ref_dyn_any ( tcx : TyCtxt < ' _ > , ty : Ty < ' _ > ) -> bool {
102
+ let ty:: Ref ( _, ref_ty, _) = * ty. kind ( ) else {
103
+ return false ;
104
+ } ;
105
+ is_dyn_any ( tcx, ref_ty)
106
+ }
107
+
98
108
fn is_dyn_any ( tcx : TyCtxt < ' _ > , ty : Ty < ' _ > ) -> bool {
99
109
let ty:: Dynamic ( traits, ..) = ty. kind ( ) else {
100
110
return false ;
0 commit comments