@@ -11,8 +11,8 @@ use rustc_hir as hir;
1111use rustc_hir:: intravisit:: { walk_body, walk_expr, walk_ty, FnKind , NestedVisitorMap , Visitor } ;
1212use rustc_hir:: {
1313 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 ,
1616} ;
1717use rustc_lint:: { LateContext , LateLintPass , LintContext } ;
1818use rustc_middle:: hir:: map:: Map ;
@@ -23,7 +23,7 @@ use rustc_semver::RustcVersion;
2323use rustc_session:: { declare_lint_pass, declare_tool_lint, impl_lint_pass} ;
2424use rustc_span:: hygiene:: { ExpnKind , MacroKind } ;
2525use rustc_span:: source_map:: Span ;
26- use rustc_span:: symbol:: sym;
26+ use rustc_span:: symbol:: { sym, Symbol } ;
2727use rustc_target:: abi:: LayoutOf ;
2828use rustc_target:: spec:: abi:: Abi ;
2929use rustc_typeck:: hir_ty_to_ty;
@@ -32,9 +32,9 @@ use crate::consts::{constant, Constant};
3232use crate :: utils:: paths;
3333use crate :: utils:: sugg:: Sugg ;
3434use 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,
3838 snippet_with_applicability, snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg,
3939 span_lint_and_then, unsext,
4040} ;
@@ -287,37 +287,55 @@ impl<'tcx> LateLintPass<'tcx> for Types {
287287 }
288288}
289289
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
306300 }
307- None
308301}
309302
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
313313 }
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
316326 }
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
319338 }
320- None
321339}
322340
323341fn match_borrows_parameter ( _cx : & LateContext < ' _ > , qpath : & QPath < ' _ > ) -> Option < Span > {
@@ -381,7 +399,7 @@ impl Types {
381399 ) ;
382400 return ; // don't recurse into the type
383401 }
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 ( ) {
385403 span_lint_and_help (
386404 cx,
387405 BOX_VEC ,
@@ -393,30 +411,27 @@ impl Types {
393411 return ; // don't recurse into the type
394412 }
395413 } 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 ) {
397415 let mut applicability = Applicability :: MachineApplicable ;
398416 span_lint_and_sugg (
399417 cx,
400418 REDUNDANT_ALLOCATION ,
401419 hir_ty. span ,
402420 "usage of `Rc<Rc<T>>`" ,
403421 "try" ,
404- snippet_with_applicability ( cx, span, ".." , & mut applicability) . to_string ( ) ,
422+ snippet_with_applicability ( cx, ty . span , ".." , & mut applicability) . to_string ( ) ,
405423 applicability,
406424 ) ;
407425 return ; // don't recurse into the type
408426 }
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,
415430 _ => return ,
416431 } ;
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 ,
420435 } ;
421436 let mut applicability = Applicability :: MachineApplicable ;
422437 span_lint_and_sugg (
@@ -445,17 +460,14 @@ impl Types {
445460 ) ;
446461 return ; // don't recurse into the type
447462 }
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,
454466 _ => return ,
455467 } ;
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 ,
459471 } ;
460472 let mut applicability = Applicability :: MachineApplicable ;
461473 span_lint_and_sugg (
@@ -498,17 +510,14 @@ impl Types {
498510 ) ;
499511 return ; // don't recurse into the type
500512 }
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,
507516 _ => return ,
508517 } ;
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 ,
512521 } ;
513522 let mut applicability = Applicability :: MachineApplicable ;
514523 span_lint_and_sugg (
@@ -563,7 +572,7 @@ impl Types {
563572 }
564573 }
565574 } 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 ( ) {
567576 span_lint (
568577 cx,
569578 OPTION_OPTION ,
0 commit comments