@@ -171,11 +171,35 @@ 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 redundant allocations anywhere in the code.
176
+ ///
177
+ /// **Why is this bad?** Expressions such as `Rc<&T>`, `Rc<Rc<T>>`, `Rc<Box<T>>`, `Box<&T>`
178
+ /// add an unnecessary level of indirection.
179
+ ///
180
+ /// **Known problems:** None.
181
+ ///
182
+ /// **Example:**
183
+ /// ```rust
184
+ /// # use std::rc::Rc;
185
+ /// fn foo(bar: Rc<&usize>) {}
186
+ /// ```
187
+ ///
188
+ /// Better:
189
+ ///
190
+ /// ```rust
191
+ /// fn foo(bar: &usize) {}
192
+ /// ```
193
+ pub REDUNDANT_ALLOCATION ,
194
+ perf,
195
+ "redundant allocation"
196
+ }
197
+
174
198
pub struct Types {
175
199
vec_box_size_threshold : u64 ,
176
200
}
177
201
178
- impl_lint_pass ! ( Types => [ BOX_VEC , VEC_BOX , OPTION_OPTION , LINKEDLIST , BORROWED_BOX ] ) ;
202
+ impl_lint_pass ! ( Types => [ BOX_VEC , VEC_BOX , OPTION_OPTION , LINKEDLIST , BORROWED_BOX , REDUNDANT_ALLOCATION ] ) ;
179
203
180
204
impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for Types {
181
205
fn check_fn (
@@ -217,7 +241,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Types {
217
241
}
218
242
219
243
/// Checks if `qpath` has last segment with type parameter matching `path`
220
- fn match_type_parameter ( cx : & LateContext < ' _ , ' _ > , qpath : & QPath < ' _ > , path : & [ & str ] ) -> bool {
244
+ fn match_type_parameter ( cx : & LateContext < ' _ , ' _ > , qpath : & QPath < ' _ > , path : & [ & str ] ) -> Option < Span > {
221
245
let last = last_path_segment ( qpath) ;
222
246
if_chain ! {
223
247
if let Some ( ref params) = last. args;
@@ -230,10 +254,27 @@ fn match_type_parameter(cx: &LateContext<'_, '_>, qpath: &QPath<'_>, path: &[&st
230
254
if let Some ( did) = qpath_res( cx, qpath, ty. hir_id) . opt_def_id( ) ;
231
255
if match_def_path( cx, did, path) ;
232
256
then {
233
- return true ;
257
+ return Some ( ty . span ) ;
234
258
}
235
259
}
236
- false
260
+ None
261
+ }
262
+
263
+ fn match_borrows_parameter ( _cx : & LateContext < ' _ , ' _ > , qpath : & QPath < ' _ > ) -> Option < Span > {
264
+ let last = last_path_segment ( qpath) ;
265
+ if_chain ! {
266
+ if let Some ( ref params) = last. args;
267
+ if !params. parenthesized;
268
+ if let Some ( ty) = params. args. iter( ) . find_map( |arg| match arg {
269
+ GenericArg :: Type ( ty) => Some ( ty) ,
270
+ _ => None ,
271
+ } ) ;
272
+ if let TyKind :: Rptr ( ..) = ty. kind;
273
+ then {
274
+ return Some ( ty. span) ;
275
+ }
276
+ }
277
+ None
237
278
}
238
279
239
280
impl Types {
@@ -267,7 +308,19 @@ impl Types {
267
308
let res = qpath_res ( cx, qpath, hir_id) ;
268
309
if let Some ( def_id) = res. opt_def_id ( ) {
269
310
if Some ( def_id) == cx. tcx . lang_items ( ) . owned_box ( ) {
270
- if match_type_parameter ( cx, qpath, & paths:: VEC ) {
311
+ if let Some ( span) = match_borrows_parameter ( cx, qpath) {
312
+ span_lint_and_sugg (
313
+ cx,
314
+ REDUNDANT_ALLOCATION ,
315
+ hir_ty. span ,
316
+ "usage of `Box<&T>`" ,
317
+ "try" ,
318
+ snippet ( cx, span, ".." ) . to_string ( ) ,
319
+ Applicability :: MachineApplicable ,
320
+ ) ;
321
+ return ; // don't recurse into the type
322
+ }
323
+ if let Some ( _) = match_type_parameter ( cx, qpath, & paths:: VEC ) {
271
324
span_lint_and_help (
272
325
cx,
273
326
BOX_VEC ,
@@ -277,6 +330,43 @@ impl Types {
277
330
) ;
278
331
return ; // don't recurse into the type
279
332
}
333
+ } else if Some ( def_id) == cx. tcx . lang_items ( ) . rc ( ) {
334
+ if let Some ( span) = match_type_parameter ( cx, qpath, & paths:: RC ) {
335
+ span_lint_and_sugg (
336
+ cx,
337
+ REDUNDANT_ALLOCATION ,
338
+ hir_ty. span ,
339
+ "usage of `Rc<Rc<T>>`" ,
340
+ "try" ,
341
+ snippet ( cx, span, ".." ) . to_string ( ) ,
342
+ Applicability :: MachineApplicable ,
343
+ ) ;
344
+ return ; // don't recurse into the type
345
+ }
346
+ if let Some ( span) = match_type_parameter ( cx, qpath, & paths:: BOX ) {
347
+ span_lint_and_sugg (
348
+ cx,
349
+ REDUNDANT_ALLOCATION ,
350
+ hir_ty. span ,
351
+ "usage of `Rc<Box<T>>`" ,
352
+ "try" ,
353
+ snippet ( cx, span, ".." ) . to_string ( ) ,
354
+ Applicability :: MachineApplicable ,
355
+ ) ;
356
+ return ; // don't recurse into the type
357
+ }
358
+ if let Some ( span) = match_borrows_parameter ( cx, qpath) {
359
+ span_lint_and_sugg (
360
+ cx,
361
+ REDUNDANT_ALLOCATION ,
362
+ hir_ty. span ,
363
+ "usage of `Rc<&T>`" ,
364
+ "try" ,
365
+ snippet ( cx, span, ".." ) . to_string ( ) ,
366
+ Applicability :: MachineApplicable ,
367
+ ) ;
368
+ return ; // don't recurse into the type
369
+ }
280
370
} else if cx. tcx . is_diagnostic_item ( Symbol :: intern ( "vec_type" ) , def_id) {
281
371
if_chain ! {
282
372
// Get the _ part of Vec<_>
@@ -314,7 +404,7 @@ impl Types {
314
404
}
315
405
}
316
406
} else if match_def_path ( cx, def_id, & paths:: OPTION ) {
317
- if match_type_parameter ( cx, qpath, & paths:: OPTION ) {
407
+ if let Some ( _ ) = match_type_parameter ( cx, qpath, & paths:: OPTION ) {
318
408
span_lint (
319
409
cx,
320
410
OPTION_OPTION ,
0 commit comments