about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJoshua Nelson <jyn514@gmail.com>2021-08-21 20:14:56 +0000
committerJoshua Nelson <jyn514@gmail.com>2021-08-26 16:58:25 +0000
commitc60a370dac4821d0a1a4d55943e28c2da2220dc7 (patch)
tree731fc787691e47ed5ceb20c889afc17a33240bca
parentd933edd5c6ee149d53bff4558c3fef8dc68b8766 (diff)
downloadrust-c60a370dac4821d0a1a4d55943e28c2da2220dc7.tar.gz
rust-c60a370dac4821d0a1a4d55943e28c2da2220dc7.zip
Fix the bugs and add a regression test
- All attributes for an item need to be considered at once, they can't
  be considered a line at a time.
- The top-level crate was not being visited. This bug was caught by
  `extern-crate-used-only-in-link`, which I'm very glad I added.
- Make the loader private to the module, so that only one function is
  exposed.
-rw-r--r--src/librustdoc/core.rs6
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs2
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links/early.rs44
-rw-r--r--src/test/rustdoc/intra-doc/auxiliary/pub-struct.rs1
-rw-r--r--src/test/rustdoc/intra-doc/extern-reference-link.rs7
5 files changed, 38 insertions, 22 deletions
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 249febb72bc..4d498e6dbdb 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -1,4 +1,3 @@
-use rustc_ast as ast;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sync::{self, Lrc};
 use rustc_driver::abort_on_err;
@@ -307,10 +306,7 @@ crate fn create_resolver<'a>(
     let (krate, resolver, _) = &*abort_on_err(queries.expansion(), sess).peek();
     let resolver = resolver.clone();
 
-    let mut loader = crate::passes::collect_intra_doc_links::IntraLinkCrateLoader::new(resolver);
-    ast::visit::walk_crate(&mut loader, krate);
-
-    loader.resolver
+    crate::passes::collect_intra_doc_links::load_intra_link_crates(resolver, krate)
 }
 
 crate fn run_global_ctxt(
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index b909f6b2695..178c8c15a15 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -38,7 +38,7 @@ use crate::lint::{BROKEN_INTRA_DOC_LINKS, PRIVATE_INTRA_DOC_LINKS};
 use crate::passes::Pass;
 
 mod early;
-crate use early::IntraLinkCrateLoader;
+crate use early::load_intra_link_crates;
 
 crate const COLLECT_INTRA_DOC_LINKS: Pass = Pass {
     name: "collect-intra-doc-links",
diff --git a/src/librustdoc/passes/collect_intra_doc_links/early.rs b/src/librustdoc/passes/collect_intra_doc_links/early.rs
index 7cba2523d1a..cd90528ab9c 100644
--- a/src/librustdoc/passes/collect_intra_doc_links/early.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links/early.rs
@@ -1,34 +1,41 @@
 use rustc_ast as ast;
 use rustc_hir::def::Namespace::TypeNS;
-use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
 use rustc_interface::interface;
+use rustc_span::Span;
 
 use std::cell::RefCell;
 use std::mem;
 use std::rc::Rc;
 
+type Resolver = Rc<RefCell<interface::BoxedResolver>>;
 // Letting the resolver escape at the end of the function leads to inconsistencies between the
 // crates the TyCtxt sees and the resolver sees (because the resolver could load more crates
 // after escaping). Hopefully `IntraLinkCrateLoader` gets all the crates we need ...
-crate struct IntraLinkCrateLoader {
-    current_mod: DefId,
-    crate resolver: Rc<RefCell<interface::BoxedResolver>>,
+crate fn load_intra_link_crates(resolver: Resolver, krate: &ast::Crate) -> Resolver {
+    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);
+    loader.resolver
 }
 
-impl IntraLinkCrateLoader {
-    crate fn new(resolver: Rc<RefCell<interface::BoxedResolver>>) -> Self {
-        let crate_id = LocalDefId { local_def_index: CRATE_DEF_INDEX }.to_def_id();
-        Self { current_mod: crate_id, resolver }
-    }
+struct IntraLinkCrateLoader {
+    current_mod: LocalDefId,
+    resolver: Rc<RefCell<interface::BoxedResolver>>,
 }
 
-impl ast::visit::Visitor<'_> for IntraLinkCrateLoader {
-    fn visit_attribute(&mut self, attr: &ast::Attribute) {
+impl IntraLinkCrateLoader {
+    fn load_links_in_attrs(&mut self, attrs: &[ast::Attribute], span: Span) {
         use crate::html::markdown::markdown_links;
         use crate::passes::collect_intra_doc_links::preprocess_link;
 
-        if let Some(doc) = attr.doc_str() {
+        // FIXME: this probably needs to consider inlining
+        let attrs = crate::clean::Attributes::from_ast(attrs, None);
+        for (parent_module, doc) in attrs.collapsed_doc_value_by_module_level() {
+            debug!(?doc);
             for link in markdown_links(&doc.as_str()) {
+                debug!(?link.link);
                 let path_str = if let Some(Ok(x)) = preprocess_link(&link) {
                     x.path_str
                 } else {
@@ -36,27 +43,32 @@ impl ast::visit::Visitor<'_> for IntraLinkCrateLoader {
                 };
                 self.resolver.borrow_mut().access(|resolver| {
                     let _ = resolver.resolve_str_path_error(
-                        attr.span,
+                        span,
                         &path_str,
                         TypeNS,
-                        self.current_mod,
+                        parent_module.unwrap_or(self.current_mod.to_def_id()),
                     );
                 });
             }
         }
-        ast::visit::walk_attribute(self, attr);
     }
+}
 
+impl ast::visit::Visitor<'_> for IntraLinkCrateLoader {
     fn visit_item(&mut self, item: &ast::Item) {
         use rustc_ast_lowering::ResolverAstLowering;
 
         if let ast::ItemKind::Mod(..) = item.kind {
             let new_mod =
                 self.resolver.borrow_mut().access(|resolver| resolver.local_def_id(item.id));
-            let old_mod = mem::replace(&mut self.current_mod, new_mod.to_def_id());
+            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);
+
             self.current_mod = old_mod;
         } else {
+            self.load_links_in_attrs(&item.attrs, item.span);
             ast::visit::walk_item(self, item);
         }
     }
diff --git a/src/test/rustdoc/intra-doc/auxiliary/pub-struct.rs b/src/test/rustdoc/intra-doc/auxiliary/pub-struct.rs
new file mode 100644
index 00000000000..75d4289321c
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/auxiliary/pub-struct.rs
@@ -0,0 +1 @@
+pub struct SomeStruct;
diff --git a/src/test/rustdoc/intra-doc/extern-reference-link.rs b/src/test/rustdoc/intra-doc/extern-reference-link.rs
new file mode 100644
index 00000000000..bad6ec75579
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/extern-reference-link.rs
@@ -0,0 +1,7 @@
+// compile-flags: --extern pub_struct
+// aux-build:pub-struct.rs
+
+/// [SomeStruct]
+///
+/// [SomeStruct]: pub_struct::SomeStruct
+pub fn foo() {}