@@ -21,9 +21,10 @@ pub fn find_path(
2121 item : ItemInNs ,
2222 from : ModuleId ,
2323 prefer_no_std : bool ,
24+ prefer_prelude : bool ,
2425) -> Option < ModPath > {
2526 let _p = profile:: span ( "find_path" ) ;
26- find_path_inner ( db, item, from, None , prefer_no_std)
27+ find_path_inner ( db, item, from, None , prefer_no_std, prefer_prelude )
2728}
2829
2930pub fn find_path_prefixed (
@@ -32,9 +33,10 @@ pub fn find_path_prefixed(
3233 from : ModuleId ,
3334 prefix_kind : PrefixKind ,
3435 prefer_no_std : bool ,
36+ prefer_prelude : bool ,
3537) -> Option < ModPath > {
3638 let _p = profile:: span ( "find_path_prefixed" ) ;
37- find_path_inner ( db, item, from, Some ( prefix_kind) , prefer_no_std)
39+ find_path_inner ( db, item, from, Some ( prefix_kind) , prefer_no_std, prefer_prelude )
3840}
3941
4042#[ derive( Copy , Clone , Debug ) ]
@@ -88,6 +90,7 @@ fn find_path_inner(
8890 from : ModuleId ,
8991 prefixed : Option < PrefixKind > ,
9092 prefer_no_std : bool ,
93+ prefer_prelude : bool ,
9194) -> Option < ModPath > {
9295 // - if the item is a builtin, it's in scope
9396 if let ItemInNs :: Types ( ModuleDefId :: BuiltinType ( builtin) ) = item {
@@ -109,6 +112,7 @@ fn find_path_inner(
109112 MAX_PATH_LEN ,
110113 prefixed,
111114 prefer_no_std || db. crate_supports_no_std ( crate_root. krate ) ,
115+ prefer_prelude,
112116 )
113117 . map ( |( item, _) | item) ;
114118 }
@@ -134,6 +138,7 @@ fn find_path_inner(
134138 from,
135139 prefixed,
136140 prefer_no_std,
141+ prefer_prelude,
137142 ) {
138143 let data = db. enum_data ( variant. parent ) ;
139144 path. push_segment ( data. variants [ variant. local_id ] . name . clone ( ) ) ;
@@ -156,6 +161,7 @@ fn find_path_inner(
156161 from,
157162 prefixed,
158163 prefer_no_std || db. crate_supports_no_std ( crate_root. krate ) ,
164+ prefer_prelude,
159165 scope_name,
160166 )
161167 . map ( |( item, _) | item)
@@ -171,6 +177,7 @@ fn find_path_for_module(
171177 max_len : usize ,
172178 prefixed : Option < PrefixKind > ,
173179 prefer_no_std : bool ,
180+ prefer_prelude : bool ,
174181) -> Option < ( ModPath , Stability ) > {
175182 if max_len == 0 {
176183 return None ;
@@ -236,6 +243,7 @@ fn find_path_for_module(
236243 from,
237244 prefixed,
238245 prefer_no_std,
246+ prefer_prelude,
239247 scope_name,
240248 )
241249}
@@ -316,6 +324,7 @@ fn calculate_best_path(
316324 from : ModuleId ,
317325 mut prefixed : Option < PrefixKind > ,
318326 prefer_no_std : bool ,
327+ prefer_prelude : bool ,
319328 scope_name : Option < Name > ,
320329) -> Option < ( ModPath , Stability ) > {
321330 if max_len <= 1 {
@@ -351,11 +360,14 @@ fn calculate_best_path(
351360 best_path_len - 1 ,
352361 prefixed,
353362 prefer_no_std,
363+ prefer_prelude,
354364 ) {
355365 path. 0 . push_segment ( name) ;
356366
357367 let new_path = match best_path. take ( ) {
358- Some ( best_path) => select_best_path ( best_path, path, prefer_no_std) ,
368+ Some ( best_path) => {
369+ select_best_path ( best_path, path, prefer_no_std, prefer_prelude)
370+ }
359371 None => path,
360372 } ;
361373 best_path_len = new_path. 0 . len ( ) ;
@@ -367,18 +379,18 @@ fn calculate_best_path(
367379 // too (unless we can't name it at all). It could *also* be (re)exported by the same crate
368380 // that wants to import it here, but we always prefer to use the external path here.
369381
370- let crate_graph = db. crate_graph ( ) ;
371- let extern_paths = crate_graph[ from. krate ] . dependencies . iter ( ) . filter_map ( |dep| {
382+ for dep in & db. crate_graph ( ) [ from. krate ] . dependencies {
372383 let import_map = db. import_map ( dep. crate_id ) ;
373- import_map. import_info_for ( item) . and_then ( |info| {
384+ let Some ( import_info_for) = import_map. import_info_for ( item) else { continue } ;
385+ for info in import_info_for {
374386 if info. is_doc_hidden {
375387 // the item or import is `#[doc(hidden)]`, so skip it as it is in an external crate
376- return None ;
388+ continue ;
377389 }
378390
379391 // Determine best path for containing module and append last segment from `info`.
380392 // FIXME: we should guide this to look up the path locally, or from the same crate again?
381- let ( mut path, path_stability) = find_path_for_module (
393+ let Some ( ( mut path, path_stability) ) = find_path_for_module (
382394 db,
383395 def_map,
384396 visited_modules,
@@ -388,22 +400,26 @@ fn calculate_best_path(
388400 max_len - 1 ,
389401 prefixed,
390402 prefer_no_std,
391- ) ?;
403+ prefer_prelude,
404+ ) else {
405+ continue ;
406+ } ;
392407 cov_mark:: hit!( partially_imported) ;
393408 path. push_segment ( info. name . clone ( ) ) ;
394- Some ( (
409+
410+ let path_with_stab = (
395411 path,
396412 zip_stability ( path_stability, if info. is_unstable { Unstable } else { Stable } ) ,
397- ) )
398- } )
399- } ) ;
413+ ) ;
400414
401- for path in extern_paths {
402- let new_path = match best_path. take ( ) {
403- Some ( best_path) => select_best_path ( best_path, path, prefer_no_std) ,
404- None => path,
405- } ;
406- update_best_path ( & mut best_path, new_path) ;
415+ let new_path_with_stab = match best_path. take ( ) {
416+ Some ( best_path) => {
417+ select_best_path ( best_path, path_with_stab, prefer_no_std, prefer_prelude)
418+ }
419+ None => path_with_stab,
420+ } ;
421+ update_best_path ( & mut best_path, new_path_with_stab) ;
422+ }
407423 }
408424 }
409425 if let Some ( module) = item. module ( db) {
@@ -420,17 +436,39 @@ fn calculate_best_path(
420436 }
421437}
422438
439+ /// Select the best (most relevant) path between two paths.
440+ /// This accounts for stability, path length whether std should be chosen over alloc/core paths as
441+ /// well as ignoring prelude like paths or not.
423442fn select_best_path (
424- old_path : ( ModPath , Stability ) ,
425- new_path : ( ModPath , Stability ) ,
443+ old_path @ ( _ , old_stability ) : ( ModPath , Stability ) ,
444+ new_path @ ( _ , new_stability ) : ( ModPath , Stability ) ,
426445 prefer_no_std : bool ,
446+ prefer_prelude : bool ,
427447) -> ( ModPath , Stability ) {
428- match ( old_path . 1 , new_path . 1 ) {
448+ match ( old_stability , new_stability ) {
429449 ( Stable , Unstable ) => return old_path,
430450 ( Unstable , Stable ) => return new_path,
431451 _ => { }
432452 }
433453 const STD_CRATES : [ Name ; 3 ] = [ known:: std, known:: core, known:: alloc] ;
454+
455+ let choose = |new_path : ( ModPath , _ ) , old_path : ( ModPath , _ ) | {
456+ let new_has_prelude = new_path. 0 . segments ( ) . iter ( ) . any ( |seg| seg == & known:: prelude) ;
457+ let old_has_prelude = old_path. 0 . segments ( ) . iter ( ) . any ( |seg| seg == & known:: prelude) ;
458+ match ( new_has_prelude, old_has_prelude, prefer_prelude) {
459+ ( true , false , true ) | ( false , true , false ) => new_path,
460+ ( true , false , false ) | ( false , true , true ) => old_path,
461+ // no prelude difference in the paths, so pick the smaller one
462+ ( true , true , _) | ( false , false , _) => {
463+ if new_path. 0 . len ( ) < old_path. 0 . len ( ) {
464+ new_path
465+ } else {
466+ old_path
467+ }
468+ }
469+ }
470+ } ;
471+
434472 match ( old_path. 0 . segments ( ) . first ( ) , new_path. 0 . segments ( ) . first ( ) ) {
435473 ( Some ( old) , Some ( new) ) if STD_CRATES . contains ( old) && STD_CRATES . contains ( new) => {
436474 let rank = match prefer_no_std {
@@ -451,23 +489,11 @@ fn select_best_path(
451489 let orank = rank ( old) ;
452490 match nrank. cmp ( & orank) {
453491 Ordering :: Less => old_path,
454- Ordering :: Equal => {
455- if new_path. 0 . len ( ) < old_path. 0 . len ( ) {
456- new_path
457- } else {
458- old_path
459- }
460- }
492+ Ordering :: Equal => choose ( new_path, old_path) ,
461493 Ordering :: Greater => new_path,
462494 }
463495 }
464- _ => {
465- if new_path. 0 . len ( ) < old_path. 0 . len ( ) {
466- new_path
467- } else {
468- old_path
469- }
470- }
496+ _ => choose ( new_path, old_path) ,
471497 }
472498}
473499
@@ -570,7 +596,13 @@ mod tests {
570596 /// `code` needs to contain a cursor marker; checks that `find_path` for the
571597 /// item the `path` refers to returns that same path when called from the
572598 /// module the cursor is in.
573- fn check_found_path_ ( ra_fixture : & str , path : & str , prefix_kind : Option < PrefixKind > ) {
599+ #[ track_caller]
600+ fn check_found_path_ (
601+ ra_fixture : & str ,
602+ path : & str ,
603+ prefix_kind : Option < PrefixKind > ,
604+ prefer_prelude : bool ,
605+ ) {
574606 let ( db, pos) = TestDB :: with_position ( ra_fixture) ;
575607 let module = db. module_at_position ( pos) ;
576608 let parsed_path_file = syntax:: SourceFile :: parse ( & format ! ( "use {path};" ) ) ;
@@ -589,11 +621,17 @@ mod tests {
589621 )
590622 . 0
591623 . take_types ( )
592- . unwrap ( ) ;
593-
594- let found_path =
595- find_path_inner ( & db, ItemInNs :: Types ( resolved) , module, prefix_kind, false ) ;
596- assert_eq ! ( found_path, Some ( mod_path) , "{prefix_kind:?}" ) ;
624+ . expect ( "path does not resolve to a type" ) ;
625+
626+ let found_path = find_path_inner (
627+ & db,
628+ ItemInNs :: Types ( resolved) ,
629+ module,
630+ prefix_kind,
631+ false ,
632+ prefer_prelude,
633+ ) ;
634+ assert_eq ! ( found_path, Some ( mod_path) , "on kind: {prefix_kind:?}" ) ;
597635 }
598636
599637 fn check_found_path (
@@ -603,10 +641,23 @@ mod tests {
603641 absolute : & str ,
604642 self_prefixed : & str ,
605643 ) {
606- check_found_path_ ( ra_fixture, unprefixed, None ) ;
607- check_found_path_ ( ra_fixture, prefixed, Some ( PrefixKind :: Plain ) ) ;
608- check_found_path_ ( ra_fixture, absolute, Some ( PrefixKind :: ByCrate ) ) ;
609- check_found_path_ ( ra_fixture, self_prefixed, Some ( PrefixKind :: BySelf ) ) ;
644+ check_found_path_ ( ra_fixture, unprefixed, None , false ) ;
645+ check_found_path_ ( ra_fixture, prefixed, Some ( PrefixKind :: Plain ) , false ) ;
646+ check_found_path_ ( ra_fixture, absolute, Some ( PrefixKind :: ByCrate ) , false ) ;
647+ check_found_path_ ( ra_fixture, self_prefixed, Some ( PrefixKind :: BySelf ) , false ) ;
648+ }
649+
650+ fn check_found_path_prelude (
651+ ra_fixture : & str ,
652+ unprefixed : & str ,
653+ prefixed : & str ,
654+ absolute : & str ,
655+ self_prefixed : & str ,
656+ ) {
657+ check_found_path_ ( ra_fixture, unprefixed, None , true ) ;
658+ check_found_path_ ( ra_fixture, prefixed, Some ( PrefixKind :: Plain ) , true ) ;
659+ check_found_path_ ( ra_fixture, absolute, Some ( PrefixKind :: ByCrate ) , true ) ;
660+ check_found_path_ ( ra_fixture, self_prefixed, Some ( PrefixKind :: BySelf ) , true ) ;
610661 }
611662
612663 #[ test]
@@ -1421,4 +1472,34 @@ pub mod error {
14211472 "std::error::Error" ,
14221473 ) ;
14231474 }
1475+
1476+ #[ test]
1477+ fn respects_prelude_setting ( ) {
1478+ let ra_fixture = r#"
1479+ //- /main.rs crate:main deps:krate
1480+ $0
1481+ //- /krate.rs crate:krate
1482+ pub mod prelude {
1483+ pub use crate::foo::*;
1484+ }
1485+
1486+ pub mod foo {
1487+ pub struct Foo;
1488+ }
1489+ "# ;
1490+ check_found_path (
1491+ ra_fixture,
1492+ "krate::foo::Foo" ,
1493+ "krate::foo::Foo" ,
1494+ "krate::foo::Foo" ,
1495+ "krate::foo::Foo" ,
1496+ ) ;
1497+ check_found_path_prelude (
1498+ ra_fixture,
1499+ "krate::prelude::Foo" ,
1500+ "krate::prelude::Foo" ,
1501+ "krate::prelude::Foo" ,
1502+ "krate::prelude::Foo" ,
1503+ ) ;
1504+ }
14241505}
0 commit comments