[rustdoc] Fix path in type-based search
This commit is contained in:
parent
539957130d
commit
09160b3f45
@ -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<F, usize>,
|
||||
itemid: F,
|
||||
lastpathid: &mut usize,
|
||||
crate_paths: &mut Vec<(ItemType, Symbol)>,
|
||||
crate_paths: &mut Vec<(ItemType, Vec<Symbol>)>,
|
||||
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<ItemId, usize>,
|
||||
primitives: &mut FxHashMap<Symbol, usize>,
|
||||
lastpathid: &mut usize,
|
||||
crate_paths: &mut Vec<(ItemType, Symbol)>,
|
||||
crate_paths: &mut Vec<(ItemType, Vec<Symbol>)>,
|
||||
) {
|
||||
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<Symbol>)>,
|
||||
// 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<String, Vec<usize>>,
|
||||
}
|
||||
|
||||
struct Paths {
|
||||
ty: ItemType,
|
||||
name: Symbol,
|
||||
path: Option<usize>,
|
||||
}
|
||||
|
||||
impl Serialize for Paths {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
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<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
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::<Vec<_>>();
|
||||
|
||||
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::<Vec<_>>(),
|
||||
)?;
|
||||
crate_data.serialize_field(
|
||||
"p",
|
||||
&self.paths.iter().map(|(it, s)| (it, s.as_str())).collect::<Vec<_>>(),
|
||||
)?;
|
||||
crate_data.serialize_field("p", &paths)?;
|
||||
if has_aliases {
|
||||
crate_data.serialize_field("a", &self.aliases)?;
|
||||
}
|
||||
|
@ -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}<span class="${type}">${name}</span>\
|
||||
);
|
||||
}
|
||||
// `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}<span class="${type}">${name}</span>\
|
||||
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}<span class="${type}">${name}</span>\
|
||||
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}<span class="${type}">${name}</span>\
|
||||
// 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}<span class="${type}">${name}</span>\
|
||||
// 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}<span class="${type}">${name}</span>\
|
||||
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(
|
||||
|
Loading…
x
Reference in New Issue
Block a user