]>
Commit | Line | Data |
---|---|---|
dfeec247 XL |
1 | use std::cell::RefCell; |
2 | use std::default::Default; | |
60c5eb7d XL |
3 | use std::fmt; |
4 | use std::hash::{Hash, Hasher}; | |
60c5eb7d | 5 | use std::iter::FromIterator; |
dfeec247 | 6 | use std::num::NonZeroU32; |
60c5eb7d | 7 | use std::rc::Rc; |
60c5eb7d | 8 | use std::sync::Arc; |
dfeec247 | 9 | use std::{slice, vec}; |
60c5eb7d XL |
10 | |
11 | use rustc::middle::lang_items; | |
12 | use rustc::middle::stability; | |
60c5eb7d | 13 | use rustc::ty::layout::VariantIdx; |
dfeec247 XL |
14 | use rustc_data_structures::fx::{FxHashMap, FxHashSet}; |
15 | use rustc_hir as hir; | |
16 | use rustc_hir::def::Res; | |
17 | use rustc_hir::def_id::{CrateNum, DefId}; | |
18 | use rustc_hir::Mutability; | |
60c5eb7d | 19 | use rustc_index::vec::IndexVec; |
dfeec247 XL |
20 | use rustc_span::hygiene::MacroKind; |
21 | use rustc_span::source_map::DUMMY_SP; | |
22 | use rustc_span::symbol::{sym, Symbol}; | |
23 | use rustc_span::{self, FileName}; | |
60c5eb7d | 24 | use rustc_target::spec::abi::Abi; |
dfeec247 | 25 | use syntax::ast::{self, AttrStyle, Ident}; |
60c5eb7d | 26 | use syntax::attr; |
dfeec247 | 27 | use syntax::util::comments::strip_doc_comment_decoration; |
60c5eb7d | 28 | |
60c5eb7d | 29 | use crate::clean::cfg::Cfg; |
60c5eb7d | 30 | use crate::clean::external_path; |
dfeec247 | 31 | use crate::clean::inline; |
60c5eb7d | 32 | use crate::clean::types::Type::{QPath, ResolvedPath}; |
dfeec247 | 33 | use crate::core::DocContext; |
60c5eb7d XL |
34 | use crate::doctree; |
35 | use crate::html::item_type::ItemType; | |
36 | use crate::html::render::{cache, ExternalLocation}; | |
37 | ||
dfeec247 | 38 | use self::FunctionRetTy::*; |
60c5eb7d XL |
39 | use self::ItemEnum::*; |
40 | use self::SelfTy::*; | |
dfeec247 | 41 | use self::Type::*; |
60c5eb7d XL |
42 | |
43 | thread_local!(pub static MAX_DEF_ID: RefCell<FxHashMap<CrateNum, DefId>> = Default::default()); | |
44 | ||
45 | #[derive(Clone, Debug)] | |
46 | pub struct Crate { | |
47 | pub name: String, | |
48 | pub version: Option<String>, | |
49 | pub src: FileName, | |
50 | pub module: Option<Item>, | |
51 | pub externs: Vec<(CrateNum, ExternalCrate)>, | |
52 | pub primitives: Vec<(DefId, PrimitiveType, Attributes)>, | |
53 | // These are later on moved into `CACHEKEY`, leaving the map empty. | |
54 | // Only here so that they can be filtered through the rustdoc passes. | |
55 | pub external_traits: Rc<RefCell<FxHashMap<DefId, Trait>>>, | |
56 | pub masked_crates: FxHashSet<CrateNum>, | |
57 | pub collapsed: bool, | |
58 | } | |
59 | ||
60 | #[derive(Clone, Debug)] | |
61 | pub struct ExternalCrate { | |
62 | pub name: String, | |
63 | pub src: FileName, | |
64 | pub attrs: Attributes, | |
65 | pub primitives: Vec<(DefId, PrimitiveType, Attributes)>, | |
66 | pub keywords: Vec<(DefId, String, Attributes)>, | |
67 | } | |
68 | ||
69 | /// Anything with a source location and set of attributes and, optionally, a | |
70 | /// name. That is, anything that can be documented. This doesn't correspond | |
71 | /// directly to the AST's concept of an item; it's a strict superset. | |
72 | #[derive(Clone)] | |
73 | pub struct Item { | |
74 | /// Stringified span | |
75 | pub source: Span, | |
76 | /// Not everything has a name. E.g., impls | |
77 | pub name: Option<String>, | |
78 | pub attrs: Attributes, | |
79 | pub inner: ItemEnum, | |
80 | pub visibility: Visibility, | |
81 | pub def_id: DefId, | |
82 | pub stability: Option<Stability>, | |
83 | pub deprecation: Option<Deprecation>, | |
84 | } | |
85 | ||
86 | impl fmt::Debug for Item { | |
87 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { | |
dfeec247 XL |
88 | let fake = MAX_DEF_ID.with(|m| { |
89 | m.borrow().get(&self.def_id.krate).map(|id| self.def_id >= *id).unwrap_or(false) | |
90 | }); | |
60c5eb7d XL |
91 | let def_id: &dyn fmt::Debug = if fake { &"**FAKE**" } else { &self.def_id }; |
92 | ||
93 | fmt.debug_struct("Item") | |
94 | .field("source", &self.source) | |
95 | .field("name", &self.name) | |
96 | .field("attrs", &self.attrs) | |
97 | .field("inner", &self.inner) | |
98 | .field("visibility", &self.visibility) | |
99 | .field("def_id", def_id) | |
100 | .field("stability", &self.stability) | |
101 | .field("deprecation", &self.deprecation) | |
102 | .finish() | |
103 | } | |
104 | } | |
105 | ||
106 | impl Item { | |
107 | /// Finds the `doc` attribute as a NameValue and returns the corresponding | |
108 | /// value found. | |
109 | pub fn doc_value(&self) -> Option<&str> { | |
110 | self.attrs.doc_value() | |
111 | } | |
112 | ||
113 | /// Finds all `doc` attributes as NameValues and returns their corresponding values, joined | |
114 | /// with newlines. | |
115 | pub fn collapsed_doc_value(&self) -> Option<String> { | |
116 | self.attrs.collapsed_doc_value() | |
117 | } | |
118 | ||
119 | pub fn links(&self) -> Vec<(String, String)> { | |
120 | self.attrs.links(&self.def_id.krate) | |
121 | } | |
122 | ||
123 | pub fn is_crate(&self) -> bool { | |
124 | match self.inner { | |
dfeec247 XL |
125 | StrippedItem(box ModuleItem(Module { is_crate: true, .. })) |
126 | | ModuleItem(Module { is_crate: true, .. }) => true, | |
60c5eb7d XL |
127 | _ => false, |
128 | } | |
129 | } | |
130 | pub fn is_mod(&self) -> bool { | |
131 | self.type_() == ItemType::Module | |
132 | } | |
133 | pub fn is_trait(&self) -> bool { | |
134 | self.type_() == ItemType::Trait | |
135 | } | |
136 | pub fn is_struct(&self) -> bool { | |
137 | self.type_() == ItemType::Struct | |
138 | } | |
139 | pub fn is_enum(&self) -> bool { | |
140 | self.type_() == ItemType::Enum | |
141 | } | |
142 | pub fn is_variant(&self) -> bool { | |
143 | self.type_() == ItemType::Variant | |
144 | } | |
145 | pub fn is_associated_type(&self) -> bool { | |
146 | self.type_() == ItemType::AssocType | |
147 | } | |
148 | pub fn is_associated_const(&self) -> bool { | |
149 | self.type_() == ItemType::AssocConst | |
150 | } | |
151 | pub fn is_method(&self) -> bool { | |
152 | self.type_() == ItemType::Method | |
153 | } | |
154 | pub fn is_ty_method(&self) -> bool { | |
155 | self.type_() == ItemType::TyMethod | |
156 | } | |
157 | pub fn is_typedef(&self) -> bool { | |
158 | self.type_() == ItemType::Typedef | |
159 | } | |
160 | pub fn is_primitive(&self) -> bool { | |
161 | self.type_() == ItemType::Primitive | |
162 | } | |
163 | pub fn is_union(&self) -> bool { | |
164 | self.type_() == ItemType::Union | |
165 | } | |
166 | pub fn is_import(&self) -> bool { | |
167 | self.type_() == ItemType::Import | |
168 | } | |
169 | pub fn is_extern_crate(&self) -> bool { | |
170 | self.type_() == ItemType::ExternCrate | |
171 | } | |
172 | pub fn is_keyword(&self) -> bool { | |
173 | self.type_() == ItemType::Keyword | |
174 | } | |
175 | pub fn is_stripped(&self) -> bool { | |
dfeec247 XL |
176 | match self.inner { |
177 | StrippedItem(..) => true, | |
178 | _ => false, | |
179 | } | |
60c5eb7d XL |
180 | } |
181 | pub fn has_stripped_fields(&self) -> Option<bool> { | |
182 | match self.inner { | |
183 | StructItem(ref _struct) => Some(_struct.fields_stripped), | |
184 | UnionItem(ref union) => Some(union.fields_stripped), | |
dfeec247 | 185 | VariantItem(Variant { kind: VariantKind::Struct(ref vstruct) }) => { |
60c5eb7d | 186 | Some(vstruct.fields_stripped) |
dfeec247 | 187 | } |
60c5eb7d XL |
188 | _ => None, |
189 | } | |
190 | } | |
191 | ||
192 | pub fn stability_class(&self) -> Option<String> { | |
193 | self.stability.as_ref().and_then(|ref s| { | |
194 | let mut classes = Vec::with_capacity(2); | |
195 | ||
196 | if s.level == stability::Unstable { | |
197 | classes.push("unstable"); | |
198 | } | |
199 | ||
200 | if s.deprecation.is_some() { | |
201 | classes.push("deprecated"); | |
202 | } | |
203 | ||
dfeec247 | 204 | if classes.len() != 0 { Some(classes.join(" ")) } else { None } |
60c5eb7d XL |
205 | }) |
206 | } | |
207 | ||
208 | pub fn stable_since(&self) -> Option<&str> { | |
209 | self.stability.as_ref().map(|s| &s.since[..]) | |
210 | } | |
211 | ||
212 | pub fn is_non_exhaustive(&self) -> bool { | |
dfeec247 | 213 | self.attrs.other_attrs.iter().any(|a| a.check_name(sym::non_exhaustive)) |
60c5eb7d XL |
214 | } |
215 | ||
216 | /// Returns a documentation-level item type from the item. | |
217 | pub fn type_(&self) -> ItemType { | |
218 | ItemType::from(self) | |
219 | } | |
220 | ||
221 | /// Returns the info in the item's `#[deprecated]` or `#[rustc_deprecated]` attributes. | |
222 | /// | |
223 | /// If the item is not deprecated, returns `None`. | |
224 | pub fn deprecation(&self) -> Option<&Deprecation> { | |
225 | self.deprecation | |
226 | .as_ref() | |
227 | .or_else(|| self.stability.as_ref().and_then(|s| s.deprecation.as_ref())) | |
228 | } | |
229 | pub fn is_default(&self) -> bool { | |
230 | match self.inner { | |
231 | ItemEnum::MethodItem(ref meth) => { | |
232 | if let Some(defaultness) = meth.defaultness { | |
233 | defaultness.has_value() && !defaultness.is_final() | |
234 | } else { | |
235 | false | |
236 | } | |
237 | } | |
238 | _ => false, | |
239 | } | |
240 | } | |
241 | } | |
242 | ||
243 | #[derive(Clone, Debug)] | |
244 | pub enum ItemEnum { | |
245 | ExternCrateItem(String, Option<String>), | |
246 | ImportItem(Import), | |
247 | StructItem(Struct), | |
248 | UnionItem(Union), | |
249 | EnumItem(Enum), | |
250 | FunctionItem(Function), | |
251 | ModuleItem(Module), | |
252 | TypedefItem(Typedef, bool /* is associated type */), | |
253 | OpaqueTyItem(OpaqueTy, bool /* is associated type */), | |
254 | StaticItem(Static), | |
255 | ConstantItem(Constant), | |
256 | TraitItem(Trait), | |
257 | TraitAliasItem(TraitAlias), | |
258 | ImplItem(Impl), | |
259 | /// A method signature only. Used for required methods in traits (ie, | |
260 | /// non-default-methods). | |
261 | TyMethodItem(TyMethod), | |
262 | /// A method with a body. | |
263 | MethodItem(Method), | |
264 | StructFieldItem(Type), | |
265 | VariantItem(Variant), | |
266 | /// `fn`s from an extern block | |
267 | ForeignFunctionItem(Function), | |
268 | /// `static`s from an extern block | |
269 | ForeignStaticItem(Static), | |
270 | /// `type`s from an extern block | |
271 | ForeignTypeItem, | |
272 | MacroItem(Macro), | |
273 | ProcMacroItem(ProcMacro), | |
274 | PrimitiveItem(PrimitiveType), | |
275 | AssocConstItem(Type, Option<String>), | |
276 | AssocTypeItem(Vec<GenericBound>, Option<Type>), | |
277 | /// An item that has been stripped by a rustdoc pass | |
278 | StrippedItem(Box<ItemEnum>), | |
279 | KeywordItem(String), | |
280 | } | |
281 | ||
282 | impl ItemEnum { | |
283 | pub fn is_associated(&self) -> bool { | |
284 | match *self { | |
dfeec247 | 285 | ItemEnum::TypedefItem(_, _) | ItemEnum::AssocTypeItem(_, _) => true, |
60c5eb7d XL |
286 | _ => false, |
287 | } | |
288 | } | |
289 | } | |
290 | ||
291 | #[derive(Clone, Debug)] | |
292 | pub struct Module { | |
293 | pub items: Vec<Item>, | |
294 | pub is_crate: bool, | |
295 | } | |
296 | ||
297 | pub struct ListAttributesIter<'a> { | |
298 | attrs: slice::Iter<'a, ast::Attribute>, | |
299 | current_list: vec::IntoIter<ast::NestedMetaItem>, | |
300 | name: Symbol, | |
301 | } | |
302 | ||
303 | impl<'a> Iterator for ListAttributesIter<'a> { | |
304 | type Item = ast::NestedMetaItem; | |
305 | ||
306 | fn next(&mut self) -> Option<Self::Item> { | |
307 | if let Some(nested) = self.current_list.next() { | |
308 | return Some(nested); | |
309 | } | |
310 | ||
311 | for attr in &mut self.attrs { | |
312 | if let Some(list) = attr.meta_item_list() { | |
313 | if attr.check_name(self.name) { | |
314 | self.current_list = list.into_iter(); | |
315 | if let Some(nested) = self.current_list.next() { | |
316 | return Some(nested); | |
317 | } | |
318 | } | |
319 | } | |
320 | } | |
321 | ||
322 | None | |
323 | } | |
324 | ||
325 | fn size_hint(&self) -> (usize, Option<usize>) { | |
326 | let lower = self.current_list.len(); | |
327 | (lower, None) | |
328 | } | |
329 | } | |
330 | ||
331 | pub trait AttributesExt { | |
332 | /// Finds an attribute as List and returns the list of attributes nested inside. | |
333 | fn lists(&self, name: Symbol) -> ListAttributesIter<'_>; | |
334 | } | |
335 | ||
336 | impl AttributesExt for [ast::Attribute] { | |
337 | fn lists(&self, name: Symbol) -> ListAttributesIter<'_> { | |
dfeec247 | 338 | ListAttributesIter { attrs: self.iter(), current_list: Vec::new().into_iter(), name } |
60c5eb7d XL |
339 | } |
340 | } | |
341 | ||
342 | pub trait NestedAttributesExt { | |
343 | /// Returns `true` if the attribute list contains a specific `Word` | |
344 | fn has_word(self, word: Symbol) -> bool; | |
345 | } | |
346 | ||
dfeec247 | 347 | impl<I: IntoIterator<Item = ast::NestedMetaItem>> NestedAttributesExt for I { |
60c5eb7d XL |
348 | fn has_word(self, word: Symbol) -> bool { |
349 | self.into_iter().any(|attr| attr.is_word() && attr.check_name(word)) | |
350 | } | |
351 | } | |
352 | ||
353 | /// A portion of documentation, extracted from a `#[doc]` attribute. | |
354 | /// | |
355 | /// Each variant contains the line number within the complete doc-comment where the fragment | |
356 | /// starts, as well as the Span where the corresponding doc comment or attribute is located. | |
357 | /// | |
358 | /// Included files are kept separate from inline doc comments so that proper line-number | |
359 | /// information can be given when a doctest fails. Sugared doc comments and "raw" doc comments are | |
360 | /// kept separate because of issue #42760. | |
361 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
362 | pub enum DocFragment { | |
363 | /// A doc fragment created from a `///` or `//!` doc comment. | |
dfeec247 | 364 | SugaredDoc(usize, rustc_span::Span, String), |
60c5eb7d | 365 | /// A doc fragment created from a "raw" `#[doc=""]` attribute. |
dfeec247 | 366 | RawDoc(usize, rustc_span::Span, String), |
60c5eb7d XL |
367 | /// A doc fragment created from a `#[doc(include="filename")]` attribute. Contains both the |
368 | /// given filename and the file contents. | |
dfeec247 | 369 | Include(usize, rustc_span::Span, String, String), |
60c5eb7d XL |
370 | } |
371 | ||
372 | impl DocFragment { | |
373 | pub fn as_str(&self) -> &str { | |
374 | match *self { | |
375 | DocFragment::SugaredDoc(_, _, ref s) => &s[..], | |
376 | DocFragment::RawDoc(_, _, ref s) => &s[..], | |
377 | DocFragment::Include(_, _, _, ref s) => &s[..], | |
378 | } | |
379 | } | |
380 | ||
dfeec247 | 381 | pub fn span(&self) -> rustc_span::Span { |
60c5eb7d | 382 | match *self { |
dfeec247 XL |
383 | DocFragment::SugaredDoc(_, span, _) |
384 | | DocFragment::RawDoc(_, span, _) | |
385 | | DocFragment::Include(_, span, _, _) => span, | |
60c5eb7d XL |
386 | } |
387 | } | |
388 | } | |
389 | ||
390 | impl<'a> FromIterator<&'a DocFragment> for String { | |
391 | fn from_iter<T>(iter: T) -> Self | |
392 | where | |
dfeec247 | 393 | T: IntoIterator<Item = &'a DocFragment>, |
60c5eb7d XL |
394 | { |
395 | iter.into_iter().fold(String::new(), |mut acc, frag| { | |
396 | if !acc.is_empty() { | |
397 | acc.push('\n'); | |
398 | } | |
399 | match *frag { | |
400 | DocFragment::SugaredDoc(_, _, ref docs) | |
dfeec247 XL |
401 | | DocFragment::RawDoc(_, _, ref docs) |
402 | | DocFragment::Include(_, _, _, ref docs) => acc.push_str(docs), | |
60c5eb7d XL |
403 | } |
404 | ||
405 | acc | |
406 | }) | |
407 | } | |
408 | } | |
409 | ||
410 | #[derive(Clone, Debug, Default)] | |
411 | pub struct Attributes { | |
412 | pub doc_strings: Vec<DocFragment>, | |
413 | pub other_attrs: Vec<ast::Attribute>, | |
414 | pub cfg: Option<Arc<Cfg>>, | |
dfeec247 | 415 | pub span: Option<rustc_span::Span>, |
60c5eb7d XL |
416 | /// map from Rust paths to resolved defs and potential URL fragments |
417 | pub links: Vec<(String, Option<DefId>, Option<String>)>, | |
418 | pub inner_docs: bool, | |
419 | } | |
420 | ||
421 | impl Attributes { | |
422 | /// Extracts the content from an attribute `#[doc(cfg(content))]`. | |
423 | pub fn extract_cfg(mi: &ast::MetaItem) -> Option<&ast::MetaItem> { | |
424 | use syntax::ast::NestedMetaItem::MetaItem; | |
425 | ||
426 | if let ast::MetaItemKind::List(ref nmis) = mi.kind { | |
427 | if nmis.len() == 1 { | |
428 | if let MetaItem(ref cfg_mi) = nmis[0] { | |
429 | if cfg_mi.check_name(sym::cfg) { | |
430 | if let ast::MetaItemKind::List(ref cfg_nmis) = cfg_mi.kind { | |
431 | if cfg_nmis.len() == 1 { | |
432 | if let MetaItem(ref content_mi) = cfg_nmis[0] { | |
433 | return Some(content_mi); | |
434 | } | |
435 | } | |
436 | } | |
437 | } | |
438 | } | |
439 | } | |
440 | } | |
441 | ||
442 | None | |
443 | } | |
444 | ||
445 | /// Reads a `MetaItem` from within an attribute, looks for whether it is a | |
446 | /// `#[doc(include="file")]`, and returns the filename and contents of the file as loaded from | |
447 | /// its expansion. | |
448 | pub fn extract_include(mi: &ast::MetaItem) -> Option<(String, String)> { | |
449 | mi.meta_item_list().and_then(|list| { | |
450 | for meta in list { | |
451 | if meta.check_name(sym::include) { | |
452 | // the actual compiled `#[doc(include="filename")]` gets expanded to | |
453 | // `#[doc(include(file="filename", contents="file contents")]` so we need to | |
454 | // look for that instead | |
455 | return meta.meta_item_list().and_then(|list| { | |
456 | let mut filename: Option<String> = None; | |
457 | let mut contents: Option<String> = None; | |
458 | ||
459 | for it in list { | |
460 | if it.check_name(sym::file) { | |
461 | if let Some(name) = it.value_str() { | |
462 | filename = Some(name.to_string()); | |
463 | } | |
464 | } else if it.check_name(sym::contents) { | |
465 | if let Some(docs) = it.value_str() { | |
466 | contents = Some(docs.to_string()); | |
467 | } | |
468 | } | |
469 | } | |
470 | ||
471 | if let (Some(filename), Some(contents)) = (filename, contents) { | |
472 | Some((filename, contents)) | |
473 | } else { | |
474 | None | |
475 | } | |
476 | }); | |
477 | } | |
478 | } | |
479 | ||
480 | None | |
481 | }) | |
482 | } | |
483 | ||
484 | pub fn has_doc_flag(&self, flag: Symbol) -> bool { | |
485 | for attr in &self.other_attrs { | |
dfeec247 XL |
486 | if !attr.check_name(sym::doc) { |
487 | continue; | |
488 | } | |
60c5eb7d XL |
489 | |
490 | if let Some(items) = attr.meta_item_list() { | |
491 | if items.iter().filter_map(|i| i.meta_item()).any(|it| it.check_name(flag)) { | |
492 | return true; | |
493 | } | |
494 | } | |
495 | } | |
496 | ||
497 | false | |
498 | } | |
499 | ||
dfeec247 | 500 | pub fn from_ast(diagnostic: &::rustc_errors::Handler, attrs: &[ast::Attribute]) -> Attributes { |
60c5eb7d XL |
501 | let mut doc_strings = vec![]; |
502 | let mut sp = None; | |
503 | let mut cfg = Cfg::True; | |
504 | let mut doc_line = 0; | |
505 | ||
dfeec247 XL |
506 | let other_attrs = attrs |
507 | .iter() | |
508 | .filter_map(|attr| { | |
509 | if let Some(value) = attr.doc_str() { | |
510 | let (value, mk_fragment): (_, fn(_, _, _) -> _) = if attr.is_doc_comment() { | |
511 | (strip_doc_comment_decoration(&value.as_str()), DocFragment::SugaredDoc) | |
512 | } else { | |
513 | (value.to_string(), DocFragment::RawDoc) | |
514 | }; | |
60c5eb7d | 515 | |
dfeec247 XL |
516 | let line = doc_line; |
517 | doc_line += value.lines().count(); | |
518 | doc_strings.push(mk_fragment(line, attr.span, value)); | |
60c5eb7d | 519 | |
dfeec247 XL |
520 | if sp.is_none() { |
521 | sp = Some(attr.span); | |
522 | } | |
523 | None | |
524 | } else { | |
525 | if attr.check_name(sym::doc) { | |
526 | if let Some(mi) = attr.meta() { | |
527 | if let Some(cfg_mi) = Attributes::extract_cfg(&mi) { | |
528 | // Extracted #[doc(cfg(...))] | |
529 | match Cfg::parse(cfg_mi) { | |
530 | Ok(new_cfg) => cfg &= new_cfg, | |
531 | Err(e) => diagnostic.span_err(e.span, e.msg), | |
532 | } | |
533 | } else if let Some((filename, contents)) = | |
534 | Attributes::extract_include(&mi) | |
535 | { | |
536 | let line = doc_line; | |
537 | doc_line += contents.lines().count(); | |
538 | doc_strings.push(DocFragment::Include( | |
539 | line, attr.span, filename, contents, | |
540 | )); | |
60c5eb7d | 541 | } |
60c5eb7d XL |
542 | } |
543 | } | |
dfeec247 | 544 | Some(attr.clone()) |
60c5eb7d | 545 | } |
60c5eb7d | 546 | }) |
dfeec247 | 547 | .collect(); |
60c5eb7d XL |
548 | |
549 | // treat #[target_feature(enable = "feat")] attributes as if they were | |
550 | // #[doc(cfg(target_feature = "feat"))] attributes as well | |
551 | for attr in attrs.lists(sym::target_feature) { | |
552 | if attr.check_name(sym::enable) { | |
553 | if let Some(feat) = attr.value_str() { | |
554 | let meta = attr::mk_name_value_item_str( | |
dfeec247 XL |
555 | Ident::with_dummy_span(sym::target_feature), |
556 | feat, | |
557 | DUMMY_SP, | |
60c5eb7d XL |
558 | ); |
559 | if let Ok(feat_cfg) = Cfg::parse(&meta) { | |
560 | cfg &= feat_cfg; | |
561 | } | |
562 | } | |
563 | } | |
564 | } | |
565 | ||
dfeec247 XL |
566 | let inner_docs = attrs |
567 | .iter() | |
568 | .filter(|a| a.doc_str().is_some()) | |
569 | .next() | |
570 | .map_or(true, |a| a.style == AttrStyle::Inner); | |
60c5eb7d XL |
571 | |
572 | Attributes { | |
573 | doc_strings, | |
574 | other_attrs, | |
575 | cfg: if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) }, | |
576 | span: sp, | |
577 | links: vec![], | |
578 | inner_docs, | |
579 | } | |
580 | } | |
581 | ||
582 | /// Finds the `doc` attribute as a NameValue and returns the corresponding | |
583 | /// value found. | |
584 | pub fn doc_value(&self) -> Option<&str> { | |
585 | self.doc_strings.first().map(|s| s.as_str()) | |
586 | } | |
587 | ||
588 | /// Finds all `doc` attributes as NameValues and returns their corresponding values, joined | |
589 | /// with newlines. | |
590 | pub fn collapsed_doc_value(&self) -> Option<String> { | |
dfeec247 | 591 | if !self.doc_strings.is_empty() { Some(self.doc_strings.iter().collect()) } else { None } |
60c5eb7d XL |
592 | } |
593 | ||
594 | /// Gets links as a vector | |
595 | /// | |
596 | /// Cache must be populated before call | |
597 | pub fn links(&self, krate: &CrateNum) -> Vec<(String, String)> { | |
598 | use crate::html::format::href; | |
599 | ||
dfeec247 XL |
600 | self.links |
601 | .iter() | |
602 | .filter_map(|&(ref s, did, ref fragment)| { | |
603 | match did { | |
604 | Some(did) => { | |
605 | if let Some((mut href, ..)) = href(did) { | |
606 | if let Some(ref fragment) = *fragment { | |
607 | href.push_str("#"); | |
608 | href.push_str(fragment); | |
609 | } | |
610 | Some((s.clone(), href)) | |
611 | } else { | |
612 | None | |
60c5eb7d | 613 | } |
60c5eb7d | 614 | } |
dfeec247 XL |
615 | None => { |
616 | if let Some(ref fragment) = *fragment { | |
617 | let cache = cache(); | |
618 | let url = match cache.extern_locations.get(krate) { | |
619 | Some(&(_, ref src, ExternalLocation::Local)) => { | |
620 | src.to_str().expect("invalid file path") | |
621 | } | |
622 | Some(&(_, _, ExternalLocation::Remote(ref s))) => s, | |
623 | Some(&(_, _, ExternalLocation::Unknown)) | None => { | |
624 | "https://doc.rust-lang.org/nightly" | |
625 | } | |
626 | }; | |
627 | // This is a primitive so the url is done "by hand". | |
628 | let tail = fragment.find('#').unwrap_or_else(|| fragment.len()); | |
629 | Some(( | |
630 | s.clone(), | |
631 | format!( | |
632 | "{}{}std/primitive.{}.html{}", | |
633 | url, | |
634 | if !url.ends_with('/') { "/" } else { "" }, | |
635 | &fragment[..tail], | |
636 | &fragment[tail..] | |
637 | ), | |
638 | )) | |
639 | } else { | |
640 | panic!("This isn't a primitive?!"); | |
641 | } | |
60c5eb7d XL |
642 | } |
643 | } | |
dfeec247 XL |
644 | }) |
645 | .collect() | |
60c5eb7d XL |
646 | } |
647 | } | |
648 | ||
649 | impl PartialEq for Attributes { | |
650 | fn eq(&self, rhs: &Self) -> bool { | |
dfeec247 XL |
651 | self.doc_strings == rhs.doc_strings |
652 | && self.cfg == rhs.cfg | |
653 | && self.span == rhs.span | |
654 | && self.links == rhs.links | |
655 | && self | |
656 | .other_attrs | |
657 | .iter() | |
658 | .map(|attr| attr.id) | |
659 | .eq(rhs.other_attrs.iter().map(|attr| attr.id)) | |
60c5eb7d XL |
660 | } |
661 | } | |
662 | ||
663 | impl Eq for Attributes {} | |
664 | ||
665 | impl Hash for Attributes { | |
666 | fn hash<H: Hasher>(&self, hasher: &mut H) { | |
667 | self.doc_strings.hash(hasher); | |
668 | self.cfg.hash(hasher); | |
669 | self.span.hash(hasher); | |
670 | self.links.hash(hasher); | |
671 | for attr in &self.other_attrs { | |
672 | attr.id.hash(hasher); | |
673 | } | |
674 | } | |
675 | } | |
676 | ||
677 | impl AttributesExt for Attributes { | |
678 | fn lists(&self, name: Symbol) -> ListAttributesIter<'_> { | |
679 | self.other_attrs.lists(name) | |
680 | } | |
681 | } | |
682 | ||
683 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
684 | pub enum GenericBound { | |
685 | TraitBound(PolyTrait, hir::TraitBoundModifier), | |
686 | Outlives(Lifetime), | |
687 | } | |
688 | ||
689 | impl GenericBound { | |
690 | pub fn maybe_sized(cx: &DocContext<'_>) -> GenericBound { | |
691 | let did = cx.tcx.require_lang_item(lang_items::SizedTraitLangItem, None); | |
692 | let empty = cx.tcx.intern_substs(&[]); | |
dfeec247 | 693 | let path = external_path(cx, cx.tcx.item_name(did), Some(did), false, vec![], empty); |
60c5eb7d | 694 | inline::record_extern_fqn(cx, did, TypeKind::Trait); |
dfeec247 XL |
695 | GenericBound::TraitBound( |
696 | PolyTrait { | |
697 | trait_: ResolvedPath { path, param_names: None, did, is_generic: false }, | |
698 | generic_params: Vec::new(), | |
60c5eb7d | 699 | }, |
dfeec247 XL |
700 | hir::TraitBoundModifier::Maybe, |
701 | ) | |
60c5eb7d XL |
702 | } |
703 | ||
704 | pub fn is_sized_bound(&self, cx: &DocContext<'_>) -> bool { | |
dfeec247 | 705 | use rustc_hir::TraitBoundModifier as TBM; |
60c5eb7d XL |
706 | if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, TBM::None) = *self { |
707 | if trait_.def_id() == cx.tcx.lang_items().sized_trait() { | |
708 | return true; | |
709 | } | |
710 | } | |
711 | false | |
712 | } | |
713 | ||
714 | pub fn get_poly_trait(&self) -> Option<PolyTrait> { | |
715 | if let GenericBound::TraitBound(ref p, _) = *self { | |
dfeec247 | 716 | return Some(p.clone()); |
60c5eb7d XL |
717 | } |
718 | None | |
719 | } | |
720 | ||
721 | pub fn get_trait_type(&self) -> Option<Type> { | |
722 | if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, _) = *self { | |
723 | Some(trait_.clone()) | |
724 | } else { | |
725 | None | |
726 | } | |
727 | } | |
728 | } | |
729 | ||
730 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
731 | pub struct Lifetime(pub String); | |
732 | ||
733 | impl Lifetime { | |
734 | pub fn get_ref<'a>(&'a self) -> &'a str { | |
735 | let Lifetime(ref s) = *self; | |
736 | let s: &'a str = s; | |
737 | s | |
738 | } | |
739 | ||
740 | pub fn statik() -> Lifetime { | |
741 | Lifetime("'static".to_string()) | |
742 | } | |
743 | } | |
744 | ||
745 | #[derive(Clone, Debug)] | |
746 | pub enum WherePredicate { | |
747 | BoundPredicate { ty: Type, bounds: Vec<GenericBound> }, | |
748 | RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> }, | |
749 | EqPredicate { lhs: Type, rhs: Type }, | |
750 | } | |
751 | ||
752 | impl WherePredicate { | |
753 | pub fn get_bounds(&self) -> Option<&[GenericBound]> { | |
754 | match *self { | |
755 | WherePredicate::BoundPredicate { ref bounds, .. } => Some(bounds), | |
756 | WherePredicate::RegionPredicate { ref bounds, .. } => Some(bounds), | |
757 | _ => None, | |
758 | } | |
759 | } | |
760 | } | |
761 | ||
762 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
763 | pub enum GenericParamDefKind { | |
764 | Lifetime, | |
765 | Type { | |
766 | did: DefId, | |
767 | bounds: Vec<GenericBound>, | |
768 | default: Option<Type>, | |
769 | synthetic: Option<hir::SyntheticTyParamKind>, | |
770 | }, | |
771 | Const { | |
772 | did: DefId, | |
773 | ty: Type, | |
774 | }, | |
775 | } | |
776 | ||
777 | impl GenericParamDefKind { | |
778 | pub fn is_type(&self) -> bool { | |
779 | match *self { | |
780 | GenericParamDefKind::Type { .. } => true, | |
781 | _ => false, | |
782 | } | |
783 | } | |
784 | ||
785 | // FIXME(eddyb) this either returns the default of a type parameter, or the | |
786 | // type of a `const` parameter. It seems that the intention is to *visit* | |
787 | // any embedded types, but `get_type` seems to be the wrong name for that. | |
788 | pub fn get_type(&self) -> Option<Type> { | |
789 | match self { | |
790 | GenericParamDefKind::Type { default, .. } => default.clone(), | |
791 | GenericParamDefKind::Const { ty, .. } => Some(ty.clone()), | |
792 | GenericParamDefKind::Lifetime => None, | |
793 | } | |
794 | } | |
795 | } | |
796 | ||
797 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
798 | pub struct GenericParamDef { | |
799 | pub name: String, | |
800 | pub kind: GenericParamDefKind, | |
801 | } | |
802 | ||
803 | impl GenericParamDef { | |
804 | pub fn is_synthetic_type_param(&self) -> bool { | |
805 | match self.kind { | |
dfeec247 | 806 | GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => false, |
60c5eb7d XL |
807 | GenericParamDefKind::Type { ref synthetic, .. } => synthetic.is_some(), |
808 | } | |
809 | } | |
810 | ||
811 | pub fn is_type(&self) -> bool { | |
812 | self.kind.is_type() | |
813 | } | |
814 | ||
815 | pub fn get_type(&self) -> Option<Type> { | |
816 | self.kind.get_type() | |
817 | } | |
818 | ||
819 | pub fn get_bounds(&self) -> Option<&[GenericBound]> { | |
820 | match self.kind { | |
821 | GenericParamDefKind::Type { ref bounds, .. } => Some(bounds), | |
822 | _ => None, | |
823 | } | |
824 | } | |
825 | } | |
826 | ||
827 | // maybe use a Generic enum and use Vec<Generic>? | |
828 | #[derive(Clone, Debug, Default)] | |
829 | pub struct Generics { | |
830 | pub params: Vec<GenericParamDef>, | |
831 | pub where_predicates: Vec<WherePredicate>, | |
832 | } | |
833 | ||
834 | #[derive(Clone, Debug)] | |
835 | pub struct Method { | |
836 | pub generics: Generics, | |
837 | pub decl: FnDecl, | |
838 | pub header: hir::FnHeader, | |
839 | pub defaultness: Option<hir::Defaultness>, | |
840 | pub all_types: Vec<Type>, | |
841 | pub ret_types: Vec<Type>, | |
842 | } | |
843 | ||
844 | #[derive(Clone, Debug)] | |
845 | pub struct TyMethod { | |
846 | pub header: hir::FnHeader, | |
847 | pub decl: FnDecl, | |
848 | pub generics: Generics, | |
849 | pub all_types: Vec<Type>, | |
850 | pub ret_types: Vec<Type>, | |
851 | } | |
852 | ||
853 | #[derive(Clone, Debug)] | |
854 | pub struct Function { | |
855 | pub decl: FnDecl, | |
856 | pub generics: Generics, | |
857 | pub header: hir::FnHeader, | |
858 | pub all_types: Vec<Type>, | |
859 | pub ret_types: Vec<Type>, | |
860 | } | |
861 | ||
862 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
863 | pub struct FnDecl { | |
864 | pub inputs: Arguments, | |
865 | pub output: FunctionRetTy, | |
866 | pub c_variadic: bool, | |
867 | pub attrs: Attributes, | |
868 | } | |
869 | ||
870 | impl FnDecl { | |
871 | pub fn self_type(&self) -> Option<SelfTy> { | |
872 | self.inputs.values.get(0).and_then(|v| v.to_self()) | |
873 | } | |
874 | ||
875 | /// Returns the sugared return type for an async function. | |
876 | /// | |
877 | /// For example, if the return type is `impl std::future::Future<Output = i32>`, this function | |
878 | /// will return `i32`. | |
879 | /// | |
880 | /// # Panics | |
881 | /// | |
882 | /// This function will panic if the return type does not match the expected sugaring for async | |
883 | /// functions. | |
884 | pub fn sugared_async_return_type(&self) -> FunctionRetTy { | |
885 | match &self.output { | |
dfeec247 XL |
886 | FunctionRetTy::Return(Type::ImplTrait(bounds)) => match &bounds[0] { |
887 | GenericBound::TraitBound(PolyTrait { trait_, .. }, ..) => { | |
888 | let bindings = trait_.bindings().unwrap(); | |
889 | FunctionRetTy::Return(bindings[0].ty().clone()) | |
60c5eb7d | 890 | } |
dfeec247 XL |
891 | _ => panic!("unexpected desugaring of async function"), |
892 | }, | |
60c5eb7d XL |
893 | _ => panic!("unexpected desugaring of async function"), |
894 | } | |
895 | } | |
896 | } | |
897 | ||
898 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
899 | pub struct Arguments { | |
900 | pub values: Vec<Argument>, | |
901 | } | |
902 | ||
903 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
904 | pub struct Argument { | |
905 | pub type_: Type, | |
906 | pub name: String, | |
907 | } | |
908 | ||
909 | #[derive(Clone, PartialEq, Debug)] | |
910 | pub enum SelfTy { | |
911 | SelfValue, | |
912 | SelfBorrowed(Option<Lifetime>, Mutability), | |
913 | SelfExplicit(Type), | |
914 | } | |
915 | ||
916 | impl Argument { | |
917 | pub fn to_self(&self) -> Option<SelfTy> { | |
918 | if self.name != "self" { | |
919 | return None; | |
920 | } | |
921 | if self.type_.is_self_type() { | |
922 | return Some(SelfValue); | |
923 | } | |
924 | match self.type_ { | |
dfeec247 | 925 | BorrowedRef { ref lifetime, mutability, ref type_ } if type_.is_self_type() => { |
60c5eb7d XL |
926 | Some(SelfBorrowed(lifetime.clone(), mutability)) |
927 | } | |
dfeec247 | 928 | _ => Some(SelfExplicit(self.type_.clone())), |
60c5eb7d XL |
929 | } |
930 | } | |
931 | } | |
932 | ||
933 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
934 | pub enum FunctionRetTy { | |
935 | Return(Type), | |
936 | DefaultReturn, | |
937 | } | |
938 | ||
939 | impl GetDefId for FunctionRetTy { | |
940 | fn def_id(&self) -> Option<DefId> { | |
941 | match *self { | |
942 | Return(ref ty) => ty.def_id(), | |
943 | DefaultReturn => None, | |
944 | } | |
945 | } | |
946 | } | |
947 | ||
948 | #[derive(Clone, Debug)] | |
949 | pub struct Trait { | |
950 | pub auto: bool, | |
951 | pub unsafety: hir::Unsafety, | |
952 | pub items: Vec<Item>, | |
953 | pub generics: Generics, | |
954 | pub bounds: Vec<GenericBound>, | |
955 | pub is_spotlight: bool, | |
956 | pub is_auto: bool, | |
957 | } | |
958 | ||
959 | #[derive(Clone, Debug)] | |
960 | pub struct TraitAlias { | |
961 | pub generics: Generics, | |
962 | pub bounds: Vec<GenericBound>, | |
963 | } | |
964 | ||
965 | /// A trait reference, which may have higher ranked lifetimes. | |
966 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
967 | pub struct PolyTrait { | |
968 | pub trait_: Type, | |
969 | pub generic_params: Vec<GenericParamDef>, | |
970 | } | |
971 | ||
972 | /// A representation of a type suitable for hyperlinking purposes. Ideally, one can get the original | |
973 | /// type out of the AST/`TyCtxt` given one of these, if more information is needed. Most | |
974 | /// importantly, it does not preserve mutability or boxes. | |
975 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
976 | pub enum Type { | |
977 | /// Structs/enums/traits (most that would be an `hir::TyKind::Path`). | |
978 | ResolvedPath { | |
979 | path: Path, | |
980 | param_names: Option<Vec<GenericBound>>, | |
981 | did: DefId, | |
982 | /// `true` if is a `T::Name` path for associated types. | |
983 | is_generic: bool, | |
984 | }, | |
985 | /// For parameterized types, so the consumer of the JSON don't go | |
986 | /// looking for types which don't exist anywhere. | |
987 | Generic(String), | |
988 | /// Primitives are the fixed-size numeric types (plus int/usize/float), char, | |
989 | /// arrays, slices, and tuples. | |
990 | Primitive(PrimitiveType), | |
991 | /// `extern "ABI" fn` | |
992 | BareFunction(Box<BareFunctionDecl>), | |
993 | Tuple(Vec<Type>), | |
994 | Slice(Box<Type>), | |
995 | Array(Box<Type>, String), | |
996 | Never, | |
997 | RawPointer(Mutability, Box<Type>), | |
998 | BorrowedRef { | |
999 | lifetime: Option<Lifetime>, | |
1000 | mutability: Mutability, | |
1001 | type_: Box<Type>, | |
1002 | }, | |
1003 | ||
1004 | // `<Type as Trait>::Name` | |
1005 | QPath { | |
1006 | name: String, | |
1007 | self_type: Box<Type>, | |
dfeec247 | 1008 | trait_: Box<Type>, |
60c5eb7d XL |
1009 | }, |
1010 | ||
1011 | // `_` | |
1012 | Infer, | |
1013 | ||
1014 | // `impl TraitA + TraitB + ...` | |
1015 | ImplTrait(Vec<GenericBound>), | |
1016 | } | |
1017 | ||
1018 | #[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)] | |
1019 | pub enum PrimitiveType { | |
dfeec247 XL |
1020 | Isize, |
1021 | I8, | |
1022 | I16, | |
1023 | I32, | |
1024 | I64, | |
1025 | I128, | |
1026 | Usize, | |
1027 | U8, | |
1028 | U16, | |
1029 | U32, | |
1030 | U64, | |
1031 | U128, | |
1032 | F32, | |
1033 | F64, | |
60c5eb7d XL |
1034 | Char, |
1035 | Bool, | |
1036 | Str, | |
1037 | Slice, | |
1038 | Array, | |
1039 | Tuple, | |
1040 | Unit, | |
1041 | RawPointer, | |
1042 | Reference, | |
1043 | Fn, | |
1044 | Never, | |
1045 | } | |
1046 | ||
1047 | #[derive(Clone, Copy, Debug)] | |
1048 | pub enum TypeKind { | |
1049 | Enum, | |
1050 | Function, | |
1051 | Module, | |
1052 | Const, | |
1053 | Static, | |
1054 | Struct, | |
1055 | Union, | |
1056 | Trait, | |
1057 | Typedef, | |
1058 | Foreign, | |
1059 | Macro, | |
1060 | Attr, | |
1061 | Derive, | |
1062 | TraitAlias, | |
1063 | } | |
1064 | ||
1065 | pub trait GetDefId { | |
1066 | fn def_id(&self) -> Option<DefId>; | |
1067 | } | |
1068 | ||
1069 | impl<T: GetDefId> GetDefId for Option<T> { | |
1070 | fn def_id(&self) -> Option<DefId> { | |
1071 | self.as_ref().and_then(|d| d.def_id()) | |
1072 | } | |
1073 | } | |
1074 | ||
1075 | impl Type { | |
1076 | pub fn primitive_type(&self) -> Option<PrimitiveType> { | |
1077 | match *self { | |
dfeec247 | 1078 | Primitive(p) | BorrowedRef { type_: box Primitive(p), .. } => Some(p), |
60c5eb7d XL |
1079 | Slice(..) | BorrowedRef { type_: box Slice(..), .. } => Some(PrimitiveType::Slice), |
1080 | Array(..) | BorrowedRef { type_: box Array(..), .. } => Some(PrimitiveType::Array), | |
dfeec247 XL |
1081 | Tuple(ref tys) => { |
1082 | if tys.is_empty() { | |
1083 | Some(PrimitiveType::Unit) | |
1084 | } else { | |
1085 | Some(PrimitiveType::Tuple) | |
1086 | } | |
1087 | } | |
60c5eb7d XL |
1088 | RawPointer(..) => Some(PrimitiveType::RawPointer), |
1089 | BorrowedRef { type_: box Generic(..), .. } => Some(PrimitiveType::Reference), | |
1090 | BareFunction(..) => Some(PrimitiveType::Fn), | |
1091 | Never => Some(PrimitiveType::Never), | |
1092 | _ => None, | |
1093 | } | |
1094 | } | |
1095 | ||
1096 | pub fn is_generic(&self) -> bool { | |
1097 | match *self { | |
1098 | ResolvedPath { is_generic, .. } => is_generic, | |
1099 | _ => false, | |
1100 | } | |
1101 | } | |
1102 | ||
1103 | pub fn is_self_type(&self) -> bool { | |
1104 | match *self { | |
1105 | Generic(ref name) => name == "Self", | |
dfeec247 | 1106 | _ => false, |
60c5eb7d XL |
1107 | } |
1108 | } | |
1109 | ||
1110 | pub fn generics(&self) -> Option<Vec<Type>> { | |
1111 | match *self { | |
dfeec247 XL |
1112 | ResolvedPath { ref path, .. } => path.segments.last().and_then(|seg| { |
1113 | if let GenericArgs::AngleBracketed { ref args, .. } = seg.args { | |
1114 | Some( | |
1115 | args.iter() | |
1116 | .filter_map(|arg| match arg { | |
1117 | GenericArg::Type(ty) => Some(ty.clone()), | |
1118 | _ => None, | |
1119 | }) | |
1120 | .collect(), | |
1121 | ) | |
1122 | } else { | |
1123 | None | |
1124 | } | |
1125 | }), | |
60c5eb7d XL |
1126 | _ => None, |
1127 | } | |
1128 | } | |
1129 | ||
1130 | pub fn bindings(&self) -> Option<&[TypeBinding]> { | |
1131 | match *self { | |
dfeec247 XL |
1132 | ResolvedPath { ref path, .. } => path.segments.last().and_then(|seg| { |
1133 | if let GenericArgs::AngleBracketed { ref bindings, .. } = seg.args { | |
1134 | Some(&**bindings) | |
1135 | } else { | |
1136 | None | |
1137 | } | |
1138 | }), | |
1139 | _ => None, | |
60c5eb7d XL |
1140 | } |
1141 | } | |
1142 | ||
1143 | pub fn is_full_generic(&self) -> bool { | |
1144 | match *self { | |
1145 | Type::Generic(_) => true, | |
1146 | _ => false, | |
1147 | } | |
1148 | } | |
1149 | ||
1150 | pub fn projection(&self) -> Option<(&Type, DefId, &str)> { | |
1151 | let (self_, trait_, name) = match self { | |
dfeec247 | 1152 | QPath { ref self_type, ref trait_, ref name } => (self_type, trait_, name), |
60c5eb7d XL |
1153 | _ => return None, |
1154 | }; | |
1155 | let trait_did = match **trait_ { | |
1156 | ResolvedPath { did, .. } => did, | |
1157 | _ => return None, | |
1158 | }; | |
1159 | Some((&self_, trait_did, name)) | |
1160 | } | |
60c5eb7d XL |
1161 | } |
1162 | ||
1163 | impl GetDefId for Type { | |
1164 | fn def_id(&self) -> Option<DefId> { | |
1165 | match *self { | |
1166 | ResolvedPath { did, .. } => Some(did), | |
1167 | Primitive(p) => crate::html::render::cache().primitive_locations.get(&p).cloned(), | |
dfeec247 XL |
1168 | BorrowedRef { type_: box Generic(..), .. } => { |
1169 | Primitive(PrimitiveType::Reference).def_id() | |
1170 | } | |
60c5eb7d | 1171 | BorrowedRef { ref type_, .. } => type_.def_id(), |
dfeec247 XL |
1172 | Tuple(ref tys) => { |
1173 | if tys.is_empty() { | |
1174 | Primitive(PrimitiveType::Unit).def_id() | |
1175 | } else { | |
1176 | Primitive(PrimitiveType::Tuple).def_id() | |
1177 | } | |
1178 | } | |
60c5eb7d XL |
1179 | BareFunction(..) => Primitive(PrimitiveType::Fn).def_id(), |
1180 | Never => Primitive(PrimitiveType::Never).def_id(), | |
1181 | Slice(..) => Primitive(PrimitiveType::Slice).def_id(), | |
1182 | Array(..) => Primitive(PrimitiveType::Array).def_id(), | |
1183 | RawPointer(..) => Primitive(PrimitiveType::RawPointer).def_id(), | |
1184 | QPath { ref self_type, .. } => self_type.def_id(), | |
1185 | _ => None, | |
1186 | } | |
1187 | } | |
1188 | } | |
1189 | ||
1190 | impl PrimitiveType { | |
1191 | pub fn from_str(s: &str) -> Option<PrimitiveType> { | |
1192 | match s { | |
1193 | "isize" => Some(PrimitiveType::Isize), | |
1194 | "i8" => Some(PrimitiveType::I8), | |
1195 | "i16" => Some(PrimitiveType::I16), | |
1196 | "i32" => Some(PrimitiveType::I32), | |
1197 | "i64" => Some(PrimitiveType::I64), | |
1198 | "i128" => Some(PrimitiveType::I128), | |
1199 | "usize" => Some(PrimitiveType::Usize), | |
1200 | "u8" => Some(PrimitiveType::U8), | |
1201 | "u16" => Some(PrimitiveType::U16), | |
1202 | "u32" => Some(PrimitiveType::U32), | |
1203 | "u64" => Some(PrimitiveType::U64), | |
1204 | "u128" => Some(PrimitiveType::U128), | |
1205 | "bool" => Some(PrimitiveType::Bool), | |
1206 | "char" => Some(PrimitiveType::Char), | |
1207 | "str" => Some(PrimitiveType::Str), | |
1208 | "f32" => Some(PrimitiveType::F32), | |
1209 | "f64" => Some(PrimitiveType::F64), | |
1210 | "array" => Some(PrimitiveType::Array), | |
1211 | "slice" => Some(PrimitiveType::Slice), | |
1212 | "tuple" => Some(PrimitiveType::Tuple), | |
1213 | "unit" => Some(PrimitiveType::Unit), | |
1214 | "pointer" => Some(PrimitiveType::RawPointer), | |
1215 | "reference" => Some(PrimitiveType::Reference), | |
1216 | "fn" => Some(PrimitiveType::Fn), | |
1217 | "never" => Some(PrimitiveType::Never), | |
1218 | _ => None, | |
1219 | } | |
1220 | } | |
1221 | ||
1222 | pub fn as_str(&self) -> &'static str { | |
1223 | use self::PrimitiveType::*; | |
1224 | match *self { | |
1225 | Isize => "isize", | |
1226 | I8 => "i8", | |
1227 | I16 => "i16", | |
1228 | I32 => "i32", | |
1229 | I64 => "i64", | |
1230 | I128 => "i128", | |
1231 | Usize => "usize", | |
1232 | U8 => "u8", | |
1233 | U16 => "u16", | |
1234 | U32 => "u32", | |
1235 | U64 => "u64", | |
1236 | U128 => "u128", | |
1237 | F32 => "f32", | |
1238 | F64 => "f64", | |
1239 | Str => "str", | |
1240 | Bool => "bool", | |
1241 | Char => "char", | |
1242 | Array => "array", | |
1243 | Slice => "slice", | |
1244 | Tuple => "tuple", | |
1245 | Unit => "unit", | |
1246 | RawPointer => "pointer", | |
1247 | Reference => "reference", | |
1248 | Fn => "fn", | |
1249 | Never => "never", | |
1250 | } | |
1251 | } | |
1252 | ||
1253 | pub fn to_url_str(&self) -> &'static str { | |
1254 | self.as_str() | |
1255 | } | |
1256 | } | |
1257 | ||
1258 | impl From<ast::IntTy> for PrimitiveType { | |
1259 | fn from(int_ty: ast::IntTy) -> PrimitiveType { | |
1260 | match int_ty { | |
1261 | ast::IntTy::Isize => PrimitiveType::Isize, | |
1262 | ast::IntTy::I8 => PrimitiveType::I8, | |
1263 | ast::IntTy::I16 => PrimitiveType::I16, | |
1264 | ast::IntTy::I32 => PrimitiveType::I32, | |
1265 | ast::IntTy::I64 => PrimitiveType::I64, | |
1266 | ast::IntTy::I128 => PrimitiveType::I128, | |
1267 | } | |
1268 | } | |
1269 | } | |
1270 | ||
1271 | impl From<ast::UintTy> for PrimitiveType { | |
1272 | fn from(uint_ty: ast::UintTy) -> PrimitiveType { | |
1273 | match uint_ty { | |
1274 | ast::UintTy::Usize => PrimitiveType::Usize, | |
1275 | ast::UintTy::U8 => PrimitiveType::U8, | |
1276 | ast::UintTy::U16 => PrimitiveType::U16, | |
1277 | ast::UintTy::U32 => PrimitiveType::U32, | |
1278 | ast::UintTy::U64 => PrimitiveType::U64, | |
1279 | ast::UintTy::U128 => PrimitiveType::U128, | |
1280 | } | |
1281 | } | |
1282 | } | |
1283 | ||
1284 | impl From<ast::FloatTy> for PrimitiveType { | |
1285 | fn from(float_ty: ast::FloatTy) -> PrimitiveType { | |
1286 | match float_ty { | |
1287 | ast::FloatTy::F32 => PrimitiveType::F32, | |
1288 | ast::FloatTy::F64 => PrimitiveType::F64, | |
1289 | } | |
1290 | } | |
1291 | } | |
1292 | ||
1293 | #[derive(Clone, PartialEq, Eq, Debug)] | |
1294 | pub enum Visibility { | |
1295 | Public, | |
1296 | Inherited, | |
1297 | Crate, | |
1298 | Restricted(DefId, Path), | |
1299 | } | |
1300 | ||
1301 | #[derive(Clone, Debug)] | |
1302 | pub struct Struct { | |
1303 | pub struct_type: doctree::StructType, | |
1304 | pub generics: Generics, | |
1305 | pub fields: Vec<Item>, | |
1306 | pub fields_stripped: bool, | |
1307 | } | |
1308 | ||
1309 | #[derive(Clone, Debug)] | |
1310 | pub struct Union { | |
1311 | pub struct_type: doctree::StructType, | |
1312 | pub generics: Generics, | |
1313 | pub fields: Vec<Item>, | |
1314 | pub fields_stripped: bool, | |
1315 | } | |
1316 | ||
1317 | /// This is a more limited form of the standard Struct, different in that | |
1318 | /// it lacks the things most items have (name, id, parameterization). Found | |
1319 | /// only as a variant in an enum. | |
1320 | #[derive(Clone, Debug)] | |
1321 | pub struct VariantStruct { | |
1322 | pub struct_type: doctree::StructType, | |
1323 | pub fields: Vec<Item>, | |
1324 | pub fields_stripped: bool, | |
1325 | } | |
1326 | ||
1327 | #[derive(Clone, Debug)] | |
1328 | pub struct Enum { | |
1329 | pub variants: IndexVec<VariantIdx, Item>, | |
1330 | pub generics: Generics, | |
1331 | pub variants_stripped: bool, | |
1332 | } | |
1333 | ||
1334 | #[derive(Clone, Debug)] | |
1335 | pub struct Variant { | |
1336 | pub kind: VariantKind, | |
1337 | } | |
1338 | ||
1339 | #[derive(Clone, Debug)] | |
1340 | pub enum VariantKind { | |
1341 | CLike, | |
1342 | Tuple(Vec<Type>), | |
1343 | Struct(VariantStruct), | |
1344 | } | |
1345 | ||
1346 | #[derive(Clone, Debug)] | |
1347 | pub struct Span { | |
1348 | pub filename: FileName, | |
1349 | pub loline: usize, | |
1350 | pub locol: usize, | |
1351 | pub hiline: usize, | |
1352 | pub hicol: usize, | |
dfeec247 | 1353 | pub original: rustc_span::Span, |
60c5eb7d XL |
1354 | } |
1355 | ||
1356 | impl Span { | |
1357 | pub fn empty() -> Span { | |
1358 | Span { | |
1359 | filename: FileName::Anon(0), | |
dfeec247 XL |
1360 | loline: 0, |
1361 | locol: 0, | |
1362 | hiline: 0, | |
1363 | hicol: 0, | |
1364 | original: rustc_span::DUMMY_SP, | |
60c5eb7d XL |
1365 | } |
1366 | } | |
1367 | ||
dfeec247 | 1368 | pub fn span(&self) -> rustc_span::Span { |
60c5eb7d XL |
1369 | self.original |
1370 | } | |
1371 | } | |
1372 | ||
1373 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
1374 | pub struct Path { | |
1375 | pub global: bool, | |
1376 | pub res: Res, | |
1377 | pub segments: Vec<PathSegment>, | |
1378 | } | |
1379 | ||
1380 | impl Path { | |
1381 | pub fn last_name(&self) -> &str { | |
1382 | self.segments.last().expect("segments were empty").name.as_str() | |
1383 | } | |
1384 | } | |
1385 | ||
1386 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
1387 | pub enum GenericArg { | |
1388 | Lifetime(Lifetime), | |
1389 | Type(Type), | |
1390 | Const(Constant), | |
1391 | } | |
1392 | ||
1393 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
1394 | pub enum GenericArgs { | |
dfeec247 XL |
1395 | AngleBracketed { args: Vec<GenericArg>, bindings: Vec<TypeBinding> }, |
1396 | Parenthesized { inputs: Vec<Type>, output: Option<Type> }, | |
60c5eb7d XL |
1397 | } |
1398 | ||
1399 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
1400 | pub struct PathSegment { | |
1401 | pub name: String, | |
1402 | pub args: GenericArgs, | |
1403 | } | |
1404 | ||
1405 | #[derive(Clone, Debug)] | |
1406 | pub struct Typedef { | |
1407 | pub type_: Type, | |
1408 | pub generics: Generics, | |
dfeec247 XL |
1409 | // Type of target item. |
1410 | pub item_type: Option<Type>, | |
1411 | } | |
1412 | ||
1413 | impl GetDefId for Typedef { | |
1414 | fn def_id(&self) -> Option<DefId> { | |
1415 | self.type_.def_id() | |
1416 | } | |
60c5eb7d XL |
1417 | } |
1418 | ||
1419 | #[derive(Clone, Debug)] | |
1420 | pub struct OpaqueTy { | |
1421 | pub bounds: Vec<GenericBound>, | |
1422 | pub generics: Generics, | |
1423 | } | |
1424 | ||
1425 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
1426 | pub struct BareFunctionDecl { | |
1427 | pub unsafety: hir::Unsafety, | |
1428 | pub generic_params: Vec<GenericParamDef>, | |
1429 | pub decl: FnDecl, | |
1430 | pub abi: Abi, | |
1431 | } | |
1432 | ||
1433 | #[derive(Clone, Debug)] | |
1434 | pub struct Static { | |
1435 | pub type_: Type, | |
1436 | pub mutability: Mutability, | |
1437 | /// It's useful to have the value of a static documented, but I have no | |
1438 | /// desire to represent expressions (that'd basically be all of the AST, | |
1439 | /// which is huge!). So, have a string. | |
1440 | pub expr: String, | |
1441 | } | |
1442 | ||
1443 | #[derive(Clone, PartialEq, Eq, Hash, Debug)] | |
1444 | pub struct Constant { | |
1445 | pub type_: Type, | |
1446 | pub expr: String, | |
dfeec247 XL |
1447 | pub value: Option<String>, |
1448 | pub is_literal: bool, | |
60c5eb7d XL |
1449 | } |
1450 | ||
1451 | #[derive(Clone, PartialEq, Debug)] | |
1452 | pub enum ImplPolarity { | |
1453 | Positive, | |
1454 | Negative, | |
1455 | } | |
1456 | ||
1457 | #[derive(Clone, Debug)] | |
1458 | pub struct Impl { | |
1459 | pub unsafety: hir::Unsafety, | |
1460 | pub generics: Generics, | |
1461 | pub provided_trait_methods: FxHashSet<String>, | |
1462 | pub trait_: Option<Type>, | |
1463 | pub for_: Type, | |
1464 | pub items: Vec<Item>, | |
1465 | pub polarity: Option<ImplPolarity>, | |
1466 | pub synthetic: bool, | |
1467 | pub blanket_impl: Option<Type>, | |
1468 | } | |
1469 | ||
1470 | #[derive(Clone, Debug)] | |
1471 | pub enum Import { | |
1472 | // use source as str; | |
1473 | Simple(String, ImportSource), | |
1474 | // use source::*; | |
dfeec247 | 1475 | Glob(ImportSource), |
60c5eb7d XL |
1476 | } |
1477 | ||
1478 | #[derive(Clone, Debug)] | |
1479 | pub struct ImportSource { | |
1480 | pub path: Path, | |
1481 | pub did: Option<DefId>, | |
1482 | } | |
1483 | ||
1484 | #[derive(Clone, Debug)] | |
1485 | pub struct Macro { | |
1486 | pub source: String, | |
1487 | pub imported_from: Option<String>, | |
1488 | } | |
1489 | ||
1490 | #[derive(Clone, Debug)] | |
1491 | pub struct ProcMacro { | |
1492 | pub kind: MacroKind, | |
1493 | pub helpers: Vec<String>, | |
1494 | } | |
1495 | ||
1496 | #[derive(Clone, Debug)] | |
1497 | pub struct Stability { | |
1498 | pub level: stability::StabilityLevel, | |
1499 | pub feature: Option<String>, | |
1500 | pub since: String, | |
1501 | pub deprecation: Option<Deprecation>, | |
1502 | pub unstable_reason: Option<String>, | |
1503 | pub issue: Option<NonZeroU32>, | |
1504 | } | |
1505 | ||
1506 | #[derive(Clone, Debug)] | |
1507 | pub struct Deprecation { | |
1508 | pub since: Option<String>, | |
1509 | pub note: Option<String>, | |
1510 | } | |
1511 | ||
1512 | /// An type binding on an associated type (e.g., `A = Bar` in `Foo<A = Bar>` or | |
1513 | /// `A: Send + Sync` in `Foo<A: Send + Sync>`). | |
1514 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
1515 | pub struct TypeBinding { | |
1516 | pub name: String, | |
1517 | pub kind: TypeBindingKind, | |
1518 | } | |
1519 | ||
1520 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
1521 | pub enum TypeBindingKind { | |
dfeec247 XL |
1522 | Equality { ty: Type }, |
1523 | Constraint { bounds: Vec<GenericBound> }, | |
60c5eb7d XL |
1524 | } |
1525 | ||
1526 | impl TypeBinding { | |
1527 | pub fn ty(&self) -> &Type { | |
1528 | match self.kind { | |
1529 | TypeBindingKind::Equality { ref ty } => ty, | |
1530 | _ => panic!("expected equality type binding for parenthesized generic args"), | |
1531 | } | |
1532 | } | |
1533 | } |