@@ -737,6 +737,7 @@ fn is_derive_trait_collision<T>(ns: &PerNS<Result<(Res, T), ResolutionFailure<'_
737737
738738impl < ' a , ' tcx > DocFolder for LinkCollector < ' a , ' tcx > {
739739 fn fold_item ( & mut self , mut item : Item ) -> Option < Item > {
740+ use rustc_ast:: AttrStyle ;
740741 use rustc_middle:: ty:: DefIdTree ;
741742
742743 let parent_node = if item. is_fake ( ) {
@@ -773,7 +774,8 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
773774
774775 let current_item = match item. inner {
775776 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 ) {
777779 if item. def_id . is_top_level_module ( ) { item. name . clone ( ) } else { None }
778780 } else {
779781 match parent_node. or ( self . mod_ids . last ( ) . copied ( ) ) {
@@ -798,10 +800,6 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
798800 _ => item. name . clone ( ) ,
799801 } ;
800802
801- if item. is_mod ( ) && item. attrs . inner_docs {
802- self . mod_ids . push ( item. def_id ) ;
803- }
804-
805803 // find item's parent to resolve `Self` in item's docs below
806804 let parent_name = self . cx . as_local_hir_id ( item. def_id ) . and_then ( |item_hir| {
807805 let parent_hir = self . cx . tcx . hir ( ) . get_parent_item ( item_hir) ;
@@ -839,6 +837,10 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
839837 }
840838 } ) ;
841839
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+
842844 // We want to resolve in the lexical scope of the documentation.
843845 // In the presence of re-exports, this is not the same as the module of the item.
844846 // 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> {
849851 // we want `///` and `#[doc]` to count as the same attribute,
850852 // but currently it will treat them as separate.
851853 // 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.
852856 let mut combined_docs = attr. doc . clone ( ) ;
853857 loop {
854858 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+ {
856862 combined_docs. push ( '\n' ) ;
857863 combined_docs. push_str ( & attrs. next ( ) . unwrap ( ) . doc ) ;
858864 }
@@ -868,15 +874,39 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
868874 trace ! ( "no parent found for {:?}" , attr. doc) ;
869875 ( item. def_id . krate , parent_node)
870876 } ;
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+
871902 // NOTE: if there are links that start in one crate and end in another, this will not resolve them.
872903 // 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?
874904 for ( ori_link, link_range) in markdown_links ( & combined_docs) {
875905 let link = self . resolve_link (
876906 & item,
877907 & combined_docs,
878908 & current_item,
879- parent_node ,
909+ base_node ,
880910 & parent_name,
881911 krate,
882912 ori_link,
@@ -888,11 +918,10 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
888918 }
889919 }
890920
891- if item. is_mod ( ) && !item. attrs . inner_docs {
892- self . mod_ids . push ( item. def_id ) ;
893- }
894-
895921 if item. is_mod ( ) {
922+ if !seen_inner_docs {
923+ self . mod_ids . push ( item. def_id ) ;
924+ }
896925 let ret = self . fold_item_recur ( item) ;
897926
898927 self . mod_ids . pop ( ) ;
@@ -910,7 +939,7 @@ impl LinkCollector<'_, '_> {
910939 item : & Item ,
911940 dox : & str ,
912941 current_item : & Option < String > ,
913- parent_node : Option < DefId > ,
942+ base_node : Option < DefId > ,
914943 parent_name : & Option < String > ,
915944 krate : CrateNum ,
916945 ori_link : String ,
@@ -968,23 +997,6 @@ impl LinkCollector<'_, '_> {
968997 . map ( |d| d. display_for ( path_str) )
969998 . unwrap_or_else ( || path_str. to_owned ( ) ) ;
970999
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-
9881000 let mut module_id = if let Some ( id) = base_node {
9891001 id
9901002 } else {
@@ -1185,6 +1197,8 @@ impl LinkCollector<'_, '_> {
11851197 ori_link : & str ,
11861198 link_range : Option < Range < usize > > ,
11871199 ) -> Option < ( Res , Option < String > ) > {
1200+ debug ! ( "resolving {} relative to {:?}" , path_str, base_node) ;
1201+
11881202 match disambiguator. map ( Disambiguator :: ns) {
11891203 Some ( ns @ ( ValueNS | TypeNS ) ) => {
11901204 match self . resolve ( path_str, ns, & current_item, base_node, & extra_fragment) {
0 commit comments