From bec4eab3f972495df32b4861a3117ef16d73a018 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 11 Feb 2023 19:14:25 +0400 Subject: [PATCH] rustdoc: Skip doc link resolution for non-exported items --- compiler/rustc_resolve/src/late.rs | 5 ++++- compiler/rustc_resolve/src/rustdoc.rs | 16 +++++++++++++++- src/librustdoc/core.rs | 9 ++------- src/librustdoc/passes/collect_intra_doc_links.rs | 13 +++++++++++-- .../intra-doc/reachable-non-exported.rs | 13 +++++++++++++ 5 files changed, 45 insertions(+), 11 deletions(-) create mode 100644 tests/rustdoc-ui/intra-doc/reachable-non-exported.rs diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 6af9dc89e569..4ca54bab31a6 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -4236,7 +4236,10 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { { return; } - ResolveDocLinks::Exported if !maybe_exported.eval(self.r) => { + ResolveDocLinks::Exported + if !maybe_exported.eval(self.r) + && !rustdoc::has_primitive_or_keyword_docs(attrs) => + { return; } ResolveDocLinks::ExportedMetadata diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index 0e40f794f186..44a27bbc175e 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -3,7 +3,7 @@ use rustc_ast as ast; use rustc_ast::util::comments::beautify_doc_string; use rustc_data_structures::fx::FxHashMap; use rustc_span::def_id::DefId; -use rustc_span::symbol::{kw, Symbol}; +use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; use std::{cmp, mem}; @@ -339,6 +339,20 @@ pub fn inner_docs(attrs: &[ast::Attribute]) -> bool { attrs.iter().find(|a| a.doc_str().is_some()).map_or(true, |a| a.style == ast::AttrStyle::Inner) } +/// Has `#[doc(primitive)]` or `#[doc(keyword)]`. +pub fn has_primitive_or_keyword_docs(attrs: &[ast::Attribute]) -> bool { + for attr in attrs { + if attr.has_name(sym::doc) && let Some(items) = attr.meta_item_list() { + for item in items { + if item.has_name(sym::primitive) || item.has_name(sym::keyword) { + return true; + } + } + } + } + false +} + /// Simplified version of the corresponding function in rustdoc. /// If the rustdoc version returns a successful result, this function must return the same result. /// Otherwise this function may return anything. diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index fbfc58a436b9..28458f329036 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -217,13 +217,8 @@ pub(crate) fn create_config( let crate_types = if proc_macro_crate { vec![CrateType::ProcMacro] } else { vec![CrateType::Rlib] }; - let resolve_doc_links = if *document_private { - ResolveDocLinks::All - } else { - // Should be `ResolveDocLinks::Exported` in theory, but for some reason rustdoc - // still tries to request resolutions for links on private items. - ResolveDocLinks::All - }; + let resolve_doc_links = + if *document_private { ResolveDocLinks::All } else { ResolveDocLinks::Exported }; let test = scrape_examples_options.map(|opts| opts.scrape_tests).unwrap_or(false); // plays with error output here! let sessopts = config::Options { diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 789523c561e5..d98cf251e971 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -15,8 +15,8 @@ use rustc_hir::def_id::{DefId, CRATE_DEF_ID}; use rustc_hir::Mutability; use rustc_middle::ty::{fast_reject::TreatProjections, Ty, TyCtxt}; use rustc_middle::{bug, ty}; -use rustc_resolve::rustdoc::MalformedGenerics; -use rustc_resolve::rustdoc::{prepare_to_doc_link_resolution, strip_generics_from_path}; +use rustc_resolve::rustdoc::{has_primitive_or_keyword_docs, prepare_to_doc_link_resolution}; +use rustc_resolve::rustdoc::{strip_generics_from_path, MalformedGenerics}; use rustc_session::lint::Lint; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{sym, Ident, Symbol}; @@ -899,6 +899,15 @@ fn preprocessed_markdown_links(s: &str) -> Vec { impl LinkCollector<'_, '_> { fn resolve_links(&mut self, item: &Item) { + if !self.cx.render_options.document_private + && let Some(def_id) = item.item_id.as_def_id() + && let Some(def_id) = def_id.as_local() + && !self.cx.tcx.effective_visibilities(()).is_exported(def_id) + && !has_primitive_or_keyword_docs(&item.attrs.other_attrs) { + // Skip link resolution for non-exported items. + return; + } + // We want to resolve in the lexical scope of the documentation. // In the presence of re-exports, this is not the same as the module of the item. // Rather than merging all documentation into one, resolve it one attribute at a time diff --git a/tests/rustdoc-ui/intra-doc/reachable-non-exported.rs b/tests/rustdoc-ui/intra-doc/reachable-non-exported.rs new file mode 100644 index 000000000000..6afcad4f9211 --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/reachable-non-exported.rs @@ -0,0 +1,13 @@ +// The structure is reachable, but not exported, so rustdoc +// doesn't attempt to request doc link resolutions on it. + +// check-pass + +mod private { + /// [core::str::FromStr] + pub struct ReachableButNotExported; +} + +pub fn foo() -> private::ReachableButNotExported { + private::ReachableButNotExported +}