11use crate :: clean:: Attributes ;
22use crate :: core:: ResolverCaches ;
33use 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 } ;
55
66use rustc_ast:: visit:: { self , AssocCtxt , Visitor } ;
77use rustc_ast:: { self as ast, ItemKind } ;
88use rustc_ast_lowering:: ResolverAstLowering ;
99use rustc_data_structures:: fx:: FxHashMap ;
1010use rustc_hir:: def:: Namespace :: * ;
1111use 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 } ;
1313use rustc_hir:: TraitCandidate ;
1414use rustc_middle:: ty:: { DefIdTree , Visibility } ;
1515use rustc_resolve:: { ParentScope , Resolver } ;
1616use rustc_session:: config:: Externs ;
1717use rustc_session:: Session ;
18+ use rustc_span:: symbol:: sym;
1819use rustc_span:: { Symbol , SyntaxContext } ;
1920
2021use std:: collections:: hash_map:: Entry ;
@@ -27,10 +28,12 @@ crate fn early_resolve_intra_doc_links(
2728 externs : Externs ,
2829 document_private_items : bool ,
2930) -> ResolverCaches {
31+ let parent_scope =
32+ ParentScope :: module ( resolver. expect_module ( CRATE_DEF_ID . to_def_id ( ) ) , resolver) ;
3033 let mut link_resolver = EarlyDocLinkResolver {
3134 resolver,
3235 sess,
33- current_mod : CRATE_DEF_ID ,
36+ parent_scope ,
3437 visited_mods : Default :: default ( ) ,
3538 markdown_links : Default :: default ( ) ,
3639 doc_link_resolutions : Default :: default ( ) ,
@@ -52,7 +55,7 @@ crate fn early_resolve_intra_doc_links(
5255 // DO NOT REMOVE THIS without first testing on the reproducer in
5356 // https://github.com/jyn514/objr/commit/edcee7b8124abf0e4c63873e8422ff81beb11ebb
5457 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 ) ;
5659 }
5760
5861 ResolverCaches {
@@ -72,7 +75,7 @@ fn doc_attrs<'a>(attrs: impl Iterator<Item = &'a ast::Attribute>) -> Attributes
7275struct EarlyDocLinkResolver < ' r , ' ra > {
7376 resolver : & ' r mut Resolver < ' ra > ,
7477 sess : & ' r Session ,
75- current_mod : LocalDefId ,
78+ parent_scope : ParentScope < ' ra > ,
7679 visited_mods : DefIdSet ,
7780 markdown_links : FxHashMap < String , Vec < PreprocessedMarkdownLink > > ,
7881 doc_link_resolutions : FxHashMap < ( Symbol , Namespace , DefId ) , Option < Res < ast:: NodeId > > > ,
@@ -82,7 +85,7 @@ struct EarlyDocLinkResolver<'r, 'ra> {
8285 document_private_items : bool ,
8386}
8487
85- impl EarlyDocLinkResolver < ' _ , ' _ > {
88+ impl < ' ra > EarlyDocLinkResolver < ' _ , ' ra > {
8689 fn add_traits_in_scope ( & mut self , def_id : DefId ) {
8790 // Calls to `traits_in_scope` are expensive, so try to avoid them if only possible.
8891 // Keys in the `traits_in_scope` cache are always module IDs.
@@ -205,34 +208,64 @@ impl EarlyDocLinkResolver<'_, '_> {
205208 if !attrs. iter ( ) . any ( |attr| attr. may_have_doc_links ( ) ) {
206209 return ;
207210 }
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 ) ;
210212 }
211213
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 > ) {
213231 let mut need_traits_in_scope = false ;
214232 for ( doc_module, doc) in attrs. prepare_to_doc_link_resolution ( ) {
215233 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) ) ;
220237 for PreprocessedMarkdownLink ( pp_link, _) in links {
221238 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+ }
230262 }
231263 }
264+ self . markdown_links = tmp_links;
232265 }
233266
234267 if need_traits_in_scope {
235- self . add_traits_in_scope ( module_id ) ;
268+ self . add_traits_in_scope ( parent_scope . module . def_id ( ) ) ;
236269 }
237270 }
238271
@@ -274,19 +307,33 @@ impl Visitor<'_> for EarlyDocLinkResolver<'_, '_> {
274307 fn visit_item ( & mut self , item : & ast:: Item ) {
275308 self . resolve_doc_links_local ( & item. attrs ) ; // Outer attribute scope
276309 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 ;
278314 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 ) ;
280316 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;
282325 } else {
283- match item. kind {
326+ match & item. kind {
284327 ItemKind :: Trait ( ..) => {
285328 self . all_traits . push ( self . resolver . local_def_id ( item. id ) . to_def_id ( ) ) ;
286329 }
287330 ItemKind :: Impl ( box ast:: Impl { of_trait : Some ( ..) , .. } ) => {
288331 self . all_trait_impls . push ( self . resolver . local_def_id ( item. id ) . to_def_id ( ) ) ;
289332 }
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+ }
290337 _ => { }
291338 }
292339 visit:: walk_item ( self , item) ;
@@ -313,6 +360,12 @@ impl Visitor<'_> for EarlyDocLinkResolver<'_, '_> {
313360 visit:: walk_field_def ( self , field)
314361 }
315362
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+
316369 // NOTE: if doc-comments are ever allowed on other nodes (e.g. function parameters),
317370 // then this will have to implement other visitor methods too.
318371}
0 commit comments