@@ -8,7 +8,7 @@ use rustc_hir::def::{
8
8
Namespace :: { self , * } ,
9
9
PerNS , Res ,
10
10
} ;
11
- use rustc_hir:: def_id:: DefId ;
11
+ use rustc_hir:: def_id:: { CrateNum , DefId } ;
12
12
use rustc_middle:: ty;
13
13
use rustc_resolve:: ParentScope ;
14
14
use rustc_session:: lint:: {
@@ -767,17 +767,6 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
767
767
self . mod_ids . push ( item. def_id ) ;
768
768
}
769
769
770
- #[ cfg( debug_assertions) ]
771
- for attr in & item. attrs . doc_strings {
772
- if let Some ( id) = attr. parent_module {
773
- trace ! ( "docs {:?} came from {:?}" , attr. doc, id) ;
774
- } else {
775
- debug ! ( "no parent found for {:?}" , attr. doc) ;
776
- }
777
- }
778
- let dox = item. attrs . collapsed_doc_value ( ) . unwrap_or_else ( String :: new) ;
779
- //trace!("got documentation '{}'", dox);
780
-
781
770
// find item's parent to resolve `Self` in item's docs below
782
771
let parent_name = self . cx . as_local_hir_id ( item. def_id ) . and_then ( |item_hir| {
783
772
let parent_hir = self . cx . tcx . hir ( ) . get_parent_item ( item_hir) ;
@@ -815,16 +804,53 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
815
804
}
816
805
} ) ;
817
806
818
- for ( ori_link, link_range) in markdown_links ( & dox) {
819
- self . resolve_link (
820
- & mut item,
821
- & dox,
822
- & current_item,
823
- parent_node,
824
- & parent_name,
825
- ori_link,
826
- link_range,
827
- ) ;
807
+ // We want to resolve in the lexical scope of the documentation.
808
+ // In the presence of re-exports, this is not the same as the module of the item.
809
+ // Rather than merging all documentation into one, resolve it one attribute at a time
810
+ // so we know which module it came from.
811
+ let mut attrs = item. attrs . doc_strings . iter ( ) . peekable ( ) ;
812
+ while let Some ( attr) = attrs. next ( ) {
813
+ // `collapse_docs` does not have the behavior we want:
814
+ // we want `///` and `#[doc]` to count as the same attribute,
815
+ // but currently it will treat them as separate.
816
+ // As a workaround, combine all attributes with the same parent module into the same attribute.
817
+ let mut combined_docs = attr. doc . clone ( ) ;
818
+ loop {
819
+ match attrs. peek ( ) {
820
+ Some ( next) if next. parent_module == attr. parent_module => {
821
+ combined_docs. push ( '\n' ) ;
822
+ combined_docs. push_str ( & attrs. next ( ) . unwrap ( ) . doc ) ;
823
+ }
824
+ _ => break ,
825
+ }
826
+ }
827
+ debug ! ( "combined_docs={}" , combined_docs) ;
828
+
829
+ let ( krate, parent_node) = if let Some ( id) = attr. parent_module {
830
+ trace ! ( "docs {:?} came from {:?}" , attr. doc, id) ;
831
+ ( id. krate , Some ( id) )
832
+ } else {
833
+ trace ! ( "no parent found for {:?}" , attr. doc) ;
834
+ ( item. def_id . krate , parent_node)
835
+ } ;
836
+ // NOTE: if there are links that start in one crate and end in another, this will not resolve them.
837
+ // This is a degenerate case and it's not supported by rustdoc.
838
+ // FIXME: this will break links that start in `#[doc = ...]` and end as a sugared doc. Should this be supported?
839
+ for ( ori_link, link_range) in markdown_links ( & combined_docs) {
840
+ let link = self . resolve_link (
841
+ & item,
842
+ & combined_docs,
843
+ & current_item,
844
+ parent_node,
845
+ & parent_name,
846
+ krate,
847
+ ori_link,
848
+ link_range,
849
+ ) ;
850
+ if let Some ( link) = link {
851
+ item. attrs . links . push ( link) ;
852
+ }
853
+ }
828
854
}
829
855
830
856
if item. is_mod ( ) && !item. attrs . inner_docs {
@@ -846,36 +872,37 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
846
872
impl LinkCollector < ' _ , ' _ > {
847
873
fn resolve_link (
848
874
& self ,
849
- item : & mut Item ,
875
+ item : & Item ,
850
876
dox : & str ,
851
877
current_item : & Option < String > ,
852
878
parent_node : Option < DefId > ,
853
879
parent_name : & Option < String > ,
880
+ krate : CrateNum ,
854
881
ori_link : String ,
855
882
link_range : Option < Range < usize > > ,
856
- ) {
883
+ ) -> Option < ItemLink > {
857
884
trace ! ( "considering link '{}'" , ori_link) ;
858
885
859
886
// Bail early for real links.
860
887
if ori_link. contains ( '/' ) {
861
- return ;
888
+ return None ;
862
889
}
863
890
864
891
// [] is mostly likely not supposed to be a link
865
892
if ori_link. is_empty ( ) {
866
- return ;
893
+ return None ;
867
894
}
868
895
869
896
let cx = self . cx ;
870
897
let link = ori_link. replace ( "`" , "" ) ;
871
898
let parts = link. split ( '#' ) . collect :: < Vec < _ > > ( ) ;
872
899
let ( link, extra_fragment) = if parts. len ( ) > 2 {
873
900
anchor_failure ( cx, & item, & link, dox, link_range, AnchorFailure :: MultipleAnchors ) ;
874
- return ;
901
+ return None ;
875
902
} else if parts. len ( ) == 2 {
876
903
if parts[ 0 ] . trim ( ) . is_empty ( ) {
877
904
// This is an anchor to an element of the current page, nothing to do in here!
878
- return ;
905
+ return None ;
879
906
}
880
907
( parts[ 0 ] , Some ( parts[ 1 ] . to_owned ( ) ) )
881
908
} else {
@@ -896,7 +923,7 @@ impl LinkCollector<'_, '_> {
896
923
. trim ( ) ;
897
924
898
925
if path_str. contains ( |ch : char | !( ch. is_alphanumeric ( ) || ch == ':' || ch == '_' ) ) {
899
- return ;
926
+ return None ;
900
927
}
901
928
902
929
// We stripped `()` and `!` when parsing the disambiguator.
@@ -936,7 +963,7 @@ impl LinkCollector<'_, '_> {
936
963
link_range,
937
964
smallvec ! [ err_kind] ,
938
965
) ;
939
- return ;
966
+ return None ;
940
967
} ;
941
968
942
969
// replace `Self` with suitable item's parent name
@@ -955,7 +982,7 @@ impl LinkCollector<'_, '_> {
955
982
// (consider `crate::char`). Instead, change it to `self::`. This works because 'self' is now the crate root.
956
983
resolved_self = format ! ( "self::{}" , & path_str[ "crate::" . len( ) ..] ) ;
957
984
path_str = & resolved_self;
958
- module_id = DefId { krate : item . def_id . krate , index : CRATE_DEF_INDEX } ;
985
+ module_id = DefId { krate, index : CRATE_DEF_INDEX } ;
959
986
}
960
987
961
988
match self . resolve_with_disambiguator (
@@ -970,7 +997,7 @@ impl LinkCollector<'_, '_> {
970
997
link_range. clone ( ) ,
971
998
) {
972
999
Some ( x) => x,
973
- None => return ,
1000
+ None => return None ,
974
1001
}
975
1002
} ;
976
1003
@@ -994,15 +1021,15 @@ impl LinkCollector<'_, '_> {
994
1021
link_range,
995
1022
AnchorFailure :: RustdocAnchorConflict ( prim) ,
996
1023
) ;
997
- return ;
1024
+ return None ;
998
1025
}
999
1026
res = prim;
1000
1027
fragment = Some ( path. to_owned ( ) ) ;
1001
1028
} else {
1002
1029
// `[char]` when a `char` module is in scope
1003
1030
let candidates = vec ! [ res, prim] ;
1004
1031
ambiguity_error ( cx, & item, path_str, dox, link_range, candidates) ;
1005
- return ;
1032
+ return None ;
1006
1033
}
1007
1034
}
1008
1035
}
@@ -1026,16 +1053,11 @@ impl LinkCollector<'_, '_> {
1026
1053
if let Res :: PrimTy ( ..) = res {
1027
1054
match disambiguator {
1028
1055
Some ( Disambiguator :: Primitive | Disambiguator :: Namespace ( _) ) | None => {
1029
- item. attrs . links . push ( ItemLink {
1030
- link : ori_link,
1031
- link_text,
1032
- did : None ,
1033
- fragment,
1034
- } ) ;
1056
+ Some ( ItemLink { link : ori_link, link_text, did : None , fragment } )
1035
1057
}
1036
1058
Some ( other) => {
1037
1059
report_mismatch ( other, Disambiguator :: Primitive ) ;
1038
- return ;
1060
+ None
1039
1061
}
1040
1062
}
1041
1063
} else {
@@ -1058,7 +1080,7 @@ impl LinkCollector<'_, '_> {
1058
1080
( actual, Some ( Disambiguator :: Kind ( expected) ) ) if actual == expected => { }
1059
1081
( _, Some ( specified @ Disambiguator :: Kind ( _) | specified @ Disambiguator :: Primitive ) ) => {
1060
1082
report_mismatch ( specified, Disambiguator :: Kind ( kind) ) ;
1061
- return ;
1083
+ return None ;
1062
1084
}
1063
1085
}
1064
1086
}
@@ -1081,14 +1103,14 @@ impl LinkCollector<'_, '_> {
1081
1103
}
1082
1104
}
1083
1105
let id = register_res ( cx, res) ;
1084
- item . attrs . links . push ( ItemLink { link : ori_link, link_text, did : Some ( id) , fragment } ) ;
1106
+ Some ( ItemLink { link : ori_link, link_text, did : Some ( id) , fragment } )
1085
1107
}
1086
1108
}
1087
1109
1088
1110
fn resolve_with_disambiguator (
1089
1111
& self ,
1090
1112
disambiguator : Option < Disambiguator > ,
1091
- item : & mut Item ,
1113
+ item : & Item ,
1092
1114
dox : & str ,
1093
1115
path_str : & str ,
1094
1116
current_item : & Option < String > ,
0 commit comments