diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs
index f34be120d29..a7771c31f85 100644
--- a/src/librustdoc/html/render/search_index.rs
+++ b/src/librustdoc/html/render/search_index.rs
@@ -4,7 +4,7 @@ use std::collections::BTreeMap;
use rustc_data_structures::fx::FxHashMap;
use rustc_middle::ty::TyCtxt;
use rustc_span::symbol::Symbol;
-use serde::ser::{Serialize, SerializeStruct, Serializer};
+use serde::ser::{Serialize, SerializeSeq, SerializeStruct, Serializer};
use crate::clean;
use crate::clean::types::{Function, Generics, ItemId, Type, WherePredicate};
@@ -78,9 +78,9 @@ pub(crate) fn build_index<'tcx>(
map: &mut FxHashMap,
itemid: F,
lastpathid: &mut usize,
- crate_paths: &mut Vec<(ItemType, Symbol)>,
+ crate_paths: &mut Vec<(ItemType, Vec)>,
item_type: ItemType,
- path: Symbol,
+ path: &[Symbol],
) {
match map.entry(itemid) {
Entry::Occupied(entry) => ty.id = Some(RenderTypeId::Index(*entry.get())),
@@ -88,7 +88,7 @@ pub(crate) fn build_index<'tcx>(
let pathid = *lastpathid;
entry.insert(pathid);
*lastpathid += 1;
- crate_paths.push((item_type, path));
+ crate_paths.push((item_type, path.to_vec()));
ty.id = Some(RenderTypeId::Index(pathid));
}
}
@@ -100,7 +100,7 @@ pub(crate) fn build_index<'tcx>(
itemid_to_pathid: &mut FxHashMap,
primitives: &mut FxHashMap,
lastpathid: &mut usize,
- crate_paths: &mut Vec<(ItemType, Symbol)>,
+ crate_paths: &mut Vec<(ItemType, Vec)>,
) {
if let Some(generics) = &mut ty.generics {
for item in generics {
@@ -131,7 +131,7 @@ pub(crate) fn build_index<'tcx>(
lastpathid,
crate_paths,
item_type,
- *fqp.last().unwrap(),
+ fqp,
);
} else {
ty.id = None;
@@ -146,7 +146,7 @@ pub(crate) fn build_index<'tcx>(
lastpathid,
crate_paths,
ItemType::Primitive,
- sym,
+ &[sym],
);
}
RenderTypeId::Index(_) => {}
@@ -191,7 +191,7 @@ pub(crate) fn build_index<'tcx>(
lastpathid += 1;
if let Some(&(ref fqp, short)) = paths.get(&defid) {
- crate_paths.push((short, *fqp.last().unwrap()));
+ crate_paths.push((short, fqp.clone()));
Some(pathid)
} else {
None
@@ -213,18 +213,58 @@ pub(crate) fn build_index<'tcx>(
struct CrateData<'a> {
doc: String,
items: Vec<&'a IndexItem>,
- paths: Vec<(ItemType, Symbol)>,
+ paths: Vec<(ItemType, Vec)>,
// The String is alias name and the vec is the list of the elements with this alias.
//
// To be noted: the `usize` elements are indexes to `items`.
aliases: &'a BTreeMap>,
}
+ struct Paths {
+ ty: ItemType,
+ name: Symbol,
+ path: Option,
+ }
+
+ impl Serialize for Paths {
+ fn serialize(&self, serializer: S) -> Result
+ where
+ S: Serializer,
+ {
+ let mut seq = serializer.serialize_seq(None)?;
+ seq.serialize_element(&self.ty)?;
+ seq.serialize_element(self.name.as_str())?;
+ if let Some(ref path) = self.path {
+ seq.serialize_element(path)?;
+ }
+ seq.end()
+ }
+ }
+
impl<'a> Serialize for CrateData<'a> {
fn serialize(&self, serializer: S) -> Result
where
S: Serializer,
{
+ let mut mod_paths = FxHashMap::default();
+ for (index, item) in self.items.iter().enumerate() {
+ if item.path.is_empty() {
+ continue;
+ }
+ 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 index = mod_paths.get(&join_with_double_colon(&path[..path.len() - 1]));
+ Paths { ty: *ty, name: *path.last().unwrap(), path: index.copied() }
+ })
+ .collect::>();
+
let has_aliases = !self.aliases.is_empty();
let mut crate_data =
serializer.serialize_struct("CrateData", if has_aliases { 9 } else { 8 })?;
@@ -321,10 +361,7 @@ pub(crate) fn build_index<'tcx>(
.filter_map(|(index, item)| item.deprecation.map(|_| index))
.collect::>(),
)?;
- crate_data.serialize_field(
- "p",
- &self.paths.iter().map(|(it, s)| (it, s.as_str())).collect::>(),
- )?;
+ crate_data.serialize_field("p", &paths)?;
if has_aliases {
crate_data.serialize_field("a", &self.aliases)?;
}
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index 00b6b3a4420..449168c460b 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -1462,6 +1462,32 @@ function initSearch(rawSearchIndex) {
if (!typePassesFilter(queryElem.typeFilter, fnType.ty)) {
continue;
}
+ const queryElemPathLength = queryElem.pathWithoutLast.length;
+ // If the query element is a path (it contains `::`), we need to check if this
+ // path is compatible with the target type.
+ if (queryElemPathLength > 0) {
+ const fnTypePath = fnType.path !== undefined && fnType.path !== null ?
+ fnType.path.split("::") : [];
+ // If the path provided in the query element is longer than this type,
+ // no need to check it since it won't match in any case.
+ if (queryElemPathLength > fnTypePath.length) {
+ continue;
+ }
+ let i = 0;
+ for (const path of fnTypePath) {
+ if (path === queryElem.pathWithoutLast[i]) {
+ i += 1;
+ if (i >= queryElemPathLength) {
+ break;
+ }
+ }
+ }
+ if (i < queryElemPathLength) {
+ // If we didn't find all parts of the path of the query element inside
+ // the fn type, then it's not the right one.
+ continue;
+ }
+ }
if (queryElem.generics.length === 0 || checkGenerics(fnType, queryElem)) {
currentFnTypeList.splice(i, 1);
const result = doHandleQueryElemList(currentFnTypeList, queryElemList);
@@ -1862,14 +1888,14 @@ function initSearch(rawSearchIndex) {
* @param {QueryElement} elem
*/
function convertNameToId(elem) {
- if (typeNameIdMap.has(elem.name)) {
- elem.id = typeNameIdMap.get(elem.name);
+ if (typeNameIdMap.has(elem.pathLast)) {
+ elem.id = typeNameIdMap.get(elem.pathLast);
} else if (!parsedQuery.literalSearch) {
let match = -1;
let matchDist = maxEditDistance + 1;
let matchName = "";
for (const [name, id] of typeNameIdMap) {
- const dist = editDistance(name, elem.name, maxEditDistance);
+ const dist = editDistance(name, elem.pathLast, maxEditDistance);
if (dist <= matchDist && dist <= maxEditDistance) {
if (dist === matchDist && matchName > name) {
continue;
@@ -2385,10 +2411,19 @@ ${item.displayPath}${name}\
);
}
// `0` is used as a sentinel because it's fewer bytes than `null`
- const item = pathIndex === 0 ? null : lowercasePaths[pathIndex - 1];
+ if (pathIndex === 0) {
+ return {
+ id: -1,
+ ty: null,
+ path: null,
+ generics: generics,
+ };
+ }
+ const item = lowercasePaths[pathIndex - 1];
return {
- id: item === null ? -1 : buildTypeMapIndex(item.name),
- ty: item === null ? null : item.ty,
+ id: buildTypeMapIndex(item.name),
+ ty: item.ty,
+ path: item.path,
generics: generics,
};
});
@@ -2417,15 +2452,25 @@ ${item.displayPath}${name}\
if (functionSearchType === 0) {
return null;
}
- let inputs, output, item;
+ let inputs, output;
if (typeof functionSearchType[INPUTS_DATA] === "number") {
const pathIndex = functionSearchType[INPUTS_DATA];
- item = pathIndex === 0 ? null : lowercasePaths[pathIndex - 1];
- inputs = [{
- id: item === null ? -1 : buildTypeMapIndex(item.name),
- ty: item === null ? null : item.ty,
- generics: [],
- }];
+ if (pathIndex === 0) {
+ inputs = [{
+ id: -1,
+ ty: null,
+ path: null,
+ generics: [],
+ }];
+ } else {
+ const item = lowercasePaths[pathIndex - 1];
+ inputs = [{
+ id: buildTypeMapIndex(item.name),
+ ty: item.ty,
+ path: item.path,
+ generics: [],
+ }];
+ }
} else {
inputs = buildItemSearchTypeAll(
functionSearchType[INPUTS_DATA],
@@ -2435,12 +2480,22 @@ ${item.displayPath}${name}\
if (functionSearchType.length > 1) {
if (typeof functionSearchType[OUTPUT_DATA] === "number") {
const pathIndex = functionSearchType[OUTPUT_DATA];
- item = pathIndex === 0 ? null : lowercasePaths[pathIndex - 1];
- output = [{
- id: item === null ? -1 : buildTypeMapIndex(item.name),
- ty: item === null ? null : item.ty,
- generics: [],
- }];
+ if (pathIndex === 0) {
+ output = [{
+ id: -1,
+ ty: null,
+ path: null,
+ generics: [],
+ }];
+ } else {
+ const item = lowercasePaths[pathIndex - 1];
+ output = [{
+ id: buildTypeMapIndex(item.name),
+ ty: item.ty,
+ path: item.path,
+ generics: [],
+ }];
+ }
} else {
output = buildItemSearchTypeAll(
functionSearchType[OUTPUT_DATA],
@@ -2573,9 +2628,19 @@ ${item.displayPath}${name}\
// convert `rawPaths` entries into object form
// generate normalizedPaths for function search mode
let len = paths.length;
+ let lastPath = itemPaths.get(0);
for (let i = 0; i < len; ++i) {
- lowercasePaths.push({ty: paths[i][0], name: paths[i][1].toLowerCase()});
- paths[i] = {ty: paths[i][0], name: paths[i][1]};
+ const elem = paths[i];
+ const ty = elem[0];
+ const name = elem[1];
+ let path = null;
+ if (elem.length > 2) {
+ path = itemPaths.has(elem[2]) ? itemPaths.get(elem[2]) : lastPath;
+ lastPath = path;
+ }
+
+ lowercasePaths.push({ty: ty, name: name.toLowerCase(), path: path});
+ paths[i] = {ty: ty, name: name, path: path};
}
// convert `item*` into an object form, and construct word indices.
@@ -2585,8 +2650,8 @@ ${item.displayPath}${name}\
// operation that is cached for the life of the page state so that
// all other search operations have access to this cached data for
// faster analysis operations
+ lastPath = "";
len = itemTypes.length;
- let lastPath = "";
for (let i = 0; i < len; ++i) {
let word = "";
// This object should have exactly the same set of fields as the "crateRow"
@@ -2595,11 +2660,12 @@ ${item.displayPath}${name}\
word = itemNames[i].toLowerCase();
}
searchWords.push(word);
+ const path = itemPaths.has(i) ? itemPaths.get(i) : lastPath;
const row = {
crate: crate,
ty: itemTypes.charCodeAt(i) - charA,
name: itemNames[i],
- path: itemPaths.has(i) ? itemPaths.get(i) : lastPath,
+ path: path,
desc: itemDescs[i],
parent: itemParentIdxs[i] > 0 ? paths[itemParentIdxs[i] - 1] : undefined,
type: buildFunctionSearchType(