]> git.proxmox.com Git - rustc.git/blame - src/librustdoc/html/render/cache.rs
New upstream version 1.45.0+dfsg1
[rustc.git] / src / librustdoc / html / render / cache.rs
CommitLineData
dfeec247 1use crate::clean::{self, AttributesExt, GetDefId};
e74abb32 2use crate::fold::DocFolder;
e74abb32 3use rustc_data_structures::fx::{FxHashMap, FxHashSet};
dfeec247 4use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX};
ba9703b0 5use rustc_middle::middle::privacy::AccessLevels;
dfeec247
XL
6use rustc_span::source_map::FileName;
7use rustc_span::symbol::sym;
8use std::collections::BTreeMap;
e74abb32
XL
9use std::mem;
10use std::path::{Path, PathBuf};
60c5eb7d
XL
11
12use serde::Serialize;
e74abb32 13
dfeec247 14use super::{plain_summary_line, shorten, Impl, IndexItem, IndexItemFunctionType, ItemType};
ba9703b0 15use super::{Generic, RenderInfo, RenderType, TypeWithKind};
e74abb32
XL
16
17/// Indicates where an external crate can be found.
18pub enum ExternalLocation {
19 /// Remote URL root of the external crate
20 Remote(String),
21 /// This external crate can be found in the local doc/ folder
22 Local,
23 /// The external crate could not be found.
24 Unknown,
25}
26
27/// This cache is used to store information about the `clean::Crate` being
28/// rendered in order to provide more useful documentation. This contains
29/// information like all implementors of a trait, all traits a type implements,
30/// documentation for all known traits, etc.
31///
32/// This structure purposefully does not implement `Clone` because it's intended
33/// to be a fairly large and expensive structure to clone. Instead this adheres
34/// to `Send` so it may be stored in a `Arc` instance and shared among the various
35/// rendering threads.
36#[derive(Default)]
37crate struct Cache {
38 /// Maps a type ID to all known implementations for that type. This is only
39 /// recognized for intra-crate `ResolvedPath` types, and is used to print
40 /// out extra documentation on the page of an enum/struct.
41 ///
42 /// The values of the map are a list of implementations and documentation
43 /// found on that implementation.
44 pub impls: FxHashMap<DefId, Vec<Impl>>,
45
74b04a01 46 /// Maintains a mapping of local crate `DefId`s to the fully qualified name
e74abb32
XL
47 /// and "short type description" of that node. This is used when generating
48 /// URLs when a type is being linked to. External paths are not located in
49 /// this map because the `External` type itself has all the information
50 /// necessary.
51 pub paths: FxHashMap<DefId, (Vec<String>, ItemType)>,
52
53 /// Similar to `paths`, but only holds external paths. This is only used for
54 /// generating explicit hyperlinks to other crates.
55 pub external_paths: FxHashMap<DefId, (Vec<String>, ItemType)>,
56
57 /// Maps local `DefId`s of exported types to fully qualified paths.
58 /// Unlike 'paths', this mapping ignores any renames that occur
59 /// due to 'use' statements.
60 ///
61 /// This map is used when writing out the special 'implementors'
62 /// javascript file. By using the exact path that the type
63 /// is declared with, we ensure that each path will be identical
64 /// to the path used if the corresponding type is inlined. By
65 /// doing this, we can detect duplicate impls on a trait page, and only display
66 /// the impl for the inlined type.
67 pub exact_paths: FxHashMap<DefId, Vec<String>>,
68
69 /// This map contains information about all known traits of this crate.
70 /// Implementations of a crate should inherit the documentation of the
71 /// parent trait if no extra documentation is specified, and default methods
72 /// should show up in documentation about trait implementations.
73 pub traits: FxHashMap<DefId, clean::Trait>,
74
75 /// When rendering traits, it's often useful to be able to list all
76 /// implementors of the trait, and this mapping is exactly, that: a mapping
77 /// of trait ids to the list of known implementors of the trait
78 pub implementors: FxHashMap<DefId, Vec<Impl>>,
79
80 /// Cache of where external crate documentation can be found.
81 pub extern_locations: FxHashMap<CrateNum, (String, PathBuf, ExternalLocation)>,
82
83 /// Cache of where documentation for primitives can be found.
84 pub primitive_locations: FxHashMap<clean::PrimitiveType, DefId>,
85
86 // Note that external items for which `doc(hidden)` applies to are shown as
87 // non-reachable while local items aren't. This is because we're reusing
88 // the access levels from the privacy check pass.
89 pub access_levels: AccessLevels<DefId>,
90
91 /// The version of the crate being documented, if given from the `--crate-version` flag.
92 pub crate_version: Option<String>,
93
94 // Private fields only used when initially crawling a crate to build a cache
e74abb32
XL
95 stack: Vec<String>,
96 parent_stack: Vec<DefId>,
97 parent_is_trait_impl: bool,
98 search_index: Vec<IndexItem>,
99 stripped_mod: bool,
100 pub deref_trait_did: Option<DefId>,
101 pub deref_mut_trait_did: Option<DefId>,
102 pub owned_box_did: Option<DefId>,
103 masked_crates: FxHashSet<CrateNum>,
104
105 // In rare case where a structure is defined in one module but implemented
106 // in another, if the implementing module is parsed before defining module,
107 // then the fully qualified name of the structure isn't presented in `paths`
108 // yet when its implementation methods are being indexed. Caches such methods
109 // and their parent id here and indexes them at the end of crate parsing.
110 orphan_impl_items: Vec<(DefId, clean::Item)>,
111
112 // Similarly to `orphan_impl_items`, sometimes trait impls are picked up
113 // even though the trait itself is not exported. This can happen if a trait
114 // was defined in function/expression scope, since the impl will be picked
115 // up by `collect-trait-impls` but the trait won't be scraped out in the HIR
116 // crawl. In order to prevent crashes when looking for spotlight traits or
117 // when gathering trait documentation on a type, hold impls here while
118 // folding and add them to the cache later on if we find the trait.
119 orphan_trait_impls: Vec<(DefId, FxHashSet<DefId>, Impl)>,
120
121 /// Aliases added through `#[doc(alias = "...")]`. Since a few items can have the same alias,
122 /// we need the alias element to have an array of items.
f9f354fc 123 pub(super) aliases: BTreeMap<String, Vec<usize>>,
e74abb32
XL
124}
125
126impl Cache {
127 pub fn from_krate(
128 renderinfo: RenderInfo,
129 extern_html_root_urls: &BTreeMap<String, String>,
130 dst: &Path,
131 mut krate: clean::Crate,
132 ) -> (clean::Crate, String, Cache) {
133 // Crawl the crate to build various caches used for the output
134 let RenderInfo {
135 inlined: _,
136 external_paths,
137 exact_paths,
138 access_levels,
139 deref_trait_did,
140 deref_mut_trait_did,
141 owned_box_did,
ba9703b0 142 ..
e74abb32
XL
143 } = renderinfo;
144
dfeec247
XL
145 let external_paths =
146 external_paths.into_iter().map(|(k, (v, t))| (k, (v, ItemType::from(t)))).collect();
e74abb32
XL
147
148 let mut cache = Cache {
149 impls: Default::default(),
150 external_paths,
151 exact_paths,
152 paths: Default::default(),
153 implementors: Default::default(),
154 stack: Vec::new(),
155 parent_stack: Vec::new(),
156 search_index: Vec::new(),
157 parent_is_trait_impl: false,
158 extern_locations: Default::default(),
159 primitive_locations: Default::default(),
160 stripped_mod: false,
161 access_levels,
162 crate_version: krate.version.take(),
163 orphan_impl_items: Vec::new(),
164 orphan_trait_impls: Vec::new(),
165 traits: krate.external_traits.replace(Default::default()),
166 deref_trait_did,
167 deref_mut_trait_did,
168 owned_box_did,
169 masked_crates: mem::take(&mut krate.masked_crates),
170 aliases: Default::default(),
171 };
172
173 // Cache where all our extern crates are located
174 for &(n, ref e) in &krate.externs {
175 let src_root = match e.src {
ba9703b0 176 FileName::Real(ref p) => match p.local_path().parent() {
e74abb32
XL
177 Some(p) => p.to_path_buf(),
178 None => PathBuf::new(),
179 },
180 _ => PathBuf::new(),
181 };
182 let extern_url = extern_html_root_urls.get(&e.name).map(|u| &**u);
dfeec247
XL
183 cache
184 .extern_locations
185 .insert(n, (e.name.clone(), src_root, extern_location(e, extern_url, &dst)));
e74abb32
XL
186
187 let did = DefId { krate: n, index: CRATE_DEF_INDEX };
188 cache.external_paths.insert(did, (vec![e.name.to_string()], ItemType::Module));
189 }
190
191 // Cache where all known primitives have their documentation located.
192 //
193 // Favor linking to as local extern as possible, so iterate all crates in
194 // reverse topological order.
195 for &(_, ref e) in krate.externs.iter().rev() {
196 for &(def_id, prim, _) in &e.primitives {
197 cache.primitive_locations.insert(prim, def_id);
198 }
199 }
200 for &(def_id, prim, _) in &krate.primitives {
201 cache.primitive_locations.insert(prim, def_id);
202 }
203
204 cache.stack.push(krate.name.clone());
205 krate = cache.fold_crate(krate);
206
207 for (trait_did, dids, impl_) in cache.orphan_trait_impls.drain(..) {
208 if cache.traits.contains_key(&trait_did) {
209 for did in dids {
210 cache.impls.entry(did).or_insert(vec![]).push(impl_.clone());
211 }
212 }
213 }
214
215 // Build our search index
216 let index = build_index(&krate, &mut cache);
217
218 (krate, index, cache)
219 }
220}
221
222impl DocFolder for Cache {
223 fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
224 if item.def_id.is_local() {
225 debug!("folding {} \"{:?}\", id {:?}", item.type_(), item.name, item.def_id);
226 }
227
228 // If this is a stripped module,
229 // we don't want it or its children in the search index.
230 let orig_stripped_mod = match item.inner {
231 clean::StrippedItem(box clean::ModuleItem(..)) => {
232 mem::replace(&mut self.stripped_mod, true)
233 }
234 _ => self.stripped_mod,
235 };
236
237 // If the impl is from a masked crate or references something from a
238 // masked crate then remove it completely.
239 if let clean::ImplItem(ref i) = item.inner {
dfeec247
XL
240 if self.masked_crates.contains(&item.def_id.krate)
241 || i.trait_.def_id().map_or(false, |d| self.masked_crates.contains(&d.krate))
242 || i.for_.def_id().map_or(false, |d| self.masked_crates.contains(&d.krate))
243 {
e74abb32
XL
244 return None;
245 }
246 }
247
248 // Propagate a trait method's documentation to all implementors of the
249 // trait.
250 if let clean::TraitItem(ref t) = item.inner {
251 self.traits.entry(item.def_id).or_insert_with(|| t.clone());
252 }
253
254 // Collect all the implementors of traits.
255 if let clean::ImplItem(ref i) = item.inner {
256 if let Some(did) = i.trait_.def_id() {
257 if i.blanket_impl.is_none() {
dfeec247
XL
258 self.implementors
259 .entry(did)
260 .or_default()
261 .push(Impl { impl_item: item.clone() });
e74abb32
XL
262 }
263 }
264 }
265
266 // Index this method for searching later on.
267 if let Some(ref s) = item.name {
268 let (parent, is_inherent_impl_item) = match item.inner {
269 clean::StrippedItem(..) => ((None, None), false),
dfeec247
XL
270 clean::AssocConstItem(..) | clean::TypedefItem(_, true)
271 if self.parent_is_trait_impl =>
272 {
e74abb32
XL
273 // skip associated items in trait impls
274 ((None, None), false)
275 }
dfeec247
XL
276 clean::AssocTypeItem(..)
277 | clean::TyMethodItem(..)
278 | clean::StructFieldItem(..)
279 | clean::VariantItem(..) => (
280 (
281 Some(*self.parent_stack.last().expect("parent_stack is empty")),
282 Some(&self.stack[..self.stack.len() - 1]),
283 ),
284 false,
285 ),
e74abb32
XL
286 clean::MethodItem(..) | clean::AssocConstItem(..) => {
287 if self.parent_stack.is_empty() {
288 ((None, None), false)
289 } else {
dfeec247 290 let last = self.parent_stack.last().expect("parent_stack is empty 2");
e74abb32
XL
291 let did = *last;
292 let path = match self.paths.get(&did) {
293 // The current stack not necessarily has correlation
294 // for where the type was defined. On the other
295 // hand, `paths` always has the right
296 // information if present.
ba9703b0
XL
297 Some(&(
298 ref fqp,
299 ItemType::Trait
300 | ItemType::Struct
301 | ItemType::Union
302 | ItemType::Enum,
303 )) => Some(&fqp[..fqp.len() - 1]),
e74abb32 304 Some(..) => Some(&*self.stack),
dfeec247 305 None => None,
e74abb32
XL
306 };
307 ((Some(*last), path), true)
308 }
309 }
dfeec247 310 _ => ((None, Some(&*self.stack)), false),
e74abb32
XL
311 };
312
313 match parent {
f9f354fc 314 (parent, Some(path)) if is_inherent_impl_item || !self.stripped_mod => {
e74abb32
XL
315 debug_assert!(!item.is_stripped());
316
317 // A crate has a module at its root, containing all items,
318 // which should not be indexed. The crate-item itself is
319 // inserted later on when serializing the search-index.
320 if item.def_id.index != CRATE_DEF_INDEX {
321 self.search_index.push(IndexItem {
322 ty: item.type_(),
323 name: s.to_string(),
324 path: path.join("::"),
325 desc: shorten(plain_summary_line(item.doc_value())),
326 parent,
327 parent_idx: None,
328 search_type: get_index_search_type(&item),
329 });
f9f354fc
XL
330
331 for alias in item.attrs.get_doc_aliases() {
332 self.aliases
333 .entry(alias.to_lowercase())
334 .or_insert(Vec::new())
335 .push(self.search_index.len() - 1);
336 }
e74abb32
XL
337 }
338 }
339 (Some(parent), None) if is_inherent_impl_item => {
340 // We have a parent, but we don't know where they're
341 // defined yet. Wait for later to index this item.
342 self.orphan_impl_items.push((parent, item.clone()));
343 }
344 _ => {}
345 }
346 }
347
348 // Keep track of the fully qualified path for this item.
349 let pushed = match item.name {
350 Some(ref n) if !n.is_empty() => {
351 self.stack.push(n.to_string());
352 true
353 }
354 _ => false,
355 };
356
357 match item.inner {
dfeec247
XL
358 clean::StructItem(..)
359 | clean::EnumItem(..)
360 | clean::TypedefItem(..)
361 | clean::TraitItem(..)
362 | clean::FunctionItem(..)
363 | clean::ModuleItem(..)
364 | clean::ForeignFunctionItem(..)
365 | clean::ForeignStaticItem(..)
366 | clean::ConstantItem(..)
367 | clean::StaticItem(..)
368 | clean::UnionItem(..)
369 | clean::ForeignTypeItem
370 | clean::MacroItem(..)
371 | clean::ProcMacroItem(..)
74b04a01 372 | clean::VariantItem(..)
dfeec247
XL
373 if !self.stripped_mod =>
374 {
e74abb32
XL
375 // Re-exported items mean that the same id can show up twice
376 // in the rustdoc ast that we're looking at. We know,
377 // however, that a re-exported item doesn't show up in the
378 // `public_items` map, so we can skip inserting into the
379 // paths map if there was already an entry present and we're
380 // not a public item.
dfeec247
XL
381 if !self.paths.contains_key(&item.def_id)
382 || self.access_levels.is_public(item.def_id)
e74abb32 383 {
dfeec247 384 self.paths.insert(item.def_id, (self.stack.clone(), item.type_()));
e74abb32 385 }
e74abb32 386 }
e74abb32 387 clean::PrimitiveItem(..) => {
dfeec247 388 self.paths.insert(item.def_id, (self.stack.clone(), item.type_()));
e74abb32
XL
389 }
390
391 _ => {}
392 }
393
394 // Maintain the parent stack
395 let orig_parent_is_trait_impl = self.parent_is_trait_impl;
396 let parent_pushed = match item.inner {
dfeec247
XL
397 clean::TraitItem(..)
398 | clean::EnumItem(..)
399 | clean::ForeignTypeItem
400 | clean::StructItem(..)
74b04a01
XL
401 | clean::UnionItem(..)
402 | clean::VariantItem(..) => {
e74abb32
XL
403 self.parent_stack.push(item.def_id);
404 self.parent_is_trait_impl = false;
405 true
406 }
407 clean::ImplItem(ref i) => {
408 self.parent_is_trait_impl = i.trait_.is_some();
409 match i.for_ {
dfeec247 410 clean::ResolvedPath { did, .. } => {
e74abb32
XL
411 self.parent_stack.push(did);
412 true
413 }
414 ref t => {
dfeec247
XL
415 let prim_did = t
416 .primitive_type()
417 .and_then(|t| self.primitive_locations.get(&t).cloned());
e74abb32
XL
418 match prim_did {
419 Some(did) => {
420 self.parent_stack.push(did);
421 true
422 }
423 None => false,
424 }
425 }
426 }
427 }
dfeec247 428 _ => false,
e74abb32
XL
429 };
430
431 // Once we've recursively found all the generics, hoard off all the
432 // implementations elsewhere.
433 let ret = self.fold_item_recur(item).and_then(|item| {
434 if let clean::Item { inner: clean::ImplItem(_), .. } = item {
435 // Figure out the id of this impl. This may map to a
436 // primitive rather than always to a struct/enum.
437 // Note: matching twice to restrict the lifetime of the `i` borrow.
438 let mut dids = FxHashSet::default();
439 if let clean::Item { inner: clean::ImplItem(ref i), .. } = item {
440 match i.for_ {
dfeec247
XL
441 clean::ResolvedPath { did, .. }
442 | clean::BorrowedRef {
e74abb32
XL
443 type_: box clean::ResolvedPath { did, .. }, ..
444 } => {
445 dids.insert(did);
446 }
447 ref t => {
dfeec247
XL
448 let did = t
449 .primitive_type()
450 .and_then(|t| self.primitive_locations.get(&t).cloned());
e74abb32
XL
451
452 if let Some(did) = did {
453 dids.insert(did);
454 }
455 }
456 }
457
458 if let Some(generics) = i.trait_.as_ref().and_then(|t| t.generics()) {
459 for bound in generics {
460 if let Some(did) = bound.def_id() {
461 dids.insert(did);
462 }
463 }
464 }
465 } else {
466 unreachable!()
467 };
dfeec247 468 let impl_item = Impl { impl_item: item };
e74abb32
XL
469 if impl_item.trait_did().map_or(true, |d| self.traits.contains_key(&d)) {
470 for did in dids {
471 self.impls.entry(did).or_insert(vec![]).push(impl_item.clone());
472 }
473 } else {
dfeec247 474 let trait_did = impl_item.trait_did().expect("no trait did");
e74abb32
XL
475 self.orphan_trait_impls.push((trait_did, dids, impl_item));
476 }
477 None
478 } else {
479 Some(item)
480 }
481 });
482
dfeec247
XL
483 if pushed {
484 self.stack.pop().expect("stack already empty");
485 }
486 if parent_pushed {
487 self.parent_stack.pop().expect("parent stack already empty");
488 }
e74abb32
XL
489 self.stripped_mod = orig_stripped_mod;
490 self.parent_is_trait_impl = orig_parent_is_trait_impl;
491 ret
492 }
493}
494
e74abb32
XL
495/// Attempts to find where an external crate is located, given that we're
496/// rendering in to the specified source destination.
dfeec247
XL
497fn extern_location(
498 e: &clean::ExternalCrate,
499 extern_url: Option<&str>,
500 dst: &Path,
501) -> ExternalLocation {
e74abb32
XL
502 use ExternalLocation::*;
503 // See if there's documentation generated into the local directory
504 let local_location = dst.join(&e.name);
505 if local_location.is_dir() {
506 return Local;
507 }
508
509 if let Some(url) = extern_url {
510 let mut url = url.to_string();
74b04a01 511 if !url.ends_with('/') {
e74abb32
XL
512 url.push('/');
513 }
514 return Remote(url);
515 }
516
517 // Failing that, see if there's an attribute specifying where to find this
518 // external crate
dfeec247
XL
519 e.attrs
520 .lists(sym::doc)
521 .filter(|a| a.check_name(sym::html_root_url))
522 .filter_map(|a| a.value_str())
523 .map(|url| {
524 let mut url = url.to_string();
74b04a01 525 if !url.ends_with('/') {
dfeec247
XL
526 url.push('/')
527 }
528 Remote(url)
529 })
530 .next()
531 .unwrap_or(Unknown) // Well, at least we tried.
e74abb32
XL
532}
533
534/// Builds the search index from the collected metadata
535fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String {
74b04a01 536 let mut defid_to_pathid = FxHashMap::default();
e74abb32 537 let mut crate_items = Vec::with_capacity(cache.search_index.len());
60c5eb7d 538 let mut crate_paths = vec![];
e74abb32 539
f9f354fc
XL
540 let Cache { ref mut search_index, ref orphan_impl_items, ref paths, ref mut aliases, .. } =
541 *cache;
e74abb32
XL
542
543 // Attach all orphan items to the type's definition if the type
544 // has since been learned.
545 for &(did, ref item) in orphan_impl_items {
546 if let Some(&(ref fqp, _)) = paths.get(&did) {
547 search_index.push(IndexItem {
548 ty: item.type_(),
549 name: item.name.clone().unwrap(),
550 path: fqp[..fqp.len() - 1].join("::"),
551 desc: shorten(plain_summary_line(item.doc_value())),
552 parent: Some(did),
553 parent_idx: None,
554 search_type: get_index_search_type(&item),
555 });
f9f354fc
XL
556 for alias in item.attrs.get_doc_aliases() {
557 aliases
558 .entry(alias.to_lowercase())
559 .or_insert(Vec::new())
560 .push(search_index.len() - 1);
561 }
e74abb32
XL
562 }
563 }
564
74b04a01 565 // Reduce `DefId` in paths into smaller sequential numbers,
e74abb32
XL
566 // and prune the paths that do not appear in the index.
567 let mut lastpath = String::new();
568 let mut lastpathid = 0usize;
569
570 for item in search_index {
ba9703b0 571 item.parent_idx = item.parent.and_then(|defid| {
74b04a01 572 if defid_to_pathid.contains_key(&defid) {
ba9703b0 573 defid_to_pathid.get(&defid).copied()
e74abb32
XL
574 } else {
575 let pathid = lastpathid;
74b04a01 576 defid_to_pathid.insert(defid, pathid);
e74abb32
XL
577 lastpathid += 1;
578
ba9703b0
XL
579 if let Some(&(ref fqp, short)) = paths.get(&defid) {
580 crate_paths.push((short, fqp.last().unwrap().clone()));
581 Some(pathid)
582 } else {
583 None
584 }
e74abb32
XL
585 }
586 });
587
588 // Omit the parent path if it is same to that of the prior item.
589 if lastpath == item.path {
590 item.path.clear();
591 } else {
592 lastpath = item.path.clone();
593 }
60c5eb7d 594 crate_items.push(&*item);
e74abb32
XL
595 }
596
dfeec247
XL
597 let crate_doc = krate
598 .module
599 .as_ref()
600 .map(|module| shorten(plain_summary_line(module.doc_value())))
601 .unwrap_or(String::new());
e74abb32 602
60c5eb7d
XL
603 #[derive(Serialize)]
604 struct CrateData<'a> {
605 doc: String,
606 #[serde(rename = "i")]
607 items: Vec<&'a IndexItem>,
608 #[serde(rename = "p")]
609 paths: Vec<(ItemType, String)>,
f9f354fc
XL
610 // The String is alias name and the vec is the list of the elements with this alias.
611 //
612 // To be noted: the `usize` elements are indexes to `items`.
613 #[serde(rename = "a")]
614 #[serde(skip_serializing_if = "BTreeMap::is_empty")]
615 aliases: &'a BTreeMap<String, Vec<usize>>,
60c5eb7d 616 }
e74abb32
XL
617
618 // Collect the index into a string
60c5eb7d 619 format!(
ba9703b0 620 r#""{}":{}"#,
60c5eb7d
XL
621 krate.name,
622 serde_json::to_string(&CrateData {
623 doc: crate_doc,
624 items: crate_items,
625 paths: crate_paths,
f9f354fc 626 aliases,
60c5eb7d 627 })
dfeec247 628 .expect("failed serde conversion")
ba9703b0
XL
629 // All these `replace` calls are because we have to go through JS string for JSON content.
630 .replace(r"\", r"\\")
631 .replace("'", r"\'")
632 // We need to escape double quotes for the JSON.
633 .replace("\\\"", "\\\\\"")
60c5eb7d 634 )
e74abb32
XL
635}
636
637fn get_index_search_type(item: &clean::Item) -> Option<IndexItemFunctionType> {
638 let (all_types, ret_types) = match item.inner {
639 clean::FunctionItem(ref f) => (&f.all_types, &f.ret_types),
640 clean::MethodItem(ref m) => (&m.all_types, &m.ret_types),
641 clean::TyMethodItem(ref m) => (&m.all_types, &m.ret_types),
642 _ => return None,
643 };
644
ba9703b0
XL
645 let inputs = all_types
646 .iter()
647 .map(|(ty, kind)| TypeWithKind::from((get_index_type(&ty), *kind)))
648 .filter(|a| a.ty.name.is_some())
649 .collect();
dfeec247
XL
650 let output = ret_types
651 .iter()
ba9703b0
XL
652 .map(|(ty, kind)| TypeWithKind::from((get_index_type(&ty), *kind)))
653 .filter(|a| a.ty.name.is_some())
dfeec247
XL
654 .collect::<Vec<_>>();
655 let output = if output.is_empty() { None } else { Some(output) };
e74abb32
XL
656
657 Some(IndexItemFunctionType { inputs, output })
658}
659
ba9703b0
XL
660fn get_index_type(clean_type: &clean::Type) -> RenderType {
661 RenderType {
662 ty: clean_type.def_id(),
663 idx: None,
e74abb32
XL
664 name: get_index_type_name(clean_type, true).map(|s| s.to_ascii_lowercase()),
665 generics: get_generics(clean_type),
ba9703b0 666 }
e74abb32
XL
667}
668
669fn get_index_type_name(clean_type: &clean::Type, accept_generic: bool) -> Option<String> {
670 match *clean_type {
671 clean::ResolvedPath { ref path, .. } => {
672 let segments = &path.segments;
74b04a01 673 let path_segment = segments.iter().last().unwrap_or_else(|| panic!(
e74abb32
XL
674 "get_index_type_name(clean_type: {:?}, accept_generic: {:?}) had length zero path",
675 clean_type, accept_generic
676 ));
677 Some(path_segment.name.clone())
678 }
679 clean::Generic(ref s) if accept_generic => Some(s.clone()),
680 clean::Primitive(ref p) => Some(format!("{:?}", p)),
681 clean::BorrowedRef { ref type_, .. } => get_index_type_name(type_, accept_generic),
682 // FIXME: add all from clean::Type.
dfeec247 683 _ => None,
e74abb32
XL
684 }
685}
686
ba9703b0 687fn get_generics(clean_type: &clean::Type) -> Option<Vec<Generic>> {
dfeec247
XL
688 clean_type.generics().and_then(|types| {
689 let r = types
690 .iter()
ba9703b0
XL
691 .filter_map(|t| {
692 get_index_type_name(t, false).map(|name| Generic {
693 name: name.to_ascii_lowercase(),
694 defid: t.def_id(),
695 idx: None,
696 })
697 })
dfeec247
XL
698 .collect::<Vec<_>>();
699 if r.is_empty() { None } else { Some(r) }
700 })
e74abb32 701}