diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 4d8d0040cdc..327be40a58f 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -5,12 +5,12 @@ pub mod inline; pub mod cfg; -mod simplify; mod auto_trait; mod blanket_impl; +mod simplify; +pub mod types; use rustc_index::vec::{IndexVec, Idx}; -use rustc_target::spec::abi::Abi; use rustc_typeck::hir_ty_to_ty; use rustc::infer::region_constraints::{RegionConstraintData, Constraint}; use rustc::middle::resolve_lifetime as rl; @@ -24,46 +24,33 @@ use rustc::hir::ptr::P; use rustc::ty::subst::{InternalSubsts, SubstsRef, GenericArgKind}; use rustc::ty::{self, DefIdTree, TyCtxt, Region, RegionVid, Ty, AdtKind}; use rustc::ty::fold::TypeFolder; -use rustc::ty::layout::VariantIdx; use rustc::util::nodemap::{FxHashMap, FxHashSet}; -use syntax::ast::{self, Attribute, AttrStyle, AttrKind, Ident}; +use syntax::ast::{self, Ident}; use syntax::attr; -use syntax::util::comments; -use syntax::source_map::DUMMY_SP; use syntax_pos::symbol::{Symbol, kw, sym}; use syntax_pos::hygiene::MacroKind; -use syntax_pos::{self, Pos, FileName}; +use syntax_pos::{self, Pos}; use std::collections::hash_map::Entry; -use std::fmt; -use std::hash::{Hash, Hasher}; +use std::hash::Hash; use std::default::Default; -use std::{mem, slice, vec}; -use std::num::NonZeroU32; -use std::iter::FromIterator; +use std::{mem, vec}; use std::rc::Rc; -use std::cell::RefCell; -use std::sync::Arc; use std::u32; use crate::core::{self, DocContext, ImplTraitParam}; use crate::doctree; -use crate::html::render::{cache, ExternalLocation}; -use crate::html::item_type::ItemType; - -use self::cfg::Cfg; use self::auto_trait::AutoTraitFinder; use self::blanket_impl::BlanketImplFinder; -pub use self::Type::*; -pub use self::Mutability::*; -pub use self::ItemEnum::*; -pub use self::SelfTy::*; -pub use self::FunctionRetTy::*; -pub use self::Visibility::{Public, Inherited}; - -thread_local!(pub static MAX_DEF_ID: RefCell> = Default::default()); +pub use self::types::*; +pub use self::types::Type::*; +pub use self::types::Mutability::*; +pub use self::types::ItemEnum::*; +pub use self::types::SelfTy::*; +pub use self::types::FunctionRetTy::*; +pub use self::types::Visibility::{Public, Inherited}; const FN_OUTPUT_NAME: &'static str = "Output"; @@ -122,21 +109,6 @@ impl, U> Clean> for P<[T]> { } } -#[derive(Clone, Debug)] -pub struct Crate { - pub name: String, - pub version: Option, - pub src: FileName, - pub module: Option, - pub externs: Vec<(CrateNum, ExternalCrate)>, - pub primitives: Vec<(DefId, PrimitiveType, Attributes)>, - // These are later on moved into `CACHEKEY`, leaving the map empty. - // Only here so that they can be filtered through the rustdoc passes. - pub external_traits: Rc>>, - pub masked_crates: FxHashSet, - pub collapsed: bool, -} - pub fn krate(mut cx: &mut DocContext<'_>) -> Crate { use crate::visit_lib::LibEmbargoVisitor; @@ -222,15 +194,6 @@ pub fn krate(mut cx: &mut DocContext<'_>) -> Crate { } } -#[derive(Clone, Debug)] -pub struct ExternalCrate { - pub name: String, - pub src: FileName, - pub attrs: Attributes, - pub primitives: Vec<(DefId, PrimitiveType, Attributes)>, - pub keywords: Vec<(DefId, String, Attributes)>, -} - impl Clean for CrateNum { fn clean(&self, cx: &DocContext<'_>) -> ExternalCrate { let root = DefId { krate: *self, index: CRATE_DEF_INDEX }; @@ -351,237 +314,6 @@ impl Clean for CrateNum { } } -/// Anything with a source location and set of attributes and, optionally, a -/// name. That is, anything that can be documented. This doesn't correspond -/// directly to the AST's concept of an item; it's a strict superset. -#[derive(Clone)] -pub struct Item { - /// Stringified span - pub source: Span, - /// Not everything has a name. E.g., impls - pub name: Option, - pub attrs: Attributes, - pub inner: ItemEnum, - pub visibility: Visibility, - pub def_id: DefId, - pub stability: Option, - pub deprecation: Option, -} - -impl fmt::Debug for Item { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - - let fake = MAX_DEF_ID.with(|m| m.borrow().get(&self.def_id.krate) - .map(|id| self.def_id >= *id).unwrap_or(false)); - let def_id: &dyn fmt::Debug = if fake { &"**FAKE**" } else { &self.def_id }; - - fmt.debug_struct("Item") - .field("source", &self.source) - .field("name", &self.name) - .field("attrs", &self.attrs) - .field("inner", &self.inner) - .field("visibility", &self.visibility) - .field("def_id", def_id) - .field("stability", &self.stability) - .field("deprecation", &self.deprecation) - .finish() - } -} - -impl Item { - /// Finds the `doc` attribute as a NameValue and returns the corresponding - /// value found. - pub fn doc_value(&self) -> Option<&str> { - self.attrs.doc_value() - } - /// Finds all `doc` attributes as NameValues and returns their corresponding values, joined - /// with newlines. - pub fn collapsed_doc_value(&self) -> Option { - self.attrs.collapsed_doc_value() - } - - pub fn links(&self) -> Vec<(String, String)> { - self.attrs.links(&self.def_id.krate) - } - - pub fn is_crate(&self) -> bool { - match self.inner { - StrippedItem(box ModuleItem(Module { is_crate: true, ..})) | - ModuleItem(Module { is_crate: true, ..}) => true, - _ => false, - } - } - pub fn is_mod(&self) -> bool { - self.type_() == ItemType::Module - } - pub fn is_trait(&self) -> bool { - self.type_() == ItemType::Trait - } - pub fn is_struct(&self) -> bool { - self.type_() == ItemType::Struct - } - pub fn is_enum(&self) -> bool { - self.type_() == ItemType::Enum - } - pub fn is_variant(&self) -> bool { - self.type_() == ItemType::Variant - } - pub fn is_associated_type(&self) -> bool { - self.type_() == ItemType::AssocType - } - pub fn is_associated_const(&self) -> bool { - self.type_() == ItemType::AssocConst - } - pub fn is_method(&self) -> bool { - self.type_() == ItemType::Method - } - pub fn is_ty_method(&self) -> bool { - self.type_() == ItemType::TyMethod - } - pub fn is_typedef(&self) -> bool { - self.type_() == ItemType::Typedef - } - pub fn is_primitive(&self) -> bool { - self.type_() == ItemType::Primitive - } - pub fn is_union(&self) -> bool { - self.type_() == ItemType::Union - } - pub fn is_import(&self) -> bool { - self.type_() == ItemType::Import - } - pub fn is_extern_crate(&self) -> bool { - self.type_() == ItemType::ExternCrate - } - pub fn is_keyword(&self) -> bool { - self.type_() == ItemType::Keyword - } - - pub fn is_stripped(&self) -> bool { - match self.inner { StrippedItem(..) => true, _ => false } - } - pub fn has_stripped_fields(&self) -> Option { - match self.inner { - StructItem(ref _struct) => Some(_struct.fields_stripped), - UnionItem(ref union) => Some(union.fields_stripped), - VariantItem(Variant { kind: VariantKind::Struct(ref vstruct)} ) => { - Some(vstruct.fields_stripped) - }, - _ => None, - } - } - - pub fn stability_class(&self) -> Option { - self.stability.as_ref().and_then(|ref s| { - let mut classes = Vec::with_capacity(2); - - if s.level == stability::Unstable { - classes.push("unstable"); - } - - if s.deprecation.is_some() { - classes.push("deprecated"); - } - - if classes.len() != 0 { - Some(classes.join(" ")) - } else { - None - } - }) - } - - pub fn stable_since(&self) -> Option<&str> { - self.stability.as_ref().map(|s| &s.since[..]) - } - - pub fn is_non_exhaustive(&self) -> bool { - self.attrs.other_attrs.iter() - .any(|a| a.check_name(sym::non_exhaustive)) - } - - /// Returns a documentation-level item type from the item. - pub fn type_(&self) -> ItemType { - ItemType::from(self) - } - - /// Returns the info in the item's `#[deprecated]` or `#[rustc_deprecated]` attributes. - /// - /// If the item is not deprecated, returns `None`. - pub fn deprecation(&self) -> Option<&Deprecation> { - self.deprecation - .as_ref() - .or_else(|| self.stability.as_ref().and_then(|s| s.deprecation.as_ref())) - } - pub fn is_default(&self) -> bool { - match self.inner { - ItemEnum::MethodItem(ref meth) => { - if let Some(defaultness) = meth.defaultness { - defaultness.has_value() && !defaultness.is_final() - } else { - false - } - } - _ => false, - } - } -} - -#[derive(Clone, Debug)] -pub enum ItemEnum { - ExternCrateItem(String, Option), - ImportItem(Import), - StructItem(Struct), - UnionItem(Union), - EnumItem(Enum), - FunctionItem(Function), - ModuleItem(Module), - TypedefItem(Typedef, bool /* is associated type */), - OpaqueTyItem(OpaqueTy, bool /* is associated type */), - StaticItem(Static), - ConstantItem(Constant), - TraitItem(Trait), - TraitAliasItem(TraitAlias), - ImplItem(Impl), - /// A method signature only. Used for required methods in traits (ie, - /// non-default-methods). - TyMethodItem(TyMethod), - /// A method with a body. - MethodItem(Method), - StructFieldItem(Type), - VariantItem(Variant), - /// `fn`s from an extern block - ForeignFunctionItem(Function), - /// `static`s from an extern block - ForeignStaticItem(Static), - /// `type`s from an extern block - ForeignTypeItem, - MacroItem(Macro), - ProcMacroItem(ProcMacro), - PrimitiveItem(PrimitiveType), - AssocConstItem(Type, Option), - AssocTypeItem(Vec, Option), - /// An item that has been stripped by a rustdoc pass - StrippedItem(Box), - KeywordItem(String), -} - -impl ItemEnum { - pub fn is_associated(&self) -> bool { - match *self { - ItemEnum::TypedefItem(_, _) | - ItemEnum::AssocTypeItem(_, _) => true, - _ => false, - } - } -} - -#[derive(Clone, Debug)] -pub struct Module { - pub items: Vec, - pub is_crate: bool, -} - impl Clean for doctree::Module<'_> { fn clean(&self, cx: &DocContext<'_>) -> Item { let name = if self.name.is_some() { @@ -645,465 +377,12 @@ impl Clean for doctree::Module<'_> { } } -pub struct ListAttributesIter<'a> { - attrs: slice::Iter<'a, ast::Attribute>, - current_list: vec::IntoIter, - name: Symbol, -} - -impl<'a> Iterator for ListAttributesIter<'a> { - type Item = ast::NestedMetaItem; - - fn next(&mut self) -> Option { - if let Some(nested) = self.current_list.next() { - return Some(nested); - } - - for attr in &mut self.attrs { - if let Some(list) = attr.meta_item_list() { - if attr.check_name(self.name) { - self.current_list = list.into_iter(); - if let Some(nested) = self.current_list.next() { - return Some(nested); - } - } - } - } - - None - } - - fn size_hint(&self) -> (usize, Option) { - let lower = self.current_list.len(); - (lower, None) - } -} - -pub trait AttributesExt { - /// Finds an attribute as List and returns the list of attributes nested inside. - fn lists(&self, name: Symbol) -> ListAttributesIter<'_>; -} - -impl AttributesExt for [ast::Attribute] { - fn lists(&self, name: Symbol) -> ListAttributesIter<'_> { - ListAttributesIter { - attrs: self.iter(), - current_list: Vec::new().into_iter(), - name, - } - } -} - -pub trait NestedAttributesExt { - /// Returns `true` if the attribute list contains a specific `Word` - fn has_word(self, word: Symbol) -> bool; -} - -impl> NestedAttributesExt for I { - fn has_word(self, word: Symbol) -> bool { - self.into_iter().any(|attr| attr.is_word() && attr.check_name(word)) - } -} - -/// A portion of documentation, extracted from a `#[doc]` attribute. -/// -/// Each variant contains the line number within the complete doc-comment where the fragment -/// starts, as well as the Span where the corresponding doc comment or attribute is located. -/// -/// Included files are kept separate from inline doc comments so that proper line-number -/// information can be given when a doctest fails. Sugared doc comments and "raw" doc comments are -/// kept separate because of issue #42760. -#[derive(Clone, PartialEq, Eq, Debug, Hash)] -pub enum DocFragment { - /// A doc fragment created from a `///` or `//!` doc comment. - SugaredDoc(usize, syntax_pos::Span, String), - /// A doc fragment created from a "raw" `#[doc=""]` attribute. - RawDoc(usize, syntax_pos::Span, String), - /// A doc fragment created from a `#[doc(include="filename")]` attribute. Contains both the - /// given filename and the file contents. - Include(usize, syntax_pos::Span, String, String), -} - -impl DocFragment { - pub fn as_str(&self) -> &str { - match *self { - DocFragment::SugaredDoc(_, _, ref s) => &s[..], - DocFragment::RawDoc(_, _, ref s) => &s[..], - DocFragment::Include(_, _, _, ref s) => &s[..], - } - } - - pub fn span(&self) -> syntax_pos::Span { - match *self { - DocFragment::SugaredDoc(_, span, _) | - DocFragment::RawDoc(_, span, _) | - DocFragment::Include(_, span, _, _) => span, - } - } -} - -impl<'a> FromIterator<&'a DocFragment> for String { - fn from_iter(iter: T) -> Self - where - T: IntoIterator - { - iter.into_iter().fold(String::new(), |mut acc, frag| { - if !acc.is_empty() { - acc.push('\n'); - } - match *frag { - DocFragment::SugaredDoc(_, _, ref docs) - | DocFragment::RawDoc(_, _, ref docs) - | DocFragment::Include(_, _, _, ref docs) => - acc.push_str(docs), - } - - acc - }) - } -} - -#[derive(Clone, Debug, Default)] -pub struct Attributes { - pub doc_strings: Vec, - pub other_attrs: Vec, - pub cfg: Option>, - pub span: Option, - /// map from Rust paths to resolved defs and potential URL fragments - pub links: Vec<(String, Option, Option)>, - pub inner_docs: bool, -} - -impl Attributes { - /// Extracts the content from an attribute `#[doc(cfg(content))]`. - fn extract_cfg(mi: &ast::MetaItem) -> Option<&ast::MetaItem> { - use syntax::ast::NestedMetaItem::MetaItem; - - if let ast::MetaItemKind::List(ref nmis) = mi.kind { - if nmis.len() == 1 { - if let MetaItem(ref cfg_mi) = nmis[0] { - if cfg_mi.check_name(sym::cfg) { - if let ast::MetaItemKind::List(ref cfg_nmis) = cfg_mi.kind { - if cfg_nmis.len() == 1 { - if let MetaItem(ref content_mi) = cfg_nmis[0] { - return Some(content_mi); - } - } - } - } - } - } - } - - None - } - - /// Reads a `MetaItem` from within an attribute, looks for whether it is a - /// `#[doc(include="file")]`, and returns the filename and contents of the file as loaded from - /// its expansion. - fn extract_include(mi: &ast::MetaItem) - -> Option<(String, String)> - { - mi.meta_item_list().and_then(|list| { - for meta in list { - if meta.check_name(sym::include) { - // the actual compiled `#[doc(include="filename")]` gets expanded to - // `#[doc(include(file="filename", contents="file contents")]` so we need to - // look for that instead - return meta.meta_item_list().and_then(|list| { - let mut filename: Option = None; - let mut contents: Option = None; - - for it in list { - if it.check_name(sym::file) { - if let Some(name) = it.value_str() { - filename = Some(name.to_string()); - } - } else if it.check_name(sym::contents) { - if let Some(docs) = it.value_str() { - contents = Some(docs.to_string()); - } - } - } - - if let (Some(filename), Some(contents)) = (filename, contents) { - Some((filename, contents)) - } else { - None - } - }); - } - } - - None - }) - } - - pub fn has_doc_flag(&self, flag: Symbol) -> bool { - for attr in &self.other_attrs { - if !attr.check_name(sym::doc) { continue; } - - if let Some(items) = attr.meta_item_list() { - if items.iter().filter_map(|i| i.meta_item()).any(|it| it.check_name(flag)) { - return true; - } - } - } - - false - } - - pub fn from_ast(diagnostic: &::errors::Handler, - attrs: &[ast::Attribute]) -> Attributes { - let mut doc_strings = vec![]; - let mut sp = None; - let mut cfg = Cfg::True; - let mut doc_line = 0; - - /// If `attr` is a doc comment, strips the leading and (if present) - /// trailing comments symbols, e.g. `///`, `/**`, and `*/`. Otherwise, - /// returns `attr` unchanged. - pub fn with_doc_comment_markers_stripped( - attr: &Attribute, - f: impl FnOnce(&Attribute) -> T - ) -> T { - match attr.kind { - AttrKind::Normal(_) => { - f(attr) - } - AttrKind::DocComment(comment) => { - let comment = - Symbol::intern(&comments::strip_doc_comment_decoration(&comment.as_str())); - f(&Attribute { - kind: AttrKind::DocComment(comment), - id: attr.id, - style: attr.style, - span: attr.span, - }) - } - } - } - - let other_attrs = attrs.iter().filter_map(|attr| { - with_doc_comment_markers_stripped(attr, |attr| { - if attr.check_name(sym::doc) { - if let Some(mi) = attr.meta() { - if let Some(value) = mi.value_str() { - // Extracted #[doc = "..."] - let value = value.to_string(); - let line = doc_line; - doc_line += value.lines().count(); - - if attr.is_doc_comment() { - doc_strings.push(DocFragment::SugaredDoc(line, attr.span, value)); - } else { - doc_strings.push(DocFragment::RawDoc(line, attr.span, value)); - } - - if sp.is_none() { - sp = Some(attr.span); - } - return None; - } else if let Some(cfg_mi) = Attributes::extract_cfg(&mi) { - // Extracted #[doc(cfg(...))] - match Cfg::parse(cfg_mi) { - Ok(new_cfg) => cfg &= new_cfg, - Err(e) => diagnostic.span_err(e.span, e.msg), - } - return None; - } else if let Some((filename, contents)) = Attributes::extract_include(&mi) - { - let line = doc_line; - doc_line += contents.lines().count(); - doc_strings.push(DocFragment::Include(line, - attr.span, - filename, - contents)); - } - } - } - Some(attr.clone()) - }) - }).collect(); - - // treat #[target_feature(enable = "feat")] attributes as if they were - // #[doc(cfg(target_feature = "feat"))] attributes as well - for attr in attrs.lists(sym::target_feature) { - if attr.check_name(sym::enable) { - if let Some(feat) = attr.value_str() { - let meta = attr::mk_name_value_item_str( - Ident::with_dummy_span(sym::target_feature), feat, DUMMY_SP - ); - if let Ok(feat_cfg) = Cfg::parse(&meta) { - cfg &= feat_cfg; - } - } - } - } - - let inner_docs = attrs.iter() - .filter(|a| a.check_name(sym::doc)) - .next() - .map_or(true, |a| a.style == AttrStyle::Inner); - - Attributes { - doc_strings, - other_attrs, - cfg: if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) }, - span: sp, - links: vec![], - inner_docs, - } - } - - /// Finds the `doc` attribute as a NameValue and returns the corresponding - /// value found. - pub fn doc_value(&self) -> Option<&str> { - self.doc_strings.first().map(|s| s.as_str()) - } - - /// Finds all `doc` attributes as NameValues and returns their corresponding values, joined - /// with newlines. - pub fn collapsed_doc_value(&self) -> Option { - if !self.doc_strings.is_empty() { - Some(self.doc_strings.iter().collect()) - } else { - None - } - } - - /// Gets links as a vector - /// - /// Cache must be populated before call - pub fn links(&self, krate: &CrateNum) -> Vec<(String, String)> { - use crate::html::format::href; - - self.links.iter().filter_map(|&(ref s, did, ref fragment)| { - match did { - Some(did) => { - if let Some((mut href, ..)) = href(did) { - if let Some(ref fragment) = *fragment { - href.push_str("#"); - href.push_str(fragment); - } - Some((s.clone(), href)) - } else { - None - } - } - None => { - if let Some(ref fragment) = *fragment { - let cache = cache(); - let url = match cache.extern_locations.get(krate) { - Some(&(_, ref src, ExternalLocation::Local)) => - src.to_str().expect("invalid file path"), - Some(&(_, _, ExternalLocation::Remote(ref s))) => s, - Some(&(_, _, ExternalLocation::Unknown)) | None => - "https://doc.rust-lang.org/nightly", - }; - // This is a primitive so the url is done "by hand". - let tail = fragment.find('#').unwrap_or_else(|| fragment.len()); - Some((s.clone(), - format!("{}{}std/primitive.{}.html{}", - url, - if !url.ends_with('/') { "/" } else { "" }, - &fragment[..tail], - &fragment[tail..]))) - } else { - panic!("This isn't a primitive?!"); - } - } - } - }).collect() - } -} - -impl PartialEq for Attributes { - fn eq(&self, rhs: &Self) -> bool { - self.doc_strings == rhs.doc_strings && - self.cfg == rhs.cfg && - self.span == rhs.span && - self.links == rhs.links && - self.other_attrs.iter().map(|attr| attr.id).eq(rhs.other_attrs.iter().map(|attr| attr.id)) - } -} - -impl Eq for Attributes {} - -impl Hash for Attributes { - fn hash(&self, hasher: &mut H) { - self.doc_strings.hash(hasher); - self.cfg.hash(hasher); - self.span.hash(hasher); - self.links.hash(hasher); - for attr in &self.other_attrs { - attr.id.hash(hasher); - } - } -} - -impl AttributesExt for Attributes { - fn lists(&self, name: Symbol) -> ListAttributesIter<'_> { - self.other_attrs.lists(name) - } -} - impl Clean for [ast::Attribute] { fn clean(&self, cx: &DocContext<'_>) -> Attributes { Attributes::from_ast(cx.sess().diagnostic(), self) } } -#[derive(Clone, PartialEq, Eq, Debug, Hash)] -pub enum GenericBound { - TraitBound(PolyTrait, hir::TraitBoundModifier), - Outlives(Lifetime), -} - -impl GenericBound { - fn maybe_sized(cx: &DocContext<'_>) -> GenericBound { - let did = cx.tcx.require_lang_item(lang_items::SizedTraitLangItem, None); - let empty = cx.tcx.intern_substs(&[]); - let path = external_path(cx, cx.tcx.item_name(did), - Some(did), false, vec![], empty); - inline::record_extern_fqn(cx, did, TypeKind::Trait); - GenericBound::TraitBound(PolyTrait { - trait_: ResolvedPath { - path, - param_names: None, - did, - is_generic: false, - }, - generic_params: Vec::new(), - }, hir::TraitBoundModifier::Maybe) - } - - fn is_sized_bound(&self, cx: &DocContext<'_>) -> bool { - use rustc::hir::TraitBoundModifier as TBM; - if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, TBM::None) = *self { - if trait_.def_id() == cx.tcx.lang_items().sized_trait() { - return true; - } - } - false - } - - fn get_poly_trait(&self) -> Option { - if let GenericBound::TraitBound(ref p, _) = *self { - return Some(p.clone()) - } - None - } - - fn get_trait_type(&self) -> Option { - if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, _) = *self { - Some(trait_.clone()) - } else { - None - } - } -} - impl Clean for hir::GenericBound { fn clean(&self, cx: &DocContext<'_>) -> GenericBound { match *self { @@ -1237,21 +516,6 @@ impl<'tcx> Clean>> for InternalSubsts<'tcx> { } } -#[derive(Clone, PartialEq, Eq, Debug, Hash)] -pub struct Lifetime(String); - -impl Lifetime { - pub fn get_ref<'a>(&'a self) -> &'a str { - let Lifetime(ref s) = *self; - let s: &'a str = s; - s - } - - pub fn statik() -> Lifetime { - Lifetime("'static".to_string()) - } -} - impl Clean for hir::Lifetime { fn clean(&self, cx: &DocContext<'_>) -> Lifetime { if self.hir_id != hir::DUMMY_HIR_ID { @@ -1332,23 +596,6 @@ impl Clean> for ty::RegionKind { } } -#[derive(Clone, Debug)] -pub enum WherePredicate { - BoundPredicate { ty: Type, bounds: Vec }, - RegionPredicate { lifetime: Lifetime, bounds: Vec }, - EqPredicate { lhs: Type, rhs: Type }, -} - -impl WherePredicate { - pub fn get_bounds(&self) -> Option<&[GenericBound]> { - match *self { - WherePredicate::BoundPredicate { ref bounds, .. } => Some(bounds), - WherePredicate::RegionPredicate { ref bounds, .. } => Some(bounds), - _ => None, - } - } -} - impl Clean for hir::WherePredicate { fn clean(&self, cx: &DocContext<'_>) -> WherePredicate { match *self { @@ -1470,73 +717,6 @@ impl<'tcx> Clean for ty::ProjectionTy<'tcx> { } } -#[derive(Clone, PartialEq, Eq, Debug, Hash)] -pub enum GenericParamDefKind { - Lifetime, - Type { - did: DefId, - bounds: Vec, - default: Option, - synthetic: Option, - }, - Const { - did: DefId, - ty: Type, - }, -} - -impl GenericParamDefKind { - pub fn is_type(&self) -> bool { - match *self { - GenericParamDefKind::Type { .. } => true, - _ => false, - } - } - - // FIXME(eddyb) this either returns the default of a type parameter, or the - // type of a `const` parameter. It seems that the intention is to *visit* - // any embedded types, but `get_type` seems to be the wrong name for that. - pub fn get_type(&self) -> Option { - match self { - GenericParamDefKind::Type { default, .. } => default.clone(), - GenericParamDefKind::Const { ty, .. } => Some(ty.clone()), - GenericParamDefKind::Lifetime => None, - } - } -} - -#[derive(Clone, PartialEq, Eq, Debug, Hash)] -pub struct GenericParamDef { - pub name: String, - - pub kind: GenericParamDefKind, -} - -impl GenericParamDef { - pub fn is_synthetic_type_param(&self) -> bool { - match self.kind { - GenericParamDefKind::Lifetime | - GenericParamDefKind::Const { .. } => false, - GenericParamDefKind::Type { ref synthetic, .. } => synthetic.is_some(), - } - } - - pub fn is_type(&self) -> bool { - self.kind.is_type() - } - - pub fn get_type(&self) -> Option { - self.kind.get_type() - } - - pub fn get_bounds(&self) -> Option<&[GenericBound]> { - match self.kind { - GenericParamDefKind::Type { ref bounds, .. } => Some(bounds), - _ => None, - } - } -} - impl Clean for ty::GenericParamDef { fn clean(&self, cx: &DocContext<'_>) -> GenericParamDef { let (name, kind) = match self.kind { @@ -1614,13 +794,6 @@ impl Clean for hir::GenericParam { } } -// maybe use a Generic enum and use Vec? -#[derive(Clone, Debug, Default)] -pub struct Generics { - pub params: Vec, - pub where_predicates: Vec, -} - impl Clean for hir::Generics { fn clean(&self, cx: &DocContext<'_>) -> Generics { // Synthetic type-parameters are inserted after normal ones. @@ -1975,16 +1148,6 @@ pub fn get_all_types( (all_types.into_iter().collect(), ret_types) } -#[derive(Clone, Debug)] -pub struct Method { - pub generics: Generics, - pub decl: FnDecl, - pub header: hir::FnHeader, - pub defaultness: Option, - pub all_types: Vec, - pub ret_types: Vec, -} - impl<'a> Clean for (&'a hir::FnSig, &'a hir::Generics, hir::BodyId, Option) { fn clean(&self, cx: &DocContext<'_>) -> Method { @@ -2003,24 +1166,6 @@ impl<'a> Clean for (&'a hir::FnSig, &'a hir::Generics, hir::BodyId, } } -#[derive(Clone, Debug)] -pub struct TyMethod { - pub header: hir::FnHeader, - pub decl: FnDecl, - pub generics: Generics, - pub all_types: Vec, - pub ret_types: Vec, -} - -#[derive(Clone, Debug)] -pub struct Function { - pub decl: FnDecl, - pub generics: Generics, - pub header: hir::FnHeader, - pub all_types: Vec, - pub ret_types: Vec, -} - impl Clean for doctree::Function<'_> { fn clean(&self, cx: &DocContext<'_>) -> Item { let (generics, decl) = enter_impl_trait(cx, || { @@ -2053,49 +1198,6 @@ impl Clean for doctree::Function<'_> { } } -#[derive(Clone, PartialEq, Eq, Debug, Hash)] -pub struct FnDecl { - pub inputs: Arguments, - pub output: FunctionRetTy, - pub c_variadic: bool, - pub attrs: Attributes, -} - -impl FnDecl { - pub fn self_type(&self) -> Option { - self.inputs.values.get(0).and_then(|v| v.to_self()) - } - - /// Returns the sugared return type for an async function. - /// - /// For example, if the return type is `impl std::future::Future`, this function - /// will return `i32`. - /// - /// # Panics - /// - /// This function will panic if the return type does not match the expected sugaring for async - /// functions. - pub fn sugared_async_return_type(&self) -> FunctionRetTy { - match &self.output { - FunctionRetTy::Return(Type::ImplTrait(bounds)) => { - match &bounds[0] { - GenericBound::TraitBound(PolyTrait { trait_, .. }, ..) => { - let bindings = trait_.bindings().unwrap(); - FunctionRetTy::Return(bindings[0].ty().clone()) - } - _ => panic!("unexpected desugaring of async function"), - } - } - _ => panic!("unexpected desugaring of async function"), - } - } -} - -#[derive(Clone, PartialEq, Eq, Debug, Hash)] -pub struct Arguments { - pub values: Vec, -} - impl<'a> Clean for (&'a [hir::Ty], &'a [ast::Ident]) { fn clean(&self, cx: &DocContext<'_>) -> Arguments { Arguments { @@ -2167,42 +1269,6 @@ impl<'tcx> Clean for (DefId, ty::PolyFnSig<'tcx>) { } } -#[derive(Clone, PartialEq, Eq, Debug, Hash)] -pub struct Argument { - pub type_: Type, - pub name: String, -} - -#[derive(Clone, PartialEq, Debug)] -pub enum SelfTy { - SelfValue, - SelfBorrowed(Option, Mutability), - SelfExplicit(Type), -} - -impl Argument { - pub fn to_self(&self) -> Option { - if self.name != "self" { - return None; - } - if self.type_.is_self_type() { - return Some(SelfValue); - } - match self.type_ { - BorrowedRef{ref lifetime, mutability, ref type_} if type_.is_self_type() => { - Some(SelfBorrowed(lifetime.clone(), mutability)) - } - _ => Some(SelfExplicit(self.type_.clone())) - } - } -} - -#[derive(Clone, PartialEq, Eq, Debug, Hash)] -pub enum FunctionRetTy { - Return(Type), - DefaultReturn, -} - impl Clean for hir::FunctionRetTy { fn clean(&self, cx: &DocContext<'_>) -> FunctionRetTy { match *self { @@ -2212,26 +1278,6 @@ impl Clean for hir::FunctionRetTy { } } -impl GetDefId for FunctionRetTy { - fn def_id(&self) -> Option { - match *self { - Return(ref ty) => ty.def_id(), - DefaultReturn => None, - } - } -} - -#[derive(Clone, Debug)] -pub struct Trait { - pub auto: bool, - pub unsafety: hir::Unsafety, - pub items: Vec, - pub generics: Generics, - pub bounds: Vec, - pub is_spotlight: bool, - pub is_auto: bool, -} - impl Clean for doctree::Trait<'_> { fn clean(&self, cx: &DocContext<'_>) -> Item { let attrs = self.attrs.clean(cx); @@ -2257,12 +1303,6 @@ impl Clean for doctree::Trait<'_> { } } -#[derive(Clone, Debug)] -pub struct TraitAlias { - pub generics: Generics, - pub bounds: Vec, -} - impl Clean for doctree::TraitAlias<'_> { fn clean(&self, cx: &DocContext<'_>) -> Item { let attrs = self.attrs.clean(cx); @@ -2541,321 +1581,6 @@ impl Clean for ty::AssocItem { } } -/// A trait reference, which may have higher ranked lifetimes. -#[derive(Clone, PartialEq, Eq, Debug, Hash)] -pub struct PolyTrait { - pub trait_: Type, - pub generic_params: Vec, -} - -/// A representation of a type suitable for hyperlinking purposes. Ideally, one can get the original -/// type out of the AST/`TyCtxt` given one of these, if more information is needed. Most -/// importantly, it does not preserve mutability or boxes. -#[derive(Clone, PartialEq, Eq, Debug, Hash)] -pub enum Type { - /// Structs/enums/traits (most that would be an `hir::TyKind::Path`). - ResolvedPath { - path: Path, - param_names: Option>, - did: DefId, - /// `true` if is a `T::Name` path for associated types. - is_generic: bool, - }, - /// For parameterized types, so the consumer of the JSON don't go - /// looking for types which don't exist anywhere. - Generic(String), - /// Primitives are the fixed-size numeric types (plus int/usize/float), char, - /// arrays, slices, and tuples. - Primitive(PrimitiveType), - /// `extern "ABI" fn` - BareFunction(Box), - Tuple(Vec), - Slice(Box), - Array(Box, String), - Never, - RawPointer(Mutability, Box), - BorrowedRef { - lifetime: Option, - mutability: Mutability, - type_: Box, - }, - - // `::Name` - QPath { - name: String, - self_type: Box, - trait_: Box - }, - - // `_` - Infer, - - // `impl TraitA + TraitB + ...` - ImplTrait(Vec), -} - -#[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)] -pub enum PrimitiveType { - Isize, I8, I16, I32, I64, I128, - Usize, U8, U16, U32, U64, U128, - F32, F64, - Char, - Bool, - Str, - Slice, - Array, - Tuple, - Unit, - RawPointer, - Reference, - Fn, - Never, -} - -#[derive(Clone, Copy, Debug)] -pub enum TypeKind { - Enum, - Function, - Module, - Const, - Static, - Struct, - Union, - Trait, - Typedef, - Foreign, - Macro, - Attr, - Derive, - TraitAlias, -} - -pub trait GetDefId { - fn def_id(&self) -> Option; -} - -impl GetDefId for Option { - fn def_id(&self) -> Option { - self.as_ref().and_then(|d| d.def_id()) - } -} - -impl Type { - pub fn primitive_type(&self) -> Option { - match *self { - Primitive(p) | BorrowedRef { type_: box Primitive(p), ..} => Some(p), - Slice(..) | BorrowedRef { type_: box Slice(..), .. } => Some(PrimitiveType::Slice), - Array(..) | BorrowedRef { type_: box Array(..), .. } => Some(PrimitiveType::Array), - Tuple(ref tys) => if tys.is_empty() { - Some(PrimitiveType::Unit) - } else { - Some(PrimitiveType::Tuple) - }, - RawPointer(..) => Some(PrimitiveType::RawPointer), - BorrowedRef { type_: box Generic(..), .. } => Some(PrimitiveType::Reference), - BareFunction(..) => Some(PrimitiveType::Fn), - Never => Some(PrimitiveType::Never), - _ => None, - } - } - - pub fn is_generic(&self) -> bool { - match *self { - ResolvedPath { is_generic, .. } => is_generic, - _ => false, - } - } - - pub fn is_self_type(&self) -> bool { - match *self { - Generic(ref name) => name == "Self", - _ => false - } - } - - pub fn generics(&self) -> Option> { - match *self { - ResolvedPath { ref path, .. } => { - path.segments.last().and_then(|seg| { - if let GenericArgs::AngleBracketed { ref args, .. } = seg.args { - Some(args.iter().filter_map(|arg| match arg { - GenericArg::Type(ty) => Some(ty.clone()), - _ => None, - }).collect()) - } else { - None - } - }) - } - _ => None, - } - } - - pub fn bindings(&self) -> Option<&[TypeBinding]> { - match *self { - ResolvedPath { ref path, .. } => { - path.segments.last().and_then(|seg| { - if let GenericArgs::AngleBracketed { ref bindings, .. } = seg.args { - Some(&**bindings) - } else { - None - } - }) - } - _ => None - } - } - - pub fn is_full_generic(&self) -> bool { - match *self { - Type::Generic(_) => true, - _ => false, - } - } - - pub fn projection(&self) -> Option<(&Type, DefId, &str)> { - let (self_, trait_, name) = match self { - QPath { ref self_type, ref trait_, ref name } => { - (self_type, trait_, name) - } - _ => return None, - }; - let trait_did = match **trait_ { - ResolvedPath { did, .. } => did, - _ => return None, - }; - Some((&self_, trait_did, name)) - } - -} - -impl GetDefId for Type { - fn def_id(&self) -> Option { - match *self { - ResolvedPath { did, .. } => Some(did), - Primitive(p) => crate::html::render::cache().primitive_locations.get(&p).cloned(), - BorrowedRef { type_: box Generic(..), .. } => - Primitive(PrimitiveType::Reference).def_id(), - BorrowedRef { ref type_, .. } => type_.def_id(), - Tuple(ref tys) => if tys.is_empty() { - Primitive(PrimitiveType::Unit).def_id() - } else { - Primitive(PrimitiveType::Tuple).def_id() - }, - BareFunction(..) => Primitive(PrimitiveType::Fn).def_id(), - Never => Primitive(PrimitiveType::Never).def_id(), - Slice(..) => Primitive(PrimitiveType::Slice).def_id(), - Array(..) => Primitive(PrimitiveType::Array).def_id(), - RawPointer(..) => Primitive(PrimitiveType::RawPointer).def_id(), - QPath { ref self_type, .. } => self_type.def_id(), - _ => None, - } - } -} - -impl PrimitiveType { - fn from_str(s: &str) -> Option { - match s { - "isize" => Some(PrimitiveType::Isize), - "i8" => Some(PrimitiveType::I8), - "i16" => Some(PrimitiveType::I16), - "i32" => Some(PrimitiveType::I32), - "i64" => Some(PrimitiveType::I64), - "i128" => Some(PrimitiveType::I128), - "usize" => Some(PrimitiveType::Usize), - "u8" => Some(PrimitiveType::U8), - "u16" => Some(PrimitiveType::U16), - "u32" => Some(PrimitiveType::U32), - "u64" => Some(PrimitiveType::U64), - "u128" => Some(PrimitiveType::U128), - "bool" => Some(PrimitiveType::Bool), - "char" => Some(PrimitiveType::Char), - "str" => Some(PrimitiveType::Str), - "f32" => Some(PrimitiveType::F32), - "f64" => Some(PrimitiveType::F64), - "array" => Some(PrimitiveType::Array), - "slice" => Some(PrimitiveType::Slice), - "tuple" => Some(PrimitiveType::Tuple), - "unit" => Some(PrimitiveType::Unit), - "pointer" => Some(PrimitiveType::RawPointer), - "reference" => Some(PrimitiveType::Reference), - "fn" => Some(PrimitiveType::Fn), - "never" => Some(PrimitiveType::Never), - _ => None, - } - } - - pub fn as_str(&self) -> &'static str { - use self::PrimitiveType::*; - match *self { - Isize => "isize", - I8 => "i8", - I16 => "i16", - I32 => "i32", - I64 => "i64", - I128 => "i128", - Usize => "usize", - U8 => "u8", - U16 => "u16", - U32 => "u32", - U64 => "u64", - U128 => "u128", - F32 => "f32", - F64 => "f64", - Str => "str", - Bool => "bool", - Char => "char", - Array => "array", - Slice => "slice", - Tuple => "tuple", - Unit => "unit", - RawPointer => "pointer", - Reference => "reference", - Fn => "fn", - Never => "never", - } - } - - pub fn to_url_str(&self) -> &'static str { - self.as_str() - } -} - -impl From for PrimitiveType { - fn from(int_ty: ast::IntTy) -> PrimitiveType { - match int_ty { - ast::IntTy::Isize => PrimitiveType::Isize, - ast::IntTy::I8 => PrimitiveType::I8, - ast::IntTy::I16 => PrimitiveType::I16, - ast::IntTy::I32 => PrimitiveType::I32, - ast::IntTy::I64 => PrimitiveType::I64, - ast::IntTy::I128 => PrimitiveType::I128, - } - } -} - -impl From for PrimitiveType { - fn from(uint_ty: ast::UintTy) -> PrimitiveType { - match uint_ty { - ast::UintTy::Usize => PrimitiveType::Usize, - ast::UintTy::U8 => PrimitiveType::U8, - ast::UintTy::U16 => PrimitiveType::U16, - ast::UintTy::U32 => PrimitiveType::U32, - ast::UintTy::U64 => PrimitiveType::U64, - ast::UintTy::U128 => PrimitiveType::U128, - } - } -} - -impl From for PrimitiveType { - fn from(float_ty: ast::FloatTy) -> PrimitiveType { - match float_ty { - ast::FloatTy::F32 => PrimitiveType::F32, - ast::FloatTy::F64 => PrimitiveType::F64, - } - } -} - impl Clean for hir::Ty { fn clean(&self, cx: &DocContext<'_>) -> Type { use rustc::hir::*; @@ -3310,14 +2035,6 @@ impl Clean for ty::FieldDef { } } -#[derive(Clone, PartialEq, Eq, Debug)] -pub enum Visibility { - Public, - Inherited, - Crate, - Restricted(DefId, Path), -} - impl Clean for hir::Visibility { fn clean(&self, cx: &DocContext<'_>) -> Visibility { match self.node { @@ -3339,22 +2056,6 @@ impl Clean for ty::Visibility { } } -#[derive(Clone, Debug)] -pub struct Struct { - pub struct_type: doctree::StructType, - pub generics: Generics, - pub fields: Vec, - pub fields_stripped: bool, -} - -#[derive(Clone, Debug)] -pub struct Union { - pub struct_type: doctree::StructType, - pub generics: Generics, - pub fields: Vec, - pub fields_stripped: bool, -} - impl Clean for doctree::Struct<'_> { fn clean(&self, cx: &DocContext<'_>) -> Item { Item { @@ -3395,16 +2096,6 @@ impl Clean for doctree::Union<'_> { } } -/// This is a more limited form of the standard Struct, different in that -/// it lacks the things most items have (name, id, parameterization). Found -/// only as a variant in an enum. -#[derive(Clone, Debug)] -pub struct VariantStruct { - pub struct_type: doctree::StructType, - pub fields: Vec, - pub fields_stripped: bool, -} - impl Clean for ::rustc::hir::VariantData { fn clean(&self, cx: &DocContext<'_>) -> VariantStruct { VariantStruct { @@ -3415,13 +2106,6 @@ impl Clean for ::rustc::hir::VariantData { } } -#[derive(Clone, Debug)] -pub struct Enum { - pub variants: IndexVec, - pub generics: Generics, - pub variants_stripped: bool, -} - impl Clean for doctree::Enum<'_> { fn clean(&self, cx: &DocContext<'_>) -> Item { Item { @@ -3441,11 +2125,6 @@ impl Clean for doctree::Enum<'_> { } } -#[derive(Clone, Debug)] -pub struct Variant { - pub kind: VariantKind, -} - impl Clean for doctree::Variant<'_> { fn clean(&self, cx: &DocContext<'_>) -> Item { Item { @@ -3504,13 +2183,6 @@ impl Clean for ty::VariantDef { } } -#[derive(Clone, Debug)] -pub enum VariantKind { - CLike, - Tuple(Vec), - Struct(VariantStruct), -} - impl Clean for hir::VariantData { fn clean(&self, cx: &DocContext<'_>) -> VariantKind { match self { @@ -3522,31 +2194,6 @@ impl Clean for hir::VariantData { } } -#[derive(Clone, Debug)] -pub struct Span { - pub filename: FileName, - pub loline: usize, - pub locol: usize, - pub hiline: usize, - pub hicol: usize, - pub original: syntax_pos::Span, -} - -impl Span { - pub fn empty() -> Span { - Span { - filename: FileName::Anon(0), - loline: 0, locol: 0, - hiline: 0, hicol: 0, - original: syntax_pos::DUMMY_SP, - } - } - - pub fn span(&self) -> syntax_pos::Span { - self.original - } -} - impl Clean for syntax_pos::Span { fn clean(&self, cx: &DocContext<'_>) -> Span { if self.is_dummy() { @@ -3568,19 +2215,6 @@ impl Clean for syntax_pos::Span { } } -#[derive(Clone, PartialEq, Eq, Debug, Hash)] -pub struct Path { - pub global: bool, - pub res: Res, - pub segments: Vec, -} - -impl Path { - pub fn last_name(&self) -> &str { - self.segments.last().expect("segments were empty").name.as_str() - } -} - impl Clean for hir::Path { fn clean(&self, cx: &DocContext<'_>) -> Path { Path { @@ -3591,25 +2225,6 @@ impl Clean for hir::Path { } } -#[derive(Clone, PartialEq, Eq, Debug, Hash)] -pub enum GenericArg { - Lifetime(Lifetime), - Type(Type), - Const(Constant), -} - -#[derive(Clone, PartialEq, Eq, Debug, Hash)] -pub enum GenericArgs { - AngleBracketed { - args: Vec, - bindings: Vec, - }, - Parenthesized { - inputs: Vec, - output: Option, - } -} - impl Clean for hir::GenericArgs { fn clean(&self, cx: &DocContext<'_>) -> GenericArgs { if self.parenthesized { @@ -3638,12 +2253,6 @@ impl Clean for hir::GenericArgs { } } -#[derive(Clone, PartialEq, Eq, Debug, Hash)] -pub struct PathSegment { - pub name: String, - pub args: GenericArgs, -} - impl Clean for hir::PathSegment { fn clean(&self, cx: &DocContext<'_>) -> PathSegment { PathSegment { @@ -3727,12 +2336,6 @@ impl Clean for ast::Name { } } -#[derive(Clone, Debug)] -pub struct Typedef { - pub type_: Type, - pub generics: Generics, -} - impl Clean for doctree::Typedef<'_> { fn clean(&self, cx: &DocContext<'_>) -> Item { Item { @@ -3751,12 +2354,6 @@ impl Clean for doctree::Typedef<'_> { } } -#[derive(Clone, Debug)] -pub struct OpaqueTy { - pub bounds: Vec, - pub generics: Generics, -} - impl Clean for doctree::OpaqueTy<'_> { fn clean(&self, cx: &DocContext<'_>) -> Item { Item { @@ -3775,14 +2372,6 @@ impl Clean for doctree::OpaqueTy<'_> { } } -#[derive(Clone, PartialEq, Eq, Debug, Hash)] -pub struct BareFunctionDecl { - pub unsafety: hir::Unsafety, - pub generic_params: Vec, - pub decl: FnDecl, - pub abi: Abi, -} - impl Clean for hir::BareFnTy { fn clean(&self, cx: &DocContext<'_>) -> BareFunctionDecl { let (generic_params, decl) = enter_impl_trait(cx, || { @@ -3797,16 +2386,6 @@ impl Clean for hir::BareFnTy { } } -#[derive(Clone, Debug)] -pub struct Static { - pub type_: Type, - pub mutability: Mutability, - /// It's useful to have the value of a static documented, but I have no - /// desire to represent expressions (that'd basically be all of the AST, - /// which is huge!). So, have a string. - pub expr: String, -} - impl Clean for doctree::Static<'_> { fn clean(&self, cx: &DocContext<'_>) -> Item { debug!("cleaning static {}: {:?}", self.name.clean(cx), self); @@ -3827,12 +2406,6 @@ impl Clean for doctree::Static<'_> { } } -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -pub struct Constant { - pub type_: Type, - pub expr: String, -} - impl Clean for doctree::Constant<'_> { fn clean(&self, cx: &DocContext<'_>) -> Item { Item { @@ -3851,12 +2424,6 @@ impl Clean for doctree::Constant<'_> { } } -#[derive(Debug, Clone, PartialEq, Eq, Copy, Hash)] -pub enum Mutability { - Mutable, - Immutable, -} - impl Clean for hir::Mutability { fn clean(&self, _: &DocContext<'_>) -> Mutability { match self { @@ -3866,12 +2433,6 @@ impl Clean for hir::Mutability { } } -#[derive(Clone, PartialEq, Debug)] -pub enum ImplPolarity { - Positive, - Negative, -} - impl Clean for ty::ImplPolarity { fn clean(&self, _: &DocContext<'_>) -> ImplPolarity { match self { @@ -3883,19 +2444,6 @@ impl Clean for ty::ImplPolarity { } } -#[derive(Clone, Debug)] -pub struct Impl { - pub unsafety: hir::Unsafety, - pub generics: Generics, - pub provided_trait_methods: FxHashSet, - pub trait_: Option, - pub for_: Type, - pub items: Vec, - pub polarity: Option, - pub synthetic: bool, - pub blanket_impl: Option, -} - pub fn get_auto_trait_and_blanket_impls( cx: &DocContext<'tcx>, ty: Ty<'tcx>, @@ -4115,20 +2663,6 @@ impl Clean> for doctree::Import<'_> { } } -#[derive(Clone, Debug)] -pub enum Import { - // use source as str; - Simple(String, ImportSource), - // use source::*; - Glob(ImportSource) -} - -#[derive(Clone, Debug)] -pub struct ImportSource { - pub path: Path, - pub did: Option, -} - impl Clean for doctree::ForeignItem<'_> { fn clean(&self, cx: &DocContext<'_>) -> Item { let inner = match self.kind { @@ -4340,12 +2874,6 @@ fn resolve_use_source(cx: &DocContext<'_>, path: Path) -> ImportSource { } } -#[derive(Clone, Debug)] -pub struct Macro { - pub source: String, - pub imported_from: Option, -} - impl Clean for doctree::Macro<'_> { fn clean(&self, cx: &DocContext<'_>) -> Item { let name = self.name.clean(cx); @@ -4369,12 +2897,6 @@ impl Clean for doctree::Macro<'_> { } } -#[derive(Clone, Debug)] -pub struct ProcMacro { - pub kind: MacroKind, - pub helpers: Vec, -} - impl Clean for doctree::ProcMacro<'_> { fn clean(&self, cx: &DocContext<'_>) -> Item { Item { @@ -4393,22 +2915,6 @@ impl Clean for doctree::ProcMacro<'_> { } } -#[derive(Clone, Debug)] -pub struct Stability { - pub level: stability::StabilityLevel, - pub feature: Option, - pub since: String, - pub deprecation: Option, - pub unstable_reason: Option, - pub issue: Option, -} - -#[derive(Clone, Debug)] -pub struct Deprecation { - pub since: Option, - pub note: Option, -} - impl Clean for attr::Stability { fn clean(&self, _: &DocContext<'_>) -> Stability { Stability { @@ -4451,33 +2957,6 @@ impl Clean for attr::Deprecation { } } -/// An type binding on an associated type (e.g., `A = Bar` in `Foo` or -/// `A: Send + Sync` in `Foo`). -#[derive(Clone, PartialEq, Eq, Debug, Hash)] -pub struct TypeBinding { - pub name: String, - pub kind: TypeBindingKind, -} - -#[derive(Clone, PartialEq, Eq, Debug, Hash)] -pub enum TypeBindingKind { - Equality { - ty: Type, - }, - Constraint { - bounds: Vec, - }, -} - -impl TypeBinding { - pub fn ty(&self) -> &Type { - match self.kind { - TypeBindingKind::Equality { ref ty } => ty, - _ => panic!("expected equality type binding for parenthesized generic args"), - } - } -} - impl Clean for hir::TypeBinding { fn clean(&self, cx: &DocContext<'_>) -> TypeBinding { TypeBinding { diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs new file mode 100644 index 00000000000..bd3f2a3690a --- /dev/null +++ b/src/librustdoc/clean/types.rs @@ -0,0 +1,1545 @@ +use std::fmt; +use std::hash::{Hash, Hasher}; +use std::default::Default; +use std::{slice, vec}; +use std::num::NonZeroU32; +use std::iter::FromIterator; +use std::rc::Rc; +use std::cell::RefCell; +use std::sync::Arc; + +use rustc::middle::lang_items; +use rustc::middle::stability; +use rustc::hir; +use rustc::hir::def::Res; +use rustc::hir::def_id::{CrateNum, DefId}; +use rustc::ty::layout::VariantIdx; +use rustc::util::nodemap::{FxHashMap, FxHashSet}; +use rustc_index::vec::IndexVec; +use rustc_target::spec::abi::Abi; +use syntax::ast::{self, Attribute, AttrStyle, AttrKind, Ident}; +use syntax::attr; +use syntax::util::comments; +use syntax::source_map::DUMMY_SP; +use syntax_pos::hygiene::MacroKind; +use syntax_pos::symbol::{Symbol, sym}; +use syntax_pos::{self, FileName}; + +use crate::core::DocContext; +use crate::clean::cfg::Cfg; +use crate::clean::inline; +use crate::clean::external_path; +use crate::clean::types::Type::{QPath, ResolvedPath}; +use crate::doctree; +use crate::html::item_type::ItemType; +use crate::html::render::{cache, ExternalLocation}; + +use self::Type::*; +use self::ItemEnum::*; +use self::SelfTy::*; +use self::FunctionRetTy::*; + +thread_local!(pub static MAX_DEF_ID: RefCell> = Default::default()); + +#[derive(Clone, Debug)] +pub struct Crate { + pub name: String, + pub version: Option, + pub src: FileName, + pub module: Option, + pub externs: Vec<(CrateNum, ExternalCrate)>, + pub primitives: Vec<(DefId, PrimitiveType, Attributes)>, + // These are later on moved into `CACHEKEY`, leaving the map empty. + // Only here so that they can be filtered through the rustdoc passes. + pub external_traits: Rc>>, + pub masked_crates: FxHashSet, + pub collapsed: bool, +} + +#[derive(Clone, Debug)] +pub struct ExternalCrate { + pub name: String, + pub src: FileName, + pub attrs: Attributes, + pub primitives: Vec<(DefId, PrimitiveType, Attributes)>, + pub keywords: Vec<(DefId, String, Attributes)>, +} + +/// Anything with a source location and set of attributes and, optionally, a +/// name. That is, anything that can be documented. This doesn't correspond +/// directly to the AST's concept of an item; it's a strict superset. +#[derive(Clone)] +pub struct Item { + /// Stringified span + pub source: Span, + /// Not everything has a name. E.g., impls + pub name: Option, + pub attrs: Attributes, + pub inner: ItemEnum, + pub visibility: Visibility, + pub def_id: DefId, + pub stability: Option, + pub deprecation: Option, +} + +impl fmt::Debug for Item { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + let fake = MAX_DEF_ID.with(|m| m.borrow().get(&self.def_id.krate) + .map(|id| self.def_id >= *id).unwrap_or(false)); + let def_id: &dyn fmt::Debug = if fake { &"**FAKE**" } else { &self.def_id }; + + fmt.debug_struct("Item") + .field("source", &self.source) + .field("name", &self.name) + .field("attrs", &self.attrs) + .field("inner", &self.inner) + .field("visibility", &self.visibility) + .field("def_id", def_id) + .field("stability", &self.stability) + .field("deprecation", &self.deprecation) + .finish() + } +} + +impl Item { + /// Finds the `doc` attribute as a NameValue and returns the corresponding + /// value found. + pub fn doc_value(&self) -> Option<&str> { + self.attrs.doc_value() + } + + /// Finds all `doc` attributes as NameValues and returns their corresponding values, joined + /// with newlines. + pub fn collapsed_doc_value(&self) -> Option { + self.attrs.collapsed_doc_value() + } + + pub fn links(&self) -> Vec<(String, String)> { + self.attrs.links(&self.def_id.krate) + } + + pub fn is_crate(&self) -> bool { + match self.inner { + StrippedItem(box ModuleItem(Module { is_crate: true, ..})) | + ModuleItem(Module { is_crate: true, ..}) => true, + _ => false, + } + } + pub fn is_mod(&self) -> bool { + self.type_() == ItemType::Module + } + pub fn is_trait(&self) -> bool { + self.type_() == ItemType::Trait + } + pub fn is_struct(&self) -> bool { + self.type_() == ItemType::Struct + } + pub fn is_enum(&self) -> bool { + self.type_() == ItemType::Enum + } + pub fn is_variant(&self) -> bool { + self.type_() == ItemType::Variant + } + pub fn is_associated_type(&self) -> bool { + self.type_() == ItemType::AssocType + } + pub fn is_associated_const(&self) -> bool { + self.type_() == ItemType::AssocConst + } + pub fn is_method(&self) -> bool { + self.type_() == ItemType::Method + } + pub fn is_ty_method(&self) -> bool { + self.type_() == ItemType::TyMethod + } + pub fn is_typedef(&self) -> bool { + self.type_() == ItemType::Typedef + } + pub fn is_primitive(&self) -> bool { + self.type_() == ItemType::Primitive + } + pub fn is_union(&self) -> bool { + self.type_() == ItemType::Union + } + pub fn is_import(&self) -> bool { + self.type_() == ItemType::Import + } + pub fn is_extern_crate(&self) -> bool { + self.type_() == ItemType::ExternCrate + } + pub fn is_keyword(&self) -> bool { + self.type_() == ItemType::Keyword + } + pub fn is_stripped(&self) -> bool { + match self.inner { StrippedItem(..) => true, _ => false } + } + pub fn has_stripped_fields(&self) -> Option { + match self.inner { + StructItem(ref _struct) => Some(_struct.fields_stripped), + UnionItem(ref union) => Some(union.fields_stripped), + VariantItem(Variant { kind: VariantKind::Struct(ref vstruct)} ) => { + Some(vstruct.fields_stripped) + }, + _ => None, + } + } + + pub fn stability_class(&self) -> Option { + self.stability.as_ref().and_then(|ref s| { + let mut classes = Vec::with_capacity(2); + + if s.level == stability::Unstable { + classes.push("unstable"); + } + + if s.deprecation.is_some() { + classes.push("deprecated"); + } + + if classes.len() != 0 { + Some(classes.join(" ")) + } else { + None + } + }) + } + + pub fn stable_since(&self) -> Option<&str> { + self.stability.as_ref().map(|s| &s.since[..]) + } + + pub fn is_non_exhaustive(&self) -> bool { + self.attrs.other_attrs.iter() + .any(|a| a.check_name(sym::non_exhaustive)) + } + + /// Returns a documentation-level item type from the item. + pub fn type_(&self) -> ItemType { + ItemType::from(self) + } + + /// Returns the info in the item's `#[deprecated]` or `#[rustc_deprecated]` attributes. + /// + /// If the item is not deprecated, returns `None`. + pub fn deprecation(&self) -> Option<&Deprecation> { + self.deprecation + .as_ref() + .or_else(|| self.stability.as_ref().and_then(|s| s.deprecation.as_ref())) + } + pub fn is_default(&self) -> bool { + match self.inner { + ItemEnum::MethodItem(ref meth) => { + if let Some(defaultness) = meth.defaultness { + defaultness.has_value() && !defaultness.is_final() + } else { + false + } + } + _ => false, + } + } +} + +#[derive(Clone, Debug)] +pub enum ItemEnum { + ExternCrateItem(String, Option), + ImportItem(Import), + StructItem(Struct), + UnionItem(Union), + EnumItem(Enum), + FunctionItem(Function), + ModuleItem(Module), + TypedefItem(Typedef, bool /* is associated type */), + OpaqueTyItem(OpaqueTy, bool /* is associated type */), + StaticItem(Static), + ConstantItem(Constant), + TraitItem(Trait), + TraitAliasItem(TraitAlias), + ImplItem(Impl), + /// A method signature only. Used for required methods in traits (ie, + /// non-default-methods). + TyMethodItem(TyMethod), + /// A method with a body. + MethodItem(Method), + StructFieldItem(Type), + VariantItem(Variant), + /// `fn`s from an extern block + ForeignFunctionItem(Function), + /// `static`s from an extern block + ForeignStaticItem(Static), + /// `type`s from an extern block + ForeignTypeItem, + MacroItem(Macro), + ProcMacroItem(ProcMacro), + PrimitiveItem(PrimitiveType), + AssocConstItem(Type, Option), + AssocTypeItem(Vec, Option), + /// An item that has been stripped by a rustdoc pass + StrippedItem(Box), + KeywordItem(String), +} + +impl ItemEnum { + pub fn is_associated(&self) -> bool { + match *self { + ItemEnum::TypedefItem(_, _) | + ItemEnum::AssocTypeItem(_, _) => true, + _ => false, + } + } +} + +#[derive(Clone, Debug)] +pub struct Module { + pub items: Vec, + pub is_crate: bool, +} + +pub struct ListAttributesIter<'a> { + attrs: slice::Iter<'a, ast::Attribute>, + current_list: vec::IntoIter, + name: Symbol, +} + +impl<'a> Iterator for ListAttributesIter<'a> { + type Item = ast::NestedMetaItem; + + fn next(&mut self) -> Option { + if let Some(nested) = self.current_list.next() { + return Some(nested); + } + + for attr in &mut self.attrs { + if let Some(list) = attr.meta_item_list() { + if attr.check_name(self.name) { + self.current_list = list.into_iter(); + if let Some(nested) = self.current_list.next() { + return Some(nested); + } + } + } + } + + None + } + + fn size_hint(&self) -> (usize, Option) { + let lower = self.current_list.len(); + (lower, None) + } +} + +pub trait AttributesExt { + /// Finds an attribute as List and returns the list of attributes nested inside. + fn lists(&self, name: Symbol) -> ListAttributesIter<'_>; +} + +impl AttributesExt for [ast::Attribute] { + fn lists(&self, name: Symbol) -> ListAttributesIter<'_> { + ListAttributesIter { + attrs: self.iter(), + current_list: Vec::new().into_iter(), + name, + } + } +} + +pub trait NestedAttributesExt { + /// Returns `true` if the attribute list contains a specific `Word` + fn has_word(self, word: Symbol) -> bool; +} + +impl> NestedAttributesExt for I { + fn has_word(self, word: Symbol) -> bool { + self.into_iter().any(|attr| attr.is_word() && attr.check_name(word)) + } +} + +/// A portion of documentation, extracted from a `#[doc]` attribute. +/// +/// Each variant contains the line number within the complete doc-comment where the fragment +/// starts, as well as the Span where the corresponding doc comment or attribute is located. +/// +/// Included files are kept separate from inline doc comments so that proper line-number +/// information can be given when a doctest fails. Sugared doc comments and "raw" doc comments are +/// kept separate because of issue #42760. +#[derive(Clone, PartialEq, Eq, Debug, Hash)] +pub enum DocFragment { + /// A doc fragment created from a `///` or `//!` doc comment. + SugaredDoc(usize, syntax_pos::Span, String), + /// A doc fragment created from a "raw" `#[doc=""]` attribute. + RawDoc(usize, syntax_pos::Span, String), + /// A doc fragment created from a `#[doc(include="filename")]` attribute. Contains both the + /// given filename and the file contents. + Include(usize, syntax_pos::Span, String, String), +} + +impl DocFragment { + pub fn as_str(&self) -> &str { + match *self { + DocFragment::SugaredDoc(_, _, ref s) => &s[..], + DocFragment::RawDoc(_, _, ref s) => &s[..], + DocFragment::Include(_, _, _, ref s) => &s[..], + } + } + + pub fn span(&self) -> syntax_pos::Span { + match *self { + DocFragment::SugaredDoc(_, span, _) | + DocFragment::RawDoc(_, span, _) | + DocFragment::Include(_, span, _, _) => span, + } + } +} + +impl<'a> FromIterator<&'a DocFragment> for String { + fn from_iter(iter: T) -> Self + where + T: IntoIterator + { + iter.into_iter().fold(String::new(), |mut acc, frag| { + if !acc.is_empty() { + acc.push('\n'); + } + match *frag { + DocFragment::SugaredDoc(_, _, ref docs) + | DocFragment::RawDoc(_, _, ref docs) + | DocFragment::Include(_, _, _, ref docs) => + acc.push_str(docs), + } + + acc + }) + } +} + +#[derive(Clone, Debug, Default)] +pub struct Attributes { + pub doc_strings: Vec, + pub other_attrs: Vec, + pub cfg: Option>, + pub span: Option, + /// map from Rust paths to resolved defs and potential URL fragments + pub links: Vec<(String, Option, Option)>, + pub inner_docs: bool, +} + +impl Attributes { + /// Extracts the content from an attribute `#[doc(cfg(content))]`. + pub fn extract_cfg(mi: &ast::MetaItem) -> Option<&ast::MetaItem> { + use syntax::ast::NestedMetaItem::MetaItem; + + if let ast::MetaItemKind::List(ref nmis) = mi.kind { + if nmis.len() == 1 { + if let MetaItem(ref cfg_mi) = nmis[0] { + if cfg_mi.check_name(sym::cfg) { + if let ast::MetaItemKind::List(ref cfg_nmis) = cfg_mi.kind { + if cfg_nmis.len() == 1 { + if let MetaItem(ref content_mi) = cfg_nmis[0] { + return Some(content_mi); + } + } + } + } + } + } + } + + None + } + + /// Reads a `MetaItem` from within an attribute, looks for whether it is a + /// `#[doc(include="file")]`, and returns the filename and contents of the file as loaded from + /// its expansion. + pub fn extract_include(mi: &ast::MetaItem) -> Option<(String, String)> { + mi.meta_item_list().and_then(|list| { + for meta in list { + if meta.check_name(sym::include) { + // the actual compiled `#[doc(include="filename")]` gets expanded to + // `#[doc(include(file="filename", contents="file contents")]` so we need to + // look for that instead + return meta.meta_item_list().and_then(|list| { + let mut filename: Option = None; + let mut contents: Option = None; + + for it in list { + if it.check_name(sym::file) { + if let Some(name) = it.value_str() { + filename = Some(name.to_string()); + } + } else if it.check_name(sym::contents) { + if let Some(docs) = it.value_str() { + contents = Some(docs.to_string()); + } + } + } + + if let (Some(filename), Some(contents)) = (filename, contents) { + Some((filename, contents)) + } else { + None + } + }); + } + } + + None + }) + } + + pub fn has_doc_flag(&self, flag: Symbol) -> bool { + for attr in &self.other_attrs { + if !attr.check_name(sym::doc) { continue; } + + if let Some(items) = attr.meta_item_list() { + if items.iter().filter_map(|i| i.meta_item()).any(|it| it.check_name(flag)) { + return true; + } + } + } + + false + } + + pub fn from_ast(diagnostic: &::errors::Handler, attrs: &[ast::Attribute]) -> Attributes { + let mut doc_strings = vec![]; + let mut sp = None; + let mut cfg = Cfg::True; + let mut doc_line = 0; + + /// If `attr` is a doc comment, strips the leading and (if present) + /// trailing comments symbols, e.g. `///`, `/**`, and `*/`. Otherwise, + /// returns `attr` unchanged. + pub fn with_doc_comment_markers_stripped( + attr: &Attribute, + f: impl FnOnce(&Attribute) -> T, + ) -> T { + match attr.kind { + AttrKind::Normal(_) => { + f(attr) + } + AttrKind::DocComment(comment) => { + let comment = + Symbol::intern(&comments::strip_doc_comment_decoration(&comment.as_str())); + f(&Attribute { + kind: AttrKind::DocComment(comment), + id: attr.id, + style: attr.style, + span: attr.span, + }) + } + } + } + + let other_attrs = attrs.iter().filter_map(|attr| { + with_doc_comment_markers_stripped(attr, |attr| { + if attr.check_name(sym::doc) { + if let Some(mi) = attr.meta() { + if let Some(value) = mi.value_str() { + // Extracted #[doc = "..."] + let value = value.to_string(); + let line = doc_line; + doc_line += value.lines().count(); + + if attr.is_doc_comment() { + doc_strings.push(DocFragment::SugaredDoc(line, attr.span, value)); + } else { + doc_strings.push(DocFragment::RawDoc(line, attr.span, value)); + } + + if sp.is_none() { + sp = Some(attr.span); + } + return None; + } else if let Some(cfg_mi) = Attributes::extract_cfg(&mi) { + // Extracted #[doc(cfg(...))] + match Cfg::parse(cfg_mi) { + Ok(new_cfg) => cfg &= new_cfg, + Err(e) => diagnostic.span_err(e.span, e.msg), + } + return None; + } else if let Some((filename, contents)) = Attributes::extract_include(&mi) + { + let line = doc_line; + doc_line += contents.lines().count(); + doc_strings.push(DocFragment::Include(line, + attr.span, + filename, + contents)); + } + } + } + Some(attr.clone()) + }) + }).collect(); + + // treat #[target_feature(enable = "feat")] attributes as if they were + // #[doc(cfg(target_feature = "feat"))] attributes as well + for attr in attrs.lists(sym::target_feature) { + if attr.check_name(sym::enable) { + if let Some(feat) = attr.value_str() { + let meta = attr::mk_name_value_item_str( + Ident::with_dummy_span(sym::target_feature), feat, DUMMY_SP + ); + if let Ok(feat_cfg) = Cfg::parse(&meta) { + cfg &= feat_cfg; + } + } + } + } + + let inner_docs = attrs.iter() + .filter(|a| a.check_name(sym::doc)) + .next() + .map_or(true, |a| a.style == AttrStyle::Inner); + + Attributes { + doc_strings, + other_attrs, + cfg: if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) }, + span: sp, + links: vec![], + inner_docs, + } + } + + /// Finds the `doc` attribute as a NameValue and returns the corresponding + /// value found. + pub fn doc_value(&self) -> Option<&str> { + self.doc_strings.first().map(|s| s.as_str()) + } + + /// Finds all `doc` attributes as NameValues and returns their corresponding values, joined + /// with newlines. + pub fn collapsed_doc_value(&self) -> Option { + if !self.doc_strings.is_empty() { + Some(self.doc_strings.iter().collect()) + } else { + None + } + } + + /// Gets links as a vector + /// + /// Cache must be populated before call + pub fn links(&self, krate: &CrateNum) -> Vec<(String, String)> { + use crate::html::format::href; + + self.links.iter().filter_map(|&(ref s, did, ref fragment)| { + match did { + Some(did) => { + if let Some((mut href, ..)) = href(did) { + if let Some(ref fragment) = *fragment { + href.push_str("#"); + href.push_str(fragment); + } + Some((s.clone(), href)) + } else { + None + } + } + None => { + if let Some(ref fragment) = *fragment { + let cache = cache(); + let url = match cache.extern_locations.get(krate) { + Some(&(_, ref src, ExternalLocation::Local)) => + src.to_str().expect("invalid file path"), + Some(&(_, _, ExternalLocation::Remote(ref s))) => s, + Some(&(_, _, ExternalLocation::Unknown)) | None => + "https://doc.rust-lang.org/nightly", + }; + // This is a primitive so the url is done "by hand". + let tail = fragment.find('#').unwrap_or_else(|| fragment.len()); + Some((s.clone(), + format!("{}{}std/primitive.{}.html{}", + url, + if !url.ends_with('/') { "/" } else { "" }, + &fragment[..tail], + &fragment[tail..]))) + } else { + panic!("This isn't a primitive?!"); + } + } + } + }).collect() + } +} + +impl PartialEq for Attributes { + fn eq(&self, rhs: &Self) -> bool { + self.doc_strings == rhs.doc_strings && + self.cfg == rhs.cfg && + self.span == rhs.span && + self.links == rhs.links && + self.other_attrs.iter().map(|attr| attr.id).eq(rhs.other_attrs.iter().map(|attr| attr.id)) + } +} + +impl Eq for Attributes {} + +impl Hash for Attributes { + fn hash(&self, hasher: &mut H) { + self.doc_strings.hash(hasher); + self.cfg.hash(hasher); + self.span.hash(hasher); + self.links.hash(hasher); + for attr in &self.other_attrs { + attr.id.hash(hasher); + } + } +} + +impl AttributesExt for Attributes { + fn lists(&self, name: Symbol) -> ListAttributesIter<'_> { + self.other_attrs.lists(name) + } +} + +#[derive(Clone, PartialEq, Eq, Debug, Hash)] +pub enum GenericBound { + TraitBound(PolyTrait, hir::TraitBoundModifier), + Outlives(Lifetime), +} + +impl GenericBound { + pub fn maybe_sized(cx: &DocContext<'_>) -> GenericBound { + let did = cx.tcx.require_lang_item(lang_items::SizedTraitLangItem, None); + let empty = cx.tcx.intern_substs(&[]); + let path = external_path(cx, cx.tcx.item_name(did), + Some(did), false, vec![], empty); + inline::record_extern_fqn(cx, did, TypeKind::Trait); + GenericBound::TraitBound(PolyTrait { + trait_: ResolvedPath { + path, + param_names: None, + did, + is_generic: false, + }, + generic_params: Vec::new(), + }, hir::TraitBoundModifier::Maybe) + } + + pub fn is_sized_bound(&self, cx: &DocContext<'_>) -> bool { + use rustc::hir::TraitBoundModifier as TBM; + if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, TBM::None) = *self { + if trait_.def_id() == cx.tcx.lang_items().sized_trait() { + return true; + } + } + false + } + + pub fn get_poly_trait(&self) -> Option { + if let GenericBound::TraitBound(ref p, _) = *self { + return Some(p.clone()) + } + None + } + + pub fn get_trait_type(&self) -> Option { + if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, _) = *self { + Some(trait_.clone()) + } else { + None + } + } +} + +#[derive(Clone, PartialEq, Eq, Debug, Hash)] +pub struct Lifetime(pub String); + +impl Lifetime { + pub fn get_ref<'a>(&'a self) -> &'a str { + let Lifetime(ref s) = *self; + let s: &'a str = s; + s + } + + pub fn statik() -> Lifetime { + Lifetime("'static".to_string()) + } +} + +#[derive(Clone, Debug)] +pub enum WherePredicate { + BoundPredicate { ty: Type, bounds: Vec }, + RegionPredicate { lifetime: Lifetime, bounds: Vec }, + EqPredicate { lhs: Type, rhs: Type }, +} + +impl WherePredicate { + pub fn get_bounds(&self) -> Option<&[GenericBound]> { + match *self { + WherePredicate::BoundPredicate { ref bounds, .. } => Some(bounds), + WherePredicate::RegionPredicate { ref bounds, .. } => Some(bounds), + _ => None, + } + } +} + +#[derive(Clone, PartialEq, Eq, Debug, Hash)] +pub enum GenericParamDefKind { + Lifetime, + Type { + did: DefId, + bounds: Vec, + default: Option, + synthetic: Option, + }, + Const { + did: DefId, + ty: Type, + }, +} + +impl GenericParamDefKind { + pub fn is_type(&self) -> bool { + match *self { + GenericParamDefKind::Type { .. } => true, + _ => false, + } + } + + // FIXME(eddyb) this either returns the default of a type parameter, or the + // type of a `const` parameter. It seems that the intention is to *visit* + // any embedded types, but `get_type` seems to be the wrong name for that. + pub fn get_type(&self) -> Option { + match self { + GenericParamDefKind::Type { default, .. } => default.clone(), + GenericParamDefKind::Const { ty, .. } => Some(ty.clone()), + GenericParamDefKind::Lifetime => None, + } + } +} + +#[derive(Clone, PartialEq, Eq, Debug, Hash)] +pub struct GenericParamDef { + pub name: String, + pub kind: GenericParamDefKind, +} + +impl GenericParamDef { + pub fn is_synthetic_type_param(&self) -> bool { + match self.kind { + GenericParamDefKind::Lifetime | + GenericParamDefKind::Const { .. } => false, + GenericParamDefKind::Type { ref synthetic, .. } => synthetic.is_some(), + } + } + + pub fn is_type(&self) -> bool { + self.kind.is_type() + } + + pub fn get_type(&self) -> Option { + self.kind.get_type() + } + + pub fn get_bounds(&self) -> Option<&[GenericBound]> { + match self.kind { + GenericParamDefKind::Type { ref bounds, .. } => Some(bounds), + _ => None, + } + } +} + +// maybe use a Generic enum and use Vec? +#[derive(Clone, Debug, Default)] +pub struct Generics { + pub params: Vec, + pub where_predicates: Vec, +} + +#[derive(Clone, Debug)] +pub struct Method { + pub generics: Generics, + pub decl: FnDecl, + pub header: hir::FnHeader, + pub defaultness: Option, + pub all_types: Vec, + pub ret_types: Vec, +} + +#[derive(Clone, Debug)] +pub struct TyMethod { + pub header: hir::FnHeader, + pub decl: FnDecl, + pub generics: Generics, + pub all_types: Vec, + pub ret_types: Vec, +} + +#[derive(Clone, Debug)] +pub struct Function { + pub decl: FnDecl, + pub generics: Generics, + pub header: hir::FnHeader, + pub all_types: Vec, + pub ret_types: Vec, +} + +#[derive(Clone, PartialEq, Eq, Debug, Hash)] +pub struct FnDecl { + pub inputs: Arguments, + pub output: FunctionRetTy, + pub c_variadic: bool, + pub attrs: Attributes, +} + +impl FnDecl { + pub fn self_type(&self) -> Option { + self.inputs.values.get(0).and_then(|v| v.to_self()) + } + + /// Returns the sugared return type for an async function. + /// + /// For example, if the return type is `impl std::future::Future`, this function + /// will return `i32`. + /// + /// # Panics + /// + /// This function will panic if the return type does not match the expected sugaring for async + /// functions. + pub fn sugared_async_return_type(&self) -> FunctionRetTy { + match &self.output { + FunctionRetTy::Return(Type::ImplTrait(bounds)) => { + match &bounds[0] { + GenericBound::TraitBound(PolyTrait { trait_, .. }, ..) => { + let bindings = trait_.bindings().unwrap(); + FunctionRetTy::Return(bindings[0].ty().clone()) + } + _ => panic!("unexpected desugaring of async function"), + } + } + _ => panic!("unexpected desugaring of async function"), + } + } +} + +#[derive(Clone, PartialEq, Eq, Debug, Hash)] +pub struct Arguments { + pub values: Vec, +} + +#[derive(Clone, PartialEq, Eq, Debug, Hash)] +pub struct Argument { + pub type_: Type, + pub name: String, +} + +#[derive(Clone, PartialEq, Debug)] +pub enum SelfTy { + SelfValue, + SelfBorrowed(Option, Mutability), + SelfExplicit(Type), +} + +impl Argument { + pub fn to_self(&self) -> Option { + if self.name != "self" { + return None; + } + if self.type_.is_self_type() { + return Some(SelfValue); + } + match self.type_ { + BorrowedRef{ref lifetime, mutability, ref type_} if type_.is_self_type() => { + Some(SelfBorrowed(lifetime.clone(), mutability)) + } + _ => Some(SelfExplicit(self.type_.clone())) + } + } +} + +#[derive(Clone, PartialEq, Eq, Debug, Hash)] +pub enum FunctionRetTy { + Return(Type), + DefaultReturn, +} + +impl GetDefId for FunctionRetTy { + fn def_id(&self) -> Option { + match *self { + Return(ref ty) => ty.def_id(), + DefaultReturn => None, + } + } +} + +#[derive(Clone, Debug)] +pub struct Trait { + pub auto: bool, + pub unsafety: hir::Unsafety, + pub items: Vec, + pub generics: Generics, + pub bounds: Vec, + pub is_spotlight: bool, + pub is_auto: bool, +} + +#[derive(Clone, Debug)] +pub struct TraitAlias { + pub generics: Generics, + pub bounds: Vec, +} + +/// A trait reference, which may have higher ranked lifetimes. +#[derive(Clone, PartialEq, Eq, Debug, Hash)] +pub struct PolyTrait { + pub trait_: Type, + pub generic_params: Vec, +} + +/// A representation of a type suitable for hyperlinking purposes. Ideally, one can get the original +/// type out of the AST/`TyCtxt` given one of these, if more information is needed. Most +/// importantly, it does not preserve mutability or boxes. +#[derive(Clone, PartialEq, Eq, Debug, Hash)] +pub enum Type { + /// Structs/enums/traits (most that would be an `hir::TyKind::Path`). + ResolvedPath { + path: Path, + param_names: Option>, + did: DefId, + /// `true` if is a `T::Name` path for associated types. + is_generic: bool, + }, + /// For parameterized types, so the consumer of the JSON don't go + /// looking for types which don't exist anywhere. + Generic(String), + /// Primitives are the fixed-size numeric types (plus int/usize/float), char, + /// arrays, slices, and tuples. + Primitive(PrimitiveType), + /// `extern "ABI" fn` + BareFunction(Box), + Tuple(Vec), + Slice(Box), + Array(Box, String), + Never, + RawPointer(Mutability, Box), + BorrowedRef { + lifetime: Option, + mutability: Mutability, + type_: Box, + }, + + // `::Name` + QPath { + name: String, + self_type: Box, + trait_: Box + }, + + // `_` + Infer, + + // `impl TraitA + TraitB + ...` + ImplTrait(Vec), +} + +#[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)] +pub enum PrimitiveType { + Isize, I8, I16, I32, I64, I128, + Usize, U8, U16, U32, U64, U128, + F32, F64, + Char, + Bool, + Str, + Slice, + Array, + Tuple, + Unit, + RawPointer, + Reference, + Fn, + Never, +} + +#[derive(Clone, Copy, Debug)] +pub enum TypeKind { + Enum, + Function, + Module, + Const, + Static, + Struct, + Union, + Trait, + Typedef, + Foreign, + Macro, + Attr, + Derive, + TraitAlias, +} + +pub trait GetDefId { + fn def_id(&self) -> Option; +} + +impl GetDefId for Option { + fn def_id(&self) -> Option { + self.as_ref().and_then(|d| d.def_id()) + } +} + +impl Type { + pub fn primitive_type(&self) -> Option { + match *self { + Primitive(p) | BorrowedRef { type_: box Primitive(p), ..} => Some(p), + Slice(..) | BorrowedRef { type_: box Slice(..), .. } => Some(PrimitiveType::Slice), + Array(..) | BorrowedRef { type_: box Array(..), .. } => Some(PrimitiveType::Array), + Tuple(ref tys) => if tys.is_empty() { + Some(PrimitiveType::Unit) + } else { + Some(PrimitiveType::Tuple) + }, + RawPointer(..) => Some(PrimitiveType::RawPointer), + BorrowedRef { type_: box Generic(..), .. } => Some(PrimitiveType::Reference), + BareFunction(..) => Some(PrimitiveType::Fn), + Never => Some(PrimitiveType::Never), + _ => None, + } + } + + pub fn is_generic(&self) -> bool { + match *self { + ResolvedPath { is_generic, .. } => is_generic, + _ => false, + } + } + + pub fn is_self_type(&self) -> bool { + match *self { + Generic(ref name) => name == "Self", + _ => false + } + } + + pub fn generics(&self) -> Option> { + match *self { + ResolvedPath { ref path, .. } => { + path.segments.last().and_then(|seg| { + if let GenericArgs::AngleBracketed { ref args, .. } = seg.args { + Some(args.iter().filter_map(|arg| match arg { + GenericArg::Type(ty) => Some(ty.clone()), + _ => None, + }).collect()) + } else { + None + } + }) + } + _ => None, + } + } + + pub fn bindings(&self) -> Option<&[TypeBinding]> { + match *self { + ResolvedPath { ref path, .. } => { + path.segments.last().and_then(|seg| { + if let GenericArgs::AngleBracketed { ref bindings, .. } = seg.args { + Some(&**bindings) + } else { + None + } + }) + } + _ => None + } + } + + pub fn is_full_generic(&self) -> bool { + match *self { + Type::Generic(_) => true, + _ => false, + } + } + + pub fn projection(&self) -> Option<(&Type, DefId, &str)> { + let (self_, trait_, name) = match self { + QPath { ref self_type, ref trait_, ref name } => { + (self_type, trait_, name) + } + _ => return None, + }; + let trait_did = match **trait_ { + ResolvedPath { did, .. } => did, + _ => return None, + }; + Some((&self_, trait_did, name)) + } + +} + +impl GetDefId for Type { + fn def_id(&self) -> Option { + match *self { + ResolvedPath { did, .. } => Some(did), + Primitive(p) => crate::html::render::cache().primitive_locations.get(&p).cloned(), + BorrowedRef { type_: box Generic(..), .. } => + Primitive(PrimitiveType::Reference).def_id(), + BorrowedRef { ref type_, .. } => type_.def_id(), + Tuple(ref tys) => if tys.is_empty() { + Primitive(PrimitiveType::Unit).def_id() + } else { + Primitive(PrimitiveType::Tuple).def_id() + }, + BareFunction(..) => Primitive(PrimitiveType::Fn).def_id(), + Never => Primitive(PrimitiveType::Never).def_id(), + Slice(..) => Primitive(PrimitiveType::Slice).def_id(), + Array(..) => Primitive(PrimitiveType::Array).def_id(), + RawPointer(..) => Primitive(PrimitiveType::RawPointer).def_id(), + QPath { ref self_type, .. } => self_type.def_id(), + _ => None, + } + } +} + +impl PrimitiveType { + pub fn from_str(s: &str) -> Option { + match s { + "isize" => Some(PrimitiveType::Isize), + "i8" => Some(PrimitiveType::I8), + "i16" => Some(PrimitiveType::I16), + "i32" => Some(PrimitiveType::I32), + "i64" => Some(PrimitiveType::I64), + "i128" => Some(PrimitiveType::I128), + "usize" => Some(PrimitiveType::Usize), + "u8" => Some(PrimitiveType::U8), + "u16" => Some(PrimitiveType::U16), + "u32" => Some(PrimitiveType::U32), + "u64" => Some(PrimitiveType::U64), + "u128" => Some(PrimitiveType::U128), + "bool" => Some(PrimitiveType::Bool), + "char" => Some(PrimitiveType::Char), + "str" => Some(PrimitiveType::Str), + "f32" => Some(PrimitiveType::F32), + "f64" => Some(PrimitiveType::F64), + "array" => Some(PrimitiveType::Array), + "slice" => Some(PrimitiveType::Slice), + "tuple" => Some(PrimitiveType::Tuple), + "unit" => Some(PrimitiveType::Unit), + "pointer" => Some(PrimitiveType::RawPointer), + "reference" => Some(PrimitiveType::Reference), + "fn" => Some(PrimitiveType::Fn), + "never" => Some(PrimitiveType::Never), + _ => None, + } + } + + pub fn as_str(&self) -> &'static str { + use self::PrimitiveType::*; + match *self { + Isize => "isize", + I8 => "i8", + I16 => "i16", + I32 => "i32", + I64 => "i64", + I128 => "i128", + Usize => "usize", + U8 => "u8", + U16 => "u16", + U32 => "u32", + U64 => "u64", + U128 => "u128", + F32 => "f32", + F64 => "f64", + Str => "str", + Bool => "bool", + Char => "char", + Array => "array", + Slice => "slice", + Tuple => "tuple", + Unit => "unit", + RawPointer => "pointer", + Reference => "reference", + Fn => "fn", + Never => "never", + } + } + + pub fn to_url_str(&self) -> &'static str { + self.as_str() + } +} + +impl From for PrimitiveType { + fn from(int_ty: ast::IntTy) -> PrimitiveType { + match int_ty { + ast::IntTy::Isize => PrimitiveType::Isize, + ast::IntTy::I8 => PrimitiveType::I8, + ast::IntTy::I16 => PrimitiveType::I16, + ast::IntTy::I32 => PrimitiveType::I32, + ast::IntTy::I64 => PrimitiveType::I64, + ast::IntTy::I128 => PrimitiveType::I128, + } + } +} + +impl From for PrimitiveType { + fn from(uint_ty: ast::UintTy) -> PrimitiveType { + match uint_ty { + ast::UintTy::Usize => PrimitiveType::Usize, + ast::UintTy::U8 => PrimitiveType::U8, + ast::UintTy::U16 => PrimitiveType::U16, + ast::UintTy::U32 => PrimitiveType::U32, + ast::UintTy::U64 => PrimitiveType::U64, + ast::UintTy::U128 => PrimitiveType::U128, + } + } +} + +impl From for PrimitiveType { + fn from(float_ty: ast::FloatTy) -> PrimitiveType { + match float_ty { + ast::FloatTy::F32 => PrimitiveType::F32, + ast::FloatTy::F64 => PrimitiveType::F64, + } + } +} + +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum Visibility { + Public, + Inherited, + Crate, + Restricted(DefId, Path), +} + +#[derive(Clone, Debug)] +pub struct Struct { + pub struct_type: doctree::StructType, + pub generics: Generics, + pub fields: Vec, + pub fields_stripped: bool, +} + +#[derive(Clone, Debug)] +pub struct Union { + pub struct_type: doctree::StructType, + pub generics: Generics, + pub fields: Vec, + pub fields_stripped: bool, +} + +/// This is a more limited form of the standard Struct, different in that +/// it lacks the things most items have (name, id, parameterization). Found +/// only as a variant in an enum. +#[derive(Clone, Debug)] +pub struct VariantStruct { + pub struct_type: doctree::StructType, + pub fields: Vec, + pub fields_stripped: bool, +} + +#[derive(Clone, Debug)] +pub struct Enum { + pub variants: IndexVec, + pub generics: Generics, + pub variants_stripped: bool, +} + +#[derive(Clone, Debug)] +pub struct Variant { + pub kind: VariantKind, +} + +#[derive(Clone, Debug)] +pub enum VariantKind { + CLike, + Tuple(Vec), + Struct(VariantStruct), +} + +#[derive(Clone, Debug)] +pub struct Span { + pub filename: FileName, + pub loline: usize, + pub locol: usize, + pub hiline: usize, + pub hicol: usize, + pub original: syntax_pos::Span, +} + +impl Span { + pub fn empty() -> Span { + Span { + filename: FileName::Anon(0), + loline: 0, locol: 0, + hiline: 0, hicol: 0, + original: syntax_pos::DUMMY_SP, + } + } + + pub fn span(&self) -> syntax_pos::Span { + self.original + } +} + +#[derive(Clone, PartialEq, Eq, Debug, Hash)] +pub struct Path { + pub global: bool, + pub res: Res, + pub segments: Vec, +} + +impl Path { + pub fn last_name(&self) -> &str { + self.segments.last().expect("segments were empty").name.as_str() + } +} + +#[derive(Clone, PartialEq, Eq, Debug, Hash)] +pub enum GenericArg { + Lifetime(Lifetime), + Type(Type), + Const(Constant), +} + +#[derive(Clone, PartialEq, Eq, Debug, Hash)] +pub enum GenericArgs { + AngleBracketed { + args: Vec, + bindings: Vec, + }, + Parenthesized { + inputs: Vec, + output: Option, + } +} + +#[derive(Clone, PartialEq, Eq, Debug, Hash)] +pub struct PathSegment { + pub name: String, + pub args: GenericArgs, +} + +#[derive(Clone, Debug)] +pub struct Typedef { + pub type_: Type, + pub generics: Generics, +} + +#[derive(Clone, Debug)] +pub struct OpaqueTy { + pub bounds: Vec, + pub generics: Generics, +} + +#[derive(Clone, PartialEq, Eq, Debug, Hash)] +pub struct BareFunctionDecl { + pub unsafety: hir::Unsafety, + pub generic_params: Vec, + pub decl: FnDecl, + pub abi: Abi, +} + +#[derive(Clone, Debug)] +pub struct Static { + pub type_: Type, + pub mutability: Mutability, + /// It's useful to have the value of a static documented, but I have no + /// desire to represent expressions (that'd basically be all of the AST, + /// which is huge!). So, have a string. + pub expr: String, +} + +#[derive(Clone, PartialEq, Eq, Hash, Debug)] +pub struct Constant { + pub type_: Type, + pub expr: String, +} + +#[derive(Debug, Clone, PartialEq, Eq, Copy, Hash)] +pub enum Mutability { + Mutable, + Immutable, +} + +#[derive(Clone, PartialEq, Debug)] +pub enum ImplPolarity { + Positive, + Negative, +} + +#[derive(Clone, Debug)] +pub struct Impl { + pub unsafety: hir::Unsafety, + pub generics: Generics, + pub provided_trait_methods: FxHashSet, + pub trait_: Option, + pub for_: Type, + pub items: Vec, + pub polarity: Option, + pub synthetic: bool, + pub blanket_impl: Option, +} + +#[derive(Clone, Debug)] +pub enum Import { + // use source as str; + Simple(String, ImportSource), + // use source::*; + Glob(ImportSource) +} + +#[derive(Clone, Debug)] +pub struct ImportSource { + pub path: Path, + pub did: Option, +} + +#[derive(Clone, Debug)] +pub struct Macro { + pub source: String, + pub imported_from: Option, +} + +#[derive(Clone, Debug)] +pub struct ProcMacro { + pub kind: MacroKind, + pub helpers: Vec, +} + +#[derive(Clone, Debug)] +pub struct Stability { + pub level: stability::StabilityLevel, + pub feature: Option, + pub since: String, + pub deprecation: Option, + pub unstable_reason: Option, + pub issue: Option, +} + +#[derive(Clone, Debug)] +pub struct Deprecation { + pub since: Option, + pub note: Option, +} + +/// An type binding on an associated type (e.g., `A = Bar` in `Foo` or +/// `A: Send + Sync` in `Foo`). +#[derive(Clone, PartialEq, Eq, Debug, Hash)] +pub struct TypeBinding { + pub name: String, + pub kind: TypeBindingKind, +} + +#[derive(Clone, PartialEq, Eq, Debug, Hash)] +pub enum TypeBindingKind { + Equality { + ty: Type, + }, + Constraint { + bounds: Vec, + }, +} + +impl TypeBinding { + pub fn ty(&self) -> &Type { + match self.kind { + TypeBindingKind::Equality { ref ty } => ty, + _ => panic!("expected equality type binding for parenthesized generic args"), + } + } +}