@@ -737,6 +737,7 @@ fn is_derive_trait_collision<T>(ns: &PerNS<Result<(Res, T), ResolutionFailure<'_
737
737
738
738
impl < ' a , ' tcx > DocFolder for LinkCollector < ' a , ' tcx > {
739
739
fn fold_item ( & mut self , mut item : Item ) -> Option < Item > {
740
+ use rustc_ast:: AttrStyle ;
740
741
use rustc_middle:: ty:: DefIdTree ;
741
742
742
743
let parent_node = if item. is_fake ( ) {
@@ -773,7 +774,8 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
773
774
774
775
let current_item = match item. inner {
775
776
ModuleItem ( ..) => {
776
- if item. attrs . inner_docs {
777
+ // FIXME: this will be wrong if there are both inner and outer docs.
778
+ if item. attrs . doc_strings . iter ( ) . any ( |attr| attr. style == AttrStyle :: Inner ) {
777
779
if item. def_id . is_top_level_module ( ) { item. name . clone ( ) } else { None }
778
780
} else {
779
781
match parent_node. or ( self . mod_ids . last ( ) . copied ( ) ) {
@@ -798,10 +800,6 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
798
800
_ => item. name . clone ( ) ,
799
801
} ;
800
802
801
- if item. is_mod ( ) && item. attrs . inner_docs {
802
- self . mod_ids . push ( item. def_id ) ;
803
- }
804
-
805
803
// find item's parent to resolve `Self` in item's docs below
806
804
let parent_name = self . cx . as_local_hir_id ( item. def_id ) . and_then ( |item_hir| {
807
805
let parent_hir = self . cx . tcx . hir ( ) . get_parent_item ( item_hir) ;
@@ -839,6 +837,10 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
839
837
}
840
838
} ) ;
841
839
840
+ // If there are both inner and outer docs, we want to only resolve the inner docs
841
+ // within the module.
842
+ let mut seen_inner_docs = false ;
843
+
842
844
// We want to resolve in the lexical scope of the documentation.
843
845
// In the presence of re-exports, this is not the same as the module of the item.
844
846
// Rather than merging all documentation into one, resolve it one attribute at a time
@@ -849,10 +851,14 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
849
851
// we want `///` and `#[doc]` to count as the same attribute,
850
852
// but currently it will treat them as separate.
851
853
// As a workaround, combine all attributes with the same parent module into the same attribute.
854
+ // NOTE: this can combine attributes across different spans,
855
+ // for example both inside and outside a crate.
852
856
let mut combined_docs = attr. doc . clone ( ) ;
853
857
loop {
854
858
match attrs. peek ( ) {
855
- Some ( next) if next. parent_module == attr. parent_module => {
859
+ Some ( next)
860
+ if next. parent_module == attr. parent_module && next. style == attr. style =>
861
+ {
856
862
combined_docs. push ( '\n' ) ;
857
863
combined_docs. push_str ( & attrs. next ( ) . unwrap ( ) . doc ) ;
858
864
}
@@ -868,15 +874,39 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
868
874
trace ! ( "no parent found for {:?}" , attr. doc) ;
869
875
( item. def_id . krate , parent_node)
870
876
} ;
877
+
878
+ // In order to correctly resolve intra-doc-links we need to
879
+ // pick a base AST node to work from. If the documentation for
880
+ // this module came from an inner comment (//!) then we anchor
881
+ // our name resolution *inside* the module. If, on the other
882
+ // hand it was an outer comment (///) then we anchor the name
883
+ // resolution in the parent module on the basis that the names
884
+ // used are more likely to be intended to be parent names. For
885
+ // this, we set base_node to None for inner comments since
886
+ // we've already pushed this node onto the resolution stack but
887
+ // for outer comments we explicitly try and resolve against the
888
+ // parent_node first.
889
+
890
+ // NOTE: there is an implicit assumption here that outer docs will always come
891
+ // before inner docs.
892
+ let base_node = if !seen_inner_docs && item. is_mod ( ) && attr. style == AttrStyle :: Inner {
893
+ // FIXME(jynelson): once `Self` handling is cleaned up I think we can get rid
894
+ // of `mod_ids` altogether
895
+ self . mod_ids . push ( item. def_id ) ;
896
+ seen_inner_docs = true ;
897
+ Some ( item. def_id )
898
+ } else {
899
+ parent_node
900
+ } ;
901
+
871
902
// NOTE: if there are links that start in one crate and end in another, this will not resolve them.
872
903
// This is a degenerate case and it's not supported by rustdoc.
873
- // FIXME: this will break links that start in `#[doc = ...]` and end as a sugared doc. Should this be supported?
874
904
for ( ori_link, link_range) in markdown_links ( & combined_docs) {
875
905
let link = self . resolve_link (
876
906
& item,
877
907
& combined_docs,
878
908
& current_item,
879
- parent_node ,
909
+ base_node ,
880
910
& parent_name,
881
911
krate,
882
912
ori_link,
@@ -888,11 +918,10 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
888
918
}
889
919
}
890
920
891
- if item. is_mod ( ) && !item. attrs . inner_docs {
892
- self . mod_ids . push ( item. def_id ) ;
893
- }
894
-
895
921
if item. is_mod ( ) {
922
+ if !seen_inner_docs {
923
+ self . mod_ids . push ( item. def_id ) ;
924
+ }
896
925
let ret = self . fold_item_recur ( item) ;
897
926
898
927
self . mod_ids . pop ( ) ;
@@ -910,7 +939,7 @@ impl LinkCollector<'_, '_> {
910
939
item : & Item ,
911
940
dox : & str ,
912
941
current_item : & Option < String > ,
913
- parent_node : Option < DefId > ,
942
+ base_node : Option < DefId > ,
914
943
parent_name : & Option < String > ,
915
944
krate : CrateNum ,
916
945
ori_link : String ,
@@ -968,23 +997,6 @@ impl LinkCollector<'_, '_> {
968
997
. map ( |d| d. display_for ( path_str) )
969
998
. unwrap_or_else ( || path_str. to_owned ( ) ) ;
970
999
971
- // In order to correctly resolve intra-doc-links we need to
972
- // pick a base AST node to work from. If the documentation for
973
- // this module came from an inner comment (//!) then we anchor
974
- // our name resolution *inside* the module. If, on the other
975
- // hand it was an outer comment (///) then we anchor the name
976
- // resolution in the parent module on the basis that the names
977
- // used are more likely to be intended to be parent names. For
978
- // this, we set base_node to None for inner comments since
979
- // we've already pushed this node onto the resolution stack but
980
- // for outer comments we explicitly try and resolve against the
981
- // parent_node first.
982
- let base_node = if item. is_mod ( ) && item. attrs . inner_docs {
983
- self . mod_ids . last ( ) . copied ( )
984
- } else {
985
- parent_node
986
- } ;
987
-
988
1000
let mut module_id = if let Some ( id) = base_node {
989
1001
id
990
1002
} else {
@@ -1185,6 +1197,8 @@ impl LinkCollector<'_, '_> {
1185
1197
ori_link : & str ,
1186
1198
link_range : Option < Range < usize > > ,
1187
1199
) -> Option < ( Res , Option < String > ) > {
1200
+ debug ! ( "resolving {} relative to {:?}" , path_str, base_node) ;
1201
+
1188
1202
match disambiguator. map ( Disambiguator :: ns) {
1189
1203
Some ( ns @ ( ValueNS | TypeNS ) ) => {
1190
1204
match self . resolve ( path_str, ns, & current_item, base_node, & extra_fragment) {
0 commit comments