@@ -260,153 +260,21 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
260260 }
261261
262262 // Index this method for searching later on.
263- if let Some ( s) = item. name . or_else ( || {
264- if item. is_stripped ( ) {
265- None
266- } else if let clean:: ImportItem ( ref i) = * item. kind
267- && let clean:: ImportKind :: Simple ( s) = i. kind
268- {
269- Some ( s)
270- } else {
271- None
272- }
273- } ) {
274- let ( parent, is_inherent_impl_item) = match * item. kind {
275- clean:: StrippedItem ( ..) => ( ( None , None ) , false ) ,
276- clean:: AssocConstItem ( ..) | clean:: AssocTypeItem ( ..)
277- if self
278- . cache
279- . parent_stack
280- . last ( )
281- . is_some_and ( |parent| parent. is_trait_impl ( ) ) =>
263+ let search_name = if !item. is_stripped ( ) {
264+ item. name . or_else ( || {
265+ if let clean:: ImportItem ( ref i) = * item. kind
266+ && let clean:: ImportKind :: Simple ( s) = i. kind
282267 {
283- // skip associated items in trait impls
284- ( ( None , None ) , false )
285- }
286- clean:: TyMethodItem ( ..)
287- | clean:: TyAssocConstItem ( ..)
288- | clean:: TyAssocTypeItem ( ..)
289- | clean:: StructFieldItem ( ..)
290- | clean:: VariantItem ( ..) => (
291- (
292- Some (
293- self . cache
294- . parent_stack
295- . last ( )
296- . expect ( "parent_stack is empty" )
297- . item_id ( )
298- . expect_def_id ( ) ,
299- ) ,
300- Some ( & self . cache . stack [ ..self . cache . stack . len ( ) - 1 ] ) ,
301- ) ,
302- false ,
303- ) ,
304- clean:: MethodItem ( ..) | clean:: AssocConstItem ( ..) | clean:: AssocTypeItem ( ..) => {
305- if self . cache . parent_stack . is_empty ( ) {
306- ( ( None , None ) , false )
307- } else {
308- let last = self . cache . parent_stack . last ( ) . expect ( "parent_stack is empty 2" ) ;
309- let did = match & * last {
310- ParentStackItem :: Impl {
311- // impl Trait for &T { fn method(self); }
312- //
313- // When generating a function index with the above shape, we want it
314- // associated with `T`, not with the primitive reference type. It should
315- // show up as `T::method`, rather than `reference::method`, in the search
316- // results page.
317- for_ : clean:: Type :: BorrowedRef { type_, .. } ,
318- ..
319- } => type_. def_id ( & self . cache ) ,
320- ParentStackItem :: Impl { for_, .. } => for_. def_id ( & self . cache ) ,
321- ParentStackItem :: Type ( item_id) => item_id. as_def_id ( ) ,
322- } ;
323- let path = did
324- . and_then ( |did| self . cache . paths . get ( & did) )
325- // The current stack not necessarily has correlation
326- // for where the type was defined. On the other
327- // hand, `paths` always has the right
328- // information if present.
329- . map ( |( fqp, _) | & fqp[ ..fqp. len ( ) - 1 ] ) ;
330- ( ( did, path) , true )
331- }
332- }
333- _ => ( ( None , Some ( & * self . cache . stack ) ) , false ) ,
334- } ;
335-
336- match parent {
337- ( parent, Some ( path) ) if is_inherent_impl_item || !self . cache . stripped_mod => {
338- debug_assert ! ( !item. is_stripped( ) ) ;
339-
340- // A crate has a module at its root, containing all items,
341- // which should not be indexed. The crate-item itself is
342- // inserted later on when serializing the search-index.
343- if item. item_id . as_def_id ( ) . is_some_and ( |idx| !idx. is_crate_root ( ) )
344- && let ty = item. type_ ( )
345- && ( ty != ItemType :: StructField
346- || u16:: from_str_radix ( s. as_str ( ) , 10 ) . is_err ( ) )
347- {
348- let desc =
349- short_markdown_summary ( & item. doc_value ( ) , & item. link_names ( self . cache ) ) ;
350- // For searching purposes, a re-export is a duplicate if:
351- //
352- // - It's either an inline, or a true re-export
353- // - It's got the same name
354- // - Both of them have the same exact path
355- let defid = ( match & * item. kind {
356- & clean:: ItemKind :: ImportItem ( ref import) => import. source . did ,
357- _ => None ,
358- } )
359- . or_else ( || item. item_id . as_def_id ( ) ) ;
360- // In case this is a field from a tuple struct, we don't add it into
361- // the search index because its name is something like "0", which is
362- // not useful for rustdoc search.
363- self . cache . search_index . push ( IndexItem {
364- ty,
365- defid,
366- name : s,
367- path : join_with_double_colon ( path) ,
368- desc,
369- parent,
370- parent_idx : None ,
371- exact_path : None ,
372- impl_id : if let Some ( ParentStackItem :: Impl { item_id, .. } ) =
373- self . cache . parent_stack . last ( )
374- {
375- item_id. as_def_id ( )
376- } else {
377- None
378- } ,
379- search_type : get_function_type_for_search (
380- & item,
381- self . tcx ,
382- clean_impl_generics ( self . cache . parent_stack . last ( ) ) . as_ref ( ) ,
383- parent,
384- self . cache ,
385- ) ,
386- aliases : item. attrs . get_doc_aliases ( ) ,
387- deprecation : item. deprecation ( self . tcx ) ,
388- } ) ;
389- }
390- }
391- ( Some ( parent) , None ) if is_inherent_impl_item => {
392- // We have a parent, but we don't know where they're
393- // defined yet. Wait for later to index this item.
394- let impl_generics = clean_impl_generics ( self . cache . parent_stack . last ( ) ) ;
395- self . cache . orphan_impl_items . push ( OrphanImplItem {
396- parent,
397- item : item. clone ( ) ,
398- impl_generics,
399- impl_id : if let Some ( ParentStackItem :: Impl { item_id, .. } ) =
400- self . cache . parent_stack . last ( )
401- {
402- item_id. as_def_id ( )
403- } else {
404- None
405- } ,
406- } ) ;
268+ Some ( s)
269+ } else {
270+ None
407271 }
408- _ => { }
409- }
272+ } )
273+ } else {
274+ None
275+ } ;
276+ if let Some ( name) = search_name {
277+ add_item_to_search_index ( self . tcx , & mut self . cache , & item, name)
410278 }
411279
412280 // Keep track of the fully qualified path for this item.
@@ -572,6 +440,152 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
572440 }
573441}
574442
443+ fn add_item_to_search_index ( tcx : TyCtxt < ' _ > , cache : & mut Cache , item : & clean:: Item , name : Symbol ) {
444+ // Item has a name, so it must also have a DefId (can't be an impl, let alone a blanket or auto impl).
445+ let item_def_id = item. item_id . as_def_id ( ) . unwrap ( ) ;
446+ let ( parent_did, parent_path) = match * item. kind {
447+ clean:: StrippedItem ( ..) => return ,
448+ clean:: AssocConstItem ( ..) | clean:: AssocTypeItem ( ..)
449+ if cache. parent_stack . last ( ) . is_some_and ( |parent| parent. is_trait_impl ( ) ) =>
450+ {
451+ // skip associated items in trait impls
452+ return ;
453+ }
454+ clean:: TyMethodItem ( ..)
455+ | clean:: TyAssocConstItem ( ..)
456+ | clean:: TyAssocTypeItem ( ..)
457+ | clean:: StructFieldItem ( ..)
458+ | clean:: VariantItem ( ..) => {
459+ // Don't index if containing module is stripped (i.e., private),
460+ // or if item is tuple struct/variant field (name is a number -> not useful for search).
461+ if cache. stripped_mod
462+ || item. type_ ( ) == ItemType :: StructField
463+ && name. as_str ( ) . chars ( ) . all ( |c| c. is_digit ( 10 ) )
464+ {
465+ return ;
466+ }
467+ let parent_did =
468+ cache. parent_stack . last ( ) . expect ( "parent_stack is empty" ) . item_id ( ) . expect_def_id ( ) ;
469+ let parent_path = & cache. stack [ ..cache. stack . len ( ) - 1 ] ;
470+ ( Some ( parent_did) , parent_path)
471+ }
472+ clean:: MethodItem ( ..) | clean:: AssocConstItem ( ..) | clean:: AssocTypeItem ( ..) => {
473+ let last = cache. parent_stack . last ( ) . expect ( "parent_stack is empty 2" ) ;
474+ let parent_did = match & * last {
475+ // impl Trait for &T { fn method(self); }
476+ //
477+ // When generating a function index with the above shape, we want it
478+ // associated with `T`, not with the primitive reference type. It should
479+ // show up as `T::method`, rather than `reference::method`, in the search
480+ // results page.
481+ ParentStackItem :: Impl { for_ : clean:: Type :: BorrowedRef { type_, .. } , .. } => {
482+ type_. def_id ( & cache)
483+ }
484+ ParentStackItem :: Impl { for_, .. } => for_. def_id ( & cache) ,
485+ ParentStackItem :: Type ( item_id) => item_id. as_def_id ( ) ,
486+ } ;
487+ let Some ( parent_did) = parent_did else { return } ;
488+ // The current stack reflects the CacheBuilder's recursive
489+ // walk over HIR. For associated items, this is the module
490+ // where the `impl` block is defined. That's an implementation
491+ // detail that we don't want to affect the search engine.
492+ //
493+ // In particular, you can arrange things like this:
494+ //
495+ // #![crate_name="me"]
496+ // mod private_mod {
497+ // impl Clone for MyThing { fn clone(&self) -> MyThing { MyThing } }
498+ // }
499+ // pub struct MyThing;
500+ //
501+ // When that happens, we need to:
502+ // - ignore the `cache.stripped_mod` flag, since the Clone impl is actually
503+ // part of the public API even though it's defined in a private module
504+ // - present the method as `me::MyThing::clone`, its publicly-visible path
505+ // - deal with the fact that the recursive walk hasn't actually reached `MyThing`
506+ // until it's already past `private_mod`, since that's first, and doesn't know
507+ // yet if `MyThing` will actually be public or not (it could be re-exported)
508+ //
509+ // We accomplish the last two points by recording children of "orphan impls"
510+ // in a field of the cache whose elements are added to the search index later,
511+ // after cache building is complete (see `handle_orphan_impl_child`).
512+ match cache. paths . get ( & parent_did) {
513+ Some ( ( fqp, _) ) => ( Some ( parent_did) , & fqp[ ..fqp. len ( ) - 1 ] ) ,
514+ None => {
515+ handle_orphan_impl_child ( cache, item, parent_did) ;
516+ return ;
517+ }
518+ }
519+ }
520+ _ => {
521+ // Don't index if item is crate root, which is inserted later on when serializing the index.
522+ // Don't index if containing module is stripped (i.e., private),
523+ if item_def_id. is_crate_root ( ) || cache. stripped_mod {
524+ return ;
525+ }
526+ ( None , & * cache. stack )
527+ }
528+ } ;
529+
530+ debug_assert ! ( !item. is_stripped( ) ) ;
531+
532+ let desc = short_markdown_summary ( & item. doc_value ( ) , & item. link_names ( cache) ) ;
533+ // For searching purposes, a re-export is a duplicate if:
534+ //
535+ // - It's either an inline, or a true re-export
536+ // - It's got the same name
537+ // - Both of them have the same exact path
538+ let defid = match & * item. kind {
539+ clean:: ItemKind :: ImportItem ( import) => import. source . did . unwrap_or ( item_def_id) ,
540+ _ => item_def_id,
541+ } ;
542+ let path = join_with_double_colon ( parent_path) ;
543+ let impl_id = if let Some ( ParentStackItem :: Impl { item_id, .. } ) = cache. parent_stack . last ( ) {
544+ item_id. as_def_id ( )
545+ } else {
546+ None
547+ } ;
548+ let search_type = get_function_type_for_search (
549+ & item,
550+ tcx,
551+ clean_impl_generics ( cache. parent_stack . last ( ) ) . as_ref ( ) ,
552+ parent_did,
553+ cache,
554+ ) ;
555+ let aliases = item. attrs . get_doc_aliases ( ) ;
556+ let deprecation = item. deprecation ( tcx) ;
557+ let index_item = IndexItem {
558+ ty : item. type_ ( ) ,
559+ defid : Some ( defid) ,
560+ name,
561+ path,
562+ desc,
563+ parent : parent_did,
564+ parent_idx : None ,
565+ exact_path : None ,
566+ impl_id,
567+ search_type,
568+ aliases,
569+ deprecation,
570+ } ;
571+ cache. search_index . push ( index_item) ;
572+ }
573+
574+ /// We have a parent, but we don't know where they're
575+ /// defined yet. Wait for later to index this item.
576+ /// See [`Cache::orphan_impl_items`].
577+ fn handle_orphan_impl_child ( cache : & mut Cache , item : & clean:: Item , parent_did : DefId ) {
578+ let impl_generics = clean_impl_generics ( cache. parent_stack . last ( ) ) ;
579+ let impl_id = if let Some ( ParentStackItem :: Impl { item_id, .. } ) = cache. parent_stack . last ( ) {
580+ item_id. as_def_id ( )
581+ } else {
582+ None
583+ } ;
584+ let orphan_item =
585+ OrphanImplItem { parent : parent_did, item : item. clone ( ) , impl_generics, impl_id } ;
586+ cache. orphan_impl_items . push ( orphan_item) ;
587+ }
588+
575589pub ( crate ) struct OrphanImplItem {
576590 pub ( crate ) parent : DefId ,
577591 pub ( crate ) impl_id : Option < DefId > ,
0 commit comments