@@ -4,6 +4,7 @@ use std::collections::{BTreeMap, VecDeque};
4
4
use rustc_data_structures:: fx:: { FxHashMap , FxIndexMap } ;
5
5
use rustc_middle:: ty:: TyCtxt ;
6
6
use rustc_span:: def_id:: DefId ;
7
+ use rustc_span:: sym;
7
8
use rustc_span:: symbol:: Symbol ;
8
9
use serde:: ser:: { Serialize , SerializeSeq , SerializeStruct , Serializer } ;
9
10
use thin_vec:: ThinVec ;
@@ -22,10 +23,13 @@ pub(crate) fn build_index<'tcx>(
22
23
cache : & mut Cache ,
23
24
tcx : TyCtxt < ' tcx > ,
24
25
) -> String {
26
+ // Maps from ID to position in the `crate_paths` array.
25
27
let mut itemid_to_pathid = FxHashMap :: default ( ) ;
26
28
let mut primitives = FxHashMap :: default ( ) ;
27
29
let mut associated_types = FxHashMap :: default ( ) ;
28
- let mut crate_paths = vec ! [ ] ;
30
+
31
+ // item type, display path, re-exported internal path
32
+ let mut crate_paths: Vec < ( ItemType , Vec < Symbol > , Option < Vec < Symbol > > ) > = vec ! [ ] ;
29
33
30
34
// Attach all orphan items to the type's definition if the type
31
35
// has since been learned.
@@ -35,11 +39,13 @@ pub(crate) fn build_index<'tcx>(
35
39
let desc = short_markdown_summary ( & item. doc_value ( ) , & item. link_names ( cache) ) ;
36
40
cache. search_index . push ( IndexItem {
37
41
ty : item. type_ ( ) ,
42
+ defid : item. item_id . as_def_id ( ) ,
38
43
name : item. name . unwrap ( ) ,
39
44
path : join_with_double_colon ( & fqp[ ..fqp. len ( ) - 1 ] ) ,
40
45
desc,
41
46
parent : Some ( parent) ,
42
47
parent_idx : None ,
48
+ exact_path : None ,
43
49
impl_id,
44
50
search_type : get_function_type_for_search (
45
51
item,
@@ -88,17 +94,22 @@ pub(crate) fn build_index<'tcx>(
88
94
map : & mut FxHashMap < F , isize > ,
89
95
itemid : F ,
90
96
lastpathid : & mut isize ,
91
- crate_paths : & mut Vec < ( ItemType , Vec < Symbol > ) > ,
97
+ crate_paths : & mut Vec < ( ItemType , Vec < Symbol > , Option < Vec < Symbol > > ) > ,
92
98
item_type : ItemType ,
93
99
path : & [ Symbol ] ,
100
+ exact_path : Option < & [ Symbol ] > ,
94
101
) -> RenderTypeId {
95
102
match map. entry ( itemid) {
96
103
Entry :: Occupied ( entry) => RenderTypeId :: Index ( * entry. get ( ) ) ,
97
104
Entry :: Vacant ( entry) => {
98
105
let pathid = * lastpathid;
99
106
entry. insert ( pathid) ;
100
107
* lastpathid += 1 ;
101
- crate_paths. push ( ( item_type, path. to_vec ( ) ) ) ;
108
+ crate_paths. push ( (
109
+ item_type,
110
+ path. to_vec ( ) ,
111
+ exact_path. map ( |path| path. to_vec ( ) ) ,
112
+ ) ) ;
102
113
RenderTypeId :: Index ( pathid)
103
114
}
104
115
}
@@ -111,21 +122,30 @@ pub(crate) fn build_index<'tcx>(
111
122
primitives : & mut FxHashMap < Symbol , isize > ,
112
123
associated_types : & mut FxHashMap < Symbol , isize > ,
113
124
lastpathid : & mut isize ,
114
- crate_paths : & mut Vec < ( ItemType , Vec < Symbol > ) > ,
125
+ crate_paths : & mut Vec < ( ItemType , Vec < Symbol > , Option < Vec < Symbol > > ) > ,
115
126
) -> Option < RenderTypeId > {
116
- let Cache { ref paths, ref external_paths, .. } = * cache;
127
+ let Cache { ref paths, ref external_paths, ref exact_paths , .. } = * cache;
117
128
match id {
118
129
RenderTypeId :: DefId ( defid) => {
119
130
if let Some ( & ( ref fqp, item_type) ) =
120
131
paths. get ( & defid) . or_else ( || external_paths. get ( & defid) )
121
132
{
133
+ let exact_fqp = exact_paths
134
+ . get ( & defid)
135
+ . or_else ( || external_paths. get ( & defid) . map ( |& ( ref fqp, _) | fqp) )
136
+ // re-exports only count if the name is exactly the same
137
+ // this is a size optimization, as well as a DWIM attempt
138
+ // since if the names are not the same, the intent probably
139
+ // isn't, either
140
+ . filter ( |fqp| fqp. last ( ) == fqp. last ( ) ) ;
122
141
Some ( insert_into_map (
123
142
itemid_to_pathid,
124
143
ItemId :: DefId ( defid) ,
125
144
lastpathid,
126
145
crate_paths,
127
146
item_type,
128
147
fqp,
148
+ exact_fqp. map ( |x| & x[ ..] ) . filter ( |exact_fqp| exact_fqp != fqp) ,
129
149
) )
130
150
} else {
131
151
None
@@ -140,6 +160,7 @@ pub(crate) fn build_index<'tcx>(
140
160
crate_paths,
141
161
ItemType :: Primitive ,
142
162
& [ sym] ,
163
+ None ,
143
164
) )
144
165
}
145
166
RenderTypeId :: Index ( _) => Some ( id) ,
@@ -150,6 +171,7 @@ pub(crate) fn build_index<'tcx>(
150
171
crate_paths,
151
172
ItemType :: AssocType ,
152
173
& [ sym] ,
174
+ None ,
153
175
) ) ,
154
176
}
155
177
}
@@ -161,7 +183,7 @@ pub(crate) fn build_index<'tcx>(
161
183
primitives : & mut FxHashMap < Symbol , isize > ,
162
184
associated_types : & mut FxHashMap < Symbol , isize > ,
163
185
lastpathid : & mut isize ,
164
- crate_paths : & mut Vec < ( ItemType , Vec < Symbol > ) > ,
186
+ crate_paths : & mut Vec < ( ItemType , Vec < Symbol > , Option < Vec < Symbol > > ) > ,
165
187
) {
166
188
if let Some ( generics) = & mut ty. generics {
167
189
for item in generics {
@@ -258,7 +280,7 @@ pub(crate) fn build_index<'tcx>(
258
280
}
259
281
}
260
282
261
- let Cache { ref paths, .. } = * cache;
283
+ let Cache { ref paths, ref exact_paths , ref external_paths , .. } = * cache;
262
284
263
285
// Then, on parent modules
264
286
let crate_items: Vec < & IndexItem > = search_index
@@ -273,14 +295,54 @@ pub(crate) fn build_index<'tcx>(
273
295
lastpathid += 1 ;
274
296
275
297
if let Some ( & ( ref fqp, short) ) = paths. get ( & defid) {
276
- crate_paths. push ( ( short, fqp. clone ( ) ) ) ;
298
+ let exact_fqp = exact_paths
299
+ . get ( & defid)
300
+ . or_else ( || external_paths. get ( & defid) . map ( |& ( ref fqp, _) | fqp) )
301
+ . filter ( |exact_fqp| {
302
+ exact_fqp. last ( ) == Some ( & item. name ) && * exact_fqp != fqp
303
+ } ) ;
304
+ crate_paths. push ( ( short, fqp. clone ( ) , exact_fqp. cloned ( ) ) ) ;
277
305
Some ( pathid)
278
306
} else {
279
307
None
280
308
}
281
309
}
282
310
} ) ;
283
311
312
+ if let Some ( defid) = item. defid
313
+ && item. parent_idx . is_none ( )
314
+ {
315
+ // If this is a re-export, retain the original path.
316
+ // Associated items don't use this.
317
+ // Their parent carries the exact fqp instead.
318
+ let exact_fqp = exact_paths
319
+ . get ( & defid)
320
+ . or_else ( || external_paths. get ( & defid) . map ( |& ( ref fqp, _) | fqp) ) ;
321
+ item. exact_path = exact_fqp. and_then ( |fqp| {
322
+ // re-exports only count if the name is exactly the same
323
+ // this is a size optimization, as well as a DWIM attempt
324
+ // since if the names are not the same, the intent probably
325
+ // isn't, either
326
+ if fqp. last ( ) != Some ( & item. name ) {
327
+ return None ;
328
+ }
329
+ let path =
330
+ if item. ty == ItemType :: Macro && tcx. has_attr ( defid, sym:: macro_export) {
331
+ // `#[macro_export]` always exports to the crate root.
332
+ tcx. crate_name ( defid. krate ) . to_string ( )
333
+ } else {
334
+ if fqp. len ( ) < 2 {
335
+ return None ;
336
+ }
337
+ join_with_double_colon ( & fqp[ ..fqp. len ( ) - 1 ] )
338
+ } ;
339
+ if path == item. path {
340
+ return None ;
341
+ }
342
+ Some ( path)
343
+ } ) ;
344
+ }
345
+
284
346
// Omit the parent path if it is same to that of the prior item.
285
347
if lastpath == & item. path {
286
348
item. path . clear ( ) ;
@@ -319,7 +381,7 @@ pub(crate) fn build_index<'tcx>(
319
381
struct CrateData < ' a > {
320
382
doc : String ,
321
383
items : Vec < & ' a IndexItem > ,
322
- paths : Vec < ( ItemType , Vec < Symbol > ) > ,
384
+ paths : Vec < ( ItemType , Vec < Symbol > , Option < Vec < Symbol > > ) > ,
323
385
// The String is alias name and the vec is the list of the elements with this alias.
324
386
//
325
387
// To be noted: the `usize` elements are indexes to `items`.
@@ -332,6 +394,7 @@ pub(crate) fn build_index<'tcx>(
332
394
ty : ItemType ,
333
395
name : Symbol ,
334
396
path : Option < usize > ,
397
+ exact_path : Option < usize > ,
335
398
}
336
399
337
400
impl Serialize for Paths {
@@ -345,6 +408,10 @@ pub(crate) fn build_index<'tcx>(
345
408
if let Some ( ref path) = self . path {
346
409
seq. serialize_element ( path) ?;
347
410
}
411
+ if let Some ( ref path) = self . exact_path {
412
+ assert ! ( self . path. is_some( ) ) ;
413
+ seq. serialize_element ( path) ?;
414
+ }
348
415
seq. end ( )
349
416
}
350
417
}
@@ -367,43 +434,94 @@ pub(crate) fn build_index<'tcx>(
367
434
mod_paths. insert ( & item. path , index) ;
368
435
}
369
436
let mut paths = Vec :: with_capacity ( self . paths . len ( ) ) ;
370
- for ( ty, path) in & self . paths {
437
+ for ( ty, path, exact ) in & self . paths {
371
438
if path. len ( ) < 2 {
372
- paths. push ( Paths { ty : * ty, name : path[ 0 ] , path : None } ) ;
439
+ paths. push ( Paths { ty : * ty, name : path[ 0 ] , path : None , exact_path : None } ) ;
373
440
continue ;
374
441
}
375
442
let full_path = join_with_double_colon ( & path[ ..path. len ( ) - 1 ] ) ;
443
+ let full_exact_path = exact
444
+ . as_ref ( )
445
+ . filter ( |exact| exact. last ( ) == path. last ( ) && exact. len ( ) >= 2 )
446
+ . map ( |exact| join_with_double_colon ( & exact[ ..exact. len ( ) - 1 ] ) ) ;
447
+ let exact_path = extra_paths. len ( ) + self . items . len ( ) ;
448
+ let exact_path = full_exact_path. as_ref ( ) . map ( |full_exact_path| match extra_paths
449
+ . entry ( full_exact_path. clone ( ) )
450
+ {
451
+ Entry :: Occupied ( entry) => * entry. get ( ) ,
452
+ Entry :: Vacant ( entry) => {
453
+ if let Some ( index) = mod_paths. get ( & full_exact_path) {
454
+ return * index;
455
+ }
456
+ entry. insert ( exact_path) ;
457
+ if !revert_extra_paths. contains_key ( & exact_path) {
458
+ revert_extra_paths. insert ( exact_path, full_exact_path. clone ( ) ) ;
459
+ }
460
+ exact_path
461
+ }
462
+ } ) ;
376
463
if let Some ( index) = mod_paths. get ( & full_path) {
377
- paths. push ( Paths { ty : * ty, name : * path. last ( ) . unwrap ( ) , path : Some ( * index) } ) ;
464
+ paths. push ( Paths {
465
+ ty : * ty,
466
+ name : * path. last ( ) . unwrap ( ) ,
467
+ path : Some ( * index) ,
468
+ exact_path,
469
+ } ) ;
378
470
continue ;
379
471
}
380
472
// It means it comes from an external crate so the item and its path will be
381
473
// stored into another array.
382
474
//
383
475
// `index` is put after the last `mod_paths`
384
476
let index = extra_paths. len ( ) + self . items . len ( ) ;
385
- if !revert_extra_paths. contains_key ( & index) {
386
- revert_extra_paths. insert ( index, full_path. clone ( ) ) ;
387
- }
388
- match extra_paths. entry ( full_path) {
477
+ match extra_paths. entry ( full_path. clone ( ) ) {
389
478
Entry :: Occupied ( entry) => {
390
479
paths. push ( Paths {
391
480
ty : * ty,
392
481
name : * path. last ( ) . unwrap ( ) ,
393
482
path : Some ( * entry. get ( ) ) ,
483
+ exact_path,
394
484
} ) ;
395
485
}
396
486
Entry :: Vacant ( entry) => {
397
487
entry. insert ( index) ;
488
+ if !revert_extra_paths. contains_key ( & index) {
489
+ revert_extra_paths. insert ( index, full_path) ;
490
+ }
398
491
paths. push ( Paths {
399
492
ty : * ty,
400
493
name : * path. last ( ) . unwrap ( ) ,
401
494
path : Some ( index) ,
495
+ exact_path,
402
496
} ) ;
403
497
}
404
498
}
405
499
}
406
500
501
+ // Direct exports use adjacent arrays for the current crate's items,
502
+ // but re-exported exact paths don't.
503
+ let mut re_exports = Vec :: new ( ) ;
504
+ for ( item_index, item) in self . items . iter ( ) . enumerate ( ) {
505
+ if let Some ( exact_path) = item. exact_path . as_ref ( ) {
506
+ if let Some ( path_index) = mod_paths. get ( & exact_path) {
507
+ re_exports. push ( ( item_index, * path_index) ) ;
508
+ } else {
509
+ let path_index = extra_paths. len ( ) + self . items . len ( ) ;
510
+ let path_index = match extra_paths. entry ( exact_path. clone ( ) ) {
511
+ Entry :: Occupied ( entry) => * entry. get ( ) ,
512
+ Entry :: Vacant ( entry) => {
513
+ entry. insert ( path_index) ;
514
+ if !revert_extra_paths. contains_key ( & path_index) {
515
+ revert_extra_paths. insert ( path_index, exact_path. clone ( ) ) ;
516
+ }
517
+ path_index
518
+ }
519
+ } ;
520
+ re_exports. push ( ( item_index, path_index) ) ;
521
+ }
522
+ }
523
+ }
524
+
407
525
let mut names = Vec :: with_capacity ( self . items . len ( ) ) ;
408
526
let mut types = String :: with_capacity ( self . items . len ( ) ) ;
409
527
let mut full_paths = Vec :: with_capacity ( self . items . len ( ) ) ;
@@ -463,6 +581,7 @@ pub(crate) fn build_index<'tcx>(
463
581
crate_data. serialize_field ( "f" , & functions) ?;
464
582
crate_data. serialize_field ( "c" , & deprecated) ?;
465
583
crate_data. serialize_field ( "p" , & paths) ?;
584
+ crate_data. serialize_field ( "r" , & re_exports) ?;
466
585
crate_data. serialize_field ( "b" , & self . associated_item_disambiguators ) ?;
467
586
if has_aliases {
468
587
crate_data. serialize_field ( "a" , & self . aliases ) ?;
0 commit comments