]>
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 | 10 | |
74b04a01 XL |
11 | use rustc_ast::ast::{self, AttrStyle, Ident}; |
12 | use rustc_ast::attr; | |
13 | use rustc_ast::util::comments::strip_doc_comment_decoration; | |
dfeec247 XL |
14 | use rustc_data_structures::fx::{FxHashMap, FxHashSet}; |
15 | use rustc_hir as hir; | |
16 | use rustc_hir::def::Res; | |
ba9703b0 XL |
17 | use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; |
18 | use rustc_hir::lang_items; | |
dfeec247 | 19 | use rustc_hir::Mutability; |
60c5eb7d | 20 | use rustc_index::vec::IndexVec; |
ba9703b0 | 21 | use rustc_middle::middle::stability; |
dfeec247 XL |
22 | use rustc_span::hygiene::MacroKind; |
23 | use rustc_span::source_map::DUMMY_SP; | |
24 | use rustc_span::symbol::{sym, Symbol}; | |
25 | use rustc_span::{self, FileName}; | |
ba9703b0 | 26 | use rustc_target::abi::VariantIdx; |
60c5eb7d | 27 | use rustc_target::spec::abi::Abi; |
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 | ||
74b04a01 | 38 | use self::FnRetTy::*; |
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 | ||
74b04a01 | 204 | if !classes.is_empty() { 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> { | |
74b04a01 | 424 | use rustc_ast::ast::NestedMetaItem::MetaItem; |
60c5eb7d XL |
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() | |
74b04a01 | 568 | .find(|a| a.doc_str().is_some()) |
dfeec247 | 569 | .map_or(true, |a| a.style == AttrStyle::Inner); |
60c5eb7d XL |
570 | |
571 | Attributes { | |
572 | doc_strings, | |
573 | other_attrs, | |
574 | cfg: if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) }, | |
575 | span: sp, | |
576 | links: vec![], | |
577 | inner_docs, | |
578 | } | |
579 | } | |
580 | ||
581 | /// Finds the `doc` attribute as a NameValue and returns the corresponding | |
582 | /// value found. | |
583 | pub fn doc_value(&self) -> Option<&str> { | |
584 | self.doc_strings.first().map(|s| s.as_str()) | |
585 | } | |
586 | ||
587 | /// Finds all `doc` attributes as NameValues and returns their corresponding values, joined | |
588 | /// with newlines. | |
589 | pub fn collapsed_doc_value(&self) -> Option<String> { | |
dfeec247 | 590 | if !self.doc_strings.is_empty() { Some(self.doc_strings.iter().collect()) } else { None } |
60c5eb7d XL |
591 | } |
592 | ||
593 | /// Gets links as a vector | |
594 | /// | |
595 | /// Cache must be populated before call | |
596 | pub fn links(&self, krate: &CrateNum) -> Vec<(String, String)> { | |
597 | use crate::html::format::href; | |
598 | ||
dfeec247 XL |
599 | self.links |
600 | .iter() | |
601 | .filter_map(|&(ref s, did, ref fragment)| { | |
602 | match did { | |
603 | Some(did) => { | |
604 | if let Some((mut href, ..)) = href(did) { | |
605 | if let Some(ref fragment) = *fragment { | |
606 | href.push_str("#"); | |
607 | href.push_str(fragment); | |
608 | } | |
609 | Some((s.clone(), href)) | |
610 | } else { | |
611 | None | |
60c5eb7d | 612 | } |
60c5eb7d | 613 | } |
dfeec247 XL |
614 | None => { |
615 | if let Some(ref fragment) = *fragment { | |
616 | let cache = cache(); | |
617 | let url = match cache.extern_locations.get(krate) { | |
618 | Some(&(_, ref src, ExternalLocation::Local)) => { | |
619 | src.to_str().expect("invalid file path") | |
620 | } | |
621 | Some(&(_, _, ExternalLocation::Remote(ref s))) => s, | |
622 | Some(&(_, _, ExternalLocation::Unknown)) | None => { | |
623 | "https://doc.rust-lang.org/nightly" | |
624 | } | |
625 | }; | |
626 | // This is a primitive so the url is done "by hand". | |
627 | let tail = fragment.find('#').unwrap_or_else(|| fragment.len()); | |
628 | Some(( | |
629 | s.clone(), | |
630 | format!( | |
631 | "{}{}std/primitive.{}.html{}", | |
632 | url, | |
633 | if !url.ends_with('/') { "/" } else { "" }, | |
634 | &fragment[..tail], | |
635 | &fragment[tail..] | |
636 | ), | |
637 | )) | |
638 | } else { | |
639 | panic!("This isn't a primitive?!"); | |
640 | } | |
60c5eb7d XL |
641 | } |
642 | } | |
dfeec247 XL |
643 | }) |
644 | .collect() | |
60c5eb7d XL |
645 | } |
646 | } | |
647 | ||
648 | impl PartialEq for Attributes { | |
649 | fn eq(&self, rhs: &Self) -> bool { | |
dfeec247 XL |
650 | self.doc_strings == rhs.doc_strings |
651 | && self.cfg == rhs.cfg | |
652 | && self.span == rhs.span | |
653 | && self.links == rhs.links | |
654 | && self | |
655 | .other_attrs | |
656 | .iter() | |
657 | .map(|attr| attr.id) | |
658 | .eq(rhs.other_attrs.iter().map(|attr| attr.id)) | |
60c5eb7d XL |
659 | } |
660 | } | |
661 | ||
662 | impl Eq for Attributes {} | |
663 | ||
664 | impl Hash for Attributes { | |
665 | fn hash<H: Hasher>(&self, hasher: &mut H) { | |
666 | self.doc_strings.hash(hasher); | |
667 | self.cfg.hash(hasher); | |
668 | self.span.hash(hasher); | |
669 | self.links.hash(hasher); | |
670 | for attr in &self.other_attrs { | |
671 | attr.id.hash(hasher); | |
672 | } | |
673 | } | |
674 | } | |
675 | ||
676 | impl AttributesExt for Attributes { | |
677 | fn lists(&self, name: Symbol) -> ListAttributesIter<'_> { | |
678 | self.other_attrs.lists(name) | |
679 | } | |
680 | } | |
681 | ||
682 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
683 | pub enum GenericBound { | |
684 | TraitBound(PolyTrait, hir::TraitBoundModifier), | |
685 | Outlives(Lifetime), | |
686 | } | |
687 | ||
688 | impl GenericBound { | |
689 | pub fn maybe_sized(cx: &DocContext<'_>) -> GenericBound { | |
690 | let did = cx.tcx.require_lang_item(lang_items::SizedTraitLangItem, None); | |
691 | let empty = cx.tcx.intern_substs(&[]); | |
dfeec247 | 692 | let path = external_path(cx, cx.tcx.item_name(did), Some(did), false, vec![], empty); |
60c5eb7d | 693 | inline::record_extern_fqn(cx, did, TypeKind::Trait); |
dfeec247 XL |
694 | GenericBound::TraitBound( |
695 | PolyTrait { | |
696 | trait_: ResolvedPath { path, param_names: None, did, is_generic: false }, | |
697 | generic_params: Vec::new(), | |
60c5eb7d | 698 | }, |
dfeec247 XL |
699 | hir::TraitBoundModifier::Maybe, |
700 | ) | |
60c5eb7d XL |
701 | } |
702 | ||
703 | pub fn is_sized_bound(&self, cx: &DocContext<'_>) -> bool { | |
dfeec247 | 704 | use rustc_hir::TraitBoundModifier as TBM; |
60c5eb7d XL |
705 | if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, TBM::None) = *self { |
706 | if trait_.def_id() == cx.tcx.lang_items().sized_trait() { | |
707 | return true; | |
708 | } | |
709 | } | |
710 | false | |
711 | } | |
712 | ||
713 | pub fn get_poly_trait(&self) -> Option<PolyTrait> { | |
714 | if let GenericBound::TraitBound(ref p, _) = *self { | |
dfeec247 | 715 | return Some(p.clone()); |
60c5eb7d XL |
716 | } |
717 | None | |
718 | } | |
719 | ||
720 | pub fn get_trait_type(&self) -> Option<Type> { | |
721 | if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, _) = *self { | |
722 | Some(trait_.clone()) | |
723 | } else { | |
724 | None | |
725 | } | |
726 | } | |
727 | } | |
728 | ||
729 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
730 | pub struct Lifetime(pub String); | |
731 | ||
732 | impl Lifetime { | |
733 | pub fn get_ref<'a>(&'a self) -> &'a str { | |
734 | let Lifetime(ref s) = *self; | |
735 | let s: &'a str = s; | |
736 | s | |
737 | } | |
738 | ||
739 | pub fn statik() -> Lifetime { | |
740 | Lifetime("'static".to_string()) | |
741 | } | |
742 | } | |
743 | ||
744 | #[derive(Clone, Debug)] | |
745 | pub enum WherePredicate { | |
746 | BoundPredicate { ty: Type, bounds: Vec<GenericBound> }, | |
747 | RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> }, | |
748 | EqPredicate { lhs: Type, rhs: Type }, | |
749 | } | |
750 | ||
751 | impl WherePredicate { | |
752 | pub fn get_bounds(&self) -> Option<&[GenericBound]> { | |
753 | match *self { | |
754 | WherePredicate::BoundPredicate { ref bounds, .. } => Some(bounds), | |
755 | WherePredicate::RegionPredicate { ref bounds, .. } => Some(bounds), | |
756 | _ => None, | |
757 | } | |
758 | } | |
759 | } | |
760 | ||
761 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
762 | pub enum GenericParamDefKind { | |
763 | Lifetime, | |
764 | Type { | |
765 | did: DefId, | |
766 | bounds: Vec<GenericBound>, | |
767 | default: Option<Type>, | |
768 | synthetic: Option<hir::SyntheticTyParamKind>, | |
769 | }, | |
770 | Const { | |
771 | did: DefId, | |
772 | ty: Type, | |
773 | }, | |
774 | } | |
775 | ||
776 | impl GenericParamDefKind { | |
777 | pub fn is_type(&self) -> bool { | |
778 | match *self { | |
779 | GenericParamDefKind::Type { .. } => true, | |
780 | _ => false, | |
781 | } | |
782 | } | |
783 | ||
784 | // FIXME(eddyb) this either returns the default of a type parameter, or the | |
785 | // type of a `const` parameter. It seems that the intention is to *visit* | |
786 | // any embedded types, but `get_type` seems to be the wrong name for that. | |
787 | pub fn get_type(&self) -> Option<Type> { | |
788 | match self { | |
789 | GenericParamDefKind::Type { default, .. } => default.clone(), | |
790 | GenericParamDefKind::Const { ty, .. } => Some(ty.clone()), | |
791 | GenericParamDefKind::Lifetime => None, | |
792 | } | |
793 | } | |
794 | } | |
795 | ||
796 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
797 | pub struct GenericParamDef { | |
798 | pub name: String, | |
799 | pub kind: GenericParamDefKind, | |
800 | } | |
801 | ||
802 | impl GenericParamDef { | |
803 | pub fn is_synthetic_type_param(&self) -> bool { | |
804 | match self.kind { | |
dfeec247 | 805 | GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => false, |
60c5eb7d XL |
806 | GenericParamDefKind::Type { ref synthetic, .. } => synthetic.is_some(), |
807 | } | |
808 | } | |
809 | ||
810 | pub fn is_type(&self) -> bool { | |
811 | self.kind.is_type() | |
812 | } | |
813 | ||
814 | pub fn get_type(&self) -> Option<Type> { | |
815 | self.kind.get_type() | |
816 | } | |
817 | ||
818 | pub fn get_bounds(&self) -> Option<&[GenericBound]> { | |
819 | match self.kind { | |
820 | GenericParamDefKind::Type { ref bounds, .. } => Some(bounds), | |
821 | _ => None, | |
822 | } | |
823 | } | |
824 | } | |
825 | ||
826 | // maybe use a Generic enum and use Vec<Generic>? | |
827 | #[derive(Clone, Debug, Default)] | |
828 | pub struct Generics { | |
829 | pub params: Vec<GenericParamDef>, | |
830 | pub where_predicates: Vec<WherePredicate>, | |
831 | } | |
832 | ||
833 | #[derive(Clone, Debug)] | |
834 | pub struct Method { | |
835 | pub generics: Generics, | |
836 | pub decl: FnDecl, | |
837 | pub header: hir::FnHeader, | |
838 | pub defaultness: Option<hir::Defaultness>, | |
ba9703b0 XL |
839 | pub all_types: Vec<(Type, TypeKind)>, |
840 | pub ret_types: Vec<(Type, TypeKind)>, | |
60c5eb7d XL |
841 | } |
842 | ||
843 | #[derive(Clone, Debug)] | |
844 | pub struct TyMethod { | |
845 | pub header: hir::FnHeader, | |
846 | pub decl: FnDecl, | |
847 | pub generics: Generics, | |
ba9703b0 XL |
848 | pub all_types: Vec<(Type, TypeKind)>, |
849 | pub ret_types: Vec<(Type, TypeKind)>, | |
60c5eb7d XL |
850 | } |
851 | ||
852 | #[derive(Clone, Debug)] | |
853 | pub struct Function { | |
854 | pub decl: FnDecl, | |
855 | pub generics: Generics, | |
856 | pub header: hir::FnHeader, | |
ba9703b0 XL |
857 | pub all_types: Vec<(Type, TypeKind)>, |
858 | pub ret_types: Vec<(Type, TypeKind)>, | |
60c5eb7d XL |
859 | } |
860 | ||
861 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
862 | pub struct FnDecl { | |
863 | pub inputs: Arguments, | |
74b04a01 | 864 | pub output: FnRetTy, |
60c5eb7d XL |
865 | pub c_variadic: bool, |
866 | pub attrs: Attributes, | |
867 | } | |
868 | ||
869 | impl FnDecl { | |
870 | pub fn self_type(&self) -> Option<SelfTy> { | |
871 | self.inputs.values.get(0).and_then(|v| v.to_self()) | |
872 | } | |
873 | ||
874 | /// Returns the sugared return type for an async function. | |
875 | /// | |
876 | /// For example, if the return type is `impl std::future::Future<Output = i32>`, this function | |
877 | /// will return `i32`. | |
878 | /// | |
879 | /// # Panics | |
880 | /// | |
881 | /// This function will panic if the return type does not match the expected sugaring for async | |
882 | /// functions. | |
74b04a01 | 883 | pub fn sugared_async_return_type(&self) -> FnRetTy { |
60c5eb7d | 884 | match &self.output { |
74b04a01 | 885 | FnRetTy::Return(Type::ImplTrait(bounds)) => match &bounds[0] { |
dfeec247 XL |
886 | GenericBound::TraitBound(PolyTrait { trait_, .. }, ..) => { |
887 | let bindings = trait_.bindings().unwrap(); | |
74b04a01 | 888 | FnRetTy::Return(bindings[0].ty().clone()) |
60c5eb7d | 889 | } |
dfeec247 XL |
890 | _ => panic!("unexpected desugaring of async function"), |
891 | }, | |
60c5eb7d XL |
892 | _ => panic!("unexpected desugaring of async function"), |
893 | } | |
894 | } | |
895 | } | |
896 | ||
897 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
898 | pub struct Arguments { | |
899 | pub values: Vec<Argument>, | |
900 | } | |
901 | ||
902 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
903 | pub struct Argument { | |
904 | pub type_: Type, | |
905 | pub name: String, | |
906 | } | |
907 | ||
908 | #[derive(Clone, PartialEq, Debug)] | |
909 | pub enum SelfTy { | |
910 | SelfValue, | |
911 | SelfBorrowed(Option<Lifetime>, Mutability), | |
912 | SelfExplicit(Type), | |
913 | } | |
914 | ||
915 | impl Argument { | |
916 | pub fn to_self(&self) -> Option<SelfTy> { | |
917 | if self.name != "self" { | |
918 | return None; | |
919 | } | |
920 | if self.type_.is_self_type() { | |
921 | return Some(SelfValue); | |
922 | } | |
923 | match self.type_ { | |
dfeec247 | 924 | BorrowedRef { ref lifetime, mutability, ref type_ } if type_.is_self_type() => { |
60c5eb7d XL |
925 | Some(SelfBorrowed(lifetime.clone(), mutability)) |
926 | } | |
dfeec247 | 927 | _ => Some(SelfExplicit(self.type_.clone())), |
60c5eb7d XL |
928 | } |
929 | } | |
930 | } | |
931 | ||
932 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
74b04a01 | 933 | pub enum FnRetTy { |
60c5eb7d XL |
934 | Return(Type), |
935 | DefaultReturn, | |
936 | } | |
937 | ||
74b04a01 | 938 | impl GetDefId for FnRetTy { |
60c5eb7d XL |
939 | fn def_id(&self) -> Option<DefId> { |
940 | match *self { | |
941 | Return(ref ty) => ty.def_id(), | |
942 | DefaultReturn => None, | |
943 | } | |
944 | } | |
945 | } | |
946 | ||
947 | #[derive(Clone, Debug)] | |
948 | pub struct Trait { | |
949 | pub auto: bool, | |
950 | pub unsafety: hir::Unsafety, | |
951 | pub items: Vec<Item>, | |
952 | pub generics: Generics, | |
953 | pub bounds: Vec<GenericBound>, | |
60c5eb7d XL |
954 | pub is_auto: bool, |
955 | } | |
956 | ||
957 | #[derive(Clone, Debug)] | |
958 | pub struct TraitAlias { | |
959 | pub generics: Generics, | |
960 | pub bounds: Vec<GenericBound>, | |
961 | } | |
962 | ||
963 | /// A trait reference, which may have higher ranked lifetimes. | |
964 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
965 | pub struct PolyTrait { | |
966 | pub trait_: Type, | |
967 | pub generic_params: Vec<GenericParamDef>, | |
968 | } | |
969 | ||
970 | /// A representation of a type suitable for hyperlinking purposes. Ideally, one can get the original | |
971 | /// type out of the AST/`TyCtxt` given one of these, if more information is needed. Most | |
972 | /// importantly, it does not preserve mutability or boxes. | |
973 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
974 | pub enum Type { | |
975 | /// Structs/enums/traits (most that would be an `hir::TyKind::Path`). | |
976 | ResolvedPath { | |
977 | path: Path, | |
978 | param_names: Option<Vec<GenericBound>>, | |
979 | did: DefId, | |
980 | /// `true` if is a `T::Name` path for associated types. | |
981 | is_generic: bool, | |
982 | }, | |
983 | /// For parameterized types, so the consumer of the JSON don't go | |
984 | /// looking for types which don't exist anywhere. | |
985 | Generic(String), | |
986 | /// Primitives are the fixed-size numeric types (plus int/usize/float), char, | |
987 | /// arrays, slices, and tuples. | |
988 | Primitive(PrimitiveType), | |
989 | /// `extern "ABI" fn` | |
990 | BareFunction(Box<BareFunctionDecl>), | |
991 | Tuple(Vec<Type>), | |
992 | Slice(Box<Type>), | |
993 | Array(Box<Type>, String), | |
994 | Never, | |
995 | RawPointer(Mutability, Box<Type>), | |
996 | BorrowedRef { | |
997 | lifetime: Option<Lifetime>, | |
998 | mutability: Mutability, | |
999 | type_: Box<Type>, | |
1000 | }, | |
1001 | ||
1002 | // `<Type as Trait>::Name` | |
1003 | QPath { | |
1004 | name: String, | |
1005 | self_type: Box<Type>, | |
dfeec247 | 1006 | trait_: Box<Type>, |
60c5eb7d XL |
1007 | }, |
1008 | ||
1009 | // `_` | |
1010 | Infer, | |
1011 | ||
1012 | // `impl TraitA + TraitB + ...` | |
1013 | ImplTrait(Vec<GenericBound>), | |
1014 | } | |
1015 | ||
1016 | #[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)] | |
1017 | pub enum PrimitiveType { | |
dfeec247 XL |
1018 | Isize, |
1019 | I8, | |
1020 | I16, | |
1021 | I32, | |
1022 | I64, | |
1023 | I128, | |
1024 | Usize, | |
1025 | U8, | |
1026 | U16, | |
1027 | U32, | |
1028 | U64, | |
1029 | U128, | |
1030 | F32, | |
1031 | F64, | |
60c5eb7d XL |
1032 | Char, |
1033 | Bool, | |
1034 | Str, | |
1035 | Slice, | |
1036 | Array, | |
1037 | Tuple, | |
1038 | Unit, | |
1039 | RawPointer, | |
1040 | Reference, | |
1041 | Fn, | |
1042 | Never, | |
1043 | } | |
1044 | ||
ba9703b0 | 1045 | #[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)] |
60c5eb7d XL |
1046 | pub enum TypeKind { |
1047 | Enum, | |
1048 | Function, | |
1049 | Module, | |
1050 | Const, | |
1051 | Static, | |
1052 | Struct, | |
1053 | Union, | |
1054 | Trait, | |
1055 | Typedef, | |
1056 | Foreign, | |
1057 | Macro, | |
1058 | Attr, | |
1059 | Derive, | |
1060 | TraitAlias, | |
1061 | } | |
1062 | ||
1063 | pub trait GetDefId { | |
1064 | fn def_id(&self) -> Option<DefId>; | |
1065 | } | |
1066 | ||
1067 | impl<T: GetDefId> GetDefId for Option<T> { | |
1068 | fn def_id(&self) -> Option<DefId> { | |
1069 | self.as_ref().and_then(|d| d.def_id()) | |
1070 | } | |
1071 | } | |
1072 | ||
1073 | impl Type { | |
1074 | pub fn primitive_type(&self) -> Option<PrimitiveType> { | |
1075 | match *self { | |
dfeec247 | 1076 | Primitive(p) | BorrowedRef { type_: box Primitive(p), .. } => Some(p), |
60c5eb7d XL |
1077 | Slice(..) | BorrowedRef { type_: box Slice(..), .. } => Some(PrimitiveType::Slice), |
1078 | Array(..) | BorrowedRef { type_: box Array(..), .. } => Some(PrimitiveType::Array), | |
dfeec247 XL |
1079 | Tuple(ref tys) => { |
1080 | if tys.is_empty() { | |
1081 | Some(PrimitiveType::Unit) | |
1082 | } else { | |
1083 | Some(PrimitiveType::Tuple) | |
1084 | } | |
1085 | } | |
60c5eb7d XL |
1086 | RawPointer(..) => Some(PrimitiveType::RawPointer), |
1087 | BorrowedRef { type_: box Generic(..), .. } => Some(PrimitiveType::Reference), | |
1088 | BareFunction(..) => Some(PrimitiveType::Fn), | |
1089 | Never => Some(PrimitiveType::Never), | |
1090 | _ => None, | |
1091 | } | |
1092 | } | |
1093 | ||
1094 | pub fn is_generic(&self) -> bool { | |
1095 | match *self { | |
1096 | ResolvedPath { is_generic, .. } => is_generic, | |
1097 | _ => false, | |
1098 | } | |
1099 | } | |
1100 | ||
1101 | pub fn is_self_type(&self) -> bool { | |
1102 | match *self { | |
1103 | Generic(ref name) => name == "Self", | |
dfeec247 | 1104 | _ => false, |
60c5eb7d XL |
1105 | } |
1106 | } | |
1107 | ||
1108 | pub fn generics(&self) -> Option<Vec<Type>> { | |
1109 | match *self { | |
dfeec247 XL |
1110 | ResolvedPath { ref path, .. } => path.segments.last().and_then(|seg| { |
1111 | if let GenericArgs::AngleBracketed { ref args, .. } = seg.args { | |
1112 | Some( | |
1113 | args.iter() | |
1114 | .filter_map(|arg| match arg { | |
1115 | GenericArg::Type(ty) => Some(ty.clone()), | |
1116 | _ => None, | |
1117 | }) | |
1118 | .collect(), | |
1119 | ) | |
1120 | } else { | |
1121 | None | |
1122 | } | |
1123 | }), | |
60c5eb7d XL |
1124 | _ => None, |
1125 | } | |
1126 | } | |
1127 | ||
1128 | pub fn bindings(&self) -> Option<&[TypeBinding]> { | |
1129 | match *self { | |
dfeec247 XL |
1130 | ResolvedPath { ref path, .. } => path.segments.last().and_then(|seg| { |
1131 | if let GenericArgs::AngleBracketed { ref bindings, .. } = seg.args { | |
1132 | Some(&**bindings) | |
1133 | } else { | |
1134 | None | |
1135 | } | |
1136 | }), | |
1137 | _ => None, | |
60c5eb7d XL |
1138 | } |
1139 | } | |
1140 | ||
1141 | pub fn is_full_generic(&self) -> bool { | |
1142 | match *self { | |
1143 | Type::Generic(_) => true, | |
1144 | _ => false, | |
1145 | } | |
1146 | } | |
1147 | ||
1148 | pub fn projection(&self) -> Option<(&Type, DefId, &str)> { | |
1149 | let (self_, trait_, name) = match self { | |
dfeec247 | 1150 | QPath { ref self_type, ref trait_, ref name } => (self_type, trait_, name), |
60c5eb7d XL |
1151 | _ => return None, |
1152 | }; | |
1153 | let trait_did = match **trait_ { | |
1154 | ResolvedPath { did, .. } => did, | |
1155 | _ => return None, | |
1156 | }; | |
1157 | Some((&self_, trait_did, name)) | |
1158 | } | |
60c5eb7d XL |
1159 | } |
1160 | ||
1161 | impl GetDefId for Type { | |
1162 | fn def_id(&self) -> Option<DefId> { | |
1163 | match *self { | |
1164 | ResolvedPath { did, .. } => Some(did), | |
1165 | Primitive(p) => crate::html::render::cache().primitive_locations.get(&p).cloned(), | |
dfeec247 XL |
1166 | BorrowedRef { type_: box Generic(..), .. } => { |
1167 | Primitive(PrimitiveType::Reference).def_id() | |
1168 | } | |
60c5eb7d | 1169 | BorrowedRef { ref type_, .. } => type_.def_id(), |
dfeec247 XL |
1170 | Tuple(ref tys) => { |
1171 | if tys.is_empty() { | |
1172 | Primitive(PrimitiveType::Unit).def_id() | |
1173 | } else { | |
1174 | Primitive(PrimitiveType::Tuple).def_id() | |
1175 | } | |
1176 | } | |
60c5eb7d XL |
1177 | BareFunction(..) => Primitive(PrimitiveType::Fn).def_id(), |
1178 | Never => Primitive(PrimitiveType::Never).def_id(), | |
1179 | Slice(..) => Primitive(PrimitiveType::Slice).def_id(), | |
1180 | Array(..) => Primitive(PrimitiveType::Array).def_id(), | |
1181 | RawPointer(..) => Primitive(PrimitiveType::RawPointer).def_id(), | |
1182 | QPath { ref self_type, .. } => self_type.def_id(), | |
1183 | _ => None, | |
1184 | } | |
1185 | } | |
1186 | } | |
1187 | ||
1188 | impl PrimitiveType { | |
1189 | pub fn from_str(s: &str) -> Option<PrimitiveType> { | |
1190 | match s { | |
1191 | "isize" => Some(PrimitiveType::Isize), | |
1192 | "i8" => Some(PrimitiveType::I8), | |
1193 | "i16" => Some(PrimitiveType::I16), | |
1194 | "i32" => Some(PrimitiveType::I32), | |
1195 | "i64" => Some(PrimitiveType::I64), | |
1196 | "i128" => Some(PrimitiveType::I128), | |
1197 | "usize" => Some(PrimitiveType::Usize), | |
1198 | "u8" => Some(PrimitiveType::U8), | |
1199 | "u16" => Some(PrimitiveType::U16), | |
1200 | "u32" => Some(PrimitiveType::U32), | |
1201 | "u64" => Some(PrimitiveType::U64), | |
1202 | "u128" => Some(PrimitiveType::U128), | |
1203 | "bool" => Some(PrimitiveType::Bool), | |
1204 | "char" => Some(PrimitiveType::Char), | |
1205 | "str" => Some(PrimitiveType::Str), | |
1206 | "f32" => Some(PrimitiveType::F32), | |
1207 | "f64" => Some(PrimitiveType::F64), | |
1208 | "array" => Some(PrimitiveType::Array), | |
1209 | "slice" => Some(PrimitiveType::Slice), | |
1210 | "tuple" => Some(PrimitiveType::Tuple), | |
1211 | "unit" => Some(PrimitiveType::Unit), | |
1212 | "pointer" => Some(PrimitiveType::RawPointer), | |
1213 | "reference" => Some(PrimitiveType::Reference), | |
1214 | "fn" => Some(PrimitiveType::Fn), | |
1215 | "never" => Some(PrimitiveType::Never), | |
1216 | _ => None, | |
1217 | } | |
1218 | } | |
1219 | ||
1220 | pub fn as_str(&self) -> &'static str { | |
1221 | use self::PrimitiveType::*; | |
1222 | match *self { | |
1223 | Isize => "isize", | |
1224 | I8 => "i8", | |
1225 | I16 => "i16", | |
1226 | I32 => "i32", | |
1227 | I64 => "i64", | |
1228 | I128 => "i128", | |
1229 | Usize => "usize", | |
1230 | U8 => "u8", | |
1231 | U16 => "u16", | |
1232 | U32 => "u32", | |
1233 | U64 => "u64", | |
1234 | U128 => "u128", | |
1235 | F32 => "f32", | |
1236 | F64 => "f64", | |
1237 | Str => "str", | |
1238 | Bool => "bool", | |
1239 | Char => "char", | |
1240 | Array => "array", | |
1241 | Slice => "slice", | |
1242 | Tuple => "tuple", | |
1243 | Unit => "unit", | |
1244 | RawPointer => "pointer", | |
1245 | Reference => "reference", | |
1246 | Fn => "fn", | |
1247 | Never => "never", | |
1248 | } | |
1249 | } | |
1250 | ||
1251 | pub fn to_url_str(&self) -> &'static str { | |
1252 | self.as_str() | |
1253 | } | |
1254 | } | |
1255 | ||
1256 | impl From<ast::IntTy> for PrimitiveType { | |
1257 | fn from(int_ty: ast::IntTy) -> PrimitiveType { | |
1258 | match int_ty { | |
1259 | ast::IntTy::Isize => PrimitiveType::Isize, | |
1260 | ast::IntTy::I8 => PrimitiveType::I8, | |
1261 | ast::IntTy::I16 => PrimitiveType::I16, | |
1262 | ast::IntTy::I32 => PrimitiveType::I32, | |
1263 | ast::IntTy::I64 => PrimitiveType::I64, | |
1264 | ast::IntTy::I128 => PrimitiveType::I128, | |
1265 | } | |
1266 | } | |
1267 | } | |
1268 | ||
1269 | impl From<ast::UintTy> for PrimitiveType { | |
1270 | fn from(uint_ty: ast::UintTy) -> PrimitiveType { | |
1271 | match uint_ty { | |
1272 | ast::UintTy::Usize => PrimitiveType::Usize, | |
1273 | ast::UintTy::U8 => PrimitiveType::U8, | |
1274 | ast::UintTy::U16 => PrimitiveType::U16, | |
1275 | ast::UintTy::U32 => PrimitiveType::U32, | |
1276 | ast::UintTy::U64 => PrimitiveType::U64, | |
1277 | ast::UintTy::U128 => PrimitiveType::U128, | |
1278 | } | |
1279 | } | |
1280 | } | |
1281 | ||
1282 | impl From<ast::FloatTy> for PrimitiveType { | |
1283 | fn from(float_ty: ast::FloatTy) -> PrimitiveType { | |
1284 | match float_ty { | |
1285 | ast::FloatTy::F32 => PrimitiveType::F32, | |
1286 | ast::FloatTy::F64 => PrimitiveType::F64, | |
1287 | } | |
1288 | } | |
1289 | } | |
1290 | ||
74b04a01 XL |
1291 | impl From<hir::PrimTy> for PrimitiveType { |
1292 | fn from(prim_ty: hir::PrimTy) -> PrimitiveType { | |
1293 | match prim_ty { | |
1294 | hir::PrimTy::Int(int_ty) => int_ty.into(), | |
1295 | hir::PrimTy::Uint(uint_ty) => uint_ty.into(), | |
1296 | hir::PrimTy::Float(float_ty) => float_ty.into(), | |
1297 | hir::PrimTy::Str => PrimitiveType::Str, | |
1298 | hir::PrimTy::Bool => PrimitiveType::Bool, | |
1299 | hir::PrimTy::Char => PrimitiveType::Char, | |
1300 | } | |
1301 | } | |
1302 | } | |
1303 | ||
60c5eb7d XL |
1304 | #[derive(Clone, PartialEq, Eq, Debug)] |
1305 | pub enum Visibility { | |
1306 | Public, | |
1307 | Inherited, | |
1308 | Crate, | |
1309 | Restricted(DefId, Path), | |
1310 | } | |
1311 | ||
1312 | #[derive(Clone, Debug)] | |
1313 | pub struct Struct { | |
1314 | pub struct_type: doctree::StructType, | |
1315 | pub generics: Generics, | |
1316 | pub fields: Vec<Item>, | |
1317 | pub fields_stripped: bool, | |
1318 | } | |
1319 | ||
1320 | #[derive(Clone, Debug)] | |
1321 | pub struct Union { | |
1322 | pub struct_type: doctree::StructType, | |
1323 | pub generics: Generics, | |
1324 | pub fields: Vec<Item>, | |
1325 | pub fields_stripped: bool, | |
1326 | } | |
1327 | ||
1328 | /// This is a more limited form of the standard Struct, different in that | |
1329 | /// it lacks the things most items have (name, id, parameterization). Found | |
1330 | /// only as a variant in an enum. | |
1331 | #[derive(Clone, Debug)] | |
1332 | pub struct VariantStruct { | |
1333 | pub struct_type: doctree::StructType, | |
1334 | pub fields: Vec<Item>, | |
1335 | pub fields_stripped: bool, | |
1336 | } | |
1337 | ||
1338 | #[derive(Clone, Debug)] | |
1339 | pub struct Enum { | |
1340 | pub variants: IndexVec<VariantIdx, Item>, | |
1341 | pub generics: Generics, | |
1342 | pub variants_stripped: bool, | |
1343 | } | |
1344 | ||
1345 | #[derive(Clone, Debug)] | |
1346 | pub struct Variant { | |
1347 | pub kind: VariantKind, | |
1348 | } | |
1349 | ||
1350 | #[derive(Clone, Debug)] | |
1351 | pub enum VariantKind { | |
1352 | CLike, | |
1353 | Tuple(Vec<Type>), | |
1354 | Struct(VariantStruct), | |
1355 | } | |
1356 | ||
1357 | #[derive(Clone, Debug)] | |
1358 | pub struct Span { | |
1359 | pub filename: FileName, | |
ba9703b0 | 1360 | pub cnum: CrateNum, |
60c5eb7d XL |
1361 | pub loline: usize, |
1362 | pub locol: usize, | |
1363 | pub hiline: usize, | |
1364 | pub hicol: usize, | |
dfeec247 | 1365 | pub original: rustc_span::Span, |
60c5eb7d XL |
1366 | } |
1367 | ||
1368 | impl Span { | |
1369 | pub fn empty() -> Span { | |
1370 | Span { | |
1371 | filename: FileName::Anon(0), | |
ba9703b0 | 1372 | cnum: LOCAL_CRATE, |
dfeec247 XL |
1373 | loline: 0, |
1374 | locol: 0, | |
1375 | hiline: 0, | |
1376 | hicol: 0, | |
1377 | original: rustc_span::DUMMY_SP, | |
60c5eb7d XL |
1378 | } |
1379 | } | |
1380 | ||
dfeec247 | 1381 | pub fn span(&self) -> rustc_span::Span { |
60c5eb7d XL |
1382 | self.original |
1383 | } | |
1384 | } | |
1385 | ||
1386 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
1387 | pub struct Path { | |
1388 | pub global: bool, | |
1389 | pub res: Res, | |
1390 | pub segments: Vec<PathSegment>, | |
1391 | } | |
1392 | ||
1393 | impl Path { | |
1394 | pub fn last_name(&self) -> &str { | |
1395 | self.segments.last().expect("segments were empty").name.as_str() | |
1396 | } | |
1397 | } | |
1398 | ||
1399 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
1400 | pub enum GenericArg { | |
1401 | Lifetime(Lifetime), | |
1402 | Type(Type), | |
1403 | Const(Constant), | |
1404 | } | |
1405 | ||
1406 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
1407 | pub enum GenericArgs { | |
dfeec247 XL |
1408 | AngleBracketed { args: Vec<GenericArg>, bindings: Vec<TypeBinding> }, |
1409 | Parenthesized { inputs: Vec<Type>, output: Option<Type> }, | |
60c5eb7d XL |
1410 | } |
1411 | ||
1412 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
1413 | pub struct PathSegment { | |
1414 | pub name: String, | |
1415 | pub args: GenericArgs, | |
1416 | } | |
1417 | ||
1418 | #[derive(Clone, Debug)] | |
1419 | pub struct Typedef { | |
1420 | pub type_: Type, | |
1421 | pub generics: Generics, | |
dfeec247 XL |
1422 | // Type of target item. |
1423 | pub item_type: Option<Type>, | |
1424 | } | |
1425 | ||
1426 | impl GetDefId for Typedef { | |
1427 | fn def_id(&self) -> Option<DefId> { | |
1428 | self.type_.def_id() | |
1429 | } | |
60c5eb7d XL |
1430 | } |
1431 | ||
1432 | #[derive(Clone, Debug)] | |
1433 | pub struct OpaqueTy { | |
1434 | pub bounds: Vec<GenericBound>, | |
1435 | pub generics: Generics, | |
1436 | } | |
1437 | ||
1438 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
1439 | pub struct BareFunctionDecl { | |
1440 | pub unsafety: hir::Unsafety, | |
1441 | pub generic_params: Vec<GenericParamDef>, | |
1442 | pub decl: FnDecl, | |
1443 | pub abi: Abi, | |
1444 | } | |
1445 | ||
1446 | #[derive(Clone, Debug)] | |
1447 | pub struct Static { | |
1448 | pub type_: Type, | |
1449 | pub mutability: Mutability, | |
1450 | /// It's useful to have the value of a static documented, but I have no | |
1451 | /// desire to represent expressions (that'd basically be all of the AST, | |
1452 | /// which is huge!). So, have a string. | |
1453 | pub expr: String, | |
1454 | } | |
1455 | ||
1456 | #[derive(Clone, PartialEq, Eq, Hash, Debug)] | |
1457 | pub struct Constant { | |
1458 | pub type_: Type, | |
1459 | pub expr: String, | |
dfeec247 XL |
1460 | pub value: Option<String>, |
1461 | pub is_literal: bool, | |
60c5eb7d XL |
1462 | } |
1463 | ||
1464 | #[derive(Clone, PartialEq, Debug)] | |
1465 | pub enum ImplPolarity { | |
1466 | Positive, | |
1467 | Negative, | |
1468 | } | |
1469 | ||
1470 | #[derive(Clone, Debug)] | |
1471 | pub struct Impl { | |
1472 | pub unsafety: hir::Unsafety, | |
1473 | pub generics: Generics, | |
1474 | pub provided_trait_methods: FxHashSet<String>, | |
1475 | pub trait_: Option<Type>, | |
1476 | pub for_: Type, | |
1477 | pub items: Vec<Item>, | |
1478 | pub polarity: Option<ImplPolarity>, | |
1479 | pub synthetic: bool, | |
1480 | pub blanket_impl: Option<Type>, | |
1481 | } | |
1482 | ||
1483 | #[derive(Clone, Debug)] | |
1484 | pub enum Import { | |
1485 | // use source as str; | |
1486 | Simple(String, ImportSource), | |
1487 | // use source::*; | |
dfeec247 | 1488 | Glob(ImportSource), |
60c5eb7d XL |
1489 | } |
1490 | ||
1491 | #[derive(Clone, Debug)] | |
1492 | pub struct ImportSource { | |
1493 | pub path: Path, | |
1494 | pub did: Option<DefId>, | |
1495 | } | |
1496 | ||
1497 | #[derive(Clone, Debug)] | |
1498 | pub struct Macro { | |
1499 | pub source: String, | |
1500 | pub imported_from: Option<String>, | |
1501 | } | |
1502 | ||
1503 | #[derive(Clone, Debug)] | |
1504 | pub struct ProcMacro { | |
1505 | pub kind: MacroKind, | |
1506 | pub helpers: Vec<String>, | |
1507 | } | |
1508 | ||
1509 | #[derive(Clone, Debug)] | |
1510 | pub struct Stability { | |
1511 | pub level: stability::StabilityLevel, | |
1512 | pub feature: Option<String>, | |
1513 | pub since: String, | |
1514 | pub deprecation: Option<Deprecation>, | |
1515 | pub unstable_reason: Option<String>, | |
1516 | pub issue: Option<NonZeroU32>, | |
1517 | } | |
1518 | ||
1519 | #[derive(Clone, Debug)] | |
1520 | pub struct Deprecation { | |
1521 | pub since: Option<String>, | |
1522 | pub note: Option<String>, | |
1523 | } | |
1524 | ||
1525 | /// An type binding on an associated type (e.g., `A = Bar` in `Foo<A = Bar>` or | |
1526 | /// `A: Send + Sync` in `Foo<A: Send + Sync>`). | |
1527 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
1528 | pub struct TypeBinding { | |
1529 | pub name: String, | |
1530 | pub kind: TypeBindingKind, | |
1531 | } | |
1532 | ||
1533 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | |
1534 | pub enum TypeBindingKind { | |
dfeec247 XL |
1535 | Equality { ty: Type }, |
1536 | Constraint { bounds: Vec<GenericBound> }, | |
60c5eb7d XL |
1537 | } |
1538 | ||
1539 | impl TypeBinding { | |
1540 | pub fn ty(&self) -> &Type { | |
1541 | match self.kind { | |
1542 | TypeBindingKind::Equality { ref ty } => ty, | |
1543 | _ => panic!("expected equality type binding for parenthesized generic args"), | |
1544 | } | |
1545 | } | |
1546 | } |