@@ -32,6 +32,7 @@ use crate::clean::{
32
32
self , types:: ExternalLocation , utils:: find_nearest_parent_module, ExternalCrate , ItemId ,
33
33
PrimitiveType ,
34
34
} ;
35
+ use crate :: formats:: cache:: Cache ;
35
36
use crate :: formats:: item_type:: ItemType ;
36
37
use crate :: html:: escape:: Escape ;
37
38
use crate :: html:: render:: Context ;
@@ -581,22 +582,11 @@ fn generate_macro_def_id_path(
581
582
cx : & Context < ' _ > ,
582
583
root_path : Option < & str > ,
583
584
) -> Result < ( String , ItemType , Vec < Symbol > ) , HrefError > {
584
- let tcx = cx. shared . tcx ;
585
+ let tcx = cx. tcx ( ) ;
585
586
let crate_name = tcx. crate_name ( def_id. krate ) ;
586
587
let cache = cx. cache ( ) ;
587
588
588
- let fqp: Vec < Symbol > = tcx
589
- . def_path ( def_id)
590
- . data
591
- . into_iter ( )
592
- . filter_map ( |elem| {
593
- // extern blocks (and a few others things) have an empty name.
594
- match elem. data . get_opt_name ( ) {
595
- Some ( s) if !s. is_empty ( ) => Some ( s) ,
596
- _ => None ,
597
- }
598
- } )
599
- . collect ( ) ;
589
+ let fqp = clean:: inline:: item_relative_path ( tcx, def_id) ;
600
590
let mut relative = fqp. iter ( ) . copied ( ) ;
601
591
let cstore = CStore :: from_tcx ( tcx) ;
602
592
// We need this to prevent a `panic` when this function is used from intra doc links...
@@ -651,92 +641,168 @@ fn generate_macro_def_id_path(
651
641
Ok ( ( url, ItemType :: Macro , fqp) )
652
642
}
653
643
644
+ fn generate_item_def_id_path (
645
+ mut def_id : DefId ,
646
+ original_def_id : DefId ,
647
+ cx : & Context < ' _ > ,
648
+ root_path : Option < & str > ,
649
+ original_def_kind : DefKind ,
650
+ ) -> Result < ( String , ItemType , Vec < Symbol > ) , HrefError > {
651
+ use crate :: rustc_trait_selection:: infer:: TyCtxtInferExt ;
652
+ use crate :: rustc_trait_selection:: traits:: query:: normalize:: QueryNormalizeExt ;
653
+ use rustc_middle:: traits:: ObligationCause ;
654
+
655
+ let tcx = cx. tcx ( ) ;
656
+ let crate_name = tcx. crate_name ( def_id. krate ) ;
657
+
658
+ // No need to try to infer the actual parent item if it's not an associated item from the `impl`
659
+ // block.
660
+ if def_id != original_def_id && matches ! ( tcx. def_kind( def_id) , DefKind :: Impl { .. } ) {
661
+ let infcx = tcx. infer_ctxt ( ) . build ( ) ;
662
+ def_id = infcx
663
+ . at ( & ObligationCause :: dummy ( ) , tcx. param_env ( def_id) )
664
+ . query_normalize ( ty:: Binder :: dummy ( tcx. type_of ( def_id) . instantiate_identity ( ) ) )
665
+ . map ( |resolved| infcx. resolve_vars_if_possible ( resolved. value ) )
666
+ . ok ( )
667
+ . and_then ( |normalized| normalized. skip_binder ( ) . ty_adt_def ( ) )
668
+ . map ( |adt| adt. did ( ) )
669
+ . unwrap_or ( def_id) ;
670
+ }
671
+
672
+ let relative = clean:: inline:: item_relative_path ( tcx, def_id) ;
673
+ let fqp: Vec < Symbol > = once ( crate_name) . chain ( relative) . collect ( ) ;
674
+
675
+ let def_kind = tcx. def_kind ( def_id) ;
676
+ let shortty = def_kind. into ( ) ;
677
+ let module_fqp = to_module_fqp ( shortty, & fqp) ;
678
+ let mut is_remote = false ;
679
+
680
+ let url_parts = url_parts ( cx. cache ( ) , def_id, & module_fqp, & cx. current , & mut is_remote) ?;
681
+ let ( url_parts, shortty, fqp) = make_href ( root_path, shortty, url_parts, & fqp, is_remote) ?;
682
+ if def_id == original_def_id {
683
+ return Ok ( ( url_parts, shortty, fqp) ) ;
684
+ }
685
+ let kind = ItemType :: from_def_kind ( original_def_kind, Some ( def_kind) ) ;
686
+ Ok ( ( format ! ( "{url_parts}#{kind}.{}" , tcx. item_name( original_def_id) ) , shortty, fqp) )
687
+ }
688
+
689
+ fn to_module_fqp ( shortty : ItemType , fqp : & [ Symbol ] ) -> & [ Symbol ] {
690
+ if shortty == ItemType :: Module { fqp } else { & fqp[ ..fqp. len ( ) - 1 ] }
691
+ }
692
+
693
+ fn url_parts (
694
+ cache : & Cache ,
695
+ def_id : DefId ,
696
+ module_fqp : & [ Symbol ] ,
697
+ relative_to : & [ Symbol ] ,
698
+ is_remote : & mut bool ,
699
+ ) -> Result < UrlPartsBuilder , HrefError > {
700
+ match cache. extern_locations [ & def_id. krate ] {
701
+ ExternalLocation :: Remote ( ref s) => {
702
+ * is_remote = true ;
703
+ let s = s. trim_end_matches ( '/' ) ;
704
+ let mut builder = UrlPartsBuilder :: singleton ( s) ;
705
+ builder. extend ( module_fqp. iter ( ) . copied ( ) ) ;
706
+ Ok ( builder)
707
+ }
708
+ ExternalLocation :: Local => Ok ( href_relative_parts ( module_fqp, relative_to) . collect ( ) ) ,
709
+ ExternalLocation :: Unknown => Err ( HrefError :: DocumentationNotBuilt ) ,
710
+ }
711
+ }
712
+
713
+ fn make_href (
714
+ root_path : Option < & str > ,
715
+ shortty : ItemType ,
716
+ mut url_parts : UrlPartsBuilder ,
717
+ fqp : & [ Symbol ] ,
718
+ is_remote : bool ,
719
+ ) -> Result < ( String , ItemType , Vec < Symbol > ) , HrefError > {
720
+ if !is_remote && let Some ( root_path) = root_path {
721
+ let root = root_path. trim_end_matches ( '/' ) ;
722
+ url_parts. push_front ( root) ;
723
+ }
724
+ debug ! ( ?url_parts) ;
725
+ match shortty {
726
+ ItemType :: Module => {
727
+ url_parts. push ( "index.html" ) ;
728
+ }
729
+ _ => {
730
+ let prefix = shortty. as_str ( ) ;
731
+ let last = fqp. last ( ) . unwrap ( ) ;
732
+ url_parts. push_fmt ( format_args ! ( "{prefix}.{last}.html" ) ) ;
733
+ }
734
+ }
735
+ Ok ( ( url_parts. finish ( ) , shortty, fqp. to_vec ( ) ) )
736
+ }
737
+
654
738
pub ( crate ) fn href_with_root_path (
655
- did : DefId ,
739
+ original_did : DefId ,
656
740
cx : & Context < ' _ > ,
657
741
root_path : Option < & str > ,
658
742
) -> Result < ( String , ItemType , Vec < Symbol > ) , HrefError > {
659
743
let tcx = cx. tcx ( ) ;
660
- let def_kind = tcx. def_kind ( did ) ;
744
+ let def_kind = tcx. def_kind ( original_did ) ;
661
745
let did = match def_kind {
662
746
DefKind :: AssocTy | DefKind :: AssocFn | DefKind :: AssocConst | DefKind :: Variant => {
663
747
// documented on their parent's page
664
- tcx. parent ( did )
748
+ tcx. parent ( original_did )
665
749
}
750
+ // If this a constructor, we get the parent (either a struct or a variant) and then
751
+ // generate the link for this item.
752
+ DefKind :: Ctor ( ..) => return href_with_root_path ( tcx. parent ( original_did) , cx, root_path) ,
666
753
DefKind :: ExternCrate => {
667
754
// Link to the crate itself, not the `extern crate` item.
668
- if let Some ( local_did) = did . as_local ( ) {
755
+ if let Some ( local_did) = original_did . as_local ( ) {
669
756
tcx. extern_mod_stmt_cnum ( local_did) . unwrap_or ( LOCAL_CRATE ) . as_def_id ( )
670
757
} else {
671
- did
758
+ original_did
672
759
}
673
760
}
674
- _ => did ,
761
+ _ => original_did ,
675
762
} ;
676
763
let cache = cx. cache ( ) ;
677
764
let relative_to = & cx. current ;
678
- fn to_module_fqp ( shortty : ItemType , fqp : & [ Symbol ] ) -> & [ Symbol ] {
679
- if shortty == ItemType :: Module { fqp } else { & fqp[ ..fqp. len ( ) - 1 ] }
680
- }
681
765
682
- if !did. is_local ( )
683
- && !cache. effective_visibilities . is_directly_public ( tcx, did)
684
- && !cache. document_private
685
- && !cache. primitive_locations . values ( ) . any ( |& id| id == did)
686
- {
687
- return Err ( HrefError :: Private ) ;
766
+ if !original_did. is_local ( ) {
767
+ // If we are generating an href for the "jump to def" feature, then the only case we want
768
+ // to ignore is if the item is `doc(hidden)` because we can't link to it.
769
+ if root_path. is_some ( ) {
770
+ if tcx. is_doc_hidden ( original_did) {
771
+ return Err ( HrefError :: Private ) ;
772
+ }
773
+ } else if !cache. effective_visibilities . is_directly_public ( tcx, did)
774
+ && !cache. document_private
775
+ && !cache. primitive_locations . values ( ) . any ( |& id| id == did)
776
+ {
777
+ return Err ( HrefError :: Private ) ;
778
+ }
688
779
}
689
780
690
781
let mut is_remote = false ;
691
- let ( fqp, shortty, mut url_parts) = match cache. paths . get ( & did) {
782
+ let ( fqp, shortty, url_parts) = match cache. paths . get ( & did) {
692
783
Some ( & ( ref fqp, shortty) ) => ( fqp, shortty, {
693
784
let module_fqp = to_module_fqp ( shortty, fqp. as_slice ( ) ) ;
694
785
debug ! ( ?fqp, ?shortty, ?module_fqp) ;
695
786
href_relative_parts ( module_fqp, relative_to) . collect ( )
696
787
} ) ,
697
788
None => {
698
- if let Some ( & ( ref fqp, shortty) ) = cache. external_paths . get ( & did) {
789
+ // Associated items are handled differently with "jump to def". The anchor is generated
790
+ // directly here whereas for intra-doc links, we have some extra computation being
791
+ // performed there.
792
+ let def_id_to_get = if root_path. is_some ( ) { original_did } else { did } ;
793
+ if let Some ( & ( ref fqp, shortty) ) = cache. external_paths . get ( & def_id_to_get) {
699
794
let module_fqp = to_module_fqp ( shortty, fqp) ;
700
- (
701
- fqp,
702
- shortty,
703
- match cache. extern_locations [ & did. krate ] {
704
- ExternalLocation :: Remote ( ref s) => {
705
- is_remote = true ;
706
- let s = s. trim_end_matches ( '/' ) ;
707
- let mut builder = UrlPartsBuilder :: singleton ( s) ;
708
- builder. extend ( module_fqp. iter ( ) . copied ( ) ) ;
709
- builder
710
- }
711
- ExternalLocation :: Local => {
712
- href_relative_parts ( module_fqp, relative_to) . collect ( )
713
- }
714
- ExternalLocation :: Unknown => return Err ( HrefError :: DocumentationNotBuilt ) ,
715
- } ,
716
- )
795
+ ( fqp, shortty, url_parts ( cache, did, module_fqp, relative_to, & mut is_remote) ?)
717
796
} else if matches ! ( def_kind, DefKind :: Macro ( _) ) {
718
797
return generate_macro_def_id_path ( did, cx, root_path) ;
798
+ } else if did. is_local ( ) {
799
+ return Err ( HrefError :: Private ) ;
719
800
} else {
720
- return Err ( HrefError :: NotInExternalCache ) ;
801
+ return generate_item_def_id_path ( did , original_did , cx , root_path , def_kind ) ;
721
802
}
722
803
}
723
804
} ;
724
- if !is_remote && let Some ( root_path) = root_path {
725
- let root = root_path. trim_end_matches ( '/' ) ;
726
- url_parts. push_front ( root) ;
727
- }
728
- debug ! ( ?url_parts) ;
729
- match shortty {
730
- ItemType :: Module => {
731
- url_parts. push ( "index.html" ) ;
732
- }
733
- _ => {
734
- let prefix = shortty. as_str ( ) ;
735
- let last = fqp. last ( ) . unwrap ( ) ;
736
- url_parts. push_fmt ( format_args ! ( "{prefix}.{last}.html" ) ) ;
737
- }
738
- }
739
- Ok ( ( url_parts. finish ( ) , shortty, fqp. to_vec ( ) ) )
805
+ make_href ( root_path, shortty, url_parts, fqp, is_remote)
740
806
}
741
807
742
808
pub ( crate ) fn href (
0 commit comments