about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGuillaume Gomez <guillaume.gomez@huawei.com>2023-09-02 23:04:37 +0200
committerGuillaume Gomez <guillaume.gomez@huawei.com>2023-09-02 23:04:37 +0200
commite161fa1a6b3752da0a9279298eedf5b84a5fe49f (patch)
treebfbd20ab32671f9cd4b206622b5ef1ff6a5479a3
parent36fa557a5e8ab96876157b44d199ad9b8e93d72c (diff)
downloadrust-e161fa1a6b3752da0a9279298eedf5b84a5fe49f.tar.gz
rust-e161fa1a6b3752da0a9279298eedf5b84a5fe49f.zip
Correctly handle paths from foreign items
-rw-r--r--src/librustdoc/html/render/search_index.rs57
-rw-r--r--tests/rustdoc-js/full-path-function.js18
-rw-r--r--tests/rustdoc-js/full-path-function.rs1
3 files changed, 65 insertions, 11 deletions
diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs
index 2bbfb64ecb5..145c7d18dd0 100644
--- a/src/librustdoc/html/render/search_index.rs
+++ b/src/librustdoc/html/render/search_index.rs
@@ -1,7 +1,7 @@
 use std::collections::hash_map::Entry;
 use std::collections::BTreeMap;
 
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_middle::ty::TyCtxt;
 use rustc_span::symbol::Symbol;
 use serde::ser::{Serialize, SerializeSeq, SerializeStruct, Serializer};
@@ -246,6 +246,11 @@ pub(crate) fn build_index<'tcx>(
         where
             S: Serializer,
         {
+            let mut extra_paths = FxHashMap::default();
+            // We need to keep the order of insertion, hence why we use an `IndexMap`. Then we will
+            // insert these "extra paths" (which are paths of items from external crates) into the
+            // `full_paths` list at the end.
+            let mut revert_extra_paths = FxIndexMap::default();
             let mut mod_paths = FxHashMap::default();
             for (index, item) in self.items.iter().enumerate() {
                 if item.path.is_empty() {
@@ -253,17 +258,43 @@ pub(crate) fn build_index<'tcx>(
                 }
                 mod_paths.insert(&item.path, index);
             }
-            let paths = self
-                .paths
-                .iter()
-                .map(|(ty, path)| {
-                    if path.len() < 2 {
-                        return Paths { ty: *ty, name: path[0], path: None };
+            let mut paths = Vec::with_capacity(self.paths.len());
+            for (ty, path) in &self.paths {
+                if path.len() < 2 {
+                    paths.push(Paths { ty: *ty, name: path[0], path: None });
+                    continue;
+                }
+                let full_path = join_with_double_colon(&path[..path.len() - 1]);
+                if let Some(index) = mod_paths.get(&full_path) {
+                    paths.push(Paths { ty: *ty, name: *path.last().unwrap(), path: Some(*index) });
+                    continue;
+                }
+                // It means it comes from an external crate so the item and its path will be
+                // stored into another array.
+                //
+                // `index` is put after the last `mod_paths`
+                let index = extra_paths.len() + self.items.len();
+                if !revert_extra_paths.contains_key(&index) {
+                    revert_extra_paths.insert(index, full_path.clone());
+                }
+                match extra_paths.entry(full_path) {
+                    Entry::Occupied(entry) => {
+                        paths.push(Paths {
+                            ty: *ty,
+                            name: *path.last().unwrap(),
+                            path: Some(*entry.get()),
+                        });
                     }
-                    let index = mod_paths.get(&join_with_double_colon(&path[..path.len() - 1]));
-                    Paths { ty: *ty, name: *path.last().unwrap(), path: index.copied() }
-                })
-                .collect::<Vec<_>>();
+                    Entry::Vacant(entry) => {
+                        entry.insert(index);
+                        paths.push(Paths {
+                            ty: *ty,
+                            name: *path.last().unwrap(),
+                            path: Some(index),
+                        });
+                    }
+                }
+            }
 
             let mut names = Vec::with_capacity(self.items.len());
             let mut types = String::with_capacity(self.items.len());
@@ -322,6 +353,10 @@ pub(crate) fn build_index<'tcx>(
                 }
             }
 
+            for (index, path) in &revert_extra_paths {
+                full_paths.push((*index, path));
+            }
+
             let has_aliases = !self.aliases.is_empty();
             let mut crate_data =
                 serializer.serialize_struct("CrateData", if has_aliases { 9 } else { 8 })?;
diff --git a/tests/rustdoc-js/full-path-function.js b/tests/rustdoc-js/full-path-function.js
index 9d3c3a4506c..48be51b156f 100644
--- a/tests/rustdoc-js/full-path-function.js
+++ b/tests/rustdoc-js/full-path-function.js
@@ -22,4 +22,22 @@ const EXPECTED = [
             { 'path': 'full_path_function::b::Sac', 'name': 'bar2' },
         ],
     },
+    {
+        'query': 'string::string -> u32',
+        'others': [
+            { 'path': 'full_path_function::b::Sac', 'name': 'string' },
+        ],
+    },
+    {
+        'query': 'alloc::string::string -> u32',
+        'others': [
+            { 'path': 'full_path_function::b::Sac', 'name': 'string' },
+        ],
+    },
+    {
+        'query': 'alloc::string -> u32',
+        'others': [
+            { 'path': 'full_path_function::b::Sac', 'name': 'string' },
+        ],
+    },
 ];
diff --git a/tests/rustdoc-js/full-path-function.rs b/tests/rustdoc-js/full-path-function.rs
index c1ec1e1731b..8dcc3f2b69d 100644
--- a/tests/rustdoc-js/full-path-function.rs
+++ b/tests/rustdoc-js/full-path-function.rs
@@ -12,5 +12,6 @@ pub mod b {
         pub fn len(&self) -> usize { 0 }
         pub fn bar(&self, w: u32) -> usize { 0 }
         pub fn bar2(&self, w: u32) -> u32 { 0 }
+        pub fn string(w: String) -> u32 { 0 }
     }
 }