@@ -171,11 +171,38 @@ declare_clippy_lint! {
171
171
"a borrow of a boxed type"
172
172
}
173
173
174
+ declare_clippy_lint ! {
175
+ /// **What it does:** Checks for use of `Box<&T>` anywhere in the code.
176
+ ///
177
+ /// **Why is this bad?** Any `Box<&T>` can also be a `&T`, which is more
178
+ /// general.
179
+ ///
180
+ /// **Known problems:** None.
181
+ ///
182
+ /// **Example:**
183
+ /// ```rust,ignore
184
+ /// struct X {
185
+ /// values: Box<&T>,
186
+ /// }
187
+ /// ```
188
+ ///
189
+ /// Better:
190
+ ///
191
+ /// ```rust,ignore
192
+ /// struct X {
193
+ /// values: &T,
194
+ /// }
195
+ /// ```
196
+ pub BOX_BORROW ,
197
+ perf,
198
+ "a box of borrowed type"
199
+ }
200
+
174
201
pub struct Types {
175
202
vec_box_size_threshold : u64 ,
176
203
}
177
204
178
- impl_lint_pass ! ( Types => [ BOX_VEC , VEC_BOX , OPTION_OPTION , LINKEDLIST , BORROWED_BOX ] ) ;
205
+ impl_lint_pass ! ( Types => [ BOX_VEC , VEC_BOX , OPTION_OPTION , LINKEDLIST , BORROWED_BOX , BOX_BORROW ] ) ;
179
206
180
207
impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for Types {
181
208
fn check_fn (
@@ -236,6 +263,24 @@ fn match_type_parameter(cx: &LateContext<'_, '_>, qpath: &QPath<'_>, path: &[&st
236
263
false
237
264
}
238
265
266
+ /// Checks if `qpath` last segment type parameter is a reference
267
+ fn match_type_parameter_rptr ( qpath : & QPath < ' _ > ) -> bool {
268
+ let last = last_path_segment ( qpath) ;
269
+ if_chain ! {
270
+ if let Some ( ref params) = last. args;
271
+ if !params. parenthesized;
272
+ if let Some ( ty) = params. args. iter( ) . find_map( |arg| match arg {
273
+ GenericArg :: Type ( ty) => Some ( ty) ,
274
+ _ => None ,
275
+ } ) ;
276
+ if let TyKind :: Rptr ( ref _lifetime_opt, ref _mut) = ty. kind;
277
+ then {
278
+ return true ;
279
+ }
280
+ }
281
+ false
282
+ }
283
+
239
284
impl Types {
240
285
pub fn new ( vec_box_size_threshold : u64 ) -> Self {
241
286
Self { vec_box_size_threshold }
@@ -267,6 +312,29 @@ impl Types {
267
312
let res = qpath_res ( cx, qpath, hir_id) ;
268
313
if let Some ( def_id) = res. opt_def_id ( ) {
269
314
if Some ( def_id) == cx. tcx . lang_items ( ) . owned_box ( ) {
315
+ if match_type_parameter_rptr ( qpath) {
316
+ let last = last_path_segment ( qpath) ;
317
+ if_chain ! {
318
+ if let Some ( ref params) = last. args;
319
+ if !params. parenthesized;
320
+ if let Some ( ty) = params. args. iter( ) . find_map( |arg| match arg {
321
+ GenericArg :: Type ( ty) => Some ( ty) ,
322
+ _ => None ,
323
+ } ) ;
324
+ if let TyKind :: Rptr ( ref _lifetime_opt, ref _mut) = ty. kind;
325
+ then {
326
+ let ty_ty = hir_ty_to_ty( cx. tcx, ty) ;
327
+ span_lint_and_help(
328
+ cx,
329
+ BOX_BORROW ,
330
+ hir_ty. span,
331
+ "usage of `Box<&T>`" ,
332
+ format!( "try `{}`" , ty_ty) . as_str( ) ,
333
+ ) ;
334
+ return ; // don't recurse into the type
335
+ }
336
+ }
337
+ }
270
338
if match_type_parameter ( cx, qpath, & paths:: VEC ) {
271
339
span_lint_and_help (
272
340
cx,
0 commit comments