From 159b56f2881ad6cf4b675852746553ff7fa84374 Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com>
Date: Tue, 1 Feb 2022 20:30:32 +0800
Subject: [PATCH] rustdoc: Resolve some more doc links early

---
 .../passes/collect_intra_doc_links/early.rs   | 45 ++++++++++++++-----
 1 file changed, 34 insertions(+), 11 deletions(-)

diff --git a/src/librustdoc/passes/collect_intra_doc_links/early.rs b/src/librustdoc/passes/collect_intra_doc_links/early.rs
index 0ac27087a97..6f9912e71c5 100644
--- a/src/librustdoc/passes/collect_intra_doc_links/early.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links/early.rs
@@ -172,34 +172,50 @@ impl<'ra> EarlyDocLinkResolver<'_, 'ra> {
     }
 
     fn resolve_doc_links_extern_impl(&mut self, def_id: DefId, is_inherent: bool) {
-        self.resolve_doc_links_extern_outer(def_id, def_id);
+        self.resolve_doc_links_extern_outer_fixme(def_id, def_id);
         let assoc_item_def_ids = Vec::from_iter(
             self.resolver.cstore().associated_item_def_ids_untracked(def_id, self.sess),
         );
         for assoc_def_id in assoc_item_def_ids {
             if !is_inherent || self.resolver.cstore().visibility_untracked(assoc_def_id).is_public()
             {
-                self.resolve_doc_links_extern_outer(assoc_def_id, def_id);
+                self.resolve_doc_links_extern_outer_fixme(assoc_def_id, def_id);
             }
         }
     }
 
+    // FIXME: replace all uses with `resolve_doc_links_extern_outer` to actually resolve links, not
+    // just add traits in scope. This may be expensive and require benchmarking and optimization.
+    fn resolve_doc_links_extern_outer_fixme(&mut self, def_id: DefId, scope_id: DefId) {
+        if !self.resolver.cstore().may_have_doc_links_untracked(def_id) {
+            return;
+        }
+        if let Some(parent_id) = self.resolver.opt_parent(scope_id) {
+            self.add_traits_in_scope(parent_id);
+        }
+    }
+
     fn resolve_doc_links_extern_outer(&mut self, def_id: DefId, scope_id: DefId) {
         if !self.resolver.cstore().may_have_doc_links_untracked(def_id) {
             return;
         }
-        // FIXME: actually resolve links, not just add traits in scope.
-        if let Some(parent_id) = self.resolver.opt_parent(scope_id) {
-            self.add_traits_in_scope(parent_id);
-        }
+        let attrs = Vec::from_iter(self.resolver.cstore().item_attrs_untracked(def_id, self.sess));
+        let parent_scope = ParentScope::module(
+            self.resolver.get_nearest_non_block_module(
+                self.resolver.opt_parent(scope_id).unwrap_or(scope_id),
+            ),
+            self.resolver,
+        );
+        self.resolve_doc_links(doc_attrs(attrs.iter()), parent_scope);
     }
 
     fn resolve_doc_links_extern_inner(&mut self, def_id: DefId) {
         if !self.resolver.cstore().may_have_doc_links_untracked(def_id) {
             return;
         }
-        // FIXME: actually resolve links, not just add traits in scope.
-        self.add_traits_in_scope(def_id);
+        let attrs = Vec::from_iter(self.resolver.cstore().item_attrs_untracked(def_id, self.sess));
+        let parent_scope = ParentScope::module(self.resolver.expect_module(def_id), self.resolver);
+        self.resolve_doc_links(doc_attrs(attrs.iter()), parent_scope);
     }
 
     fn resolve_doc_links_local(&mut self, attrs: &[ast::Attribute]) {
@@ -253,9 +269,16 @@ impl<'ra> EarlyDocLinkResolver<'_, 'ra> {
                         }
                     }
 
-                    // FIXME: Resolve all prefixes for type-relative resolution or for diagnostics.
-                    if (need_assoc || !any_resolved) && pinfo.path_str.contains("::") {
-                        need_traits_in_scope = true;
+                    // Resolve all prefixes for type-relative resolution or for diagnostics.
+                    if need_assoc || !any_resolved {
+                        let mut path = &pinfo.path_str[..];
+                        while let Some(idx) = path.rfind("::") {
+                            path = &path[..idx];
+                            need_traits_in_scope = true;
+                            for ns in [TypeNS, ValueNS, MacroNS] {
+                                self.resolve_and_cache(path, ns, &parent_scope);
+                            }
+                        }
                     }
                 }
             }