@@ -21,9 +21,10 @@ pub fn find_path(
21
21
item : ItemInNs ,
22
22
from : ModuleId ,
23
23
prefer_no_std : bool ,
24
+ prefer_prelude : bool ,
24
25
) -> Option < ModPath > {
25
26
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 )
27
28
}
28
29
29
30
pub fn find_path_prefixed (
@@ -32,9 +33,10 @@ pub fn find_path_prefixed(
32
33
from : ModuleId ,
33
34
prefix_kind : PrefixKind ,
34
35
prefer_no_std : bool ,
36
+ prefer_prelude : bool ,
35
37
) -> Option < ModPath > {
36
38
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 )
38
40
}
39
41
40
42
#[ derive( Copy , Clone , Debug ) ]
@@ -88,6 +90,7 @@ fn find_path_inner(
88
90
from : ModuleId ,
89
91
prefixed : Option < PrefixKind > ,
90
92
prefer_no_std : bool ,
93
+ prefer_prelude : bool ,
91
94
) -> Option < ModPath > {
92
95
// - if the item is a builtin, it's in scope
93
96
if let ItemInNs :: Types ( ModuleDefId :: BuiltinType ( builtin) ) = item {
@@ -109,6 +112,7 @@ fn find_path_inner(
109
112
MAX_PATH_LEN ,
110
113
prefixed,
111
114
prefer_no_std || db. crate_supports_no_std ( crate_root. krate ) ,
115
+ prefer_prelude,
112
116
)
113
117
. map ( |( item, _) | item) ;
114
118
}
@@ -134,6 +138,7 @@ fn find_path_inner(
134
138
from,
135
139
prefixed,
136
140
prefer_no_std,
141
+ prefer_prelude,
137
142
) {
138
143
let data = db. enum_data ( variant. parent ) ;
139
144
path. push_segment ( data. variants [ variant. local_id ] . name . clone ( ) ) ;
@@ -156,6 +161,7 @@ fn find_path_inner(
156
161
from,
157
162
prefixed,
158
163
prefer_no_std || db. crate_supports_no_std ( crate_root. krate ) ,
164
+ prefer_prelude,
159
165
scope_name,
160
166
)
161
167
. map ( |( item, _) | item)
@@ -171,6 +177,7 @@ fn find_path_for_module(
171
177
max_len : usize ,
172
178
prefixed : Option < PrefixKind > ,
173
179
prefer_no_std : bool ,
180
+ prefer_prelude : bool ,
174
181
) -> Option < ( ModPath , Stability ) > {
175
182
if max_len == 0 {
176
183
return None ;
@@ -236,6 +243,7 @@ fn find_path_for_module(
236
243
from,
237
244
prefixed,
238
245
prefer_no_std,
246
+ prefer_prelude,
239
247
scope_name,
240
248
)
241
249
}
@@ -316,6 +324,7 @@ fn calculate_best_path(
316
324
from : ModuleId ,
317
325
mut prefixed : Option < PrefixKind > ,
318
326
prefer_no_std : bool ,
327
+ prefer_prelude : bool ,
319
328
scope_name : Option < Name > ,
320
329
) -> Option < ( ModPath , Stability ) > {
321
330
if max_len <= 1 {
@@ -351,11 +360,14 @@ fn calculate_best_path(
351
360
best_path_len - 1 ,
352
361
prefixed,
353
362
prefer_no_std,
363
+ prefer_prelude,
354
364
) {
355
365
path. 0 . push_segment ( name) ;
356
366
357
367
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
+ }
359
371
None => path,
360
372
} ;
361
373
best_path_len = new_path. 0 . len ( ) ;
@@ -367,18 +379,18 @@ fn calculate_best_path(
367
379
// too (unless we can't name it at all). It could *also* be (re)exported by the same crate
368
380
// that wants to import it here, but we always prefer to use the external path here.
369
381
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 {
372
383
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 {
374
386
if info. is_doc_hidden {
375
387
// the item or import is `#[doc(hidden)]`, so skip it as it is in an external crate
376
- return None ;
388
+ continue ;
377
389
}
378
390
379
391
// Determine best path for containing module and append last segment from `info`.
380
392
// 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 (
382
394
db,
383
395
def_map,
384
396
visited_modules,
@@ -388,22 +400,26 @@ fn calculate_best_path(
388
400
max_len - 1 ,
389
401
prefixed,
390
402
prefer_no_std,
391
- ) ?;
403
+ prefer_prelude,
404
+ ) else {
405
+ continue ;
406
+ } ;
392
407
cov_mark:: hit!( partially_imported) ;
393
408
path. push_segment ( info. name . clone ( ) ) ;
394
- Some ( (
409
+
410
+ let path_with_stab = (
395
411
path,
396
412
zip_stability ( path_stability, if info. is_unstable { Unstable } else { Stable } ) ,
397
- ) )
398
- } )
399
- } ) ;
413
+ ) ;
400
414
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
+ }
407
423
}
408
424
}
409
425
if let Some ( module) = item. module ( db) {
@@ -420,17 +436,39 @@ fn calculate_best_path(
420
436
}
421
437
}
422
438
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.
423
442
fn 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 ) ,
426
445
prefer_no_std : bool ,
446
+ prefer_prelude : bool ,
427
447
) -> ( ModPath , Stability ) {
428
- match ( old_path . 1 , new_path . 1 ) {
448
+ match ( old_stability , new_stability ) {
429
449
( Stable , Unstable ) => return old_path,
430
450
( Unstable , Stable ) => return new_path,
431
451
_ => { }
432
452
}
433
453
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
+
434
472
match ( old_path. 0 . segments ( ) . first ( ) , new_path. 0 . segments ( ) . first ( ) ) {
435
473
( Some ( old) , Some ( new) ) if STD_CRATES . contains ( old) && STD_CRATES . contains ( new) => {
436
474
let rank = match prefer_no_std {
@@ -451,23 +489,11 @@ fn select_best_path(
451
489
let orank = rank ( old) ;
452
490
match nrank. cmp ( & orank) {
453
491
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) ,
461
493
Ordering :: Greater => new_path,
462
494
}
463
495
}
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) ,
471
497
}
472
498
}
473
499
@@ -570,7 +596,13 @@ mod tests {
570
596
/// `code` needs to contain a cursor marker; checks that `find_path` for the
571
597
/// item the `path` refers to returns that same path when called from the
572
598
/// 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
+ ) {
574
606
let ( db, pos) = TestDB :: with_position ( ra_fixture) ;
575
607
let module = db. module_at_position ( pos) ;
576
608
let parsed_path_file = syntax:: SourceFile :: parse ( & format ! ( "use {path};" ) ) ;
@@ -589,11 +621,17 @@ mod tests {
589
621
)
590
622
. 0
591
623
. 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:?}" ) ;
597
635
}
598
636
599
637
fn check_found_path (
@@ -603,10 +641,23 @@ mod tests {
603
641
absolute : & str ,
604
642
self_prefixed : & str ,
605
643
) {
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 ) ;
610
661
}
611
662
612
663
#[ test]
@@ -1421,4 +1472,34 @@ pub mod error {
1421
1472
"std::error::Error" ,
1422
1473
) ;
1423
1474
}
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
+ }
1424
1505
}
0 commit comments