@@ -32,11 +32,29 @@ pub(crate) struct Module<'hir> {
32
32
pub ( crate ) def_id : LocalDefId ,
33
33
pub ( crate ) renamed : Option < Symbol > ,
34
34
pub ( crate ) import_id : Option < LocalDefId > ,
35
- /// The key is the item `ItemId` and the value is: (item, renamed, import_id).
35
+ /// The key is the item `ItemId` and the value is: (item, renamed, Vec< import_id> ).
36
36
/// We use `FxIndexMap` to keep the insert order.
37
+ ///
38
+ /// `import_id` needs to be a `Vec` because we live in a dark world where you can have code
39
+ /// like:
40
+ ///
41
+ /// ```
42
+ /// mod raw {
43
+ /// pub fn foo() {}
44
+ /// }
45
+ ///
46
+ /// /// Foobar
47
+ /// pub use raw::foo;
48
+ ///
49
+ /// pub use raw::*;
50
+ /// ```
51
+ ///
52
+ /// So in this case, we don't want to have two items but just one with attributes from all
53
+ /// non-glob imports to be merged. Glob imports attributes are always ignored, whether they're
54
+ /// shadowed or not.
37
55
pub ( crate ) items : FxIndexMap <
38
56
( LocalDefId , Option < Symbol > ) ,
39
- ( & ' hir hir:: Item < ' hir > , Option < Symbol > , Option < LocalDefId > ) ,
57
+ ( & ' hir hir:: Item < ' hir > , Option < Symbol > , Vec < LocalDefId > ) ,
40
58
> ,
41
59
42
60
/// (def_id, renamed) -> (res, local_import_id)
@@ -154,7 +172,9 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
154
172
{
155
173
let item = self . cx . tcx . hir_expect_item ( local_def_id) ;
156
174
let ( ident, _, _) = item. expect_macro ( ) ;
157
- top_level_module. items . insert ( ( local_def_id, Some ( ident. name ) ) , ( item, None , None ) ) ;
175
+ top_level_module
176
+ . items
177
+ . insert ( ( local_def_id, Some ( ident. name ) ) , ( item, None , Vec :: new ( ) ) ) ;
158
178
}
159
179
}
160
180
@@ -236,7 +256,6 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
236
256
) -> bool {
237
257
debug ! ( "maybe_inline_local (renamed: {renamed:?}) res: {res:?}" ) ;
238
258
239
- let glob = renamed. is_none ( ) ;
240
259
if renamed == Some ( kw:: Underscore ) {
241
260
// We never inline `_` reexports.
242
261
return false ;
@@ -261,14 +280,15 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
261
280
return false ;
262
281
}
263
282
283
+ let is_glob = renamed. is_none ( ) ;
264
284
let is_hidden = !document_hidden && tcx. is_doc_hidden ( ori_res_did) ;
265
285
let Some ( res_did) = ori_res_did. as_local ( ) else {
266
286
// For cross-crate impl inlining we need to know whether items are
267
287
// reachable in documentation -- a previously unreachable item can be
268
288
// made reachable by cross-crate inlining which we're checking here.
269
289
// (this is done here because we need to know this upfront).
270
290
crate :: visit_lib:: lib_embargo_visit_item ( self . cx , ori_res_did) ;
271
- if is_hidden || glob {
291
+ if is_hidden || is_glob {
272
292
return false ;
273
293
}
274
294
// We store inlined foreign items otherwise, it'd mean that the `use` item would be kept
@@ -316,10 +336,10 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
316
336
// Bang macros are handled a bit on their because of how they are handled by the
317
337
// compiler. If they have `#[doc(hidden)]` and the re-export doesn't have
318
338
// `#[doc(inline)]`, then we don't inline it.
319
- Node :: Item ( _) if is_bang_macro && !please_inline && renamed . is_some ( ) && is_hidden => {
339
+ Node :: Item ( _) if is_bang_macro && !please_inline && !is_glob && is_hidden => {
320
340
return false ;
321
341
}
322
- Node :: Item ( & hir:: Item { kind : hir:: ItemKind :: Mod ( _, m) , .. } ) if glob => {
342
+ Node :: Item ( & hir:: Item { kind : hir:: ItemKind :: Mod ( _, m) , .. } ) if is_glob => {
323
343
let prev = mem:: replace ( & mut self . inlining , true ) ;
324
344
for & i in m. item_ids {
325
345
let i = tcx. hir_item ( i) ;
@@ -328,13 +348,13 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
328
348
self . inlining = prev;
329
349
true
330
350
}
331
- Node :: Item ( it) if !glob => {
351
+ Node :: Item ( it) if !is_glob => {
332
352
let prev = mem:: replace ( & mut self . inlining , true ) ;
333
353
self . visit_item_inner ( it, renamed, Some ( def_id) ) ;
334
354
self . inlining = prev;
335
355
true
336
356
}
337
- Node :: ForeignItem ( it) if !glob => {
357
+ Node :: ForeignItem ( it) if !is_glob => {
338
358
let prev = mem:: replace ( & mut self . inlining , true ) ;
339
359
self . visit_foreign_item_inner ( it, renamed, Some ( def_id) ) ;
340
360
self . inlining = prev;
@@ -378,8 +398,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
378
398
fn add_to_current_mod (
379
399
& mut self ,
380
400
item : & ' tcx hir:: Item < ' _ > ,
381
- renamed : Option < Symbol > ,
382
- parent_id : Option < LocalDefId > ,
401
+ mut renamed : Option < Symbol > ,
402
+ import_id : Option < LocalDefId > ,
383
403
) {
384
404
if self . is_importable_from_parent
385
405
// If we're inside an item, only impl blocks and `macro_rules!` with the `macro_export`
@@ -392,11 +412,21 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
392
412
_ => false ,
393
413
}
394
414
{
395
- self . modules
396
- . last_mut ( )
397
- . unwrap ( )
398
- . items
399
- . insert ( ( item. owner_id . def_id , renamed) , ( item, renamed, parent_id) ) ;
415
+ if renamed == item. kind . ident ( ) . map ( |ident| ident. name ) {
416
+ renamed = None ;
417
+ }
418
+ let key = ( item. owner_id . def_id , renamed) ;
419
+ if let Some ( import_id) = import_id {
420
+ self . modules
421
+ . last_mut ( )
422
+ . unwrap ( )
423
+ . items
424
+ . entry ( key)
425
+ . and_modify ( |v| v. 2 . push ( import_id) )
426
+ . or_insert_with ( || ( item, renamed, vec ! [ import_id] ) ) ;
427
+ } else {
428
+ self . modules . last_mut ( ) . unwrap ( ) . items . insert ( key, ( item, renamed, Vec :: new ( ) ) ) ;
429
+ }
400
430
}
401
431
}
402
432
@@ -468,7 +498,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
468
498
_ => false ,
469
499
} ) ;
470
500
let ident = match kind {
471
- hir:: UseKind :: Single ( ident) => Some ( renamed . unwrap_or ( ident. name ) ) ,
501
+ hir:: UseKind :: Single ( ident) => Some ( ident. name ) ,
472
502
hir:: UseKind :: Glob => None ,
473
503
hir:: UseKind :: ListStem => unreachable ! ( ) ,
474
504
} ;
0 commit comments