@@ -11,8 +11,8 @@ use rustc_hir as hir;
11
11
use rustc_hir:: intravisit:: { walk_body, walk_expr, walk_ty, FnKind , NestedVisitorMap , Visitor } ;
12
12
use rustc_hir:: {
13
13
BinOpKind , Block , Body , Expr , ExprKind , FnDecl , FnRetTy , FnSig , GenericArg , GenericBounds , GenericParamKind , HirId ,
14
- ImplItem , ImplItemKind , Item , ItemKind , Lifetime , Lit , Local , MatchSource , MutTy , Mutability , Node , QPath , Stmt ,
15
- StmtKind , SyntheticTyParamKind , TraitFn , TraitItem , TraitItemKind , TyKind , UnOp ,
14
+ ImplItem , ImplItemKind , Item , ItemKind , LangItem , Lifetime , Lit , Local , MatchSource , MutTy , Mutability , Node ,
15
+ QPath , Stmt , StmtKind , SyntheticTyParamKind , TraitFn , TraitItem , TraitItemKind , TyKind , UnOp ,
16
16
} ;
17
17
use rustc_lint:: { LateContext , LateLintPass , LintContext } ;
18
18
use rustc_middle:: hir:: map:: Map ;
@@ -23,7 +23,7 @@ use rustc_semver::RustcVersion;
23
23
use rustc_session:: { declare_lint_pass, declare_tool_lint, impl_lint_pass} ;
24
24
use rustc_span:: hygiene:: { ExpnKind , MacroKind } ;
25
25
use rustc_span:: source_map:: Span ;
26
- use rustc_span:: symbol:: sym;
26
+ use rustc_span:: symbol:: { sym, Symbol } ;
27
27
use rustc_target:: abi:: LayoutOf ;
28
28
use rustc_target:: spec:: abi:: Abi ;
29
29
use rustc_typeck:: hir_ty_to_ty;
@@ -32,9 +32,9 @@ use crate::consts::{constant, Constant};
32
32
use crate :: utils:: paths;
33
33
use crate :: utils:: sugg:: Sugg ;
34
34
use crate :: utils:: {
35
- clip, comparisons, differing_macro_contexts, higher, in_constant, indent_of, int_bits, is_hir_ty_cfg_dependant ,
36
- is_type_diagnostic_item, last_path_segment, match_def_path, match_path, meets_msrv, method_chain_args ,
37
- multispan_sugg, numeric_literal:: NumericLiteral , reindent_multiline, sext, snippet, snippet_opt,
35
+ clip, comparisons, differing_macro_contexts, get_qpath_generic_tys , higher, in_constant, indent_of, int_bits,
36
+ is_hir_ty_cfg_dependant , is_type_diagnostic_item, last_path_segment, match_def_path, match_path, meets_msrv,
37
+ method_chain_args , multispan_sugg, numeric_literal:: NumericLiteral , reindent_multiline, sext, snippet, snippet_opt,
38
38
snippet_with_applicability, snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg,
39
39
span_lint_and_then, unsext,
40
40
} ;
@@ -287,37 +287,55 @@ impl<'tcx> LateLintPass<'tcx> for Types {
287
287
}
288
288
}
289
289
290
- /// Checks if `qpath` has last segment with type parameter matching `path`
291
- fn match_type_parameter ( cx : & LateContext < ' _ > , qpath : & QPath < ' _ > , path : & [ & str ] ) -> Option < Span > {
292
- let last = last_path_segment ( qpath) ;
293
- if_chain ! {
294
- if let Some ( ref params) = last. args;
295
- if !params. parenthesized;
296
- if let Some ( ty) = params. args. iter( ) . find_map( |arg| match arg {
297
- GenericArg :: Type ( ty) => Some ( ty) ,
298
- _ => None ,
299
- } ) ;
300
- if let TyKind :: Path ( ref qpath) = ty. kind;
301
- if let Some ( did) = cx. qpath_res( qpath, ty. hir_id) . opt_def_id( ) ;
302
- if match_def_path( cx, did, path) ;
303
- then {
304
- return Some ( ty. span) ;
305
- }
290
+ /// Checks if the first type parameter is a lang item.
291
+ fn is_ty_param_lang_item ( cx : & LateContext < ' _ > , qpath : & QPath < ' tcx > , item : LangItem ) -> Option < & ' tcx hir:: Ty < ' tcx > > {
292
+ let ty = get_qpath_generic_tys ( qpath) . next ( ) ?;
293
+
294
+ if let TyKind :: Path ( qpath) = & ty. kind {
295
+ cx. qpath_res ( qpath, ty. hir_id )
296
+ . opt_def_id ( )
297
+ . and_then ( |id| ( cx. tcx . lang_items ( ) . require ( item) == Ok ( id) ) . then ( || ty) )
298
+ } else {
299
+ None
306
300
}
307
- None
308
301
}
309
302
310
- fn match_buffer_type ( cx : & LateContext < ' _ > , qpath : & QPath < ' _ > ) -> Option < & ' static str > {
311
- if match_type_parameter ( cx, qpath, & paths:: STRING ) . is_some ( ) {
312
- return Some ( "str" ) ;
303
+ /// Checks if the first type parameter is a diagnostic item.
304
+ fn is_ty_param_diagnostic_item ( cx : & LateContext < ' _ > , qpath : & QPath < ' tcx > , item : Symbol ) -> Option < & ' tcx hir:: Ty < ' tcx > > {
305
+ let ty = get_qpath_generic_tys ( qpath) . next ( ) ?;
306
+
307
+ if let TyKind :: Path ( qpath) = & ty. kind {
308
+ cx. qpath_res ( qpath, ty. hir_id )
309
+ . opt_def_id ( )
310
+ . and_then ( |id| cx. tcx . is_diagnostic_item ( item, id) . then ( || ty) )
311
+ } else {
312
+ None
313
313
}
314
- if match_type_parameter ( cx, qpath, & paths:: OS_STRING ) . is_some ( ) {
315
- return Some ( "std::ffi::OsStr" ) ;
314
+ }
315
+
316
+ /// Checks if the first type parameter is a given item.
317
+ fn is_ty_param_path ( cx : & LateContext < ' _ > , qpath : & QPath < ' tcx > , path : & [ & str ] ) -> Option < & ' tcx hir:: Ty < ' tcx > > {
318
+ let ty = get_qpath_generic_tys ( qpath) . next ( ) ?;
319
+
320
+ if let TyKind :: Path ( qpath) = & ty. kind {
321
+ cx. qpath_res ( qpath, ty. hir_id )
322
+ . opt_def_id ( )
323
+ . and_then ( |id| match_def_path ( cx, id, path) . then ( || ty) )
324
+ } else {
325
+ None
316
326
}
317
- if match_type_parameter ( cx, qpath, & paths:: PATH_BUF ) . is_some ( ) {
318
- return Some ( "std::path::Path" ) ;
327
+ }
328
+
329
+ fn match_buffer_type ( cx : & LateContext < ' _ > , qpath : & QPath < ' _ > ) -> Option < & ' static str > {
330
+ if is_ty_param_diagnostic_item ( cx, qpath, sym:: string_type) . is_some ( ) {
331
+ Some ( "str" )
332
+ } else if is_ty_param_path ( cx, qpath, & paths:: OS_STRING ) . is_some ( ) {
333
+ Some ( "std::ffi::OsStr" )
334
+ } else if is_ty_param_path ( cx, qpath, & paths:: PATH_BUF ) . is_some ( ) {
335
+ Some ( "std::path::Path" )
336
+ } else {
337
+ None
319
338
}
320
- None
321
339
}
322
340
323
341
fn match_borrows_parameter ( _cx : & LateContext < ' _ > , qpath : & QPath < ' _ > ) -> Option < Span > {
@@ -381,7 +399,7 @@ impl Types {
381
399
) ;
382
400
return ; // don't recurse into the type
383
401
}
384
- if match_type_parameter ( cx, qpath, & paths :: VEC ) . is_some ( ) {
402
+ if is_ty_param_diagnostic_item ( cx, qpath, sym :: vec_type ) . is_some ( ) {
385
403
span_lint_and_help (
386
404
cx,
387
405
BOX_VEC ,
@@ -393,30 +411,27 @@ impl Types {
393
411
return ; // don't recurse into the type
394
412
}
395
413
} else if cx. tcx . is_diagnostic_item ( sym:: Rc , def_id) {
396
- if let Some ( span ) = match_type_parameter ( cx, qpath, & paths :: RC ) {
414
+ if let Some ( ty ) = is_ty_param_diagnostic_item ( cx, qpath, sym :: Rc ) {
397
415
let mut applicability = Applicability :: MachineApplicable ;
398
416
span_lint_and_sugg (
399
417
cx,
400
418
REDUNDANT_ALLOCATION ,
401
419
hir_ty. span ,
402
420
"usage of `Rc<Rc<T>>`" ,
403
421
"try" ,
404
- snippet_with_applicability ( cx, span, ".." , & mut applicability) . to_string ( ) ,
422
+ snippet_with_applicability ( cx, ty . span , ".." , & mut applicability) . to_string ( ) ,
405
423
applicability,
406
424
) ;
407
425
return ; // don't recurse into the type
408
426
}
409
- if match_type_parameter ( cx, qpath, & paths:: BOX ) . is_some ( ) {
410
- let box_ty = match & last_path_segment ( qpath) . args . unwrap ( ) . args [ 0 ] {
411
- GenericArg :: Type ( ty) => match & ty. kind {
412
- TyKind :: Path ( qpath) => qpath,
413
- _ => return ,
414
- } ,
427
+ if let Some ( ty) = is_ty_param_lang_item ( cx, qpath, LangItem :: OwnedBox ) {
428
+ let qpath = match & ty. kind {
429
+ TyKind :: Path ( qpath) => qpath,
415
430
_ => return ,
416
431
} ;
417
- let inner_span = match & last_path_segment ( & box_ty ) . args . unwrap ( ) . args [ 0 ] {
418
- GenericArg :: Type ( ty) => ty. span ,
419
- _ => return ,
432
+ let inner_span = match get_qpath_generic_tys ( qpath ) . next ( ) {
433
+ Some ( ty) => ty. span ,
434
+ None => return ,
420
435
} ;
421
436
let mut applicability = Applicability :: MachineApplicable ;
422
437
span_lint_and_sugg (
@@ -445,17 +460,14 @@ impl Types {
445
460
) ;
446
461
return ; // don't recurse into the type
447
462
}
448
- if match_type_parameter ( cx, qpath, & paths:: VEC ) . is_some ( ) {
449
- let vec_ty = match & last_path_segment ( qpath) . args . unwrap ( ) . args [ 0 ] {
450
- GenericArg :: Type ( ty) => match & ty. kind {
451
- TyKind :: Path ( qpath) => qpath,
452
- _ => return ,
453
- } ,
463
+ if let Some ( ty) = is_ty_param_diagnostic_item ( cx, qpath, sym:: vec_type) {
464
+ let qpath = match & ty. kind {
465
+ TyKind :: Path ( qpath) => qpath,
454
466
_ => return ,
455
467
} ;
456
- let inner_span = match & last_path_segment ( & vec_ty ) . args . unwrap ( ) . args [ 0 ] {
457
- GenericArg :: Type ( ty) => ty. span ,
458
- _ => return ,
468
+ let inner_span = match get_qpath_generic_tys ( qpath ) . next ( ) {
469
+ Some ( ty) => ty. span ,
470
+ None => return ,
459
471
} ;
460
472
let mut applicability = Applicability :: MachineApplicable ;
461
473
span_lint_and_sugg (
@@ -498,17 +510,14 @@ impl Types {
498
510
) ;
499
511
return ; // don't recurse into the type
500
512
}
501
- if match_type_parameter ( cx, qpath, & paths:: VEC ) . is_some ( ) {
502
- let vec_ty = match & last_path_segment ( qpath) . args . unwrap ( ) . args [ 0 ] {
503
- GenericArg :: Type ( ty) => match & ty. kind {
504
- TyKind :: Path ( qpath) => qpath,
505
- _ => return ,
506
- } ,
513
+ if let Some ( ty) = is_ty_param_diagnostic_item ( cx, qpath, sym:: vec_type) {
514
+ let qpath = match & ty. kind {
515
+ TyKind :: Path ( qpath) => qpath,
507
516
_ => return ,
508
517
} ;
509
- let inner_span = match & last_path_segment ( & vec_ty ) . args . unwrap ( ) . args [ 0 ] {
510
- GenericArg :: Type ( ty) => ty. span ,
511
- _ => return ,
518
+ let inner_span = match get_qpath_generic_tys ( qpath ) . next ( ) {
519
+ Some ( ty) => ty. span ,
520
+ None => return ,
512
521
} ;
513
522
let mut applicability = Applicability :: MachineApplicable ;
514
523
span_lint_and_sugg (
@@ -563,7 +572,7 @@ impl Types {
563
572
}
564
573
}
565
574
} else if cx. tcx . is_diagnostic_item ( sym:: option_type, def_id) {
566
- if match_type_parameter ( cx, qpath, & paths :: OPTION ) . is_some ( ) {
575
+ if is_ty_param_diagnostic_item ( cx, qpath, sym :: option_type ) . is_some ( ) {
567
576
span_lint (
568
577
cx,
569
578
OPTION_OPTION ,
0 commit comments