rustdoc: Keep full ParentScope during early doc link resolution

This commit is contained in:
Vadim Petrochenkov 2022-04-27 22:51:44 +03:00
parent 921f63fb1f
commit 044e45c595
3 changed files with 36 additions and 30 deletions

View File

@ -143,7 +143,7 @@ enum ScopeSet<'a> {
/// but not for late resolution yet. /// but not for late resolution yet.
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub struct ParentScope<'a> { pub struct ParentScope<'a> {
module: Module<'a>, pub module: Module<'a>,
expansion: LocalExpnId, expansion: LocalExpnId,
macro_rules: MacroRulesScopeRef<'a>, macro_rules: MacroRulesScopeRef<'a>,
derives: &'a [ast::Path], derives: &'a [ast::Path],
@ -1874,25 +1874,25 @@ impl<'a> Resolver<'a> {
&mut self, &mut self,
path_str: &str, path_str: &str,
ns: Namespace, ns: Namespace,
mut module_id: DefId, mut parent_scope: ParentScope<'a>,
) -> Option<Res> { ) -> Option<Res> {
let mut segments = let mut segments =
Vec::from_iter(path_str.split("::").map(Ident::from_str).map(Segment::from_ident)); Vec::from_iter(path_str.split("::").map(Ident::from_str).map(Segment::from_ident));
if let Some(segment) = segments.first_mut() { if let Some(segment) = segments.first_mut() {
if segment.ident.name == kw::Crate { if segment.ident.name == kw::Crate {
// FIXME: `resolve_path` always resolves `crate` to the current crate root, but // FIXME: `resolve_path` always resolves `crate` to the current crate root, but
// rustdoc wants it to resolve to the `module_id`'s crate root. This trick of // rustdoc wants it to resolve to the `parent_scope`'s crate root. This trick of
// replacing `crate` with `self` and changing the current module should achieve // replacing `crate` with `self` and changing the current module should achieve
// the same effect. // the same effect.
segment.ident.name = kw::SelfLower; segment.ident.name = kw::SelfLower;
module_id = module_id.krate.as_def_id(); parent_scope.module =
self.expect_module(parent_scope.module.def_id().krate.as_def_id());
} else if segment.ident.name == kw::Empty { } else if segment.ident.name == kw::Empty {
segment.ident.name = kw::PathRoot; segment.ident.name = kw::PathRoot;
} }
} }
let module = self.expect_module(module_id); match self.maybe_resolve_path(&segments, Some(ns), &parent_scope) {
match self.maybe_resolve_path(&segments, Some(ns), &ParentScope::module(module, self)) {
PathResult::Module(ModuleOrUniformRoot::Module(module)) => Some(module.res().unwrap()), PathResult::Module(ModuleOrUniformRoot::Module(module)) => Some(module.res().unwrap()),
PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => { PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => {
Some(path_res.base_res()) Some(path_res.base_res())
@ -1904,11 +1904,6 @@ impl<'a> Resolver<'a> {
} }
} }
// For rustdoc.
pub fn graph_root(&self) -> Module<'a> {
self.graph_root
}
// For rustdoc. // For rustdoc.
pub fn take_all_macro_rules(&mut self) -> FxHashMap<Symbol, Res> { pub fn take_all_macro_rules(&mut self) -> FxHashMap<Symbol, Res> {
mem::take(&mut self.all_macro_rules) mem::take(&mut self.all_macro_rules)

View File

@ -12,6 +12,7 @@ use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
use rustc_hir::Mutability; use rustc_hir::Mutability;
use rustc_middle::ty::{DefIdTree, Ty, TyCtxt}; use rustc_middle::ty::{DefIdTree, Ty, TyCtxt};
use rustc_middle::{bug, span_bug, ty}; use rustc_middle::{bug, span_bug, ty};
use rustc_resolve::ParentScope;
use rustc_session::lint::Lint; use rustc_session::lint::Lint;
use rustc_span::hygiene::MacroKind; use rustc_span::hygiene::MacroKind;
use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::symbol::{sym, Ident, Symbol};
@ -564,7 +565,9 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
.copied() .copied()
.unwrap_or_else(|| { .unwrap_or_else(|| {
self.cx.enter_resolver(|resolver| { self.cx.enter_resolver(|resolver| {
resolver.resolve_rustdoc_path(path_str, ns, module_id) let parent_scope =
ParentScope::module(resolver.expect_module(module_id), resolver);
resolver.resolve_rustdoc_path(path_str, ns, parent_scope)
}) })
}) })
.and_then(|res| res.try_into().ok()) .and_then(|res| res.try_into().ok())

View File

@ -9,7 +9,7 @@ use rustc_ast_lowering::ResolverAstLowering;
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def::Namespace::*; use rustc_hir::def::Namespace::*;
use rustc_hir::def::{DefKind, Namespace, Res}; use rustc_hir::def::{DefKind, Namespace, Res};
use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LocalDefId, CRATE_DEF_ID}; use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, CRATE_DEF_ID};
use rustc_hir::TraitCandidate; use rustc_hir::TraitCandidate;
use rustc_middle::ty::{DefIdTree, Visibility}; use rustc_middle::ty::{DefIdTree, Visibility};
use rustc_resolve::{ParentScope, Resolver}; use rustc_resolve::{ParentScope, Resolver};
@ -27,10 +27,12 @@ crate fn early_resolve_intra_doc_links(
externs: Externs, externs: Externs,
document_private_items: bool, document_private_items: bool,
) -> ResolverCaches { ) -> ResolverCaches {
let parent_scope =
ParentScope::module(resolver.expect_module(CRATE_DEF_ID.to_def_id()), resolver);
let mut link_resolver = EarlyDocLinkResolver { let mut link_resolver = EarlyDocLinkResolver {
resolver, resolver,
sess, sess,
current_mod: CRATE_DEF_ID, parent_scope,
visited_mods: Default::default(), visited_mods: Default::default(),
markdown_links: Default::default(), markdown_links: Default::default(),
doc_link_resolutions: Default::default(), doc_link_resolutions: Default::default(),
@ -52,7 +54,7 @@ crate fn early_resolve_intra_doc_links(
// DO NOT REMOVE THIS without first testing on the reproducer in // DO NOT REMOVE THIS without first testing on the reproducer in
// https://github.com/jyn514/objr/commit/edcee7b8124abf0e4c63873e8422ff81beb11ebb // https://github.com/jyn514/objr/commit/edcee7b8124abf0e4c63873e8422ff81beb11ebb
for (extern_name, _) in externs.iter().filter(|(_, entry)| entry.add_prelude) { for (extern_name, _) in externs.iter().filter(|(_, entry)| entry.add_prelude) {
link_resolver.resolver.resolve_rustdoc_path(extern_name, TypeNS, CRATE_DEF_ID.to_def_id()); link_resolver.resolver.resolve_rustdoc_path(extern_name, TypeNS, parent_scope);
} }
ResolverCaches { ResolverCaches {
@ -72,7 +74,7 @@ fn doc_attrs<'a>(attrs: impl Iterator<Item = &'a ast::Attribute>) -> Attributes
struct EarlyDocLinkResolver<'r, 'ra> { struct EarlyDocLinkResolver<'r, 'ra> {
resolver: &'r mut Resolver<'ra>, resolver: &'r mut Resolver<'ra>,
sess: &'r Session, sess: &'r Session,
current_mod: LocalDefId, parent_scope: ParentScope<'ra>,
visited_mods: DefIdSet, visited_mods: DefIdSet,
markdown_links: FxHashMap<String, Vec<PreprocessedMarkdownLink>>, markdown_links: FxHashMap<String, Vec<PreprocessedMarkdownLink>>,
doc_link_resolutions: FxHashMap<(Symbol, Namespace, DefId), Option<Res<ast::NodeId>>>, doc_link_resolutions: FxHashMap<(Symbol, Namespace, DefId), Option<Res<ast::NodeId>>>,
@ -82,7 +84,7 @@ struct EarlyDocLinkResolver<'r, 'ra> {
document_private_items: bool, document_private_items: bool,
} }
impl EarlyDocLinkResolver<'_, '_> { impl<'ra> EarlyDocLinkResolver<'_, 'ra> {
fn add_traits_in_scope(&mut self, def_id: DefId) { fn add_traits_in_scope(&mut self, def_id: DefId) {
// Calls to `traits_in_scope` are expensive, so try to avoid them if only possible. // Calls to `traits_in_scope` are expensive, so try to avoid them if only possible.
// Keys in the `traits_in_scope` cache are always module IDs. // Keys in the `traits_in_scope` cache are always module IDs.
@ -205,20 +207,24 @@ impl EarlyDocLinkResolver<'_, '_> {
if !attrs.iter().any(|attr| attr.may_have_doc_links()) { if !attrs.iter().any(|attr| attr.may_have_doc_links()) {
return; return;
} }
let module_id = self.current_mod.to_def_id(); self.resolve_doc_links(doc_attrs(attrs.iter()), self.parent_scope);
self.resolve_doc_links(doc_attrs(attrs.iter()), module_id);
} }
fn resolve_and_cache(&mut self, path_str: &str, ns: Namespace, module_id: DefId) -> bool { fn resolve_and_cache(
&mut self,
path_str: &str,
ns: Namespace,
parent_scope: &ParentScope<'ra>,
) -> bool {
self.doc_link_resolutions self.doc_link_resolutions
.entry((Symbol::intern(path_str), ns, module_id)) .entry((Symbol::intern(path_str), ns, parent_scope.module.def_id()))
.or_insert_with_key(|(path, ns, module_id)| { .or_insert_with_key(|(path, ns, _)| {
self.resolver.resolve_rustdoc_path(path.as_str(), *ns, *module_id) self.resolver.resolve_rustdoc_path(path.as_str(), *ns, *parent_scope)
}) })
.is_some() .is_some()
} }
fn resolve_doc_links(&mut self, attrs: Attributes, module_id: DefId) { fn resolve_doc_links(&mut self, attrs: Attributes, parent_scope: ParentScope<'ra>) {
let mut need_traits_in_scope = false; let mut need_traits_in_scope = false;
for (doc_module, doc) in attrs.prepare_to_doc_link_resolution() { for (doc_module, doc) in attrs.prepare_to_doc_link_resolution() {
assert_eq!(doc_module, None); assert_eq!(doc_module, None);
@ -230,7 +236,7 @@ impl EarlyDocLinkResolver<'_, '_> {
// The logic here is a conservative approximation for path resolution in // The logic here is a conservative approximation for path resolution in
// `resolve_with_disambiguator`. // `resolve_with_disambiguator`.
if let Some(ns) = pinfo.disambiguator.map(Disambiguator::ns) { if let Some(ns) = pinfo.disambiguator.map(Disambiguator::ns) {
if self.resolve_and_cache(&pinfo.path_str, ns, module_id) { if self.resolve_and_cache(&pinfo.path_str, ns, &parent_scope) {
continue; continue;
} }
} }
@ -239,7 +245,7 @@ impl EarlyDocLinkResolver<'_, '_> {
let mut any_resolved = false; let mut any_resolved = false;
let mut need_assoc = false; let mut need_assoc = false;
for ns in [TypeNS, ValueNS, MacroNS] { for ns in [TypeNS, ValueNS, MacroNS] {
if self.resolve_and_cache(&pinfo.path_str, ns, module_id) { if self.resolve_and_cache(&pinfo.path_str, ns, &parent_scope) {
any_resolved = true; any_resolved = true;
} else if ns != MacroNS { } else if ns != MacroNS {
need_assoc = true; need_assoc = true;
@ -256,7 +262,7 @@ impl EarlyDocLinkResolver<'_, '_> {
} }
if need_traits_in_scope { if need_traits_in_scope {
self.add_traits_in_scope(module_id); self.add_traits_in_scope(parent_scope.module.def_id());
} }
} }
@ -298,11 +304,13 @@ impl Visitor<'_> for EarlyDocLinkResolver<'_, '_> {
fn visit_item(&mut self, item: &ast::Item) { fn visit_item(&mut self, item: &ast::Item) {
self.resolve_doc_links_local(&item.attrs); // Outer attribute scope self.resolve_doc_links_local(&item.attrs); // Outer attribute scope
if let ItemKind::Mod(..) = item.kind { if let ItemKind::Mod(..) = item.kind {
let old_mod = mem::replace(&mut self.current_mod, self.resolver.local_def_id(item.id)); let module_def_id = self.resolver.local_def_id(item.id).to_def_id();
let module = self.resolver.expect_module(module_def_id);
let old_module = mem::replace(&mut self.parent_scope.module, module);
self.resolve_doc_links_local(&item.attrs); // Inner attribute scope self.resolve_doc_links_local(&item.attrs); // Inner attribute scope
self.process_module_children_or_reexports(self.current_mod.to_def_id()); self.process_module_children_or_reexports(module_def_id);
visit::walk_item(self, item); visit::walk_item(self, item);
self.current_mod = old_mod; self.parent_scope.module = old_module;
} else { } else {
match item.kind { match item.kind {
ItemKind::Trait(..) => { ItemKind::Trait(..) => {