@@ -68,6 +68,34 @@ declare_clippy_lint! {
68
68
"usage of `Box<Vec<T>>`, vector elements are already on the heap"
69
69
}
70
70
71
+ /// **What it does:** Checks for use of `Vec<Box<T>>` where T: Sized anywhere in the code.
72
+ ///
73
+ /// **Why is this bad?** `Vec` already keeps its contents in a separate area on
74
+ /// the heap. So if you `Box` its contents, you just add another level of indirection.
75
+ ///
76
+ /// **Known problems:** Vec<Box<T: Sized>> makes sense if T is a large type (see #3530,
77
+ /// 1st comment).
78
+ ///
79
+ /// **Example:**
80
+ /// ```rust
81
+ /// struct X {
82
+ /// values: Vec<Box<i32>>,
83
+ /// }
84
+ /// ```
85
+ ///
86
+ /// Better:
87
+ ///
88
+ /// ```rust
89
+ /// struct X {
90
+ /// values: Vec<i32>,
91
+ /// }
92
+ /// ```
93
+ declare_clippy_lint ! {
94
+ pub VEC_BOX ,
95
+ complexity,
96
+ "usage of `Vec<Box<T>>` where T: Sized, vector elements are already on the heap"
97
+ }
98
+
71
99
/// **What it does:** Checks for use of `Option<Option<_>>` in function signatures and type
72
100
/// definitions
73
101
///
@@ -148,7 +176,7 @@ declare_clippy_lint! {
148
176
149
177
impl LintPass for TypePass {
150
178
fn get_lints ( & self ) -> LintArray {
151
- lint_array ! ( BOX_VEC , OPTION_OPTION , LINKEDLIST , BORROWED_BOX )
179
+ lint_array ! ( BOX_VEC , VEC_BOX , OPTION_OPTION , LINKEDLIST , BORROWED_BOX )
152
180
}
153
181
}
154
182
@@ -238,6 +266,43 @@ fn check_ty(cx: &LateContext<'_, '_>, ast_ty: &hir::Ty, is_local: bool) {
238
266
) ;
239
267
return ; // don't recurse into the type
240
268
}
269
+ } else if match_def_path ( cx. tcx , def_id, & paths:: VEC ) {
270
+ if_chain ! {
271
+ // Get the _ part of Vec<_>
272
+ if let Some ( ref last) = last_path_segment( qpath) . args;
273
+ if let Some ( ty) = last. args. iter( ) . find_map( |arg| match arg {
274
+ GenericArg :: Type ( ty) => Some ( ty) ,
275
+ GenericArg :: Lifetime ( _) => None ,
276
+ } ) ;
277
+ // ty is now _ at this point
278
+ if let TyKind :: Path ( ref ty_qpath) = ty. node;
279
+ let def = cx. tables. qpath_def( ty_qpath, ty. hir_id) ;
280
+ if let Some ( def_id) = opt_def_id( def) ;
281
+ if Some ( def_id) == cx. tcx. lang_items( ) . owned_box( ) ;
282
+ // At this point, we know ty is Box<T>, now get T
283
+ if let Some ( ref last) = last_path_segment( ty_qpath) . args;
284
+ if let Some ( ty) = last. args. iter( ) . find_map( |arg| match arg {
285
+ GenericArg :: Type ( ty) => Some ( ty) ,
286
+ GenericArg :: Lifetime ( _) => None ,
287
+ } ) ;
288
+ if let TyKind :: Path ( ref ty_qpath) = ty. node;
289
+ let def = cx. tables. qpath_def( ty_qpath, ty. hir_id) ;
290
+ if let Some ( def_id) = opt_def_id( def) ;
291
+ let boxed_type = cx. tcx. type_of( def_id) ;
292
+ if boxed_type. is_sized( cx. tcx. at( ty. span) , cx. param_env) ;
293
+ then {
294
+ span_lint_and_sugg(
295
+ cx,
296
+ VEC_BOX ,
297
+ ast_ty. span,
298
+ "`Vec<T>` is already on the heap, the boxing is unnecessary." ,
299
+ "try" ,
300
+ format!( "Vec<{}>" , boxed_type) ,
301
+ Applicability :: MaybeIncorrect ,
302
+ ) ;
303
+ return ; // don't recurse into the type
304
+ }
305
+ }
241
306
} else if match_def_path ( cx. tcx , def_id, & paths:: OPTION ) {
242
307
if match_type_parameter ( cx, qpath, & paths:: OPTION ) {
243
308
span_lint (
0 commit comments