1
+ use std:: borrow:: Cow ;
2
+
1
3
use crate :: methods:: TYPE_ID_ON_BOX ;
2
4
use clippy_utils:: diagnostics:: span_lint_and_then;
3
5
use clippy_utils:: source:: snippet;
4
6
use rustc_errors:: Applicability ;
5
7
use rustc_hir:: Expr ;
6
8
use rustc_lint:: LateContext ;
7
9
use rustc_middle:: ty:: adjustment:: { Adjust , Adjustment } ;
10
+ use rustc_middle:: ty:: print:: with_forced_trimmed_paths;
8
11
use rustc_middle:: ty:: { self , ExistentialPredicate , Ty } ;
9
12
use rustc_span:: { sym, Span } ;
10
13
11
- fn is_dyn_any ( cx : & LateContext < ' _ > , ty : Ty < ' _ > ) -> bool {
14
+ /// Checks if a [`Ty`] is a `dyn Any` or a `dyn Trait` where `Trait: Any`
15
+ /// and returns the name of the trait object.
16
+ fn is_dyn_any ( cx : & LateContext < ' _ > , ty : Ty < ' _ > ) -> Option < Cow < ' static , str > > {
12
17
if let ty:: Dynamic ( preds, ..) = ty. kind ( ) {
13
- preds. iter ( ) . any ( |p| match p. skip_binder ( ) {
14
- ExistentialPredicate :: Trait ( tr) => cx. tcx . is_diagnostic_item ( sym:: Any , tr. def_id ) ,
15
- _ => false ,
18
+ preds. iter ( ) . find_map ( |p| match p. skip_binder ( ) {
19
+ ExistentialPredicate :: Trait ( tr) => {
20
+ if cx. tcx . is_diagnostic_item ( sym:: Any , tr. def_id ) {
21
+ Some ( Cow :: Borrowed ( "Any" ) )
22
+ } else if cx
23
+ . tcx
24
+ . super_predicates_of ( tr. def_id )
25
+ . predicates
26
+ . iter ( )
27
+ . any ( |( clause, _) | {
28
+ matches ! ( clause. kind( ) . skip_binder( ) , ty:: ClauseKind :: Trait ( super_tr)
29
+ if cx. tcx. is_diagnostic_item( sym:: Any , super_tr. def_id( ) ) )
30
+ } )
31
+ {
32
+ Some ( Cow :: Owned ( with_forced_trimmed_paths ! ( cx. tcx. def_path_str( tr. def_id) ) ) )
33
+ } else {
34
+ None
35
+ }
36
+ } ,
37
+ _ => None ,
16
38
} )
17
39
} else {
18
- false
40
+ None
19
41
}
20
42
}
21
43
@@ -26,13 +48,13 @@ pub(super) fn check(cx: &LateContext<'_>, receiver: &Expr<'_>, call_span: Span)
26
48
&& let ty:: Ref ( _, ty, _) = recv_ty. kind ( )
27
49
&& let ty:: Adt ( adt, args) = ty. kind ( )
28
50
&& adt. is_box ( )
29
- && is_dyn_any ( cx, args. type_at ( 0 ) )
51
+ && let Some ( trait_path ) = is_dyn_any ( cx, args. type_at ( 0 ) )
30
52
{
31
53
span_lint_and_then (
32
54
cx,
33
55
TYPE_ID_ON_BOX ,
34
56
call_span,
35
- "calling `.type_id()` on a `Box<dyn Any >`" ,
57
+ & format ! ( "calling `.type_id()` on `Box<dyn {trait_path} >`" ) ,
36
58
|diag| {
37
59
let derefs = recv_adjusts
38
60
. iter ( )
@@ -43,13 +65,13 @@ pub(super) fn check(cx: &LateContext<'_>, receiver: &Expr<'_>, call_span: Span)
43
65
sugg += & snippet ( cx, receiver. span , "<expr>" ) ;
44
66
45
67
diag. note (
46
- "this returns the type id of the literal type `Box<dyn Any>` instead of the \
47
- type id of the boxed value, which is most likely not what you want",
48
- )
49
- . note (
50
- "if this is intentional, use `TypeId::of::<Box<dyn Any>>()` instead, \
51
- which makes it more clear",
68
+ "this returns the type id of the literal type `Box<_>` instead of the \
69
+ type id of the boxed value, which is most likely not what you want"
52
70
)
71
+ . note ( format ! (
72
+ "if this is intentional, use `TypeId::of::<Box<dyn {trait_path}>>()` instead, \
73
+ which makes it more clear"
74
+ ) )
53
75
. span_suggestion (
54
76
receiver. span ,
55
77
"consider dereferencing first" ,
0 commit comments