From 8b8e70ba1d47ca76217980f0c4c6f55b60a06e06 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 22 May 2014 22:02:34 -0700 Subject: std: Add doc(noinline) to the prelude reexports --- src/libstd/prelude.rs | 91 +++++++++++++++++++++++++++------------------------ 1 file changed, 49 insertions(+), 42 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/prelude.rs b/src/libstd/prelude.rs index 8d028a7a96a..ef05f3b167a 100644 --- a/src/libstd/prelude.rs +++ b/src/libstd/prelude.rs @@ -38,55 +38,62 @@ //! `drop`, `spawn`, and `channel`. // Reexported core operators -pub use kinds::{Copy, Send, Sized, Share}; -pub use ops::{Add, Sub, Mul, Div, Rem, Neg, Not}; -pub use ops::{BitAnd, BitOr, BitXor}; -pub use ops::{Drop, Deref, DerefMut}; -pub use ops::{Shl, Shr, Index}; -pub use option::{Option, Some, None}; -pub use result::{Result, Ok, Err}; +#[doc(noinline)] pub use kinds::{Copy, Send, Sized, Share}; +#[doc(noinline)] pub use ops::{Add, Sub, Mul, Div, Rem, Neg, Not}; +#[doc(noinline)] pub use ops::{BitAnd, BitOr, BitXor}; +#[doc(noinline)] pub use ops::{Drop, Deref, DerefMut}; +#[doc(noinline)] pub use ops::{Shl, Shr, Index}; +#[doc(noinline)] pub use option::{Option, Some, None}; +#[doc(noinline)] pub use result::{Result, Ok, Err}; // Reexported functions -pub use from_str::from_str; -pub use iter::range; -pub use mem::drop; +#[doc(noinline)] pub use from_str::from_str; +#[doc(noinline)] pub use iter::range; +#[doc(noinline)] pub use mem::drop; // Reexported types and traits -pub use ascii::{Ascii, AsciiCast, OwnedAsciiCast, AsciiStr, IntoBytes}; -pub use c_str::ToCStr; -pub use char::Char; -pub use clone::Clone; -pub use cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater, Equiv}; -pub use container::{Container, Mutable, Map, MutableMap, Set, MutableSet}; -pub use iter::{FromIterator, Extendable}; -pub use iter::{Iterator, DoubleEndedIterator, RandomAccessIterator, CloneableIterator}; -pub use iter::{OrdIterator, MutableDoubleEndedIterator, ExactSize}; -pub use num::{Num, NumCast, CheckedAdd, CheckedSub, CheckedMul}; -pub use num::{Signed, Unsigned}; -pub use num::{Primitive, Int, Float, FloatMath, ToPrimitive, FromPrimitive}; -pub use option::Expect; -pub use owned::Box; -pub use path::{GenericPath, Path, PosixPath, WindowsPath}; -pub use ptr::RawPtr; -pub use io::{Buffer, Writer, Reader, Seek}; -pub use str::{Str, StrVector, StrSlice, OwnedStr, IntoMaybeOwned}; -pub use str::{StrAllocating}; -pub use to_str::{ToStr, IntoStr}; -pub use tuple::{Tuple1, Tuple2, Tuple3, Tuple4}; -pub use tuple::{Tuple5, Tuple6, Tuple7, Tuple8}; -pub use tuple::{Tuple9, Tuple10, Tuple11, Tuple12}; -pub use slice::{CloneableVector, ImmutableCloneableVector, MutableCloneableVector}; -pub use slice::{ImmutableVector, MutableVector}; -pub use slice::{ImmutableEqVector, ImmutableTotalOrdVector, MutableTotalOrdVector}; -pub use slice::{Vector, VectorVector, OwnedVector, MutableVectorAllocating}; -pub use string::String; -pub use vec::Vec; +#[doc(noinline)] pub use ascii::{Ascii, AsciiCast, OwnedAsciiCast, AsciiStr}; +#[doc(noinline)] pub use ascii::IntoBytes; +#[doc(noinline)] pub use c_str::ToCStr; +#[doc(noinline)] pub use char::Char; +#[doc(noinline)] pub use clone::Clone; +#[doc(noinline)] pub use cmp::{Eq, Ord, TotalEq, TotalOrd}; +#[doc(noinline)] pub use cmp::{Ordering, Less, Equal, Greater, Equiv}; +#[doc(noinline)] pub use container::{Container, Mutable, Map, MutableMap}; +#[doc(noinline)] pub use container::{Set, MutableSet}; +#[doc(noinline)] pub use iter::{FromIterator, Extendable, ExactSize}; +#[doc(noinline)] pub use iter::{Iterator, DoubleEndedIterator}; +#[doc(noinline)] pub use iter::{RandomAccessIterator, CloneableIterator}; +#[doc(noinline)] pub use iter::{OrdIterator, MutableDoubleEndedIterator}; +#[doc(noinline)] pub use num::{Num, NumCast, CheckedAdd, CheckedSub, CheckedMul}; +#[doc(noinline)] pub use num::{Signed, Unsigned, Primitive, Int, Float}; +#[doc(noinline)] pub use num::{FloatMath, ToPrimitive, FromPrimitive}; +#[doc(noinline)] pub use option::Expect; +#[doc(noinline)] pub use owned::Box; +#[doc(noinline)] pub use path::{GenericPath, Path, PosixPath, WindowsPath}; +#[doc(noinline)] pub use ptr::RawPtr; +#[doc(noinline)] pub use io::{Buffer, Writer, Reader, Seek}; +#[doc(noinline)] pub use str::{Str, StrVector, StrSlice, OwnedStr}; +#[doc(noinline)] pub use str::{IntoMaybeOwned, StrAllocating}; +#[doc(noinline)] pub use to_str::{ToStr, IntoStr}; +#[doc(noinline)] pub use tuple::{Tuple1, Tuple2, Tuple3, Tuple4}; +#[doc(noinline)] pub use tuple::{Tuple5, Tuple6, Tuple7, Tuple8}; +#[doc(noinline)] pub use tuple::{Tuple9, Tuple10, Tuple11, Tuple12}; +#[doc(noinline)] pub use slice::{CloneableVector, ImmutableCloneableVector}; +#[doc(noinline)] pub use slice::{MutableCloneableVector, MutableTotalOrdVector}; +#[doc(noinline)] pub use slice::{ImmutableVector, MutableVector}; +#[doc(noinline)] pub use slice::{ImmutableEqVector, ImmutableTotalOrdVector}; +#[doc(noinline)] pub use slice::{Vector, VectorVector, OwnedVector}; +#[doc(noinline)] pub use slice::MutableVectorAllocating; +#[doc(noinline)] pub use string::String; +#[doc(noinline)] pub use vec::Vec; // Reexported runtime types -pub use comm::{sync_channel, channel, SyncSender, Sender, Receiver}; -pub use task::spawn; +#[doc(noinline)] pub use comm::{sync_channel, channel}; +#[doc(noinline)] pub use comm::{SyncSender, Sender, Receiver}; +#[doc(noinline)] pub use task::spawn; // Reexported statics #[cfg(not(test))] -pub use gc::GC; +#[doc(noinline)] pub use gc::GC; -- cgit 1.4.1-3-g733a5 From 3100bc5b82257820051774eb4aa0447b12f3616a Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 24 May 2014 11:56:38 -0700 Subject: rustdoc: Move inlining to its own module --- src/doc/rustdoc.md | 6 +- src/librustc/metadata/csearch.rs | 2 +- src/librustc/metadata/decoder.rs | 2 +- src/librustdoc/clean.rs | 2083 ------------------------------------ src/librustdoc/clean/inline.rs | 278 +++++ src/librustdoc/clean/mod.rs | 1830 +++++++++++++++++++++++++++++++ src/librustdoc/html/render.rs | 39 +- src/librustdoc/html/static/main.js | 12 +- src/libstd/lib.rs | 12 +- src/libstd/prelude.rs | 98 +- 10 files changed, 2208 insertions(+), 2154 deletions(-) delete mode 100644 src/librustdoc/clean.rs create mode 100644 src/librustdoc/clean/inline.rs create mode 100644 src/librustdoc/clean/mod.rs (limited to 'src/libstd') diff --git a/src/doc/rustdoc.md b/src/doc/rustdoc.md index 625a7a6d802..1034c776ea6 100644 --- a/src/doc/rustdoc.md +++ b/src/doc/rustdoc.md @@ -41,7 +41,9 @@ pub fn recalibrate() { # } ~~~ -Documentation can also be controlled via the `doc` attribute on items. +Documentation can also be controlled via the `doc` attribute on items. This is +implicitly done by the compiler when using the above form of doc comments +(converting the slash-based comments to `#[doc]` attributes). ~~~ #[doc = " @@ -50,6 +52,7 @@ Calculates the factorial of a number. Given the input integer `n`, this function will calculate `n!` and return it. "] pub fn factorial(n: int) -> int { if n < 2 {1} else {n * factorial(n)} } +# fn main() {} ~~~ The `doc` attribute can also be used to control how rustdoc emits documentation @@ -60,6 +63,7 @@ in some cases. // `pub use` reaches across crates, but this behavior can also be disabled. #[doc(no_inline)] pub use std::option::Option; +# fn main() {} ``` Doc comments are markdown, and are currently parsed with the diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index d7f603d1909..d407cc04680 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -308,7 +308,7 @@ pub fn get_missing_lang_items(cstore: &cstore::CStore, cnum: ast::CrateNum) } pub fn get_method_arg_names(cstore: &cstore::CStore, did: ast::DefId) - -> Vec + -> Vec { let cdata = cstore.get_crate_data(did.krate); decoder::get_method_arg_names(&*cdata, did.node) diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 26149785653..e8be05feae8 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -1310,7 +1310,7 @@ pub fn get_missing_lang_items(cdata: Cmd) return result; } -pub fn get_method_arg_names(cdata: Cmd, id: ast::NodeId) -> Vec { +pub fn get_method_arg_names(cdata: Cmd, id: ast::NodeId) -> Vec { let mut ret = Vec::new(); let method_doc = lookup_item(id, cdata.data()); match reader::maybe_get_doc(method_doc, tag_method_argument_names) { diff --git a/src/librustdoc/clean.rs b/src/librustdoc/clean.rs deleted file mode 100644 index ab953419a41..00000000000 --- a/src/librustdoc/clean.rs +++ /dev/null @@ -1,2083 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! This module contains the "cleaned" pieces of the AST, and the functions -//! that clean them. - -use syntax; -use syntax::ast; -use syntax::ast_util; -use syntax::attr; -use syntax::attr::{AttributeMethods, AttrMetaMethods}; -use syntax::codemap::Pos; -use syntax::parse::token::InternedString; -use syntax::parse::token; - -use rustc::back::link; -use rustc::driver::driver; -use rustc::metadata::cstore; -use rustc::metadata::csearch; -use rustc::metadata::decoder; -use rustc::middle::ty; - -use std::rc::Rc; - -use core; -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.2"; - -pub trait Clean { - fn clean(&self) -> T; -} - -impl, U> Clean> for Vec { - fn clean(&self) -> Vec { - self.iter().map(|x| x.clean()).collect() - } -} - -impl, U> Clean for @T { - fn clean(&self) -> U { - (**self).clean() - } -} - -impl, U> Clean for Rc { - fn clean(&self) -> U { - (**self).clean() - } -} - -impl, U> Clean> for Option { - fn clean(&self) -> Option { - match self { - &None => None, - &Some(ref v) => Some(v.clean()) - } - } -} - -impl, U> Clean> for syntax::owned_slice::OwnedSlice { - fn clean(&self) -> Vec { - self.iter().map(|x| x.clean()).collect() - } -} - -#[deriving(Clone, Encodable, Decodable)] -pub struct Crate { - pub name: String, - pub module: Option, - pub externs: Vec<(ast::CrateNum, ExternalCrate)>, -} - -impl<'a> Clean for visit_ast::RustdocVisitor<'a> { - fn clean(&self) -> Crate { - let cx = super::ctxtkey.get().unwrap(); - - let mut externs = Vec::new(); - cx.sess().cstore.iter_crate_data(|n, meta| { - externs.push((n, meta.clean())); - }); - - let input = driver::FileInput(cx.src.clone()); - let t_outputs = driver::build_output_filenames(&input, - &None, - &None, - self.attrs.as_slice(), - cx.sess()); - let id = link::find_crate_id(self.attrs.as_slice(), - t_outputs.out_filestem.as_slice()); - Crate { - name: id.name.to_strbuf(), - module: Some(self.module.clean()), - externs: externs, - } - } -} - -#[deriving(Clone, Encodable, Decodable)] -pub struct ExternalCrate { - pub name: String, - pub attrs: Vec, -} - -impl Clean for cstore::crate_metadata { - fn clean(&self) -> ExternalCrate { - ExternalCrate { - name: self.name.to_strbuf(), - attrs: decoder::get_crate_attributes(self.data()).clean() - .move_iter() - .collect(), - } - } -} - -/// 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. -#[deriving(Clone, Encodable, Decodable)] -pub struct Item { - /// Stringified span - pub source: Span, - /// Not everything has a name. E.g., impls - pub name: Option, - pub attrs: Vec , - pub inner: ItemEnum, - pub visibility: Option, - pub def_id: ast::DefId, -} - -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.as_slice() => { - 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.as_slice() => { - 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.as_slice() => { - return true - } - _ => (), - } - } - }, - None => () - } - return false; - } - - pub fn is_mod(&self) -> bool { - match self.inner { ModuleItem(..) => true, _ => false } - } - pub fn is_trait(&self) -> bool { - match self.inner { TraitItem(..) => true, _ => false } - } - pub fn is_struct(&self) -> bool { - match self.inner { StructItem(..) => true, _ => false } - } - pub fn is_enum(&self) -> bool { - match self.inner { EnumItem(..) => true, _ => false } - } - pub fn is_fn(&self) -> bool { - match self.inner { FunctionItem(..) => true, _ => false } - } -} - -#[deriving(Clone, Encodable, Decodable)] -pub enum ItemEnum { - StructItem(Struct), - EnumItem(Enum), - FunctionItem(Function), - ModuleItem(Module), - TypedefItem(Typedef), - StaticItem(Static), - TraitItem(Trait), - ImplItem(Impl), - /// `use` and `extern crate` - ViewItemItem(ViewItem), - /// A method signature only. Used for required methods in traits (ie, - /// non-default-methods). - TyMethodItem(TyMethod), - /// A method with a body. - MethodItem(Method), - StructFieldItem(StructField), - VariantItem(Variant), - /// `fn`s from an extern block - ForeignFunctionItem(Function), - /// `static`s from an extern block - ForeignStaticItem(Static), - MacroItem(Macro), -} - -#[deriving(Clone, Encodable, Decodable)] -pub struct Module { - pub items: Vec, - pub is_crate: bool, -} - -impl Clean for doctree::Module { - fn clean(&self) -> Item { - let name = if self.name.is_some() { - self.name.unwrap().clean() - } else { - "".to_strbuf() - }; - let mut foreigns = Vec::new(); - for subforeigns in self.foreigns.clean().move_iter() { - for foreign in subforeigns.move_iter() { - foreigns.push(foreign) - } - } - let items: Vec > = vec!( - self.structs.clean().move_iter().collect(), - self.enums.clean().move_iter().collect(), - self.fns.clean().move_iter().collect(), - foreigns, - self.mods.clean().move_iter().collect(), - self.typedefs.clean().move_iter().collect(), - self.statics.clean().move_iter().collect(), - self.traits.clean().move_iter().collect(), - self.impls.clean().move_iter().collect(), - self.view_items.clean().move_iter() - .flat_map(|s| s.move_iter()).collect(), - self.macros.clean().move_iter().collect() - ); - - // determine if we should display the inner contents or - // the outer `mod` item for the source code. - let where = { - let ctxt = super::ctxtkey.get().unwrap(); - let cm = ctxt.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 - } - }; - - Item { - name: Some(name), - attrs: self.attrs.clean(), - source: where.clean(), - visibility: self.vis.clean(), - def_id: ast_util::local_def(self.id), - inner: ModuleItem(Module { - is_crate: self.is_crate, - items: items.iter() - .flat_map(|x| x.iter().map(|x| (*x).clone())) - .collect(), - }) - } - } -} - -#[deriving(Clone, Encodable, Decodable)] -pub enum Attribute { - Word(String), - List(String, Vec ), - NameValue(String, String) -} - -impl Clean for ast::MetaItem { - fn clean(&self) -> Attribute { - match self.node { - ast::MetaWord(ref s) => Word(s.get().to_strbuf()), - ast::MetaList(ref s, ref l) => { - List(s.get().to_strbuf(), l.clean().move_iter().collect()) - } - ast::MetaNameValue(ref s, ref v) => { - NameValue(s.get().to_strbuf(), lit_to_str(v)) - } - } - } -} - -impl Clean for ast::Attribute { - fn clean(&self) -> Attribute { - self.desugar_doc().node.value.clean() - } -} - -// 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 { - match *self { - NameValue(_, ref v) => { - Some(token::intern_and_get_ident(v.as_slice())) - } - _ => None, - } - } - fn meta_item_list<'a>(&'a self) -> Option<&'a [@ast::MetaItem]> { None } - fn name_str_pair(&self) -> Option<(InternedString, InternedString)> { - None - } -} -impl<'a> attr::AttrMetaMethods for &'a Attribute { - fn name(&self) -> InternedString { (**self).name() } - fn value_str(&self) -> Option { (**self).value_str() } - fn meta_item_list<'a>(&'a self) -> Option<&'a [@ast::MetaItem]> { None } - fn name_str_pair(&self) -> Option<(InternedString, InternedString)> { - None - } -} - -#[deriving(Clone, Encodable, Decodable)] -pub struct TyParam { - pub name: String, - pub did: ast::DefId, - pub bounds: Vec, -} - -impl Clean for ast::TyParam { - fn clean(&self) -> TyParam { - TyParam { - name: self.ident.clean(), - did: ast::DefId { krate: ast::LOCAL_CRATE, node: self.id }, - bounds: self.bounds.clean().move_iter().collect(), - } - } -} - -impl Clean for ty::TypeParameterDef { - fn clean(&self) -> TyParam { - let cx = super::ctxtkey.get().unwrap(); - cx.external_typarams.borrow_mut().get_mut_ref().insert(self.def_id, - self.ident.clean()); - TyParam { - name: self.ident.clean(), - did: self.def_id, - bounds: self.bounds.clean(), - } - } -} - -#[deriving(Clone, Encodable, Decodable)] -pub enum TyParamBound { - RegionBound, - TraitBound(Type) -} - -impl Clean for ast::TyParamBound { - fn clean(&self) -> TyParamBound { - match *self { - ast::StaticRegionTyParamBound => RegionBound, - ast::OtherRegionTyParamBound(_) => RegionBound, - ast::TraitTyParamBound(ref t) => TraitBound(t.clean()), - } - } -} - -fn external_path(name: &str) -> Path { - Path { - global: false, - segments: vec![PathSegment { - name: name.to_strbuf(), - lifetimes: Vec::new(), - types: Vec::new(), - }] - } -} - -impl Clean for ty::BuiltinBound { - fn clean(&self) -> TyParamBound { - let cx = super::ctxtkey.get().unwrap(); - let tcx = match cx.maybe_typed { - core::Typed(ref tcx) => tcx, - core::NotTyped(_) => return RegionBound, - }; - let (did, path) = match *self { - ty::BoundStatic => return RegionBound, - ty::BoundSend => - (tcx.lang_items.send_trait().unwrap(), external_path("Send")), - ty::BoundSized => - (tcx.lang_items.sized_trait().unwrap(), external_path("Sized")), - ty::BoundCopy => - (tcx.lang_items.copy_trait().unwrap(), external_path("Copy")), - ty::BoundShare => - (tcx.lang_items.share_trait().unwrap(), external_path("Share")), - }; - let fqn = csearch::get_item_path(tcx, did); - let fqn = fqn.move_iter().map(|i| i.to_str().to_strbuf()).collect(); - cx.external_paths.borrow_mut().get_mut_ref().insert(did, - (fqn, TypeTrait)); - TraitBound(ResolvedPath { - path: path, - typarams: None, - did: did, - }) - } -} - -impl Clean for ty::TraitRef { - fn clean(&self) -> TyParamBound { - let cx = super::ctxtkey.get().unwrap(); - let tcx = match cx.maybe_typed { - core::Typed(ref tcx) => tcx, - core::NotTyped(_) => return RegionBound, - }; - let fqn = csearch::get_item_path(tcx, self.def_id); - let fqn = fqn.move_iter().map(|i| i.to_str().to_strbuf()) - .collect::>(); - let path = external_path(fqn.last().unwrap().as_slice()); - cx.external_paths.borrow_mut().get_mut_ref().insert(self.def_id, - (fqn, TypeTrait)); - TraitBound(ResolvedPath { - path: path, - typarams: None, - did: self.def_id, - }) - } -} - -impl Clean> for ty::ParamBounds { - fn clean(&self) -> Vec { - let mut v = Vec::new(); - for b in self.builtin_bounds.iter() { - if b != ty::BoundSized { - v.push(b.clean()); - } - } - for t in self.trait_bounds.iter() { - v.push(t.clean()); - } - return v; - } -} - -impl Clean>> for ty::substs { - fn clean(&self) -> Option> { - let mut v = Vec::new(); - match self.regions { - ty::NonerasedRegions(..) => v.push(RegionBound), - ty::ErasedRegions => {} - } - v.extend(self.tps.iter().map(|t| TraitBound(t.clean()))); - - if v.len() > 0 {Some(v)} else {None} - } -} - -#[deriving(Clone, Encodable, Decodable, Eq)] -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.as_slice(); - return s; - } -} - -impl Clean for ast::Lifetime { - fn clean(&self) -> Lifetime { - Lifetime(token::get_name(self.name).get().to_strbuf()) - } -} - -impl Clean for ty::RegionParameterDef { - fn clean(&self) -> Lifetime { - Lifetime(token::get_name(self.name).get().to_strbuf()) - } -} - -impl Clean> for ty::Region { - fn clean(&self) -> Option { - match *self { - ty::ReStatic => Some(Lifetime("static".to_strbuf())), - ty::ReLateBound(_, ty::BrNamed(_, name)) => - Some(Lifetime(token::get_name(name).get().to_strbuf())), - - ty::ReLateBound(..) | - ty::ReEarlyBound(..) | - ty::ReFree(..) | - ty::ReScope(..) | - ty::ReInfer(..) | - ty::ReEmpty(..) => None - } - } -} - -// maybe use a Generic enum and use ~[Generic]? -#[deriving(Clone, Encodable, Decodable)] -pub struct Generics { - pub lifetimes: Vec, - pub type_params: Vec, -} - -impl Clean for ast::Generics { - fn clean(&self) -> Generics { - Generics { - lifetimes: self.lifetimes.clean().move_iter().collect(), - type_params: self.ty_params.clean().move_iter().collect(), - } - } -} - -impl Clean for ty::Generics { - fn clean(&self) -> Generics { - Generics { - lifetimes: self.region_param_defs.clean(), - type_params: self.type_param_defs.clean(), - } - } -} - -#[deriving(Clone, Encodable, Decodable)] -pub struct Method { - pub generics: Generics, - pub self_: SelfTy, - pub fn_style: ast::FnStyle, - pub decl: FnDecl, -} - -impl Clean for ast::Method { - fn clean(&self) -> Item { - let inputs = match self.explicit_self.node { - ast::SelfStatic => self.decl.inputs.as_slice(), - _ => self.decl.inputs.slice_from(1) - }; - let decl = FnDecl { - inputs: Arguments { - values: inputs.iter().map(|x| x.clean()).collect(), - }, - output: (self.decl.output.clean()), - cf: self.decl.cf.clean(), - attrs: Vec::new() - }; - Item { - name: Some(self.ident.clean()), - attrs: self.attrs.clean().move_iter().collect(), - source: self.span.clean(), - def_id: ast_util::local_def(self.id.clone()), - visibility: self.vis.clean(), - inner: MethodItem(Method { - generics: self.generics.clean(), - self_: self.explicit_self.node.clean(), - fn_style: self.fn_style.clone(), - decl: decl, - }), - } - } -} - -#[deriving(Clone, Encodable, Decodable)] -pub struct TyMethod { - pub fn_style: ast::FnStyle, - pub decl: FnDecl, - pub generics: Generics, - pub self_: SelfTy, -} - -impl Clean for ast::TypeMethod { - fn clean(&self) -> Item { - let inputs = match self.explicit_self.node { - ast::SelfStatic => self.decl.inputs.as_slice(), - _ => self.decl.inputs.slice_from(1) - }; - let decl = FnDecl { - inputs: Arguments { - values: inputs.iter().map(|x| x.clean()).collect(), - }, - output: (self.decl.output.clean()), - cf: self.decl.cf.clean(), - attrs: Vec::new() - }; - Item { - name: Some(self.ident.clean()), - attrs: self.attrs.clean().move_iter().collect(), - source: self.span.clean(), - def_id: ast_util::local_def(self.id), - visibility: None, - inner: TyMethodItem(TyMethod { - fn_style: self.fn_style.clone(), - decl: decl, - self_: self.explicit_self.node.clean(), - generics: self.generics.clean(), - }), - } - } -} - -#[deriving(Clone, Encodable, Decodable, Eq)] -pub enum SelfTy { - SelfStatic, - SelfValue, - SelfBorrowed(Option, Mutability), - SelfOwned, -} - -impl Clean for ast::ExplicitSelf_ { - fn clean(&self) -> SelfTy { - match *self { - ast::SelfStatic => SelfStatic, - ast::SelfValue => SelfValue, - ast::SelfUniq => SelfOwned, - ast::SelfRegion(lt, mt) => SelfBorrowed(lt.clean(), mt.clean()), - } - } -} - -#[deriving(Clone, Encodable, Decodable)] -pub struct Function { - pub decl: FnDecl, - pub generics: Generics, - pub fn_style: ast::FnStyle, -} - -impl Clean for doctree::Function { - fn clean(&self) -> Item { - Item { - name: Some(self.name.clean()), - attrs: self.attrs.clean(), - source: self.where.clean(), - visibility: self.vis.clean(), - def_id: ast_util::local_def(self.id), - inner: FunctionItem(Function { - decl: self.decl.clean(), - generics: self.generics.clean(), - fn_style: self.fn_style, - }), - } - } -} - -#[deriving(Clone, Encodable, Decodable)] -pub struct ClosureDecl { - pub lifetimes: Vec, - pub decl: FnDecl, - pub onceness: ast::Onceness, - pub fn_style: ast::FnStyle, - pub bounds: Vec, -} - -impl Clean for ast::ClosureTy { - fn clean(&self) -> ClosureDecl { - ClosureDecl { - lifetimes: self.lifetimes.clean(), - decl: self.decl.clean(), - onceness: self.onceness, - fn_style: self.fn_style, - bounds: match self.bounds { - Some(ref x) => x.clean().move_iter().collect(), - None => Vec::new() - }, - } - } -} - -#[deriving(Clone, Encodable, Decodable)] -pub struct FnDecl { - pub inputs: Arguments, - pub output: Type, - pub cf: RetStyle, - pub attrs: Vec, -} - -#[deriving(Clone, Encodable, Decodable)] -pub struct Arguments { - pub values: Vec, -} - -impl Clean for ast::FnDecl { - fn clean(&self) -> FnDecl { - FnDecl { - inputs: Arguments { - values: self.inputs.iter().map(|x| x.clean()).collect(), - }, - output: (self.output.clean()), - cf: self.cf.clean(), - attrs: Vec::new() - } - } -} - -impl<'a> Clean for (ast::DefId, &'a ty::FnSig) { - fn clean(&self) -> FnDecl { - let cx = super::ctxtkey.get().unwrap(); - let tcx = match cx.maybe_typed { - core::Typed(ref tcx) => tcx, - core::NotTyped(_) => fail!(), - }; - let (did, sig) = *self; - let mut names = if did.node != 0 { - csearch::get_method_arg_names(&tcx.sess.cstore, did).move_iter() - } else { - Vec::new().move_iter() - }.peekable(); - if names.peek().map(|s| s.as_slice()) == Some("self") { - let _ = names.next(); - } - if did.node == 0 { - let _ = names.len(); - } - FnDecl { - output: sig.output.clean(), - cf: Return, - attrs: Vec::new(), - inputs: Arguments { - values: sig.inputs.iter().map(|t| { - Argument { - type_: t.clean(), - id: 0, - name: names.next().unwrap_or("".to_strbuf()), - } - }).collect(), - }, - } - } -} - -#[deriving(Clone, Encodable, Decodable)] -pub struct Argument { - pub type_: Type, - pub name: String, - pub id: ast::NodeId, -} - -impl Clean for ast::Arg { - fn clean(&self) -> Argument { - Argument { - name: name_from_pat(self.pat), - type_: (self.ty.clean()), - id: self.id - } - } -} - -#[deriving(Clone, Encodable, Decodable)] -pub enum RetStyle { - NoReturn, - Return -} - -impl Clean for ast::RetStyle { - fn clean(&self) -> RetStyle { - match *self { - ast::Return => Return, - ast::NoReturn => NoReturn - } - } -} - -#[deriving(Clone, Encodable, Decodable)] -pub struct Trait { - pub methods: Vec, - pub generics: Generics, - pub parents: Vec, -} - -impl Clean for doctree::Trait { - fn clean(&self) -> Item { - Item { - name: Some(self.name.clean()), - attrs: self.attrs.clean(), - source: self.where.clean(), - def_id: ast_util::local_def(self.id), - visibility: self.vis.clean(), - inner: TraitItem(Trait { - methods: self.methods.clean(), - generics: self.generics.clean(), - parents: self.parents.clean(), - }), - } - } -} - -impl Clean for ast::TraitRef { - fn clean(&self) -> Type { - resolve_type(self.path.clean(), None, self.ref_id) - } -} - -#[deriving(Clone, Encodable, Decodable)] -pub enum TraitMethod { - Required(Item), - Provided(Item), -} - -impl TraitMethod { - pub fn is_req(&self) -> bool { - match self { - &Required(..) => true, - _ => false, - } - } - pub fn is_def(&self) -> bool { - match self { - &Provided(..) => true, - _ => false, - } - } - pub fn item<'a>(&'a self) -> &'a Item { - match *self { - Required(ref item) => item, - Provided(ref item) => item, - } - } -} - -impl Clean for ast::TraitMethod { - fn clean(&self) -> TraitMethod { - match self { - &ast::Required(ref t) => Required(t.clean()), - &ast::Provided(ref t) => Provided(t.clean()), - } - } -} - -impl Clean for ty::Method { - fn clean(&self) -> TraitMethod { - let m = if self.provided_source.is_some() {Provided} else {Required}; - let cx = super::ctxtkey.get().unwrap(); - let tcx = match cx.maybe_typed { - core::Typed(ref tcx) => tcx, - core::NotTyped(_) => fail!(), - }; - let (self_, sig) = match self.explicit_self { - ast::SelfStatic => (ast::SelfStatic.clean(), self.fty.sig.clone()), - s => { - let sig = ty::FnSig { - inputs: Vec::from_slice(self.fty.sig.inputs.slice_from(1)), - ..self.fty.sig.clone() - }; - let s = match s { - ast::SelfRegion(..) => { - match ty::get(*self.fty.sig.inputs.get(0)).sty { - ty::ty_rptr(r, mt) => { - SelfBorrowed(r.clean(), mt.mutbl.clean()) - } - _ => s.clean(), - } - } - s => s.clean(), - }; - (s, sig) - } - }; - - m(Item { - name: Some(self.ident.clean()), - visibility: Some(ast::Inherited), - def_id: self.def_id, - attrs: load_attrs(tcx, self.def_id), - source: Span::empty(), - inner: TyMethodItem(TyMethod { - fn_style: self.fty.fn_style, - generics: self.generics.clean(), - self_: self_, - decl: (self.def_id, &sig).clean(), - }) - }) - } -} - -/// 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. -#[deriving(Clone, Encodable, Decodable)] -pub enum Type { - /// structs/enums/traits (anything that'd be an ast::TyPath) - ResolvedPath { - pub path: Path, - pub typarams: Option>, - pub did: ast::DefId, - }, - // 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(ast::DefId), - /// For references to self - Self(ast::DefId), - /// Primitives are just the fixed-size numeric types (plus int/uint/float), and char. - Primitive(ast::PrimTy), - Closure(Box, Option), - Proc(Box), - /// extern "ABI" fn - BareFunction(Box), - Tuple(Vec), - Vector(Box), - FixedVector(Box, String), - String, - Bool, - /// aka TyNil - Unit, - /// aka TyBot - Bottom, - Unique(Box), - Managed(Box), - RawPointer(Mutability, Box), - BorrowedRef { - pub lifetime: Option, - pub mutability: Mutability, - pub type_: Box, - }, - // region, raw, other boxes, mutable -} - -#[deriving(Clone, Encodable, Decodable)] -pub enum TypeKind { - TypeEnum, - TypeFunction, - TypeModule, - TypeStatic, - TypeStruct, - TypeTrait, - TypeVariant, -} - -impl Clean for ast::Ty { - fn clean(&self) -> Type { - use syntax::ast::*; - match self.node { - TyNil => Unit, - TyPtr(ref m) => RawPointer(m.mutbl.clean(), box m.ty.clean()), - TyRptr(ref l, ref m) => - BorrowedRef {lifetime: l.clean(), mutability: m.mutbl.clean(), - type_: box m.ty.clean()}, - TyBox(ty) => Managed(box ty.clean()), - TyUniq(ty) => Unique(box ty.clean()), - TyVec(ty) => Vector(box ty.clean()), - TyFixedLengthVec(ty, ref e) => FixedVector(box ty.clean(), - e.span.to_src()), - TyTup(ref tys) => Tuple(tys.iter().map(|x| x.clean()).collect()), - TyPath(ref p, ref tpbs, id) => { - resolve_type(p.clean(), - tpbs.clean().map(|x| x.move_iter().collect()), - id) - } - TyClosure(ref c, region) => Closure(box c.clean(), region.clean()), - TyProc(ref c) => Proc(box c.clean()), - TyBareFn(ref barefn) => BareFunction(box barefn.clean()), - TyBot => Bottom, - ref x => fail!("Unimplemented type {:?}", x), - } - } -} - -impl Clean for ty::t { - fn clean(&self) -> Type { - match ty::get(*self).sty { - ty::ty_nil => Unit, - ty::ty_bot => Bottom, - ty::ty_bool => Bool, - ty::ty_char => Primitive(ast::TyChar), - ty::ty_int(t) => Primitive(ast::TyInt(t)), - ty::ty_uint(u) => Primitive(ast::TyUint(u)), - ty::ty_float(f) => Primitive(ast::TyFloat(f)), - ty::ty_box(t) => Managed(box t.clean()), - ty::ty_uniq(t) => Unique(box t.clean()), - ty::ty_str => String, - ty::ty_vec(mt, None) => Vector(box mt.ty.clean()), - ty::ty_vec(mt, Some(i)) => FixedVector(box mt.ty.clean(), - format_strbuf!("{}", i)), - ty::ty_ptr(mt) => RawPointer(mt.mutbl.clean(), box mt.ty.clean()), - ty::ty_rptr(r, mt) => BorrowedRef { - lifetime: r.clean(), - mutability: mt.mutbl.clean(), - type_: box mt.ty.clean(), - }, - ty::ty_bare_fn(ref fty) => BareFunction(box BareFunctionDecl { - fn_style: fty.fn_style, - generics: Generics { - lifetimes: Vec::new(), type_params: Vec::new() - }, - decl: (ast_util::local_def(0), &fty.sig).clean(), - abi: fty.abi.to_str().to_strbuf(), - }), - ty::ty_closure(ref fty) => { - let decl = box ClosureDecl { - lifetimes: Vec::new(), // FIXME: this looks wrong... - decl: (ast_util::local_def(0), &fty.sig).clean(), - onceness: fty.onceness, - fn_style: fty.fn_style, - bounds: fty.bounds.iter().map(|i| i.clean()).collect(), - }; - match fty.store { - ty::UniqTraitStore => Proc(decl), - ty::RegionTraitStore(ref r, _) => Closure(decl, r.clean()), - } - } - ty::ty_struct(did, ref substs) | - ty::ty_enum(did, ref substs) | - ty::ty_trait(box ty::TyTrait { def_id: did, ref substs, .. }) => { - let cx = super::ctxtkey.get().unwrap(); - let tcx = match cx.maybe_typed { - core::Typed(ref tycx) => tycx, - core::NotTyped(_) => fail!(), - }; - let fqn = csearch::get_item_path(tcx, did); - let fqn: Vec = fqn.move_iter().map(|i| { - i.to_str().to_strbuf() - }).collect(); - let mut path = external_path(fqn.last() - .unwrap() - .to_str() - .as_slice()); - let kind = match ty::get(*self).sty { - ty::ty_struct(..) => TypeStruct, - ty::ty_trait(..) => TypeTrait, - _ => TypeEnum, - }; - path.segments.get_mut(0).lifetimes = match substs.regions { - ty::ErasedRegions => Vec::new(), - ty::NonerasedRegions(ref v) => { - v.iter().filter_map(|v| v.clean()).collect() - } - }; - path.segments.get_mut(0).types = substs.tps.clean(); - cx.external_paths.borrow_mut().get_mut_ref().insert(did, - (fqn, kind)); - ResolvedPath { - path: path, - typarams: None, - did: did, - } - } - ty::ty_tup(ref t) => Tuple(t.iter().map(|t| t.clean()).collect()), - - ty::ty_param(ref p) => Generic(p.def_id), - ty::ty_self(did) => Self(did), - - ty::ty_infer(..) => fail!("ty_infer"), - ty::ty_err => fail!("ty_err"), - } - } -} - -#[deriving(Clone, Encodable, Decodable)] -pub enum StructField { - HiddenStructField, // inserted later by strip passes - TypedStructField(Type), -} - -impl Clean for ast::StructField { - fn clean(&self) -> Item { - let (name, vis) = match self.node.kind { - ast::NamedField(id, vis) => (Some(id), vis), - ast::UnnamedField(vis) => (None, vis) - }; - Item { - name: name.clean(), - attrs: self.node.attrs.clean().move_iter().collect(), - source: self.span.clean(), - visibility: Some(vis), - def_id: ast_util::local_def(self.node.id), - inner: StructFieldItem(TypedStructField(self.node.ty.clean())), - } - } -} - -impl Clean for ty::field_ty { - fn clean(&self) -> Item { - use syntax::parse::token::special_idents::unnamed_field; - let name = if self.name == unnamed_field.name { - None - } else { - Some(self.name) - }; - let cx = super::ctxtkey.get().unwrap(); - let tcx = match cx.maybe_typed { - core::Typed(ref tycx) => tycx, - core::NotTyped(_) => fail!(), - }; - let ty = ty::lookup_item_type(tcx, self.id); - Item { - name: name.clean(), - attrs: load_attrs(tcx, self.id), - source: Span::empty(), - visibility: Some(self.vis), - def_id: self.id, - inner: StructFieldItem(TypedStructField(ty.ty.clean())), - } - } -} - -pub type Visibility = ast::Visibility; - -impl Clean> for ast::Visibility { - fn clean(&self) -> Option { - Some(*self) - } -} - -#[deriving(Clone, Encodable, Decodable)] -pub struct Struct { - pub struct_type: doctree::StructType, - pub generics: Generics, - pub fields: Vec, - pub fields_stripped: bool, -} - -impl Clean for doctree::Struct { - fn clean(&self) -> Item { - Item { - name: Some(self.name.clean()), - attrs: self.attrs.clean(), - source: self.where.clean(), - def_id: ast_util::local_def(self.id), - visibility: self.vis.clean(), - inner: StructItem(Struct { - struct_type: self.struct_type, - generics: self.generics.clean(), - fields: self.fields.clean(), - fields_stripped: false, - }), - } - } -} - -/// 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. -#[deriving(Clone, Encodable, Decodable)] -pub struct VariantStruct { - pub struct_type: doctree::StructType, - pub fields: Vec, - pub fields_stripped: bool, -} - -impl Clean for syntax::ast::StructDef { - fn clean(&self) -> VariantStruct { - VariantStruct { - struct_type: doctree::struct_type_from_def(self), - fields: self.fields.clean().move_iter().collect(), - fields_stripped: false, - } - } -} - -#[deriving(Clone, Encodable, Decodable)] -pub struct Enum { - pub variants: Vec, - pub generics: Generics, - pub variants_stripped: bool, -} - -impl Clean for doctree::Enum { - fn clean(&self) -> Item { - Item { - name: Some(self.name.clean()), - attrs: self.attrs.clean(), - source: self.where.clean(), - def_id: ast_util::local_def(self.id), - visibility: self.vis.clean(), - inner: EnumItem(Enum { - variants: self.variants.clean(), - generics: self.generics.clean(), - variants_stripped: false, - }), - } - } -} - -#[deriving(Clone, Encodable, Decodable)] -pub struct Variant { - pub kind: VariantKind, -} - -impl Clean for doctree::Variant { - fn clean(&self) -> Item { - Item { - name: Some(self.name.clean()), - attrs: self.attrs.clean(), - source: self.where.clean(), - visibility: self.vis.clean(), - def_id: ast_util::local_def(self.id), - inner: VariantItem(Variant { - kind: self.kind.clean(), - }), - } - } -} - -impl Clean for ty::VariantInfo { - fn clean(&self) -> Item { - // use syntax::parse::token::special_idents::unnamed_field; - let cx = super::ctxtkey.get().unwrap(); - let tcx = match cx.maybe_typed { - core::Typed(ref tycx) => tycx, - core::NotTyped(_) => fail!("tcx not present"), - }; - 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.iter().map(|t| t.clean()).collect()) - } - 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()), - attrs: Vec::new(), - visibility: Some(ast::Public), - def_id: self.id, // FIXME: this is not accurate - inner: StructFieldItem( - TypedStructField(ty.clean()) - ) - } - }).collect() - }) - } - }; - Item { - name: Some(self.name.clean()), - attrs: load_attrs(tcx, self.id), - source: Span::empty(), - visibility: Some(ast::Public), - def_id: self.id, - inner: VariantItem(Variant { kind: kind }), - } - } -} - -#[deriving(Clone, Encodable, Decodable)] -pub enum VariantKind { - CLikeVariant, - TupleVariant(Vec), - StructVariant(VariantStruct), -} - -impl Clean for ast::VariantKind { - fn clean(&self) -> VariantKind { - match self { - &ast::TupleVariantKind(ref args) => { - if args.len() == 0 { - CLikeVariant - } else { - TupleVariant(args.iter().map(|x| x.ty.clean()).collect()) - } - }, - &ast::StructVariantKind(ref sd) => StructVariant(sd.clean()), - } - } -} - -#[deriving(Clone, Encodable, Decodable)] -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_strbuf(), - loline: 0, locol: 0, - hiline: 0, hicol: 0, - } - } -} - -impl Clean for syntax::codemap::Span { - fn clean(&self) -> Span { - let ctxt = super::ctxtkey.get().unwrap(); - let cm = ctxt.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_strbuf(), - loline: lo.line, - locol: lo.col.to_uint(), - hiline: hi.line, - hicol: hi.col.to_uint(), - } - } -} - -#[deriving(Clone, Encodable, Decodable)] -pub struct Path { - pub global: bool, - pub segments: Vec, -} - -impl Clean for ast::Path { - fn clean(&self) -> Path { - Path { - global: self.global, - segments: self.segments.clean().move_iter().collect(), - } - } -} - -#[deriving(Clone, Encodable, Decodable)] -pub struct PathSegment { - pub name: String, - pub lifetimes: Vec, - pub types: Vec, -} - -impl Clean for ast::PathSegment { - fn clean(&self) -> PathSegment { - PathSegment { - name: self.identifier.clean(), - lifetimes: self.lifetimes.clean().move_iter().collect(), - types: self.types.clean().move_iter().collect() - } - } -} - -fn path_to_str(p: &ast::Path) -> String { - use syntax::parse::token; - - let mut s = String::new(); - let mut first = true; - for i in p.segments.iter().map(|x| token::get_ident(x.identifier)) { - if !first || p.global { - s.push_str("::"); - } else { - first = false; - } - s.push_str(i.get()); - } - s -} - -impl Clean for ast::Ident { - fn clean(&self) -> String { - token::get_ident(*self).get().to_strbuf() - } -} - -impl Clean for ast::Name { - fn clean(&self) -> StrBuf { - token::get_name(*self).get().to_strbuf() - } -} - -#[deriving(Clone, Encodable, Decodable)] -pub struct Typedef { - pub type_: Type, - pub generics: Generics, -} - -impl Clean for doctree::Typedef { - fn clean(&self) -> Item { - Item { - name: Some(self.name.clean()), - attrs: self.attrs.clean(), - source: self.where.clean(), - def_id: ast_util::local_def(self.id.clone()), - visibility: self.vis.clean(), - inner: TypedefItem(Typedef { - type_: self.ty.clean(), - generics: self.gen.clean(), - }), - } - } -} - -#[deriving(Clone, Encodable, Decodable)] -pub struct BareFunctionDecl { - pub fn_style: ast::FnStyle, - pub generics: Generics, - pub decl: FnDecl, - pub abi: String, -} - -impl Clean for ast::BareFnTy { - fn clean(&self) -> BareFunctionDecl { - BareFunctionDecl { - fn_style: self.fn_style, - generics: Generics { - lifetimes: self.lifetimes.clean().move_iter().collect(), - type_params: Vec::new(), - }, - decl: self.decl.clean(), - abi: self.abi.to_str().to_strbuf(), - } - } -} - -#[deriving(Clone, Encodable, Decodable)] -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) -> Item { - debug!("claning static {}: {:?}", self.name.clean(), self); - Item { - name: Some(self.name.clean()), - attrs: self.attrs.clean(), - source: self.where.clean(), - def_id: ast_util::local_def(self.id), - visibility: self.vis.clean(), - inner: StaticItem(Static { - type_: self.type_.clean(), - mutability: self.mutability.clean(), - expr: self.expr.span.to_src(), - }), - } - } -} - -#[deriving(Show, Clone, Encodable, Decodable, Eq)] -pub enum Mutability { - Mutable, - Immutable, -} - -impl Clean for ast::Mutability { - fn clean(&self) -> Mutability { - match self { - &ast::MutMutable => Mutable, - &ast::MutImmutable => Immutable, - } - } -} - -#[deriving(Clone, Encodable, Decodable)] -pub struct Impl { - pub generics: Generics, - pub trait_: Option, - pub for_: Type, - pub methods: Vec, - pub derived: bool, -} - -fn detect_derived(attrs: &[M]) -> bool { - attrs.iter().any(|attr| { - attr.name().get() == "automatically_derived" - }) -} - -impl Clean for doctree::Impl { - fn clean(&self) -> Item { - Item { - name: None, - attrs: self.attrs.clean(), - source: self.where.clean(), - def_id: ast_util::local_def(self.id), - visibility: self.vis.clean(), - inner: ImplItem(Impl { - generics: self.generics.clean(), - trait_: self.trait_.clean(), - for_: self.for_.clean(), - methods: self.methods.clean(), - derived: detect_derived(self.attrs.as_slice()), - }), - } - } -} - -#[deriving(Clone, Encodable, Decodable)] -pub struct ViewItem { - pub inner: ViewItemInner, -} - -impl Clean> for ast::ViewItem { - fn clean(&self) -> Vec { - 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, "noinline"), - None => false, - } - }); - let convert = |node: &ast::ViewItem_| { - Item { - name: None, - attrs: self.attrs.clean().move_iter().collect(), - source: self.span.clean(), - def_id: ast_util::local_def(0), - visibility: self.vis.clean(), - inner: ViewItemItem(ViewItem { inner: node.clean() }), - } - }; - 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) => { - let remaining = list.iter().filter(|path| { - match try_inline(path.node.id) { - Some(items) => { - ret.extend(items.move_iter()); false - } - None => true, - } - }).map(|a| a.clone()).collect::>(); - 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(@path))); - } - } - ast::ViewPathSimple(_, _, id) => { - match try_inline(id) { - Some(items) => ret.extend(items.move_iter()), - None => ret.push(convert(&self.node)), - } - } - } - } - ref n => ret.push(convert(n)), - } - return ret; - } -} - -fn try_inline(id: ast::NodeId) -> Option> { - let cx = super::ctxtkey.get().unwrap(); - let tcx = match cx.maybe_typed { - core::Typed(ref tycx) => tycx, - core::NotTyped(_) => return None, - }; - let def = match tcx.def_map.borrow().find(&id) { - Some(def) => *def, - None => return None, - }; - let did = ast_util::def_id_of_def(def); - if ast_util::is_local(did) { return None } - try_inline_def(&**cx, tcx, def) -} - -fn try_inline_def(cx: &core::DocContext, - tcx: &ty::ctxt, - def: ast::Def) -> Option> { - let mut ret = Vec::new(); - let did = ast_util::def_id_of_def(def); - let inner = match def { - ast::DefTrait(did) => { - record_extern_fqn(cx, did, TypeTrait); - TraitItem(build_external_trait(tcx, did)) - } - ast::DefFn(did, style) => { - record_extern_fqn(cx, did, TypeFunction); - FunctionItem(build_external_function(tcx, did, style)) - } - ast::DefStruct(did) => { - record_extern_fqn(cx, did, TypeStruct); - ret.extend(build_impls(tcx, did).move_iter()); - StructItem(build_struct(tcx, did)) - } - ast::DefTy(did) => { - record_extern_fqn(cx, did, TypeEnum); - ret.extend(build_impls(tcx, did).move_iter()); - build_type(tcx, did) - } - // Assume that the enum type is reexported next to the variant, and - // variants don't show up in documentation specially. - ast::DefVariant(..) => return Some(Vec::new()), - ast::DefMod(did) => { - record_extern_fqn(cx, did, TypeModule); - ModuleItem(build_module(cx, tcx, did)) - } - _ => return None, - }; - let fqn = csearch::get_item_path(tcx, did); - ret.push(Item { - source: Span::empty(), - name: Some(fqn.last().unwrap().to_str().to_strbuf()), - attrs: load_attrs(tcx, did), - inner: inner, - visibility: Some(ast::Public), - def_id: did, - }); - Some(ret) -} - -fn load_attrs(tcx: &ty::ctxt, did: ast::DefId) -> Vec { - let mut attrs = Vec::new(); - csearch::get_item_attrs(&tcx.sess.cstore, did, |v| { - attrs.extend(v.move_iter().map(|item| { - let mut a = attr::mk_attr_outer(item); - // FIXME this isn't quite always true, it's just true about 99% of - // the time when dealing with documentation - if a.name().get() == "doc" && a.value_str().is_some() { - a.node.is_sugared_doc = true; - } - a.clean() - })); - }); - attrs -} - -#[deriving(Clone, Encodable, Decodable)] -pub enum ViewItemInner { - ExternCrate(String, Option, ast::NodeId), - Import(ViewPath) -} - -impl Clean for ast::ViewItem_ { - fn clean(&self) -> ViewItemInner { - match self { - &ast::ViewItemExternCrate(ref i, ref p, ref id) => { - let string = match *p { - None => None, - Some((ref x, _)) => Some(x.get().to_strbuf()), - }; - ExternCrate(i.clean(), string, *id) - } - &ast::ViewItemUse(ref vp) => { - Import(vp.clean()) - } - } - } -} - -#[deriving(Clone, Encodable, Decodable)] -pub enum ViewPath { - // use str = source; - SimpleImport(String, ImportSource), - // use source::*; - GlobImport(ImportSource), - // use source::{a, b, c}; - ImportList(ImportSource, Vec), -} - -#[deriving(Clone, Encodable, Decodable)] -pub struct ImportSource { - pub path: Path, - pub did: Option, -} - -impl Clean for ast::ViewPath { - fn clean(&self) -> ViewPath { - match self.node { - ast::ViewPathSimple(ref i, ref p, id) => - SimpleImport(i.clean(), resolve_use_source(p.clean(), id)), - ast::ViewPathGlob(ref p, id) => - GlobImport(resolve_use_source(p.clean(), id)), - ast::ViewPathList(ref p, ref pl, id) => { - ImportList(resolve_use_source(p.clean(), id), - pl.clean().move_iter().collect()) - } - } - } -} - -#[deriving(Clone, Encodable, Decodable)] -pub struct ViewListIdent { - pub name: String, - pub source: Option, -} - -impl Clean for ast::PathListIdent { - fn clean(&self) -> ViewListIdent { - ViewListIdent { - name: self.node.name.clean(), - source: resolve_def(self.node.id), - } - } -} - -impl Clean> for ast::ForeignMod { - fn clean(&self) -> Vec { - self.items.clean() - } -} - -impl Clean for ast::ForeignItem { - fn clean(&self) -> Item { - let inner = match self.node { - ast::ForeignItemFn(ref decl, ref generics) => { - ForeignFunctionItem(Function { - decl: decl.clean(), - generics: generics.clean(), - fn_style: ast::UnsafeFn, - }) - } - ast::ForeignItemStatic(ref ty, mutbl) => { - ForeignStaticItem(Static { - type_: ty.clean(), - mutability: if mutbl {Mutable} else {Immutable}, - expr: "".to_strbuf(), - }) - } - }; - Item { - name: Some(self.ident.clean()), - attrs: self.attrs.clean().move_iter().collect(), - source: self.span.clean(), - def_id: ast_util::local_def(self.id), - visibility: self.vis.clean(), - inner: inner, - } - } -} - -// Utilities - -trait ToSource { - fn to_src(&self) -> String; -} - -impl ToSource for syntax::codemap::Span { - fn to_src(&self) -> String { - debug!("converting span {:?} to snippet", self.clean()); - let ctxt = super::ctxtkey.get().unwrap(); - let cm = ctxt.sess().codemap().clone(); - let sn = match cm.span_to_snippet(*self) { - Some(x) => x.to_strbuf(), - None => "".to_strbuf() - }; - debug!("got snippet {}", sn); - sn - } -} - -fn lit_to_str(lit: &ast::Lit) -> String { - match lit.node { - ast::LitStr(ref st, _) => st.get().to_strbuf(), - ast::LitBinary(ref data) => format_strbuf!("{:?}", data.as_slice()), - ast::LitChar(c) => format_strbuf!("'{}'", c), - ast::LitInt(i, _t) => i.to_str().to_strbuf(), - ast::LitUint(u, _t) => u.to_str().to_strbuf(), - ast::LitIntUnsuffixed(i) => i.to_str().to_strbuf(), - ast::LitFloat(ref f, _t) => f.get().to_strbuf(), - ast::LitFloatUnsuffixed(ref f) => f.get().to_strbuf(), - ast::LitBool(b) => b.to_str().to_strbuf(), - ast::LitNil => "".to_strbuf(), - } -} - -fn name_from_pat(p: &ast::Pat) -> String { - use syntax::ast::*; - debug!("Trying to get a name from pattern: {:?}", p); - - match p.node { - PatWild => "_".to_strbuf(), - PatWildMulti => "..".to_strbuf(), - PatIdent(_, ref p, _) => path_to_str(p), - PatEnum(ref p, _) => path_to_str(p), - PatStruct(..) => fail!("tried to get argument name from pat_struct, \ - which is not allowed in function arguments"), - PatTup(..) => "(tuple arg NYI)".to_strbuf(), - PatUniq(p) => name_from_pat(p), - PatRegion(p) => name_from_pat(p), - PatLit(..) => { - warn!("tried to get argument name from PatLit, \ - which is silly in function arguments"); - "()".to_strbuf() - }, - PatRange(..) => fail!("tried to get argument name from PatRange, \ - which is not allowed in function arguments"), - PatVec(..) => fail!("tried to get argument name from pat_vec, \ - which is not allowed in function arguments") - } -} - -/// Given a Type, resolve it using the def_map -fn resolve_type(path: Path, tpbs: Option>, - id: ast::NodeId) -> Type { - let cx = super::ctxtkey.get().unwrap(); - let tycx = match cx.maybe_typed { - core::Typed(ref tycx) => tycx, - // If we're extracting tests, this return value doesn't matter. - core::NotTyped(_) => return Bool - }; - debug!("searching for {:?} in defmap", id); - let def = match tycx.def_map.borrow().find(&id) { - Some(&k) => k, - None => fail!("unresolved id not in defmap") - }; - - match def { - ast::DefSelfTy(i) => return Self(ast_util::local_def(i)), - ast::DefPrimTy(p) => match p { - ast::TyStr => return String, - ast::TyBool => return Bool, - _ => return Primitive(p) - }, - ast::DefTyParam(i, _) => return Generic(i), - ast::DefTyParamBinder(i) => return TyParamBinder(i), - _ => {} - }; - let did = register_def(&**cx, def); - ResolvedPath { path: path, typarams: tpbs, did: did } -} - -fn register_def(cx: &core::DocContext, def: ast::Def) -> ast::DefId { - let (did, kind) = match def { - ast::DefFn(i, _) => (i, TypeFunction), - ast::DefTy(i) => (i, TypeEnum), - ast::DefTrait(i) => (i, TypeTrait), - ast::DefStruct(i) => (i, TypeStruct), - ast::DefMod(i) => (i, TypeModule), - ast::DefStatic(i, _) => (i, TypeStatic), - ast::DefVariant(i, _, _) => (i, TypeEnum), - _ => return ast_util::def_id_of_def(def), - }; - if ast_util::is_local(did) { return did } - let tcx = match cx.maybe_typed { - core::Typed(ref t) => t, - core::NotTyped(_) => return did - }; - record_extern_fqn(cx, did, kind); - match kind { - TypeTrait => { - let t = build_external_trait(tcx, did); - cx.external_traits.borrow_mut().get_mut_ref().insert(did, t); - } - _ => {} - } - return did; -} - -fn record_extern_fqn(cx: &core::DocContext, - did: ast::DefId, - kind: TypeKind) { - match cx.maybe_typed { - core::Typed(ref tcx) => { - let fqn = csearch::get_item_path(tcx, did); - let fqn = fqn.move_iter().map(|i| i.to_str().to_strbuf()).collect(); - cx.external_paths.borrow_mut().get_mut_ref().insert(did, (fqn, kind)); - } - core::NotTyped(..) => {} - } -} - -fn build_external_trait(tcx: &ty::ctxt, did: ast::DefId) -> Trait { - let def = ty::lookup_trait_def(tcx, did); - let methods = ty::trait_methods(tcx, did); - Trait { - generics: def.generics.clean(), - methods: methods.iter().map(|i| i.clean()).collect(), - parents: Vec::new(), // FIXME: this is likely wrong - } -} - -fn build_external_function(tcx: &ty::ctxt, - did: ast::DefId, - style: ast::FnStyle) -> Function { - let t = ty::lookup_item_type(tcx, did); - Function { - decl: match ty::get(t.ty).sty { - ty::ty_bare_fn(ref f) => (did, &f.sig).clean(), - _ => fail!("bad function"), - }, - generics: t.generics.clean(), - fn_style: style, - } -} - -fn build_struct(tcx: &ty::ctxt, did: ast::DefId) -> Struct { - use syntax::parse::token::special_idents::unnamed_field; - - let t = ty::lookup_item_type(tcx, did); - let fields = ty::lookup_struct_fields(tcx, did); - - Struct { - struct_type: match fields.as_slice() { - [] => doctree::Unit, - [ref f] if f.name == unnamed_field.name => doctree::Newtype, - [ref f, ..] if f.name == unnamed_field.name => doctree::Tuple, - _ => doctree::Plain, - }, - generics: t.generics.clean(), - fields: fields.iter().map(|f| f.clean()).collect(), - fields_stripped: false, - } -} - -fn build_type(tcx: &ty::ctxt, did: ast::DefId) -> ItemEnum { - let t = ty::lookup_item_type(tcx, did); - match ty::get(t.ty).sty { - ty::ty_enum(edid, _) => { - return EnumItem(Enum { - generics: t.generics.clean(), - variants_stripped: false, - variants: ty::enum_variants(tcx, edid).clean(), - }) - } - _ => {} - } - - TypedefItem(Typedef { - type_: t.ty.clean(), - generics: t.generics.clean(), - }) -} - -fn build_impls(tcx: &ty::ctxt, - did: ast::DefId) -> Vec { - ty::populate_implementations_for_type_if_necessary(tcx, did); - let mut impls = Vec::new(); - - match tcx.inherent_impls.borrow().find(&did) { - None => {} - Some(i) => { - impls.extend(i.borrow().iter().map(|&did| { build_impl(tcx, did) })); - } - } - - // csearch::each_impl(&tcx.sess.cstore, did.krate, |imp| { - // // if imp.krate - // let t = ty::lookup_item_type(tcx, imp); - // println!("{}", ::rustc::util::ppaux::ty_to_str(tcx, t.ty)); - // match ty::get(t.ty).sty { - // ty::ty_struct(tdid, _) | - // ty::ty_enum(tdid, _) if tdid == did => { - // impls.push(build_impl(tcx, imp)); - // } - // _ => {} - // } - // }); - // for (k, v) in tcx.trait_impls.borrow().iter() { - // if k.krate != did.krate { continue } - // for imp in v.borrow().iter() { - // if imp.krate != did.krate { continue } - // let t = ty::lookup_item_type(tcx, *imp); - // println!("{}", ::rustc::util::ppaux::ty_to_str(tcx, t.ty)); - // match ty::get(t.ty).sty { - // ty::ty_struct(tdid, _) | - // ty::ty_enum(tdid, _) if tdid == did => { - // impls.push(build_impl(tcx, *imp)); - // } - // _ => {} - // } - // } - // } - - impls -} - -fn build_impl(tcx: &ty::ctxt, did: ast::DefId) -> Item { - let associated_trait = csearch::get_impl_trait(tcx, did); - let attrs = load_attrs(tcx, did); - let ty = ty::lookup_item_type(tcx, did); - let methods = csearch::get_impl_methods(&tcx.sess.cstore, did).iter().map(|did| { - let mut item = match ty::method(tcx, *did).clean() { - Provided(item) => item, - Required(item) => item, - }; - item.inner = match item.inner.clone() { - TyMethodItem(TyMethod { fn_style, decl, self_, generics }) => { - MethodItem(Method { - fn_style: fn_style, - decl: decl, - self_: self_, - generics: generics, - }) - } - _ => fail!("not a tymethod"), - }; - item - }).collect(); - Item { - inner: ImplItem(Impl { - derived: detect_derived(attrs.as_slice()), - trait_: associated_trait.clean().map(|bound| { - match bound { - TraitBound(ty) => ty, - RegionBound => fail!(), - } - }), - for_: ty.ty.clean(), - generics: ty.generics.clean(), - methods: methods, - }), - source: Span::empty(), - name: None, - attrs: attrs, - visibility: Some(ast::Inherited), - def_id: did, - } -} - -fn build_module(cx: &core::DocContext, tcx: &ty::ctxt, - did: ast::DefId) -> Module { - let mut items = Vec::new(); - - csearch::each_child_of_item(&tcx.sess.cstore, did, |def, _, _| { - match def { - decoder::DlDef(def) => { - match try_inline_def(cx, tcx, def) { - Some(i) => items.extend(i.move_iter()), - None => {} - } - } - decoder::DlImpl(did) => items.push(build_impl(tcx, did)), - decoder::DlField => fail!("unimplemented field"), - } - }); - - Module { - items: items, - is_crate: false, - } -} - -fn resolve_use_source(path: Path, id: ast::NodeId) -> ImportSource { - ImportSource { - path: path, - did: resolve_def(id), - } -} - -fn resolve_def(id: ast::NodeId) -> Option { - let cx = super::ctxtkey.get().unwrap(); - match cx.maybe_typed { - core::Typed(ref tcx) => { - tcx.def_map.borrow().find(&id).map(|&def| register_def(&**cx, def)) - } - core::NotTyped(_) => None - } -} - -#[deriving(Clone, Encodable, Decodable)] -pub struct Macro { - pub source: String, -} - -impl Clean for doctree::Macro { - fn clean(&self) -> Item { - Item { - name: Some(format_strbuf!("{}!", self.name.clean())), - attrs: self.attrs.clean(), - source: self.where.clean(), - visibility: ast::Public.clean(), - def_id: ast_util::local_def(self.id), - inner: MacroItem(Macro { - source: self.where.to_src(), - }), - } - } -} diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs new file mode 100644 index 00000000000..dd5fddca0db --- /dev/null +++ b/src/librustdoc/clean/inline.rs @@ -0,0 +1,278 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Support for inlining external documentation into the current AST. + +use syntax::ast; +use syntax::ast_util; +use syntax::attr::AttrMetaMethods; + +use rustc::metadata::csearch; +use rustc::metadata::decoder; +use rustc::middle::ty; + +use core; +use doctree; +use clean; + +use super::Clean; + +/// Attempt to inline the definition of a local node id into this AST. +/// +/// This function will fetch the definition of the id specified, and if it is +/// from another crate it will attempt to inline the documentation from the +/// other crate into this crate. +/// +/// This is primarily used for `pub use` statements which are, in general, +/// implementation details. Inlining the documentation should help provide a +/// better experience when reading the documentation in this use case. +/// +/// The returned value is `None` if the `id` could not be inlined, and `Some` +/// of a vector of items if it was successfully expanded. +pub fn try_inline(id: ast::NodeId) -> Option> { + let cx = ::ctxtkey.get().unwrap(); + let tcx = match cx.maybe_typed { + core::Typed(ref tycx) => tycx, + core::NotTyped(_) => return None, + }; + let def = match tcx.def_map.borrow().find(&id) { + Some(def) => *def, + None => return None, + }; + let did = ast_util::def_id_of_def(def); + if ast_util::is_local(did) { return None } + try_inline_def(&**cx, tcx, def) +} + +fn try_inline_def(cx: &core::DocContext, + tcx: &ty::ctxt, + def: ast::Def) -> Option> { + let mut ret = Vec::new(); + let did = ast_util::def_id_of_def(def); + let inner = match def { + ast::DefTrait(did) => { + record_extern_fqn(cx, did, clean::TypeTrait); + clean::TraitItem(build_external_trait(tcx, did)) + } + ast::DefFn(did, style) => { + record_extern_fqn(cx, did, clean::TypeFunction); + clean::FunctionItem(build_external_function(tcx, did, style)) + } + ast::DefStruct(did) => { + record_extern_fqn(cx, did, clean::TypeStruct); + ret.extend(build_impls(tcx, did).move_iter()); + clean::StructItem(build_struct(tcx, did)) + } + ast::DefTy(did) => { + record_extern_fqn(cx, did, clean::TypeEnum); + ret.extend(build_impls(tcx, did).move_iter()); + build_type(tcx, did) + } + // Assume that the enum type is reexported next to the variant, and + // variants don't show up in documentation specially. + ast::DefVariant(..) => return Some(Vec::new()), + ast::DefMod(did) => { + record_extern_fqn(cx, did, clean::TypeModule); + clean::ModuleItem(build_module(cx, tcx, did)) + } + _ => return None, + }; + let fqn = csearch::get_item_path(tcx, did); + ret.push(clean::Item { + source: clean::Span::empty(), + name: Some(fqn.last().unwrap().to_str().to_strbuf()), + attrs: load_attrs(tcx, did), + inner: inner, + visibility: Some(ast::Public), + def_id: did, + }); + Some(ret) +} + +pub fn load_attrs(tcx: &ty::ctxt, did: ast::DefId) -> Vec { + let mut attrs = Vec::new(); + csearch::get_item_attrs(&tcx.sess.cstore, did, |v| { + attrs.extend(v.move_iter().map(|mut a| { + // FIXME this isn't quite always true, it's just true about 99% of + // the time when dealing with documentation. For example, + // this would treat doc comments of the form `#[doc = "foo"]` + // incorrectly. + if a.name().get() == "doc" && a.value_str().is_some() { + a.node.is_sugared_doc = true; + } + a.clean() + })); + }); + attrs +} + +/// Record an external fully qualified name in the external_paths cache. +/// +/// These names are used later on by HTML rendering to generate things like +/// source links back to the original item. +pub fn record_extern_fqn(cx: &core::DocContext, + did: ast::DefId, + kind: clean::TypeKind) { + match cx.maybe_typed { + core::Typed(ref tcx) => { + let fqn = csearch::get_item_path(tcx, did); + let fqn = fqn.move_iter().map(|i| i.to_str().to_strbuf()).collect(); + cx.external_paths.borrow_mut().get_mut_ref().insert(did, (fqn, kind)); + } + core::NotTyped(..) => {} + } +} + +pub fn build_external_trait(tcx: &ty::ctxt, did: ast::DefId) -> clean::Trait { + let def = ty::lookup_trait_def(tcx, did); + let methods = ty::trait_methods(tcx, did); + clean::Trait { + generics: def.generics.clean(), + methods: methods.iter().map(|i| i.clean()).collect(), + parents: Vec::new(), // FIXME: this is likely wrong + } +} + +fn build_external_function(tcx: &ty::ctxt, + did: ast::DefId, + style: ast::FnStyle) -> clean::Function { + let t = ty::lookup_item_type(tcx, did); + clean::Function { + decl: match ty::get(t.ty).sty { + ty::ty_bare_fn(ref f) => (did, &f.sig).clean(), + _ => fail!("bad function"), + }, + generics: t.generics.clean(), + fn_style: style, + } +} + +fn build_struct(tcx: &ty::ctxt, did: ast::DefId) -> clean::Struct { + use syntax::parse::token::special_idents::unnamed_field; + + let t = ty::lookup_item_type(tcx, did); + let fields = ty::lookup_struct_fields(tcx, did); + + clean::Struct { + struct_type: match fields.as_slice() { + [] => doctree::Unit, + [ref f] if f.name == unnamed_field.name => doctree::Newtype, + [ref f, ..] if f.name == unnamed_field.name => doctree::Tuple, + _ => doctree::Plain, + }, + generics: t.generics.clean(), + fields: fields.iter().map(|f| f.clean()).collect(), + fields_stripped: false, + } +} + +fn build_type(tcx: &ty::ctxt, did: ast::DefId) -> clean::ItemEnum { + let t = ty::lookup_item_type(tcx, did); + match ty::get(t.ty).sty { + ty::ty_enum(edid, _) => { + return clean::EnumItem(clean::Enum { + generics: t.generics.clean(), + variants_stripped: false, + variants: ty::enum_variants(tcx, edid).clean(), + }) + } + _ => {} + } + + clean::TypedefItem(clean::Typedef { + type_: t.ty.clean(), + generics: t.generics.clean(), + }) +} + +fn build_impls(tcx: &ty::ctxt, + did: ast::DefId) -> Vec { + ty::populate_implementations_for_type_if_necessary(tcx, did); + let mut impls = Vec::new(); + + match tcx.inherent_impls.borrow().find(&did) { + None => {} + Some(i) => { + impls.extend(i.borrow().iter().map(|&did| { build_impl(tcx, did) })); + } + } + + impls +} + +fn build_impl(tcx: &ty::ctxt, did: ast::DefId) -> clean::Item { + let associated_trait = csearch::get_impl_trait(tcx, did); + let attrs = load_attrs(tcx, did); + let ty = ty::lookup_item_type(tcx, did); + let methods = csearch::get_impl_methods(&tcx.sess.cstore, did).iter().map(|did| { + let mut item = match ty::method(tcx, *did).clean() { + clean::Provided(item) => item, + clean::Required(item) => item, + }; + item.inner = match item.inner.clone() { + clean::TyMethodItem(clean::TyMethod { + fn_style, decl, self_, generics + }) => { + clean::MethodItem(clean::Method { + fn_style: fn_style, + decl: decl, + self_: self_, + generics: generics, + }) + } + _ => fail!("not a tymethod"), + }; + item + }).collect(); + clean::Item { + inner: clean::ImplItem(clean::Impl { + derived: clean::detect_derived(attrs.as_slice()), + trait_: associated_trait.clean().map(|bound| { + match bound { + clean::TraitBound(ty) => ty, + clean::RegionBound => unreachable!(), + } + }), + for_: ty.ty.clean(), + generics: ty.generics.clean(), + methods: methods, + }), + source: clean::Span::empty(), + name: None, + attrs: attrs, + visibility: Some(ast::Inherited), + def_id: did, + } +} + +fn build_module(cx: &core::DocContext, tcx: &ty::ctxt, + did: ast::DefId) -> clean::Module { + let mut items = Vec::new(); + + // FIXME: this doesn't handle reexports inside the module itself. + // Should they be handled? + csearch::each_child_of_item(&tcx.sess.cstore, did, |def, _, _| { + match def { + decoder::DlDef(def) => { + match try_inline_def(cx, tcx, def) { + Some(i) => items.extend(i.move_iter()), + None => {} + } + } + decoder::DlImpl(did) => items.push(build_impl(tcx, did)), + decoder::DlField => fail!("unimplemented field"), + } + }); + + clean::Module { + items: items, + is_crate: false, + } +} diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs new file mode 100644 index 00000000000..f0f68426425 --- /dev/null +++ b/src/librustdoc/clean/mod.rs @@ -0,0 +1,1830 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! This module contains the "cleaned" pieces of the AST, and the functions +//! that clean them. + +use syntax; +use syntax::ast; +use syntax::ast_util; +use syntax::attr; +use syntax::attr::{AttributeMethods, AttrMetaMethods}; +use syntax::codemap::Pos; +use syntax::parse::token::InternedString; +use syntax::parse::token; + +use rustc::back::link; +use rustc::driver::driver; +use rustc::metadata::cstore; +use rustc::metadata::csearch; +use rustc::metadata::decoder; +use rustc::middle::ty; + +use std::rc::Rc; + +use core; +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.2"; + +mod inline; + +pub trait Clean { + fn clean(&self) -> T; +} + +impl, U> Clean> for Vec { + fn clean(&self) -> Vec { + self.iter().map(|x| x.clean()).collect() + } +} + +impl, U> Clean for @T { + fn clean(&self) -> U { + (**self).clean() + } +} + +impl, U> Clean for Rc { + fn clean(&self) -> U { + (**self).clean() + } +} + +impl, U> Clean> for Option { + fn clean(&self) -> Option { + match self { + &None => None, + &Some(ref v) => Some(v.clean()) + } + } +} + +impl, U> Clean> for syntax::owned_slice::OwnedSlice { + fn clean(&self) -> Vec { + self.iter().map(|x| x.clean()).collect() + } +} + +#[deriving(Clone, Encodable, Decodable)] +pub struct Crate { + pub name: String, + pub module: Option, + pub externs: Vec<(ast::CrateNum, ExternalCrate)>, +} + +impl<'a> Clean for visit_ast::RustdocVisitor<'a> { + fn clean(&self) -> Crate { + let cx = super::ctxtkey.get().unwrap(); + + let mut externs = Vec::new(); + cx.sess().cstore.iter_crate_data(|n, meta| { + externs.push((n, meta.clean())); + }); + + let input = driver::FileInput(cx.src.clone()); + let t_outputs = driver::build_output_filenames(&input, + &None, + &None, + self.attrs.as_slice(), + cx.sess()); + let id = link::find_crate_id(self.attrs.as_slice(), + t_outputs.out_filestem.as_slice()); + Crate { + name: id.name.to_strbuf(), + module: Some(self.module.clean()), + externs: externs, + } + } +} + +#[deriving(Clone, Encodable, Decodable)] +pub struct ExternalCrate { + pub name: String, + pub attrs: Vec, +} + +impl Clean for cstore::crate_metadata { + fn clean(&self) -> ExternalCrate { + ExternalCrate { + name: self.name.to_strbuf(), + attrs: decoder::get_crate_attributes(self.data()).clean() + .move_iter() + .collect(), + } + } +} + +/// 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. +#[deriving(Clone, Encodable, Decodable)] +pub struct Item { + /// Stringified span + pub source: Span, + /// Not everything has a name. E.g., impls + pub name: Option, + pub attrs: Vec , + pub inner: ItemEnum, + pub visibility: Option, + pub def_id: ast::DefId, +} + +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.as_slice() => { + 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.as_slice() => { + 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.as_slice() => { + return true + } + _ => (), + } + } + }, + None => () + } + return false; + } + + pub fn is_mod(&self) -> bool { + match self.inner { ModuleItem(..) => true, _ => false } + } + pub fn is_trait(&self) -> bool { + match self.inner { TraitItem(..) => true, _ => false } + } + pub fn is_struct(&self) -> bool { + match self.inner { StructItem(..) => true, _ => false } + } + pub fn is_enum(&self) -> bool { + match self.inner { EnumItem(..) => true, _ => false } + } + pub fn is_fn(&self) -> bool { + match self.inner { FunctionItem(..) => true, _ => false } + } +} + +#[deriving(Clone, Encodable, Decodable)] +pub enum ItemEnum { + StructItem(Struct), + EnumItem(Enum), + FunctionItem(Function), + ModuleItem(Module), + TypedefItem(Typedef), + StaticItem(Static), + TraitItem(Trait), + ImplItem(Impl), + /// `use` and `extern crate` + ViewItemItem(ViewItem), + /// A method signature only. Used for required methods in traits (ie, + /// non-default-methods). + TyMethodItem(TyMethod), + /// A method with a body. + MethodItem(Method), + StructFieldItem(StructField), + VariantItem(Variant), + /// `fn`s from an extern block + ForeignFunctionItem(Function), + /// `static`s from an extern block + ForeignStaticItem(Static), + MacroItem(Macro), +} + +#[deriving(Clone, Encodable, Decodable)] +pub struct Module { + pub items: Vec, + pub is_crate: bool, +} + +impl Clean for doctree::Module { + fn clean(&self) -> Item { + let name = if self.name.is_some() { + self.name.unwrap().clean() + } else { + "".to_strbuf() + }; + let mut foreigns = Vec::new(); + for subforeigns in self.foreigns.clean().move_iter() { + for foreign in subforeigns.move_iter() { + foreigns.push(foreign) + } + } + let items: Vec > = vec!( + self.structs.clean().move_iter().collect(), + self.enums.clean().move_iter().collect(), + self.fns.clean().move_iter().collect(), + foreigns, + self.mods.clean().move_iter().collect(), + self.typedefs.clean().move_iter().collect(), + self.statics.clean().move_iter().collect(), + self.traits.clean().move_iter().collect(), + self.impls.clean().move_iter().collect(), + self.view_items.clean().move_iter() + .flat_map(|s| s.move_iter()).collect(), + self.macros.clean().move_iter().collect() + ); + + // determine if we should display the inner contents or + // the outer `mod` item for the source code. + let where = { + let ctxt = super::ctxtkey.get().unwrap(); + let cm = ctxt.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 + } + }; + + Item { + name: Some(name), + attrs: self.attrs.clean(), + source: where.clean(), + visibility: self.vis.clean(), + def_id: ast_util::local_def(self.id), + inner: ModuleItem(Module { + is_crate: self.is_crate, + items: items.iter() + .flat_map(|x| x.iter().map(|x| (*x).clone())) + .collect(), + }) + } + } +} + +#[deriving(Clone, Encodable, Decodable)] +pub enum Attribute { + Word(String), + List(String, Vec ), + NameValue(String, String) +} + +impl Clean for ast::MetaItem { + fn clean(&self) -> Attribute { + match self.node { + ast::MetaWord(ref s) => Word(s.get().to_strbuf()), + ast::MetaList(ref s, ref l) => { + List(s.get().to_strbuf(), l.clean().move_iter().collect()) + } + ast::MetaNameValue(ref s, ref v) => { + NameValue(s.get().to_strbuf(), lit_to_str(v)) + } + } + } +} + +impl Clean for ast::Attribute { + fn clean(&self) -> Attribute { + self.desugar_doc().node.value.clean() + } +} + +// 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 { + match *self { + NameValue(_, ref v) => { + Some(token::intern_and_get_ident(v.as_slice())) + } + _ => None, + } + } + fn meta_item_list<'a>(&'a self) -> Option<&'a [@ast::MetaItem]> { None } + fn name_str_pair(&self) -> Option<(InternedString, InternedString)> { + None + } +} +impl<'a> attr::AttrMetaMethods for &'a Attribute { + fn name(&self) -> InternedString { (**self).name() } + fn value_str(&self) -> Option { (**self).value_str() } + fn meta_item_list<'a>(&'a self) -> Option<&'a [@ast::MetaItem]> { None } + fn name_str_pair(&self) -> Option<(InternedString, InternedString)> { + None + } +} + +#[deriving(Clone, Encodable, Decodable)] +pub struct TyParam { + pub name: String, + pub did: ast::DefId, + pub bounds: Vec, +} + +impl Clean for ast::TyParam { + fn clean(&self) -> TyParam { + TyParam { + name: self.ident.clean(), + did: ast::DefId { krate: ast::LOCAL_CRATE, node: self.id }, + bounds: self.bounds.clean().move_iter().collect(), + } + } +} + +impl Clean for ty::TypeParameterDef { + fn clean(&self) -> TyParam { + let cx = super::ctxtkey.get().unwrap(); + cx.external_typarams.borrow_mut().get_mut_ref().insert(self.def_id, + self.ident.clean()); + TyParam { + name: self.ident.clean(), + did: self.def_id, + bounds: self.bounds.clean(), + } + } +} + +#[deriving(Clone, Encodable, Decodable)] +pub enum TyParamBound { + RegionBound, + TraitBound(Type) +} + +impl Clean for ast::TyParamBound { + fn clean(&self) -> TyParamBound { + match *self { + ast::StaticRegionTyParamBound => RegionBound, + ast::OtherRegionTyParamBound(_) => RegionBound, + ast::TraitTyParamBound(ref t) => TraitBound(t.clean()), + } + } +} + +fn external_path(name: &str) -> Path { + Path { + global: false, + segments: vec![PathSegment { + name: name.to_strbuf(), + lifetimes: Vec::new(), + types: Vec::new(), + }] + } +} + +impl Clean for ty::BuiltinBound { + fn clean(&self) -> TyParamBound { + let cx = super::ctxtkey.get().unwrap(); + let tcx = match cx.maybe_typed { + core::Typed(ref tcx) => tcx, + core::NotTyped(_) => return RegionBound, + }; + let (did, path) = match *self { + ty::BoundStatic => return RegionBound, + ty::BoundSend => + (tcx.lang_items.send_trait().unwrap(), external_path("Send")), + ty::BoundSized => + (tcx.lang_items.sized_trait().unwrap(), external_path("Sized")), + ty::BoundCopy => + (tcx.lang_items.copy_trait().unwrap(), external_path("Copy")), + ty::BoundShare => + (tcx.lang_items.share_trait().unwrap(), external_path("Share")), + }; + let fqn = csearch::get_item_path(tcx, did); + let fqn = fqn.move_iter().map(|i| i.to_str().to_strbuf()).collect(); + cx.external_paths.borrow_mut().get_mut_ref().insert(did, + (fqn, TypeTrait)); + TraitBound(ResolvedPath { + path: path, + typarams: None, + did: did, + }) + } +} + +impl Clean for ty::TraitRef { + fn clean(&self) -> TyParamBound { + let cx = super::ctxtkey.get().unwrap(); + let tcx = match cx.maybe_typed { + core::Typed(ref tcx) => tcx, + core::NotTyped(_) => return RegionBound, + }; + let fqn = csearch::get_item_path(tcx, self.def_id); + let fqn = fqn.move_iter().map(|i| i.to_str().to_strbuf()) + .collect::>(); + let path = external_path(fqn.last().unwrap().as_slice()); + cx.external_paths.borrow_mut().get_mut_ref().insert(self.def_id, + (fqn, TypeTrait)); + TraitBound(ResolvedPath { + path: path, + typarams: None, + did: self.def_id, + }) + } +} + +impl Clean> for ty::ParamBounds { + fn clean(&self) -> Vec { + let mut v = Vec::new(); + for b in self.builtin_bounds.iter() { + if b != ty::BoundSized { + v.push(b.clean()); + } + } + for t in self.trait_bounds.iter() { + v.push(t.clean()); + } + return v; + } +} + +impl Clean>> for ty::substs { + fn clean(&self) -> Option> { + let mut v = Vec::new(); + match self.regions { + ty::NonerasedRegions(..) => v.push(RegionBound), + ty::ErasedRegions => {} + } + v.extend(self.tps.iter().map(|t| TraitBound(t.clean()))); + + if v.len() > 0 {Some(v)} else {None} + } +} + +#[deriving(Clone, Encodable, Decodable, Eq)] +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.as_slice(); + return s; + } +} + +impl Clean for ast::Lifetime { + fn clean(&self) -> Lifetime { + Lifetime(token::get_name(self.name).get().to_strbuf()) + } +} + +impl Clean for ty::RegionParameterDef { + fn clean(&self) -> Lifetime { + Lifetime(token::get_name(self.name).get().to_strbuf()) + } +} + +impl Clean> for ty::Region { + fn clean(&self) -> Option { + match *self { + ty::ReStatic => Some(Lifetime("static".to_strbuf())), + ty::ReLateBound(_, ty::BrNamed(_, name)) => + Some(Lifetime(token::get_name(name).get().to_strbuf())), + + ty::ReLateBound(..) | + ty::ReEarlyBound(..) | + ty::ReFree(..) | + ty::ReScope(..) | + ty::ReInfer(..) | + ty::ReEmpty(..) => None + } + } +} + +// maybe use a Generic enum and use ~[Generic]? +#[deriving(Clone, Encodable, Decodable)] +pub struct Generics { + pub lifetimes: Vec, + pub type_params: Vec, +} + +impl Clean for ast::Generics { + fn clean(&self) -> Generics { + Generics { + lifetimes: self.lifetimes.clean().move_iter().collect(), + type_params: self.ty_params.clean().move_iter().collect(), + } + } +} + +impl Clean for ty::Generics { + fn clean(&self) -> Generics { + Generics { + lifetimes: self.region_param_defs.clean(), + type_params: self.type_param_defs.clean(), + } + } +} + +#[deriving(Clone, Encodable, Decodable)] +pub struct Method { + pub generics: Generics, + pub self_: SelfTy, + pub fn_style: ast::FnStyle, + pub decl: FnDecl, +} + +impl Clean for ast::Method { + fn clean(&self) -> Item { + let inputs = match self.explicit_self.node { + ast::SelfStatic => self.decl.inputs.as_slice(), + _ => self.decl.inputs.slice_from(1) + }; + let decl = FnDecl { + inputs: Arguments { + values: inputs.iter().map(|x| x.clean()).collect(), + }, + output: (self.decl.output.clean()), + cf: self.decl.cf.clean(), + attrs: Vec::new() + }; + Item { + name: Some(self.ident.clean()), + attrs: self.attrs.clean().move_iter().collect(), + source: self.span.clean(), + def_id: ast_util::local_def(self.id.clone()), + visibility: self.vis.clean(), + inner: MethodItem(Method { + generics: self.generics.clean(), + self_: self.explicit_self.node.clean(), + fn_style: self.fn_style.clone(), + decl: decl, + }), + } + } +} + +#[deriving(Clone, Encodable, Decodable)] +pub struct TyMethod { + pub fn_style: ast::FnStyle, + pub decl: FnDecl, + pub generics: Generics, + pub self_: SelfTy, +} + +impl Clean for ast::TypeMethod { + fn clean(&self) -> Item { + let inputs = match self.explicit_self.node { + ast::SelfStatic => self.decl.inputs.as_slice(), + _ => self.decl.inputs.slice_from(1) + }; + let decl = FnDecl { + inputs: Arguments { + values: inputs.iter().map(|x| x.clean()).collect(), + }, + output: (self.decl.output.clean()), + cf: self.decl.cf.clean(), + attrs: Vec::new() + }; + Item { + name: Some(self.ident.clean()), + attrs: self.attrs.clean().move_iter().collect(), + source: self.span.clean(), + def_id: ast_util::local_def(self.id), + visibility: None, + inner: TyMethodItem(TyMethod { + fn_style: self.fn_style.clone(), + decl: decl, + self_: self.explicit_self.node.clean(), + generics: self.generics.clean(), + }), + } + } +} + +#[deriving(Clone, Encodable, Decodable, Eq)] +pub enum SelfTy { + SelfStatic, + SelfValue, + SelfBorrowed(Option, Mutability), + SelfOwned, +} + +impl Clean for ast::ExplicitSelf_ { + fn clean(&self) -> SelfTy { + match *self { + ast::SelfStatic => SelfStatic, + ast::SelfValue => SelfValue, + ast::SelfUniq => SelfOwned, + ast::SelfRegion(lt, mt) => SelfBorrowed(lt.clean(), mt.clean()), + } + } +} + +#[deriving(Clone, Encodable, Decodable)] +pub struct Function { + pub decl: FnDecl, + pub generics: Generics, + pub fn_style: ast::FnStyle, +} + +impl Clean for doctree::Function { + fn clean(&self) -> Item { + Item { + name: Some(self.name.clean()), + attrs: self.attrs.clean(), + source: self.where.clean(), + visibility: self.vis.clean(), + def_id: ast_util::local_def(self.id), + inner: FunctionItem(Function { + decl: self.decl.clean(), + generics: self.generics.clean(), + fn_style: self.fn_style, + }), + } + } +} + +#[deriving(Clone, Encodable, Decodable)] +pub struct ClosureDecl { + pub lifetimes: Vec, + pub decl: FnDecl, + pub onceness: ast::Onceness, + pub fn_style: ast::FnStyle, + pub bounds: Vec, +} + +impl Clean for ast::ClosureTy { + fn clean(&self) -> ClosureDecl { + ClosureDecl { + lifetimes: self.lifetimes.clean(), + decl: self.decl.clean(), + onceness: self.onceness, + fn_style: self.fn_style, + bounds: match self.bounds { + Some(ref x) => x.clean().move_iter().collect(), + None => Vec::new() + }, + } + } +} + +#[deriving(Clone, Encodable, Decodable)] +pub struct FnDecl { + pub inputs: Arguments, + pub output: Type, + pub cf: RetStyle, + pub attrs: Vec, +} + +#[deriving(Clone, Encodable, Decodable)] +pub struct Arguments { + pub values: Vec, +} + +impl Clean for ast::FnDecl { + fn clean(&self) -> FnDecl { + FnDecl { + inputs: Arguments { + values: self.inputs.iter().map(|x| x.clean()).collect(), + }, + output: (self.output.clean()), + cf: self.cf.clean(), + attrs: Vec::new() + } + } +} + +impl<'a> Clean for (ast::DefId, &'a ty::FnSig) { + fn clean(&self) -> FnDecl { + let cx = super::ctxtkey.get().unwrap(); + let tcx = match cx.maybe_typed { + core::Typed(ref tcx) => tcx, + core::NotTyped(_) => unreachable!(), + }; + let (did, sig) = *self; + let mut names = if did.node != 0 { + csearch::get_method_arg_names(&tcx.sess.cstore, did).move_iter() + } else { + Vec::new().move_iter() + }.peekable(); + if names.peek().map(|s| s.as_slice()) == Some("self") { + let _ = names.next(); + } + FnDecl { + output: sig.output.clean(), + cf: Return, + attrs: Vec::new(), + inputs: Arguments { + values: sig.inputs.iter().map(|t| { + Argument { + type_: t.clean(), + id: 0, + name: names.next().unwrap_or("".to_strbuf()), + } + }).collect(), + }, + } + } +} + +#[deriving(Clone, Encodable, Decodable)] +pub struct Argument { + pub type_: Type, + pub name: String, + pub id: ast::NodeId, +} + +impl Clean for ast::Arg { + fn clean(&self) -> Argument { + Argument { + name: name_from_pat(self.pat), + type_: (self.ty.clean()), + id: self.id + } + } +} + +#[deriving(Clone, Encodable, Decodable)] +pub enum RetStyle { + NoReturn, + Return +} + +impl Clean for ast::RetStyle { + fn clean(&self) -> RetStyle { + match *self { + ast::Return => Return, + ast::NoReturn => NoReturn + } + } +} + +#[deriving(Clone, Encodable, Decodable)] +pub struct Trait { + pub methods: Vec, + pub generics: Generics, + pub parents: Vec, +} + +impl Clean for doctree::Trait { + fn clean(&self) -> Item { + Item { + name: Some(self.name.clean()), + attrs: self.attrs.clean(), + source: self.where.clean(), + def_id: ast_util::local_def(self.id), + visibility: self.vis.clean(), + inner: TraitItem(Trait { + methods: self.methods.clean(), + generics: self.generics.clean(), + parents: self.parents.clean(), + }), + } + } +} + +impl Clean for ast::TraitRef { + fn clean(&self) -> Type { + resolve_type(self.path.clean(), None, self.ref_id) + } +} + +#[deriving(Clone, Encodable, Decodable)] +pub enum TraitMethod { + Required(Item), + Provided(Item), +} + +impl TraitMethod { + pub fn is_req(&self) -> bool { + match self { + &Required(..) => true, + _ => false, + } + } + pub fn is_def(&self) -> bool { + match self { + &Provided(..) => true, + _ => false, + } + } + pub fn item<'a>(&'a self) -> &'a Item { + match *self { + Required(ref item) => item, + Provided(ref item) => item, + } + } +} + +impl Clean for ast::TraitMethod { + fn clean(&self) -> TraitMethod { + match self { + &ast::Required(ref t) => Required(t.clean()), + &ast::Provided(ref t) => Provided(t.clean()), + } + } +} + +impl Clean for ty::Method { + fn clean(&self) -> TraitMethod { + let m = if self.provided_source.is_some() {Provided} else {Required}; + let cx = super::ctxtkey.get().unwrap(); + let tcx = match cx.maybe_typed { + core::Typed(ref tcx) => tcx, + core::NotTyped(_) => unreachable!(), + }; + let (self_, sig) = match self.explicit_self { + ast::SelfStatic => (ast::SelfStatic.clean(), self.fty.sig.clone()), + s => { + let sig = ty::FnSig { + inputs: Vec::from_slice(self.fty.sig.inputs.slice_from(1)), + ..self.fty.sig.clone() + }; + let s = match s { + ast::SelfRegion(..) => { + match ty::get(*self.fty.sig.inputs.get(0)).sty { + ty::ty_rptr(r, mt) => { + SelfBorrowed(r.clean(), mt.mutbl.clean()) + } + _ => s.clean(), + } + } + s => s.clean(), + }; + (s, sig) + } + }; + + m(Item { + name: Some(self.ident.clean()), + visibility: Some(ast::Inherited), + def_id: self.def_id, + attrs: inline::load_attrs(tcx, self.def_id), + source: Span::empty(), + inner: TyMethodItem(TyMethod { + fn_style: self.fty.fn_style, + generics: self.generics.clean(), + self_: self_, + decl: (self.def_id, &sig).clean(), + }) + }) + } +} + +/// 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. +#[deriving(Clone, Encodable, Decodable)] +pub enum Type { + /// structs/enums/traits (anything that'd be an ast::TyPath) + ResolvedPath { + pub path: Path, + pub typarams: Option>, + pub did: ast::DefId, + }, + // 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(ast::DefId), + /// For references to self + Self(ast::DefId), + /// Primitives are just the fixed-size numeric types (plus int/uint/float), and char. + Primitive(ast::PrimTy), + Closure(Box, Option), + Proc(Box), + /// extern "ABI" fn + BareFunction(Box), + Tuple(Vec), + Vector(Box), + FixedVector(Box, String), + String, + Bool, + /// aka TyNil + Unit, + /// aka TyBot + Bottom, + Unique(Box), + Managed(Box), + RawPointer(Mutability, Box), + BorrowedRef { + pub lifetime: Option, + pub mutability: Mutability, + pub type_: Box, + }, + // region, raw, other boxes, mutable +} + +#[deriving(Clone, Encodable, Decodable)] +pub enum TypeKind { + TypeEnum, + TypeFunction, + TypeModule, + TypeStatic, + TypeStruct, + TypeTrait, + TypeVariant, +} + +impl Clean for ast::Ty { + fn clean(&self) -> Type { + use syntax::ast::*; + match self.node { + TyNil => Unit, + TyPtr(ref m) => RawPointer(m.mutbl.clean(), box m.ty.clean()), + TyRptr(ref l, ref m) => + BorrowedRef {lifetime: l.clean(), mutability: m.mutbl.clean(), + type_: box m.ty.clean()}, + TyBox(ty) => Managed(box ty.clean()), + TyUniq(ty) => Unique(box ty.clean()), + TyVec(ty) => Vector(box ty.clean()), + TyFixedLengthVec(ty, ref e) => FixedVector(box ty.clean(), + e.span.to_src()), + TyTup(ref tys) => Tuple(tys.iter().map(|x| x.clean()).collect()), + TyPath(ref p, ref tpbs, id) => { + resolve_type(p.clean(), + tpbs.clean().map(|x| x.move_iter().collect()), + id) + } + TyClosure(ref c, region) => Closure(box c.clean(), region.clean()), + TyProc(ref c) => Proc(box c.clean()), + TyBareFn(ref barefn) => BareFunction(box barefn.clean()), + TyBot => Bottom, + ref x => fail!("Unimplemented type {:?}", x), + } + } +} + +impl Clean for ty::t { + fn clean(&self) -> Type { + match ty::get(*self).sty { + ty::ty_nil => Unit, + ty::ty_bot => Bottom, + ty::ty_bool => Bool, + ty::ty_char => Primitive(ast::TyChar), + ty::ty_int(t) => Primitive(ast::TyInt(t)), + ty::ty_uint(u) => Primitive(ast::TyUint(u)), + ty::ty_float(f) => Primitive(ast::TyFloat(f)), + ty::ty_box(t) => Managed(box t.clean()), + ty::ty_uniq(t) => Unique(box t.clean()), + ty::ty_str => String, + ty::ty_vec(mt, None) => Vector(box mt.ty.clean()), + ty::ty_vec(mt, Some(i)) => FixedVector(box mt.ty.clean(), + format_strbuf!("{}", i)), + ty::ty_ptr(mt) => RawPointer(mt.mutbl.clean(), box mt.ty.clean()), + ty::ty_rptr(r, mt) => BorrowedRef { + lifetime: r.clean(), + mutability: mt.mutbl.clean(), + type_: box mt.ty.clean(), + }, + ty::ty_bare_fn(ref fty) => BareFunction(box BareFunctionDecl { + fn_style: fty.fn_style, + generics: Generics { + lifetimes: Vec::new(), type_params: Vec::new() + }, + decl: (ast_util::local_def(0), &fty.sig).clean(), + abi: fty.abi.to_str().to_strbuf(), + }), + ty::ty_closure(ref fty) => { + let decl = box ClosureDecl { + lifetimes: Vec::new(), // FIXME: this looks wrong... + decl: (ast_util::local_def(0), &fty.sig).clean(), + onceness: fty.onceness, + fn_style: fty.fn_style, + bounds: fty.bounds.iter().map(|i| i.clean()).collect(), + }; + match fty.store { + ty::UniqTraitStore => Proc(decl), + ty::RegionTraitStore(ref r, _) => Closure(decl, r.clean()), + } + } + ty::ty_struct(did, ref substs) | + ty::ty_enum(did, ref substs) | + ty::ty_trait(box ty::TyTrait { def_id: did, ref substs, .. }) => { + let cx = super::ctxtkey.get().unwrap(); + let tcx = match cx.maybe_typed { + core::Typed(ref tycx) => tycx, + core::NotTyped(_) => unreachable!(), + }; + let fqn = csearch::get_item_path(tcx, did); + let fqn: Vec = fqn.move_iter().map(|i| { + i.to_str().to_strbuf() + }).collect(); + let mut path = external_path(fqn.last() + .unwrap() + .to_str() + .as_slice()); + let kind = match ty::get(*self).sty { + ty::ty_struct(..) => TypeStruct, + ty::ty_trait(..) => TypeTrait, + _ => TypeEnum, + }; + path.segments.get_mut(0).lifetimes = match substs.regions { + ty::ErasedRegions => Vec::new(), + ty::NonerasedRegions(ref v) => { + v.iter().filter_map(|v| v.clean()).collect() + } + }; + path.segments.get_mut(0).types = substs.tps.clean(); + cx.external_paths.borrow_mut().get_mut_ref().insert(did, + (fqn, kind)); + ResolvedPath { + path: path, + typarams: None, + did: did, + } + } + ty::ty_tup(ref t) => Tuple(t.iter().map(|t| t.clean()).collect()), + + ty::ty_param(ref p) => Generic(p.def_id), + ty::ty_self(did) => Self(did), + + ty::ty_infer(..) => fail!("ty_infer"), + ty::ty_err => fail!("ty_err"), + } + } +} + +#[deriving(Clone, Encodable, Decodable)] +pub enum StructField { + HiddenStructField, // inserted later by strip passes + TypedStructField(Type), +} + +impl Clean for ast::StructField { + fn clean(&self) -> Item { + let (name, vis) = match self.node.kind { + ast::NamedField(id, vis) => (Some(id), vis), + ast::UnnamedField(vis) => (None, vis) + }; + Item { + name: name.clean(), + attrs: self.node.attrs.clean().move_iter().collect(), + source: self.span.clean(), + visibility: Some(vis), + def_id: ast_util::local_def(self.node.id), + inner: StructFieldItem(TypedStructField(self.node.ty.clean())), + } + } +} + +impl Clean for ty::field_ty { + fn clean(&self) -> Item { + use syntax::parse::token::special_idents::unnamed_field; + let name = if self.name == unnamed_field.name { + None + } else { + Some(self.name) + }; + let cx = super::ctxtkey.get().unwrap(); + let tcx = match cx.maybe_typed { + core::Typed(ref tycx) => tycx, + core::NotTyped(_) => unreachable!(), + }; + let ty = ty::lookup_item_type(tcx, self.id); + Item { + name: name.clean(), + attrs: inline::load_attrs(tcx, self.id), + source: Span::empty(), + visibility: Some(self.vis), + def_id: self.id, + inner: StructFieldItem(TypedStructField(ty.ty.clean())), + } + } +} + +pub type Visibility = ast::Visibility; + +impl Clean> for ast::Visibility { + fn clean(&self) -> Option { + Some(*self) + } +} + +#[deriving(Clone, Encodable, Decodable)] +pub struct Struct { + pub struct_type: doctree::StructType, + pub generics: Generics, + pub fields: Vec, + pub fields_stripped: bool, +} + +impl Clean for doctree::Struct { + fn clean(&self) -> Item { + Item { + name: Some(self.name.clean()), + attrs: self.attrs.clean(), + source: self.where.clean(), + def_id: ast_util::local_def(self.id), + visibility: self.vis.clean(), + inner: StructItem(Struct { + struct_type: self.struct_type, + generics: self.generics.clean(), + fields: self.fields.clean(), + fields_stripped: false, + }), + } + } +} + +/// 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. +#[deriving(Clone, Encodable, Decodable)] +pub struct VariantStruct { + pub struct_type: doctree::StructType, + pub fields: Vec, + pub fields_stripped: bool, +} + +impl Clean for syntax::ast::StructDef { + fn clean(&self) -> VariantStruct { + VariantStruct { + struct_type: doctree::struct_type_from_def(self), + fields: self.fields.clean().move_iter().collect(), + fields_stripped: false, + } + } +} + +#[deriving(Clone, Encodable, Decodable)] +pub struct Enum { + pub variants: Vec, + pub generics: Generics, + pub variants_stripped: bool, +} + +impl Clean for doctree::Enum { + fn clean(&self) -> Item { + Item { + name: Some(self.name.clean()), + attrs: self.attrs.clean(), + source: self.where.clean(), + def_id: ast_util::local_def(self.id), + visibility: self.vis.clean(), + inner: EnumItem(Enum { + variants: self.variants.clean(), + generics: self.generics.clean(), + variants_stripped: false, + }), + } + } +} + +#[deriving(Clone, Encodable, Decodable)] +pub struct Variant { + pub kind: VariantKind, +} + +impl Clean for doctree::Variant { + fn clean(&self) -> Item { + Item { + name: Some(self.name.clean()), + attrs: self.attrs.clean(), + source: self.where.clean(), + visibility: self.vis.clean(), + def_id: ast_util::local_def(self.id), + inner: VariantItem(Variant { + kind: self.kind.clean(), + }), + } + } +} + +impl Clean for ty::VariantInfo { + fn clean(&self) -> Item { + // use syntax::parse::token::special_idents::unnamed_field; + let cx = super::ctxtkey.get().unwrap(); + let tcx = match cx.maybe_typed { + core::Typed(ref tycx) => tycx, + core::NotTyped(_) => fail!("tcx not present"), + }; + 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.iter().map(|t| t.clean()).collect()) + } + 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()), + 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. Nothing currently + // uses this so we should be good for now. + def_id: self.id, + inner: StructFieldItem( + TypedStructField(ty.clean()) + ) + } + }).collect() + }) + } + }; + Item { + name: Some(self.name.clean()), + attrs: inline::load_attrs(tcx, self.id), + source: Span::empty(), + visibility: Some(ast::Public), + def_id: self.id, + inner: VariantItem(Variant { kind: kind }), + } + } +} + +#[deriving(Clone, Encodable, Decodable)] +pub enum VariantKind { + CLikeVariant, + TupleVariant(Vec), + StructVariant(VariantStruct), +} + +impl Clean for ast::VariantKind { + fn clean(&self) -> VariantKind { + match self { + &ast::TupleVariantKind(ref args) => { + if args.len() == 0 { + CLikeVariant + } else { + TupleVariant(args.iter().map(|x| x.ty.clean()).collect()) + } + }, + &ast::StructVariantKind(ref sd) => StructVariant(sd.clean()), + } + } +} + +#[deriving(Clone, Encodable, Decodable)] +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_strbuf(), + loline: 0, locol: 0, + hiline: 0, hicol: 0, + } + } +} + +impl Clean for syntax::codemap::Span { + fn clean(&self) -> Span { + let ctxt = super::ctxtkey.get().unwrap(); + let cm = ctxt.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_strbuf(), + loline: lo.line, + locol: lo.col.to_uint(), + hiline: hi.line, + hicol: hi.col.to_uint(), + } + } +} + +#[deriving(Clone, Encodable, Decodable)] +pub struct Path { + pub global: bool, + pub segments: Vec, +} + +impl Clean for ast::Path { + fn clean(&self) -> Path { + Path { + global: self.global, + segments: self.segments.clean().move_iter().collect(), + } + } +} + +#[deriving(Clone, Encodable, Decodable)] +pub struct PathSegment { + pub name: String, + pub lifetimes: Vec, + pub types: Vec, +} + +impl Clean for ast::PathSegment { + fn clean(&self) -> PathSegment { + PathSegment { + name: self.identifier.clean(), + lifetimes: self.lifetimes.clean().move_iter().collect(), + types: self.types.clean().move_iter().collect() + } + } +} + +fn path_to_str(p: &ast::Path) -> String { + use syntax::parse::token; + + let mut s = String::new(); + let mut first = true; + for i in p.segments.iter().map(|x| token::get_ident(x.identifier)) { + if !first || p.global { + s.push_str("::"); + } else { + first = false; + } + s.push_str(i.get()); + } + s +} + +impl Clean for ast::Ident { + fn clean(&self) -> String { + token::get_ident(*self).get().to_strbuf() + } +} + +impl Clean for ast::Name { + fn clean(&self) -> String { + token::get_name(*self).get().to_strbuf() + } +} + +#[deriving(Clone, Encodable, Decodable)] +pub struct Typedef { + pub type_: Type, + pub generics: Generics, +} + +impl Clean for doctree::Typedef { + fn clean(&self) -> Item { + Item { + name: Some(self.name.clean()), + attrs: self.attrs.clean(), + source: self.where.clean(), + def_id: ast_util::local_def(self.id.clone()), + visibility: self.vis.clean(), + inner: TypedefItem(Typedef { + type_: self.ty.clean(), + generics: self.gen.clean(), + }), + } + } +} + +#[deriving(Clone, Encodable, Decodable)] +pub struct BareFunctionDecl { + pub fn_style: ast::FnStyle, + pub generics: Generics, + pub decl: FnDecl, + pub abi: String, +} + +impl Clean for ast::BareFnTy { + fn clean(&self) -> BareFunctionDecl { + BareFunctionDecl { + fn_style: self.fn_style, + generics: Generics { + lifetimes: self.lifetimes.clean().move_iter().collect(), + type_params: Vec::new(), + }, + decl: self.decl.clean(), + abi: self.abi.to_str().to_strbuf(), + } + } +} + +#[deriving(Clone, Encodable, Decodable)] +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) -> Item { + debug!("claning static {}: {:?}", self.name.clean(), self); + Item { + name: Some(self.name.clean()), + attrs: self.attrs.clean(), + source: self.where.clean(), + def_id: ast_util::local_def(self.id), + visibility: self.vis.clean(), + inner: StaticItem(Static { + type_: self.type_.clean(), + mutability: self.mutability.clean(), + expr: self.expr.span.to_src(), + }), + } + } +} + +#[deriving(Show, Clone, Encodable, Decodable, Eq)] +pub enum Mutability { + Mutable, + Immutable, +} + +impl Clean for ast::Mutability { + fn clean(&self) -> Mutability { + match self { + &ast::MutMutable => Mutable, + &ast::MutImmutable => Immutable, + } + } +} + +#[deriving(Clone, Encodable, Decodable)] +pub struct Impl { + pub generics: Generics, + pub trait_: Option, + pub for_: Type, + pub methods: Vec, + pub derived: bool, +} + +fn detect_derived(attrs: &[M]) -> bool { + attr::contains_name(attrs, "automatically_derived") +} + +impl Clean for doctree::Impl { + fn clean(&self) -> Item { + Item { + name: None, + attrs: self.attrs.clean(), + source: self.where.clean(), + def_id: ast_util::local_def(self.id), + visibility: self.vis.clean(), + inner: ImplItem(Impl { + generics: self.generics.clean(), + trait_: self.trait_.clean(), + for_: self.for_.clean(), + methods: self.methods.clean(), + derived: detect_derived(self.attrs.as_slice()), + }), + } + } +} + +#[deriving(Clone, Encodable, Decodable)] +pub struct ViewItem { + pub inner: ViewItemInner, +} + +impl Clean> for ast::ViewItem { + fn clean(&self) -> Vec { + // We consider inlining the documentation of `pub use` statments, 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().move_iter().collect(), + source: self.span.clean(), + def_id: ast_util::local_def(0), + visibility: self.vis.clean(), + inner: ViewItemItem(ViewItem { inner: node.clean() }), + } + }; + 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(path.node.id) { + Some(items) => { + ret.extend(items.move_iter()); false + } + None => true, + } + }).map(|a| a.clone()).collect::>(); + 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(@path))); + } + } + ast::ViewPathSimple(_, _, id) => { + match inline::try_inline(id) { + Some(items) => ret.extend(items.move_iter()), + None => ret.push(convert(&self.node)), + } + } + } + } + ref n => ret.push(convert(n)), + } + return ret; + } +} + +#[deriving(Clone, Encodable, Decodable)] +pub enum ViewItemInner { + ExternCrate(String, Option, ast::NodeId), + Import(ViewPath) +} + +impl Clean for ast::ViewItem_ { + fn clean(&self) -> ViewItemInner { + match self { + &ast::ViewItemExternCrate(ref i, ref p, ref id) => { + let string = match *p { + None => None, + Some((ref x, _)) => Some(x.get().to_strbuf()), + }; + ExternCrate(i.clean(), string, *id) + } + &ast::ViewItemUse(ref vp) => { + Import(vp.clean()) + } + } + } +} + +#[deriving(Clone, Encodable, Decodable)] +pub enum ViewPath { + // use str = source; + SimpleImport(String, ImportSource), + // use source::*; + GlobImport(ImportSource), + // use source::{a, b, c}; + ImportList(ImportSource, Vec), +} + +#[deriving(Clone, Encodable, Decodable)] +pub struct ImportSource { + pub path: Path, + pub did: Option, +} + +impl Clean for ast::ViewPath { + fn clean(&self) -> ViewPath { + match self.node { + ast::ViewPathSimple(ref i, ref p, id) => + SimpleImport(i.clean(), resolve_use_source(p.clean(), id)), + ast::ViewPathGlob(ref p, id) => + GlobImport(resolve_use_source(p.clean(), id)), + ast::ViewPathList(ref p, ref pl, id) => { + ImportList(resolve_use_source(p.clean(), id), + pl.clean().move_iter().collect()) + } + } + } +} + +#[deriving(Clone, Encodable, Decodable)] +pub struct ViewListIdent { + pub name: String, + pub source: Option, +} + +impl Clean for ast::PathListIdent { + fn clean(&self) -> ViewListIdent { + ViewListIdent { + name: self.node.name.clean(), + source: resolve_def(self.node.id), + } + } +} + +impl Clean> for ast::ForeignMod { + fn clean(&self) -> Vec { + self.items.clean() + } +} + +impl Clean for ast::ForeignItem { + fn clean(&self) -> Item { + let inner = match self.node { + ast::ForeignItemFn(ref decl, ref generics) => { + ForeignFunctionItem(Function { + decl: decl.clean(), + generics: generics.clean(), + fn_style: ast::UnsafeFn, + }) + } + ast::ForeignItemStatic(ref ty, mutbl) => { + ForeignStaticItem(Static { + type_: ty.clean(), + mutability: if mutbl {Mutable} else {Immutable}, + expr: "".to_strbuf(), + }) + } + }; + Item { + name: Some(self.ident.clean()), + attrs: self.attrs.clean().move_iter().collect(), + source: self.span.clean(), + def_id: ast_util::local_def(self.id), + visibility: self.vis.clean(), + inner: inner, + } + } +} + +// Utilities + +trait ToSource { + fn to_src(&self) -> String; +} + +impl ToSource for syntax::codemap::Span { + fn to_src(&self) -> String { + debug!("converting span {:?} to snippet", self.clean()); + let ctxt = super::ctxtkey.get().unwrap(); + let cm = ctxt.sess().codemap().clone(); + let sn = match cm.span_to_snippet(*self) { + Some(x) => x.to_strbuf(), + None => "".to_strbuf() + }; + debug!("got snippet {}", sn); + sn + } +} + +fn lit_to_str(lit: &ast::Lit) -> String { + match lit.node { + ast::LitStr(ref st, _) => st.get().to_strbuf(), + ast::LitBinary(ref data) => format_strbuf!("{:?}", data.as_slice()), + ast::LitChar(c) => format_strbuf!("'{}'", c), + ast::LitInt(i, _t) => i.to_str().to_strbuf(), + ast::LitUint(u, _t) => u.to_str().to_strbuf(), + ast::LitIntUnsuffixed(i) => i.to_str().to_strbuf(), + ast::LitFloat(ref f, _t) => f.get().to_strbuf(), + ast::LitFloatUnsuffixed(ref f) => f.get().to_strbuf(), + ast::LitBool(b) => b.to_str().to_strbuf(), + ast::LitNil => "".to_strbuf(), + } +} + +fn name_from_pat(p: &ast::Pat) -> String { + use syntax::ast::*; + debug!("Trying to get a name from pattern: {:?}", p); + + match p.node { + PatWild => "_".to_strbuf(), + PatWildMulti => "..".to_strbuf(), + PatIdent(_, ref p, _) => path_to_str(p), + PatEnum(ref p, _) => path_to_str(p), + PatStruct(..) => fail!("tried to get argument name from pat_struct, \ + which is not allowed in function arguments"), + PatTup(..) => "(tuple arg NYI)".to_strbuf(), + PatUniq(p) => name_from_pat(p), + PatRegion(p) => name_from_pat(p), + PatLit(..) => { + warn!("tried to get argument name from PatLit, \ + which is silly in function arguments"); + "()".to_strbuf() + }, + PatRange(..) => fail!("tried to get argument name from PatRange, \ + which is not allowed in function arguments"), + PatVec(..) => fail!("tried to get argument name from pat_vec, \ + which is not allowed in function arguments") + } +} + +/// Given a Type, resolve it using the def_map +fn resolve_type(path: Path, tpbs: Option>, + id: ast::NodeId) -> Type { + let cx = super::ctxtkey.get().unwrap(); + let tycx = match cx.maybe_typed { + core::Typed(ref tycx) => tycx, + // If we're extracting tests, this return value doesn't matter. + core::NotTyped(_) => return Bool + }; + debug!("searching for {:?} in defmap", id); + let def = match tycx.def_map.borrow().find(&id) { + Some(&k) => k, + None => fail!("unresolved id not in defmap") + }; + + match def { + ast::DefSelfTy(i) => return Self(ast_util::local_def(i)), + ast::DefPrimTy(p) => match p { + ast::TyStr => return String, + ast::TyBool => return Bool, + _ => return Primitive(p) + }, + ast::DefTyParam(i, _) => return Generic(i), + ast::DefTyParamBinder(i) => return TyParamBinder(i), + _ => {} + }; + let did = register_def(&**cx, def); + ResolvedPath { path: path, typarams: tpbs, did: did } +} + +fn register_def(cx: &core::DocContext, def: ast::Def) -> ast::DefId { + let (did, kind) = match def { + ast::DefFn(i, _) => (i, TypeFunction), + ast::DefTy(i) => (i, TypeEnum), + ast::DefTrait(i) => (i, TypeTrait), + ast::DefStruct(i) => (i, TypeStruct), + ast::DefMod(i) => (i, TypeModule), + ast::DefStatic(i, _) => (i, TypeStatic), + ast::DefVariant(i, _, _) => (i, TypeEnum), + _ => return ast_util::def_id_of_def(def), + }; + if ast_util::is_local(did) { return did } + let tcx = match cx.maybe_typed { + core::Typed(ref t) => t, + core::NotTyped(_) => return did + }; + inline::record_extern_fqn(cx, did, kind); + match kind { + TypeTrait => { + let t = inline::build_external_trait(tcx, did); + cx.external_traits.borrow_mut().get_mut_ref().insert(did, t); + } + _ => {} + } + return did; +} + +fn resolve_use_source(path: Path, id: ast::NodeId) -> ImportSource { + ImportSource { + path: path, + did: resolve_def(id), + } +} + +fn resolve_def(id: ast::NodeId) -> Option { + let cx = super::ctxtkey.get().unwrap(); + match cx.maybe_typed { + core::Typed(ref tcx) => { + tcx.def_map.borrow().find(&id).map(|&def| register_def(&**cx, def)) + } + core::NotTyped(_) => None + } +} + +#[deriving(Clone, Encodable, Decodable)] +pub struct Macro { + pub source: String, +} + +impl Clean for doctree::Macro { + fn clean(&self) -> Item { + Item { + name: Some(format_strbuf!("{}!", self.name.clean())), + attrs: self.attrs.clean(), + source: self.where.clean(), + visibility: ast::Public.clean(), + def_id: ast_util::local_def(self.id), + inner: MacroItem(Macro { + source: self.where.to_src(), + }), + } + } +} diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index ce7f230ea53..d601d2ae957 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -143,7 +143,7 @@ pub struct Cache { /// Similar to `paths`, but only holds external paths. This is only used for /// generating explicit hyperlinks to other crates. - pub external_paths: HashMap>, + pub external_paths: HashMap>, /// This map contains information about all known traits of this crate. /// Implementations of a crate should inherit the documentation of the @@ -253,7 +253,7 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> { let analysis = ::analysiskey.get(); let public_items = analysis.as_ref().map(|a| a.public_items.clone()); let public_items = public_items.unwrap_or(NodeSet::new()); - let paths: HashMap, ItemType)> = + let paths: HashMap, ItemType)> = analysis.as_ref().map(|a| { let paths = a.external_paths.borrow_mut().take_unwrap(); paths.move_iter().map(|(k, (v, t))| { @@ -1041,7 +1041,19 @@ impl<'a> Item<'a> { } } - fn link(&self) -> Option { + /// Generate a url appropriate for an `href` attribute back to the source of + /// this item. + /// + /// The url generated, when clicked, will redirect the browser back to the + /// original source code. + /// + /// If `None` is returned, then a source link couldn't be generated. This + /// may happen, for example, with externally inlined items where the source + /// of their crate documentation isn't known. + fn href(&self) -> Option { + // If this item is part of the local crate, then we're guaranteed to + // know the span, so we plow forward and generate a proper url. The url + // has anchors for the line numbers that we're linking to. if ast_util::is_local(self.item.def_id) { let mut path = Vec::new(); clean_srcpath(self.item.source.filename.as_bytes(), |component| { @@ -1059,6 +1071,18 @@ impl<'a> Item<'a> { krate = self.cx.layout.krate, path = path.connect("/"), href = href)) + + // If this item is not part of the local crate, then things get a little + // trickier. We don't actually know the span of the external item, but + // we know that the documentation on the other end knows the span! + // + // In this case, we generate a link to the *documentation* for this type + // in the original crate. There's an extra URL parameter which says that + // we want to go somewhere else, and the JS on the destination page will + // pick it up and instantly redirect the browser to the source code. + // + // If we don't know where the external documentation for this crate is + // located, then we return `None`. } else { let cache = cache_key.get().unwrap(); let path = cache.external_paths.get(&self.item.def_id); @@ -1120,8 +1144,13 @@ impl<'a> fmt::Show for Item<'a> { } // Write `src` tag + // + // When this item is part of a `pub use` in a downstream crate, the + // [src] link in the downstream documentation will actually come back to + // this page, and this link will be auto-clicked. The `id` attribute is + // used to find the link to auto-click. if self.cx.include_sources { - match self.link() { + match self.href() { Some(l) => { try!(write!(fmt, " = ")); if s.contains("\n") { write!(f, "[definition]", - item.link()) + item.href()) } else { write!(f, "{}", s.as_slice()) } diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index ec58162fa92..2fb824653d3 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -676,13 +676,9 @@ window.register_implementors(window.pending_implementors); } - - var query = window.location.search.substring(1); - var vars = query.split('&'); - for (var i = 0; i < vars.length; i++) { - var pair = vars[i].split('='); - if (pair[0] == 'gotosrc') { - window.location = $('#src-' + pair[1]).attr('href'); - } + // See documentaiton in html/render.rs for what this is doing. + var query = getQueryStringParams(); + if (query['gotosrc']) { + window.location = $('#src-' + query['gotosrc']).attr('href'); } }()); diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 0d42e1743f5..1786cc8062e 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -16,10 +16,10 @@ //! //! ## Intrinsic types and operations //! -//! The [`ptr`](../core/ptr/index.html) and [`mem`](../core/mem/index.html) +//! The [`ptr`](ptr/index.html) and [`mem`](mem/index.html) //! modules deal with unsafe pointers and memory manipulation. -//! [`kinds`](../core/kinds/index.html) defines the special built-in traits, -//! and [`raw`](../core/raw/index.html) the runtime representation of Rust types. +//! [`kinds`](kinds/index.html) defines the special built-in traits, +//! and [`raw`](raw/index.html) the runtime representation of Rust types. //! These are some of the lowest-level building blocks in Rust. //! //! ## Math on primitive types and math traits @@ -31,11 +31,11 @@ //! //! ## Pervasive types //! -//! The [`option`](option/index.html) and [`result`](../core/result/index.html) +//! The [`option`](option/index.html) and [`result`](result/index.html) //! modules define optional and error-handling types, `Option` and `Result`. -//! [`iter`](../core/iter/index.html) defines Rust's iterator protocol +//! [`iter`](iter/index.html) defines Rust's iterator protocol //! along with a wide variety of iterators. -//! [`Cell` and `RefCell`](../core/cell/index.html) are for creating types that +//! [`Cell` and `RefCell`](cell/index.html) are for creating types that //! manage their own mutability. //! //! ## Vectors, slices and strings diff --git a/src/libstd/prelude.rs b/src/libstd/prelude.rs index ef05f3b167a..07aaeac64be 100644 --- a/src/libstd/prelude.rs +++ b/src/libstd/prelude.rs @@ -38,62 +38,62 @@ //! `drop`, `spawn`, and `channel`. // Reexported core operators -#[doc(noinline)] pub use kinds::{Copy, Send, Sized, Share}; -#[doc(noinline)] pub use ops::{Add, Sub, Mul, Div, Rem, Neg, Not}; -#[doc(noinline)] pub use ops::{BitAnd, BitOr, BitXor}; -#[doc(noinline)] pub use ops::{Drop, Deref, DerefMut}; -#[doc(noinline)] pub use ops::{Shl, Shr, Index}; -#[doc(noinline)] pub use option::{Option, Some, None}; -#[doc(noinline)] pub use result::{Result, Ok, Err}; +#[doc(no_inline)] pub use kinds::{Copy, Send, Sized, Share}; +#[doc(no_inline)] pub use ops::{Add, Sub, Mul, Div, Rem, Neg, Not}; +#[doc(no_inline)] pub use ops::{BitAnd, BitOr, BitXor}; +#[doc(no_inline)] pub use ops::{Drop, Deref, DerefMut}; +#[doc(no_inline)] pub use ops::{Shl, Shr, Index}; +#[doc(no_inline)] pub use option::{Option, Some, None}; +#[doc(no_inline)] pub use result::{Result, Ok, Err}; // Reexported functions -#[doc(noinline)] pub use from_str::from_str; -#[doc(noinline)] pub use iter::range; -#[doc(noinline)] pub use mem::drop; +#[doc(no_inline)] pub use from_str::from_str; +#[doc(no_inline)] pub use iter::range; +#[doc(no_inline)] pub use mem::drop; // Reexported types and traits -#[doc(noinline)] pub use ascii::{Ascii, AsciiCast, OwnedAsciiCast, AsciiStr}; -#[doc(noinline)] pub use ascii::IntoBytes; -#[doc(noinline)] pub use c_str::ToCStr; -#[doc(noinline)] pub use char::Char; -#[doc(noinline)] pub use clone::Clone; -#[doc(noinline)] pub use cmp::{Eq, Ord, TotalEq, TotalOrd}; -#[doc(noinline)] pub use cmp::{Ordering, Less, Equal, Greater, Equiv}; -#[doc(noinline)] pub use container::{Container, Mutable, Map, MutableMap}; -#[doc(noinline)] pub use container::{Set, MutableSet}; -#[doc(noinline)] pub use iter::{FromIterator, Extendable, ExactSize}; -#[doc(noinline)] pub use iter::{Iterator, DoubleEndedIterator}; -#[doc(noinline)] pub use iter::{RandomAccessIterator, CloneableIterator}; -#[doc(noinline)] pub use iter::{OrdIterator, MutableDoubleEndedIterator}; -#[doc(noinline)] pub use num::{Num, NumCast, CheckedAdd, CheckedSub, CheckedMul}; -#[doc(noinline)] pub use num::{Signed, Unsigned, Primitive, Int, Float}; -#[doc(noinline)] pub use num::{FloatMath, ToPrimitive, FromPrimitive}; -#[doc(noinline)] pub use option::Expect; -#[doc(noinline)] pub use owned::Box; -#[doc(noinline)] pub use path::{GenericPath, Path, PosixPath, WindowsPath}; -#[doc(noinline)] pub use ptr::RawPtr; -#[doc(noinline)] pub use io::{Buffer, Writer, Reader, Seek}; -#[doc(noinline)] pub use str::{Str, StrVector, StrSlice, OwnedStr}; -#[doc(noinline)] pub use str::{IntoMaybeOwned, StrAllocating}; -#[doc(noinline)] pub use to_str::{ToStr, IntoStr}; -#[doc(noinline)] pub use tuple::{Tuple1, Tuple2, Tuple3, Tuple4}; -#[doc(noinline)] pub use tuple::{Tuple5, Tuple6, Tuple7, Tuple8}; -#[doc(noinline)] pub use tuple::{Tuple9, Tuple10, Tuple11, Tuple12}; -#[doc(noinline)] pub use slice::{CloneableVector, ImmutableCloneableVector}; -#[doc(noinline)] pub use slice::{MutableCloneableVector, MutableTotalOrdVector}; -#[doc(noinline)] pub use slice::{ImmutableVector, MutableVector}; -#[doc(noinline)] pub use slice::{ImmutableEqVector, ImmutableTotalOrdVector}; -#[doc(noinline)] pub use slice::{Vector, VectorVector, OwnedVector}; -#[doc(noinline)] pub use slice::MutableVectorAllocating; -#[doc(noinline)] pub use string::String; -#[doc(noinline)] pub use vec::Vec; +#[doc(no_inline)] pub use ascii::{Ascii, AsciiCast, OwnedAsciiCast, AsciiStr}; +#[doc(no_inline)] pub use ascii::IntoBytes; +#[doc(no_inline)] pub use c_str::ToCStr; +#[doc(no_inline)] pub use char::Char; +#[doc(no_inline)] pub use clone::Clone; +#[doc(no_inline)] pub use cmp::{Eq, Ord, TotalEq, TotalOrd}; +#[doc(no_inline)] pub use cmp::{Ordering, Less, Equal, Greater, Equiv}; +#[doc(no_inline)] pub use container::{Container, Mutable, Map, MutableMap}; +#[doc(no_inline)] pub use container::{Set, MutableSet}; +#[doc(no_inline)] pub use iter::{FromIterator, Extendable, ExactSize}; +#[doc(no_inline)] pub use iter::{Iterator, DoubleEndedIterator}; +#[doc(no_inline)] pub use iter::{RandomAccessIterator, CloneableIterator}; +#[doc(no_inline)] pub use iter::{OrdIterator, MutableDoubleEndedIterator}; +#[doc(no_inline)] pub use num::{Num, NumCast, CheckedAdd, CheckedSub, CheckedMul}; +#[doc(no_inline)] pub use num::{Signed, Unsigned, Primitive, Int, Float}; +#[doc(no_inline)] pub use num::{FloatMath, ToPrimitive, FromPrimitive}; +#[doc(no_inline)] pub use option::Expect; +#[doc(no_inline)] pub use owned::Box; +#[doc(no_inline)] pub use path::{GenericPath, Path, PosixPath, WindowsPath}; +#[doc(no_inline)] pub use ptr::RawPtr; +#[doc(no_inline)] pub use io::{Buffer, Writer, Reader, Seek}; +#[doc(no_inline)] pub use str::{Str, StrVector, StrSlice, OwnedStr}; +#[doc(no_inline)] pub use str::{IntoMaybeOwned, StrAllocating}; +#[doc(no_inline)] pub use to_str::{ToStr, IntoStr}; +#[doc(no_inline)] pub use tuple::{Tuple1, Tuple2, Tuple3, Tuple4}; +#[doc(no_inline)] pub use tuple::{Tuple5, Tuple6, Tuple7, Tuple8}; +#[doc(no_inline)] pub use tuple::{Tuple9, Tuple10, Tuple11, Tuple12}; +#[doc(no_inline)] pub use slice::{CloneableVector, ImmutableCloneableVector}; +#[doc(no_inline)] pub use slice::{MutableCloneableVector, MutableTotalOrdVector}; +#[doc(no_inline)] pub use slice::{ImmutableVector, MutableVector}; +#[doc(no_inline)] pub use slice::{ImmutableEqVector, ImmutableTotalOrdVector}; +#[doc(no_inline)] pub use slice::{Vector, VectorVector, OwnedVector}; +#[doc(no_inline)] pub use slice::MutableVectorAllocating; +#[doc(no_inline)] pub use string::String; +#[doc(no_inline)] pub use vec::Vec; // Reexported runtime types -#[doc(noinline)] pub use comm::{sync_channel, channel}; -#[doc(noinline)] pub use comm::{SyncSender, Sender, Receiver}; -#[doc(noinline)] pub use task::spawn; +#[doc(no_inline)] pub use comm::{sync_channel, channel}; +#[doc(no_inline)] pub use comm::{SyncSender, Sender, Receiver}; +#[doc(no_inline)] pub use task::spawn; // Reexported statics #[cfg(not(test))] -#[doc(noinline)] pub use gc::GC; +#[doc(no_inline)] pub use gc::GC; -- cgit 1.4.1-3-g733a5