1
- use crate :: clean:: { self , PrimitiveType } ;
1
+ use crate :: clean:: { self , rustc_span , PrimitiveType } ;
2
2
use crate :: html:: sources;
3
3
4
4
use rustc_data_structures:: fx:: FxHashMap ;
5
5
use rustc_hir:: def:: { DefKind , Res } ;
6
- use rustc_hir:: def_id:: DefId ;
6
+ use rustc_hir:: def_id:: { DefId , LOCAL_CRATE } ;
7
7
use rustc_hir:: intravisit:: { self , Visitor } ;
8
- use rustc_hir:: { ExprKind , HirId , Mod , Node } ;
8
+ use rustc_hir:: { ExprKind , HirId , Item , ItemKind , Mod , Node } ;
9
9
use rustc_middle:: hir:: nested_filter;
10
10
use rustc_middle:: ty:: TyCtxt ;
11
11
use rustc_span:: hygiene:: MacroKind ;
@@ -25,6 +25,7 @@ pub(crate) enum LinkFromSrc {
25
25
Local ( clean:: Span ) ,
26
26
External ( DefId ) ,
27
27
Primitive ( PrimitiveType ) ,
28
+ Doc ( DefId ) ,
28
29
}
29
30
30
31
/// This function will do at most two things:
@@ -65,24 +66,43 @@ struct SpanMapVisitor<'tcx> {
65
66
impl < ' tcx > SpanMapVisitor < ' tcx > {
66
67
/// This function is where we handle `hir::Path` elements and add them into the "span map".
67
68
fn handle_path ( & mut self , path : & rustc_hir:: Path < ' _ > ) {
68
- let info = match path. res {
69
+ match path. res {
69
70
// FIXME: For now, we handle `DefKind` if it's not a `DefKind::TyParam`.
70
71
// Would be nice to support them too alongside the other `DefKind`
71
72
// (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
+ }
74
86
Res :: PrimTy ( p) => {
75
87
// FIXME: Doesn't handle "path-like" primitives like arrays or tuples.
76
88
self . matches . insert ( path. span , LinkFromSrc :: Primitive ( PrimitiveType :: from ( p) ) ) ;
77
- return ;
78
89
}
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
+ }
86
106
}
87
107
}
88
108
@@ -117,10 +137,13 @@ impl<'tcx> SpanMapVisitor<'tcx> {
117
137
_ => return true ,
118
138
} ;
119
139
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
+ }
122
146
}
123
- Some ( macro_def_id) => LinkFromSrc :: External ( macro_def_id) ,
124
147
None => return true ,
125
148
} ;
126
149
let new_span = data. call_site ;
@@ -160,6 +183,9 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
160
183
LinkFromSrc :: Local ( clean:: Span :: new ( m. spans . inner_span ) ) ,
161
184
) ;
162
185
}
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) ;
163
189
}
164
190
intravisit:: walk_mod ( self , m, id) ;
165
191
}
@@ -176,18 +202,41 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
176
202
. tcx
177
203
. typeck_body ( hir. maybe_body_owned_by ( body_id) . expect ( "a body which isn't a body" ) ) ;
178
204
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) ;
186
211
}
187
212
} else if self . handle_macro ( expr. span ) {
188
213
// We don't want to go deeper into the macro.
189
214
return ;
190
215
}
191
216
intravisit:: walk_expr ( self , expr) ;
192
217
}
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
+ }
193
242
}
0 commit comments