@@ -31,7 +31,6 @@ pub use self::hir_utils::{both, eq_expr_value, over, SpanlessEq, SpanlessHash};
3131use std:: borrow:: Cow ;
3232use std:: collections:: hash_map:: Entry ;
3333use std:: hash:: BuildHasherDefault ;
34- use std:: mem;
3534
3635use if_chain:: if_chain;
3736use rustc_ast:: ast:: { self , Attribute , LitKind } ;
@@ -40,7 +39,7 @@ use rustc_data_structures::fx::FxHashMap;
4039use rustc_errors:: Applicability ;
4140use rustc_hir as hir;
4241use rustc_hir:: def:: { DefKind , Res } ;
43- use rustc_hir:: def_id:: { DefId , CRATE_DEF_INDEX , LOCAL_CRATE } ;
42+ use rustc_hir:: def_id:: { DefId , LOCAL_CRATE } ;
4443use rustc_hir:: intravisit:: { self , NestedVisitorMap , Visitor } ;
4544use rustc_hir:: Node ;
4645use rustc_hir:: {
@@ -49,6 +48,7 @@ use rustc_hir::{
4948} ;
5049use rustc_infer:: infer:: TyCtxtInferExt ;
5150use rustc_lint:: { LateContext , Level , Lint , LintContext } ;
51+ use rustc_middle:: hir:: exports:: Export ;
5252use rustc_middle:: hir:: map:: Map ;
5353use rustc_middle:: ty:: subst:: { GenericArg , GenericArgKind } ;
5454use rustc_middle:: ty:: { self , layout:: IntegerExt , Ty , TyCtxt , TypeFoldable } ;
@@ -309,65 +309,43 @@ pub fn match_path_ast(path: &ast::Path, segments: &[&str]) -> bool {
309309}
310310
311311/// Gets the definition associated to a path.
312- pub fn path_to_res ( cx : & LateContext < ' _ > , path : & [ & str ] ) -> Option < def:: Res > {
313- let crates = cx. tcx . crates ( ) ;
314- let krate = crates
315- . iter ( )
316- . find ( |& & krate| cx. tcx . crate_name ( krate) . as_str ( ) == path[ 0 ] ) ;
317- if let Some ( krate) = krate {
318- let krate = DefId {
319- krate : * krate,
320- index : CRATE_DEF_INDEX ,
321- } ;
322- let mut current_item = None ;
323- let mut items = cx. tcx . item_children ( krate) ;
324- let mut path_it = path. iter ( ) . skip ( 1 ) . peekable ( ) ;
325-
326- loop {
327- let segment = match path_it. next ( ) {
328- Some ( segment) => segment,
329- None => return None ,
330- } ;
331-
332- // `get_def_path` seems to generate these empty segments for extern blocks.
333- // We can just ignore them.
334- if segment. is_empty ( ) {
335- continue ;
336- }
337-
338- let result = SmallVec :: < [ _ ; 8 ] > :: new ( ) ;
339- for item in mem:: replace ( & mut items, cx. tcx . arena . alloc_slice ( & result) ) . iter ( ) {
340- if item. ident . name . as_str ( ) == * segment {
341- if path_it. peek ( ) . is_none ( ) {
342- return Some ( item. res ) ;
343- }
344-
345- current_item = Some ( item) ;
346- items = cx. tcx . item_children ( item. res . def_id ( ) ) ;
347- break ;
348- }
349- }
312+ #[ allow( clippy:: shadow_unrelated) ] // false positive #6563
313+ pub fn path_to_res ( cx : & LateContext < ' _ > , path : & [ & str ] ) -> Option < Res > {
314+ fn item_child_by_name < ' tcx > ( tcx : TyCtxt < ' tcx > , def_id : DefId , name : & str ) -> Option < & ' tcx Export < HirId > > {
315+ tcx. item_children ( def_id)
316+ . iter ( )
317+ . find ( |item| item. ident . name . as_str ( ) == name)
318+ }
350319
351- // The segment isn't a child_item.
352- // Try to find it under an inherent impl.
353- if_chain ! {
354- if path_it. peek( ) . is_none( ) ;
355- if let Some ( current_item) = current_item;
356- let item_def_id = current_item. res. def_id( ) ;
357- if cx. tcx. def_kind( item_def_id) == DefKind :: Struct ;
358- then {
359- // Bad `find_map` suggestion. See #4193.
360- #[ allow( clippy:: find_map) ]
361- return cx. tcx. inherent_impls( item_def_id) . iter( )
362- . flat_map( |& impl_def_id| cx. tcx. item_children( impl_def_id) )
363- . find( |item| item. ident. name. as_str( ) == * segment)
364- . map( |item| item. res) ;
365- }
320+ let ( krate, first, path) = match * path {
321+ [ krate, first, ref path @ ..] => ( krate, first, path) ,
322+ _ => return None ,
323+ } ;
324+ let tcx = cx. tcx ;
325+ let crates = tcx. crates ( ) ;
326+ let krate = crates. iter ( ) . find ( |& & num| tcx. crate_name ( num) . as_str ( ) == krate) ?;
327+ let first = item_child_by_name ( tcx, krate. as_def_id ( ) , first) ?;
328+ let last = path
329+ . iter ( )
330+ . copied ( )
331+ // `get_def_path` seems to generate these empty segments for extern blocks.
332+ // We can just ignore them.
333+ . filter ( |segment| !segment. is_empty ( ) )
334+ // for each segment, find the child item
335+ . try_fold ( first, |item, segment| {
336+ let def_id = item. res . def_id ( ) ;
337+ if let Some ( item) = item_child_by_name ( tcx, def_id, segment) {
338+ Some ( item)
339+ } else if matches ! ( item. res, Res :: Def ( DefKind :: Enum | DefKind :: Struct , _) ) {
340+ // it is not a child item so check inherent impl items
341+ tcx. inherent_impls ( def_id)
342+ . iter ( )
343+ . find_map ( |& impl_def_id| item_child_by_name ( tcx, impl_def_id, segment) )
344+ } else {
345+ None
366346 }
367- }
368- } else {
369- None
370- }
347+ } ) ?;
348+ Some ( last. res )
371349}
372350
373351pub fn qpath_res ( cx : & LateContext < ' _ > , qpath : & hir:: QPath < ' _ > , id : hir:: HirId ) -> Res {
0 commit comments