@@ -7,10 +7,39 @@ use crate::{
7
7
visibility:: Visibility ,
8
8
CrateId , ModuleDefId , ModuleId ,
9
9
} ;
10
- use hir_expand:: name:: Name ;
10
+ use hir_expand:: name:: { known, Name } ;
11
+ use test_utils:: tested_by;
11
12
12
13
const MAX_PATH_LEN : usize = 15 ;
13
14
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
+
14
43
// FIXME: handle local items
15
44
16
45
/// 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(
112
141
Some ( path) => path,
113
142
} ;
114
143
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) ;
119
149
}
120
150
best_path
121
151
}
122
152
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
+ }
132
165
}
133
166
134
167
fn find_importable_locations (
@@ -201,6 +234,7 @@ mod tests {
201
234
use hir_expand:: hygiene:: Hygiene ;
202
235
use ra_db:: fixture:: WithFixture ;
203
236
use ra_syntax:: ast:: AstNode ;
237
+ use test_utils:: covers;
204
238
205
239
/// `code` needs to contain a cursor marker; checks that `find_path` for the
206
240
/// item the `path` refers to returns that same path when called from the
@@ -452,4 +486,41 @@ mod tests {
452
486
"# ;
453
487
check_found_path ( code, "crate::foo::S" ) ;
454
488
}
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
+ }
455
526
}
0 commit comments