1
1
use crate :: clean:: Attributes ;
2
2
use crate :: core:: ResolverCaches ;
3
- use crate :: html:: markdown:: markdown_links;
3
+ use crate :: html:: markdown:: { markdown_links, MarkdownLink } ;
4
4
use crate :: passes:: collect_intra_doc_links:: preprocess_link;
5
5
6
6
use rustc_ast:: visit:: { self , AssocCtxt , Visitor } ;
7
7
use rustc_ast:: { self as ast, ItemKind } ;
8
8
use rustc_ast_lowering:: ResolverAstLowering ;
9
- use rustc_hir:: def:: Namespace :: TypeNS ;
10
- use rustc_hir:: def:: { DefKind , Res } ;
9
+ use rustc_data_structures:: fx:: FxHashMap ;
10
+ use rustc_hir:: def:: Namespace :: * ;
11
+ use rustc_hir:: def:: { DefKind , Namespace , Res } ;
11
12
use rustc_hir:: def_id:: { DefId , DefIdMap , DefIdSet , LocalDefId , CRATE_DEF_ID } ;
12
13
use rustc_hir:: TraitCandidate ;
13
14
use rustc_middle:: ty:: { DefIdTree , Visibility } ;
14
15
use rustc_resolve:: { ParentScope , Resolver } ;
15
16
use rustc_session:: config:: Externs ;
16
- use rustc_span:: SyntaxContext ;
17
+ use rustc_span:: { Symbol , SyntaxContext } ;
17
18
18
19
use std:: collections:: hash_map:: Entry ;
19
20
use std:: mem;
@@ -28,6 +29,8 @@ crate fn early_resolve_intra_doc_links(
28
29
resolver,
29
30
current_mod : CRATE_DEF_ID ,
30
31
visited_mods : Default :: default ( ) ,
32
+ markdown_links : Default :: default ( ) ,
33
+ doc_link_resolutions : Default :: default ( ) ,
31
34
traits_in_scope : Default :: default ( ) ,
32
35
all_traits : Default :: default ( ) ,
33
36
all_trait_impls : Default :: default ( ) ,
@@ -36,7 +39,7 @@ crate fn early_resolve_intra_doc_links(
36
39
37
40
// Overridden `visit_item` below doesn't apply to the crate root,
38
41
// so we have to visit its attributes and reexports separately.
39
- link_resolver. load_links_in_attrs ( & krate. attrs ) ;
42
+ link_resolver. resolve_doc_links_local ( & krate. attrs ) ;
40
43
link_resolver. process_module_children_or_reexports ( CRATE_DEF_ID . to_def_id ( ) ) ;
41
44
visit:: walk_crate ( & mut link_resolver, krate) ;
42
45
link_resolver. process_extern_impls ( ) ;
@@ -50,17 +53,27 @@ crate fn early_resolve_intra_doc_links(
50
53
}
51
54
52
55
ResolverCaches {
56
+ markdown_links : Some ( link_resolver. markdown_links ) ,
57
+ doc_link_resolutions : link_resolver. doc_link_resolutions ,
53
58
traits_in_scope : link_resolver. traits_in_scope ,
54
59
all_traits : Some ( link_resolver. all_traits ) ,
55
60
all_trait_impls : Some ( link_resolver. all_trait_impls ) ,
56
61
all_macro_rules : link_resolver. resolver . take_all_macro_rules ( ) ,
57
62
}
58
63
}
59
64
65
+ fn doc_attrs < ' a > ( attrs : impl Iterator < Item = & ' a ast:: Attribute > ) -> Attributes {
66
+ let mut attrs = Attributes :: from_ast_iter ( attrs. filter ( |attr| attr. doc_str ( ) . is_some ( ) ) , None ) ;
67
+ attrs. unindent_doc_comments ( ) ;
68
+ attrs
69
+ }
70
+
60
71
struct EarlyDocLinkResolver < ' r , ' ra > {
61
72
resolver : & ' r mut Resolver < ' ra > ,
62
73
current_mod : LocalDefId ,
63
74
visited_mods : DefIdSet ,
75
+ markdown_links : FxHashMap < String , Vec < MarkdownLink > > ,
76
+ doc_link_resolutions : FxHashMap < ( Symbol , Namespace , DefId ) , Option < Res < ast:: NodeId > > > ,
64
77
traits_in_scope : DefIdMap < Vec < TraitCandidate > > ,
65
78
all_traits : Vec < DefId > ,
66
79
all_trait_impls : Vec < DefId > ,
@@ -92,18 +105,11 @@ impl EarlyDocLinkResolver<'_, '_> {
92
105
}
93
106
}
94
107
95
- fn add_traits_in_parent_scope ( & mut self , def_id : DefId ) {
96
- if let Some ( module_id) = self . resolver . parent ( def_id) {
97
- self . add_traits_in_scope ( module_id) ;
98
- }
99
- }
100
-
101
108
/// Add traits in scope for links in impls collected by the `collect-intra-doc-links` pass.
102
109
/// That pass filters impls using type-based information, but we don't yet have such
103
110
/// information here, so we just conservatively calculate traits in scope for *all* modules
104
111
/// having impls in them.
105
112
fn process_extern_impls ( & mut self ) {
106
- // FIXME: Need to resolve doc links on all these impl and trait items below.
107
113
// Resolving links in already existing crates may trigger loading of new crates.
108
114
let mut start_cnum = 0 ;
109
115
loop {
@@ -124,7 +130,7 @@ impl EarlyDocLinkResolver<'_, '_> {
124
130
// the current crate, and links in their doc comments are not resolved.
125
131
for & def_id in & all_traits {
126
132
if self . resolver . cstore ( ) . visibility_untracked ( def_id) == Visibility :: Public {
127
- self . add_traits_in_parent_scope ( def_id) ;
133
+ self . resolve_doc_links_extern_impl ( def_id, false ) ;
128
134
}
129
135
}
130
136
for & ( trait_def_id, impl_def_id, simplified_self_ty) in & all_trait_impls {
@@ -135,17 +141,17 @@ impl EarlyDocLinkResolver<'_, '_> {
135
141
== Visibility :: Public
136
142
} )
137
143
{
138
- self . add_traits_in_parent_scope ( impl_def_id) ;
144
+ self . resolve_doc_links_extern_impl ( impl_def_id, false ) ;
139
145
}
140
146
}
141
147
for ( ty_def_id, impl_def_id) in all_inherent_impls {
142
148
if self . resolver . cstore ( ) . visibility_untracked ( ty_def_id) == Visibility :: Public
143
149
{
144
- self . add_traits_in_parent_scope ( impl_def_id) ;
150
+ self . resolve_doc_links_extern_impl ( impl_def_id, true ) ;
145
151
}
146
152
}
147
- for def_id in all_incoherent_impls {
148
- self . add_traits_in_parent_scope ( def_id ) ;
153
+ for impl_def_id in all_incoherent_impls {
154
+ self . resolve_doc_links_extern_impl ( impl_def_id , true ) ;
149
155
}
150
156
151
157
self . all_traits . extend ( all_traits) ;
@@ -161,16 +167,52 @@ impl EarlyDocLinkResolver<'_, '_> {
161
167
}
162
168
}
163
169
164
- fn load_links_in_attrs ( & mut self , attrs : & [ ast:: Attribute ] ) {
170
+ fn resolve_doc_links_extern_impl ( & mut self , def_id : DefId , _is_inherent : bool ) {
171
+ // FIXME: Resolve links in associated items in addition to traits themselves,
172
+ // `force` is used to provide traits in scope for the associated items.
173
+ self . resolve_doc_links_extern_outer ( def_id, def_id, true ) ;
174
+ }
175
+
176
+ fn resolve_doc_links_extern_outer ( & mut self , def_id : DefId , scope_id : DefId , force : bool ) {
177
+ if !force && !self . resolver . cstore ( ) . may_have_doc_links_untracked ( def_id) {
178
+ return ;
179
+ }
180
+ // FIXME: actually resolve links, not just add traits in scope.
181
+ if let Some ( parent_id) = self . resolver . parent ( scope_id) {
182
+ self . add_traits_in_scope ( parent_id) ;
183
+ }
184
+ }
185
+
186
+ fn resolve_doc_links_extern_inner ( & mut self , def_id : DefId ) {
187
+ if !self . resolver . cstore ( ) . may_have_doc_links_untracked ( def_id) {
188
+ return ;
189
+ }
190
+ // FIXME: actually resolve links, not just add traits in scope.
191
+ self . add_traits_in_scope ( def_id) ;
192
+ }
193
+
194
+ fn resolve_doc_links_local ( & mut self , attrs : & [ ast:: Attribute ] ) {
195
+ if !attrs. iter ( ) . any ( |attr| attr. may_have_doc_links ( ) ) {
196
+ return ;
197
+ }
165
198
let module_id = self . current_mod . to_def_id ( ) ;
199
+ self . resolve_doc_links ( doc_attrs ( attrs. iter ( ) ) , module_id) ;
200
+ }
201
+
202
+ fn resolve_doc_links ( & mut self , attrs : Attributes , module_id : DefId ) {
166
203
let mut need_traits_in_scope = false ;
167
- for ( doc_module, doc) in
168
- Attributes :: from_ast ( attrs, None ) . collapsed_doc_value_by_module_level ( )
169
- {
204
+ for ( doc_module, doc) in attrs. collapsed_doc_value_by_module_level ( ) {
170
205
assert_eq ! ( doc_module, None ) ;
171
- for link in markdown_links ( & doc. as_str ( ) ) {
206
+ for link in self . markdown_links . entry ( doc) . or_insert_with_key ( |doc| markdown_links ( doc) )
207
+ {
172
208
if let Some ( Ok ( pinfo) ) = preprocess_link ( & link) {
173
- self . resolver . resolve_rustdoc_path ( & pinfo. path_str , TypeNS , module_id) ;
209
+ // FIXME: Resolve the path in all namespaces and resolve its prefixes too.
210
+ let ns = TypeNS ;
211
+ self . doc_link_resolutions
212
+ . entry ( ( Symbol :: intern ( & pinfo. path_str ) , ns, module_id) )
213
+ . or_insert_with_key ( |( path, ns, module_id) | {
214
+ self . resolver . resolve_rustdoc_path ( path. as_str ( ) , * ns, * module_id)
215
+ } ) ;
174
216
need_traits_in_scope = true ;
175
217
}
176
218
}
@@ -197,15 +239,13 @@ impl EarlyDocLinkResolver<'_, '_> {
197
239
&& module_id. is_local ( )
198
240
{
199
241
if let Some ( def_id) = child. res . opt_def_id ( ) && !def_id. is_local ( ) {
200
- // FIXME: Need to resolve doc links on all these extern items
201
- // reached through reexports.
202
242
let scope_id = match child. res {
203
243
Res :: Def ( DefKind :: Variant , ..) => self . resolver . parent ( def_id) . unwrap ( ) ,
204
244
_ => def_id,
205
245
} ;
206
- self . add_traits_in_parent_scope ( scope_id) ; // Outer attribute scope
246
+ self . resolve_doc_links_extern_outer ( def_id , scope_id, false ) ; // Outer attribute scope
207
247
if let Res :: Def ( DefKind :: Mod , ..) = child. res {
208
- self . add_traits_in_scope ( def_id) ; // Inner attribute scope
248
+ self . resolve_doc_links_extern_inner ( def_id) ; // Inner attribute scope
209
249
}
210
250
// Traits are processed in `add_extern_traits_in_scope`.
211
251
if let Res :: Def ( DefKind :: Mod | DefKind :: Enum , ..) = child. res {
@@ -219,10 +259,10 @@ impl EarlyDocLinkResolver<'_, '_> {
219
259
220
260
impl Visitor < ' _ > for EarlyDocLinkResolver < ' _ , ' _ > {
221
261
fn visit_item ( & mut self , item : & ast:: Item ) {
222
- self . load_links_in_attrs ( & item. attrs ) ; // Outer attribute scope
262
+ self . resolve_doc_links_local ( & item. attrs ) ; // Outer attribute scope
223
263
if let ItemKind :: Mod ( ..) = item. kind {
224
264
let old_mod = mem:: replace ( & mut self . current_mod , self . resolver . local_def_id ( item. id ) ) ;
225
- self . load_links_in_attrs ( & item. attrs ) ; // Inner attribute scope
265
+ self . resolve_doc_links_local ( & item. attrs ) ; // Inner attribute scope
226
266
self . process_module_children_or_reexports ( self . current_mod . to_def_id ( ) ) ;
227
267
visit:: walk_item ( self , item) ;
228
268
self . current_mod = old_mod;
@@ -241,22 +281,22 @@ impl Visitor<'_> for EarlyDocLinkResolver<'_, '_> {
241
281
}
242
282
243
283
fn visit_assoc_item ( & mut self , item : & ast:: AssocItem , ctxt : AssocCtxt ) {
244
- self . load_links_in_attrs ( & item. attrs ) ;
284
+ self . resolve_doc_links_local ( & item. attrs ) ;
245
285
visit:: walk_assoc_item ( self , item, ctxt)
246
286
}
247
287
248
288
fn visit_foreign_item ( & mut self , item : & ast:: ForeignItem ) {
249
- self . load_links_in_attrs ( & item. attrs ) ;
289
+ self . resolve_doc_links_local ( & item. attrs ) ;
250
290
visit:: walk_foreign_item ( self , item)
251
291
}
252
292
253
293
fn visit_variant ( & mut self , v : & ast:: Variant ) {
254
- self . load_links_in_attrs ( & v. attrs ) ;
294
+ self . resolve_doc_links_local ( & v. attrs ) ;
255
295
visit:: walk_variant ( self , v)
256
296
}
257
297
258
298
fn visit_field_def ( & mut self , field : & ast:: FieldDef ) {
259
- self . load_links_in_attrs ( & field. attrs ) ;
299
+ self . resolve_doc_links_local ( & field. attrs ) ;
260
300
visit:: walk_field_def ( self , field)
261
301
}
262
302
0 commit comments