@@ -31,7 +31,6 @@ pub use self::hir_utils::{both, eq_expr_value, over, SpanlessEq, SpanlessHash};
31
31
use std:: borrow:: Cow ;
32
32
use std:: collections:: hash_map:: Entry ;
33
33
use std:: hash:: BuildHasherDefault ;
34
- use std:: mem;
35
34
36
35
use if_chain:: if_chain;
37
36
use rustc_ast:: ast:: { self , Attribute , LitKind } ;
@@ -40,7 +39,7 @@ use rustc_data_structures::fx::FxHashMap;
40
39
use rustc_errors:: Applicability ;
41
40
use rustc_hir as hir;
42
41
use 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 } ;
44
43
use rustc_hir:: intravisit:: { self , NestedVisitorMap , Visitor } ;
45
44
use rustc_hir:: Node ;
46
45
use rustc_hir:: {
@@ -49,6 +48,7 @@ use rustc_hir::{
49
48
} ;
50
49
use rustc_infer:: infer:: TyCtxtInferExt ;
51
50
use rustc_lint:: { LateContext , Level , Lint , LintContext } ;
51
+ use rustc_middle:: hir:: exports:: Export ;
52
52
use rustc_middle:: hir:: map:: Map ;
53
53
use rustc_middle:: ty:: subst:: { GenericArg , GenericArgKind } ;
54
54
use rustc_middle:: ty:: { self , layout:: IntegerExt , Ty , TyCtxt , TypeFoldable } ;
@@ -309,65 +309,43 @@ pub fn match_path_ast(path: &ast::Path, segments: &[&str]) -> bool {
309
309
}
310
310
311
311
/// 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
+ }
350
319
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
366
346
}
367
- }
368
- } else {
369
- None
370
- }
347
+ } ) ?;
348
+ Some ( last. res )
371
349
}
372
350
373
351
pub fn qpath_res ( cx : & LateContext < ' _ > , qpath : & hir:: QPath < ' _ > , id : hir:: HirId ) -> Res {
0 commit comments