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} ;
33use clippy_utils:: { get_qpath_generic_tys, is_ty_param_diagnostic_item, is_ty_param_lang_item} ;
44use rustc_errors:: Applicability ;
55use rustc_hir:: { self as hir, def_id:: DefId , LangItem , QPath , TyKind } ;
@@ -9,74 +9,99 @@ use rustc_span::symbol::sym;
99use super :: { utils, REDUNDANT_ALLOCATION } ;
1010
1111pub ( 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 ;
2640 }
2741
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 (
7070 hir_ty. span ,
71- "usage of `Rc<&T>`" ,
7271 "try" ,
73- snippet_with_applicability ( cx , span , ".. ", & mut applicability ) . to_string ( ) ,
72+ format ! ( "{}<{}> ", outer_sym , generic_snippet ) ,
7473 applicability,
7574 ) ;
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+ ) ;
7983 } 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+ ) ;
81105 }
106+ true
82107}
0 commit comments