11//! An algorithm to find a path to refer to a certain item.
22
3- use std:: { cell:: Cell , cmp:: Ordering , iter} ;
3+ use std:: { cell:: Cell , cmp:: Ordering , iter, ops :: BitOr } ;
44
5+ use base_db:: CrateId ;
56use hir_expand:: {
67 name:: { AsName , Name } ,
78 Lookup ,
@@ -37,7 +38,8 @@ pub fn find_path(
3738
3839 // within block modules, forcing a `self` or `crate` prefix will not allow using inner items, so
3940 // default to plain paths.
40- if item. module ( db) . is_some_and ( ModuleId :: is_within_block) {
41+ let item_module = item. module ( db) ?;
42+ if item_module. is_within_block ( ) {
4143 prefix_kind = PrefixKind :: Plain ;
4244 }
4345 cfg. prefer_no_std = cfg. prefer_no_std || db. crate_supports_no_std ( from. krate ( ) ) ;
@@ -50,6 +52,7 @@ pub fn find_path(
5052 ignore_local_imports,
5153 from,
5254 from_def_map : & from. def_map ( db) ,
55+ is_std_item : db. crate_graph ( ) [ item_module. krate ( ) ] . origin . is_lang ( ) ,
5356 fuel : Cell :: new ( FIND_PATH_FUEL ) ,
5457 } ,
5558 item,
@@ -104,6 +107,7 @@ struct FindPathCtx<'db> {
104107 ignore_local_imports : bool ,
105108 from : ModuleId ,
106109 from_def_map : & ' db DefMap ,
110+ is_std_item : bool ,
107111 fuel : Cell < usize > ,
108112}
109113
@@ -373,9 +377,12 @@ fn calculate_best_path(
373377 // too (unless we can't name it at all). It could *also* be (re)exported by the same crate
374378 // that wants to import it here, but we always prefer to use the external path here.
375379
376- for dep in & db. crate_graph ( ) [ ctx. from . krate ] . dependencies {
377- let import_map = db. import_map ( dep. crate_id ) ;
378- let Some ( import_info_for) = import_map. import_info_for ( item) else { continue } ;
380+ let mut process_dep = |dep : CrateId | {
381+ let import_map = db. import_map ( dep) ;
382+ let Some ( import_info_for) = import_map. import_info_for ( item) else {
383+ return false ;
384+ } ;
385+ let mut processed_something = false ;
379386 for info in import_info_for {
380387 if info. is_doc_hidden {
381388 // the item or import is `#[doc(hidden)]`, so skip it as it is in an external crate
@@ -396,8 +403,33 @@ fn calculate_best_path(
396403 ) ;
397404
398405 process ( path, info. name . clone ( ) , & mut best_path_len) ;
406+ processed_something = true ;
407+ }
408+ processed_something
409+ } ;
410+
411+ let dependencies = & db. crate_graph ( ) [ ctx. from . krate ] . dependencies ;
412+ if ctx. is_std_item {
413+ // The item we are searching for comes from the sysroot libraries, so skip prefer looking in
414+ // the sysroot libraries directly.
415+ // We do need to fallback as the item in question could be re-exported by another crate
416+ // while not being a transitive dependency of the current crate.
417+ let processed = dependencies
418+ . iter ( )
419+ . filter ( |it| it. is_sysroot ( ) )
420+ . map ( |dep| process_dep ( dep. crate_id ) )
421+ . reduce ( BitOr :: bitor)
422+ . unwrap_or ( false ) ;
423+ if processed {
424+ // Found a path in a sysroot crate, so return it.
425+ return best_path;
399426 }
400427 }
428+
429+ dependencies
430+ . iter ( )
431+ . filter ( |it| !ctx. is_std_item || !it. is_sysroot ( ) )
432+ . for_each ( |dep| _ = process_dep ( dep. crate_id ) ) ;
401433 }
402434 best_path
403435}
@@ -1918,4 +1950,34 @@ pub fn c() {}
19181950 "# ] ] ,
19191951 ) ;
19201952 }
1953+
1954+ #[ test]
1955+ fn prefer_long_std_over_short_extern ( ) {
1956+ check_found_path (
1957+ r#"
1958+ //- /lib.rs crate:main deps:futures_lite,std,core
1959+ $0
1960+ //- /futures_lite.rs crate:futures_lite deps:std,core
1961+ pub use crate::future::Future;
1962+ pub mod future {
1963+ pub use core::future::Future;
1964+ }
1965+ //- /std.rs crate:std deps:core
1966+ pub use core::future;
1967+ //- /core.rs crate:core
1968+ pub mod future {
1969+ pub trait Future {}
1970+ }
1971+ "# ,
1972+ "core::future::Future" ,
1973+ expect ! [ [ r#"
1974+ Plain (imports ✔): std::future::Future
1975+ Plain (imports ✖): std::future::Future
1976+ ByCrate(imports ✔): std::future::Future
1977+ ByCrate(imports ✖): std::future::Future
1978+ BySelf (imports ✔): std::future::Future
1979+ BySelf (imports ✖): std::future::Future
1980+ "# ] ] ,
1981+ ) ;
1982+ }
19211983}
0 commit comments