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>,
|
||||
}
|
||||
|
||||
impl Generics {
|
||||
pub(crate) fn is_empty(&self) -> bool {
|
||||
self.params.is_empty() && self.where_predicates.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct Function {
|
||||
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
|
||||
stack: Vec<Symbol>,
|
||||
parent_stack: Vec<DefId>,
|
||||
impl_generics_stack: Vec<(clean::Type, clean::Generics)>,
|
||||
parent_is_trait_impl: bool,
|
||||
parent_is_blanket_or_auto_impl: bool,
|
||||
stripped_mod: bool,
|
||||
|
||||
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`
|
||||
// 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.
|
||||
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
|
||||
// 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,
|
||||
parent,
|
||||
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(),
|
||||
});
|
||||
}
|
||||
@ -323,7 +332,12 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
|
||||
(Some(parent), None) if is_inherent_impl_item => {
|
||||
// We have a parent, but we don't know where they're
|
||||
// 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,
|
||||
};
|
||||
|
||||
// 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
|
||||
// implementations elsewhere.
|
||||
let item = self.fold_item_recur(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
|
||||
// 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
|
||||
// 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) {
|
||||
let desc = item
|
||||
.doc_value()
|
||||
@ -37,7 +37,13 @@ pub(crate) fn build_index<'tcx>(
|
||||
desc,
|
||||
parent: Some(did),
|
||||
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(),
|
||||
});
|
||||
}
|
||||
@ -192,12 +198,18 @@ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
pub(crate) fn get_function_type_for_search<'tcx>(
|
||||
item: &clean::Item,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
impl_generics: Option<&(clean::Type, clean::Generics)>,
|
||||
from_blanket_or_auto_impl: bool,
|
||||
cache: &Cache,
|
||||
) -> Option<IndexItemFunctionType> {
|
||||
if from_blanket_or_auto_impl {
|
||||
return None;
|
||||
}
|
||||
|
||||
let (mut inputs, mut output) = match *item.kind {
|
||||
clean::FunctionItem(ref f) => get_fn_inputs_and_outputs(f, tcx, cache),
|
||||
clean::MethodItem(ref m, _) => get_fn_inputs_and_outputs(m, tcx, cache),
|
||||
clean::TyMethodItem(ref m) => get_fn_inputs_and_outputs(m, 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, impl_generics, cache),
|
||||
clean::TyMethodItem(ref m) => get_fn_inputs_and_outputs(m, tcx, impl_generics, cache),
|
||||
_ => 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
|
||||
/// `T: Option<Result<(), ()>>`, it'll go into `Option` and then into `Result`.
|
||||
#[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,
|
||||
arg: &Type,
|
||||
arg: &'a Type,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
recurse: usize,
|
||||
res: &mut Vec<TypeWithKind>,
|
||||
@ -334,6 +347,17 @@ fn insert_ty(
|
||||
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
|
||||
// for its bounds.
|
||||
if let Type::Generic(arg_s) = *arg {
|
||||
@ -350,6 +374,7 @@ fn insert_ty(
|
||||
match ¶m_def.kind {
|
||||
clean::GenericParamDefKind::Type { default: Some(ty), .. } => {
|
||||
add_generics_and_bounds_as_types(
|
||||
self_,
|
||||
generics,
|
||||
ty,
|
||||
tcx,
|
||||
@ -372,6 +397,7 @@ fn insert_ty(
|
||||
if let Some(path) = bound.get_trait_path() {
|
||||
let ty = Type::Path { path };
|
||||
add_generics_and_bounds_as_types(
|
||||
self_,
|
||||
generics,
|
||||
&ty,
|
||||
tcx,
|
||||
@ -393,6 +419,7 @@ fn insert_ty(
|
||||
if let Some(arg_generics) = arg.generics() {
|
||||
for gen in arg_generics.iter() {
|
||||
add_generics_and_bounds_as_types(
|
||||
self_,
|
||||
generics,
|
||||
gen,
|
||||
tcx,
|
||||
@ -413,18 +440,33 @@ fn insert_ty(
|
||||
fn get_fn_inputs_and_outputs<'tcx>(
|
||||
func: &Function,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
impl_generics: Option<&(clean::Type, clean::Generics)>,
|
||||
cache: &Cache,
|
||||
) -> (Vec<TypeWithKind>, Vec<TypeWithKind>) {
|
||||
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();
|
||||
for arg in decl.inputs.values.iter() {
|
||||
if arg.type_.is_self_type() {
|
||||
continue;
|
||||
}
|
||||
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() {
|
||||
all_types.extend(args);
|
||||
} else {
|
||||
@ -437,7 +479,15 @@ fn get_fn_inputs_and_outputs<'tcx>(
|
||||
let mut ret_types = Vec::new();
|
||||
match decl.output {
|
||||
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 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)));
|
||||
|
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