rustdoc: include impl generics / self in search index
This commit is contained in:
parent
9fed13030c
commit
b9ed8784b3
@ -1410,6 +1410,12 @@ pub(crate) struct Generics {
|
|||||||
pub(crate) where_predicates: Vec<WherePredicate>,
|
pub(crate) where_predicates: Vec<WherePredicate>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Generics {
|
||||||
|
pub(crate) fn is_empty(&self) -> bool {
|
||||||
|
self.params.is_empty() && self.where_predicates.is_empty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub(crate) struct Function {
|
pub(crate) struct Function {
|
||||||
pub(crate) decl: FnDecl,
|
pub(crate) decl: FnDecl,
|
||||||
|
@ -95,7 +95,9 @@ pub(crate) struct Cache {
|
|||||||
// Private fields only used when initially crawling a crate to build a cache
|
// Private fields only used when initially crawling a crate to build a cache
|
||||||
stack: Vec<Symbol>,
|
stack: Vec<Symbol>,
|
||||||
parent_stack: Vec<DefId>,
|
parent_stack: Vec<DefId>,
|
||||||
|
impl_generics_stack: Vec<(clean::Type, clean::Generics)>,
|
||||||
parent_is_trait_impl: bool,
|
parent_is_trait_impl: bool,
|
||||||
|
parent_is_blanket_or_auto_impl: bool,
|
||||||
stripped_mod: bool,
|
stripped_mod: bool,
|
||||||
|
|
||||||
pub(crate) search_index: Vec<IndexItem>,
|
pub(crate) search_index: Vec<IndexItem>,
|
||||||
@ -105,7 +107,8 @@ pub(crate) struct Cache {
|
|||||||
// then the fully qualified name of the structure isn't presented in `paths`
|
// then the fully qualified name of the structure isn't presented in `paths`
|
||||||
// yet when its implementation methods are being indexed. Caches such methods
|
// yet when its implementation methods are being indexed. Caches such methods
|
||||||
// and their parent id here and indexes them at the end of crate parsing.
|
// and their parent id here and indexes them at the end of crate parsing.
|
||||||
pub(crate) orphan_impl_items: Vec<(DefId, clean::Item)>,
|
pub(crate) orphan_impl_items:
|
||||||
|
Vec<(DefId, clean::Item, Option<(clean::Type, clean::Generics)>, bool)>,
|
||||||
|
|
||||||
// Similarly to `orphan_impl_items`, sometimes trait impls are picked up
|
// Similarly to `orphan_impl_items`, sometimes trait impls are picked up
|
||||||
// even though the trait itself is not exported. This can happen if a trait
|
// even though the trait itself is not exported. This can happen if a trait
|
||||||
@ -315,7 +318,13 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
|
|||||||
desc,
|
desc,
|
||||||
parent,
|
parent,
|
||||||
parent_idx: None,
|
parent_idx: None,
|
||||||
search_type: get_function_type_for_search(&item, self.tcx, self.cache),
|
search_type: get_function_type_for_search(
|
||||||
|
&item,
|
||||||
|
self.tcx,
|
||||||
|
self.cache.impl_generics_stack.last(),
|
||||||
|
self.cache.parent_is_blanket_or_auto_impl,
|
||||||
|
self.cache,
|
||||||
|
),
|
||||||
aliases: item.attrs.get_doc_aliases(),
|
aliases: item.attrs.get_doc_aliases(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -323,7 +332,12 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
|
|||||||
(Some(parent), None) if is_inherent_impl_item => {
|
(Some(parent), None) if is_inherent_impl_item => {
|
||||||
// We have a parent, but we don't know where they're
|
// We have a parent, but we don't know where they're
|
||||||
// defined yet. Wait for later to index this item.
|
// defined yet. Wait for later to index this item.
|
||||||
self.cache.orphan_impl_items.push((parent, item.clone()));
|
self.cache.orphan_impl_items.push((
|
||||||
|
parent,
|
||||||
|
item.clone(),
|
||||||
|
self.cache.impl_generics_stack.last().cloned(),
|
||||||
|
self.cache.parent_is_blanket_or_auto_impl,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@ -440,9 +454,34 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
|
|||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// When recursing into an impl item, make the generics context visible
|
||||||
|
// to the child items.
|
||||||
|
let item = {
|
||||||
|
let mut item = item;
|
||||||
|
let mut old_parent_is_blanket_or_auto_impl = false;
|
||||||
|
if let clean::Item { kind: box clean::ImplItem(ref mut i), .. } = item {
|
||||||
|
old_parent_is_blanket_or_auto_impl = mem::replace(
|
||||||
|
&mut self.cache.parent_is_blanket_or_auto_impl,
|
||||||
|
!matches!(i.kind, clean::ImplKind::Normal),
|
||||||
|
);
|
||||||
|
self.cache.impl_generics_stack.push((
|
||||||
|
mem::replace(&mut i.for_, clean::Type::Infer),
|
||||||
|
mem::replace(
|
||||||
|
&mut i.generics,
|
||||||
|
clean::Generics { params: Vec::new(), where_predicates: Vec::new() },
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
let mut item = self.fold_item_recur(item);
|
||||||
|
if let clean::Item { kind: box clean::ImplItem(ref mut i), .. } = item {
|
||||||
|
self.cache.parent_is_blanket_or_auto_impl = old_parent_is_blanket_or_auto_impl;
|
||||||
|
(i.for_, i.generics) = self.cache.impl_generics_stack.pop().expect("pushed above");
|
||||||
|
}
|
||||||
|
item
|
||||||
|
};
|
||||||
|
|
||||||
// Once we've recursively found all the generics, hoard off all the
|
// Once we've recursively found all the generics, hoard off all the
|
||||||
// implementations elsewhere.
|
// implementations elsewhere.
|
||||||
let item = self.fold_item_recur(item);
|
|
||||||
let ret = if let clean::Item { kind: box clean::ImplItem(ref i), .. } = item {
|
let ret = if let clean::Item { kind: box clean::ImplItem(ref i), .. } = item {
|
||||||
// Figure out the id of this impl. This may map to a
|
// Figure out the id of this impl. This may map to a
|
||||||
// primitive rather than always to a struct/enum.
|
// primitive rather than always to a struct/enum.
|
||||||
|
@ -25,7 +25,7 @@ pub(crate) fn build_index<'tcx>(
|
|||||||
|
|
||||||
// Attach all orphan items to the type's definition if the type
|
// Attach all orphan items to the type's definition if the type
|
||||||
// has since been learned.
|
// has since been learned.
|
||||||
for &(did, ref item) in &cache.orphan_impl_items {
|
for &(did, ref item, ref impl_generics, from_blanket_or_auto_impl) in &cache.orphan_impl_items {
|
||||||
if let Some(&(ref fqp, _)) = cache.paths.get(&did) {
|
if let Some(&(ref fqp, _)) = cache.paths.get(&did) {
|
||||||
let desc = item
|
let desc = item
|
||||||
.doc_value()
|
.doc_value()
|
||||||
@ -37,7 +37,13 @@ pub(crate) fn build_index<'tcx>(
|
|||||||
desc,
|
desc,
|
||||||
parent: Some(did),
|
parent: Some(did),
|
||||||
parent_idx: None,
|
parent_idx: None,
|
||||||
search_type: get_function_type_for_search(item, tcx, cache),
|
search_type: get_function_type_for_search(
|
||||||
|
item,
|
||||||
|
tcx,
|
||||||
|
impl_generics.as_ref(),
|
||||||
|
from_blanket_or_auto_impl,
|
||||||
|
cache,
|
||||||
|
),
|
||||||
aliases: item.attrs.get_doc_aliases(),
|
aliases: item.attrs.get_doc_aliases(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -192,12 +198,18 @@ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|||||||
pub(crate) fn get_function_type_for_search<'tcx>(
|
pub(crate) fn get_function_type_for_search<'tcx>(
|
||||||
item: &clean::Item,
|
item: &clean::Item,
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
|
impl_generics: Option<&(clean::Type, clean::Generics)>,
|
||||||
|
from_blanket_or_auto_impl: bool,
|
||||||
cache: &Cache,
|
cache: &Cache,
|
||||||
) -> Option<IndexItemFunctionType> {
|
) -> Option<IndexItemFunctionType> {
|
||||||
|
if from_blanket_or_auto_impl {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
let (mut inputs, mut output) = match *item.kind {
|
let (mut inputs, mut output) = match *item.kind {
|
||||||
clean::FunctionItem(ref f) => get_fn_inputs_and_outputs(f, tcx, cache),
|
clean::FunctionItem(ref f) => get_fn_inputs_and_outputs(f, tcx, impl_generics, cache),
|
||||||
clean::MethodItem(ref m, _) => get_fn_inputs_and_outputs(m, tcx, cache),
|
clean::MethodItem(ref m, _) => get_fn_inputs_and_outputs(m, tcx, impl_generics, cache),
|
||||||
clean::TyMethodItem(ref m) => get_fn_inputs_and_outputs(m, tcx, cache),
|
clean::TyMethodItem(ref m) => get_fn_inputs_and_outputs(m, tcx, impl_generics, cache),
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -247,9 +259,10 @@ fn get_index_type_name(clean_type: &clean::Type) -> Option<Symbol> {
|
|||||||
/// Important note: It goes through generics recursively. So if you have
|
/// Important note: It goes through generics recursively. So if you have
|
||||||
/// `T: Option<Result<(), ()>>`, it'll go into `Option` and then into `Result`.
|
/// `T: Option<Result<(), ()>>`, it'll go into `Option` and then into `Result`.
|
||||||
#[instrument(level = "trace", skip(tcx, res, cache))]
|
#[instrument(level = "trace", skip(tcx, res, cache))]
|
||||||
fn add_generics_and_bounds_as_types<'tcx>(
|
fn add_generics_and_bounds_as_types<'tcx, 'a>(
|
||||||
|
self_: Option<&'a Type>,
|
||||||
generics: &Generics,
|
generics: &Generics,
|
||||||
arg: &Type,
|
arg: &'a Type,
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
recurse: usize,
|
recurse: usize,
|
||||||
res: &mut Vec<TypeWithKind>,
|
res: &mut Vec<TypeWithKind>,
|
||||||
@ -334,6 +347,17 @@ fn insert_ty(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// First, check if it's "Self".
|
||||||
|
let arg = if let Some(self_) = self_ {
|
||||||
|
match &*arg {
|
||||||
|
Type::BorrowedRef { type_, .. } if type_.is_self_type() => self_,
|
||||||
|
type_ if type_.is_self_type() => self_,
|
||||||
|
arg => arg,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
arg
|
||||||
|
};
|
||||||
|
|
||||||
// If this argument is a type parameter and not a trait bound or a type, we need to look
|
// If this argument is a type parameter and not a trait bound or a type, we need to look
|
||||||
// for its bounds.
|
// for its bounds.
|
||||||
if let Type::Generic(arg_s) = *arg {
|
if let Type::Generic(arg_s) = *arg {
|
||||||
@ -350,6 +374,7 @@ fn insert_ty(
|
|||||||
match ¶m_def.kind {
|
match ¶m_def.kind {
|
||||||
clean::GenericParamDefKind::Type { default: Some(ty), .. } => {
|
clean::GenericParamDefKind::Type { default: Some(ty), .. } => {
|
||||||
add_generics_and_bounds_as_types(
|
add_generics_and_bounds_as_types(
|
||||||
|
self_,
|
||||||
generics,
|
generics,
|
||||||
ty,
|
ty,
|
||||||
tcx,
|
tcx,
|
||||||
@ -372,6 +397,7 @@ fn insert_ty(
|
|||||||
if let Some(path) = bound.get_trait_path() {
|
if let Some(path) = bound.get_trait_path() {
|
||||||
let ty = Type::Path { path };
|
let ty = Type::Path { path };
|
||||||
add_generics_and_bounds_as_types(
|
add_generics_and_bounds_as_types(
|
||||||
|
self_,
|
||||||
generics,
|
generics,
|
||||||
&ty,
|
&ty,
|
||||||
tcx,
|
tcx,
|
||||||
@ -393,6 +419,7 @@ fn insert_ty(
|
|||||||
if let Some(arg_generics) = arg.generics() {
|
if let Some(arg_generics) = arg.generics() {
|
||||||
for gen in arg_generics.iter() {
|
for gen in arg_generics.iter() {
|
||||||
add_generics_and_bounds_as_types(
|
add_generics_and_bounds_as_types(
|
||||||
|
self_,
|
||||||
generics,
|
generics,
|
||||||
gen,
|
gen,
|
||||||
tcx,
|
tcx,
|
||||||
@ -413,18 +440,33 @@ fn insert_ty(
|
|||||||
fn get_fn_inputs_and_outputs<'tcx>(
|
fn get_fn_inputs_and_outputs<'tcx>(
|
||||||
func: &Function,
|
func: &Function,
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
|
impl_generics: Option<&(clean::Type, clean::Generics)>,
|
||||||
cache: &Cache,
|
cache: &Cache,
|
||||||
) -> (Vec<TypeWithKind>, Vec<TypeWithKind>) {
|
) -> (Vec<TypeWithKind>, Vec<TypeWithKind>) {
|
||||||
let decl = &func.decl;
|
let decl = &func.decl;
|
||||||
let generics = &func.generics;
|
|
||||||
|
let combined_generics;
|
||||||
|
let (self_, generics) = if let Some(&(ref impl_self, ref impl_generics)) = impl_generics {
|
||||||
|
match (impl_generics.is_empty(), func.generics.is_empty()) {
|
||||||
|
(true, _) => (Some(impl_self), &func.generics),
|
||||||
|
(_, true) => (Some(impl_self), impl_generics),
|
||||||
|
(false, false) => {
|
||||||
|
let mut params = func.generics.params.clone();
|
||||||
|
params.extend(impl_generics.params.clone());
|
||||||
|
let mut where_predicates = func.generics.where_predicates.clone();
|
||||||
|
where_predicates.extend(impl_generics.where_predicates.clone());
|
||||||
|
combined_generics = clean::Generics { params, where_predicates };
|
||||||
|
(Some(impl_self), &combined_generics)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
(None, &func.generics)
|
||||||
|
};
|
||||||
|
|
||||||
let mut all_types = Vec::new();
|
let mut all_types = Vec::new();
|
||||||
for arg in decl.inputs.values.iter() {
|
for arg in decl.inputs.values.iter() {
|
||||||
if arg.type_.is_self_type() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let mut args = Vec::new();
|
let mut args = Vec::new();
|
||||||
add_generics_and_bounds_as_types(generics, &arg.type_, tcx, 0, &mut args, cache);
|
add_generics_and_bounds_as_types(self_, generics, &arg.type_, tcx, 0, &mut args, cache);
|
||||||
if !args.is_empty() {
|
if !args.is_empty() {
|
||||||
all_types.extend(args);
|
all_types.extend(args);
|
||||||
} else {
|
} else {
|
||||||
@ -437,7 +479,15 @@ fn get_fn_inputs_and_outputs<'tcx>(
|
|||||||
let mut ret_types = Vec::new();
|
let mut ret_types = Vec::new();
|
||||||
match decl.output {
|
match decl.output {
|
||||||
FnRetTy::Return(ref return_type) => {
|
FnRetTy::Return(ref return_type) => {
|
||||||
add_generics_and_bounds_as_types(generics, return_type, tcx, 0, &mut ret_types, cache);
|
add_generics_and_bounds_as_types(
|
||||||
|
self_,
|
||||||
|
generics,
|
||||||
|
return_type,
|
||||||
|
tcx,
|
||||||
|
0,
|
||||||
|
&mut ret_types,
|
||||||
|
cache,
|
||||||
|
);
|
||||||
if ret_types.is_empty() {
|
if ret_types.is_empty() {
|
||||||
if let Some(kind) = return_type.def_id(cache).map(|did| tcx.def_kind(did).into()) {
|
if let Some(kind) = return_type.def_id(cache).map(|did| tcx.def_kind(did).into()) {
|
||||||
ret_types.push(TypeWithKind::from((get_index_type(return_type, vec![]), kind)));
|
ret_types.push(TypeWithKind::from((get_index_type(return_type, vec![]), kind)));
|
||||||
|
57
src/test/rustdoc-js/generics-impl.js
Normal file
57
src/test/rustdoc-js/generics-impl.js
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
// exact-check
|
||||||
|
|
||||||
|
const QUERY = [
|
||||||
|
'Aaaaaaa -> u32',
|
||||||
|
'Aaaaaaa -> bool',
|
||||||
|
'Aaaaaaa -> usize',
|
||||||
|
'Read -> u64',
|
||||||
|
'bool -> u64',
|
||||||
|
'Ddddddd -> u64',
|
||||||
|
'-> Ddddddd'
|
||||||
|
];
|
||||||
|
|
||||||
|
const EXPECTED = [
|
||||||
|
{
|
||||||
|
// Aaaaaaa -> u32
|
||||||
|
'others': [
|
||||||
|
{ 'path': 'generics_impl::Aaaaaaa', 'name': 'bbbbbbb' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Aaaaaaa -> bool
|
||||||
|
'others': [
|
||||||
|
{ 'path': 'generics_impl::Aaaaaaa', 'name': 'ccccccc' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Aaaaaaa -> usize
|
||||||
|
'others': [
|
||||||
|
{ 'path': 'generics_impl::Aaaaaaa', 'name': 'read' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Read -> u64
|
||||||
|
'others': [
|
||||||
|
{ 'path': 'generics_impl::Ddddddd', 'name': 'eeeeeee' },
|
||||||
|
{ 'path': 'generics_impl::Ddddddd', 'name': 'ggggggg' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// bool -> u64
|
||||||
|
'others': [
|
||||||
|
{ 'path': 'generics_impl::Ddddddd', 'name': 'fffffff' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Ddddddd -> u64
|
||||||
|
'others': [
|
||||||
|
{ 'path': 'generics_impl::Ddddddd', 'name': 'ggggggg' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// -> "Ddddddd"
|
||||||
|
'returned': [
|
||||||
|
{ 'path': 'generics_impl::Ddddddd', 'name': 'hhhhhhh' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
35
src/test/rustdoc-js/generics-impl.rs
Normal file
35
src/test/rustdoc-js/generics-impl.rs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
use std::io::{Result as IoResult, Read};
|
||||||
|
|
||||||
|
pub struct Aaaaaaa;
|
||||||
|
|
||||||
|
impl Aaaaaaa {
|
||||||
|
pub fn bbbbbbb(self) -> u32 {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
pub fn ccccccc(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Read for Aaaaaaa {
|
||||||
|
fn read(&mut self, out: &mut [u8]) -> IoResult<usize> {
|
||||||
|
Ok(out.len())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Ddddddd<T>(T);
|
||||||
|
|
||||||
|
impl<T: Read> Ddddddd<T> {
|
||||||
|
pub fn eeeeeee(_: T) -> u64 {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
pub fn fffffff(_: bool) -> u64 {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
pub fn ggggggg(self) -> u64 {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
pub fn hhhhhhh() -> Self where T: Default {
|
||||||
|
Ddddddd(T::default())
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user