1
- use clippy_utils:: diagnostics:: span_lint_and_sugg ;
2
- use clippy_utils:: source:: snippet_with_applicability;
1
+ use clippy_utils:: diagnostics:: span_lint_and_then ;
2
+ use clippy_utils:: source:: { snippet , snippet_with_applicability} ;
3
3
use clippy_utils:: { get_qpath_generic_tys, is_ty_param_diagnostic_item, is_ty_param_lang_item} ;
4
4
use rustc_errors:: Applicability ;
5
5
use rustc_hir:: { self as hir, def_id:: DefId , LangItem , QPath , TyKind } ;
@@ -9,74 +9,99 @@ use rustc_span::symbol::sym;
9
9
use super :: { utils, REDUNDANT_ALLOCATION } ;
10
10
11
11
pub ( super ) fn check ( cx : & LateContext < ' _ > , hir_ty : & hir:: Ty < ' _ > , qpath : & QPath < ' _ > , def_id : DefId ) -> bool {
12
- if Some ( def_id) == cx. tcx . lang_items ( ) . owned_box ( ) {
13
- if let Some ( span) = utils:: match_borrows_parameter ( cx, qpath) {
14
- let mut applicability = Applicability :: MachineApplicable ;
15
- span_lint_and_sugg (
16
- cx,
17
- REDUNDANT_ALLOCATION ,
18
- hir_ty. span ,
19
- "usage of `Box<&T>`" ,
20
- "try" ,
21
- snippet_with_applicability ( cx, span, ".." , & mut applicability) . to_string ( ) ,
22
- applicability,
23
- ) ;
24
- return true ;
25
- }
12
+ let outer_sym = if Some ( def_id) == cx. tcx . lang_items ( ) . owned_box ( ) {
13
+ "Box"
14
+ } else if cx. tcx . is_diagnostic_item ( sym:: Rc , def_id) {
15
+ "Rc"
16
+ } else if cx. tcx . is_diagnostic_item ( sym:: Arc , def_id) {
17
+ "Arc"
18
+ } else {
19
+ return false ;
20
+ } ;
21
+
22
+ if let Some ( span) = utils:: match_borrows_parameter ( cx, qpath) {
23
+ let mut applicability = Applicability :: MaybeIncorrect ;
24
+ let generic_snippet = snippet_with_applicability ( cx, span, ".." , & mut applicability) ;
25
+ span_lint_and_then (
26
+ cx,
27
+ REDUNDANT_ALLOCATION ,
28
+ hir_ty. span ,
29
+ & format ! ( "usage of `{}<{}>`" , outer_sym, generic_snippet) ,
30
+ |diag| {
31
+ diag. span_suggestion ( hir_ty. span , "try" , format ! ( "{}" , generic_snippet) , applicability) ;
32
+ diag. note ( & format ! (
33
+ "`{generic}` is already a pointer, `{outer}<{generic}>` allocates a pointer on the heap" ,
34
+ outer = outer_sym,
35
+ generic = generic_snippet
36
+ ) ) ;
37
+ } ,
38
+ ) ;
39
+ return true ;
26
40
}
27
41
28
- if cx. tcx . is_diagnostic_item ( sym:: Rc , def_id) {
29
- if let Some ( ty) = is_ty_param_diagnostic_item ( cx, qpath, sym:: Rc ) {
30
- let mut applicability = Applicability :: MachineApplicable ;
31
- span_lint_and_sugg (
32
- cx,
33
- REDUNDANT_ALLOCATION ,
34
- hir_ty. span ,
35
- "usage of `Rc<Rc<T>>`" ,
36
- "try" ,
37
- snippet_with_applicability ( cx, ty. span , ".." , & mut applicability) . to_string ( ) ,
38
- applicability,
39
- ) ;
40
- true
41
- } else if let Some ( ty) = is_ty_param_lang_item ( cx, qpath, LangItem :: OwnedBox ) {
42
- let qpath = match & ty. kind {
43
- TyKind :: Path ( qpath) => qpath,
44
- _ => return false ,
45
- } ;
46
- let inner_span = match get_qpath_generic_tys ( qpath) . next ( ) {
47
- Some ( ty) => ty. span ,
48
- None => return false ,
49
- } ;
50
- let mut applicability = Applicability :: MachineApplicable ;
51
- span_lint_and_sugg (
52
- cx,
53
- REDUNDANT_ALLOCATION ,
54
- hir_ty. span ,
55
- "usage of `Rc<Box<T>>`" ,
56
- "try" ,
57
- format ! (
58
- "Rc<{}>" ,
59
- snippet_with_applicability( cx, inner_span, ".." , & mut applicability)
60
- ) ,
61
- applicability,
62
- ) ;
63
- true
64
- } else {
65
- utils:: match_borrows_parameter ( cx, qpath) . map_or ( false , |span| {
66
- let mut applicability = Applicability :: MachineApplicable ;
67
- span_lint_and_sugg (
68
- cx,
69
- REDUNDANT_ALLOCATION ,
42
+ let ( inner_sym, ty) = if let Some ( ty) = is_ty_param_lang_item ( cx, qpath, LangItem :: OwnedBox ) {
43
+ ( "Box" , ty)
44
+ } else if let Some ( ty) = is_ty_param_diagnostic_item ( cx, qpath, sym:: Rc ) {
45
+ ( "Rc" , ty)
46
+ } else if let Some ( ty) = is_ty_param_diagnostic_item ( cx, qpath, sym:: Arc ) {
47
+ ( "Arc" , ty)
48
+ } else {
49
+ return false ;
50
+ } ;
51
+
52
+ let inner_qpath = match & ty. kind {
53
+ TyKind :: Path ( inner_qpath) => inner_qpath,
54
+ _ => return false ,
55
+ } ;
56
+ let inner_span = match get_qpath_generic_tys ( inner_qpath) . next ( ) {
57
+ Some ( ty) => ty. span ,
58
+ None => return false ,
59
+ } ;
60
+ if inner_sym == outer_sym {
61
+ let mut applicability = Applicability :: MaybeIncorrect ;
62
+ let generic_snippet = snippet_with_applicability ( cx, inner_span, ".." , & mut applicability) ;
63
+ span_lint_and_then (
64
+ cx,
65
+ REDUNDANT_ALLOCATION ,
66
+ hir_ty. span ,
67
+ & format ! ( "usage of `{}<{}<{}>>`" , outer_sym, inner_sym, generic_snippet) ,
68
+ |diag| {
69
+ diag. span_suggestion (
70
70
hir_ty. span ,
71
- "usage of `Rc<&T>`" ,
72
71
"try" ,
73
- snippet_with_applicability ( cx , span , ".. ", & mut applicability ) . to_string ( ) ,
72
+ format ! ( "{}<{}> ", outer_sym , generic_snippet ) ,
74
73
applicability,
75
74
) ;
76
- true
77
- } )
78
- }
75
+ diag. note ( & format ! (
76
+ "`{inner}<{generic}>` is already on the heap, `{outer}<{inner}<{generic}>>` makes an extra allocation" ,
77
+ outer = outer_sym,
78
+ inner = inner_sym,
79
+ generic = generic_snippet
80
+ ) ) ;
81
+ } ,
82
+ ) ;
79
83
} else {
80
- false
84
+ let generic_snippet = snippet ( cx, inner_span, ".." ) ;
85
+ span_lint_and_then (
86
+ cx,
87
+ REDUNDANT_ALLOCATION ,
88
+ hir_ty. span ,
89
+ & format ! ( "usage of `{}<{}<{}>>`" , outer_sym, inner_sym, generic_snippet) ,
90
+ |diag| {
91
+ diag. note ( & format ! (
92
+ "`{inner}<{generic}>` is already on the heap, `{outer}<{inner}<{generic}>>` makes an extra allocation" ,
93
+ outer = outer_sym,
94
+ inner = inner_sym,
95
+ generic = generic_snippet
96
+ ) ) ;
97
+ diag. help ( & format ! (
98
+ "consider using just `{outer}<{generic}>` or `{inner}<{generic}>`" ,
99
+ outer = outer_sym,
100
+ inner = inner_sym,
101
+ generic = generic_snippet
102
+ ) ) ;
103
+ } ,
104
+ ) ;
81
105
}
106
+ true
82
107
}
0 commit comments