rustdoc: Collect rustdoc-reachable items during early doc link resolution
This commit is contained in:
parent
95b61d16d4
commit
957bc606dd
5 changed files with 83 additions and 6 deletions
|
@ -632,6 +632,12 @@ impl CStore {
|
||||||
.get_attr_flags(def_id.index)
|
.get_attr_flags(def_id.index)
|
||||||
.contains(AttrFlags::MAY_HAVE_DOC_LINKS)
|
.contains(AttrFlags::MAY_HAVE_DOC_LINKS)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_doc_hidden_untracked(&self, def_id: DefId) -> bool {
|
||||||
|
self.get_crate_data(def_id.krate)
|
||||||
|
.get_attr_flags(def_id.index)
|
||||||
|
.contains(AttrFlags::IS_DOC_HIDDEN)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CrateStore for CStore {
|
impl CrateStore for CStore {
|
||||||
|
|
|
@ -29,11 +29,6 @@ mod tests;
|
||||||
pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate {
|
pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate {
|
||||||
let module = crate::visit_ast::RustdocVisitor::new(cx).visit();
|
let module = crate::visit_ast::RustdocVisitor::new(cx).visit();
|
||||||
|
|
||||||
for &cnum in cx.tcx.crates(()) {
|
|
||||||
// Analyze doc-reachability for extern items
|
|
||||||
crate::visit_lib::lib_embargo_visit_item(cx, cnum.as_def_id());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clean the crate, translating the entire librustc_ast AST to one that is
|
// Clean the crate, translating the entire librustc_ast AST to one that is
|
||||||
// understood by rustdoc.
|
// understood by rustdoc.
|
||||||
let mut module = clean_doc_module(&module, cx);
|
let mut module = clean_doc_module(&module, cx);
|
||||||
|
|
|
@ -41,6 +41,7 @@ pub(crate) struct ResolverCaches {
|
||||||
pub(crate) traits_in_scope: DefIdMap<Vec<TraitCandidate>>,
|
pub(crate) traits_in_scope: DefIdMap<Vec<TraitCandidate>>,
|
||||||
pub(crate) all_trait_impls: Option<Vec<DefId>>,
|
pub(crate) all_trait_impls: Option<Vec<DefId>>,
|
||||||
pub(crate) all_macro_rules: FxHashMap<Symbol, Res<NodeId>>,
|
pub(crate) all_macro_rules: FxHashMap<Symbol, Res<NodeId>>,
|
||||||
|
pub(crate) extern_doc_reachable: DefIdSet,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct DocContext<'tcx> {
|
pub(crate) struct DocContext<'tcx> {
|
||||||
|
@ -363,6 +364,10 @@ pub(crate) fn run_global_ctxt(
|
||||||
show_coverage,
|
show_coverage,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ctxt.cache
|
||||||
|
.effective_visibilities
|
||||||
|
.init(mem::take(&mut ctxt.resolver_caches.extern_doc_reachable));
|
||||||
|
|
||||||
// Small hack to force the Sized trait to be present.
|
// Small hack to force the Sized trait to be present.
|
||||||
//
|
//
|
||||||
// Note that in case of `#![no_core]`, the trait is not available.
|
// Note that in case of `#![no_core]`, the trait is not available.
|
||||||
|
|
|
@ -2,6 +2,7 @@ use crate::clean::Attributes;
|
||||||
use crate::core::ResolverCaches;
|
use crate::core::ResolverCaches;
|
||||||
use crate::passes::collect_intra_doc_links::preprocessed_markdown_links;
|
use crate::passes::collect_intra_doc_links::preprocessed_markdown_links;
|
||||||
use crate::passes::collect_intra_doc_links::{Disambiguator, PreprocessedMarkdownLink};
|
use crate::passes::collect_intra_doc_links::{Disambiguator, PreprocessedMarkdownLink};
|
||||||
|
use crate::visit_lib::early_lib_embargo_visit_item;
|
||||||
|
|
||||||
use rustc_ast::visit::{self, AssocCtxt, Visitor};
|
use rustc_ast::visit::{self, AssocCtxt, Visitor};
|
||||||
use rustc_ast::{self as ast, ItemKind};
|
use rustc_ast::{self as ast, ItemKind};
|
||||||
|
@ -34,6 +35,8 @@ pub(crate) fn early_resolve_intra_doc_links(
|
||||||
traits_in_scope: Default::default(),
|
traits_in_scope: Default::default(),
|
||||||
all_trait_impls: Default::default(),
|
all_trait_impls: Default::default(),
|
||||||
all_macro_rules: Default::default(),
|
all_macro_rules: Default::default(),
|
||||||
|
extern_doc_reachable: Default::default(),
|
||||||
|
local_doc_reachable: Default::default(),
|
||||||
document_private_items,
|
document_private_items,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -61,6 +64,7 @@ pub(crate) fn early_resolve_intra_doc_links(
|
||||||
traits_in_scope: link_resolver.traits_in_scope,
|
traits_in_scope: link_resolver.traits_in_scope,
|
||||||
all_trait_impls: Some(link_resolver.all_trait_impls),
|
all_trait_impls: Some(link_resolver.all_trait_impls),
|
||||||
all_macro_rules: link_resolver.all_macro_rules,
|
all_macro_rules: link_resolver.all_macro_rules,
|
||||||
|
extern_doc_reachable: link_resolver.extern_doc_reachable,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,6 +81,15 @@ struct EarlyDocLinkResolver<'r, 'ra> {
|
||||||
traits_in_scope: DefIdMap<Vec<TraitCandidate>>,
|
traits_in_scope: DefIdMap<Vec<TraitCandidate>>,
|
||||||
all_trait_impls: Vec<DefId>,
|
all_trait_impls: Vec<DefId>,
|
||||||
all_macro_rules: FxHashMap<Symbol, Res<ast::NodeId>>,
|
all_macro_rules: FxHashMap<Symbol, Res<ast::NodeId>>,
|
||||||
|
/// This set is used as a seed for `effective_visibilities`, which are then extended by some
|
||||||
|
/// more items using `lib_embargo_visit_item` during doc inlining.
|
||||||
|
extern_doc_reachable: DefIdSet,
|
||||||
|
/// This is an easily identifiable superset of items added to `effective_visibilities`
|
||||||
|
/// using `lib_embargo_visit_item` during doc inlining.
|
||||||
|
/// The union of `(extern,local)_doc_reachable` is therefore a superset of
|
||||||
|
/// `effective_visibilities` and can be used for pruning extern impls here
|
||||||
|
/// in early doc link resolution.
|
||||||
|
local_doc_reachable: DefIdSet,
|
||||||
document_private_items: bool,
|
document_private_items: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,6 +127,14 @@ impl<'ra> EarlyDocLinkResolver<'_, 'ra> {
|
||||||
let mut start_cnum = 0;
|
let mut start_cnum = 0;
|
||||||
loop {
|
loop {
|
||||||
let crates = Vec::from_iter(self.resolver.cstore().crates_untracked());
|
let crates = Vec::from_iter(self.resolver.cstore().crates_untracked());
|
||||||
|
for cnum in &crates[start_cnum..] {
|
||||||
|
early_lib_embargo_visit_item(
|
||||||
|
self.resolver,
|
||||||
|
&mut self.extern_doc_reachable,
|
||||||
|
cnum.as_def_id(),
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
}
|
||||||
for &cnum in &crates[start_cnum..] {
|
for &cnum in &crates[start_cnum..] {
|
||||||
let all_trait_impls =
|
let all_trait_impls =
|
||||||
Vec::from_iter(self.resolver.cstore().trait_impls_in_crate_untracked(cnum));
|
Vec::from_iter(self.resolver.cstore().trait_impls_in_crate_untracked(cnum));
|
||||||
|
@ -298,6 +319,7 @@ impl<'ra> EarlyDocLinkResolver<'_, 'ra> {
|
||||||
&& module_id.is_local()
|
&& module_id.is_local()
|
||||||
{
|
{
|
||||||
if let Some(def_id) = child.res.opt_def_id() && !def_id.is_local() {
|
if let Some(def_id) = child.res.opt_def_id() && !def_id.is_local() {
|
||||||
|
self.local_doc_reachable.insert(def_id);
|
||||||
let scope_id = match child.res {
|
let scope_id = match child.res {
|
||||||
Res::Def(
|
Res::Def(
|
||||||
DefKind::Variant
|
DefKind::Variant
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
use crate::core::DocContext;
|
use crate::core::DocContext;
|
||||||
use rustc_hir::def::DefKind;
|
use rustc_hir::def::{DefKind, Res};
|
||||||
use rustc_hir::def_id::{DefId, DefIdSet};
|
use rustc_hir::def_id::{DefId, DefIdSet};
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
|
use rustc_resolve::Resolver;
|
||||||
|
|
||||||
// FIXME: this may not be exhaustive, but is sufficient for rustdocs current uses
|
// FIXME: this may not be exhaustive, but is sufficient for rustdocs current uses
|
||||||
|
|
||||||
|
@ -25,6 +26,10 @@ impl RustdocEffectiveVisibilities {
|
||||||
define_method!(is_directly_public);
|
define_method!(is_directly_public);
|
||||||
define_method!(is_exported);
|
define_method!(is_exported);
|
||||||
define_method!(is_reachable);
|
define_method!(is_reachable);
|
||||||
|
|
||||||
|
pub(crate) fn init(&mut self, extern_public: DefIdSet) {
|
||||||
|
self.extern_public = extern_public;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn lib_embargo_visit_item(cx: &mut DocContext<'_>, def_id: DefId) {
|
pub(crate) fn lib_embargo_visit_item(cx: &mut DocContext<'_>, def_id: DefId) {
|
||||||
|
@ -37,6 +42,17 @@ pub(crate) fn lib_embargo_visit_item(cx: &mut DocContext<'_>, def_id: DefId) {
|
||||||
.visit_item(def_id)
|
.visit_item(def_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn early_lib_embargo_visit_item(
|
||||||
|
resolver: &Resolver<'_>,
|
||||||
|
extern_public: &mut DefIdSet,
|
||||||
|
def_id: DefId,
|
||||||
|
is_mod: bool,
|
||||||
|
) {
|
||||||
|
assert!(!def_id.is_local());
|
||||||
|
EarlyLibEmbargoVisitor { resolver, extern_public, visited_mods: Default::default() }
|
||||||
|
.visit_item(def_id, is_mod)
|
||||||
|
}
|
||||||
|
|
||||||
/// Similar to `librustc_privacy::EmbargoVisitor`, but also takes
|
/// Similar to `librustc_privacy::EmbargoVisitor`, but also takes
|
||||||
/// specific rustdoc annotations into account (i.e., `doc(hidden)`)
|
/// specific rustdoc annotations into account (i.e., `doc(hidden)`)
|
||||||
struct LibEmbargoVisitor<'a, 'tcx> {
|
struct LibEmbargoVisitor<'a, 'tcx> {
|
||||||
|
@ -47,6 +63,14 @@ struct LibEmbargoVisitor<'a, 'tcx> {
|
||||||
visited_mods: DefIdSet,
|
visited_mods: DefIdSet,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct EarlyLibEmbargoVisitor<'r, 'ra> {
|
||||||
|
resolver: &'r Resolver<'ra>,
|
||||||
|
// Effective visibilities for reachable nodes
|
||||||
|
extern_public: &'r mut DefIdSet,
|
||||||
|
// Keeps track of already visited modules, in case a module re-exports its parent
|
||||||
|
visited_mods: DefIdSet,
|
||||||
|
}
|
||||||
|
|
||||||
impl LibEmbargoVisitor<'_, '_> {
|
impl LibEmbargoVisitor<'_, '_> {
|
||||||
fn visit_mod(&mut self, def_id: DefId) {
|
fn visit_mod(&mut self, def_id: DefId) {
|
||||||
if !self.visited_mods.insert(def_id) {
|
if !self.visited_mods.insert(def_id) {
|
||||||
|
@ -71,3 +95,28 @@ impl LibEmbargoVisitor<'_, '_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl EarlyLibEmbargoVisitor<'_, '_> {
|
||||||
|
fn visit_mod(&mut self, def_id: DefId) {
|
||||||
|
if !self.visited_mods.insert(def_id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for item in self.resolver.cstore().module_children_untracked(def_id, self.resolver.sess()) {
|
||||||
|
if let Some(def_id) = item.res.opt_def_id() {
|
||||||
|
if item.vis.is_public() {
|
||||||
|
self.visit_item(def_id, matches!(item.res, Res::Def(DefKind::Mod, _)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_item(&mut self, def_id: DefId, is_mod: bool) {
|
||||||
|
if !self.resolver.cstore().is_doc_hidden_untracked(def_id) {
|
||||||
|
self.extern_public.insert(def_id);
|
||||||
|
if is_mod {
|
||||||
|
self.visit_mod(def_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue