@@ -7,10 +7,39 @@ use crate::{
77 visibility:: Visibility ,
88 CrateId , ModuleDefId , ModuleId ,
99} ;
10- use hir_expand:: name:: Name ;
10+ use hir_expand:: name:: { known, Name } ;
11+ use test_utils:: tested_by;
1112
1213const MAX_PATH_LEN : usize = 15 ;
1314
15+ impl ModPath {
16+ fn starts_with_std ( & self ) -> bool {
17+ self . segments . first ( ) . filter ( |& first_segment| first_segment == & known:: std) . is_some ( )
18+ }
19+
20+ // When std library is present, paths starting with `std::`
21+ // should be preferred over paths starting with `core::` and `alloc::`
22+ fn should_start_with_std ( & self ) -> bool {
23+ self . segments
24+ . first ( )
25+ . filter ( |& first_segment| {
26+ first_segment == & known:: alloc || first_segment == & known:: core
27+ } )
28+ . is_some ( )
29+ }
30+
31+ fn len ( & self ) -> usize {
32+ self . segments . len ( )
33+ + match self . kind {
34+ PathKind :: Plain => 0 ,
35+ PathKind :: Super ( i) => i as usize ,
36+ PathKind :: Crate => 1 ,
37+ PathKind :: Abs => 0 ,
38+ PathKind :: DollarCrate ( _) => 1 ,
39+ }
40+ }
41+ }
42+
1443// FIXME: handle local items
1544
1645/// Find a path that can be used to refer to a certain item. This can depend on
@@ -112,23 +141,27 @@ fn find_path_inner(
112141 Some ( path) => path,
113142 } ;
114143 path. segments . push ( name) ;
115- if path_len ( & path) < best_path_len {
116- best_path_len = path_len ( & path) ;
117- best_path = Some ( path) ;
118- }
144+
145+ let new_path =
146+ if let Some ( best_path) = best_path { select_best_path ( best_path, path) } else { path } ;
147+ best_path_len = new_path. len ( ) ;
148+ best_path = Some ( new_path) ;
119149 }
120150 best_path
121151}
122152
123- fn path_len ( path : & ModPath ) -> usize {
124- path. segments . len ( )
125- + match path. kind {
126- PathKind :: Plain => 0 ,
127- PathKind :: Super ( i) => i as usize ,
128- PathKind :: Crate => 1 ,
129- PathKind :: Abs => 0 ,
130- PathKind :: DollarCrate ( _) => 1 ,
131- }
153+ fn select_best_path ( old_path : ModPath , new_path : ModPath ) -> ModPath {
154+ if old_path. starts_with_std ( ) && new_path. should_start_with_std ( ) {
155+ tested_by ! ( prefer_std_paths) ;
156+ old_path
157+ } else if new_path. starts_with_std ( ) && old_path. should_start_with_std ( ) {
158+ tested_by ! ( prefer_std_paths) ;
159+ new_path
160+ } else if new_path. len ( ) < old_path. len ( ) {
161+ new_path
162+ } else {
163+ old_path
164+ }
132165}
133166
134167fn find_importable_locations (
@@ -201,6 +234,7 @@ mod tests {
201234 use hir_expand:: hygiene:: Hygiene ;
202235 use ra_db:: fixture:: WithFixture ;
203236 use ra_syntax:: ast:: AstNode ;
237+ use test_utils:: covers;
204238
205239 /// `code` needs to contain a cursor marker; checks that `find_path` for the
206240 /// item the `path` refers to returns that same path when called from the
@@ -452,4 +486,41 @@ mod tests {
452486 "# ;
453487 check_found_path ( code, "crate::foo::S" ) ;
454488 }
489+
490+ #[ test]
491+ fn prefer_std_paths_over_alloc ( ) {
492+ covers ! ( prefer_std_paths) ;
493+ let code = r#"
494+ //- /main.rs crate:main deps:alloc,std
495+ <|>
496+
497+ //- /std.rs crate:std deps:alloc
498+ pub mod sync {
499+ pub use alloc::sync::Arc;
500+ }
501+
502+ //- /zzz.rs crate:alloc
503+ pub mod sync {
504+ pub struct Arc;
505+ }
506+ "# ;
507+ check_found_path ( code, "std::sync::Arc" ) ;
508+ }
509+
510+ #[ test]
511+ fn prefer_shorter_paths_if_not_alloc ( ) {
512+ let code = r#"
513+ //- /main.rs crate:main deps:megaalloc,std
514+ <|>
515+
516+ //- /std.rs crate:std deps:megaalloc
517+ pub mod sync {
518+ pub use megaalloc::sync::Arc;
519+ }
520+
521+ //- /zzz.rs crate:megaalloc
522+ pub struct Arc;
523+ "# ;
524+ check_found_path ( code, "megaalloc::Arc" ) ;
525+ }
455526}
0 commit comments