Skip to content

Commit da4ce6b

Browse files
committed
Skip doc link resolution for some crate types and non-exported items
1 parent 3b08662 commit da4ce6b

File tree

5 files changed

+106
-19
lines changed

5 files changed

+106
-19
lines changed

compiler/rustc_resolve/src/late.rs

+65-14
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@ use rustc_hir::{BindingAnnotation, PrimTy, TraitCandidate};
2424
use rustc_middle::middle::resolve_lifetime::Set1;
2525
use rustc_middle::ty::DefIdTree;
2626
use rustc_middle::{bug, span_bug};
27-
use rustc_session::config::CrateType;
27+
use rustc_session::config::{CrateType, ResolveDocLinks};
2828
use rustc_session::lint;
29+
use rustc_span::source_map::{respan, Spanned};
2930
use rustc_span::symbol::{kw, sym, Ident, Symbol};
3031
use rustc_span::{BytePos, Span, SyntaxContext};
3132
use smallvec::{smallvec, SmallVec};
3233

33-
use rustc_span::source_map::{respan, Spanned};
3434
use std::assert_matches::debug_assert_matches;
3535
use std::borrow::Cow;
3636
use std::collections::{hash_map::Entry, BTreeSet};
@@ -494,6 +494,30 @@ impl<'a> PathSource<'a> {
494494
}
495495
}
496496

497+
/// At this point for most items we can answer whether that item is exported or not,
498+
/// but some items like impls require type information to determine exported-ness, so we make a
499+
/// conservative estimate for them (e.g. based on nominal visibility).
500+
#[derive(Clone, Copy)]
501+
enum MaybeExported<'a> {
502+
Ok(NodeId),
503+
Impl(Option<DefId>),
504+
ImplItem(Result<DefId, &'a Visibility>),
505+
}
506+
507+
impl MaybeExported<'_> {
508+
fn eval(self, r: &Resolver<'_>) -> bool {
509+
let def_id = match self {
510+
MaybeExported::Ok(node_id) => Some(r.local_def_id(node_id)),
511+
MaybeExported::Impl(Some(trait_def_id)) | MaybeExported::ImplItem(Ok(trait_def_id)) => {
512+
trait_def_id.as_local()
513+
}
514+
MaybeExported::Impl(None) => return true,
515+
MaybeExported::ImplItem(Err(vis)) => return vis.kind.is_pub(),
516+
};
517+
def_id.map_or(true, |def_id| r.effective_visibilities.is_exported(def_id))
518+
}
519+
}
520+
497521
#[derive(Default)]
498522
struct DiagnosticMetadata<'ast> {
499523
/// 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> {
774798
);
775799
}
776800
fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) {
777-
self.resolve_doc_links(&foreign_item.attrs);
801+
self.resolve_doc_links(&foreign_item.attrs, MaybeExported::Ok(foreign_item.id));
778802
match foreign_item.kind {
779803
ForeignItemKind::TyAlias(box TyAlias { ref generics, .. }) => {
780804
self.with_generic_param_rib(
@@ -1165,12 +1189,12 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
11651189
}
11661190

11671191
fn visit_variant(&mut self, v: &'ast Variant) {
1168-
self.resolve_doc_links(&v.attrs);
1192+
self.resolve_doc_links(&v.attrs, MaybeExported::Ok(v.id));
11691193
visit::walk_variant(self, v)
11701194
}
11711195

11721196
fn visit_field_def(&mut self, f: &'ast FieldDef) {
1173-
self.resolve_doc_links(&f.attrs);
1197+
self.resolve_doc_links(&f.attrs, MaybeExported::Ok(f.id));
11741198
visit::walk_field_def(self, f)
11751199
}
11761200
}
@@ -2201,8 +2225,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
22012225
fn resolve_item(&mut self, item: &'ast Item) {
22022226
let mod_inner_docs =
22032227
matches!(item.kind, ItemKind::Mod(..)) && rustdoc::inner_docs(&item.attrs);
2204-
if !mod_inner_docs {
2205-
self.resolve_doc_links(&item.attrs);
2228+
if !mod_inner_docs && !matches!(item.kind, ItemKind::Impl(..)) {
2229+
self.resolve_doc_links(&item.attrs, MaybeExported::Ok(item.id));
22062230
}
22072231

22082232
let name = item.ident.name;
@@ -2249,7 +2273,14 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
22492273
..
22502274
}) => {
22512275
self.diagnostic_metadata.current_impl_items = Some(impl_items);
2252-
self.resolve_implementation(generics, of_trait, &self_ty, item.id, impl_items);
2276+
self.resolve_implementation(
2277+
&item.attrs,
2278+
generics,
2279+
of_trait,
2280+
&self_ty,
2281+
item.id,
2282+
impl_items,
2283+
);
22532284
self.diagnostic_metadata.current_impl_items = None;
22542285
}
22552286

@@ -2297,7 +2328,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
22972328
ItemKind::Mod(..) => {
22982329
self.with_scope(item.id, |this| {
22992330
if mod_inner_docs {
2300-
this.resolve_doc_links(&item.attrs);
2331+
this.resolve_doc_links(&item.attrs, MaybeExported::Ok(item.id));
23012332
}
23022333
let old_macro_rules = this.parent_scope.macro_rules;
23032334
visit::walk_item(this, item);
@@ -2583,7 +2614,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
25832614
};
25842615

25852616
for item in trait_items {
2586-
self.resolve_doc_links(&item.attrs);
2617+
self.resolve_doc_links(&item.attrs, MaybeExported::Ok(item.id));
25872618
match &item.kind {
25882619
AssocItemKind::Const(_, ty, default) => {
25892620
self.visit_ty(ty);
@@ -2671,6 +2702,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
26712702

26722703
fn resolve_implementation(
26732704
&mut self,
2705+
attrs: &[ast::Attribute],
26742706
generics: &'ast Generics,
26752707
opt_trait_reference: &'ast Option<TraitRef>,
26762708
self_type: &'ast Ty,
@@ -2701,6 +2733,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
27012733
opt_trait_reference.as_ref(),
27022734
self_type,
27032735
|this, trait_id| {
2736+
this.resolve_doc_links(attrs, MaybeExported::Impl(trait_id));
2737+
27042738
let item_def_id = this.r.local_def_id(item_id);
27052739

27062740
// Register the trait definitions from here.
@@ -2734,7 +2768,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
27342768
debug!("resolve_implementation with_self_rib_ns(ValueNS, ...)");
27352769
let mut seen_trait_items = Default::default();
27362770
for item in impl_items {
2737-
this.resolve_impl_item(&**item, &mut seen_trait_items);
2771+
this.resolve_impl_item(&**item, &mut seen_trait_items, trait_id);
27382772
}
27392773
});
27402774
});
@@ -2752,9 +2786,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
27522786
&mut self,
27532787
item: &'ast AssocItem,
27542788
seen_trait_items: &mut FxHashMap<DefId, Span>,
2789+
trait_id: Option<DefId>,
27552790
) {
27562791
use crate::ResolutionError::*;
2757-
self.resolve_doc_links(&item.attrs);
2792+
self.resolve_doc_links(&item.attrs, MaybeExported::ImplItem(trait_id.ok_or(&item.vis)));
27582793
match &item.kind {
27592794
AssocItemKind::Const(_, ty, default) => {
27602795
debug!("resolve_implementation AssocItemKind::Const");
@@ -4183,7 +4218,23 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
41834218
res
41844219
}
41854220

4186-
fn resolve_doc_links(&mut self, attrs: &[Attribute]) {
4221+
fn resolve_doc_links(&mut self, attrs: &[Attribute], maybe_exported: MaybeExported<'_>) {
4222+
match self.r.session.opts.resolve_doc_links {
4223+
ResolveDocLinks::None => return,
4224+
ResolveDocLinks::ExportedMetadata
4225+
if !self.r.session.crate_types().iter().copied().any(CrateType::has_metadata)
4226+
|| !maybe_exported.eval(self.r) =>
4227+
{
4228+
return;
4229+
}
4230+
ResolveDocLinks::Exported if !maybe_exported.eval(self.r) => {
4231+
return;
4232+
}
4233+
ResolveDocLinks::ExportedMetadata
4234+
| ResolveDocLinks::Exported
4235+
| ResolveDocLinks::All => {}
4236+
}
4237+
41874238
if !attrs.iter().any(|attr| attr.may_have_doc_links()) {
41884239
return;
41894240
}
@@ -4283,7 +4334,7 @@ impl<'a> Resolver<'a> {
42834334
pub(crate) fn late_resolve_crate(&mut self, krate: &Crate) {
42844335
visit::walk_crate(&mut LifetimeCountVisitor { r: self }, krate);
42854336
let mut late_resolution_visitor = LateResolutionVisitor::new(self);
4286-
late_resolution_visitor.resolve_doc_links(&krate.attrs);
4337+
late_resolution_visitor.resolve_doc_links(&krate.attrs, MaybeExported::Ok(CRATE_NODE_ID));
42874338
visit::walk_crate(&mut late_resolution_visitor, krate);
42884339
for (id, span) in late_resolution_visitor.diagnostic_metadata.unused_labels.iter() {
42894340
self.lint_buffer.buffer_lint(lint::builtin::UNUSED_LABELS, *id, *span, "unused label");

compiler/rustc_session/src/config.rs

+27-2
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,18 @@ pub enum TrimmedDefPaths {
419419
GoodPath,
420420
}
421421

422+
#[derive(Clone, Hash)]
423+
pub enum ResolveDocLinks {
424+
/// Do not resolve doc links.
425+
None,
426+
/// Resolve doc links on exported items only for crate types that have metadata.
427+
ExportedMetadata,
428+
/// Resolve doc links on exported items.
429+
Exported,
430+
/// Resolve doc links on all items.
431+
All,
432+
}
433+
422434
/// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
423435
/// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
424436
/// dependency tracking for command-line arguments. Also only hash keys, since tracking
@@ -788,6 +800,7 @@ impl Default for Options {
788800
unstable_features: UnstableFeatures::Disallow,
789801
debug_assertions: true,
790802
actually_rustdoc: false,
803+
resolve_doc_links: ResolveDocLinks::None,
791804
trimmed_def_paths: TrimmedDefPaths::default(),
792805
cli_forced_codegen_units: None,
793806
cli_forced_local_thinlto_off: false,
@@ -883,6 +896,15 @@ pub enum CrateType {
883896
ProcMacro,
884897
}
885898

899+
impl CrateType {
900+
pub fn has_metadata(self) -> bool {
901+
match self {
902+
CrateType::Rlib | CrateType::Dylib | CrateType::ProcMacro => true,
903+
CrateType::Executable | CrateType::Cdylib | CrateType::Staticlib => false,
904+
}
905+
}
906+
}
907+
886908
#[derive(Clone, Hash, Debug, PartialEq, Eq)]
887909
pub enum Passes {
888910
Some(Vec<String>),
@@ -2562,6 +2584,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
25622584
libs,
25632585
debug_assertions,
25642586
actually_rustdoc: false,
2587+
resolve_doc_links: ResolveDocLinks::ExportedMetadata,
25652588
trimmed_def_paths: TrimmedDefPaths::default(),
25662589
cli_forced_codegen_units: codegen_units,
25672590
cli_forced_local_thinlto_off: disable_local_thinlto,
@@ -2825,8 +2848,9 @@ pub(crate) mod dep_tracking {
28252848
use super::{
28262849
BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, ErrorOutputType,
28272850
InstrumentCoverage, InstrumentXRay, LdImpl, LinkerPluginLto, LocationDetail, LtoCli,
2828-
OomStrategy, OptLevel, OutputType, OutputTypes, Passes, SourceFileHashAlgorithm,
2829-
SplitDwarfKind, SwitchWithOptPath, SymbolManglingVersion, TraitSolver, TrimmedDefPaths,
2851+
OomStrategy, OptLevel, OutputType, OutputTypes, Passes, ResolveDocLinks,
2852+
SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath, SymbolManglingVersion,
2853+
TraitSolver, TrimmedDefPaths,
28302854
};
28312855
use crate::lint;
28322856
use crate::options::WasiExecModel;
@@ -2913,6 +2937,7 @@ pub(crate) mod dep_tracking {
29132937
TargetTriple,
29142938
Edition,
29152939
LinkerPluginLto,
2940+
ResolveDocLinks,
29162941
SplitDebuginfo,
29172942
SplitDwarfKind,
29182943
StackProtector,

compiler/rustc_session/src/options.rs

+2
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,8 @@ top_level_options!(
169169
/// is currently just a hack and will be removed eventually, so please
170170
/// try to not rely on this too much.
171171
actually_rustdoc: bool [TRACKED],
172+
/// Whether name resolver should resolve documentation links.
173+
resolve_doc_links: ResolveDocLinks [TRACKED],
172174

173175
/// Control path trimming.
174176
trimmed_def_paths: TrimmedDefPaths [TRACKED],

src/librustdoc/core.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use rustc_hir::{HirId, Path};
1212
use rustc_interface::interface;
1313
use rustc_middle::hir::nested_filter;
1414
use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
15-
use rustc_session::config::{self, CrateType, ErrorOutputType};
15+
use rustc_session::config::{self, CrateType, ErrorOutputType, ResolveDocLinks};
1616
use rustc_session::lint;
1717
use rustc_session::Session;
1818
use rustc_span::symbol::sym;
@@ -200,6 +200,7 @@ pub(crate) fn create_config(
200200
scrape_examples_options,
201201
..
202202
}: RustdocOptions,
203+
RenderOptions { document_private, .. }: &RenderOptions,
203204
) -> rustc_interface::Config {
204205
// Add the doc cfg into the doc build.
205206
cfgs.push("doc".to_string());
@@ -227,6 +228,13 @@ pub(crate) fn create_config(
227228

228229
let crate_types =
229230
if proc_macro_crate { vec![CrateType::ProcMacro] } else { vec![CrateType::Rlib] };
231+
let resolve_doc_links = if *document_private {
232+
ResolveDocLinks::All
233+
} else {
234+
// Should be `ResolveDocLinks::Exported` in theory, but for some reason rustdoc
235+
// still tries to request resolutions for links on private items.
236+
ResolveDocLinks::All
237+
};
230238
let test = scrape_examples_options.map(|opts| opts.scrape_tests).unwrap_or(false);
231239
// plays with error output here!
232240
let sessopts = config::Options {
@@ -240,6 +248,7 @@ pub(crate) fn create_config(
240248
target_triple: target,
241249
unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
242250
actually_rustdoc: true,
251+
resolve_doc_links,
243252
unstable_opts,
244253
error_format,
245254
diagnostic_width,

src/librustdoc/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -742,7 +742,7 @@ fn main_args(at_args: &[String]) -> MainResult {
742742
(false, true) => {
743743
let input = options.input.clone();
744744
let edition = options.edition;
745-
let config = core::create_config(options);
745+
let config = core::create_config(options, &render_options);
746746

747747
// `markdown::render` can invoke `doctest::make_test`, which
748748
// requires session globals and a thread pool, so we use
@@ -775,7 +775,7 @@ fn main_args(at_args: &[String]) -> MainResult {
775775
let scrape_examples_options = options.scrape_examples_options.clone();
776776
let bin_crate = options.bin_crate;
777777

778-
let config = core::create_config(options);
778+
let config = core::create_config(options, &render_options);
779779

780780
interface::run_compiler(config, |compiler| {
781781
let sess = compiler.session();

0 commit comments

Comments
 (0)