1
1
use crate :: clean:: Attributes ;
2
2
use crate :: core:: ResolverCaches ;
3
3
use crate :: passes:: collect_intra_doc_links:: preprocessed_markdown_links;
4
- use crate :: passes:: collect_intra_doc_links:: PreprocessedMarkdownLink ;
4
+ use crate :: passes:: collect_intra_doc_links:: { Disambiguator , PreprocessedMarkdownLink } ;
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
9
use rustc_data_structures:: fx:: FxHashMap ;
10
10
use rustc_hir:: def:: Namespace :: * ;
11
11
use rustc_hir:: def:: { DefKind , Namespace , Res } ;
12
- use rustc_hir:: def_id:: { DefId , DefIdMap , DefIdSet , LocalDefId , CRATE_DEF_ID } ;
12
+ use rustc_hir:: def_id:: { DefId , DefIdMap , DefIdSet , CRATE_DEF_ID } ;
13
13
use rustc_hir:: TraitCandidate ;
14
14
use rustc_middle:: ty:: { DefIdTree , Visibility } ;
15
15
use rustc_resolve:: { ParentScope , Resolver } ;
16
16
use rustc_session:: config:: Externs ;
17
17
use rustc_session:: Session ;
18
+ use rustc_span:: symbol:: sym;
18
19
use rustc_span:: { Symbol , SyntaxContext } ;
19
20
20
21
use std:: collections:: hash_map:: Entry ;
@@ -27,10 +28,12 @@ crate fn early_resolve_intra_doc_links(
27
28
externs : Externs ,
28
29
document_private_items : bool ,
29
30
) -> ResolverCaches {
31
+ let parent_scope =
32
+ ParentScope :: module ( resolver. expect_module ( CRATE_DEF_ID . to_def_id ( ) ) , resolver) ;
30
33
let mut link_resolver = EarlyDocLinkResolver {
31
34
resolver,
32
35
sess,
33
- current_mod : CRATE_DEF_ID ,
36
+ parent_scope ,
34
37
visited_mods : Default :: default ( ) ,
35
38
markdown_links : Default :: default ( ) ,
36
39
doc_link_resolutions : Default :: default ( ) ,
@@ -52,7 +55,7 @@ crate fn early_resolve_intra_doc_links(
52
55
// DO NOT REMOVE THIS without first testing on the reproducer in
53
56
// https://github.com/jyn514/objr/commit/edcee7b8124abf0e4c63873e8422ff81beb11ebb
54
57
for ( extern_name, _) in externs. iter ( ) . filter ( |( _, entry) | entry. add_prelude ) {
55
- link_resolver. resolver . resolve_rustdoc_path ( extern_name, TypeNS , CRATE_DEF_ID . to_def_id ( ) ) ;
58
+ link_resolver. resolver . resolve_rustdoc_path ( extern_name, TypeNS , parent_scope ) ;
56
59
}
57
60
58
61
ResolverCaches {
@@ -72,7 +75,7 @@ fn doc_attrs<'a>(attrs: impl Iterator<Item = &'a ast::Attribute>) -> Attributes
72
75
struct EarlyDocLinkResolver < ' r , ' ra > {
73
76
resolver : & ' r mut Resolver < ' ra > ,
74
77
sess : & ' r Session ,
75
- current_mod : LocalDefId ,
78
+ parent_scope : ParentScope < ' ra > ,
76
79
visited_mods : DefIdSet ,
77
80
markdown_links : FxHashMap < String , Vec < PreprocessedMarkdownLink > > ,
78
81
doc_link_resolutions : FxHashMap < ( Symbol , Namespace , DefId ) , Option < Res < ast:: NodeId > > > ,
@@ -82,7 +85,7 @@ struct EarlyDocLinkResolver<'r, 'ra> {
82
85
document_private_items : bool ,
83
86
}
84
87
85
- impl EarlyDocLinkResolver < ' _ , ' _ > {
88
+ impl < ' ra > EarlyDocLinkResolver < ' _ , ' ra > {
86
89
fn add_traits_in_scope ( & mut self , def_id : DefId ) {
87
90
// Calls to `traits_in_scope` are expensive, so try to avoid them if only possible.
88
91
// Keys in the `traits_in_scope` cache are always module IDs.
@@ -205,34 +208,64 @@ impl EarlyDocLinkResolver<'_, '_> {
205
208
if !attrs. iter ( ) . any ( |attr| attr. may_have_doc_links ( ) ) {
206
209
return ;
207
210
}
208
- let module_id = self . current_mod . to_def_id ( ) ;
209
- self . resolve_doc_links ( doc_attrs ( attrs. iter ( ) ) , module_id) ;
211
+ self . resolve_doc_links ( doc_attrs ( attrs. iter ( ) ) , self . parent_scope ) ;
210
212
}
211
213
212
- fn resolve_doc_links ( & mut self , attrs : Attributes , module_id : DefId ) {
214
+ fn resolve_and_cache (
215
+ & mut self ,
216
+ path_str : & str ,
217
+ ns : Namespace ,
218
+ parent_scope : & ParentScope < ' ra > ,
219
+ ) -> bool {
220
+ // FIXME: This caching may be incorrect in case of multiple `macro_rules`
221
+ // items with the same name in the same module.
222
+ self . doc_link_resolutions
223
+ . entry ( ( Symbol :: intern ( path_str) , ns, parent_scope. module . def_id ( ) ) )
224
+ . or_insert_with_key ( |( path, ns, _) | {
225
+ self . resolver . resolve_rustdoc_path ( path. as_str ( ) , * ns, * parent_scope)
226
+ } )
227
+ . is_some ( )
228
+ }
229
+
230
+ fn resolve_doc_links ( & mut self , attrs : Attributes , parent_scope : ParentScope < ' ra > ) {
213
231
let mut need_traits_in_scope = false ;
214
232
for ( doc_module, doc) in attrs. prepare_to_doc_link_resolution ( ) {
215
233
assert_eq ! ( doc_module, None ) ;
216
- let links = self
217
- . markdown_links
218
- . entry ( doc)
219
- . or_insert_with_key ( |doc| preprocessed_markdown_links ( doc) ) ;
234
+ let mut tmp_links = mem:: take ( & mut self . markdown_links ) ;
235
+ let links =
236
+ tmp_links. entry ( doc) . or_insert_with_key ( |doc| preprocessed_markdown_links ( doc) ) ;
220
237
for PreprocessedMarkdownLink ( pp_link, _) in links {
221
238
if let Ok ( pinfo) = pp_link {
222
- // FIXME: Resolve the path in all namespaces and resolve its prefixes too.
223
- let ns = TypeNS ;
224
- self . doc_link_resolutions
225
- . entry ( ( Symbol :: intern ( & pinfo. path_str ) , ns, module_id) )
226
- . or_insert_with_key ( |( path, ns, module_id) | {
227
- self . resolver . resolve_rustdoc_path ( path. as_str ( ) , * ns, * module_id)
228
- } ) ;
229
- need_traits_in_scope = true ;
239
+ // The logic here is a conservative approximation for path resolution in
240
+ // `resolve_with_disambiguator`.
241
+ if let Some ( ns) = pinfo. disambiguator . map ( Disambiguator :: ns) {
242
+ if self . resolve_and_cache ( & pinfo. path_str , ns, & parent_scope) {
243
+ continue ;
244
+ }
245
+ }
246
+
247
+ // Resolve all namespaces due to no disambiguator or for diagnostics.
248
+ let mut any_resolved = false ;
249
+ let mut need_assoc = false ;
250
+ for ns in [ TypeNS , ValueNS , MacroNS ] {
251
+ if self . resolve_and_cache ( & pinfo. path_str , ns, & parent_scope) {
252
+ any_resolved = true ;
253
+ } else if ns != MacroNS {
254
+ need_assoc = true ;
255
+ }
256
+ }
257
+
258
+ // FIXME: Resolve all prefixes for type-relative resolution or for diagnostics.
259
+ if ( need_assoc || !any_resolved) && pinfo. path_str . contains ( "::" ) {
260
+ need_traits_in_scope = true ;
261
+ }
230
262
}
231
263
}
264
+ self . markdown_links = tmp_links;
232
265
}
233
266
234
267
if need_traits_in_scope {
235
- self . add_traits_in_scope ( module_id ) ;
268
+ self . add_traits_in_scope ( parent_scope . module . def_id ( ) ) ;
236
269
}
237
270
}
238
271
@@ -274,19 +307,33 @@ impl Visitor<'_> for EarlyDocLinkResolver<'_, '_> {
274
307
fn visit_item ( & mut self , item : & ast:: Item ) {
275
308
self . resolve_doc_links_local ( & item. attrs ) ; // Outer attribute scope
276
309
if let ItemKind :: Mod ( ..) = item. kind {
277
- let old_mod = mem:: replace ( & mut self . current_mod , self . resolver . local_def_id ( item. id ) ) ;
310
+ let module_def_id = self . resolver . local_def_id ( item. id ) . to_def_id ( ) ;
311
+ let module = self . resolver . expect_module ( module_def_id) ;
312
+ let old_module = mem:: replace ( & mut self . parent_scope . module , module) ;
313
+ let old_macro_rules = self . parent_scope . macro_rules ;
278
314
self . resolve_doc_links_local ( & item. attrs ) ; // Inner attribute scope
279
- self . process_module_children_or_reexports ( self . current_mod . to_def_id ( ) ) ;
315
+ self . process_module_children_or_reexports ( module_def_id ) ;
280
316
visit:: walk_item ( self , item) ;
281
- self . current_mod = old_mod;
317
+ if item
318
+ . attrs
319
+ . iter ( )
320
+ . all ( |attr| !attr. has_name ( sym:: macro_use) && !attr. has_name ( sym:: macro_escape) )
321
+ {
322
+ self . parent_scope . macro_rules = old_macro_rules;
323
+ }
324
+ self . parent_scope . module = old_module;
282
325
} else {
283
- match item. kind {
326
+ match & item. kind {
284
327
ItemKind :: Trait ( ..) => {
285
328
self . all_traits . push ( self . resolver . local_def_id ( item. id ) . to_def_id ( ) ) ;
286
329
}
287
330
ItemKind :: Impl ( box ast:: Impl { of_trait : Some ( ..) , .. } ) => {
288
331
self . all_trait_impls . push ( self . resolver . local_def_id ( item. id ) . to_def_id ( ) ) ;
289
332
}
333
+ ItemKind :: MacroDef ( macro_def) if macro_def. macro_rules => {
334
+ self . parent_scope . macro_rules =
335
+ self . resolver . macro_rules_scope ( self . resolver . local_def_id ( item. id ) ) ;
336
+ }
290
337
_ => { }
291
338
}
292
339
visit:: walk_item ( self , item) ;
@@ -313,6 +360,12 @@ impl Visitor<'_> for EarlyDocLinkResolver<'_, '_> {
313
360
visit:: walk_field_def ( self , field)
314
361
}
315
362
363
+ fn visit_block ( & mut self , block : & ast:: Block ) {
364
+ let old_macro_rules = self . parent_scope . macro_rules ;
365
+ visit:: walk_block ( self , block) ;
366
+ self . parent_scope . macro_rules = old_macro_rules;
367
+ }
368
+
316
369
// NOTE: if doc-comments are ever allowed on other nodes (e.g. function parameters),
317
370
// then this will have to implement other visitor methods too.
318
371
}
0 commit comments