Skip to content

Commit b9ed878

Browse files
committed
rustdoc: include impl generics / self in search index
1 parent 9fed130 commit b9ed878

File tree

5 files changed

+204
-17
lines changed

5 files changed

+204
-17
lines changed

src/librustdoc/clean/types.rs

+6
Original file line numberDiff line numberDiff line change
@@ -1410,6 +1410,12 @@ pub(crate) struct Generics {
14101410
pub(crate) where_predicates: Vec<WherePredicate>,
14111411
}
14121412

1413+
impl Generics {
1414+
pub(crate) fn is_empty(&self) -> bool {
1415+
self.params.is_empty() && self.where_predicates.is_empty()
1416+
}
1417+
}
1418+
14131419
#[derive(Clone, Debug)]
14141420
pub(crate) struct Function {
14151421
pub(crate) decl: FnDecl,

src/librustdoc/formats/cache.rs

+43-4
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,9 @@ pub(crate) struct Cache {
9595
// Private fields only used when initially crawling a crate to build a cache
9696
stack: Vec<Symbol>,
9797
parent_stack: Vec<DefId>,
98+
impl_generics_stack: Vec<(clean::Type, clean::Generics)>,
9899
parent_is_trait_impl: bool,
100+
parent_is_blanket_or_auto_impl: bool,
99101
stripped_mod: bool,
100102

101103
pub(crate) search_index: Vec<IndexItem>,
@@ -105,7 +107,8 @@ pub(crate) struct Cache {
105107
// then the fully qualified name of the structure isn't presented in `paths`
106108
// yet when its implementation methods are being indexed. Caches such methods
107109
// and their parent id here and indexes them at the end of crate parsing.
108-
pub(crate) orphan_impl_items: Vec<(DefId, clean::Item)>,
110+
pub(crate) orphan_impl_items:
111+
Vec<(DefId, clean::Item, Option<(clean::Type, clean::Generics)>, bool)>,
109112

110113
// Similarly to `orphan_impl_items`, sometimes trait impls are picked up
111114
// even though the trait itself is not exported. This can happen if a trait
@@ -315,15 +318,26 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
315318
desc,
316319
parent,
317320
parent_idx: None,
318-
search_type: get_function_type_for_search(&item, self.tcx, self.cache),
321+
search_type: get_function_type_for_search(
322+
&item,
323+
self.tcx,
324+
self.cache.impl_generics_stack.last(),
325+
self.cache.parent_is_blanket_or_auto_impl,
326+
self.cache,
327+
),
319328
aliases: item.attrs.get_doc_aliases(),
320329
});
321330
}
322331
}
323332
(Some(parent), None) if is_inherent_impl_item => {
324333
// We have a parent, but we don't know where they're
325334
// defined yet. Wait for later to index this item.
326-
self.cache.orphan_impl_items.push((parent, item.clone()));
335+
self.cache.orphan_impl_items.push((
336+
parent,
337+
item.clone(),
338+
self.cache.impl_generics_stack.last().cloned(),
339+
self.cache.parent_is_blanket_or_auto_impl,
340+
));
327341
}
328342
_ => {}
329343
}
@@ -440,9 +454,34 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
440454
_ => false,
441455
};
442456

457+
// When recursing into an impl item, make the generics context visible
458+
// to the child items.
459+
let item = {
460+
let mut item = item;
461+
let mut old_parent_is_blanket_or_auto_impl = false;
462+
if let clean::Item { kind: box clean::ImplItem(ref mut i), .. } = item {
463+
old_parent_is_blanket_or_auto_impl = mem::replace(
464+
&mut self.cache.parent_is_blanket_or_auto_impl,
465+
!matches!(i.kind, clean::ImplKind::Normal),
466+
);
467+
self.cache.impl_generics_stack.push((
468+
mem::replace(&mut i.for_, clean::Type::Infer),
469+
mem::replace(
470+
&mut i.generics,
471+
clean::Generics { params: Vec::new(), where_predicates: Vec::new() },
472+
),
473+
));
474+
}
475+
let mut item = self.fold_item_recur(item);
476+
if let clean::Item { kind: box clean::ImplItem(ref mut i), .. } = item {
477+
self.cache.parent_is_blanket_or_auto_impl = old_parent_is_blanket_or_auto_impl;
478+
(i.for_, i.generics) = self.cache.impl_generics_stack.pop().expect("pushed above");
479+
}
480+
item
481+
};
482+
443483
// Once we've recursively found all the generics, hoard off all the
444484
// implementations elsewhere.
445-
let item = self.fold_item_recur(item);
446485
let ret = if let clean::Item { kind: box clean::ImplItem(ref i), .. } = item {
447486
// Figure out the id of this impl. This may map to a
448487
// primitive rather than always to a struct/enum.

src/librustdoc/html/render/search_index.rs

+63-13
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ pub(crate) fn build_index<'tcx>(
2525

2626
// Attach all orphan items to the type's definition if the type
2727
// has since been learned.
28-
for &(did, ref item) in &cache.orphan_impl_items {
28+
for &(did, ref item, ref impl_generics, from_blanket_or_auto_impl) in &cache.orphan_impl_items {
2929
if let Some(&(ref fqp, _)) = cache.paths.get(&did) {
3030
let desc = item
3131
.doc_value()
@@ -37,7 +37,13 @@ pub(crate) fn build_index<'tcx>(
3737
desc,
3838
parent: Some(did),
3939
parent_idx: None,
40-
search_type: get_function_type_for_search(item, tcx, cache),
40+
search_type: get_function_type_for_search(
41+
item,
42+
tcx,
43+
impl_generics.as_ref(),
44+
from_blanket_or_auto_impl,
45+
cache,
46+
),
4147
aliases: item.attrs.get_doc_aliases(),
4248
});
4349
}
@@ -192,12 +198,18 @@ pub(crate) fn build_index<'tcx>(
192198
pub(crate) fn get_function_type_for_search<'tcx>(
193199
item: &clean::Item,
194200
tcx: TyCtxt<'tcx>,
201+
impl_generics: Option<&(clean::Type, clean::Generics)>,
202+
from_blanket_or_auto_impl: bool,
195203
cache: &Cache,
196204
) -> Option<IndexItemFunctionType> {
205+
if from_blanket_or_auto_impl {
206+
return None;
207+
}
208+
197209
let (mut inputs, mut output) = match *item.kind {
198-
clean::FunctionItem(ref f) => get_fn_inputs_and_outputs(f, tcx, cache),
199-
clean::MethodItem(ref m, _) => get_fn_inputs_and_outputs(m, tcx, cache),
200-
clean::TyMethodItem(ref m) => get_fn_inputs_and_outputs(m, tcx, cache),
210+
clean::FunctionItem(ref f) => get_fn_inputs_and_outputs(f, tcx, impl_generics, cache),
211+
clean::MethodItem(ref m, _) => get_fn_inputs_and_outputs(m, tcx, impl_generics, cache),
212+
clean::TyMethodItem(ref m) => get_fn_inputs_and_outputs(m, tcx, impl_generics, cache),
201213
_ => return None,
202214
};
203215

@@ -247,9 +259,10 @@ fn get_index_type_name(clean_type: &clean::Type) -> Option<Symbol> {
247259
/// Important note: It goes through generics recursively. So if you have
248260
/// `T: Option<Result<(), ()>>`, it'll go into `Option` and then into `Result`.
249261
#[instrument(level = "trace", skip(tcx, res, cache))]
250-
fn add_generics_and_bounds_as_types<'tcx>(
262+
fn add_generics_and_bounds_as_types<'tcx, 'a>(
263+
self_: Option<&'a Type>,
251264
generics: &Generics,
252-
arg: &Type,
265+
arg: &'a Type,
253266
tcx: TyCtxt<'tcx>,
254267
recurse: usize,
255268
res: &mut Vec<TypeWithKind>,
@@ -334,6 +347,17 @@ fn add_generics_and_bounds_as_types<'tcx>(
334347
return;
335348
}
336349

350+
// First, check if it's "Self".
351+
let arg = if let Some(self_) = self_ {
352+
match &*arg {
353+
Type::BorrowedRef { type_, .. } if type_.is_self_type() => self_,
354+
type_ if type_.is_self_type() => self_,
355+
arg => arg,
356+
}
357+
} else {
358+
arg
359+
};
360+
337361
// If this argument is a type parameter and not a trait bound or a type, we need to look
338362
// for its bounds.
339363
if let Type::Generic(arg_s) = *arg {
@@ -350,6 +374,7 @@ fn add_generics_and_bounds_as_types<'tcx>(
350374
match &param_def.kind {
351375
clean::GenericParamDefKind::Type { default: Some(ty), .. } => {
352376
add_generics_and_bounds_as_types(
377+
self_,
353378
generics,
354379
ty,
355380
tcx,
@@ -372,6 +397,7 @@ fn add_generics_and_bounds_as_types<'tcx>(
372397
if let Some(path) = bound.get_trait_path() {
373398
let ty = Type::Path { path };
374399
add_generics_and_bounds_as_types(
400+
self_,
375401
generics,
376402
&ty,
377403
tcx,
@@ -393,6 +419,7 @@ fn add_generics_and_bounds_as_types<'tcx>(
393419
if let Some(arg_generics) = arg.generics() {
394420
for gen in arg_generics.iter() {
395421
add_generics_and_bounds_as_types(
422+
self_,
396423
generics,
397424
gen,
398425
tcx,
@@ -413,18 +440,33 @@ fn add_generics_and_bounds_as_types<'tcx>(
413440
fn get_fn_inputs_and_outputs<'tcx>(
414441
func: &Function,
415442
tcx: TyCtxt<'tcx>,
443+
impl_generics: Option<&(clean::Type, clean::Generics)>,
416444
cache: &Cache,
417445
) -> (Vec<TypeWithKind>, Vec<TypeWithKind>) {
418446
let decl = &func.decl;
419-
let generics = &func.generics;
447+
448+
let combined_generics;
449+
let (self_, generics) = if let Some(&(ref impl_self, ref impl_generics)) = impl_generics {
450+
match (impl_generics.is_empty(), func.generics.is_empty()) {
451+
(true, _) => (Some(impl_self), &func.generics),
452+
(_, true) => (Some(impl_self), impl_generics),
453+
(false, false) => {
454+
let mut params = func.generics.params.clone();
455+
params.extend(impl_generics.params.clone());
456+
let mut where_predicates = func.generics.where_predicates.clone();
457+
where_predicates.extend(impl_generics.where_predicates.clone());
458+
combined_generics = clean::Generics { params, where_predicates };
459+
(Some(impl_self), &combined_generics)
460+
}
461+
}
462+
} else {
463+
(None, &func.generics)
464+
};
420465

421466
let mut all_types = Vec::new();
422467
for arg in decl.inputs.values.iter() {
423-
if arg.type_.is_self_type() {
424-
continue;
425-
}
426468
let mut args = Vec::new();
427-
add_generics_and_bounds_as_types(generics, &arg.type_, tcx, 0, &mut args, cache);
469+
add_generics_and_bounds_as_types(self_, generics, &arg.type_, tcx, 0, &mut args, cache);
428470
if !args.is_empty() {
429471
all_types.extend(args);
430472
} else {
@@ -437,7 +479,15 @@ fn get_fn_inputs_and_outputs<'tcx>(
437479
let mut ret_types = Vec::new();
438480
match decl.output {
439481
FnRetTy::Return(ref return_type) => {
440-
add_generics_and_bounds_as_types(generics, return_type, tcx, 0, &mut ret_types, cache);
482+
add_generics_and_bounds_as_types(
483+
self_,
484+
generics,
485+
return_type,
486+
tcx,
487+
0,
488+
&mut ret_types,
489+
cache,
490+
);
441491
if ret_types.is_empty() {
442492
if let Some(kind) = return_type.def_id(cache).map(|did| tcx.def_kind(did).into()) {
443493
ret_types.push(TypeWithKind::from((get_index_type(return_type, vec![]), kind)));

src/test/rustdoc-js/generics-impl.js

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// exact-check
2+
3+
const QUERY = [
4+
'Aaaaaaa -> u32',
5+
'Aaaaaaa -> bool',
6+
'Aaaaaaa -> usize',
7+
'Read -> u64',
8+
'bool -> u64',
9+
'Ddddddd -> u64',
10+
'-> Ddddddd'
11+
];
12+
13+
const EXPECTED = [
14+
{
15+
// Aaaaaaa -> u32
16+
'others': [
17+
{ 'path': 'generics_impl::Aaaaaaa', 'name': 'bbbbbbb' },
18+
],
19+
},
20+
{
21+
// Aaaaaaa -> bool
22+
'others': [
23+
{ 'path': 'generics_impl::Aaaaaaa', 'name': 'ccccccc' },
24+
],
25+
},
26+
{
27+
// Aaaaaaa -> usize
28+
'others': [
29+
{ 'path': 'generics_impl::Aaaaaaa', 'name': 'read' },
30+
],
31+
},
32+
{
33+
// Read -> u64
34+
'others': [
35+
{ 'path': 'generics_impl::Ddddddd', 'name': 'eeeeeee' },
36+
{ 'path': 'generics_impl::Ddddddd', 'name': 'ggggggg' },
37+
],
38+
},
39+
{
40+
// bool -> u64
41+
'others': [
42+
{ 'path': 'generics_impl::Ddddddd', 'name': 'fffffff' },
43+
],
44+
},
45+
{
46+
// Ddddddd -> u64
47+
'others': [
48+
{ 'path': 'generics_impl::Ddddddd', 'name': 'ggggggg' },
49+
],
50+
},
51+
{
52+
// -> "Ddddddd"
53+
'returned': [
54+
{ 'path': 'generics_impl::Ddddddd', 'name': 'hhhhhhh' },
55+
],
56+
},
57+
];

src/test/rustdoc-js/generics-impl.rs

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
use std::io::{Result as IoResult, Read};
2+
3+
pub struct Aaaaaaa;
4+
5+
impl Aaaaaaa {
6+
pub fn bbbbbbb(self) -> u32 {
7+
1
8+
}
9+
pub fn ccccccc(&self) -> bool {
10+
true
11+
}
12+
}
13+
14+
impl Read for Aaaaaaa {
15+
fn read(&mut self, out: &mut [u8]) -> IoResult<usize> {
16+
Ok(out.len())
17+
}
18+
}
19+
20+
pub struct Ddddddd<T>(T);
21+
22+
impl<T: Read> Ddddddd<T> {
23+
pub fn eeeeeee(_: T) -> u64 {
24+
1
25+
}
26+
pub fn fffffff(_: bool) -> u64 {
27+
1
28+
}
29+
pub fn ggggggg(self) -> u64 {
30+
1
31+
}
32+
pub fn hhhhhhh() -> Self where T: Default {
33+
Ddddddd(T::default())
34+
}
35+
}

0 commit comments

Comments
 (0)