diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 92278179a51c9..a331f4cf3e6e7 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -16,13 +16,15 @@ use rustc_middle::hir::map::Map; use rustc_middle::middle::privacy::AccessLevels; use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; use rustc_resolve as resolve; +use rustc_resolve::Namespace::TypeNS; use rustc_session::config::{self, CrateType, ErrorOutputType}; use rustc_session::lint; use rustc_session::DiagnosticOutput; use rustc_session::Session; +use rustc_span::def_id::CRATE_DEF_INDEX; use rustc_span::source_map; use rustc_span::symbol::sym; -use rustc_span::Span; +use rustc_span::{Span, DUMMY_SP}; use std::cell::RefCell; use std::lazy::SyncLazy; @@ -283,13 +285,43 @@ crate fn create_config( } crate fn create_resolver<'a>( + externs: config::Externs, queries: &Queries<'a>, sess: &Session, ) -> Rc> { let (krate, resolver, _) = &*abort_on_err(queries.expansion(), sess).peek(); let resolver = resolver.clone(); - crate::passes::collect_intra_doc_links::load_intra_link_crates(resolver, krate) + let resolver = crate::passes::collect_intra_doc_links::load_intra_link_crates(resolver, krate); + + // FIXME: somehow rustdoc is still missing crates even though we loaded all + // the known necessary crates. Load them all unconditionally until we find a way to fix this. + // DO NOT REMOVE THIS without first testing on the reproducer in + // https://github.com/jyn514/objr/commit/edcee7b8124abf0e4c63873e8422ff81beb11ebb + let extern_names: Vec = externs + .iter() + .filter(|(_, entry)| entry.add_prelude) + .map(|(name, _)| name) + .cloned() + .collect(); + resolver.borrow_mut().access(|resolver| { + sess.time("load_extern_crates", || { + for extern_name in &extern_names { + debug!("loading extern crate {}", extern_name); + if let Err(()) = resolver + .resolve_str_path_error( + DUMMY_SP, + extern_name, + TypeNS, + LocalDefId { local_def_index: CRATE_DEF_INDEX }.to_def_id(), + ) { + warn!("unable to resolve external crate {} (do you have an unused `--extern` crate?)", extern_name) + } + } + }); + }); + + resolver } crate fn run_global_ctxt( diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index fb252a9c73934..1c12cc547e0da 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -756,6 +756,7 @@ fn main_options(options: config::Options) -> MainResult { let default_passes = options.default_passes; let output_format = options.output_format; // FIXME: fix this clone (especially render_options) + let externs = options.externs.clone(); let manual_passes = options.manual_passes.clone(); let render_options = options.render_options.clone(); let scrape_examples_options = options.scrape_examples_options.clone(); @@ -774,7 +775,7 @@ fn main_options(options: config::Options) -> MainResult { // We need to hold on to the complete resolver, so we cause everything to be // cloned for the analysis passes to use. Suboptimal, but necessary in the // current architecture. - let resolver = core::create_resolver(queries, sess); + let resolver = core::create_resolver(externs, queries, sess); if sess.diagnostic().has_errors_or_lint_errors() { sess.fatal("Compilation failed, aborting rustdoc"); diff --git a/src/librustdoc/passes/collect_intra_doc_links/early.rs b/src/librustdoc/passes/collect_intra_doc_links/early.rs index 565bcb8bd1340..4cebf741e2002 100644 --- a/src/librustdoc/passes/collect_intra_doc_links/early.rs +++ b/src/librustdoc/passes/collect_intra_doc_links/early.rs @@ -1,3 +1,4 @@ +use ast::visit; use rustc_ast as ast; use rustc_hir::def::Namespace::TypeNS; use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; @@ -16,7 +17,7 @@ crate fn load_intra_link_crates(resolver: Resolver, krate: &ast::Crate) -> Resol let mut loader = IntraLinkCrateLoader { current_mod: CRATE_DEF_ID, resolver }; // `walk_crate` doesn't visit the crate itself for some reason. loader.load_links_in_attrs(&krate.attrs, krate.span); - ast::visit::walk_crate(&mut loader, krate); + visit::walk_crate(&mut loader, krate); loader.resolver } @@ -54,7 +55,12 @@ impl IntraLinkCrateLoader { } } -impl ast::visit::Visitor<'_> for IntraLinkCrateLoader { +impl visit::Visitor<'_> for IntraLinkCrateLoader { + fn visit_foreign_item(&mut self, item: &ast::ForeignItem) { + self.load_links_in_attrs(&item.attrs, item.span); + visit::walk_foreign_item(self, item) + } + fn visit_item(&mut self, item: &ast::Item) { use rustc_ast_lowering::ResolverAstLowering; @@ -64,12 +70,29 @@ impl ast::visit::Visitor<'_> for IntraLinkCrateLoader { let old_mod = mem::replace(&mut self.current_mod, new_mod); self.load_links_in_attrs(&item.attrs, item.span); - ast::visit::walk_item(self, item); + visit::walk_item(self, item); self.current_mod = old_mod; } else { self.load_links_in_attrs(&item.attrs, item.span); - ast::visit::walk_item(self, item); + visit::walk_item(self, item); } } + + // NOTE: if doc-comments are ever allowed on function parameters, this will have to implement `visit_param` too. + + fn visit_assoc_item(&mut self, item: &ast::AssocItem, ctxt: visit::AssocCtxt) { + self.load_links_in_attrs(&item.attrs, item.span); + visit::walk_assoc_item(self, item, ctxt) + } + + fn visit_field_def(&mut self, field: &ast::FieldDef) { + self.load_links_in_attrs(&field.attrs, field.span); + visit::walk_field_def(self, field) + } + + fn visit_variant(&mut self, v: &ast::Variant) { + self.load_links_in_attrs(&v.attrs, v.span); + visit::walk_variant(self, v) + } } diff --git a/src/test/rustdoc-ui/intra-doc/auxiliary/dep1.rs b/src/test/rustdoc-ui/intra-doc/auxiliary/dep1.rs new file mode 100644 index 0000000000000..d11c69f812a8d --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/auxiliary/dep1.rs @@ -0,0 +1 @@ +// intentionally empty diff --git a/src/test/rustdoc-ui/intra-doc/auxiliary/dep2.rs b/src/test/rustdoc-ui/intra-doc/auxiliary/dep2.rs new file mode 100644 index 0000000000000..d11c69f812a8d --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/auxiliary/dep2.rs @@ -0,0 +1 @@ +// intentionally empty diff --git a/src/test/rustdoc-ui/intra-doc/auxiliary/dep3.rs b/src/test/rustdoc-ui/intra-doc/auxiliary/dep3.rs new file mode 100644 index 0000000000000..d11c69f812a8d --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/auxiliary/dep3.rs @@ -0,0 +1 @@ +// intentionally empty diff --git a/src/test/rustdoc-ui/intra-doc/auxiliary/dep4.rs b/src/test/rustdoc-ui/intra-doc/auxiliary/dep4.rs new file mode 100644 index 0000000000000..d11c69f812a8d --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/auxiliary/dep4.rs @@ -0,0 +1 @@ +// intentionally empty diff --git a/src/test/rustdoc-ui/intra-doc/extern-crate-load.rs b/src/test/rustdoc-ui/intra-doc/extern-crate-load.rs new file mode 100644 index 0000000000000..438c56aa516a9 --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/extern-crate-load.rs @@ -0,0 +1,26 @@ +// check-pass +// aux-crate:dep1=dep1.rs +// aux-crate:dep2=dep2.rs +// aux-crate:dep3=dep3.rs +// aux-crate:dep4=dep4.rs +#![deny(rustdoc::broken_intra_doc_links)] + +pub trait Trait { + /// [dep1] + type Item; +} + +pub struct S { + /// [dep2] + pub x: usize, +} + +extern "C" { + /// [dep3] + pub fn printf(); +} + +pub enum E { + /// [dep4] + A +}