11use clippy_utils:: diagnostics:: span_lint_and_sugg;
2- use clippy_utils:: source :: snippet ;
2+ use clippy_utils:: sugg :: { self , Sugg } ;
33use clippy_utils:: sym;
44use rustc_errors:: Applicability ;
55use rustc_hir:: { Expr , ExprKind } ;
66use rustc_lint:: { LateContext , LateLintPass } ;
7+ use rustc_middle:: ty:: adjustment:: { Adjust , PointerCoercion } ;
78use rustc_middle:: ty:: { self , ExistentialPredicate , Ty , TyCtxt } ;
89use rustc_session:: declare_lint_pass;
910
@@ -49,23 +50,18 @@ declare_lint_pass!(CoerceContainerToAny => [COERCE_CONTAINER_TO_ANY]);
4950
5051impl < ' tcx > LateLintPass < ' tcx > for CoerceContainerToAny {
5152 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 ;
6258 }
6359
6460 let expr_ty = cx. typeck_results ( ) . expr_ty ( e) ;
6561 let ty:: Ref ( _, expr_ref_ty, _) = * expr_ty. kind ( ) else {
6662 return ;
6763 } ;
68- // ... but only due to coercion ...
64+ // ... but it's not actually `&dyn Any` ...
6965 if is_dyn_any ( cx. tcx , expr_ref_ty) {
7066 return ;
7167 }
@@ -78,23 +74,37 @@ impl<'tcx> LateLintPass<'tcx> for CoerceContainerToAny {
7874 }
7975
8076 // ... that's probably not intended.
81- let ( span , deref_count) = match e. kind {
77+ let ( target_expr , deref_count) = match e. kind {
8278 // 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 ) ,
8581 } ;
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+ ) ;
8689 span_lint_and_sugg (
8790 cx,
8891 COERCE_CONTAINER_TO_ANY ,
8992 e. span ,
90- format ! ( "coercing `{expr_ty}` to `& dyn Any`" ) ,
93+ format ! ( "coercing `{expr_ty}` to `{} dyn Any`" , mutability . ref_prefix_str ( ) ) ,
9194 "consider dereferencing" ,
92- format ! ( "&{}{}" , str :: repeat ( "*" , deref_count ) , snippet ( cx , span , "x" ) ) ,
95+ sugg . to_string ( ) ,
9396 Applicability :: MaybeIncorrect ,
9497 ) ;
9598 }
9699}
97100
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+
98108fn is_dyn_any ( tcx : TyCtxt < ' _ > , ty : Ty < ' _ > ) -> bool {
99109 let ty:: Dynamic ( traits, ..) = ty. kind ( ) else {
100110 return false ;
0 commit comments