@@ -194,11 +194,96 @@ declare_clippy_lint! {
194
194
"a box of borrowed type"
195
195
}
196
196
197
+ declare_clippy_lint ! {
198
+ /// **What it does:** Checks for use of `Rc<&T>` anywhere in the code.
199
+ ///
200
+ /// **Why is this bad?** Any `Rc<&T>` can also be a `&T`, which is more
201
+ /// general.
202
+ ///
203
+ /// **Known problems:** None.
204
+ ///
205
+ /// **Example:**
206
+ /// ```rust
207
+ /// fn foo(bar: Rc<&usize>) {}
208
+ /// ```
209
+ ///
210
+ /// Better:
211
+ ///
212
+ /// ```rust
213
+ /// fn foo(bar: &usize) {}
214
+ /// ```
215
+ pub RC_BORROWS ,
216
+ perf,
217
+ "a Rc of borrowed type"
218
+ }
219
+
220
+ declare_clippy_lint ! {
221
+ /// **What it does:** Checks for use of `Rc<Rc<T>>` anywhere in the code.
222
+ ///
223
+ /// **Why is this bad?** Reference counting pointer of reference counting pointer
224
+ /// is an unnecessary level of indirection.
225
+ ///
226
+ /// **Known problems:** None.
227
+ ///
228
+ /// **Example:**
229
+ /// ```rust
230
+ /// # use std::rc::Rc;
231
+ /// fn foo(bar: Rc<Rc<usize>>) {}
232
+ /// ```
233
+ ///
234
+ /// Better:
235
+ ///
236
+ /// ```rust
237
+ /// # use std::rc::Rc;
238
+ /// fn foo(bar: Rc<usize>) {}
239
+ /// ```
240
+ pub RC_RC ,
241
+ perf,
242
+ "an Rc of Rc"
243
+ }
244
+
245
+ declare_clippy_lint ! {
246
+ /// **What it does:** Checks for use of `Rc<Box<T>>` anywhere in the code.
247
+ ///
248
+ /// **Why is this bad?** `Rc` already keeps its contents in a separate area on
249
+ /// the heap. So if you `Box` its contents, you just add another level of indirection.
250
+ ///
251
+ /// **Known problems:** None.
252
+ ///
253
+ /// **Example:**
254
+ /// ```rust
255
+ /// # use std::rc::Rc;
256
+ /// # use std::boxed::Box;
257
+ /// fn foo(bar: Rc<Box<usize>>) {}
258
+ /// ```
259
+ ///
260
+ /// Better:
261
+ ///
262
+ /// ```rust
263
+ /// # use std::rc::Rc;
264
+ /// # use std::boxed::Box;
265
+ /// fn foo(bar: Rc<usize>) {}
266
+ /// ```
267
+ pub RC_BOX ,
268
+ perf,
269
+ "an Rc of Box"
270
+ }
271
+
197
272
pub struct Types {
198
273
vec_box_size_threshold : u64 ,
199
274
}
200
275
201
- impl_lint_pass ! ( Types => [ BOX_VEC , VEC_BOX , OPTION_OPTION , LINKEDLIST , BORROWED_BOX , BOX_BORROWS ] ) ;
276
+ impl_lint_pass ! ( Types => [
277
+ BOX_VEC ,
278
+ VEC_BOX ,
279
+ OPTION_OPTION ,
280
+ LINKEDLIST ,
281
+ BORROWED_BOX ,
282
+ BOX_BORROWS ,
283
+ RC_RC ,
284
+ RC_BOX ,
285
+ RC_BORROWS
286
+ ] ) ;
202
287
203
288
impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for Types {
204
289
fn check_fn (
@@ -259,6 +344,24 @@ fn match_type_parameter(cx: &LateContext<'_, '_>, qpath: &QPath<'_>, path: &[&st
259
344
false
260
345
}
261
346
347
+ fn match_borrows_parameter < ' a > ( cx : & ' a LateContext < ' _ , ' _ > , qpath : & QPath < ' _ > ) -> Option < Ty < ' a > > {
348
+ if_chain ! {
349
+ let last = last_path_segment( qpath) ; // why last path segment?
350
+ if let Some ( ref params) = last. args;
351
+ if !params. parenthesized; // what are parenthesized params?
352
+ if let Some ( ty) = params. args. iter( ) . find_map( |arg| match arg {
353
+ GenericArg :: Type ( ty) => Some ( ty) ,
354
+ _ => None ,
355
+ } ) ;
356
+ if let TyKind :: Rptr ( ..) = ty. kind;
357
+ let ty_ty = hir_ty_to_ty( cx. tcx, ty) ;
358
+ then {
359
+ return Some ( ty_ty) ;
360
+ }
361
+ }
362
+ return None ;
363
+ }
364
+
262
365
impl Types {
263
366
pub fn new ( vec_box_size_threshold : u64 ) -> Self {
264
367
Self { vec_box_size_threshold }
@@ -291,26 +394,15 @@ impl Types {
291
394
let res = qpath_res ( cx, qpath, hir_id) ;
292
395
if let Some ( def_id) = res. opt_def_id ( ) {
293
396
if Some ( def_id) == cx. tcx . lang_items ( ) . owned_box ( ) {
294
- if_chain ! {
295
- let last = last_path_segment( qpath) ;
296
- if let Some ( ref params) = last. args;
297
- if !params. parenthesized;
298
- if let Some ( ty) = params. args. iter( ) . find_map( |arg| match arg {
299
- GenericArg :: Type ( ty) => Some ( ty) ,
300
- _ => None ,
301
- } ) ;
302
- if let TyKind :: Rptr ( ..) = ty. kind;
303
- let ty_ty = hir_ty_to_ty( cx. tcx, ty) ;
304
- then {
305
- span_lint_and_help(
306
- cx,
307
- BOX_BORROWS ,
308
- hir_ty. span,
309
- "usage of `Box<&T>`" ,
310
- format!( "try `{}`" , ty_ty) . as_str( ) ,
311
- ) ;
312
- return ; // don't recurse into the type
313
- }
397
+ if let Some ( ty_ty) = match_borrows_parameter ( cx, qpath) {
398
+ span_lint_and_help (
399
+ cx,
400
+ BOX_BORROWS ,
401
+ hir_ty. span ,
402
+ "usage of `Box<&T>`" ,
403
+ format ! ( "try `{}`" , ty_ty) . as_str ( ) ,
404
+ ) ;
405
+ return ; // don't recurse into the type
314
406
}
315
407
if match_type_parameter ( cx, qpath, & paths:: VEC ) {
316
408
span_lint_and_help (
@@ -322,6 +414,37 @@ impl Types {
322
414
) ;
323
415
return ; // don't recurse into the type
324
416
}
417
+ } else if Some ( def_id) == cx. tcx . lang_items ( ) . rc ( ) {
418
+ if match_type_parameter ( cx, qpath, & paths:: RC ) {
419
+ span_lint_and_help (
420
+ cx,
421
+ RC_RC ,
422
+ hir_ty. span ,
423
+ "usage of `Rc<Rc<T>>`" ,
424
+ "Rc<Rc<T>> can be simplified to Rc<T>" ,
425
+ ) ;
426
+ return ; // don't recurse into the type
427
+ }
428
+ if match_type_parameter ( cx, qpath, & paths:: BOX ) {
429
+ span_lint_and_help (
430
+ cx,
431
+ RC_BOX ,
432
+ hir_ty. span ,
433
+ "usage of `Rc<Box<T>>`" ,
434
+ "Rc<Box<T>> can be simplified to Rc<T>" ,
435
+ ) ;
436
+ return ; // don't recurse into the type
437
+ }
438
+ if let Some ( ty_ty) = match_borrows_parameter ( cx, qpath) {
439
+ span_lint_and_help (
440
+ cx,
441
+ RC_BORROWS ,
442
+ hir_ty. span ,
443
+ "usage of `Rc<&T>`" ,
444
+ format ! ( "try `{}`" , ty_ty) . as_str ( ) ,
445
+ ) ;
446
+ return ; // don't recurse into the type
447
+ }
325
448
} else if cx. tcx . is_diagnostic_item ( Symbol :: intern ( "vec_type" ) , def_id) {
326
449
if_chain ! {
327
450
// Get the _ part of Vec<_>
0 commit comments