2020-06-24 08:16:21 -05:00
|
|
|
use std::mem;
|
|
|
|
|
|
2023-04-02 16:35:17 -07:00
|
|
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
|
2023-01-22 01:33:53 +04:00
|
|
|
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet};
|
2022-04-29 14:01:57 -07:00
|
|
|
use rustc_middle::ty::{self, TyCtxt};
|
2022-09-27 12:27:04 -07:00
|
|
|
use rustc_span::Symbol;
|
2020-06-24 08:16:21 -05:00
|
|
|
|
2021-12-27 18:57:07 -08:00
|
|
|
use crate::clean::{self, types::ExternalLocation, ExternalCrate, ItemId, PrimitiveType};
|
2021-11-19 17:51:45 -05:00
|
|
|
use crate::core::DocContext;
|
2020-06-24 08:16:21 -05:00
|
|
|
use crate::fold::DocFolder;
|
|
|
|
|
use crate::formats::item_type::ItemType;
|
|
|
|
|
use crate::formats::Impl;
|
2021-12-15 06:18:18 +11:00
|
|
|
use crate::html::format::join_with_double_colon;
|
2020-10-04 20:42:34 -07:00
|
|
|
use crate::html::markdown::short_markdown_summary;
|
2021-12-27 19:19:56 -08:00
|
|
|
use crate::html::render::search_index::get_function_type_for_search;
|
2020-06-24 08:16:21 -05:00
|
|
|
use crate::html::render::IndexItem;
|
2022-10-19 22:37:59 +04:00
|
|
|
use crate::visit_lib::RustdocEffectiveVisibilities;
|
2020-06-24 08:16:21 -05:00
|
|
|
|
2020-10-04 20:42:34 -07:00
|
|
|
/// This cache is used to store information about the [`clean::Crate`] being
|
2020-06-24 08:16:21 -05:00
|
|
|
/// rendered in order to provide more useful documentation. This contains
|
|
|
|
|
/// information like all implementors of a trait, all traits a type implements,
|
|
|
|
|
/// documentation for all known traits, etc.
|
|
|
|
|
///
|
|
|
|
|
/// This structure purposefully does not implement `Clone` because it's intended
|
|
|
|
|
/// to be a fairly large and expensive structure to clone. Instead this adheres
|
2021-08-22 16:20:58 +02:00
|
|
|
/// to `Send` so it may be stored in an `Arc` instance and shared among the various
|
2020-06-24 08:16:21 -05:00
|
|
|
/// rendering threads.
|
2022-01-13 14:05:52 +08:00
|
|
|
#[derive(Default)]
|
2022-05-20 21:06:44 -04:00
|
|
|
pub(crate) struct Cache {
|
2020-06-24 08:16:21 -05:00
|
|
|
/// Maps a type ID to all known implementations for that type. This is only
|
2021-11-24 12:29:58 -08:00
|
|
|
/// recognized for intra-crate [`clean::Type::Path`]s, and is used to print
|
2020-06-24 08:16:21 -05:00
|
|
|
/// out extra documentation on the page of an enum/struct.
|
|
|
|
|
///
|
|
|
|
|
/// The values of the map are a list of implementations and documentation
|
|
|
|
|
/// found on that implementation.
|
2023-01-22 01:33:53 +04:00
|
|
|
pub(crate) impls: DefIdMap<Vec<Impl>>,
|
2020-06-24 08:16:21 -05:00
|
|
|
|
|
|
|
|
/// Maintains a mapping of local crate `DefId`s to the fully qualified name
|
|
|
|
|
/// and "short type description" of that node. This is used when generating
|
|
|
|
|
/// URLs when a type is being linked to. External paths are not located in
|
|
|
|
|
/// this map because the `External` type itself has all the information
|
|
|
|
|
/// necessary.
|
2022-05-20 21:06:44 -04:00
|
|
|
pub(crate) paths: FxHashMap<DefId, (Vec<Symbol>, ItemType)>,
|
2020-06-24 08:16:21 -05:00
|
|
|
|
|
|
|
|
/// Similar to `paths`, but only holds external paths. This is only used for
|
|
|
|
|
/// generating explicit hyperlinks to other crates.
|
2022-05-20 21:06:44 -04:00
|
|
|
pub(crate) external_paths: FxHashMap<DefId, (Vec<Symbol>, ItemType)>,
|
2020-06-24 08:16:21 -05:00
|
|
|
|
|
|
|
|
/// Maps local `DefId`s of exported types to fully qualified paths.
|
|
|
|
|
/// Unlike 'paths', this mapping ignores any renames that occur
|
|
|
|
|
/// due to 'use' statements.
|
|
|
|
|
///
|
|
|
|
|
/// This map is used when writing out the special 'implementors'
|
|
|
|
|
/// javascript file. By using the exact path that the type
|
|
|
|
|
/// is declared with, we ensure that each path will be identical
|
|
|
|
|
/// to the path used if the corresponding type is inlined. By
|
|
|
|
|
/// doing this, we can detect duplicate impls on a trait page, and only display
|
|
|
|
|
/// the impl for the inlined type.
|
2023-01-22 01:33:53 +04:00
|
|
|
pub(crate) exact_paths: DefIdMap<Vec<Symbol>>,
|
2020-06-24 08:16:21 -05:00
|
|
|
|
|
|
|
|
/// This map contains information about all known traits of this crate.
|
|
|
|
|
/// Implementations of a crate should inherit the documentation of the
|
|
|
|
|
/// parent trait if no extra documentation is specified, and default methods
|
|
|
|
|
/// should show up in documentation about trait implementations.
|
2022-09-27 12:27:04 -07:00
|
|
|
pub(crate) traits: FxHashMap<DefId, clean::Trait>,
|
2020-06-24 08:16:21 -05:00
|
|
|
|
|
|
|
|
/// When rendering traits, it's often useful to be able to list all
|
|
|
|
|
/// implementors of the trait, and this mapping is exactly, that: a mapping
|
|
|
|
|
/// of trait ids to the list of known implementors of the trait
|
2022-05-20 21:06:44 -04:00
|
|
|
pub(crate) implementors: FxHashMap<DefId, Vec<Impl>>,
|
2020-06-24 08:16:21 -05:00
|
|
|
|
|
|
|
|
/// Cache of where external crate documentation can be found.
|
2022-05-20 21:06:44 -04:00
|
|
|
pub(crate) extern_locations: FxHashMap<CrateNum, ExternalLocation>,
|
2020-06-24 08:16:21 -05:00
|
|
|
|
|
|
|
|
/// Cache of where documentation for primitives can be found.
|
2022-05-20 21:06:44 -04:00
|
|
|
pub(crate) primitive_locations: FxHashMap<clean::PrimitiveType, DefId>,
|
2020-06-24 08:16:21 -05:00
|
|
|
|
|
|
|
|
// Note that external items for which `doc(hidden)` applies to are shown as
|
|
|
|
|
// non-reachable while local items aren't. This is because we're reusing
|
2022-09-22 16:19:53 +03:00
|
|
|
// the effective visibilities from the privacy check pass.
|
2022-10-19 22:37:59 +04:00
|
|
|
pub(crate) effective_visibilities: RustdocEffectiveVisibilities,
|
2020-06-24 08:16:21 -05:00
|
|
|
|
|
|
|
|
/// The version of the crate being documented, if given from the `--crate-version` flag.
|
2022-05-20 21:06:44 -04:00
|
|
|
pub(crate) crate_version: Option<String>,
|
2020-06-24 08:16:21 -05:00
|
|
|
|
|
|
|
|
/// Whether to document private items.
|
|
|
|
|
/// This is stored in `Cache` so it doesn't need to be passed through all rustdoc functions.
|
2022-05-20 21:06:44 -04:00
|
|
|
pub(crate) document_private: bool,
|
2023-07-14 16:44:41 +02:00
|
|
|
/// Whether to document hidden items.
|
|
|
|
|
/// This is stored in `Cache` so it doesn't need to be passed through all rustdoc functions.
|
|
|
|
|
pub(crate) document_hidden: bool,
|
2020-06-24 08:16:21 -05:00
|
|
|
|
2021-03-09 19:55:35 -08:00
|
|
|
/// Crates marked with [`#[doc(masked)]`][doc_masked].
|
|
|
|
|
///
|
|
|
|
|
/// [doc_masked]: https://doc.rust-lang.org/nightly/unstable-book/language-features/doc-masked.html
|
2022-05-20 21:06:44 -04:00
|
|
|
pub(crate) masked_crates: FxHashSet<CrateNum>,
|
2021-03-09 19:55:35 -08:00
|
|
|
|
2020-06-24 08:16:21 -05:00
|
|
|
// Private fields only used when initially crawling a crate to build a cache
|
2021-12-15 06:18:18 +11:00
|
|
|
stack: Vec<Symbol>,
|
2022-05-27 12:23:29 -07:00
|
|
|
parent_stack: Vec<ParentStackItem>,
|
2020-06-24 08:16:21 -05:00
|
|
|
stripped_mod: bool,
|
|
|
|
|
|
2022-05-20 21:06:44 -04:00
|
|
|
pub(crate) search_index: Vec<IndexItem>,
|
2020-06-24 08:16:21 -05:00
|
|
|
|
|
|
|
|
// In rare case where a structure is defined in one module but implemented
|
|
|
|
|
// in another, if the implementing module is parsed before defining module,
|
|
|
|
|
// 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.
|
2022-05-26 14:01:08 -07:00
|
|
|
pub(crate) orphan_impl_items: Vec<OrphanImplItem>,
|
2020-06-24 08:16:21 -05:00
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
// was defined in function/expression scope, since the impl will be picked
|
|
|
|
|
// up by `collect-trait-impls` but the trait won't be scraped out in the HIR
|
2021-04-01 13:26:29 -07:00
|
|
|
// crawl. In order to prevent crashes when looking for notable traits or
|
2020-06-24 08:16:21 -05:00
|
|
|
// when gathering trait documentation on a type, hold impls here while
|
|
|
|
|
// folding and add them to the cache later on if we find the trait.
|
|
|
|
|
orphan_trait_impls: Vec<(DefId, FxHashSet<DefId>, Impl)>,
|
2021-04-03 22:15:24 -04:00
|
|
|
|
|
|
|
|
/// All intra-doc links resolved so far.
|
|
|
|
|
///
|
|
|
|
|
/// Links are indexed by the DefId of the item they document.
|
2023-04-02 16:35:17 -07:00
|
|
|
pub(crate) intra_doc_links: FxHashMap<ItemId, FxIndexSet<clean::ItemLink>>,
|
2020-11-04 21:59:35 +01:00
|
|
|
/// Cfg that have been hidden via #![doc(cfg_hide(...))]
|
2022-05-20 21:06:44 -04:00
|
|
|
pub(crate) hidden_cfg: FxHashSet<clean::cfg::Cfg>,
|
2023-06-19 21:17:57 +02:00
|
|
|
|
|
|
|
|
/// Contains the list of `DefId`s which have been inlined. It is used when generating files
|
|
|
|
|
/// to check if a stripped item should get its file generated or not: if it's inside a
|
|
|
|
|
/// `#[doc(hidden)]` item or a private one and not inlined, it shouldn't get a file.
|
|
|
|
|
pub(crate) inlined_items: DefIdSet,
|
2020-06-24 08:16:21 -05:00
|
|
|
}
|
|
|
|
|
|
2021-01-28 16:07:24 +01:00
|
|
|
/// This struct is used to wrap the `cache` and `tcx` in order to run `DocFolder`.
|
|
|
|
|
struct CacheBuilder<'a, 'tcx> {
|
|
|
|
|
cache: &'a mut Cache,
|
2022-04-15 21:52:43 +02:00
|
|
|
/// This field is used to prevent duplicated impl blocks.
|
2023-01-22 01:33:53 +04:00
|
|
|
impl_ids: DefIdMap<DefIdSet>,
|
2021-01-28 16:07:24 +01:00
|
|
|
tcx: TyCtxt<'tcx>,
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-24 08:16:21 -05:00
|
|
|
impl Cache {
|
2023-07-14 16:44:41 +02:00
|
|
|
pub(crate) fn new(document_private: bool, document_hidden: bool) -> Self {
|
|
|
|
|
Cache { document_private, document_hidden, ..Cache::default() }
|
2021-02-11 21:29:22 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Populates the `Cache` with more data. The returned `Crate` will be missing some data that was
|
|
|
|
|
/// in `krate` due to the data being moved into the `Cache`.
|
2022-05-20 21:06:44 -04:00
|
|
|
pub(crate) fn populate(cx: &mut DocContext<'_>, mut krate: clean::Crate) -> clean::Crate {
|
2021-11-19 17:51:45 -05:00
|
|
|
let tcx = cx.tcx;
|
|
|
|
|
|
2021-02-12 00:03:24 -05:00
|
|
|
// Crawl the crate to build various caches used for the output
|
2021-11-19 17:51:45 -05:00
|
|
|
debug!(?cx.cache.crate_version);
|
|
|
|
|
cx.cache.traits = krate.external_traits.take();
|
2021-11-19 21:16:48 -05:00
|
|
|
|
2020-06-24 08:16:21 -05:00
|
|
|
// Cache where all our extern crates are located
|
2020-06-26 09:14:45 -05:00
|
|
|
// FIXME: this part is specific to HTML so it'd be nice to remove it from the common code
|
2023-05-27 14:46:54 +02:00
|
|
|
for &crate_num in tcx.crates(()) {
|
2021-11-19 21:24:12 -05:00
|
|
|
let e = ExternalCrate { crate_num };
|
|
|
|
|
|
2021-04-22 19:02:09 -04:00
|
|
|
let name = e.name(tcx);
|
2021-11-19 21:24:12 -05:00
|
|
|
let render_options = &cx.render_options;
|
2021-12-15 14:39:23 +11:00
|
|
|
let extern_url = render_options.extern_html_root_urls.get(name.as_str()).map(|u| &**u);
|
2021-11-19 21:24:12 -05:00
|
|
|
let extern_url_takes_precedence = render_options.extern_html_root_takes_precedence;
|
|
|
|
|
let dst = &render_options.output;
|
|
|
|
|
let location = e.location(extern_url, extern_url_takes_precedence, dst, tcx);
|
2021-11-19 17:51:45 -05:00
|
|
|
cx.cache.extern_locations.insert(e.crate_num, location);
|
2021-12-15 06:18:18 +11:00
|
|
|
cx.cache.external_paths.insert(e.def_id(), (vec![name], ItemType::Module));
|
2020-06-24 08:16:21 -05:00
|
|
|
}
|
|
|
|
|
|
2021-07-10 22:25:36 -04:00
|
|
|
// FIXME: avoid this clone (requires implementing Default manually)
|
2021-11-19 17:51:45 -05:00
|
|
|
cx.cache.primitive_locations = PrimitiveType::primitive_locations(tcx).clone();
|
|
|
|
|
for (prim, &def_id) in &cx.cache.primitive_locations {
|
2021-07-10 22:25:36 -04:00
|
|
|
let crate_name = tcx.crate_name(def_id.krate);
|
|
|
|
|
// Recall that we only allow primitive modules to be at the root-level of the crate.
|
|
|
|
|
// If that restriction is ever lifted, this will have to include the relative paths instead.
|
2021-12-15 06:18:18 +11:00
|
|
|
cx.cache
|
|
|
|
|
.external_paths
|
|
|
|
|
.insert(def_id, (vec![crate_name, prim.as_sym()], ItemType::Primitive));
|
2020-06-24 08:16:21 -05:00
|
|
|
}
|
|
|
|
|
|
2022-04-15 21:52:43 +02:00
|
|
|
let (krate, mut impl_ids) = {
|
|
|
|
|
let mut cache_builder =
|
2023-01-22 01:33:53 +04:00
|
|
|
CacheBuilder { tcx, cache: &mut cx.cache, impl_ids: Default::default() };
|
2022-04-15 21:52:43 +02:00
|
|
|
krate = cache_builder.fold_crate(krate);
|
|
|
|
|
(krate, cache_builder.impl_ids)
|
|
|
|
|
};
|
2020-06-24 08:16:21 -05:00
|
|
|
|
2021-11-19 17:51:45 -05:00
|
|
|
for (trait_did, dids, impl_) in cx.cache.orphan_trait_impls.drain(..) {
|
|
|
|
|
if cx.cache.traits.contains_key(&trait_did) {
|
2020-06-24 08:16:21 -05:00
|
|
|
for did in dids {
|
2022-04-15 21:52:43 +02:00
|
|
|
if impl_ids.entry(did).or_default().insert(impl_.def_id()) {
|
|
|
|
|
cx.cache.impls.entry(did).or_default().push(impl_.clone());
|
|
|
|
|
}
|
2020-06-24 08:16:21 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-11 21:29:22 -05:00
|
|
|
krate
|
2020-06-24 08:16:21 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-28 16:07:24 +01:00
|
|
|
impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
|
2020-06-24 08:16:21 -05:00
|
|
|
fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
|
2022-04-16 14:28:09 +02:00
|
|
|
if item.item_id.is_local() {
|
2023-05-02 14:35:34 +02:00
|
|
|
let is_stripped = matches!(*item.kind, clean::ItemKind::StrippedItem(..));
|
|
|
|
|
debug!(
|
|
|
|
|
"folding {} (stripped: {is_stripped:?}) \"{:?}\", id {:?}",
|
|
|
|
|
item.type_(),
|
|
|
|
|
item.name,
|
|
|
|
|
item.item_id
|
|
|
|
|
);
|
2020-06-24 08:16:21 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If this is a stripped module,
|
|
|
|
|
// we don't want it or its children in the search index.
|
2020-12-13 11:32:57 -05:00
|
|
|
let orig_stripped_mod = match *item.kind {
|
2020-06-24 08:16:21 -05:00
|
|
|
clean::StrippedItem(box clean::ModuleItem(..)) => {
|
2021-01-28 16:07:24 +01:00
|
|
|
mem::replace(&mut self.cache.stripped_mod, true)
|
2020-06-24 08:16:21 -05:00
|
|
|
}
|
2021-01-28 16:07:24 +01:00
|
|
|
_ => self.cache.stripped_mod,
|
2020-06-24 08:16:21 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// If the impl is from a masked crate or references something from a
|
|
|
|
|
// masked crate then remove it completely.
|
2023-03-20 11:31:17 -07:00
|
|
|
if let clean::ImplItem(ref i) = *item.kind &&
|
|
|
|
|
(self.cache.masked_crates.contains(&item.item_id.krate())
|
2021-08-26 19:16:58 -07:00
|
|
|
|| i.trait_
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map_or(false, |t| self.cache.masked_crates.contains(&t.def_id().krate))
|
2021-10-21 20:12:20 -07:00
|
|
|
|| i.for_
|
2021-10-21 20:17:47 -07:00
|
|
|
.def_id(self.cache)
|
2023-03-20 11:31:17 -07:00
|
|
|
.map_or(false, |d| self.cache.masked_crates.contains(&d.krate)))
|
|
|
|
|
{
|
|
|
|
|
return None;
|
2020-06-24 08:16:21 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Propagate a trait method's documentation to all implementors of the
|
|
|
|
|
// trait.
|
2020-12-13 11:32:57 -05:00
|
|
|
if let clean::TraitItem(ref t) = *item.kind {
|
2022-09-27 12:27:04 -07:00
|
|
|
self.cache.traits.entry(item.item_id.expect_def_id()).or_insert_with(|| (**t).clone());
|
2020-06-24 08:16:21 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Collect all the implementors of traits.
|
2023-02-15 11:30:14 +01:00
|
|
|
if let clean::ImplItem(ref i) = *item.kind &&
|
|
|
|
|
let Some(trait_) = &i.trait_ &&
|
|
|
|
|
!i.kind.is_blanket()
|
|
|
|
|
{
|
|
|
|
|
self.cache
|
|
|
|
|
.implementors
|
|
|
|
|
.entry(trait_.def_id())
|
|
|
|
|
.or_default()
|
|
|
|
|
.push(Impl { impl_item: item.clone() });
|
2020-06-24 08:16:21 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Index this method for searching later on.
|
2023-01-13 15:39:16 +03:00
|
|
|
if let Some(s) = item.name.or_else(|| {
|
2022-05-05 21:56:03 +02:00
|
|
|
if item.is_stripped() {
|
|
|
|
|
None
|
|
|
|
|
} else if let clean::ImportItem(ref i) = *item.kind &&
|
|
|
|
|
let clean::ImportKind::Simple(s) = i.kind {
|
|
|
|
|
Some(s)
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
}) {
|
2020-12-13 11:32:57 -05:00
|
|
|
let (parent, is_inherent_impl_item) = match *item.kind {
|
2020-06-24 08:16:21 -05:00
|
|
|
clean::StrippedItem(..) => ((None, None), false),
|
2022-03-29 19:30:54 +02:00
|
|
|
clean::AssocConstItem(..) | clean::AssocTypeItem(..)
|
2022-05-27 12:23:29 -07:00
|
|
|
if self
|
|
|
|
|
.cache
|
|
|
|
|
.parent_stack
|
|
|
|
|
.last()
|
|
|
|
|
.map_or(false, |parent| parent.is_trait_impl()) =>
|
2020-06-24 08:16:21 -05:00
|
|
|
{
|
|
|
|
|
// skip associated items in trait impls
|
|
|
|
|
((None, None), false)
|
|
|
|
|
}
|
2022-03-29 19:30:54 +02:00
|
|
|
clean::TyMethodItem(..)
|
|
|
|
|
| clean::TyAssocConstItem(..)
|
|
|
|
|
| clean::TyAssocTypeItem(..)
|
2020-06-24 08:16:21 -05:00
|
|
|
| clean::StructFieldItem(..)
|
|
|
|
|
| clean::VariantItem(..) => (
|
|
|
|
|
(
|
2022-05-27 12:23:29 -07:00
|
|
|
Some(
|
|
|
|
|
self.cache
|
|
|
|
|
.parent_stack
|
|
|
|
|
.last()
|
|
|
|
|
.expect("parent_stack is empty")
|
|
|
|
|
.item_id()
|
|
|
|
|
.expect_def_id(),
|
|
|
|
|
),
|
2021-01-28 16:07:24 +01:00
|
|
|
Some(&self.cache.stack[..self.cache.stack.len() - 1]),
|
2020-06-24 08:16:21 -05:00
|
|
|
),
|
|
|
|
|
false,
|
|
|
|
|
),
|
2022-03-29 19:30:54 +02:00
|
|
|
clean::MethodItem(..) | clean::AssocConstItem(..) | clean::AssocTypeItem(..) => {
|
2021-01-28 16:07:24 +01:00
|
|
|
if self.cache.parent_stack.is_empty() {
|
2020-06-24 08:16:21 -05:00
|
|
|
((None, None), false)
|
|
|
|
|
} else {
|
2021-01-28 16:07:24 +01:00
|
|
|
let last = self.cache.parent_stack.last().expect("parent_stack is empty 2");
|
2022-05-27 12:23:29 -07:00
|
|
|
let did = match &*last {
|
2023-02-16 16:49:28 -07:00
|
|
|
ParentStackItem::Impl {
|
2023-02-17 10:35:19 -07:00
|
|
|
// impl Trait for &T { fn method(self); }
|
|
|
|
|
//
|
|
|
|
|
// When generating a function index with the above shape, we want it
|
|
|
|
|
// associated with `T`, not with the primitive reference type. It should
|
|
|
|
|
// show up as `T::method`, rather than `reference::method`, in the search
|
|
|
|
|
// results page.
|
2023-02-16 16:49:28 -07:00
|
|
|
for_: clean::Type::BorrowedRef { type_, .. },
|
|
|
|
|
..
|
|
|
|
|
} => type_.def_id(&self.cache),
|
2022-05-27 12:23:29 -07:00
|
|
|
ParentStackItem::Impl { for_, .. } => for_.def_id(&self.cache),
|
|
|
|
|
ParentStackItem::Type(item_id) => item_id.as_def_id(),
|
|
|
|
|
};
|
2023-04-15 20:18:30 +02:00
|
|
|
let path = did
|
|
|
|
|
.and_then(|did| self.cache.paths.get(&did))
|
2020-06-24 08:16:21 -05:00
|
|
|
// The current stack not necessarily has correlation
|
|
|
|
|
// for where the type was defined. On the other
|
|
|
|
|
// hand, `paths` always has the right
|
|
|
|
|
// information if present.
|
2023-04-15 20:18:30 +02:00
|
|
|
.map(|(fqp, _)| &fqp[..fqp.len() - 1]);
|
2022-05-27 12:23:29 -07:00
|
|
|
((did, path), true)
|
2020-06-24 08:16:21 -05:00
|
|
|
}
|
|
|
|
|
}
|
2021-01-28 16:07:24 +01:00
|
|
|
_ => ((None, Some(&*self.cache.stack)), false),
|
2020-06-24 08:16:21 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
match parent {
|
2021-01-28 16:07:24 +01:00
|
|
|
(parent, Some(path)) if is_inherent_impl_item || !self.cache.stripped_mod => {
|
2020-06-24 08:16:21 -05:00
|
|
|
debug_assert!(!item.is_stripped());
|
|
|
|
|
|
|
|
|
|
// A crate has a module at its root, containing all items,
|
|
|
|
|
// which should not be indexed. The crate-item itself is
|
|
|
|
|
// inserted later on when serializing the search-index.
|
2023-03-20 11:31:17 -07:00
|
|
|
if item.item_id.as_def_id().map_or(false, |idx| !idx.is_crate_root())
|
|
|
|
|
&& let ty = item.type_()
|
|
|
|
|
&& (ty != ItemType::StructField
|
|
|
|
|
|| u16::from_str_radix(s.as_str(), 10).is_err())
|
|
|
|
|
{
|
2023-05-12 20:34:24 +03:00
|
|
|
let desc =
|
|
|
|
|
short_markdown_summary(&item.doc_value(), &item.link_names(self.cache));
|
2023-03-20 11:31:17 -07:00
|
|
|
// In case this is a field from a tuple struct, we don't add it into
|
|
|
|
|
// the search index because its name is something like "0", which is
|
|
|
|
|
// not useful for rustdoc search.
|
|
|
|
|
self.cache.search_index.push(IndexItem {
|
|
|
|
|
ty,
|
|
|
|
|
name: s,
|
|
|
|
|
path: join_with_double_colon(path),
|
|
|
|
|
desc,
|
|
|
|
|
parent,
|
|
|
|
|
parent_idx: None,
|
rustdoc-search: add impl disambiguator to duplicate assoc items
Helps with #90929
This changes the search results, specifically, when there's more than
one impl with an associated item with the same name. For example,
the search queries `simd<i8> -> simd<i8>` and `simd<i64> -> simd<i64>`
don't link to the same function, but most of the functions have the
same names.
This change should probably be FCP-ed, especially since it adds a new
anchor link format for `main.js` to handle, so that URLs like
`struct.Vec.html#impl-AsMut<[T]>-for-Vec<T,+A>/method.as_mut` redirect
to `struct.Vec.html#method.as_mut-2`. It's a strange design, but there
are a few reasons for it:
* I'd like to avoid making the HTML bigger. Obviously, fixing this bug
is going to add at least a little more data to the search index, but
adding more HTML penalises viewers for the benefit of searchers.
* Breaking `struct.Vec.html#method.len` would also be a disappointment.
On the other hand:
* The path-style anchors might be less prone to link rot than the numbered
anchors. It's definitely less likely to have URLs that appear to "work",
but silently point at the wrong thing.
* This commit arranges the path-style anchor to redirect to the numbered
anchor. Nothing stops rustdoc from doing the opposite, making path-style
anchors the default and redirecting the "legacy" numbered ones.
2023-03-20 16:02:51 -07:00
|
|
|
impl_id: if let Some(ParentStackItem::Impl { item_id, .. }) = self.cache.parent_stack.last() {
|
|
|
|
|
item_id.as_def_id()
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
},
|
2023-03-20 11:31:17 -07:00
|
|
|
search_type: get_function_type_for_search(
|
|
|
|
|
&item,
|
|
|
|
|
self.tcx,
|
|
|
|
|
clean_impl_generics(self.cache.parent_stack.last()).as_ref(),
|
|
|
|
|
self.cache,
|
|
|
|
|
),
|
|
|
|
|
aliases: item.attrs.get_doc_aliases(),
|
|
|
|
|
deprecation: item.deprecation(self.tcx),
|
|
|
|
|
});
|
2020-06-24 08:16:21 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
(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.
|
2022-05-27 12:23:29 -07:00
|
|
|
let impl_generics = clean_impl_generics(self.cache.parent_stack.last());
|
2022-05-26 14:01:08 -07:00
|
|
|
self.cache.orphan_impl_items.push(OrphanImplItem {
|
2022-05-02 14:51:45 -07:00
|
|
|
parent,
|
2022-05-26 14:01:08 -07:00
|
|
|
item: item.clone(),
|
2022-05-27 12:23:29 -07:00
|
|
|
impl_generics,
|
rustdoc-search: add impl disambiguator to duplicate assoc items
Helps with #90929
This changes the search results, specifically, when there's more than
one impl with an associated item with the same name. For example,
the search queries `simd<i8> -> simd<i8>` and `simd<i64> -> simd<i64>`
don't link to the same function, but most of the functions have the
same names.
This change should probably be FCP-ed, especially since it adds a new
anchor link format for `main.js` to handle, so that URLs like
`struct.Vec.html#impl-AsMut<[T]>-for-Vec<T,+A>/method.as_mut` redirect
to `struct.Vec.html#method.as_mut-2`. It's a strange design, but there
are a few reasons for it:
* I'd like to avoid making the HTML bigger. Obviously, fixing this bug
is going to add at least a little more data to the search index, but
adding more HTML penalises viewers for the benefit of searchers.
* Breaking `struct.Vec.html#method.len` would also be a disappointment.
On the other hand:
* The path-style anchors might be less prone to link rot than the numbered
anchors. It's definitely less likely to have URLs that appear to "work",
but silently point at the wrong thing.
* This commit arranges the path-style anchor to redirect to the numbered
anchor. Nothing stops rustdoc from doing the opposite, making path-style
anchors the default and redirecting the "legacy" numbered ones.
2023-03-20 16:02:51 -07:00
|
|
|
impl_id: if let Some(ParentStackItem::Impl { item_id, .. }) =
|
|
|
|
|
self.cache.parent_stack.last()
|
|
|
|
|
{
|
|
|
|
|
item_id.as_def_id()
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
},
|
2022-05-26 14:01:08 -07:00
|
|
|
});
|
2020-06-24 08:16:21 -05:00
|
|
|
}
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Keep track of the fully qualified path for this item.
|
|
|
|
|
let pushed = match item.name {
|
2020-12-14 23:23:58 -05:00
|
|
|
Some(n) if !n.is_empty() => {
|
2021-12-15 06:18:18 +11:00
|
|
|
self.cache.stack.push(n);
|
2020-06-24 08:16:21 -05:00
|
|
|
true
|
|
|
|
|
}
|
|
|
|
|
_ => false,
|
|
|
|
|
};
|
|
|
|
|
|
2020-12-13 11:32:57 -05:00
|
|
|
match *item.kind {
|
2020-06-24 08:16:21 -05:00
|
|
|
clean::StructItem(..)
|
|
|
|
|
| clean::EnumItem(..)
|
2023-08-21 13:56:22 -07:00
|
|
|
| clean::TypeAliasItem(..)
|
2020-06-24 08:16:21 -05:00
|
|
|
| clean::TraitItem(..)
|
2021-05-01 21:39:59 -07:00
|
|
|
| clean::TraitAliasItem(..)
|
2020-06-24 08:16:21 -05:00
|
|
|
| clean::FunctionItem(..)
|
|
|
|
|
| clean::ModuleItem(..)
|
|
|
|
|
| clean::ForeignFunctionItem(..)
|
|
|
|
|
| clean::ForeignStaticItem(..)
|
|
|
|
|
| clean::ConstantItem(..)
|
|
|
|
|
| clean::StaticItem(..)
|
|
|
|
|
| clean::UnionItem(..)
|
|
|
|
|
| clean::ForeignTypeItem
|
|
|
|
|
| clean::MacroItem(..)
|
|
|
|
|
| clean::ProcMacroItem(..)
|
2021-05-01 21:39:59 -07:00
|
|
|
| clean::VariantItem(..) => {
|
|
|
|
|
if !self.cache.stripped_mod {
|
|
|
|
|
// Re-exported items mean that the same id can show up twice
|
|
|
|
|
// in the rustdoc ast that we're looking at. We know,
|
|
|
|
|
// however, that a re-exported item doesn't show up in the
|
|
|
|
|
// `public_items` map, so we can skip inserting into the
|
|
|
|
|
// paths map if there was already an entry present and we're
|
|
|
|
|
// not a public item.
|
2022-04-16 14:28:09 +02:00
|
|
|
if !self.cache.paths.contains_key(&item.item_id.expect_def_id())
|
2022-09-22 16:19:53 +03:00
|
|
|
|| self
|
|
|
|
|
.cache
|
|
|
|
|
.effective_visibilities
|
2022-10-19 22:37:59 +04:00
|
|
|
.is_directly_public(self.tcx, item.item_id.expect_def_id())
|
2021-05-01 21:39:59 -07:00
|
|
|
{
|
2021-04-29 21:36:54 +02:00
|
|
|
self.cache.paths.insert(
|
2022-04-16 14:28:09 +02:00
|
|
|
item.item_id.expect_def_id(),
|
2021-04-29 21:36:54 +02:00
|
|
|
(self.cache.stack.clone(), item.type_()),
|
|
|
|
|
);
|
2021-05-01 21:39:59 -07:00
|
|
|
}
|
2020-06-24 08:16:21 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
clean::PrimitiveItem(..) => {
|
2021-04-29 21:36:54 +02:00
|
|
|
self.cache
|
|
|
|
|
.paths
|
2022-04-16 14:28:09 +02:00
|
|
|
.insert(item.item_id.expect_def_id(), (self.cache.stack.clone(), item.type_()));
|
2020-06-24 08:16:21 -05:00
|
|
|
}
|
|
|
|
|
|
2021-05-01 21:39:59 -07:00
|
|
|
clean::ExternCrateItem { .. }
|
|
|
|
|
| clean::ImportItem(..)
|
|
|
|
|
| clean::OpaqueTyItem(..)
|
|
|
|
|
| clean::ImplItem(..)
|
|
|
|
|
| clean::TyMethodItem(..)
|
|
|
|
|
| clean::MethodItem(..)
|
|
|
|
|
| clean::StructFieldItem(..)
|
2022-03-29 19:30:54 +02:00
|
|
|
| clean::TyAssocConstItem(..)
|
2021-05-01 21:39:59 -07:00
|
|
|
| clean::AssocConstItem(..)
|
2022-03-29 19:30:54 +02:00
|
|
|
| clean::TyAssocTypeItem(..)
|
2021-05-01 21:39:59 -07:00
|
|
|
| clean::AssocTypeItem(..)
|
|
|
|
|
| clean::StrippedItem(..)
|
2022-07-21 16:05:17 +02:00
|
|
|
| clean::KeywordItem => {
|
2021-05-01 21:39:59 -07:00
|
|
|
// FIXME: Do these need handling?
|
|
|
|
|
// The person writing this comment doesn't know.
|
|
|
|
|
// So would rather leave them to an expert,
|
|
|
|
|
// as at least the list is better than `_ => {}`.
|
|
|
|
|
}
|
2020-06-24 08:16:21 -05:00
|
|
|
}
|
|
|
|
|
|
2022-05-27 12:23:29 -07:00
|
|
|
// Maintain the parent stack.
|
|
|
|
|
let (item, parent_pushed) = match *item.kind {
|
2020-06-24 08:16:21 -05:00
|
|
|
clean::TraitItem(..)
|
|
|
|
|
| clean::EnumItem(..)
|
|
|
|
|
| clean::ForeignTypeItem
|
|
|
|
|
| clean::StructItem(..)
|
|
|
|
|
| clean::UnionItem(..)
|
2022-05-27 12:23:29 -07:00
|
|
|
| clean::VariantItem(..)
|
2023-08-18 17:57:20 +02:00
|
|
|
| clean::TypeAliasItem(..)
|
2022-05-27 12:23:29 -07:00
|
|
|
| clean::ImplItem(..) => {
|
|
|
|
|
self.cache.parent_stack.push(ParentStackItem::new(&item));
|
|
|
|
|
(self.fold_item_recur(item), true)
|
2022-05-02 14:51:45 -07:00
|
|
|
}
|
2022-05-27 12:23:29 -07:00
|
|
|
_ => (self.fold_item_recur(item), false),
|
2022-05-02 14:51:45 -07:00
|
|
|
};
|
|
|
|
|
|
2020-06-24 08:16:21 -05:00
|
|
|
// Once we've recursively found all the generics, hoard off all the
|
|
|
|
|
// implementations elsewhere.
|
2020-12-13 11:32:57 -05:00
|
|
|
let ret = if let clean::Item { kind: box clean::ImplItem(ref i), .. } = item {
|
2020-11-22 12:57:55 -05:00
|
|
|
// Figure out the id of this impl. This may map to a
|
|
|
|
|
// primitive rather than always to a struct/enum.
|
|
|
|
|
// Note: matching twice to restrict the lifetime of the `i` borrow.
|
|
|
|
|
let mut dids = FxHashSet::default();
|
2020-12-13 11:32:57 -05:00
|
|
|
match i.for_ {
|
2021-11-24 12:29:58 -08:00
|
|
|
clean::Type::Path { ref path }
|
|
|
|
|
| clean::BorrowedRef { type_: box clean::Type::Path { ref path }, .. } => {
|
2021-11-11 15:45:45 -08:00
|
|
|
dids.insert(path.def_id());
|
2022-04-29 14:01:57 -07:00
|
|
|
if let Some(generics) = path.generics() &&
|
2023-07-11 22:35:29 +01:00
|
|
|
let ty::Adt(adt, _) = self.tcx.type_of(path.def_id()).instantiate_identity().kind() &&
|
2022-04-29 14:01:57 -07:00
|
|
|
adt.is_fundamental() {
|
|
|
|
|
for ty in generics {
|
2022-05-21 14:07:18 -04:00
|
|
|
if let Some(did) = ty.def_id(self.cache) {
|
2022-04-29 14:01:57 -07:00
|
|
|
dids.insert(did);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-12-13 11:32:57 -05:00
|
|
|
}
|
2021-06-18 21:47:42 +02:00
|
|
|
clean::DynTrait(ref bounds, _)
|
|
|
|
|
| clean::BorrowedRef { type_: box clean::DynTrait(ref bounds, _), .. } => {
|
2021-08-26 19:16:58 -07:00
|
|
|
dids.insert(bounds[0].trait_.def_id());
|
2021-06-18 21:47:42 +02:00
|
|
|
}
|
2020-12-13 11:32:57 -05:00
|
|
|
ref t => {
|
2021-01-28 16:07:24 +01:00
|
|
|
let did = t
|
|
|
|
|
.primitive_type()
|
|
|
|
|
.and_then(|t| self.cache.primitive_locations.get(&t).cloned());
|
2020-06-24 08:16:21 -05:00
|
|
|
|
2020-12-13 11:32:57 -05:00
|
|
|
if let Some(did) = did {
|
|
|
|
|
dids.insert(did);
|
2020-06-24 08:16:21 -05:00
|
|
|
}
|
2020-11-22 12:57:55 -05:00
|
|
|
}
|
2020-12-13 11:32:57 -05:00
|
|
|
}
|
2020-06-24 08:16:21 -05:00
|
|
|
|
2020-12-13 11:32:57 -05:00
|
|
|
if let Some(generics) = i.trait_.as_ref().and_then(|t| t.generics()) {
|
|
|
|
|
for bound in generics {
|
2021-10-21 20:17:47 -07:00
|
|
|
if let Some(did) = bound.def_id(self.cache) {
|
2020-12-13 11:32:57 -05:00
|
|
|
dids.insert(did);
|
2020-06-24 08:16:21 -05:00
|
|
|
}
|
|
|
|
|
}
|
2020-12-13 11:32:57 -05:00
|
|
|
}
|
2020-11-22 12:57:55 -05:00
|
|
|
let impl_item = Impl { impl_item: item };
|
2021-01-28 16:07:24 +01:00
|
|
|
if impl_item.trait_did().map_or(true, |d| self.cache.traits.contains_key(&d)) {
|
2020-11-22 12:57:55 -05:00
|
|
|
for did in dids {
|
2022-04-15 21:52:43 +02:00
|
|
|
if self.impl_ids.entry(did).or_default().insert(impl_item.def_id()) {
|
|
|
|
|
self.cache
|
|
|
|
|
.impls
|
|
|
|
|
.entry(did)
|
|
|
|
|
.or_insert_with(Vec::new)
|
|
|
|
|
.push(impl_item.clone());
|
|
|
|
|
}
|
2020-11-22 12:57:55 -05:00
|
|
|
}
|
|
|
|
|
} else {
|
2021-01-15 15:36:15 +01:00
|
|
|
let trait_did = impl_item.trait_did().expect("no trait did");
|
2021-01-28 16:07:24 +01:00
|
|
|
self.cache.orphan_trait_impls.push((trait_did, dids, impl_item));
|
2020-06-24 08:16:21 -05:00
|
|
|
}
|
2020-11-22 12:57:55 -05:00
|
|
|
None
|
|
|
|
|
} else {
|
|
|
|
|
Some(item)
|
|
|
|
|
};
|
2020-06-24 08:16:21 -05:00
|
|
|
|
|
|
|
|
if pushed {
|
2021-01-28 16:07:24 +01:00
|
|
|
self.cache.stack.pop().expect("stack already empty");
|
2020-06-24 08:16:21 -05:00
|
|
|
}
|
|
|
|
|
if parent_pushed {
|
2021-01-28 16:07:24 +01:00
|
|
|
self.cache.parent_stack.pop().expect("parent stack already empty");
|
2020-06-24 08:16:21 -05:00
|
|
|
}
|
2021-01-28 16:07:24 +01:00
|
|
|
self.cache.stripped_mod = orig_stripped_mod;
|
2020-06-24 08:16:21 -05:00
|
|
|
ret
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-05-26 14:01:08 -07:00
|
|
|
|
|
|
|
|
pub(crate) struct OrphanImplItem {
|
|
|
|
|
pub(crate) parent: DefId,
|
rustdoc-search: add impl disambiguator to duplicate assoc items
Helps with #90929
This changes the search results, specifically, when there's more than
one impl with an associated item with the same name. For example,
the search queries `simd<i8> -> simd<i8>` and `simd<i64> -> simd<i64>`
don't link to the same function, but most of the functions have the
same names.
This change should probably be FCP-ed, especially since it adds a new
anchor link format for `main.js` to handle, so that URLs like
`struct.Vec.html#impl-AsMut<[T]>-for-Vec<T,+A>/method.as_mut` redirect
to `struct.Vec.html#method.as_mut-2`. It's a strange design, but there
are a few reasons for it:
* I'd like to avoid making the HTML bigger. Obviously, fixing this bug
is going to add at least a little more data to the search index, but
adding more HTML penalises viewers for the benefit of searchers.
* Breaking `struct.Vec.html#method.len` would also be a disappointment.
On the other hand:
* The path-style anchors might be less prone to link rot than the numbered
anchors. It's definitely less likely to have URLs that appear to "work",
but silently point at the wrong thing.
* This commit arranges the path-style anchor to redirect to the numbered
anchor. Nothing stops rustdoc from doing the opposite, making path-style
anchors the default and redirecting the "legacy" numbered ones.
2023-03-20 16:02:51 -07:00
|
|
|
pub(crate) impl_id: Option<DefId>,
|
2022-05-26 14:01:08 -07:00
|
|
|
pub(crate) item: clean::Item,
|
|
|
|
|
pub(crate) impl_generics: Option<(clean::Type, clean::Generics)>,
|
2022-05-27 12:23:29 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Information about trait and type parents is tracked while traversing the item tree to build
|
|
|
|
|
/// the cache.
|
|
|
|
|
///
|
|
|
|
|
/// We don't just store `Item` in there, because `Item` contains the list of children being
|
|
|
|
|
/// traversed and it would be wasteful to clone all that. We also need the item id, so just
|
|
|
|
|
/// storing `ItemKind` won't work, either.
|
|
|
|
|
enum ParentStackItem {
|
|
|
|
|
Impl {
|
|
|
|
|
for_: clean::Type,
|
|
|
|
|
trait_: Option<clean::Path>,
|
|
|
|
|
generics: clean::Generics,
|
|
|
|
|
kind: clean::ImplKind,
|
|
|
|
|
item_id: ItemId,
|
|
|
|
|
},
|
|
|
|
|
Type(ItemId),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl ParentStackItem {
|
|
|
|
|
fn new(item: &clean::Item) -> Self {
|
|
|
|
|
match &*item.kind {
|
2022-07-21 23:14:12 +02:00
|
|
|
clean::ItemKind::ImplItem(box clean::Impl { for_, trait_, generics, kind, .. }) => {
|
2022-05-27 12:23:29 -07:00
|
|
|
ParentStackItem::Impl {
|
|
|
|
|
for_: for_.clone(),
|
|
|
|
|
trait_: trait_.clone(),
|
|
|
|
|
generics: generics.clone(),
|
|
|
|
|
kind: kind.clone(),
|
|
|
|
|
item_id: item.item_id,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_ => ParentStackItem::Type(item.item_id),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
fn is_trait_impl(&self) -> bool {
|
|
|
|
|
matches!(self, ParentStackItem::Impl { trait_: Some(..), .. })
|
|
|
|
|
}
|
|
|
|
|
fn item_id(&self) -> ItemId {
|
|
|
|
|
match self {
|
|
|
|
|
ParentStackItem::Impl { item_id, .. } => *item_id,
|
|
|
|
|
ParentStackItem::Type(item_id) => *item_id,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn clean_impl_generics(item: Option<&ParentStackItem>) -> Option<(clean::Type, clean::Generics)> {
|
|
|
|
|
if let Some(ParentStackItem::Impl { for_, generics, kind: clean::ImplKind::Normal, .. }) = item
|
|
|
|
|
{
|
|
|
|
|
Some((for_.clone(), generics.clone()))
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
}
|
2022-05-26 14:01:08 -07:00
|
|
|
}
|