1- use crate :: clean:: { self , PrimitiveType } ;
1+ use crate :: clean:: { self , rustc_span , PrimitiveType } ;
22use crate :: html:: sources;
33
44use rustc_data_structures:: fx:: FxHashMap ;
55use rustc_hir:: def:: { DefKind , Res } ;
6- use rustc_hir:: def_id:: DefId ;
6+ use rustc_hir:: def_id:: { DefId , LOCAL_CRATE } ;
77use rustc_hir:: intravisit:: { self , Visitor } ;
8- use rustc_hir:: { ExprKind , HirId , Mod , Node } ;
8+ use rustc_hir:: { ExprKind , HirId , Item , ItemKind , Mod , Node } ;
99use rustc_middle:: hir:: nested_filter;
1010use rustc_middle:: ty:: TyCtxt ;
1111use rustc_span:: hygiene:: MacroKind ;
@@ -25,6 +25,7 @@ pub(crate) enum LinkFromSrc {
2525 Local ( clean:: Span ) ,
2626 External ( DefId ) ,
2727 Primitive ( PrimitiveType ) ,
28+ Doc ( DefId ) ,
2829}
2930
3031/// This function will do at most two things:
@@ -65,24 +66,43 @@ struct SpanMapVisitor<'tcx> {
6566impl < ' tcx > SpanMapVisitor < ' tcx > {
6667 /// This function is where we handle `hir::Path` elements and add them into the "span map".
6768 fn handle_path ( & mut self , path : & rustc_hir:: Path < ' _ > ) {
68- let info = match path. res {
69+ match path. res {
6970 // FIXME: For now, we handle `DefKind` if it's not a `DefKind::TyParam`.
7071 // Would be nice to support them too alongside the other `DefKind`
7172 // (such as primitive types!).
72- Res :: Def ( kind, def_id) if kind != DefKind :: TyParam => Some ( def_id) ,
73- Res :: Local ( _) => None ,
73+ Res :: Def ( kind, def_id) if kind != DefKind :: TyParam => {
74+ let link = if def_id. as_local ( ) . is_some ( ) {
75+ LinkFromSrc :: Local ( rustc_span ( def_id, self . tcx ) )
76+ } else {
77+ LinkFromSrc :: External ( def_id)
78+ } ;
79+ self . matches . insert ( path. span , link) ;
80+ }
81+ Res :: Local ( _) => {
82+ if let Some ( span) = self . tcx . hir ( ) . res_span ( path. res ) {
83+ self . matches . insert ( path. span , LinkFromSrc :: Local ( clean:: Span :: new ( span) ) ) ;
84+ }
85+ }
7486 Res :: PrimTy ( p) => {
7587 // FIXME: Doesn't handle "path-like" primitives like arrays or tuples.
7688 self . matches . insert ( path. span , LinkFromSrc :: Primitive ( PrimitiveType :: from ( p) ) ) ;
77- return ;
7889 }
79- Res :: Err => return ,
80- _ => return ,
81- } ;
82- if let Some ( span) = self . tcx . hir ( ) . res_span ( path. res ) {
83- self . matches . insert ( path. span , LinkFromSrc :: Local ( clean:: Span :: new ( span) ) ) ;
84- } else if let Some ( def_id) = info {
85- self . matches . insert ( path. span , LinkFromSrc :: External ( def_id) ) ;
90+ Res :: Err => { }
91+ _ => { }
92+ }
93+ }
94+
95+ /// Used to generate links on items' definition to go to their documentation page.
96+ pub ( crate ) fn extract_info_from_hir_id ( & mut self , hir_id : HirId ) {
97+ if let Some ( Node :: Item ( item) ) = self . tcx . hir ( ) . find ( hir_id) {
98+ if let Some ( span) = self . tcx . def_ident_span ( item. owner_id ) {
99+ let cspan = clean:: Span :: new ( span) ;
100+ // If the span isn't from the current crate, we ignore it.
101+ if cspan. inner ( ) . is_dummy ( ) || cspan. cnum ( self . tcx . sess ) != LOCAL_CRATE {
102+ return ;
103+ }
104+ self . matches . insert ( span, LinkFromSrc :: Doc ( item. owner_id . to_def_id ( ) ) ) ;
105+ }
86106 }
87107 }
88108
@@ -117,10 +137,13 @@ impl<'tcx> SpanMapVisitor<'tcx> {
117137 _ => return true ,
118138 } ;
119139 let link_from_src = match data. macro_def_id {
120- Some ( macro_def_id) if macro_def_id. is_local ( ) => {
121- LinkFromSrc :: Local ( clean:: Span :: new ( data. def_site ) )
140+ Some ( macro_def_id) => {
141+ if macro_def_id. is_local ( ) {
142+ LinkFromSrc :: Local ( clean:: Span :: new ( data. def_site ) )
143+ } else {
144+ LinkFromSrc :: External ( macro_def_id)
145+ }
122146 }
123- Some ( macro_def_id) => LinkFromSrc :: External ( macro_def_id) ,
124147 None => return true ,
125148 } ;
126149 let new_span = data. call_site ;
@@ -160,6 +183,9 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
160183 LinkFromSrc :: Local ( clean:: Span :: new ( m. spans . inner_span ) ) ,
161184 ) ;
162185 }
186+ } else {
187+ // If it's a "mod foo {}", we want to look to its documentation page.
188+ self . extract_info_from_hir_id ( id) ;
163189 }
164190 intravisit:: walk_mod ( self , m, id) ;
165191 }
@@ -176,18 +202,41 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
176202 . tcx
177203 . typeck_body ( hir. maybe_body_owned_by ( body_id) . expect ( "a body which isn't a body" ) ) ;
178204 if let Some ( def_id) = typeck_results. type_dependent_def_id ( expr. hir_id ) {
179- self . matches . insert (
180- segment. ident . span ,
181- match hir. span_if_local ( def_id) {
182- Some ( span) => LinkFromSrc :: Local ( clean:: Span :: new ( span) ) ,
183- None => LinkFromSrc :: External ( def_id) ,
184- } ,
185- ) ;
205+ let link = if def_id. as_local ( ) . is_some ( ) {
206+ LinkFromSrc :: Local ( rustc_span ( def_id, self . tcx ) )
207+ } else {
208+ LinkFromSrc :: External ( def_id)
209+ } ;
210+ self . matches . insert ( segment. ident . span , link) ;
186211 }
187212 } else if self . handle_macro ( expr. span ) {
188213 // We don't want to go deeper into the macro.
189214 return ;
190215 }
191216 intravisit:: walk_expr ( self , expr) ;
192217 }
218+
219+ fn visit_item ( & mut self , item : & ' tcx Item < ' tcx > ) {
220+ match item. kind {
221+ ItemKind :: Static ( _, _, _)
222+ | ItemKind :: Const ( _, _)
223+ | ItemKind :: Fn ( _, _, _)
224+ | ItemKind :: Macro ( _, _)
225+ | ItemKind :: TyAlias ( _, _)
226+ | ItemKind :: Enum ( _, _)
227+ | ItemKind :: Struct ( _, _)
228+ | ItemKind :: Union ( _, _)
229+ | ItemKind :: Trait ( _, _, _, _, _)
230+ | ItemKind :: TraitAlias ( _, _) => self . extract_info_from_hir_id ( item. hir_id ( ) ) ,
231+ ItemKind :: Impl ( _)
232+ | ItemKind :: Use ( _, _)
233+ | ItemKind :: ExternCrate ( _)
234+ | ItemKind :: ForeignMod { .. }
235+ | ItemKind :: GlobalAsm ( _)
236+ | ItemKind :: OpaqueTy ( _)
237+ // We already have "visit_mod" above so no need to check it here.
238+ | ItemKind :: Mod ( _) => { }
239+ }
240+ intravisit:: walk_item ( self , item) ;
241+ }
193242}
0 commit comments