mirror of
https://github.com/rust-lang/rust.git
synced 2024-10-31 06:22:00 +00:00
Skip doc link resolution for some crate types and non-exported items
This commit is contained in:
parent
3b0866272a
commit
da4ce6b41e
@ -24,13 +24,13 @@ use rustc_hir::{BindingAnnotation, PrimTy, TraitCandidate};
|
||||
use rustc_middle::middle::resolve_lifetime::Set1;
|
||||
use rustc_middle::ty::DefIdTree;
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_session::config::CrateType;
|
||||
use rustc_session::config::{CrateType, ResolveDocLinks};
|
||||
use rustc_session::lint;
|
||||
use rustc_span::source_map::{respan, Spanned};
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
use rustc_span::{BytePos, Span, SyntaxContext};
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
|
||||
use rustc_span::source_map::{respan, Spanned};
|
||||
use std::assert_matches::debug_assert_matches;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::{hash_map::Entry, BTreeSet};
|
||||
@ -494,6 +494,30 @@ impl<'a> PathSource<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// At this point for most items we can answer whether that item is exported or not,
|
||||
/// but some items like impls require type information to determine exported-ness, so we make a
|
||||
/// conservative estimate for them (e.g. based on nominal visibility).
|
||||
#[derive(Clone, Copy)]
|
||||
enum MaybeExported<'a> {
|
||||
Ok(NodeId),
|
||||
Impl(Option<DefId>),
|
||||
ImplItem(Result<DefId, &'a Visibility>),
|
||||
}
|
||||
|
||||
impl MaybeExported<'_> {
|
||||
fn eval(self, r: &Resolver<'_>) -> bool {
|
||||
let def_id = match self {
|
||||
MaybeExported::Ok(node_id) => Some(r.local_def_id(node_id)),
|
||||
MaybeExported::Impl(Some(trait_def_id)) | MaybeExported::ImplItem(Ok(trait_def_id)) => {
|
||||
trait_def_id.as_local()
|
||||
}
|
||||
MaybeExported::Impl(None) => return true,
|
||||
MaybeExported::ImplItem(Err(vis)) => return vis.kind.is_pub(),
|
||||
};
|
||||
def_id.map_or(true, |def_id| r.effective_visibilities.is_exported(def_id))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct DiagnosticMetadata<'ast> {
|
||||
/// The current trait's associated items' ident, used for diagnostic suggestions.
|
||||
@ -774,7 +798,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
|
||||
);
|
||||
}
|
||||
fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) {
|
||||
self.resolve_doc_links(&foreign_item.attrs);
|
||||
self.resolve_doc_links(&foreign_item.attrs, MaybeExported::Ok(foreign_item.id));
|
||||
match foreign_item.kind {
|
||||
ForeignItemKind::TyAlias(box TyAlias { ref generics, .. }) => {
|
||||
self.with_generic_param_rib(
|
||||
@ -1165,12 +1189,12 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
|
||||
}
|
||||
|
||||
fn visit_variant(&mut self, v: &'ast Variant) {
|
||||
self.resolve_doc_links(&v.attrs);
|
||||
self.resolve_doc_links(&v.attrs, MaybeExported::Ok(v.id));
|
||||
visit::walk_variant(self, v)
|
||||
}
|
||||
|
||||
fn visit_field_def(&mut self, f: &'ast FieldDef) {
|
||||
self.resolve_doc_links(&f.attrs);
|
||||
self.resolve_doc_links(&f.attrs, MaybeExported::Ok(f.id));
|
||||
visit::walk_field_def(self, f)
|
||||
}
|
||||
}
|
||||
@ -2201,8 +2225,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
fn resolve_item(&mut self, item: &'ast Item) {
|
||||
let mod_inner_docs =
|
||||
matches!(item.kind, ItemKind::Mod(..)) && rustdoc::inner_docs(&item.attrs);
|
||||
if !mod_inner_docs {
|
||||
self.resolve_doc_links(&item.attrs);
|
||||
if !mod_inner_docs && !matches!(item.kind, ItemKind::Impl(..)) {
|
||||
self.resolve_doc_links(&item.attrs, MaybeExported::Ok(item.id));
|
||||
}
|
||||
|
||||
let name = item.ident.name;
|
||||
@ -2249,7 +2273,14 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
..
|
||||
}) => {
|
||||
self.diagnostic_metadata.current_impl_items = Some(impl_items);
|
||||
self.resolve_implementation(generics, of_trait, &self_ty, item.id, impl_items);
|
||||
self.resolve_implementation(
|
||||
&item.attrs,
|
||||
generics,
|
||||
of_trait,
|
||||
&self_ty,
|
||||
item.id,
|
||||
impl_items,
|
||||
);
|
||||
self.diagnostic_metadata.current_impl_items = None;
|
||||
}
|
||||
|
||||
@ -2297,7 +2328,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
ItemKind::Mod(..) => {
|
||||
self.with_scope(item.id, |this| {
|
||||
if mod_inner_docs {
|
||||
this.resolve_doc_links(&item.attrs);
|
||||
this.resolve_doc_links(&item.attrs, MaybeExported::Ok(item.id));
|
||||
}
|
||||
let old_macro_rules = this.parent_scope.macro_rules;
|
||||
visit::walk_item(this, item);
|
||||
@ -2583,7 +2614,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
};
|
||||
|
||||
for item in trait_items {
|
||||
self.resolve_doc_links(&item.attrs);
|
||||
self.resolve_doc_links(&item.attrs, MaybeExported::Ok(item.id));
|
||||
match &item.kind {
|
||||
AssocItemKind::Const(_, ty, default) => {
|
||||
self.visit_ty(ty);
|
||||
@ -2671,6 +2702,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
|
||||
fn resolve_implementation(
|
||||
&mut self,
|
||||
attrs: &[ast::Attribute],
|
||||
generics: &'ast Generics,
|
||||
opt_trait_reference: &'ast Option<TraitRef>,
|
||||
self_type: &'ast Ty,
|
||||
@ -2701,6 +2733,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
opt_trait_reference.as_ref(),
|
||||
self_type,
|
||||
|this, trait_id| {
|
||||
this.resolve_doc_links(attrs, MaybeExported::Impl(trait_id));
|
||||
|
||||
let item_def_id = this.r.local_def_id(item_id);
|
||||
|
||||
// Register the trait definitions from here.
|
||||
@ -2734,7 +2768,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
debug!("resolve_implementation with_self_rib_ns(ValueNS, ...)");
|
||||
let mut seen_trait_items = Default::default();
|
||||
for item in impl_items {
|
||||
this.resolve_impl_item(&**item, &mut seen_trait_items);
|
||||
this.resolve_impl_item(&**item, &mut seen_trait_items, trait_id);
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -2752,9 +2786,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
&mut self,
|
||||
item: &'ast AssocItem,
|
||||
seen_trait_items: &mut FxHashMap<DefId, Span>,
|
||||
trait_id: Option<DefId>,
|
||||
) {
|
||||
use crate::ResolutionError::*;
|
||||
self.resolve_doc_links(&item.attrs);
|
||||
self.resolve_doc_links(&item.attrs, MaybeExported::ImplItem(trait_id.ok_or(&item.vis)));
|
||||
match &item.kind {
|
||||
AssocItemKind::Const(_, ty, default) => {
|
||||
debug!("resolve_implementation AssocItemKind::Const");
|
||||
@ -4183,7 +4218,23 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
res
|
||||
}
|
||||
|
||||
fn resolve_doc_links(&mut self, attrs: &[Attribute]) {
|
||||
fn resolve_doc_links(&mut self, attrs: &[Attribute], maybe_exported: MaybeExported<'_>) {
|
||||
match self.r.session.opts.resolve_doc_links {
|
||||
ResolveDocLinks::None => return,
|
||||
ResolveDocLinks::ExportedMetadata
|
||||
if !self.r.session.crate_types().iter().copied().any(CrateType::has_metadata)
|
||||
|| !maybe_exported.eval(self.r) =>
|
||||
{
|
||||
return;
|
||||
}
|
||||
ResolveDocLinks::Exported if !maybe_exported.eval(self.r) => {
|
||||
return;
|
||||
}
|
||||
ResolveDocLinks::ExportedMetadata
|
||||
| ResolveDocLinks::Exported
|
||||
| ResolveDocLinks::All => {}
|
||||
}
|
||||
|
||||
if !attrs.iter().any(|attr| attr.may_have_doc_links()) {
|
||||
return;
|
||||
}
|
||||
@ -4283,7 +4334,7 @@ impl<'a> Resolver<'a> {
|
||||
pub(crate) fn late_resolve_crate(&mut self, krate: &Crate) {
|
||||
visit::walk_crate(&mut LifetimeCountVisitor { r: self }, krate);
|
||||
let mut late_resolution_visitor = LateResolutionVisitor::new(self);
|
||||
late_resolution_visitor.resolve_doc_links(&krate.attrs);
|
||||
late_resolution_visitor.resolve_doc_links(&krate.attrs, MaybeExported::Ok(CRATE_NODE_ID));
|
||||
visit::walk_crate(&mut late_resolution_visitor, krate);
|
||||
for (id, span) in late_resolution_visitor.diagnostic_metadata.unused_labels.iter() {
|
||||
self.lint_buffer.buffer_lint(lint::builtin::UNUSED_LABELS, *id, *span, "unused label");
|
||||
|
@ -419,6 +419,18 @@ pub enum TrimmedDefPaths {
|
||||
GoodPath,
|
||||
}
|
||||
|
||||
#[derive(Clone, Hash)]
|
||||
pub enum ResolveDocLinks {
|
||||
/// Do not resolve doc links.
|
||||
None,
|
||||
/// Resolve doc links on exported items only for crate types that have metadata.
|
||||
ExportedMetadata,
|
||||
/// Resolve doc links on exported items.
|
||||
Exported,
|
||||
/// Resolve doc links on all items.
|
||||
All,
|
||||
}
|
||||
|
||||
/// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
|
||||
/// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
|
||||
/// dependency tracking for command-line arguments. Also only hash keys, since tracking
|
||||
@ -788,6 +800,7 @@ impl Default for Options {
|
||||
unstable_features: UnstableFeatures::Disallow,
|
||||
debug_assertions: true,
|
||||
actually_rustdoc: false,
|
||||
resolve_doc_links: ResolveDocLinks::None,
|
||||
trimmed_def_paths: TrimmedDefPaths::default(),
|
||||
cli_forced_codegen_units: None,
|
||||
cli_forced_local_thinlto_off: false,
|
||||
@ -883,6 +896,15 @@ pub enum CrateType {
|
||||
ProcMacro,
|
||||
}
|
||||
|
||||
impl CrateType {
|
||||
pub fn has_metadata(self) -> bool {
|
||||
match self {
|
||||
CrateType::Rlib | CrateType::Dylib | CrateType::ProcMacro => true,
|
||||
CrateType::Executable | CrateType::Cdylib | CrateType::Staticlib => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Hash, Debug, PartialEq, Eq)]
|
||||
pub enum Passes {
|
||||
Some(Vec<String>),
|
||||
@ -2562,6 +2584,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
|
||||
libs,
|
||||
debug_assertions,
|
||||
actually_rustdoc: false,
|
||||
resolve_doc_links: ResolveDocLinks::ExportedMetadata,
|
||||
trimmed_def_paths: TrimmedDefPaths::default(),
|
||||
cli_forced_codegen_units: codegen_units,
|
||||
cli_forced_local_thinlto_off: disable_local_thinlto,
|
||||
@ -2825,8 +2848,9 @@ pub(crate) mod dep_tracking {
|
||||
use super::{
|
||||
BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, ErrorOutputType,
|
||||
InstrumentCoverage, InstrumentXRay, LdImpl, LinkerPluginLto, LocationDetail, LtoCli,
|
||||
OomStrategy, OptLevel, OutputType, OutputTypes, Passes, SourceFileHashAlgorithm,
|
||||
SplitDwarfKind, SwitchWithOptPath, SymbolManglingVersion, TraitSolver, TrimmedDefPaths,
|
||||
OomStrategy, OptLevel, OutputType, OutputTypes, Passes, ResolveDocLinks,
|
||||
SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath, SymbolManglingVersion,
|
||||
TraitSolver, TrimmedDefPaths,
|
||||
};
|
||||
use crate::lint;
|
||||
use crate::options::WasiExecModel;
|
||||
@ -2913,6 +2937,7 @@ pub(crate) mod dep_tracking {
|
||||
TargetTriple,
|
||||
Edition,
|
||||
LinkerPluginLto,
|
||||
ResolveDocLinks,
|
||||
SplitDebuginfo,
|
||||
SplitDwarfKind,
|
||||
StackProtector,
|
||||
|
@ -169,6 +169,8 @@ top_level_options!(
|
||||
/// is currently just a hack and will be removed eventually, so please
|
||||
/// try to not rely on this too much.
|
||||
actually_rustdoc: bool [TRACKED],
|
||||
/// Whether name resolver should resolve documentation links.
|
||||
resolve_doc_links: ResolveDocLinks [TRACKED],
|
||||
|
||||
/// Control path trimming.
|
||||
trimmed_def_paths: TrimmedDefPaths [TRACKED],
|
||||
|
@ -12,7 +12,7 @@ use rustc_hir::{HirId, Path};
|
||||
use rustc_interface::interface;
|
||||
use rustc_middle::hir::nested_filter;
|
||||
use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
|
||||
use rustc_session::config::{self, CrateType, ErrorOutputType};
|
||||
use rustc_session::config::{self, CrateType, ErrorOutputType, ResolveDocLinks};
|
||||
use rustc_session::lint;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::symbol::sym;
|
||||
@ -200,6 +200,7 @@ pub(crate) fn create_config(
|
||||
scrape_examples_options,
|
||||
..
|
||||
}: RustdocOptions,
|
||||
RenderOptions { document_private, .. }: &RenderOptions,
|
||||
) -> rustc_interface::Config {
|
||||
// Add the doc cfg into the doc build.
|
||||
cfgs.push("doc".to_string());
|
||||
@ -227,6 +228,13 @@ 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 test = scrape_examples_options.map(|opts| opts.scrape_tests).unwrap_or(false);
|
||||
// plays with error output here!
|
||||
let sessopts = config::Options {
|
||||
@ -240,6 +248,7 @@ pub(crate) fn create_config(
|
||||
target_triple: target,
|
||||
unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
|
||||
actually_rustdoc: true,
|
||||
resolve_doc_links,
|
||||
unstable_opts,
|
||||
error_format,
|
||||
diagnostic_width,
|
||||
|
@ -742,7 +742,7 @@ fn main_args(at_args: &[String]) -> MainResult {
|
||||
(false, true) => {
|
||||
let input = options.input.clone();
|
||||
let edition = options.edition;
|
||||
let config = core::create_config(options);
|
||||
let config = core::create_config(options, &render_options);
|
||||
|
||||
// `markdown::render` can invoke `doctest::make_test`, which
|
||||
// requires session globals and a thread pool, so we use
|
||||
@ -775,7 +775,7 @@ fn main_args(at_args: &[String]) -> MainResult {
|
||||
let scrape_examples_options = options.scrape_examples_options.clone();
|
||||
let bin_crate = options.bin_crate;
|
||||
|
||||
let config = core::create_config(options);
|
||||
let config = core::create_config(options, &render_options);
|
||||
|
||||
interface::run_compiler(config, |compiler| {
|
||||
let sess = compiler.session();
|
||||
|
Loading…
Reference in New Issue
Block a user