@@ -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,51 @@ 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
+ join_with_double_colon ( & fqp[ ..fqp. len ( ) - 1 ] )
335
+ } ;
336
+ if path == item. path {
337
+ return None ;
338
+ }
339
+ Some ( path)
340
+ } ) ;
341
+ }
342
+
284
343
// Omit the parent path if it is same to that of the prior item.
285
344
if lastpath == & item. path {
286
345
item. path . clear ( ) ;
@@ -319,7 +378,7 @@ pub(crate) fn build_index<'tcx>(
319
378
struct CrateData < ' a > {
320
379
doc : String ,
321
380
items : Vec < & ' a IndexItem > ,
322
- paths : Vec < ( ItemType , Vec < Symbol > ) > ,
381
+ paths : Vec < ( ItemType , Vec < Symbol > , Option < Vec < Symbol > > ) > ,
323
382
// The String is alias name and the vec is the list of the elements with this alias.
324
383
//
325
384
// To be noted: the `usize` elements are indexes to `items`.
@@ -332,6 +391,7 @@ pub(crate) fn build_index<'tcx>(
332
391
ty : ItemType ,
333
392
name : Symbol ,
334
393
path : Option < usize > ,
394
+ exact_path : Option < usize > ,
335
395
}
336
396
337
397
impl Serialize for Paths {
@@ -345,6 +405,10 @@ pub(crate) fn build_index<'tcx>(
345
405
if let Some ( ref path) = self . path {
346
406
seq. serialize_element ( path) ?;
347
407
}
408
+ if let Some ( ref path) = self . exact_path {
409
+ assert ! ( self . path. is_some( ) ) ;
410
+ seq. serialize_element ( path) ?;
411
+ }
348
412
seq. end ( )
349
413
}
350
414
}
@@ -367,43 +431,94 @@ pub(crate) fn build_index<'tcx>(
367
431
mod_paths. insert ( & item. path , index) ;
368
432
}
369
433
let mut paths = Vec :: with_capacity ( self . paths . len ( ) ) ;
370
- for ( ty, path) in & self . paths {
434
+ for ( ty, path, exact ) in & self . paths {
371
435
if path. len ( ) < 2 {
372
- paths. push ( Paths { ty : * ty, name : path[ 0 ] , path : None } ) ;
436
+ paths. push ( Paths { ty : * ty, name : path[ 0 ] , path : None , exact_path : None } ) ;
373
437
continue ;
374
438
}
375
439
let full_path = join_with_double_colon ( & path[ ..path. len ( ) - 1 ] ) ;
440
+ let full_exact_path = exact
441
+ . as_ref ( )
442
+ . filter ( |exact| exact. last ( ) == path. last ( ) )
443
+ . map ( |exact| join_with_double_colon ( & exact[ ..exact. len ( ) - 1 ] ) ) ;
444
+ let exact_path = extra_paths. len ( ) + self . items . len ( ) ;
445
+ let exact_path = full_exact_path. as_ref ( ) . map ( |full_exact_path| match extra_paths
446
+ . entry ( full_exact_path. clone ( ) )
447
+ {
448
+ Entry :: Occupied ( entry) => * entry. get ( ) ,
449
+ Entry :: Vacant ( entry) => {
450
+ if let Some ( index) = mod_paths. get ( & full_exact_path) {
451
+ return * index;
452
+ }
453
+ entry. insert ( exact_path) ;
454
+ if !revert_extra_paths. contains_key ( & exact_path) {
455
+ revert_extra_paths. insert ( exact_path, full_exact_path. clone ( ) ) ;
456
+ }
457
+ exact_path
458
+ }
459
+ } ) ;
376
460
if let Some ( index) = mod_paths. get ( & full_path) {
377
- paths. push ( Paths { ty : * ty, name : * path. last ( ) . unwrap ( ) , path : Some ( * index) } ) ;
461
+ paths. push ( Paths {
462
+ ty : * ty,
463
+ name : * path. last ( ) . unwrap ( ) ,
464
+ path : Some ( * index) ,
465
+ exact_path,
466
+ } ) ;
378
467
continue ;
379
468
}
380
469
// It means it comes from an external crate so the item and its path will be
381
470
// stored into another array.
382
471
//
383
472
// `index` is put after the last `mod_paths`
384
473
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) {
474
+ match extra_paths. entry ( full_path. clone ( ) ) {
389
475
Entry :: Occupied ( entry) => {
390
476
paths. push ( Paths {
391
477
ty : * ty,
392
478
name : * path. last ( ) . unwrap ( ) ,
393
479
path : Some ( * entry. get ( ) ) ,
480
+ exact_path,
394
481
} ) ;
395
482
}
396
483
Entry :: Vacant ( entry) => {
397
484
entry. insert ( index) ;
485
+ if !revert_extra_paths. contains_key ( & index) {
486
+ revert_extra_paths. insert ( index, full_path) ;
487
+ }
398
488
paths. push ( Paths {
399
489
ty : * ty,
400
490
name : * path. last ( ) . unwrap ( ) ,
401
491
path : Some ( index) ,
492
+ exact_path,
402
493
} ) ;
403
494
}
404
495
}
405
496
}
406
497
498
+ // Direct exports use adjacent arrays for the current crate's items,
499
+ // but re-exported exact paths don't.
500
+ let mut re_exports = Vec :: new ( ) ;
501
+ for ( item_index, item) in self . items . iter ( ) . enumerate ( ) {
502
+ if let Some ( exact_path) = item. exact_path . as_ref ( ) {
503
+ if let Some ( path_index) = mod_paths. get ( & exact_path) {
504
+ re_exports. push ( ( item_index, * path_index) ) ;
505
+ } else {
506
+ let path_index = extra_paths. len ( ) + self . items . len ( ) ;
507
+ let path_index = match extra_paths. entry ( exact_path. clone ( ) ) {
508
+ Entry :: Occupied ( entry) => * entry. get ( ) ,
509
+ Entry :: Vacant ( entry) => {
510
+ entry. insert ( path_index) ;
511
+ if !revert_extra_paths. contains_key ( & path_index) {
512
+ revert_extra_paths. insert ( path_index, exact_path. clone ( ) ) ;
513
+ }
514
+ path_index
515
+ }
516
+ } ;
517
+ re_exports. push ( ( item_index, path_index) ) ;
518
+ }
519
+ }
520
+ }
521
+
407
522
let mut names = Vec :: with_capacity ( self . items . len ( ) ) ;
408
523
let mut types = String :: with_capacity ( self . items . len ( ) ) ;
409
524
let mut full_paths = Vec :: with_capacity ( self . items . len ( ) ) ;
@@ -463,6 +578,7 @@ pub(crate) fn build_index<'tcx>(
463
578
crate_data. serialize_field ( "f" , & functions) ?;
464
579
crate_data. serialize_field ( "c" , & deprecated) ?;
465
580
crate_data. serialize_field ( "p" , & paths) ?;
581
+ crate_data. serialize_field ( "r" , & re_exports) ?;
466
582
crate_data. serialize_field ( "b" , & self . associated_item_disambiguators ) ?;
467
583
if has_aliases {
468
584
crate_data. serialize_field ( "a" , & self . aliases ) ?;
0 commit comments