[rustdoc] Fix path in type-based search
This commit is contained in:
parent
539957130d
commit
09160b3f45
2 changed files with 139 additions and 36 deletions
|
@ -4,7 +4,7 @@ use std::collections::BTreeMap;
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_span::symbol::Symbol;
|
use rustc_span::symbol::Symbol;
|
||||||
use serde::ser::{Serialize, SerializeStruct, Serializer};
|
use serde::ser::{Serialize, SerializeSeq, SerializeStruct, Serializer};
|
||||||
|
|
||||||
use crate::clean;
|
use crate::clean;
|
||||||
use crate::clean::types::{Function, Generics, ItemId, Type, WherePredicate};
|
use crate::clean::types::{Function, Generics, ItemId, Type, WherePredicate};
|
||||||
|
@ -78,9 +78,9 @@ pub(crate) fn build_index<'tcx>(
|
||||||
map: &mut FxHashMap<F, usize>,
|
map: &mut FxHashMap<F, usize>,
|
||||||
itemid: F,
|
itemid: F,
|
||||||
lastpathid: &mut usize,
|
lastpathid: &mut usize,
|
||||||
crate_paths: &mut Vec<(ItemType, Symbol)>,
|
crate_paths: &mut Vec<(ItemType, Vec<Symbol>)>,
|
||||||
item_type: ItemType,
|
item_type: ItemType,
|
||||||
path: Symbol,
|
path: &[Symbol],
|
||||||
) {
|
) {
|
||||||
match map.entry(itemid) {
|
match map.entry(itemid) {
|
||||||
Entry::Occupied(entry) => ty.id = Some(RenderTypeId::Index(*entry.get())),
|
Entry::Occupied(entry) => ty.id = Some(RenderTypeId::Index(*entry.get())),
|
||||||
|
@ -88,7 +88,7 @@ pub(crate) fn build_index<'tcx>(
|
||||||
let pathid = *lastpathid;
|
let pathid = *lastpathid;
|
||||||
entry.insert(pathid);
|
entry.insert(pathid);
|
||||||
*lastpathid += 1;
|
*lastpathid += 1;
|
||||||
crate_paths.push((item_type, path));
|
crate_paths.push((item_type, path.to_vec()));
|
||||||
ty.id = Some(RenderTypeId::Index(pathid));
|
ty.id = Some(RenderTypeId::Index(pathid));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -100,7 +100,7 @@ pub(crate) fn build_index<'tcx>(
|
||||||
itemid_to_pathid: &mut FxHashMap<ItemId, usize>,
|
itemid_to_pathid: &mut FxHashMap<ItemId, usize>,
|
||||||
primitives: &mut FxHashMap<Symbol, usize>,
|
primitives: &mut FxHashMap<Symbol, usize>,
|
||||||
lastpathid: &mut usize,
|
lastpathid: &mut usize,
|
||||||
crate_paths: &mut Vec<(ItemType, Symbol)>,
|
crate_paths: &mut Vec<(ItemType, Vec<Symbol>)>,
|
||||||
) {
|
) {
|
||||||
if let Some(generics) = &mut ty.generics {
|
if let Some(generics) = &mut ty.generics {
|
||||||
for item in generics {
|
for item in generics {
|
||||||
|
@ -131,7 +131,7 @@ pub(crate) fn build_index<'tcx>(
|
||||||
lastpathid,
|
lastpathid,
|
||||||
crate_paths,
|
crate_paths,
|
||||||
item_type,
|
item_type,
|
||||||
*fqp.last().unwrap(),
|
fqp,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
ty.id = None;
|
ty.id = None;
|
||||||
|
@ -146,7 +146,7 @@ pub(crate) fn build_index<'tcx>(
|
||||||
lastpathid,
|
lastpathid,
|
||||||
crate_paths,
|
crate_paths,
|
||||||
ItemType::Primitive,
|
ItemType::Primitive,
|
||||||
sym,
|
&[sym],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
RenderTypeId::Index(_) => {}
|
RenderTypeId::Index(_) => {}
|
||||||
|
@ -191,7 +191,7 @@ pub(crate) fn build_index<'tcx>(
|
||||||
lastpathid += 1;
|
lastpathid += 1;
|
||||||
|
|
||||||
if let Some(&(ref fqp, short)) = paths.get(&defid) {
|
if let Some(&(ref fqp, short)) = paths.get(&defid) {
|
||||||
crate_paths.push((short, *fqp.last().unwrap()));
|
crate_paths.push((short, fqp.clone()));
|
||||||
Some(pathid)
|
Some(pathid)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -213,18 +213,58 @@ pub(crate) fn build_index<'tcx>(
|
||||||
struct CrateData<'a> {
|
struct CrateData<'a> {
|
||||||
doc: String,
|
doc: String,
|
||||||
items: Vec<&'a IndexItem>,
|
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.
|
// 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`.
|
// To be noted: the `usize` elements are indexes to `items`.
|
||||||
aliases: &'a BTreeMap<String, Vec<usize>>,
|
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> {
|
impl<'a> Serialize for CrateData<'a> {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
S: Serializer,
|
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 has_aliases = !self.aliases.is_empty();
|
||||||
let mut crate_data =
|
let mut crate_data =
|
||||||
serializer.serialize_struct("CrateData", if has_aliases { 9 } else { 8 })?;
|
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))
|
.filter_map(|(index, item)| item.deprecation.map(|_| index))
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
)?;
|
)?;
|
||||||
crate_data.serialize_field(
|
crate_data.serialize_field("p", &paths)?;
|
||||||
"p",
|
|
||||||
&self.paths.iter().map(|(it, s)| (it, s.as_str())).collect::<Vec<_>>(),
|
|
||||||
)?;
|
|
||||||
if has_aliases {
|
if has_aliases {
|
||||||
crate_data.serialize_field("a", &self.aliases)?;
|
crate_data.serialize_field("a", &self.aliases)?;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1462,6 +1462,32 @@ function initSearch(rawSearchIndex) {
|
||||||
if (!typePassesFilter(queryElem.typeFilter, fnType.ty)) {
|
if (!typePassesFilter(queryElem.typeFilter, fnType.ty)) {
|
||||||
continue;
|
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)) {
|
if (queryElem.generics.length === 0 || checkGenerics(fnType, queryElem)) {
|
||||||
currentFnTypeList.splice(i, 1);
|
currentFnTypeList.splice(i, 1);
|
||||||
const result = doHandleQueryElemList(currentFnTypeList, queryElemList);
|
const result = doHandleQueryElemList(currentFnTypeList, queryElemList);
|
||||||
|
@ -1862,14 +1888,14 @@ function initSearch(rawSearchIndex) {
|
||||||
* @param {QueryElement} elem
|
* @param {QueryElement} elem
|
||||||
*/
|
*/
|
||||||
function convertNameToId(elem) {
|
function convertNameToId(elem) {
|
||||||
if (typeNameIdMap.has(elem.name)) {
|
if (typeNameIdMap.has(elem.pathLast)) {
|
||||||
elem.id = typeNameIdMap.get(elem.name);
|
elem.id = typeNameIdMap.get(elem.pathLast);
|
||||||
} else if (!parsedQuery.literalSearch) {
|
} else if (!parsedQuery.literalSearch) {
|
||||||
let match = -1;
|
let match = -1;
|
||||||
let matchDist = maxEditDistance + 1;
|
let matchDist = maxEditDistance + 1;
|
||||||
let matchName = "";
|
let matchName = "";
|
||||||
for (const [name, id] of typeNameIdMap) {
|
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 && dist <= maxEditDistance) {
|
||||||
if (dist === matchDist && matchName > name) {
|
if (dist === matchDist && matchName > name) {
|
||||||
continue;
|
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`
|
// `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 {
|
return {
|
||||||
id: item === null ? -1 : buildTypeMapIndex(item.name),
|
id: buildTypeMapIndex(item.name),
|
||||||
ty: item === null ? null : item.ty,
|
ty: item.ty,
|
||||||
|
path: item.path,
|
||||||
generics: generics,
|
generics: generics,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
@ -2417,15 +2452,25 @@ ${item.displayPath}<span class="${type}">${name}</span>\
|
||||||
if (functionSearchType === 0) {
|
if (functionSearchType === 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
let inputs, output, item;
|
let inputs, output;
|
||||||
if (typeof functionSearchType[INPUTS_DATA] === "number") {
|
if (typeof functionSearchType[INPUTS_DATA] === "number") {
|
||||||
const pathIndex = functionSearchType[INPUTS_DATA];
|
const pathIndex = functionSearchType[INPUTS_DATA];
|
||||||
item = pathIndex === 0 ? null : lowercasePaths[pathIndex - 1];
|
if (pathIndex === 0) {
|
||||||
inputs = [{
|
inputs = [{
|
||||||
id: item === null ? -1 : buildTypeMapIndex(item.name),
|
id: -1,
|
||||||
ty: item === null ? null : item.ty,
|
ty: null,
|
||||||
generics: [],
|
path: null,
|
||||||
}];
|
generics: [],
|
||||||
|
}];
|
||||||
|
} else {
|
||||||
|
const item = lowercasePaths[pathIndex - 1];
|
||||||
|
inputs = [{
|
||||||
|
id: buildTypeMapIndex(item.name),
|
||||||
|
ty: item.ty,
|
||||||
|
path: item.path,
|
||||||
|
generics: [],
|
||||||
|
}];
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
inputs = buildItemSearchTypeAll(
|
inputs = buildItemSearchTypeAll(
|
||||||
functionSearchType[INPUTS_DATA],
|
functionSearchType[INPUTS_DATA],
|
||||||
|
@ -2435,12 +2480,22 @@ ${item.displayPath}<span class="${type}">${name}</span>\
|
||||||
if (functionSearchType.length > 1) {
|
if (functionSearchType.length > 1) {
|
||||||
if (typeof functionSearchType[OUTPUT_DATA] === "number") {
|
if (typeof functionSearchType[OUTPUT_DATA] === "number") {
|
||||||
const pathIndex = functionSearchType[OUTPUT_DATA];
|
const pathIndex = functionSearchType[OUTPUT_DATA];
|
||||||
item = pathIndex === 0 ? null : lowercasePaths[pathIndex - 1];
|
if (pathIndex === 0) {
|
||||||
output = [{
|
output = [{
|
||||||
id: item === null ? -1 : buildTypeMapIndex(item.name),
|
id: -1,
|
||||||
ty: item === null ? null : item.ty,
|
ty: null,
|
||||||
generics: [],
|
path: null,
|
||||||
}];
|
generics: [],
|
||||||
|
}];
|
||||||
|
} else {
|
||||||
|
const item = lowercasePaths[pathIndex - 1];
|
||||||
|
output = [{
|
||||||
|
id: buildTypeMapIndex(item.name),
|
||||||
|
ty: item.ty,
|
||||||
|
path: item.path,
|
||||||
|
generics: [],
|
||||||
|
}];
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
output = buildItemSearchTypeAll(
|
output = buildItemSearchTypeAll(
|
||||||
functionSearchType[OUTPUT_DATA],
|
functionSearchType[OUTPUT_DATA],
|
||||||
|
@ -2573,9 +2628,19 @@ ${item.displayPath}<span class="${type}">${name}</span>\
|
||||||
// convert `rawPaths` entries into object form
|
// convert `rawPaths` entries into object form
|
||||||
// generate normalizedPaths for function search mode
|
// generate normalizedPaths for function search mode
|
||||||
let len = paths.length;
|
let len = paths.length;
|
||||||
|
let lastPath = itemPaths.get(0);
|
||||||
for (let i = 0; i < len; ++i) {
|
for (let i = 0; i < len; ++i) {
|
||||||
lowercasePaths.push({ty: paths[i][0], name: paths[i][1].toLowerCase()});
|
const elem = paths[i];
|
||||||
paths[i] = {ty: paths[i][0], name: paths[i][1]};
|
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.
|
// 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
|
// operation that is cached for the life of the page state so that
|
||||||
// all other search operations have access to this cached data for
|
// all other search operations have access to this cached data for
|
||||||
// faster analysis operations
|
// faster analysis operations
|
||||||
|
lastPath = "";
|
||||||
len = itemTypes.length;
|
len = itemTypes.length;
|
||||||
let lastPath = "";
|
|
||||||
for (let i = 0; i < len; ++i) {
|
for (let i = 0; i < len; ++i) {
|
||||||
let word = "";
|
let word = "";
|
||||||
// This object should have exactly the same set of fields as the "crateRow"
|
// 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();
|
word = itemNames[i].toLowerCase();
|
||||||
}
|
}
|
||||||
searchWords.push(word);
|
searchWords.push(word);
|
||||||
|
const path = itemPaths.has(i) ? itemPaths.get(i) : lastPath;
|
||||||
const row = {
|
const row = {
|
||||||
crate: crate,
|
crate: crate,
|
||||||
ty: itemTypes.charCodeAt(i) - charA,
|
ty: itemTypes.charCodeAt(i) - charA,
|
||||||
name: itemNames[i],
|
name: itemNames[i],
|
||||||
path: itemPaths.has(i) ? itemPaths.get(i) : lastPath,
|
path: path,
|
||||||
desc: itemDescs[i],
|
desc: itemDescs[i],
|
||||||
parent: itemParentIdxs[i] > 0 ? paths[itemParentIdxs[i] - 1] : undefined,
|
parent: itemParentIdxs[i] > 0 ? paths[itemParentIdxs[i] - 1] : undefined,
|
||||||
type: buildFunctionSearchType(
|
type: buildFunctionSearchType(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue