rust/src/librustdoc/clean/mod.rs

2602 lines
84 KiB
Rust
Raw Normal View History

// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
2013-08-15 16:28:54 -04:00
//! This module contains the "cleaned" pieces of the AST, and the functions
//! that clean them.
pub use self::ImplMethod::*;
pub use self::Type::*;
pub use self::PrimitiveType::*;
pub use self::TypeKind::*;
pub use self::StructField::*;
pub use self::VariantKind::*;
pub use self::Mutability::*;
pub use self::ViewItemInner::*;
pub use self::ViewPath::*;
pub use self::ItemEnum::*;
pub use self::Attribute::*;
pub use self::TyParamBound::*;
pub use self::SelfTy::*;
pub use self::FunctionRetTy::*;
pub use self::TraitMethod::*;
2013-08-15 16:28:54 -04:00
use syntax;
use syntax::ast;
use syntax::ast_util;
use syntax::ast_util::PostExpansionMethod;
use syntax::attr;
use syntax::attr::{AttributeMethods, AttrMetaMethods};
use syntax::codemap::{DUMMY_SP, Pos, Spanned};
2015-01-03 22:42:21 -05:00
use syntax::parse::token::{self, InternedString, special_idents};
use syntax::ptr::P;
2013-08-15 16:28:54 -04:00
use rustc_trans::back::link;
rustdoc: Generate hyperlinks between crates The general idea of hyperlinking between crates is that it should require as little configuration as possible, if any at all. In this vein, there are two separate ways to generate hyperlinks between crates: 1. When you're generating documentation for a crate 'foo' into folder 'doc', then if foo's external crate dependencies already have documented in the folder 'doc', then hyperlinks will be generated. This will work because all documentation is in the same folder, allowing links to work seamlessly both on the web and on the local filesystem browser. The rationale for this use case is a package with multiple libraries/crates that all want to link to one another, and you don't want to have to deal with going to the web. In theory this could be extended to have a RUST_PATH-style searching situtation, but I'm not sure that it would work seamlessly on the web as it does on the local filesystem, so I'm not attempting to explore this case in this pull request. I believe to fully realize this potential rustdoc would have to be acting as a server instead of a static site generator. 2. One of foo's external dependencies has a #[doc(html_root_url = "...")] attribute. This means that all hyperlinks to the dependency will be rooted at this url. This use case encompasses all packages using libstd/libextra. These two crates now have this attribute encoded (currently at the /doc/master url) and will be read by anything which has a dependency on libstd/libextra. This should also work for arbitrary crates in the wild that have online documentation. I don't like how the version is hard-wired into the url, but I think that this may be a case-by-case thing which doesn't end up being too bad in the long run. Closes #9539
2013-10-02 15:39:32 -07:00
use rustc::metadata::cstore;
use rustc::metadata::csearch;
use rustc::metadata::decoder;
use rustc::middle::def;
2015-01-03 22:42:21 -05:00
use rustc::middle::subst::{self, ParamSpace, VecPerParamSpace};
use rustc::middle::ty;
use rustc::middle::stability;
use rustc::session::config;
rustdoc: Generate hyperlinks between crates The general idea of hyperlinking between crates is that it should require as little configuration as possible, if any at all. In this vein, there are two separate ways to generate hyperlinks between crates: 1. When you're generating documentation for a crate 'foo' into folder 'doc', then if foo's external crate dependencies already have documented in the folder 'doc', then hyperlinks will be generated. This will work because all documentation is in the same folder, allowing links to work seamlessly both on the web and on the local filesystem browser. The rationale for this use case is a package with multiple libraries/crates that all want to link to one another, and you don't want to have to deal with going to the web. In theory this could be extended to have a RUST_PATH-style searching situtation, but I'm not sure that it would work seamlessly on the web as it does on the local filesystem, so I'm not attempting to explore this case in this pull request. I believe to fully realize this potential rustdoc would have to be acting as a server instead of a static site generator. 2. One of foo's external dependencies has a #[doc(html_root_url = "...")] attribute. This means that all hyperlinks to the dependency will be rooted at this url. This use case encompasses all packages using libstd/libextra. These two crates now have this attribute encoded (currently at the /doc/master url) and will be read by anything which has a dependency on libstd/libextra. This should also work for arbitrary crates in the wild that have online documentation. I don't like how the version is hard-wired into the url, but I think that this may be a case-by-case thing which doesn't end up being too bad in the long run. Closes #9539
2013-10-02 15:39:32 -07:00
use std::rc::Rc;
use std::u32;
use std::str::Str as StrTrait; // Conflicts with Str variant
use std::path::Path as FsPath; // Conflicts with Path struct
rustdoc: Generate hyperlinks between crates The general idea of hyperlinking between crates is that it should require as little configuration as possible, if any at all. In this vein, there are two separate ways to generate hyperlinks between crates: 1. When you're generating documentation for a crate 'foo' into folder 'doc', then if foo's external crate dependencies already have documented in the folder 'doc', then hyperlinks will be generated. This will work because all documentation is in the same folder, allowing links to work seamlessly both on the web and on the local filesystem browser. The rationale for this use case is a package with multiple libraries/crates that all want to link to one another, and you don't want to have to deal with going to the web. In theory this could be extended to have a RUST_PATH-style searching situtation, but I'm not sure that it would work seamlessly on the web as it does on the local filesystem, so I'm not attempting to explore this case in this pull request. I believe to fully realize this potential rustdoc would have to be acting as a server instead of a static site generator. 2. One of foo's external dependencies has a #[doc(html_root_url = "...")] attribute. This means that all hyperlinks to the dependency will be rooted at this url. This use case encompasses all packages using libstd/libextra. These two crates now have this attribute encoded (currently at the /doc/master url) and will be read by anything which has a dependency on libstd/libextra. This should also work for arbitrary crates in the wild that have online documentation. I don't like how the version is hard-wired into the url, but I think that this may be a case-by-case thing which doesn't end up being too bad in the long run. Closes #9539
2013-10-02 15:39:32 -07:00
use core::DocContext;
2013-08-15 16:28:54 -04:00
use doctree;
use visit_ast;
/// A stable identifier to the particular version of JSON output.
/// Increment this when the `Crate` and related structures change.
pub static SCHEMA_VERSION: &'static str = "0.8.3";
mod inline;
// extract the stability index for a node from tcx, if possible
fn get_stability(cx: &DocContext, def_id: ast::DefId) -> Option<Stability> {
cx.tcx_opt().and_then(|tcx| stability::lookup(tcx, def_id)).clean(cx)
}
2013-08-15 16:28:54 -04:00
pub trait Clean<T> {
fn clean(&self, cx: &DocContext) -> T;
2013-08-15 16:28:54 -04:00
}
impl<T: Clean<U>, U> Clean<Vec<U>> for Vec<T> {
fn clean(&self, cx: &DocContext) -> Vec<U> {
self.iter().map(|x| x.clean(cx)).collect()
}
}
impl<T: Clean<U>, U> Clean<VecPerParamSpace<U>> for VecPerParamSpace<T> {
fn clean(&self, cx: &DocContext) -> VecPerParamSpace<U> {
self.map(|x| x.clean(cx))
}
}
impl<T: Clean<U>, U> Clean<U> for P<T> {
fn clean(&self, cx: &DocContext) -> U {
(**self).clean(cx)
2013-08-15 16:28:54 -04:00
}
}
impl<T: Clean<U>, U> Clean<U> for Rc<T> {
fn clean(&self, cx: &DocContext) -> U {
(**self).clean(cx)
}
}
2013-08-15 16:28:54 -04:00
impl<T: Clean<U>, U> Clean<Option<U>> for Option<T> {
fn clean(&self, cx: &DocContext) -> Option<U> {
2013-08-15 16:28:54 -04:00
match self {
&None => None,
&Some(ref v) => Some(v.clean(cx))
2013-08-15 16:28:54 -04:00
}
}
}
impl<T, U> Clean<U> for ty::Binder<T> where T: Clean<U> {
fn clean(&self, cx: &DocContext) -> U {
self.0.clean(cx)
}
}
impl<T: Clean<U>, U> Clean<Vec<U>> for syntax::owned_slice::OwnedSlice<T> {
fn clean(&self, cx: &DocContext) -> Vec<U> {
self.iter().map(|x| x.clean(cx)).collect()
2013-08-15 16:28:54 -04:00
}
}
#[derive(Clone, RustcEncodable, RustcDecodable)]
2013-08-15 16:28:54 -04:00
pub struct Crate {
pub name: String,
pub src: FsPath,
pub module: Option<Item>,
pub externs: Vec<(ast::CrateNum, ExternalCrate)>,
pub primitives: Vec<PrimitiveType>,
2013-08-15 16:28:54 -04:00
}
impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> {
fn clean(&self, cx: &DocContext) -> Crate {
let mut externs = Vec::new();
2014-03-05 16:36:01 +02:00
cx.sess().cstore.iter_crate_data(|n, meta| {
externs.push((n, meta.clean(cx)));
});
externs.sort_by(|&(a, _), &(b, _)| a.cmp(&b));
2013-08-15 16:28:54 -04:00
// Figure out the name of this crate
let input = config::Input::File(cx.src.clone());
let name = link::find_crate_name(None, self.attrs.as_slice(), &input);
// Clean the crate, translating the entire libsyntax AST to one that is
// understood by rustdoc.
let mut module = self.module.clean(cx);
// Collect all inner modules which are tagged as implementations of
// primitives.
//
// Note that this loop only searches the top-level items of the crate,
// and this is intentional. If we were to search the entire crate for an
// item tagged with `#[doc(primitive)]` then we we would also have to
// search the entirety of external modules for items tagged
// `#[doc(primitive)]`, which is a pretty inefficient process (decoding
// all that metadata unconditionally).
//
// In order to keep the metadata load under control, the
// `#[doc(primitive)]` feature is explicitly designed to only allow the
// primitive tags to show up as the top level items in a crate.
//
// Also note that this does not attempt to deal with modules tagged
// duplicately for the same primitive. This is handled later on when
// rendering by delegating everything to a hash map.
let mut primitives = Vec::new();
{
let m = match module.inner {
ModuleItem(ref mut m) => m,
_ => unreachable!(),
};
let mut tmp = Vec::new();
2014-09-14 20:27:36 -07:00
for child in m.items.iter_mut() {
match child.inner {
ModuleItem(..) => {}
_ => continue,
}
let prim = match PrimitiveType::find(child.attrs.as_slice()) {
Some(prim) => prim,
None => continue,
};
primitives.push(prim);
tmp.push(Item {
source: Span::empty(),
name: Some(prim.to_url_str().to_string()),
attrs: child.attrs.clone(),
visibility: Some(ast::Public),
stability: None,
def_id: ast_util::local_def(prim.to_node_id()),
inner: PrimitiveItem(prim),
});
}
2014-09-14 20:27:36 -07:00
m.items.extend(tmp.into_iter());
}
2013-08-15 16:28:54 -04:00
Crate {
name: name.to_string(),
src: cx.src.clone(),
module: Some(module),
rustdoc: Generate hyperlinks between crates The general idea of hyperlinking between crates is that it should require as little configuration as possible, if any at all. In this vein, there are two separate ways to generate hyperlinks between crates: 1. When you're generating documentation for a crate 'foo' into folder 'doc', then if foo's external crate dependencies already have documented in the folder 'doc', then hyperlinks will be generated. This will work because all documentation is in the same folder, allowing links to work seamlessly both on the web and on the local filesystem browser. The rationale for this use case is a package with multiple libraries/crates that all want to link to one another, and you don't want to have to deal with going to the web. In theory this could be extended to have a RUST_PATH-style searching situtation, but I'm not sure that it would work seamlessly on the web as it does on the local filesystem, so I'm not attempting to explore this case in this pull request. I believe to fully realize this potential rustdoc would have to be acting as a server instead of a static site generator. 2. One of foo's external dependencies has a #[doc(html_root_url = "...")] attribute. This means that all hyperlinks to the dependency will be rooted at this url. This use case encompasses all packages using libstd/libextra. These two crates now have this attribute encoded (currently at the /doc/master url) and will be read by anything which has a dependency on libstd/libextra. This should also work for arbitrary crates in the wild that have online documentation. I don't like how the version is hard-wired into the url, but I think that this may be a case-by-case thing which doesn't end up being too bad in the long run. Closes #9539
2013-10-02 15:39:32 -07:00
externs: externs,
primitives: primitives,
rustdoc: Generate hyperlinks between crates The general idea of hyperlinking between crates is that it should require as little configuration as possible, if any at all. In this vein, there are two separate ways to generate hyperlinks between crates: 1. When you're generating documentation for a crate 'foo' into folder 'doc', then if foo's external crate dependencies already have documented in the folder 'doc', then hyperlinks will be generated. This will work because all documentation is in the same folder, allowing links to work seamlessly both on the web and on the local filesystem browser. The rationale for this use case is a package with multiple libraries/crates that all want to link to one another, and you don't want to have to deal with going to the web. In theory this could be extended to have a RUST_PATH-style searching situtation, but I'm not sure that it would work seamlessly on the web as it does on the local filesystem, so I'm not attempting to explore this case in this pull request. I believe to fully realize this potential rustdoc would have to be acting as a server instead of a static site generator. 2. One of foo's external dependencies has a #[doc(html_root_url = "...")] attribute. This means that all hyperlinks to the dependency will be rooted at this url. This use case encompasses all packages using libstd/libextra. These two crates now have this attribute encoded (currently at the /doc/master url) and will be read by anything which has a dependency on libstd/libextra. This should also work for arbitrary crates in the wild that have online documentation. I don't like how the version is hard-wired into the url, but I think that this may be a case-by-case thing which doesn't end up being too bad in the long run. Closes #9539
2013-10-02 15:39:32 -07:00
}
}
}
#[derive(Clone, RustcEncodable, RustcDecodable)]
rustdoc: Generate hyperlinks between crates The general idea of hyperlinking between crates is that it should require as little configuration as possible, if any at all. In this vein, there are two separate ways to generate hyperlinks between crates: 1. When you're generating documentation for a crate 'foo' into folder 'doc', then if foo's external crate dependencies already have documented in the folder 'doc', then hyperlinks will be generated. This will work because all documentation is in the same folder, allowing links to work seamlessly both on the web and on the local filesystem browser. The rationale for this use case is a package with multiple libraries/crates that all want to link to one another, and you don't want to have to deal with going to the web. In theory this could be extended to have a RUST_PATH-style searching situtation, but I'm not sure that it would work seamlessly on the web as it does on the local filesystem, so I'm not attempting to explore this case in this pull request. I believe to fully realize this potential rustdoc would have to be acting as a server instead of a static site generator. 2. One of foo's external dependencies has a #[doc(html_root_url = "...")] attribute. This means that all hyperlinks to the dependency will be rooted at this url. This use case encompasses all packages using libstd/libextra. These two crates now have this attribute encoded (currently at the /doc/master url) and will be read by anything which has a dependency on libstd/libextra. This should also work for arbitrary crates in the wild that have online documentation. I don't like how the version is hard-wired into the url, but I think that this may be a case-by-case thing which doesn't end up being too bad in the long run. Closes #9539
2013-10-02 15:39:32 -07:00
pub struct ExternalCrate {
pub name: String,
pub attrs: Vec<Attribute>,
pub primitives: Vec<PrimitiveType>,
rustdoc: Generate hyperlinks between crates The general idea of hyperlinking between crates is that it should require as little configuration as possible, if any at all. In this vein, there are two separate ways to generate hyperlinks between crates: 1. When you're generating documentation for a crate 'foo' into folder 'doc', then if foo's external crate dependencies already have documented in the folder 'doc', then hyperlinks will be generated. This will work because all documentation is in the same folder, allowing links to work seamlessly both on the web and on the local filesystem browser. The rationale for this use case is a package with multiple libraries/crates that all want to link to one another, and you don't want to have to deal with going to the web. In theory this could be extended to have a RUST_PATH-style searching situtation, but I'm not sure that it would work seamlessly on the web as it does on the local filesystem, so I'm not attempting to explore this case in this pull request. I believe to fully realize this potential rustdoc would have to be acting as a server instead of a static site generator. 2. One of foo's external dependencies has a #[doc(html_root_url = "...")] attribute. This means that all hyperlinks to the dependency will be rooted at this url. This use case encompasses all packages using libstd/libextra. These two crates now have this attribute encoded (currently at the /doc/master url) and will be read by anything which has a dependency on libstd/libextra. This should also work for arbitrary crates in the wild that have online documentation. I don't like how the version is hard-wired into the url, but I think that this may be a case-by-case thing which doesn't end up being too bad in the long run. Closes #9539
2013-10-02 15:39:32 -07:00
}
impl Clean<ExternalCrate> for cstore::crate_metadata {
fn clean(&self, cx: &DocContext) -> ExternalCrate {
let mut primitives = Vec::new();
cx.tcx_opt().map(|tcx| {
csearch::each_top_level_item_of_crate(&tcx.sess.cstore,
self.cnum,
|def, _, _| {
let did = match def {
decoder::DlDef(def::DefMod(did)) => did,
_ => return
};
let attrs = inline::load_attrs(cx, tcx, did);
PrimitiveType::find(attrs.as_slice()).map(|prim| primitives.push(prim));
})
});
rustdoc: Generate hyperlinks between crates The general idea of hyperlinking between crates is that it should require as little configuration as possible, if any at all. In this vein, there are two separate ways to generate hyperlinks between crates: 1. When you're generating documentation for a crate 'foo' into folder 'doc', then if foo's external crate dependencies already have documented in the folder 'doc', then hyperlinks will be generated. This will work because all documentation is in the same folder, allowing links to work seamlessly both on the web and on the local filesystem browser. The rationale for this use case is a package with multiple libraries/crates that all want to link to one another, and you don't want to have to deal with going to the web. In theory this could be extended to have a RUST_PATH-style searching situtation, but I'm not sure that it would work seamlessly on the web as it does on the local filesystem, so I'm not attempting to explore this case in this pull request. I believe to fully realize this potential rustdoc would have to be acting as a server instead of a static site generator. 2. One of foo's external dependencies has a #[doc(html_root_url = "...")] attribute. This means that all hyperlinks to the dependency will be rooted at this url. This use case encompasses all packages using libstd/libextra. These two crates now have this attribute encoded (currently at the /doc/master url) and will be read by anything which has a dependency on libstd/libextra. This should also work for arbitrary crates in the wild that have online documentation. I don't like how the version is hard-wired into the url, but I think that this may be a case-by-case thing which doesn't end up being too bad in the long run. Closes #9539
2013-10-02 15:39:32 -07:00
ExternalCrate {
name: self.name.to_string(),
attrs: decoder::get_crate_attributes(self.data()).clean(cx),
primitives: primitives,
2013-08-15 16:28:54 -04:00
}
}
}
/// 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, RustcEncodable, RustcDecodable)]
2013-08-15 16:28:54 -04:00
pub struct Item {
/// Stringified span
pub source: Span,
2013-08-15 16:28:54 -04:00
/// Not everything has a name. E.g., impls
pub name: Option<String>,
pub attrs: Vec<Attribute> ,
pub inner: ItemEnum,
pub visibility: Option<Visibility>,
pub def_id: ast::DefId,
pub stability: Option<Stability>,
2013-08-15 16:28:54 -04:00
}
impl Item {
/// Finds the `doc` attribute as a List and returns the list of attributes
/// nested inside.
pub fn doc_list<'a>(&'a self) -> Option<&'a [Attribute]> {
for attr in self.attrs.iter() {
match *attr {
List(ref x, ref list) if "doc" == *x => {
return Some(list.as_slice());
}
_ => {}
}
}
return None;
}
/// Finds the `doc` attribute as a NameValue and returns the corresponding
/// value found.
pub fn doc_value<'a>(&'a self) -> Option<&'a str> {
for attr in self.attrs.iter() {
match *attr {
NameValue(ref x, ref v) if "doc" == *x => {
return Some(v.as_slice());
}
_ => {}
}
}
return None;
}
pub fn is_hidden_from_doc(&self) -> bool {
match self.doc_list() {
Some(ref l) => {
for innerattr in l.iter() {
match *innerattr {
Word(ref s) if "hidden" == *s => {
return true
}
_ => (),
}
}
},
None => ()
}
return false;
}
pub fn is_mod(&self) -> bool {
2013-11-28 12:22:53 -08:00
match self.inner { ModuleItem(..) => true, _ => false }
}
pub fn is_trait(&self) -> bool {
2013-11-28 12:22:53 -08:00
match self.inner { TraitItem(..) => true, _ => false }
}
pub fn is_struct(&self) -> bool {
2013-11-28 12:22:53 -08:00
match self.inner { StructItem(..) => true, _ => false }
}
pub fn is_enum(&self) -> bool {
2013-11-28 12:22:53 -08:00
match self.inner { EnumItem(..) => true, _ => false }
}
pub fn is_fn(&self) -> bool {
2013-11-28 12:22:53 -08:00
match self.inner { FunctionItem(..) => true, _ => false }
}
}
#[derive(Clone, RustcEncodable, RustcDecodable)]
2013-08-15 16:28:54 -04:00
pub enum ItemEnum {
StructItem(Struct),
EnumItem(Enum),
FunctionItem(Function),
ModuleItem(Module),
TypedefItem(Typedef),
StaticItem(Static),
ConstantItem(Constant),
2013-08-15 16:28:54 -04:00
TraitItem(Trait),
ImplItem(Impl),
2014-03-16 19:12:00 -04:00
/// `use` and `extern crate`
2013-08-15 16:28:54 -04:00
ViewItemItem(ViewItem),
2014-03-16 19:12:00 -04:00
/// A method signature only. Used for required methods in traits (ie,
/// non-default-methods).
2013-08-15 16:28:54 -04:00
TyMethodItem(TyMethod),
2014-03-16 19:12:00 -04:00
/// A method with a body.
2013-08-15 16:28:54 -04:00
MethodItem(Method),
StructFieldItem(StructField),
VariantItem(Variant),
2014-03-16 19:12:00 -04:00
/// `fn`s from an extern block
ForeignFunctionItem(Function),
2014-03-16 19:12:00 -04:00
/// `static`s from an extern block
ForeignStaticItem(Static),
MacroItem(Macro),
PrimitiveItem(PrimitiveType),
AssociatedTypeItem(TyParam),
2013-08-15 16:28:54 -04:00
}
#[derive(Clone, RustcEncodable, RustcDecodable)]
2013-08-15 16:28:54 -04:00
pub struct Module {
pub items: Vec<Item>,
pub is_crate: bool,
2013-08-15 16:28:54 -04:00
}
impl Clean<Item> for doctree::Module {
fn clean(&self, cx: &DocContext) -> Item {
2013-08-15 16:28:54 -04:00
let name = if self.name.is_some() {
self.name.unwrap().clean(cx)
2013-08-15 16:28:54 -04:00
} else {
"".to_string()
2013-08-15 16:28:54 -04:00
};
let mut foreigns = Vec::new();
2014-09-14 20:27:36 -07:00
for subforeigns in self.foreigns.clean(cx).into_iter() {
for foreign in subforeigns.into_iter() {
foreigns.push(foreign)
}
}
let items: Vec<Vec<Item> > = vec!(
self.structs.clean(cx),
self.enums.clean(cx),
self.fns.clean(cx),
foreigns,
self.mods.clean(cx),
self.typedefs.clean(cx),
self.statics.clean(cx),
self.constants.clean(cx),
self.traits.clean(cx),
self.impls.clean(cx),
2014-09-14 20:27:36 -07:00
self.view_items.clean(cx).into_iter()
.flat_map(|s| s.into_iter()).collect(),
self.macros.clean(cx),
);
// determine if we should display the inner contents or
// the outer `mod` item for the source code.
let whence = {
let cm = cx.sess().codemap();
let outer = cm.lookup_char_pos(self.where_outer.lo);
let inner = cm.lookup_char_pos(self.where_inner.lo);
if outer.file.start_pos == inner.file.start_pos {
// mod foo { ... }
self.where_outer
} else {
// mod foo; (and a separate FileMap for the contents)
self.where_inner
}
};
2013-08-15 16:28:54 -04:00
Item {
name: Some(name),
attrs: self.attrs.clean(cx),
source: whence.clean(cx),
visibility: self.vis.clean(cx),
stability: self.stab.clean(cx),
def_id: ast_util::local_def(self.id),
2013-08-15 16:28:54 -04:00
inner: ModuleItem(Module {
is_crate: self.is_crate,
items: items.iter()
.flat_map(|x| x.iter().map(|x| (*x).clone()))
.collect(),
2013-08-15 16:28:54 -04:00
})
}
}
}
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Show)]
2013-08-15 16:28:54 -04:00
pub enum Attribute {
Word(String),
List(String, Vec<Attribute> ),
NameValue(String, String)
2013-08-15 16:28:54 -04:00
}
impl Clean<Attribute> for ast::MetaItem {
fn clean(&self, cx: &DocContext) -> Attribute {
2013-08-15 16:28:54 -04:00
match self.node {
ast::MetaWord(ref s) => Word(s.get().to_string()),
ast::MetaList(ref s, ref l) => {
List(s.get().to_string(), l.clean(cx))
}
ast::MetaNameValue(ref s, ref v) => {
NameValue(s.get().to_string(), lit_to_string(v))
}
2013-08-15 16:28:54 -04:00
}
}
}
impl Clean<Attribute> for ast::Attribute {
fn clean(&self, cx: &DocContext) -> Attribute {
self.with_desugared_doc(|a| a.node.value.clean(cx))
2013-08-15 16:28:54 -04:00
}
}
// This is a rough approximation that gets us what we want.
impl attr::AttrMetaMethods for Attribute {
fn name(&self) -> InternedString {
match *self {
Word(ref n) | List(ref n, _) | NameValue(ref n, _) => {
token::intern_and_get_ident(n.as_slice())
}
}
}
fn value_str(&self) -> Option<InternedString> {
match *self {
NameValue(_, ref v) => {
Some(token::intern_and_get_ident(v.as_slice()))
}
_ => None,
}
}
fn meta_item_list<'a>(&'a self) -> Option<&'a [P<ast::MetaItem>]> { None }
}
impl<'a> attr::AttrMetaMethods for &'a Attribute {
fn name(&self) -> InternedString { (**self).name() }
fn value_str(&self) -> Option<InternedString> { (**self).value_str() }
2014-12-12 11:09:32 -05:00
fn meta_item_list(&self) -> Option<&[P<ast::MetaItem>]> { None }
}
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Show)]
2013-08-15 16:28:54 -04:00
pub struct TyParam {
pub name: String,
pub did: ast::DefId,
pub bounds: Vec<TyParamBound>,
pub default: Option<Type>,
}
2013-08-15 16:28:54 -04:00
impl Clean<TyParam> for ast::TyParam {
fn clean(&self, cx: &DocContext) -> TyParam {
2013-08-15 16:28:54 -04:00
TyParam {
name: self.ident.clean(cx),
did: ast::DefId { krate: ast::LOCAL_CRATE, node: self.id },
bounds: self.bounds.clean(cx),
default: self.default.clean(cx),
2013-08-15 16:28:54 -04:00
}
}
}
impl<'tcx> Clean<TyParam> for ty::TypeParameterDef<'tcx> {
fn clean(&self, cx: &DocContext) -> TyParam {
cx.external_typarams.borrow_mut().as_mut().unwrap()
.insert(self.def_id, self.name.clean(cx));
2014-12-24 22:34:57 +13:00
let bounds = self.bounds.clean(cx);
TyParam {
name: self.name.clean(cx),
did: self.def_id,
bounds: bounds,
default: self.default.clean(cx),
}
}
}
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Show)]
2013-08-15 16:28:54 -04:00
pub enum TyParamBound {
RegionBound(Lifetime),
2014-12-24 22:34:57 +13:00
TraitBound(PolyTrait, ast::TraitBoundModifier)
2013-08-15 16:28:54 -04:00
}
impl Clean<TyParamBound> for ast::TyParamBound {
fn clean(&self, cx: &DocContext) -> TyParamBound {
2013-08-15 16:28:54 -04:00
match *self {
ast::RegionTyParamBound(lt) => RegionBound(lt.clean(cx)),
2014-12-24 22:34:57 +13:00
ast::TraitTyParamBound(ref t, modifier) => TraitBound(t.clean(cx), modifier),
2013-08-15 16:28:54 -04:00
}
}
}
impl<'tcx> Clean<(Vec<TyParamBound>, Vec<TypeBinding>)> for ty::ExistentialBounds<'tcx> {
fn clean(&self, cx: &DocContext) -> (Vec<TyParamBound>, Vec<TypeBinding>) {
let mut tp_bounds = vec![];
self.region_bound.clean(cx).map(|b| tp_bounds.push(RegionBound(b)));
for bb in self.builtin_bounds.iter() {
tp_bounds.push(bb.clean(cx));
}
2014-12-29 11:02:24 -05:00
let mut bindings = vec![];
for &ty::Binder(ref pb) in self.projection_bounds.iter() {
bindings.push(TypeBinding {
name: pb.projection_ty.item_name.clean(cx),
ty: pb.ty.clean(cx)
});
}
2014-12-29 11:02:24 -05:00
(tp_bounds, bindings)
}
}
fn external_path_params(cx: &DocContext, trait_did: Option<ast::DefId>,
bindings: Vec<TypeBinding>, substs: &subst::Substs) -> PathParameters {
use rustc::middle::ty::sty;
let lifetimes = substs.regions().get_slice(subst::TypeSpace)
.iter()
.filter_map(|v| v.clean(cx))
.collect();
2014-09-17 12:56:31 -07:00
let types = substs.types.get_slice(subst::TypeSpace).to_vec();
match (trait_did, cx.tcx_opt()) {
// Attempt to sugar an external path like Fn<(A, B,), C> to Fn(A, B) -> C
(Some(did), Some(ref tcx)) if tcx.lang_items.fn_trait_kind(did).is_some() => {
assert_eq!(types.len(), 2);
let inputs = match types[0].sty {
sty::ty_tup(ref tys) => tys.iter().map(|t| t.clean(cx)).collect(),
_ => {
return PathParameters::AngleBracketed {
lifetimes: lifetimes,
types: types.clean(cx),
bindings: bindings
}
}
};
let output = match types[1].sty {
sty::ty_tup(ref v) if v.is_empty() => None, // -> ()
_ => Some(types[1].clean(cx))
};
PathParameters::Parenthesized {
inputs: inputs,
output: output
}
},
(_, _) => {
PathParameters::AngleBracketed {
lifetimes: lifetimes,
types: types.clean(cx),
bindings: bindings
}
}
}
}
// trait_did should be set to a trait's DefId if called on a TraitRef, in order to sugar
// from Fn<(A, B,), C> to Fn(A, B) -> C
fn external_path(cx: &DocContext, name: &str, trait_did: Option<ast::DefId>,
bindings: Vec<TypeBinding>, substs: &subst::Substs) -> Path {
Path {
global: false,
segments: vec![PathSegment {
name: name.to_string(),
params: external_path_params(cx, trait_did, bindings, substs)
}],
}
}
impl Clean<TyParamBound> for ty::BuiltinBound {
fn clean(&self, cx: &DocContext) -> TyParamBound {
let tcx = match cx.tcx_opt() {
Some(tcx) => tcx,
None => return RegionBound(Lifetime::statik())
};
let empty = subst::Substs::empty();
let (did, path) = match *self {
ty::BoundSend =>
(tcx.lang_items.send_trait().unwrap(),
external_path(cx, "Send", None, vec![], &empty)),
ty::BoundSized =>
(tcx.lang_items.sized_trait().unwrap(),
external_path(cx, "Sized", None, vec![], &empty)),
ty::BoundCopy =>
(tcx.lang_items.copy_trait().unwrap(),
external_path(cx, "Copy", None, vec![], &empty)),
ty::BoundSync =>
(tcx.lang_items.sync_trait().unwrap(),
external_path(cx, "Sync", None, vec![], &empty)),
};
let fqn = csearch::get_item_path(tcx, did);
2014-09-14 20:27:36 -07:00
let fqn = fqn.into_iter().map(|i| i.to_string()).collect();
2014-08-18 17:52:38 -07:00
cx.external_paths.borrow_mut().as_mut().unwrap().insert(did,
(fqn, TypeTrait));
TraitBound(PolyTrait {
trait_: ResolvedPath {
path: path,
typarams: None,
did: did,
},
lifetimes: vec![]
2014-12-24 22:34:57 +13:00
}, ast::TraitBoundModifier::None)
}
}
impl<'tcx> Clean<TyParamBound> for ty::TraitRef<'tcx> {
fn clean(&self, cx: &DocContext) -> TyParamBound {
let tcx = match cx.tcx_opt() {
Some(tcx) => tcx,
None => return RegionBound(Lifetime::statik())
};
let fqn = csearch::get_item_path(tcx, self.def_id);
2014-09-14 20:27:36 -07:00
let fqn = fqn.into_iter().map(|i| i.to_string())
.collect::<Vec<String>>();
let path = external_path(cx, fqn.last().unwrap().as_slice(),
Some(self.def_id), vec![], self.substs);
2014-08-18 17:52:38 -07:00
cx.external_paths.borrow_mut().as_mut().unwrap().insert(self.def_id,
(fqn, TypeTrait));
debug!("ty::TraitRef\n substs.types(TypeSpace): {:?}\n",
self.substs.types.get_slice(ParamSpace::TypeSpace));
// collect any late bound regions
let mut late_bounds = vec![];
for &ty_s in self.substs.types.get_slice(ParamSpace::TypeSpace).iter() {
use rustc::middle::ty::{Region, sty};
if let sty::ty_tup(ref ts) = ty_s.sty {
for &ty_s in ts.iter() {
if let sty::ty_rptr(ref reg, _) = ty_s.sty {
2014-12-26 22:33:56 +11:00
if let &Region::ReLateBound(_, _) = *reg {
debug!(" hit an ReLateBound {:?}", reg);
if let Some(lt) = reg.clean(cx) {
late_bounds.push(lt)
}
}
}
}
}
}
TraitBound(PolyTrait {
trait_: ResolvedPath { path: path, typarams: None, did: self.def_id, },
lifetimes: late_bounds
2014-12-24 22:34:57 +13:00
}, ast::TraitBoundModifier::None)
}
}
2014-12-24 22:34:57 +13:00
impl<'tcx> Clean<Vec<TyParamBound>> for ty::ParamBounds<'tcx> {
fn clean(&self, cx: &DocContext) -> Vec<TyParamBound> {
let mut v = Vec::new();
for t in self.trait_bounds.iter() {
v.push(t.clean(cx));
}
for r in self.region_bounds.iter().filter_map(|r| r.clean(cx)) {
v.push(RegionBound(r));
}
2014-12-24 22:34:57 +13:00
v
}
}
impl<'tcx> Clean<Option<Vec<TyParamBound>>> for subst::Substs<'tcx> {
fn clean(&self, cx: &DocContext) -> Option<Vec<TyParamBound>> {
let mut v = Vec::new();
v.extend(self.regions().iter().filter_map(|r| r.clean(cx)).map(RegionBound));
v.extend(self.types.iter().map(|t| TraitBound(PolyTrait {
trait_: t.clean(cx),
lifetimes: vec![]
2014-12-24 22:34:57 +13:00
}, ast::TraitBoundModifier::None)));
if v.len() > 0 {Some(v)} else {None}
}
}
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Show)]
pub struct Lifetime(String);
2013-08-15 16:28:54 -04:00
impl Lifetime {
pub fn get_ref<'a>(&'a self) -> &'a str {
let Lifetime(ref s) = *self;
let s: &'a str = s.as_slice();
return s;
}
pub fn statik() -> Lifetime {
Lifetime("'static".to_string())
}
}
2013-08-15 16:28:54 -04:00
impl Clean<Lifetime> for ast::Lifetime {
fn clean(&self, _: &DocContext) -> Lifetime {
Lifetime(token::get_name(self.name).get().to_string())
2013-08-15 16:28:54 -04:00
}
}
impl Clean<Lifetime> for ast::LifetimeDef {
fn clean(&self, _: &DocContext) -> Lifetime {
Lifetime(token::get_name(self.lifetime.name).get().to_string())
}
}
impl Clean<Lifetime> for ty::RegionParameterDef {
fn clean(&self, _: &DocContext) -> Lifetime {
Lifetime(token::get_name(self.name).get().to_string())
}
}
impl Clean<Option<Lifetime>> for ty::Region {
fn clean(&self, cx: &DocContext) -> Option<Lifetime> {
match *self {
ty::ReStatic => Some(Lifetime::statik()),
ty::ReLateBound(_, ty::BrNamed(_, name)) =>
Some(Lifetime(token::get_name(name).get().to_string())),
ty::ReEarlyBound(_, _, _, name) => Some(Lifetime(name.clean(cx))),
ty::ReLateBound(..) |
ty::ReFree(..) |
ty::ReScope(..) |
ty::ReInfer(..) |
ty::ReEmpty(..) => None
}
}
}
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Show)]
pub enum WherePredicate {
BoundPredicate { ty: Type, bounds: Vec<TyParamBound> },
RegionPredicate { lifetime: Lifetime, bounds: Vec<Lifetime>},
EqPredicate { lhs: Type, rhs: Type }
}
impl Clean<WherePredicate> for ast::WherePredicate {
fn clean(&self, cx: &DocContext) -> WherePredicate {
2014-12-02 15:03:02 -08:00
match *self {
ast::WherePredicate::BoundPredicate(ref wbp) => {
WherePredicate::BoundPredicate {
ty: wbp.bounded_ty.clean(cx),
2014-12-02 15:03:02 -08:00
bounds: wbp.bounds.clean(cx)
}
}
ast::WherePredicate::RegionPredicate(ref wrp) => {
WherePredicate::RegionPredicate {
lifetime: wrp.lifetime.clean(cx),
bounds: wrp.bounds.clean(cx)
}
}
ast::WherePredicate::EqPredicate(_) => {
unimplemented!() // FIXME(#20041)
2014-12-02 15:03:02 -08:00
}
}
}
}
impl<'a> Clean<WherePredicate> for ty::Predicate<'a> {
fn clean(&self, cx: &DocContext) -> WherePredicate {
use rustc::middle::ty::Predicate;
match *self {
Predicate::Trait(ref pred) => pred.clean(cx),
Predicate::Equate(ref pred) => pred.clean(cx),
Predicate::RegionOutlives(ref pred) => pred.clean(cx),
Predicate::TypeOutlives(ref pred) => pred.clean(cx),
Predicate::Projection(ref pred) => pred.clean(cx)
}
}
}
impl<'a> Clean<WherePredicate> for ty::TraitPredicate<'a> {
fn clean(&self, cx: &DocContext) -> WherePredicate {
WherePredicate::BoundPredicate {
ty: self.trait_ref.substs.self_ty().clean(cx).unwrap(),
bounds: vec![self.trait_ref.clean(cx)]
}
}
}
impl<'tcx> Clean<WherePredicate> for ty::EquatePredicate<'tcx> {
fn clean(&self, cx: &DocContext) -> WherePredicate {
let ty::EquatePredicate(ref lhs, ref rhs) = *self;
WherePredicate::EqPredicate {
lhs: lhs.clean(cx),
rhs: rhs.clean(cx)
}
}
}
impl Clean<WherePredicate> for ty::OutlivesPredicate<ty::Region, ty::Region> {
fn clean(&self, cx: &DocContext) -> WherePredicate {
let ty::OutlivesPredicate(ref a, ref b) = *self;
WherePredicate::RegionPredicate {
lifetime: a.clean(cx).unwrap(),
bounds: vec![b.clean(cx).unwrap()]
}
}
}
impl<'tcx> Clean<WherePredicate> for ty::OutlivesPredicate<ty::Ty<'tcx>, ty::Region> {
fn clean(&self, cx: &DocContext) -> WherePredicate {
let ty::OutlivesPredicate(ref ty, ref lt) = *self;
WherePredicate::BoundPredicate {
ty: ty.clean(cx),
bounds: vec![TyParamBound::RegionBound(lt.clean(cx).unwrap())]
}
}
}
impl<'tcx> Clean<WherePredicate> for ty::ProjectionPredicate<'tcx> {
fn clean(&self, cx: &DocContext) -> WherePredicate {
WherePredicate::EqPredicate {
lhs: self.projection_ty.clean(cx),
rhs: self.ty.clean(cx)
}
}
}
impl<'tcx> Clean<Type> for ty::ProjectionTy<'tcx> {
fn clean(&self, cx: &DocContext) -> Type {
let trait_ = match self.trait_ref.clean(cx) {
TyParamBound::TraitBound(t, _) => t.trait_,
TyParamBound::RegionBound(_) => panic!("cleaning a trait got a region??"),
};
Type::QPath {
name: self.item_name.clean(cx),
self_type: box self.trait_ref.self_ty().clean(cx),
trait_: box trait_
}
}
}
2013-08-15 16:28:54 -04:00
// maybe use a Generic enum and use ~[Generic]?
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Show)]
2013-08-15 16:28:54 -04:00
pub struct Generics {
pub lifetimes: Vec<Lifetime>,
pub type_params: Vec<TyParam>,
pub where_predicates: Vec<WherePredicate>
}
2013-08-15 16:28:54 -04:00
impl Clean<Generics> for ast::Generics {
fn clean(&self, cx: &DocContext) -> Generics {
2013-08-15 16:28:54 -04:00
Generics {
lifetimes: self.lifetimes.clean(cx),
type_params: self.ty_params.clean(cx),
where_predicates: self.where_clause.predicates.clean(cx)
2013-08-15 16:28:54 -04:00
}
}
}
impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics<'tcx>, subst::ParamSpace) {
fn clean(&self, cx: &DocContext) -> Generics {
use std::collections::HashSet;
use syntax::ast::TraitBoundModifier as TBM;
use self::WherePredicate as WP;
fn has_sized_bound(bounds: &[TyParamBound], cx: &DocContext) -> bool {
if let Some(tcx) = cx.tcx_opt() {
let sized_did = match tcx.lang_items.sized_trait() {
Some(did) => did,
None => return false
};
for bound in bounds.iter() {
if let TyParamBound::TraitBound(PolyTrait {
trait_: Type::ResolvedPath { did, .. }, ..
}, TBM::None) = *bound {
if did == sized_did {
return true
}
}
}
}
false
}
let (gens, space) = *self;
// Bounds in the type_params and lifetimes fields are repeated in the predicates
// field (see rustc_typeck::collect::ty_generics), so remove them.
let stripped_typarams = gens.types.get_slice(space).iter().map(|tp| {
let mut stp = tp.clone();
stp.bounds = ty::ParamBounds::empty();
stp.clean(cx)
}).collect::<Vec<_>>();
let stripped_lifetimes = gens.regions.get_slice(space).iter().map(|rp| {
let mut srp = rp.clone();
srp.bounds = Vec::new();
srp.clean(cx)
}).collect::<Vec<_>>();
let where_predicates = gens.predicates.get_slice(space).to_vec().clean(cx);
// Type parameters have a Sized bound by default unless removed with ?Sized.
// Scan through the predicates and mark any type parameter with a Sized
// bound, removing the bounds as we find them.
let mut sized_params = HashSet::new();
let mut where_predicates = where_predicates.into_iter().filter_map(|pred| {
if let WP::BoundPredicate { ty: Type::Generic(ref g), ref bounds } = pred {
if has_sized_bound(&**bounds, cx) {
sized_params.insert(g.clone());
return None
}
}
Some(pred)
}).collect::<Vec<_>>();
// Finally, run through the type parameters again and insert a ?Sized unbound for
// any we didn't find to be Sized.
for tp in stripped_typarams.iter() {
if !sized_params.contains(&tp.name) {
let mut sized_bound = ty::BuiltinBound::BoundSized.clean(cx);
if let TyParamBound::TraitBound(_, ref mut tbm) = sized_bound {
*tbm = TBM::Maybe
};
where_predicates.push(WP::BoundPredicate {
ty: Type::Generic(tp.name.clone()),
bounds: vec![sized_bound]
})
}
}
// It would be nice to collect all of the bounds on a type and recombine
// them if possible, to avoid e.g. `where T: Foo, T: Bar, T: Sized, T: 'a`
// and instead see `where T: Foo + Bar + Sized + 'a`
Generics {
type_params: stripped_typarams,
lifetimes: stripped_lifetimes,
where_predicates: where_predicates
}
}
}
#[derive(Clone, RustcEncodable, RustcDecodable)]
2013-08-15 16:28:54 -04:00
pub struct Method {
pub generics: Generics,
pub self_: SelfTy,
2014-12-09 10:36:46 -05:00
pub unsafety: ast::Unsafety,
pub decl: FnDecl,
2013-08-15 16:28:54 -04:00
}
impl Clean<Item> for ast::Method {
fn clean(&self, cx: &DocContext) -> Item {
let all_inputs = &self.pe_fn_decl().inputs;
let inputs = match self.pe_explicit_self().node {
ast::SelfStatic => all_inputs.as_slice(),
2015-01-07 11:58:31 -05:00
_ => &all_inputs[1..]
};
let decl = FnDecl {
inputs: Arguments {
values: inputs.iter().map(|x| x.clean(cx)).collect(),
},
output: self.pe_fn_decl().output.clean(cx),
attrs: Vec::new()
};
2013-08-15 16:28:54 -04:00
Item {
name: Some(self.pe_ident().clean(cx)),
attrs: self.attrs.clean(cx),
source: self.span.clean(cx),
def_id: ast_util::local_def(self.id),
visibility: self.pe_vis().clean(cx),
stability: get_stability(cx, ast_util::local_def(self.id)),
2013-08-15 16:28:54 -04:00
inner: MethodItem(Method {
generics: self.pe_generics().clean(cx),
self_: self.pe_explicit_self().node.clean(cx),
2014-12-09 10:36:46 -05:00
unsafety: self.pe_unsafety().clone(),
decl: decl,
2013-08-15 16:28:54 -04:00
}),
}
}
}
#[derive(Clone, RustcEncodable, RustcDecodable)]
2013-08-15 16:28:54 -04:00
pub struct TyMethod {
2014-12-09 10:36:46 -05:00
pub unsafety: ast::Unsafety,
pub decl: FnDecl,
pub generics: Generics,
pub self_: SelfTy,
2013-08-15 16:28:54 -04:00
}
impl Clean<Item> for ast::TypeMethod {
fn clean(&self, cx: &DocContext) -> Item {
let inputs = match self.explicit_self.node {
ast::SelfStatic => self.decl.inputs.as_slice(),
2015-01-07 11:58:31 -05:00
_ => &self.decl.inputs[1..]
};
let decl = FnDecl {
inputs: Arguments {
values: inputs.iter().map(|x| x.clean(cx)).collect(),
},
output: self.decl.output.clean(cx),
attrs: Vec::new()
};
2013-08-15 16:28:54 -04:00
Item {
name: Some(self.ident.clean(cx)),
attrs: self.attrs.clean(cx),
source: self.span.clean(cx),
def_id: ast_util::local_def(self.id),
2013-08-15 16:28:54 -04:00
visibility: None,
stability: get_stability(cx, ast_util::local_def(self.id)),
2013-08-15 16:28:54 -04:00
inner: TyMethodItem(TyMethod {
2014-12-09 10:36:46 -05:00
unsafety: self.unsafety.clone(),
decl: decl,
self_: self.explicit_self.node.clean(cx),
generics: self.generics.clean(cx),
2013-08-15 16:28:54 -04:00
}),
}
}
}
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq)]
2013-08-15 16:28:54 -04:00
pub enum SelfTy {
SelfStatic,
SelfValue,
SelfBorrowed(Option<Lifetime>, Mutability),
SelfExplicit(Type),
2013-08-15 16:28:54 -04:00
}
impl Clean<SelfTy> for ast::ExplicitSelf_ {
fn clean(&self, cx: &DocContext) -> SelfTy {
match *self {
ast::SelfStatic => SelfStatic,
ast::SelfValue(_) => SelfValue,
ast::SelfRegion(ref lt, ref mt, _) => {
SelfBorrowed(lt.clean(cx), mt.clean(cx))
}
ast::SelfExplicit(ref typ, _) => SelfExplicit(typ.clean(cx)),
2013-08-15 16:28:54 -04:00
}
}
}
#[derive(Clone, RustcEncodable, RustcDecodable)]
2013-08-15 16:28:54 -04:00
pub struct Function {
pub decl: FnDecl,
pub generics: Generics,
2014-12-09 10:36:46 -05:00
pub unsafety: ast::Unsafety,
2013-08-15 16:28:54 -04:00
}
impl Clean<Item> for doctree::Function {
fn clean(&self, cx: &DocContext) -> Item {
2013-08-15 16:28:54 -04:00
Item {
name: Some(self.name.clean(cx)),
attrs: self.attrs.clean(cx),
source: self.whence.clean(cx),
visibility: self.vis.clean(cx),
stability: self.stab.clean(cx),
def_id: ast_util::local_def(self.id),
2013-08-15 16:28:54 -04:00
inner: FunctionItem(Function {
decl: self.decl.clean(cx),
generics: self.generics.clean(cx),
2014-12-09 10:36:46 -05:00
unsafety: self.unsafety,
2013-08-15 16:28:54 -04:00
}),
}
}
}
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Show)]
2013-08-15 16:28:54 -04:00
pub struct FnDecl {
pub inputs: Arguments,
pub output: FunctionRetTy,
pub attrs: Vec<Attribute>,
}
2013-08-15 16:28:54 -04:00
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Show)]
pub struct Arguments {
pub values: Vec<Argument>,
}
impl Clean<FnDecl> for ast::FnDecl {
fn clean(&self, cx: &DocContext) -> FnDecl {
2013-08-15 16:28:54 -04:00
FnDecl {
inputs: Arguments {
values: self.inputs.clean(cx),
},
output: self.output.clean(cx),
attrs: Vec::new()
2013-08-15 16:28:54 -04:00
}
}
}
impl<'tcx> Clean<Type> for ty::FnOutput<'tcx> {
fn clean(&self, cx: &DocContext) -> Type {
match *self {
ty::FnConverging(ty) => ty.clean(cx),
ty::FnDiverging => Bottom
}
}
}
impl<'a, 'tcx> Clean<FnDecl> for (ast::DefId, &'a ty::PolyFnSig<'tcx>) {
fn clean(&self, cx: &DocContext) -> FnDecl {
let (did, sig) = *self;
let mut names = if did.node != 0 {
2014-09-14 20:27:36 -07:00
csearch::get_method_arg_names(&cx.tcx().sess.cstore, did).into_iter()
} else {
2014-09-14 20:27:36 -07:00
Vec::new().into_iter()
}.peekable();
if names.peek().map(|s| s.as_slice()) == Some("self") {
let _ = names.next();
}
FnDecl {
output: Return(sig.0.output.clean(cx)),
attrs: Vec::new(),
inputs: Arguments {
values: sig.0.inputs.iter().map(|t| {
Argument {
type_: t.clean(cx),
id: 0,
name: names.next().unwrap_or("".to_string()),
}
}).collect(),
},
}
}
}
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Show)]
2013-08-15 16:28:54 -04:00
pub struct Argument {
pub type_: Type,
pub name: String,
pub id: ast::NodeId,
2013-08-15 16:28:54 -04:00
}
impl Clean<Argument> for ast::Arg {
fn clean(&self, cx: &DocContext) -> Argument {
2013-08-15 16:28:54 -04:00
Argument {
2014-05-16 10:15:33 -07:00
name: name_from_pat(&*self.pat),
type_: (self.ty.clean(cx)),
2013-08-15 16:28:54 -04:00
id: self.id
}
}
}
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Show)]
pub enum FunctionRetTy {
Return(Type),
DefaultReturn,
NoReturn
2013-08-15 16:28:54 -04:00
}
impl Clean<FunctionRetTy> for ast::FunctionRetTy {
fn clean(&self, cx: &DocContext) -> FunctionRetTy {
2013-08-15 16:28:54 -04:00
match *self {
ast::Return(ref typ) => Return(typ.clean(cx)),
ast::DefaultReturn(..) => DefaultReturn,
ast::NoReturn(..) => NoReturn
2013-08-15 16:28:54 -04:00
}
}
}
#[derive(Clone, RustcEncodable, RustcDecodable)]
2013-08-15 16:28:54 -04:00
pub struct Trait {
pub unsafety: ast::Unsafety,
pub items: Vec<TraitMethod>,
pub generics: Generics,
pub bounds: Vec<TyParamBound>,
2013-08-15 16:28:54 -04:00
}
impl Clean<Item> for doctree::Trait {
fn clean(&self, cx: &DocContext) -> Item {
2013-08-15 16:28:54 -04:00
Item {
name: Some(self.name.clean(cx)),
attrs: self.attrs.clean(cx),
source: self.whence.clean(cx),
def_id: ast_util::local_def(self.id),
visibility: self.vis.clean(cx),
stability: self.stab.clean(cx),
2013-08-15 16:28:54 -04:00
inner: TraitItem(Trait {
unsafety: self.unsafety,
items: self.items.clean(cx),
generics: self.generics.clean(cx),
bounds: self.bounds.clean(cx),
2013-08-15 16:28:54 -04:00
}),
}
}
}
impl Clean<Type> for ast::TraitRef {
fn clean(&self, cx: &DocContext) -> Type {
2014-11-20 19:44:49 -05:00
resolve_type(cx, self.path.clean(cx), self.ref_id)
2013-08-15 16:28:54 -04:00
}
}
impl Clean<PolyTrait> for ast::PolyTraitRef {
fn clean(&self, cx: &DocContext) -> PolyTrait {
PolyTrait {
trait_: self.trait_ref.clean(cx),
lifetimes: self.bound_lifetimes.clean(cx)
}
2014-11-07 06:53:45 -05:00
}
}
/// An item belonging to a trait, whether a method or associated. Could be named
/// TraitItem except that's already taken by an exported enum variant.
#[derive(Clone, RustcEncodable, RustcDecodable)]
pub enum TraitMethod {
RequiredMethod(Item),
ProvidedMethod(Item),
TypeTraitItem(Item),
2013-08-15 16:28:54 -04:00
}
impl TraitMethod {
pub fn is_req(&self) -> bool {
2013-08-15 16:28:54 -04:00
match self {
&RequiredMethod(..) => true,
2013-08-15 16:28:54 -04:00
_ => false,
}
}
pub fn is_def(&self) -> bool {
2013-08-15 16:28:54 -04:00
match self {
&ProvidedMethod(..) => true,
2013-08-15 16:28:54 -04:00
_ => false,
}
}
pub fn is_type(&self) -> bool {
match self {
&TypeTraitItem(..) => true,
_ => false,
}
}
pub fn item<'a>(&'a self) -> &'a Item {
match *self {
RequiredMethod(ref item) => item,
ProvidedMethod(ref item) => item,
TypeTraitItem(ref item) => item,
}
}
2013-08-15 16:28:54 -04:00
}
impl Clean<TraitMethod> for ast::TraitItem {
fn clean(&self, cx: &DocContext) -> TraitMethod {
2013-08-15 16:28:54 -04:00
match self {
&ast::RequiredMethod(ref t) => RequiredMethod(t.clean(cx)),
&ast::ProvidedMethod(ref t) => ProvidedMethod(t.clean(cx)),
&ast::TypeTraitItem(ref t) => TypeTraitItem(t.clean(cx)),
}
}
}
#[derive(Clone, RustcEncodable, RustcDecodable)]
pub enum ImplMethod {
MethodImplItem(Item),
TypeImplItem(Item),
}
impl Clean<ImplMethod> for ast::ImplItem {
fn clean(&self, cx: &DocContext) -> ImplMethod {
match self {
&ast::MethodImplItem(ref t) => MethodImplItem(t.clean(cx)),
&ast::TypeImplItem(ref t) => TypeImplItem(t.clean(cx)),
2013-08-15 16:28:54 -04:00
}
}
}
impl<'tcx> Clean<Item> for ty::Method<'tcx> {
fn clean(&self, cx: &DocContext) -> Item {
let (self_, sig) = match self.explicit_self {
ty::StaticExplicitSelfCategory => (ast::SelfStatic.clean(cx),
self.fty.sig.clone()),
s => {
let sig = ty::Binder(ty::FnSig {
2015-01-07 11:58:31 -05:00
inputs: self.fty.sig.0.inputs[1..].to_vec(),
..self.fty.sig.0.clone()
});
let s = match s {
ty::ByValueExplicitSelfCategory => SelfValue,
ty::ByReferenceExplicitSelfCategory(..) => {
match self.fty.sig.0.inputs[0].sty {
ty::ty_rptr(r, mt) => {
SelfBorrowed(r.clean(cx), mt.mutbl.clean(cx))
}
_ => unreachable!(),
}
}
ty::ByBoxExplicitSelfCategory => {
SelfExplicit(self.fty.sig.0.inputs[0].clean(cx))
}
ty::StaticExplicitSelfCategory => unreachable!(),
};
(s, sig)
}
};
Item {
name: Some(self.name.clean(cx)),
visibility: Some(ast::Inherited),
stability: get_stability(cx, self.def_id),
def_id: self.def_id,
attrs: inline::load_attrs(cx, cx.tcx(), self.def_id),
source: Span::empty(),
inner: TyMethodItem(TyMethod {
2014-12-09 10:36:46 -05:00
unsafety: self.fty.unsafety,
generics: (&self.generics, subst::FnSpace).clean(cx),
self_: self_,
decl: (self.def_id, &sig).clean(cx),
})
}
}
}
impl<'tcx> Clean<Item> for ty::ImplOrTraitItem<'tcx> {
fn clean(&self, cx: &DocContext) -> Item {
match *self {
ty::MethodTraitItem(ref mti) => mti.clean(cx),
ty::TypeTraitItem(ref tti) => tti.clean(cx),
}
}
}
/// A trait reference, which may have higher ranked lifetimes.
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Show)]
pub struct PolyTrait {
pub trait_: Type,
pub lifetimes: Vec<Lifetime>
}
2013-08-15 16:28:54 -04:00
/// A representation of a Type suitable for hyperlinking purposes. Ideally one can get the original
/// type out of the AST/ty::ctxt given one of these, if more information is needed. Most importantly
/// it does not preserve mutability or boxes.
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Show)]
2013-08-15 16:28:54 -04:00
pub enum Type {
/// structs/enums/traits (anything that'd be an ast::TyPath)
ResolvedPath {
path: Path,
typarams: Option<Vec<TyParamBound>>,
did: ast::DefId,
},
2013-08-15 16:28:54 -04:00
// I have no idea how to usefully use this.
TyParamBinder(ast::NodeId),
/// For parameterized types, so the consumer of the JSON don't go
/// looking for types which don't exist anywhere.
Generic(String),
2013-08-15 16:28:54 -04:00
/// Primitives are just the fixed-size numeric types (plus int/uint/float), and char.
Primitive(PrimitiveType),
2013-08-15 16:28:54 -04:00
/// extern "ABI" fn
BareFunction(Box<BareFunctionDecl>),
Tuple(Vec<Type>),
Vector(Box<Type>),
FixedVector(Box<Type>, String),
/// aka TyBot
2013-08-15 16:28:54 -04:00
Bottom,
Unique(Box<Type>),
RawPointer(Mutability, Box<Type>),
BorrowedRef {
lifetime: Option<Lifetime>,
mutability: Mutability,
type_: Box<Type>,
},
// <Type as Trait>::Name
2014-11-20 21:45:05 -08:00
QPath {
name: String,
self_type: Box<Type>,
trait_: Box<Type>
},
// _
Infer,
// for<'a> Foo(&'a)
PolyTraitRef(Vec<TyParamBound>),
2013-08-15 16:28:54 -04:00
}
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Copy, Show)]
pub enum PrimitiveType {
2014-12-05 18:11:46 -08:00
Isize, I8, I16, I32, I64,
Usize, U8, U16, U32, U64,
F32, F64,
Char,
Bool,
Str,
Slice,
PrimitiveTuple,
}
#[derive(Clone, RustcEncodable, RustcDecodable, Copy)]
rustdoc: Generate hyperlinks between crates The general idea of hyperlinking between crates is that it should require as little configuration as possible, if any at all. In this vein, there are two separate ways to generate hyperlinks between crates: 1. When you're generating documentation for a crate 'foo' into folder 'doc', then if foo's external crate dependencies already have documented in the folder 'doc', then hyperlinks will be generated. This will work because all documentation is in the same folder, allowing links to work seamlessly both on the web and on the local filesystem browser. The rationale for this use case is a package with multiple libraries/crates that all want to link to one another, and you don't want to have to deal with going to the web. In theory this could be extended to have a RUST_PATH-style searching situtation, but I'm not sure that it would work seamlessly on the web as it does on the local filesystem, so I'm not attempting to explore this case in this pull request. I believe to fully realize this potential rustdoc would have to be acting as a server instead of a static site generator. 2. One of foo's external dependencies has a #[doc(html_root_url = "...")] attribute. This means that all hyperlinks to the dependency will be rooted at this url. This use case encompasses all packages using libstd/libextra. These two crates now have this attribute encoded (currently at the /doc/master url) and will be read by anything which has a dependency on libstd/libextra. This should also work for arbitrary crates in the wild that have online documentation. I don't like how the version is hard-wired into the url, but I think that this may be a case-by-case thing which doesn't end up being too bad in the long run. Closes #9539
2013-10-02 15:39:32 -07:00
pub enum TypeKind {
TypeEnum,
TypeFunction,
TypeModule,
TypeConst,
TypeStatic,
TypeStruct,
TypeTrait,
TypeVariant,
TypeTypedef,
rustdoc: Generate hyperlinks between crates The general idea of hyperlinking between crates is that it should require as little configuration as possible, if any at all. In this vein, there are two separate ways to generate hyperlinks between crates: 1. When you're generating documentation for a crate 'foo' into folder 'doc', then if foo's external crate dependencies already have documented in the folder 'doc', then hyperlinks will be generated. This will work because all documentation is in the same folder, allowing links to work seamlessly both on the web and on the local filesystem browser. The rationale for this use case is a package with multiple libraries/crates that all want to link to one another, and you don't want to have to deal with going to the web. In theory this could be extended to have a RUST_PATH-style searching situtation, but I'm not sure that it would work seamlessly on the web as it does on the local filesystem, so I'm not attempting to explore this case in this pull request. I believe to fully realize this potential rustdoc would have to be acting as a server instead of a static site generator. 2. One of foo's external dependencies has a #[doc(html_root_url = "...")] attribute. This means that all hyperlinks to the dependency will be rooted at this url. This use case encompasses all packages using libstd/libextra. These two crates now have this attribute encoded (currently at the /doc/master url) and will be read by anything which has a dependency on libstd/libextra. This should also work for arbitrary crates in the wild that have online documentation. I don't like how the version is hard-wired into the url, but I think that this may be a case-by-case thing which doesn't end up being too bad in the long run. Closes #9539
2013-10-02 15:39:32 -07:00
}
impl PrimitiveType {
fn from_str(s: &str) -> Option<PrimitiveType> {
match s.as_slice() {
2014-12-05 18:11:46 -08:00
"isize" | "int" => Some(Isize),
"i8" => Some(I8),
"i16" => Some(I16),
"i32" => Some(I32),
"i64" => Some(I64),
2014-12-05 18:11:46 -08:00
"usize" | "uint" => Some(Usize),
"u8" => Some(U8),
"u16" => Some(U16),
"u32" => Some(U32),
"u64" => Some(U64),
"bool" => Some(Bool),
"char" => Some(Char),
"str" => Some(Str),
"f32" => Some(F32),
"f64" => Some(F64),
"slice" => Some(Slice),
"tuple" => Some(PrimitiveTuple),
_ => None,
}
}
fn find(attrs: &[Attribute]) -> Option<PrimitiveType> {
for attr in attrs.iter() {
let list = match *attr {
List(ref k, ref l) if *k == "doc" => l,
_ => continue,
};
for sub_attr in list.iter() {
let value = match *sub_attr {
NameValue(ref k, ref v)
if *k == "primitive" => v.as_slice(),
_ => continue,
};
match PrimitiveType::from_str(value) {
Some(p) => return Some(p),
None => {}
}
}
}
return None
}
pub fn to_string(&self) -> &'static str {
match *self {
2014-12-05 18:11:46 -08:00
Isize => "isize",
I8 => "i8",
I16 => "i16",
I32 => "i32",
I64 => "i64",
2014-12-05 18:11:46 -08:00
Usize => "usize",
U8 => "u8",
U16 => "u16",
U32 => "u32",
U64 => "u64",
F32 => "f32",
F64 => "f64",
Str => "str",
Bool => "bool",
Char => "char",
Slice => "slice",
PrimitiveTuple => "tuple",
}
}
pub fn to_url_str(&self) -> &'static str {
self.to_string()
}
/// Creates a rustdoc-specific node id for primitive types.
///
/// These node ids are generally never used by the AST itself.
pub fn to_node_id(&self) -> ast::NodeId {
u32::MAX - 1 - (*self as u32)
}
}
2013-08-15 16:28:54 -04:00
impl Clean<Type> for ast::Ty {
fn clean(&self, cx: &DocContext) -> Type {
2013-08-15 16:28:54 -04:00
use syntax::ast::*;
match self.node {
TyPtr(ref m) => RawPointer(m.mutbl.clean(cx), box m.ty.clean(cx)),
TyRptr(ref l, ref m) =>
BorrowedRef {lifetime: l.clean(cx), mutability: m.mutbl.clean(cx),
type_: box m.ty.clean(cx)},
TyVec(ref ty) => Vector(box ty.clean(cx)),
TyFixedLengthVec(ref ty, ref e) => FixedVector(box ty.clean(cx),
e.span.to_src(cx)),
TyTup(ref tys) => Tuple(tys.clean(cx)),
2014-11-20 19:44:49 -05:00
TyPath(ref p, id) => {
resolve_type(cx, p.clean(cx), id)
}
TyObjectSum(ref lhs, ref bounds) => {
let lhs_ty = lhs.clean(cx);
match lhs_ty {
ResolvedPath { path, typarams: None, did } => {
ResolvedPath { path: path, typarams: Some(bounds.clean(cx)), did: did}
}
_ => {
lhs_ty // shouldn't happen
}
}
}
TyBareFn(ref barefn) => BareFunction(box barefn.clean(cx)),
TyParen(ref ty) => ty.clean(cx),
2014-11-20 21:45:05 -08:00
TyQPath(ref qp) => qp.clean(cx),
TyPolyTraitRef(ref bounds) => {
PolyTraitRef(bounds.clean(cx))
},
TyInfer(..) => {
Infer
},
TyTypeof(..) => {
panic!("Unimplemented type {:?}", self.node)
},
}
2013-08-15 16:28:54 -04:00
}
}
impl<'tcx> Clean<Type> for ty::Ty<'tcx> {
fn clean(&self, cx: &DocContext) -> Type {
match self.sty {
ty::ty_bool => Primitive(Bool),
ty::ty_char => Primitive(Char),
ty::ty_int(ast::TyIs(_)) => Primitive(Isize),
ty::ty_int(ast::TyI8) => Primitive(I8),
ty::ty_int(ast::TyI16) => Primitive(I16),
ty::ty_int(ast::TyI32) => Primitive(I32),
ty::ty_int(ast::TyI64) => Primitive(I64),
ty::ty_uint(ast::TyUs(_)) => Primitive(Usize),
ty::ty_uint(ast::TyU8) => Primitive(U8),
ty::ty_uint(ast::TyU16) => Primitive(U16),
ty::ty_uint(ast::TyU32) => Primitive(U32),
ty::ty_uint(ast::TyU64) => Primitive(U64),
ty::ty_float(ast::TyF32) => Primitive(F32),
ty::ty_float(ast::TyF64) => Primitive(F64),
ty::ty_str => Primitive(Str),
ty::ty_uniq(t) => {
let box_did = cx.tcx_opt().and_then(|tcx| {
tcx.lang_items.owned_box()
});
lang_struct(cx, box_did, t, "Box", Unique)
}
ty::ty_vec(ty, None) => Vector(box ty.clean(cx)),
ty::ty_vec(ty, Some(i)) => FixedVector(box ty.clean(cx),
format!("{}", i)),
ty::ty_ptr(mt) => RawPointer(mt.mutbl.clean(cx), box mt.ty.clean(cx)),
ty::ty_rptr(r, mt) => BorrowedRef {
lifetime: r.clean(cx),
mutability: mt.mutbl.clean(cx),
type_: box mt.ty.clean(cx),
},
ty::ty_bare_fn(_, ref fty) => BareFunction(box BareFunctionDecl {
2014-12-09 10:36:46 -05:00
unsafety: fty.unsafety,
generics: Generics {
lifetimes: Vec::new(),
type_params: Vec::new(),
where_predicates: Vec::new()
},
decl: (ast_util::local_def(0), &fty.sig).clean(cx),
abi: fty.abi.to_string(),
}),
ty::ty_struct(did, substs) |
ty::ty_enum(did, substs) => {
let fqn = csearch::get_item_path(cx.tcx(), did);
let fqn: Vec<_> = fqn.into_iter().map(|i| i.to_string()).collect();
let kind = match self.sty {
ty::ty_struct(..) => TypeStruct,
_ => TypeEnum,
};
let path = external_path(cx, fqn.last().unwrap().to_string().as_slice(),
None, vec![], substs);
cx.external_paths.borrow_mut().as_mut().unwrap().insert(did, (fqn, kind));
ResolvedPath {
path: path,
typarams: None,
did: did,
}
}
ty::ty_trait(box ty::TyTrait { ref principal, ref bounds }) => {
let did = principal.def_id();
let fqn = csearch::get_item_path(cx.tcx(), did);
let fqn: Vec<_> = fqn.into_iter().map(|i| i.to_string()).collect();
let (typarams, bindings) = bounds.clean(cx);
let path = external_path(cx, fqn.last().unwrap().to_string().as_slice(),
Some(did), bindings, principal.substs());
cx.external_paths.borrow_mut().as_mut().unwrap().insert(did, (fqn, TypeTrait));
ResolvedPath {
path: path,
typarams: Some(typarams),
did: did,
}
}
ty::ty_tup(ref t) => Tuple(t.clean(cx)),
ty::ty_projection(ref data) => {
let trait_ref = match data.trait_ref.clean(cx) {
2014-12-30 12:09:21 -05:00
TyParamBound::TraitBound(t, _) => t.trait_,
TyParamBound::RegionBound(_) => panic!("cleaning a trait got a region??"),
};
Type::QPath {
name: data.item_name.clean(cx),
self_type: box data.trait_ref.self_ty().clean(cx),
trait_: box trait_ref,
}
}
ty::ty_param(ref p) => Generic(token::get_name(p.name).to_string()),
ty::ty_unboxed_closure(..) => Tuple(vec![]), // FIXME(pcwalton)
ty::ty_infer(..) => panic!("ty_infer"),
ty::ty_open(..) => panic!("ty_open"),
ty::ty_err => panic!("ty_err"),
}
}
}
2014-11-20 21:45:05 -08:00
impl Clean<Type> for ast::QPath {
fn clean(&self, cx: &DocContext) -> Type {
Type::QPath {
name: self.item_path.identifier.clean(cx),
2014-11-20 21:45:05 -08:00
self_type: box self.self_type.clean(cx),
trait_: box self.trait_ref.clean(cx)
}
}
}
#[derive(Clone, RustcEncodable, RustcDecodable)]
pub enum StructField {
HiddenStructField, // inserted later by strip passes
TypedStructField(Type),
2013-08-15 16:28:54 -04:00
}
impl Clean<Item> for ast::StructField {
fn clean(&self, cx: &DocContext) -> Item {
2013-08-15 16:28:54 -04:00
let (name, vis) = match self.node.kind {
ast::NamedField(id, vis) => (Some(id), vis),
ast::UnnamedField(vis) => (None, vis)
2013-08-15 16:28:54 -04:00
};
Item {
name: name.clean(cx),
attrs: self.node.attrs.clean(cx),
source: self.span.clean(cx),
visibility: Some(vis),
stability: get_stability(cx, ast_util::local_def(self.node.id)),
def_id: ast_util::local_def(self.node.id),
inner: StructFieldItem(TypedStructField(self.node.ty.clean(cx))),
2013-08-15 16:28:54 -04:00
}
}
}
impl Clean<Item> for ty::field_ty {
fn clean(&self, cx: &DocContext) -> Item {
use syntax::parse::token::special_idents::unnamed_field;
use rustc::metadata::csearch;
let attr_map = csearch::get_struct_field_attrs(&cx.tcx().sess.cstore, self.id);
let (name, attrs) = if self.name == unnamed_field.name {
(None, None)
} else {
2014-11-06 12:25:16 -05:00
(Some(self.name), Some(attr_map.get(&self.id.node).unwrap()))
};
let ty = ty::lookup_item_type(cx.tcx(), self.id);
Item {
name: name.clean(cx),
attrs: attrs.unwrap_or(&Vec::new()).clean(cx),
source: Span::empty(),
visibility: Some(self.vis),
stability: get_stability(cx, self.id),
def_id: self.id,
inner: StructFieldItem(TypedStructField(ty.ty.clean(cx))),
}
}
}
pub type Visibility = ast::Visibility;
2013-08-15 16:28:54 -04:00
impl Clean<Option<Visibility>> for ast::Visibility {
fn clean(&self, _: &DocContext) -> Option<Visibility> {
2013-08-15 16:28:54 -04:00
Some(*self)
}
}
#[derive(Clone, RustcEncodable, RustcDecodable)]
2013-08-15 16:28:54 -04:00
pub struct Struct {
pub struct_type: doctree::StructType,
pub generics: Generics,
pub fields: Vec<Item>,
pub fields_stripped: bool,
2013-08-15 16:28:54 -04:00
}
impl Clean<Item> for doctree::Struct {
fn clean(&self, cx: &DocContext) -> Item {
2013-08-15 16:28:54 -04:00
Item {
name: Some(self.name.clean(cx)),
attrs: self.attrs.clean(cx),
source: self.whence.clean(cx),
def_id: ast_util::local_def(self.id),
visibility: self.vis.clean(cx),
stability: self.stab.clean(cx),
2013-08-15 16:28:54 -04:00
inner: StructItem(Struct {
struct_type: self.struct_type,
generics: self.generics.clean(cx),
fields: self.fields.clean(cx),
fields_stripped: false,
2013-08-15 16:28:54 -04:00
}),
}
}
}
/// This is a more limited form of the standard Struct, different in that
2013-08-15 16:28:54 -04:00
/// it lacks the things most items have (name, id, parameterization). Found
/// only as a variant in an enum.
#[derive(Clone, RustcEncodable, RustcDecodable)]
2013-08-15 16:28:54 -04:00
pub struct VariantStruct {
pub struct_type: doctree::StructType,
pub fields: Vec<Item>,
pub fields_stripped: bool,
2013-08-15 16:28:54 -04:00
}
impl Clean<VariantStruct> for syntax::ast::StructDef {
fn clean(&self, cx: &DocContext) -> VariantStruct {
2013-08-15 16:28:54 -04:00
VariantStruct {
struct_type: doctree::struct_type_from_def(self),
fields: self.fields.clean(cx),
fields_stripped: false,
2013-08-15 16:28:54 -04:00
}
}
}
#[derive(Clone, RustcEncodable, RustcDecodable)]
2013-08-15 16:28:54 -04:00
pub struct Enum {
pub variants: Vec<Item>,
pub generics: Generics,
pub variants_stripped: bool,
2013-08-15 16:28:54 -04:00
}
impl Clean<Item> for doctree::Enum {
fn clean(&self, cx: &DocContext) -> Item {
2013-08-15 16:28:54 -04:00
Item {
name: Some(self.name.clean(cx)),
attrs: self.attrs.clean(cx),
source: self.whence.clean(cx),
def_id: ast_util::local_def(self.id),
visibility: self.vis.clean(cx),
stability: self.stab.clean(cx),
2013-08-15 16:28:54 -04:00
inner: EnumItem(Enum {
variants: self.variants.clean(cx),
generics: self.generics.clean(cx),
variants_stripped: false,
2013-08-15 16:28:54 -04:00
}),
}
}
}
#[derive(Clone, RustcEncodable, RustcDecodable)]
2013-08-15 16:28:54 -04:00
pub struct Variant {
pub kind: VariantKind,
2013-08-15 16:28:54 -04:00
}
impl Clean<Item> for doctree::Variant {
fn clean(&self, cx: &DocContext) -> Item {
2013-08-15 16:28:54 -04:00
Item {
name: Some(self.name.clean(cx)),
attrs: self.attrs.clean(cx),
source: self.whence.clean(cx),
visibility: self.vis.clean(cx),
stability: self.stab.clean(cx),
def_id: ast_util::local_def(self.id),
2013-08-15 16:28:54 -04:00
inner: VariantItem(Variant {
kind: self.kind.clean(cx),
2013-08-15 16:28:54 -04:00
}),
}
}
}
impl<'tcx> Clean<Item> for ty::VariantInfo<'tcx> {
fn clean(&self, cx: &DocContext) -> Item {
2014-05-23 16:14:54 -07:00
// use syntax::parse::token::special_idents::unnamed_field;
let kind = match self.arg_names.as_ref().map(|s| s.as_slice()) {
None | Some([]) if self.args.len() == 0 => CLikeVariant,
None | Some([]) => {
TupleVariant(self.args.clean(cx))
2014-05-23 16:14:54 -07:00
}
Some(s) => {
StructVariant(VariantStruct {
struct_type: doctree::Plain,
fields_stripped: false,
fields: s.iter().zip(self.args.iter()).map(|(name, ty)| {
Item {
source: Span::empty(),
name: Some(name.clean(cx)),
2014-05-23 16:14:54 -07:00
attrs: Vec::new(),
visibility: Some(ast::Public),
// FIXME: this is not accurate, we need an id for
// the specific field but we're using the id
// for the whole variant. Thus we read the
// stability from the whole variant as well.
// Struct variants are experimental and need
// more infrastructure work before we can get
// at the needed information here.
def_id: self.id,
stability: get_stability(cx, self.id),
2014-05-23 16:14:54 -07:00
inner: StructFieldItem(
TypedStructField(ty.clean(cx))
2014-05-23 16:14:54 -07:00
)
}
}).collect()
})
}
};
Item {
name: Some(self.name.clean(cx)),
attrs: inline::load_attrs(cx, cx.tcx(), self.id),
2014-05-23 16:14:54 -07:00
source: Span::empty(),
visibility: Some(ast::Public),
def_id: self.id,
inner: VariantItem(Variant { kind: kind }),
stability: get_stability(cx, self.id),
2014-05-23 16:14:54 -07:00
}
}
}
#[derive(Clone, RustcEncodable, RustcDecodable)]
2013-08-15 16:28:54 -04:00
pub enum VariantKind {
CLikeVariant,
TupleVariant(Vec<Type>),
2013-08-15 16:28:54 -04:00
StructVariant(VariantStruct),
}
impl Clean<VariantKind> for ast::VariantKind {
fn clean(&self, cx: &DocContext) -> VariantKind {
2013-08-15 16:28:54 -04:00
match self {
&ast::TupleVariantKind(ref args) => {
2013-08-15 16:28:54 -04:00
if args.len() == 0 {
CLikeVariant
} else {
TupleVariant(args.iter().map(|x| x.ty.clean(cx)).collect())
2013-08-15 16:28:54 -04:00
}
},
&ast::StructVariantKind(ref sd) => StructVariant(sd.clean(cx)),
2013-08-15 16:28:54 -04:00
}
}
}
#[derive(Clone, RustcEncodable, RustcDecodable, Show)]
pub struct Span {
pub filename: String,
pub loline: uint,
pub locol: uint,
pub hiline: uint,
pub hicol: uint,
}
impl Span {
fn empty() -> Span {
Span {
filename: "".to_string(),
loline: 0, locol: 0,
hiline: 0, hicol: 0,
}
}
}
impl Clean<Span> for syntax::codemap::Span {
fn clean(&self, cx: &DocContext) -> Span {
let cm = cx.sess().codemap();
let filename = cm.span_to_filename(*self);
let lo = cm.lookup_char_pos(self.lo);
let hi = cm.lookup_char_pos(self.hi);
Span {
filename: filename.to_string(),
loline: lo.line,
locol: lo.col.to_uint(),
hiline: hi.line,
hicol: hi.col.to_uint(),
}
2013-08-15 16:28:54 -04:00
}
}
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Show)]
2013-08-15 16:28:54 -04:00
pub struct Path {
pub global: bool,
pub segments: Vec<PathSegment>,
2013-08-15 16:28:54 -04:00
}
impl Clean<Path> for ast::Path {
fn clean(&self, cx: &DocContext) -> Path {
2013-08-15 16:28:54 -04:00
Path {
global: self.global,
segments: self.segments.clean(cx),
}
}
}
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Show)]
pub enum PathParameters {
AngleBracketed {
lifetimes: Vec<Lifetime>,
types: Vec<Type>,
bindings: Vec<TypeBinding>
},
Parenthesized {
inputs: Vec<Type>,
output: Option<Type>
}
}
impl Clean<PathParameters> for ast::PathParameters {
fn clean(&self, cx: &DocContext) -> PathParameters {
match *self {
ast::AngleBracketedParameters(ref data) => {
PathParameters::AngleBracketed {
lifetimes: data.lifetimes.clean(cx),
types: data.types.clean(cx),
bindings: data.bindings.clean(cx)
}
}
ast::ParenthesizedParameters(ref data) => {
PathParameters::Parenthesized {
inputs: data.inputs.clean(cx),
output: data.output.clean(cx)
}
}
}
}
}
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Show)]
pub struct PathSegment {
pub name: String,
pub params: PathParameters
}
impl Clean<PathSegment> for ast::PathSegment {
fn clean(&self, cx: &DocContext) -> PathSegment {
PathSegment {
name: self.identifier.clean(cx),
params: self.parameters.clean(cx)
2013-08-15 16:28:54 -04:00
}
}
}
fn path_to_string(p: &ast::Path) -> String {
let mut s = String::new();
2013-08-15 16:28:54 -04:00
let mut first = true;
for i in p.segments.iter().map(|x| token::get_ident(x.identifier)) {
2013-08-15 16:28:54 -04:00
if !first || p.global {
s.push_str("::");
} else {
first = false;
}
s.push_str(i.get());
2013-08-15 16:28:54 -04:00
}
s
2013-08-15 16:28:54 -04:00
}
impl Clean<String> for ast::Ident {
fn clean(&self, _: &DocContext) -> String {
token::get_ident(*self).get().to_string()
2013-08-15 16:28:54 -04:00
}
}
impl Clean<String> for ast::Name {
fn clean(&self, _: &DocContext) -> String {
token::get_name(*self).get().to_string()
}
}
#[derive(Clone, RustcEncodable, RustcDecodable)]
2013-08-15 16:28:54 -04:00
pub struct Typedef {
pub type_: Type,
pub generics: Generics,
2013-08-15 16:28:54 -04:00
}
impl Clean<Item> for doctree::Typedef {
fn clean(&self, cx: &DocContext) -> Item {
2013-08-15 16:28:54 -04:00
Item {
name: Some(self.name.clean(cx)),
attrs: self.attrs.clean(cx),
source: self.whence.clean(cx),
def_id: ast_util::local_def(self.id.clone()),
visibility: self.vis.clean(cx),
stability: self.stab.clean(cx),
2013-08-15 16:28:54 -04:00
inner: TypedefItem(Typedef {
type_: self.ty.clean(cx),
generics: self.gen.clean(cx),
2013-08-15 16:28:54 -04:00
}),
}
}
}
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Show)]
2013-08-15 16:28:54 -04:00
pub struct BareFunctionDecl {
2014-12-09 10:36:46 -05:00
pub unsafety: ast::Unsafety,
pub generics: Generics,
pub decl: FnDecl,
pub abi: String,
2013-08-15 16:28:54 -04:00
}
impl Clean<BareFunctionDecl> for ast::BareFnTy {
fn clean(&self, cx: &DocContext) -> BareFunctionDecl {
2013-08-15 16:28:54 -04:00
BareFunctionDecl {
2014-12-09 10:36:46 -05:00
unsafety: self.unsafety,
2013-08-15 16:28:54 -04:00
generics: Generics {
lifetimes: self.lifetimes.clean(cx),
type_params: Vec::new(),
where_predicates: Vec::new()
2013-08-15 16:28:54 -04:00
},
decl: self.decl.clean(cx),
abi: self.abi.to_string(),
2013-08-15 16:28:54 -04:00
}
}
}
#[derive(Clone, RustcEncodable, RustcDecodable, Show)]
2013-08-15 16:28:54 -04:00
pub struct Static {
pub type_: Type,
pub mutability: Mutability,
2013-08-15 16:28:54 -04:00
/// 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,
2013-08-15 16:28:54 -04:00
}
impl Clean<Item> for doctree::Static {
fn clean(&self, cx: &DocContext) -> Item {
debug!("cleaning static {}: {:?}", self.name.clean(cx), self);
2013-08-15 16:28:54 -04:00
Item {
name: Some(self.name.clean(cx)),
attrs: self.attrs.clean(cx),
source: self.whence.clean(cx),
def_id: ast_util::local_def(self.id),
visibility: self.vis.clean(cx),
stability: self.stab.clean(cx),
2013-08-15 16:28:54 -04:00
inner: StaticItem(Static {
type_: self.type_.clean(cx),
mutability: self.mutability.clean(cx),
expr: self.expr.span.to_src(cx),
2013-08-15 16:28:54 -04:00
}),
}
}
}
#[derive(Clone, RustcEncodable, RustcDecodable, Show)]
pub struct Constant {
pub type_: Type,
pub expr: String,
}
impl Clean<Item> for doctree::Constant {
fn clean(&self, cx: &DocContext) -> Item {
Item {
name: Some(self.name.clean(cx)),
attrs: self.attrs.clean(cx),
source: self.whence.clean(cx),
def_id: ast_util::local_def(self.id),
visibility: self.vis.clean(cx),
stability: self.stab.clean(cx),
inner: ConstantItem(Constant {
type_: self.type_.clean(cx),
expr: self.expr.span.to_src(cx),
}),
}
}
}
#[derive(Show, Clone, RustcEncodable, RustcDecodable, PartialEq, Copy)]
2013-08-15 16:28:54 -04:00
pub enum Mutability {
Mutable,
Immutable,
}
2013-09-05 10:14:35 -04:00
impl Clean<Mutability> for ast::Mutability {
fn clean(&self, _: &DocContext) -> Mutability {
2013-08-15 16:28:54 -04:00
match self {
2013-09-05 10:14:35 -04:00
&ast::MutMutable => Mutable,
&ast::MutImmutable => Immutable,
2013-08-15 16:28:54 -04:00
}
}
}
#[derive(Clone, RustcEncodable, RustcDecodable)]
2013-08-15 16:28:54 -04:00
pub struct Impl {
pub generics: Generics,
pub trait_: Option<Type>,
pub for_: Type,
pub items: Vec<Item>,
pub derived: bool,
2013-08-15 16:28:54 -04:00
}
fn detect_derived<M: AttrMetaMethods>(attrs: &[M]) -> bool {
attr::contains_name(attrs, "automatically_derived")
}
2013-08-15 16:28:54 -04:00
impl Clean<Item> for doctree::Impl {
fn clean(&self, cx: &DocContext) -> Item {
2013-08-15 16:28:54 -04:00
Item {
name: None,
attrs: self.attrs.clean(cx),
source: self.whence.clean(cx),
def_id: ast_util::local_def(self.id),
visibility: self.vis.clean(cx),
stability: self.stab.clean(cx),
2013-08-15 16:28:54 -04:00
inner: ImplItem(Impl {
generics: self.generics.clean(cx),
trait_: self.trait_.clean(cx),
for_: self.for_.clean(cx),
2014-09-14 20:27:36 -07:00
items: self.items.clean(cx).into_iter().map(|ti| {
match ti {
MethodImplItem(i) => i,
TypeImplItem(i) => i,
}
}).collect(),
derived: detect_derived(self.attrs.as_slice()),
2013-08-15 16:28:54 -04:00
}),
}
}
}
#[derive(Clone, RustcEncodable, RustcDecodable)]
2013-08-15 16:28:54 -04:00
pub struct ViewItem {
pub inner: ViewItemInner,
2013-08-15 16:28:54 -04:00
}
impl Clean<Vec<Item>> for ast::ViewItem {
fn clean(&self, cx: &DocContext) -> Vec<Item> {
2014-07-02 21:27:07 -04:00
// We consider inlining the documentation of `pub use` statements, but we
// forcefully don't inline if this is not public or if the
// #[doc(no_inline)] attribute is present.
let denied = self.vis != ast::Public || self.attrs.iter().any(|a| {
a.name().get() == "doc" && match a.meta_item_list() {
Some(l) => attr::contains_name(l, "no_inline"),
None => false,
}
});
let convert = |&: node: &ast::ViewItem_| {
Item {
name: None,
attrs: self.attrs.clean(cx),
source: self.span.clean(cx),
def_id: ast_util::local_def(0),
visibility: self.vis.clean(cx),
stability: None,
inner: ViewItemItem(ViewItem { inner: node.clean(cx) }),
}
};
let mut ret = Vec::new();
match self.node {
ast::ViewItemUse(ref path) if !denied => {
match path.node {
ast::ViewPathGlob(..) => ret.push(convert(&self.node)),
ast::ViewPathList(ref a, ref list, ref b) => {
// Attempt to inline all reexported items, but be sure
// to keep any non-inlineable reexports so they can be
// listed in the documentation.
let remaining = list.iter().filter(|path| {
match inline::try_inline(cx, path.node.id(), None) {
Some(items) => {
2014-09-14 20:27:36 -07:00
ret.extend(items.into_iter()); false
}
None => true,
}
}).map(|a| a.clone()).collect::<Vec<ast::PathListItem>>();
if remaining.len() > 0 {
let path = ast::ViewPathList(a.clone(),
remaining,
b.clone());
let path = syntax::codemap::dummy_spanned(path);
ret.push(convert(&ast::ViewItemUse(P(path))));
}
}
ast::ViewPathSimple(ident, _, id) => {
match inline::try_inline(cx, id, Some(ident)) {
2014-09-14 20:27:36 -07:00
Some(items) => ret.extend(items.into_iter()),
None => ret.push(convert(&self.node)),
}
}
}
}
ref n => ret.push(convert(n)),
2013-08-15 16:28:54 -04:00
}
return ret;
2013-08-15 16:28:54 -04:00
}
}
#[derive(Clone, RustcEncodable, RustcDecodable)]
2013-08-15 16:28:54 -04:00
pub enum ViewItemInner {
ExternCrate(String, Option<String>, ast::NodeId),
Import(ViewPath)
2013-08-15 16:28:54 -04:00
}
impl Clean<ViewItemInner> for ast::ViewItem_ {
fn clean(&self, cx: &DocContext) -> ViewItemInner {
2013-08-15 16:28:54 -04:00
match self {
&ast::ViewItemExternCrate(ref i, ref p, ref id) => {
2014-01-21 10:08:10 -08:00
let string = match *p {
None => None,
Some((ref x, _)) => Some(x.get().to_string()),
2014-01-21 10:08:10 -08:00
};
ExternCrate(i.clean(cx), string, *id)
2014-01-21 10:08:10 -08:00
}
&ast::ViewItemUse(ref vp) => {
Import(vp.clean(cx))
}
2013-08-15 16:28:54 -04:00
}
}
}
#[derive(Clone, RustcEncodable, RustcDecodable)]
2013-08-15 16:28:54 -04:00
pub enum ViewPath {
// use source as str;
SimpleImport(String, ImportSource),
// use source::*;
GlobImport(ImportSource),
// use source::{a, b, c};
ImportList(ImportSource, Vec<ViewListIdent>),
}
#[derive(Clone, RustcEncodable, RustcDecodable)]
pub struct ImportSource {
pub path: Path,
pub did: Option<ast::DefId>,
2013-08-15 16:28:54 -04:00
}
impl Clean<ViewPath> for ast::ViewPath {
fn clean(&self, cx: &DocContext) -> ViewPath {
2013-08-15 16:28:54 -04:00
match self.node {
ast::ViewPathSimple(ref i, ref p, id) =>
SimpleImport(i.clean(cx), resolve_use_source(cx, p.clean(cx), id)),
ast::ViewPathGlob(ref p, id) =>
GlobImport(resolve_use_source(cx, p.clean(cx), id)),
ast::ViewPathList(ref p, ref pl, id) => {
ImportList(resolve_use_source(cx, p.clean(cx), id),
pl.clean(cx))
}
2013-08-15 16:28:54 -04:00
}
}
}
#[derive(Clone, RustcEncodable, RustcDecodable)]
pub struct ViewListIdent {
pub name: String,
pub source: Option<ast::DefId>,
}
2013-08-15 16:28:54 -04:00
impl Clean<ViewListIdent> for ast::PathListItem {
fn clean(&self, cx: &DocContext) -> ViewListIdent {
match self.node {
ast::PathListIdent { id, name } => ViewListIdent {
name: name.clean(cx),
source: resolve_def(cx, id)
},
ast::PathListMod { id } => ViewListIdent {
name: "mod".to_string(),
source: resolve_def(cx, id)
}
}
2013-08-15 16:28:54 -04:00
}
}
impl Clean<Vec<Item>> for ast::ForeignMod {
fn clean(&self, cx: &DocContext) -> Vec<Item> {
self.items.clean(cx)
}
}
impl Clean<Item> for ast::ForeignItem {
fn clean(&self, cx: &DocContext) -> Item {
let inner = match self.node {
ast::ForeignItemFn(ref decl, ref generics) => {
ForeignFunctionItem(Function {
decl: decl.clean(cx),
generics: generics.clean(cx),
2014-12-09 10:36:46 -05:00
unsafety: ast::Unsafety::Unsafe,
})
}
ast::ForeignItemStatic(ref ty, mutbl) => {
ForeignStaticItem(Static {
type_: ty.clean(cx),
mutability: if mutbl {Mutable} else {Immutable},
expr: "".to_string(),
})
}
};
Item {
name: Some(self.ident.clean(cx)),
attrs: self.attrs.clean(cx),
source: self.span.clean(cx),
def_id: ast_util::local_def(self.id),
visibility: self.vis.clean(cx),
stability: get_stability(cx, ast_util::local_def(self.id)),
inner: inner,
}
}
}
2013-08-15 16:28:54 -04:00
// Utilities
trait ToSource {
fn to_src(&self, cx: &DocContext) -> String;
2013-08-15 16:28:54 -04:00
}
2013-09-05 10:14:35 -04:00
impl ToSource for syntax::codemap::Span {
fn to_src(&self, cx: &DocContext) -> String {
debug!("converting span {:?} to snippet", self.clean(cx));
let sn = match cx.sess().codemap().span_to_snippet(*self) {
Some(x) => x.to_string(),
None => "".to_string()
2013-08-15 16:28:54 -04:00
};
debug!("got snippet {}", sn);
2013-08-15 16:28:54 -04:00
sn
}
}
fn lit_to_string(lit: &ast::Lit) -> String {
2013-08-15 16:28:54 -04:00
match lit.node {
ast::LitStr(ref st, _) => st.get().to_string(),
ast::LitBinary(ref data) => format!("{:?}", data),
2014-06-06 16:04:04 +01:00
ast::LitByte(b) => {
let mut res = String::from_str("b'");
for c in (b as char).escape_default() {
res.push(c);
}
res.push('\'');
2014-06-06 16:04:04 +01:00
res
},
ast::LitChar(c) => format!("'{}'", c),
ast::LitInt(i, _t) => i.to_string(),
ast::LitFloat(ref f, _t) => f.get().to_string(),
ast::LitFloatUnsuffixed(ref f) => f.get().to_string(),
ast::LitBool(b) => b.to_string(),
2013-08-15 16:28:54 -04:00
}
}
fn name_from_pat(p: &ast::Pat) -> String {
2013-08-15 16:28:54 -04:00
use syntax::ast::*;
debug!("Trying to get a name from pattern: {:?}", p);
2013-12-29 00:13:29 -05:00
2013-08-15 16:28:54 -04:00
match p.node {
PatWild(PatWildSingle) => "_".to_string(),
PatWild(PatWildMulti) => "..".to_string(),
PatIdent(_, ref p, _) => token::get_ident(p.node).get().to_string(),
PatEnum(ref p, _) => path_to_string(p),
PatStruct(ref name, ref fields, etc) => {
format!("{} {{ {}{} }}", path_to_string(name),
fields.iter().map(|&Spanned { node: ref fp, .. }|
format!("{}: {}", fp.ident.as_str(), name_from_pat(&*fp.pat)))
.collect::<Vec<String>>().connect(", "),
if etc { ", ..." } else { "" }
)
},
PatTup(ref elts) => format!("({})", elts.iter().map(|p| name_from_pat(&**p))
.collect::<Vec<String>>().connect(", ")),
PatBox(ref p) => name_from_pat(&**p),
PatRegion(ref p, _) => name_from_pat(&**p),
2013-12-29 00:13:29 -05:00
PatLit(..) => {
warn!("tried to get argument name from PatLit, \
which is silly in function arguments");
"()".to_string()
2013-12-29 00:13:29 -05:00
},
PatRange(..) => panic!("tried to get argument name from PatRange, \
2013-09-05 10:14:35 -04:00
which is not allowed in function arguments"),
PatVec(ref begin, ref mid, ref end) => {
let begin = begin.iter().map(|p| name_from_pat(&**p));
let mid = mid.as_ref().map(|p| format!("..{}", name_from_pat(&**p))).into_iter();
let end = end.iter().map(|p| name_from_pat(&**p));
format!("[{}]", begin.chain(mid).chain(end).collect::<Vec<_>>().connect(", "))
},
2014-05-19 13:29:41 -07:00
PatMac(..) => {
warn!("can't document the name of a function argument \
produced by a pattern macro");
"(argument produced by macro)".to_string()
}
2013-08-15 16:28:54 -04:00
}
}
/// Given a Type, resolve it using the def_map
2014-11-20 19:44:49 -05:00
fn resolve_type(cx: &DocContext,
path: Path,
id: ast::NodeId) -> Type {
let tcx = match cx.tcx_opt() {
Some(tcx) => tcx,
// If we're extracting tests, this return value doesn't matter.
None => return Primitive(Bool),
};
2014-10-15 03:20:39 -04:00
debug!("searching for {} in defmap", id);
2014-11-06 12:25:16 -05:00
let def = match tcx.def_map.borrow().get(&id) {
2014-03-20 21:52:59 -07:00
Some(&k) => k,
None => panic!("unresolved id not in defmap")
2013-08-15 16:28:54 -04:00
};
match def {
def::DefSelfTy(..) => {
return Generic(token::get_name(special_idents::type_self.name).to_string());
}
def::DefPrimTy(p) => match p {
ast::TyStr => return Primitive(Str),
ast::TyBool => return Primitive(Bool),
ast::TyChar => return Primitive(Char),
ast::TyInt(ast::TyIs(_)) => return Primitive(Isize),
ast::TyInt(ast::TyI8) => return Primitive(I8),
ast::TyInt(ast::TyI16) => return Primitive(I16),
ast::TyInt(ast::TyI32) => return Primitive(I32),
ast::TyInt(ast::TyI64) => return Primitive(I64),
ast::TyUint(ast::TyUs(_)) => return Primitive(Usize),
ast::TyUint(ast::TyU8) => return Primitive(U8),
ast::TyUint(ast::TyU16) => return Primitive(U16),
ast::TyUint(ast::TyU32) => return Primitive(U32),
ast::TyUint(ast::TyU64) => return Primitive(U64),
ast::TyFloat(ast::TyF32) => return Primitive(F32),
ast::TyFloat(ast::TyF64) => return Primitive(F64),
2013-08-15 16:28:54 -04:00
},
def::DefTyParam(_, _, _, n) => return Generic(token::get_name(n).to_string()),
def::DefTyParamBinder(i) => return TyParamBinder(i),
_ => {}
};
let did = register_def(&*cx, def);
2014-11-20 19:44:49 -05:00
ResolvedPath { path: path, typarams: None, did: did }
}
fn register_def(cx: &DocContext, def: def::Def) -> ast::DefId {
let (did, kind) = match def {
2014-10-31 15:00:35 +13:00
def::DefFn(i, _) => (i, TypeFunction),
def::DefTy(i, false) => (i, TypeTypedef),
def::DefTy(i, true) => (i, TypeEnum),
def::DefTrait(i) => (i, TypeTrait),
def::DefStruct(i) => (i, TypeStruct),
def::DefMod(i) => (i, TypeModule),
def::DefStatic(i, _) => (i, TypeStatic),
def::DefVariant(i, _, _) => (i, TypeEnum),
_ => return def.def_id()
2013-08-15 16:28:54 -04:00
};
if ast_util::is_local(did) { return did }
let tcx = match cx.tcx_opt() {
Some(tcx) => tcx,
None => return did
};
inline::record_extern_fqn(cx, did, kind);
if let TypeTrait = kind {
let t = inline::build_external_trait(cx, tcx, did);
cx.external_traits.borrow_mut().as_mut().unwrap().insert(did, t);
}
return did;
2013-08-15 16:28:54 -04:00
}
fn resolve_use_source(cx: &DocContext, path: Path, id: ast::NodeId) -> ImportSource {
ImportSource {
path: path,
did: resolve_def(cx, id),
}
}
fn resolve_def(cx: &DocContext, id: ast::NodeId) -> Option<ast::DefId> {
cx.tcx_opt().and_then(|tcx| {
2014-11-06 12:25:16 -05:00
tcx.def_map.borrow().get(&id).map(|&def| register_def(cx, def))
})
}
#[derive(Clone, RustcEncodable, RustcDecodable)]
pub struct Macro {
pub source: String,
}
impl Clean<Item> for doctree::Macro {
fn clean(&self, cx: &DocContext) -> Item {
Item {
name: Some(format!("{}!", self.name.clean(cx))),
attrs: self.attrs.clean(cx),
source: self.whence.clean(cx),
visibility: ast::Public.clean(cx),
stability: self.stab.clean(cx),
def_id: ast_util::local_def(self.id),
inner: MacroItem(Macro {
source: self.whence.to_src(cx),
}),
}
}
}
#[derive(Clone, RustcEncodable, RustcDecodable)]
pub struct Stability {
pub level: attr::StabilityLevel,
pub text: String
}
impl Clean<Stability> for attr::Stability {
fn clean(&self, _: &DocContext) -> Stability {
Stability {
level: self.level,
text: self.text.as_ref().map_or("".to_string(),
|interned| interned.get().to_string()),
}
}
}
impl Clean<Item> for ast::AssociatedType {
fn clean(&self, cx: &DocContext) -> Item {
Item {
source: self.ty_param.span.clean(cx),
name: Some(self.ty_param.ident.clean(cx)),
attrs: self.attrs.clean(cx),
inner: AssociatedTypeItem(self.ty_param.clean(cx)),
visibility: None,
def_id: ast_util::local_def(self.ty_param.id),
stability: None,
}
}
}
impl Clean<Item> for ty::AssociatedType {
fn clean(&self, cx: &DocContext) -> Item {
Item {
source: DUMMY_SP.clean(cx),
name: Some(self.name.clean(cx)),
attrs: Vec::new(),
// FIXME(#18048): this is wrong, but cross-crate associated types are broken
// anyway, for the time being.
inner: AssociatedTypeItem(TyParam {
name: self.name.clean(cx),
did: ast::DefId {
krate: 0,
node: ast::DUMMY_NODE_ID
},
bounds: vec![],
default: None,
}),
visibility: None,
def_id: self.def_id,
stability: None,
}
}
}
impl Clean<Item> for ast::Typedef {
fn clean(&self, cx: &DocContext) -> Item {
Item {
source: self.span.clean(cx),
name: Some(self.ident.clean(cx)),
attrs: self.attrs.clean(cx),
inner: TypedefItem(Typedef {
type_: self.typ.clean(cx),
generics: Generics {
lifetimes: Vec::new(),
type_params: Vec::new(),
where_predicates: Vec::new()
},
}),
visibility: None,
def_id: ast_util::local_def(self.id),
stability: None,
}
}
}
fn lang_struct(cx: &DocContext, did: Option<ast::DefId>,
t: ty::Ty, name: &str,
fallback: fn(Box<Type>) -> Type) -> Type {
let did = match did {
Some(did) => did,
None => return fallback(box t.clean(cx)),
};
let fqn = csearch::get_item_path(cx.tcx(), did);
2014-09-14 20:27:36 -07:00
let fqn: Vec<String> = fqn.into_iter().map(|i| {
i.to_string()
}).collect();
cx.external_paths.borrow_mut().as_mut().unwrap().insert(did, (fqn, TypeStruct));
ResolvedPath {
typarams: None,
did: did,
path: Path {
global: false,
segments: vec![PathSegment {
name: name.to_string(),
params: PathParameters::AngleBracketed {
lifetimes: vec![],
types: vec![t.clean(cx)],
bindings: vec![]
}
}],
},
}
}
/// An equality constraint on an associated type, e.g. `A=Bar` in `Foo<A=Bar>`
2015-01-07 18:53:58 -08:00
#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable, Show)]
pub struct TypeBinding {
pub name: String,
pub ty: Type
}
impl Clean<TypeBinding> for ast::TypeBinding {
fn clean(&self, cx: &DocContext) -> TypeBinding {
TypeBinding {
name: self.ident.clean(cx),
ty: self.ty.clean(cx)
}
}
}