From 712118b9c0030762fa8942c0ad52a652875bee02 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 22 May 2014 22:00:18 -0700 Subject: [PATCH 01/16] rustdoc: Inline documentation of `pub use` This commit teaches rustdoc to inline the documentation for the destination of a `pub use` statement across crate boundaries. This is intended for the standard library's facade to show the fact that the facade is just an implementation detail rather than the api of the standard library itself. This starts out by inlining traits and functions, but more items will come soon. The current drawback of this system is that hyperlinks across crates sill go to the original item's definition rather than the reexported location. --- src/librustdoc/clean.rs | 131 +++++++++++++++++++++++++++++----- src/librustdoc/html/render.rs | 62 +++++++--------- 2 files changed, 140 insertions(+), 53 deletions(-) diff --git a/src/librustdoc/clean.rs b/src/librustdoc/clean.rs index 68af35acdbe33..8f98ccc04050a 100644 --- a/src/librustdoc/clean.rs +++ b/src/librustdoc/clean.rs @@ -15,7 +15,7 @@ use syntax; use syntax::ast; use syntax::ast_util; use syntax::attr; -use syntax::attr::AttributeMethods; +use syntax::attr::{AttributeMethods, AttrMetaMethods}; use syntax::codemap::Pos; use syntax::parse::token::InternedString; use syntax::parse::token; @@ -250,7 +250,8 @@ impl Clean for doctree::Module { self.statics.clean().move_iter().collect(), self.traits.clean().move_iter().collect(), self.impls.clean().move_iter().collect(), - self.view_items.clean().move_iter().collect(), + self.view_items.clean().move_iter() + .flat_map(|s| s.move_iter()).collect(), self.macros.clean().move_iter().collect() ); @@ -832,10 +833,6 @@ impl Clean for ty::Method { core::Typed(ref tcx) => tcx, core::NotTyped(_) => fail!(), }; - let mut attrs = Vec::new(); - csearch::get_item_attrs(&tcx.sess.cstore, self.def_id, |v| { - attrs.extend(v.move_iter().map(|i| i.clean())); - }); let (self_, sig) = match self.explicit_self { ast::SelfStatic => (ast::SelfStatic.clean(), self.fty.sig.clone()), s => { @@ -861,7 +858,7 @@ impl Clean for ty::Method { name: Some(self.ident.clean()), visibility: Some(ast::Inherited), def_id: self.def_id, - attrs: attrs, + attrs: load_attrs(tcx, self.def_id), source: Span { filename: "".to_strbuf(), loline: 0, locol: 0, hiline: 0, hicol: 0, @@ -1404,21 +1401,105 @@ pub struct ViewItem { pub inner: ViewItemInner, } -impl Clean for ast::ViewItem { - fn clean(&self) -> Item { - 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: self.node.clean() - }), +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(item) => { ret.push(item); 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(item) => ret.push(item), + 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 } + let inner = match def { + ast::DefTrait(did) => TraitItem(build_external_trait(tcx, did)), + ast::DefFn(did, style) => + FunctionItem(build_external_function(tcx, did, style)), + _ => return None, + }; + let fqn = csearch::get_item_path(tcx, did); + Some(Item { + source: Span { + filename: "".to_strbuf(), loline: 0, locol: 0, hiline: 0, hicol: 0, + }, + name: Some(fqn.last().unwrap().to_str().to_strbuf()), + attrs: load_attrs(tcx, did), + inner: inner, + visibility: Some(ast::Public), + def_id: did, + }) +} + +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), @@ -1654,6 +1735,20 @@ fn build_external_trait(tcx: &ty::ctxt, did: ast::DefId) -> Trait { } } +fn build_external_function(tcx: &ty::ctxt, + did: ast::DefId, + style: ast::FnStyle) -> Function { + let t = csearch::get_type(tcx, did); + Function { + decl: match ty::get(t.ty).sty { + ty::ty_bare_fn(ref f) => f.sig.clean(), + _ => fail!("bad function"), + }, + generics: t.generics.clean(), + fn_style: style, + } +} + fn resolve_use_source(path: Path, id: ast::NodeId) -> ImportSource { ImportSource { path: path, diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 53e271dafa28d..76b7a7a2101e2 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -157,9 +157,9 @@ pub struct Cache { // Private fields only used when initially crawling a crate to build a cache - stack: Vec , - parent_stack: Vec , - search_index: Vec , + stack: Vec, + parent_stack: Vec, + search_index: Vec, privmod: bool, public_items: NodeSet, @@ -198,7 +198,7 @@ struct IndexItem { name: String, path: String, desc: String, - parent: Option, + parent: Option, } // TLS keys used to carry information around during rendering. @@ -302,7 +302,7 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> { path: fqp.slice_to(fqp.len() - 1).connect("::") .to_strbuf(), desc: shorter(item.doc_value()).to_strbuf(), - parent: Some(pid), + parent: Some(did), }); }, None => {} @@ -360,9 +360,8 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> { try!(write!(&mut w, r#"],"paths":["#)); - for (i, &nodeid) in pathid_to_nodeid.iter().enumerate() { - let def = ast_util::local_def(nodeid); - let &(ref fqp, short) = cache.paths.find(&def).unwrap(); + for (i, &did) in pathid_to_nodeid.iter().enumerate() { + let &(ref fqp, short) = cache.paths.find(&did).unwrap(); if i > 0 { try!(write!(&mut w, ",")); } @@ -730,14 +729,13 @@ impl DocFolder for Cache { clean::VariantItem(..) => { (Some(*self.parent_stack.last().unwrap()), Some(self.stack.slice_to(self.stack.len() - 1))) - } clean::MethodItem(..) => { if self.parent_stack.len() == 0 { (None, None) } else { let last = self.parent_stack.last().unwrap(); - let did = ast_util::local_def(*last); + let did = *last; let path = match self.paths.find(&did) { Some(&(_, item_type::Trait)) => Some(self.stack.slice_to(self.stack.len() - 1)), @@ -766,9 +764,11 @@ impl DocFolder for Cache { }); } (Some(parent), None) if !self.privmod => { - // We have a parent, but we don't know where they're - // defined yet. Wait for later to index this item. - self.orphan_methods.push((parent, item.clone())) + if ast_util::is_local(parent) { + // We have a parent, but we don't know where they're + // defined yet. Wait for later to index this item. + self.orphan_methods.push((parent.node, item.clone())) + } } _ => {} } @@ -789,19 +789,17 @@ impl DocFolder for Cache { clean::TypedefItem(..) | clean::TraitItem(..) | clean::FunctionItem(..) | clean::ModuleItem(..) | clean::ForeignFunctionItem(..) => { - if ast_util::is_local(item.def_id) { - // Reexported items mean that the same id can show up twice - // in the rustdoc ast that we're looking at. We know, - // however, that a reexported item doesn't show up in the - // `public_items` map, so we can skip inserting into the - // paths map if there was already an entry present and we're - // not a public item. - let id = item.def_id.node; - if !self.paths.contains_key(&item.def_id) || - self.public_items.contains(&id) { - self.paths.insert(item.def_id, - (self.stack.clone(), shortty(&item))); - } + // Reexported items mean that the same id can show up twice + // in the rustdoc ast that we're looking at. We know, + // however, that a reexported item doesn't show up in the + // `public_items` map, so we can skip inserting into the + // paths map if there was already an entry present and we're + // not a public item. + let id = item.def_id.node; + if !self.paths.contains_key(&item.def_id) || + self.public_items.contains(&id) { + self.paths.insert(item.def_id, + (self.stack.clone(), shortty(&item))); } } // link variants to their parent enum because pages aren't emitted @@ -817,20 +815,14 @@ impl DocFolder for Cache { // Maintain the parent stack let parent_pushed = match item.inner { clean::TraitItem(..) | clean::EnumItem(..) | clean::StructItem(..) => { - if ast_util::is_local(item.def_id) { - self.parent_stack.push(item.def_id.node); - } + self.parent_stack.push(item.def_id); true } clean::ImplItem(ref i) => { match i.for_ { clean::ResolvedPath{ did, .. } => { - if ast_util::is_local(did) { - self.parent_stack.push(did.node); - true - } else { - false - } + self.parent_stack.push(did); + true } _ => false } From 8b8e70ba1d47ca76217980f0c4c6f55b60a06e06 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 22 May 2014 22:02:34 -0700 Subject: [PATCH 02/16] std: Add doc(noinline) to the prelude reexports --- src/libstd/prelude.rs | 91 +++++++++++++++++++++++-------------------- 1 file changed, 49 insertions(+), 42 deletions(-) diff --git a/src/libstd/prelude.rs b/src/libstd/prelude.rs index 8d028a7a96a7e..ef05f3b167a68 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; From c81b511bfdbb5f0fb2a6c7522cf4b8dbe5c83ece Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 May 2014 00:42:33 -0700 Subject: [PATCH 03/16] rustdoc: Start inlining structs across crates --- src/librustdoc/clean.rs | 213 +++++++++++++++++++++++++++++----- src/librustdoc/html/render.rs | 10 +- src/librustdoc/passes.rs | 3 +- 3 files changed, 192 insertions(+), 34 deletions(-) diff --git a/src/librustdoc/clean.rs b/src/librustdoc/clean.rs index 8f98ccc04050a..5497ca7b135a0 100644 --- a/src/librustdoc/clean.rs +++ b/src/librustdoc/clean.rs @@ -27,7 +27,7 @@ use rustc::metadata::csearch; use rustc::metadata::decoder; use rustc::middle::ty; -use std::string::String; +use std::rc::Rc; use core; use doctree; @@ -53,6 +53,12 @@ impl, U> Clean for @T { } } +impl, U> Clean for Rc { + fn clean(&self) -> U { + (**self).clean() + } +} + impl, U> Clean> for Option { fn clean(&self) -> Option { match self { @@ -337,6 +343,14 @@ impl attr::AttrMetaMethods for Attribute { 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 { @@ -859,10 +873,7 @@ impl Clean for ty::Method { visibility: Some(ast::Inherited), def_id: self.def_id, attrs: load_attrs(tcx, self.def_id), - source: Span { - filename: "".to_strbuf(), - loline: 0, locol: 0, hiline: 0, hicol: 0, - }, + source: Span::empty(), inner: TyMethodItem(TyMethod { fn_style: self.fty.fn_style, generics: self.generics.clean(), @@ -1070,6 +1081,31 @@ impl Clean for ast::StructField { } } +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 { @@ -1199,6 +1235,16 @@ pub struct Span { 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(); @@ -1270,6 +1316,12 @@ impl Clean for ast::Ident { } } +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, @@ -1366,19 +1418,14 @@ pub struct Impl { 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 { - let mut derived = false; - for attr in self.attrs.iter() { - match attr.node.value.node { - ast::MetaWord(ref s) => { - if s.get() == "automatically_derived" { - derived = true; - } - } - _ => {} - } - } Item { name: None, attrs: self.attrs.clean(), @@ -1390,7 +1437,7 @@ impl Clean for doctree::Impl { trait_: self.trait_.clean(), for_: self.for_.clean(), methods: self.methods.clean(), - derived: derived, + derived: detect_derived(self.attrs.as_slice()), }), } } @@ -1427,7 +1474,9 @@ impl Clean> for ast::ViewItem { ast::ViewPathList(ref a, ref list, ref b) => { let remaining = list.iter().filter(|path| { match try_inline(path.node.id) { - Some(item) => { ret.push(item); false } + Some(items) => { + ret.extend(items.move_iter()); false + } None => true, } }).map(|a| a.clone()).collect::>(); @@ -1441,7 +1490,7 @@ impl Clean> for ast::ViewItem { } ast::ViewPathSimple(_, _, id) => { match try_inline(id) { - Some(item) => ret.push(item), + Some(items) => ret.extend(items.move_iter()), None => ret.push(convert(&self.node)), } } @@ -1453,7 +1502,7 @@ impl Clean> for ast::ViewItem { } } -fn try_inline(id: ast::NodeId) -> Option { +fn try_inline(id: ast::NodeId) -> Option> { let cx = super::ctxtkey.get().unwrap(); let tcx = match cx.maybe_typed { core::Typed(ref tycx) => tycx, @@ -1465,23 +1514,28 @@ fn try_inline(id: ast::NodeId) -> Option { }; let did = ast_util::def_id_of_def(def); if ast_util::is_local(did) { return None } + + let mut ret = Vec::new(); let inner = match def { ast::DefTrait(did) => TraitItem(build_external_trait(tcx, did)), ast::DefFn(did, style) => FunctionItem(build_external_function(tcx, did, style)), + ast::DefStruct(did) => { + ret.extend(build_impls(tcx, did).move_iter()); + StructItem(build_struct(tcx, did)) + } _ => return None, }; let fqn = csearch::get_item_path(tcx, did); - Some(Item { - source: Span { - filename: "".to_strbuf(), loline: 0, locol: 0, hiline: 0, hicol: 0, - }, + 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 { @@ -1726,7 +1780,7 @@ fn register_def(cx: &core::DocContext, def: ast::Def) -> ast::DefId { } fn build_external_trait(tcx: &ty::ctxt, did: ast::DefId) -> Trait { - let def = csearch::get_trait_def(tcx, did); + let def = ty::lookup_trait_def(tcx, did); let methods = ty::trait_methods(tcx, did); Trait { generics: def.generics.clean(), @@ -1738,7 +1792,7 @@ fn build_external_trait(tcx: &ty::ctxt, did: ast::DefId) -> Trait { fn build_external_function(tcx: &ty::ctxt, did: ast::DefId, style: ast::FnStyle) -> Function { - let t = csearch::get_type(tcx, did); + let t = ty::lookup_item_type(tcx, did); Function { decl: match ty::get(t.ty).sty { ty::ty_bare_fn(ref f) => f.sig.clean(), @@ -1749,6 +1803,111 @@ fn build_external_function(tcx: &ty::ctxt, } } +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_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 = tcx.impl_methods.borrow().get(&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 resolve_use_source(path: Path, id: ast::NodeId) -> ImportSource { ImportSource { path: path, diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 76b7a7a2101e2..93bd5249a2f71 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -132,7 +132,7 @@ pub struct Cache { /// /// The values of the map are a list of implementations and documentation /// found on that implementation. - pub impls: HashMap)>>, + pub impls: HashMap)>>, /// Maintains a mapping of local crate node ids to the fully qualified name /// and "short type description" of that node. This is used when generating @@ -837,10 +837,8 @@ impl DocFolder for Cache { match item { clean::Item{ attrs, inner: clean::ImplItem(i), .. } => { match i.for_ { - clean::ResolvedPath { did, .. } - if ast_util::is_local(did) => - { - let v = self.impls.find_or_insert_with(did.node, |_| { + clean::ResolvedPath { did, .. } => { + let v = self.impls.find_or_insert_with(did, |_| { Vec::new() }); // extract relevant documentation for this impl @@ -1664,7 +1662,7 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item, } fn render_methods(w: &mut fmt::Formatter, it: &clean::Item) -> fmt::Result { - match cache_key.get().unwrap().impls.find(&it.def_id.node) { + match cache_key.get().unwrap().impls.find(&it.def_id) { Some(v) => { let mut non_trait = v.iter().filter(|p| { p.ref0().trait_.is_none() diff --git a/src/librustdoc/passes.rs b/src/librustdoc/passes.rs index 16c319d6363bb..390f81642e6b2 100644 --- a/src/librustdoc/passes.rs +++ b/src/librustdoc/passes.rs @@ -152,7 +152,8 @@ impl<'a> fold::DocFolder for Stripper<'a> { clean::ImplItem(clean::Impl{ for_: clean::ResolvedPath{ did, .. }, .. }) => { - if !self.exported_items.contains(&did.node) { + if ast_util::is_local(did) && + !self.exported_items.contains(&did.node) { return None; } } From 622c8f7b57b70a61dc5c9a4b288ce5bf2ff8ac04 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 May 2014 16:14:54 -0700 Subject: [PATCH 04/16] rustdoc: Inline enums across crates --- src/librustdoc/clean.rs | 66 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/src/librustdoc/clean.rs b/src/librustdoc/clean.rs index 5497ca7b135a0..77b835b232d9c 100644 --- a/src/librustdoc/clean.rs +++ b/src/librustdoc/clean.rs @@ -1204,6 +1204,49 @@ impl Clean for doctree::Variant { } } +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, @@ -1524,6 +1567,10 @@ fn try_inline(id: ast::NodeId) -> Option> { ret.extend(build_impls(tcx, did).move_iter()); StructItem(build_struct(tcx, did)) } + ast::DefTy(did) => { + ret.extend(build_impls(tcx, did).move_iter()); + build_type(tcx, did) + } _ => return None, }; let fqn = csearch::get_item_path(tcx, did); @@ -1822,6 +1869,25 @@ fn build_struct(tcx: &ty::ctxt, did: ast::DefId) -> Struct { } } +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); From ec4f79ff6c997b4144a59fbfb145933c1e3ff593 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 May 2014 16:16:35 -0700 Subject: [PATCH 05/16] rustdoc: Don't show reexported enum variants For now just assume that the enum type itself is reexported. --- src/librustdoc/clean.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/librustdoc/clean.rs b/src/librustdoc/clean.rs index 77b835b232d9c..94ccd3ac40ea7 100644 --- a/src/librustdoc/clean.rs +++ b/src/librustdoc/clean.rs @@ -1571,6 +1571,9 @@ fn try_inline(id: ast::NodeId) -> Option> { 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()), _ => return None, }; let fqn = csearch::get_item_path(tcx, did); From 6ee9109c8b1eb170b7fb6fac6d248801dcd42817 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 May 2014 17:13:44 -0700 Subject: [PATCH 06/16] rustdoc: Inline argument names of foreign methods --- src/librustc/metadata/common.rs | 3 +++ src/librustc/metadata/csearch.rs | 7 +++++++ src/librustc/metadata/decoder.rs | 15 +++++++++++++++ src/librustc/metadata/encoder.rs | 15 +++++++++++++++ src/librustdoc/clean.rs | 18 ++++++++++++++---- 5 files changed, 54 insertions(+), 4 deletions(-) diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index f30d6119339ab..c798118bbd0fa 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -206,6 +206,9 @@ pub static tag_crate_triple: uint = 0x66; pub static tag_dylib_dependency_formats: uint = 0x67; +pub static tag_method_argument_names: uint = 0x8e; +pub static tag_method_argument_name: uint = 0x8f; + #[deriving(Clone, Show)] pub struct LinkMeta { pub crateid: CrateId, diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index efe3633195e7c..d7f603d19092d 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -306,3 +306,10 @@ pub fn get_missing_lang_items(cstore: &cstore::CStore, cnum: ast::CrateNum) let cdata = cstore.get_crate_data(cnum); decoder::get_missing_lang_items(&*cdata) } + +pub fn get_method_arg_names(cstore: &cstore::CStore, did: ast::DefId) + -> 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 83b24d882e5b5..26149785653fd 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -1309,3 +1309,18 @@ pub fn get_missing_lang_items(cdata: Cmd) }); return result; } + +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) { + Some(args_doc) => { + reader::tagged_docs(args_doc, tag_method_argument_name, |name_doc| { + ret.push(name_doc.as_str_slice().to_strbuf()); + true + }); + } + None => {} + } + return ret; +} diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index bd333a5afe087..941977f6d16e7 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -774,6 +774,21 @@ fn encode_info_for_method(ecx: &EncodeContext, } else { encode_symbol(ecx, ebml_w, m.def_id.node); } + + ebml_w.start_tag(tag_method_argument_names); + for arg in ast_method.decl.inputs.iter() { + ebml_w.start_tag(tag_method_argument_name); + match arg.pat.node { + ast::PatIdent(_, ref name, _) => { + let name = name.segments.last().unwrap().identifier; + let name = token::get_ident(name); + ebml_w.writer.write(name.get().as_bytes()); + } + _ => {} + } + ebml_w.end_tag(); + } + ebml_w.end_tag(); } ebml_w.end_tag(); diff --git a/src/librustdoc/clean.rs b/src/librustdoc/clean.rs index 94ccd3ac40ea7..6e3186eda4c7e 100644 --- a/src/librustdoc/clean.rs +++ b/src/librustdoc/clean.rs @@ -488,7 +488,7 @@ impl Clean>> for ty::substs { } } -#[deriving(Clone, Encodable, Decodable)] +#[deriving(Clone, Encodable, Decodable, Eq)] pub struct Lifetime(String); impl Lifetime { @@ -629,7 +629,7 @@ impl Clean for ast::TypeMethod { } } -#[deriving(Clone, Encodable, Decodable)] +#[deriving(Clone, Encodable, Decodable, Eq)] pub enum SelfTy { SelfStatic, SelfValue, @@ -868,6 +868,16 @@ impl Clean for ty::Method { (s, sig) } }; + let mut names = csearch::get_method_arg_names(&tcx.sess.cstore, + self.def_id).move_iter(); + if self_ != SelfStatic { + names.next(); + } + let mut decl = sig.clean(); + for (name, slot) in names.zip(decl.inputs.values.mut_iter()) { + slot.name = name; + } + m(Item { name: Some(self.ident.clean()), visibility: Some(ast::Inherited), @@ -878,7 +888,7 @@ impl Clean for ty::Method { fn_style: self.fty.fn_style, generics: self.generics.clean(), self_: self_, - decl: sig.clean(), + decl: decl, }) }) } @@ -1437,7 +1447,7 @@ impl Clean for doctree::Static { } } -#[deriving(Show, Clone, Encodable, Decodable)] +#[deriving(Show, Clone, Encodable, Decodable, Eq)] pub enum Mutability { Mutable, Immutable, From 9181c35ee925240fc129d77695e3f88c6d5f0f2b Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 May 2014 18:47:01 -0700 Subject: [PATCH 07/16] rustdoc: Inline names of function arguments --- src/librustc/metadata/encoder.rs | 31 ++++++++++++---------- src/librustdoc/clean.rs | 44 +++++++++++++++++++------------- 2 files changed, 44 insertions(+), 31 deletions(-) diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 941977f6d16e7..b12de2aee09f5 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -774,23 +774,27 @@ fn encode_info_for_method(ecx: &EncodeContext, } else { encode_symbol(ecx, ebml_w, m.def_id.node); } + encode_method_argument_names(ebml_w, &*ast_method.decl); + } - ebml_w.start_tag(tag_method_argument_names); - for arg in ast_method.decl.inputs.iter() { - ebml_w.start_tag(tag_method_argument_name); - match arg.pat.node { - ast::PatIdent(_, ref name, _) => { - let name = name.segments.last().unwrap().identifier; - let name = token::get_ident(name); - ebml_w.writer.write(name.get().as_bytes()); - } - _ => {} + ebml_w.end_tag(); +} + +fn encode_method_argument_names(ebml_w: &mut Encoder, + decl: &ast::FnDecl) { + ebml_w.start_tag(tag_method_argument_names); + for arg in decl.inputs.iter() { + ebml_w.start_tag(tag_method_argument_name); + match arg.pat.node { + ast::PatIdent(_, ref name, _) => { + let name = name.segments.last().unwrap().identifier; + let name = token::get_ident(name); + ebml_w.writer.write(name.get().as_bytes()); } - ebml_w.end_tag(); + _ => {} } ebml_w.end_tag(); } - ebml_w.end_tag(); } @@ -910,7 +914,7 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_visibility(ebml_w, vis); ebml_w.end_tag(); } - ItemFn(_, fn_style, _, ref generics, _) => { + ItemFn(ref decl, fn_style, _, ref generics, _) => { add_to_index(item, ebml_w, index); ebml_w.start_tag(tag_items_data_item); encode_def_id(ebml_w, def_id); @@ -926,6 +930,7 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_symbol(ecx, ebml_w, item.id); } encode_visibility(ebml_w, vis); + encode_method_argument_names(ebml_w, &**decl); ebml_w.end_tag(); } ItemMod(ref m) => { diff --git a/src/librustdoc/clean.rs b/src/librustdoc/clean.rs index 6e3186eda4c7e..79f687b062484 100644 --- a/src/librustdoc/clean.rs +++ b/src/librustdoc/clean.rs @@ -722,18 +722,35 @@ impl Clean for ast::FnDecl { } } -impl Clean for ty::FnSig { +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: self.output.clean(), + output: sig.output.clean(), cf: Return, - attrs: Vec::new(), // FIXME: this is likely wrong + attrs: Vec::new(), inputs: Arguments { - values: self.inputs.iter().map(|t| { + values: sig.inputs.iter().map(|t| { Argument { type_: t.clean(), id: 0, - name: "".to_strbuf(), // FIXME: where are the names? + name: names.next().unwrap_or("".to_strbuf()), } }).collect(), }, @@ -868,15 +885,6 @@ impl Clean for ty::Method { (s, sig) } }; - let mut names = csearch::get_method_arg_names(&tcx.sess.cstore, - self.def_id).move_iter(); - if self_ != SelfStatic { - names.next(); - } - let mut decl = sig.clean(); - for (name, slot) in names.zip(decl.inputs.values.mut_iter()) { - slot.name = name; - } m(Item { name: Some(self.ident.clean()), @@ -888,7 +896,7 @@ impl Clean for ty::Method { fn_style: self.fty.fn_style, generics: self.generics.clean(), self_: self_, - decl: decl, + decl: (self.def_id, &sig).clean(), }) }) } @@ -1005,13 +1013,13 @@ impl Clean for ty::t { generics: Generics { lifetimes: Vec::new(), type_params: Vec::new() }, - decl: fty.sig.clean(), + 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: fty.sig.clean(), + 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(), @@ -1855,7 +1863,7 @@ fn build_external_function(tcx: &ty::ctxt, let t = ty::lookup_item_type(tcx, did); Function { decl: match ty::get(t.ty).sty { - ty::ty_bare_fn(ref f) => f.sig.clean(), + ty::ty_bare_fn(ref f) => (did, &f.sig).clean(), _ => fail!("bad function"), }, generics: t.generics.clean(), From 5ee3d0e1ffa6e190d73815ba4754b2618528c83e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 May 2014 19:01:33 -0700 Subject: [PATCH 08/16] rustdoc: Inline reexported modules --- src/librustdoc/clean.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/librustdoc/clean.rs b/src/librustdoc/clean.rs index 79f687b062484..a78e9d1d1fb0c 100644 --- a/src/librustdoc/clean.rs +++ b/src/librustdoc/clean.rs @@ -1575,8 +1575,12 @@ fn try_inline(id: ast::NodeId) -> Option> { }; let did = ast_util::def_id_of_def(def); if ast_util::is_local(did) { return None } + try_inline_def(tcx, def) +} +fn try_inline_def(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) => TraitItem(build_external_trait(tcx, did)), ast::DefFn(did, style) => @@ -1592,6 +1596,7 @@ fn try_inline(id: ast::NodeId) -> Option> { // 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) => ModuleItem(build_module(tcx, did)), _ => return None, }; let fqn = csearch::get_item_path(tcx, did); @@ -1995,6 +2000,28 @@ fn build_impl(tcx: &ty::ctxt, did: ast::DefId) -> Item { } } +fn build_module(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(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, From 781e898348496d5d290ef0d181ce0a68f606c128 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 May 2014 19:31:13 -0700 Subject: [PATCH 09/16] rustdoc: Use csearch for impl loading The normal analysis passes aren't guaranteed to have loaded all impls, so use the csearch methods directly to load impls. --- src/librustdoc/clean.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/clean.rs b/src/librustdoc/clean.rs index a78e9d1d1fb0c..4ba59647063ee 100644 --- a/src/librustdoc/clean.rs +++ b/src/librustdoc/clean.rs @@ -1961,7 +1961,7 @@ 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 = tcx.impl_methods.borrow().get(&did).iter().map(|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, From 316ef79dc2726a688373f86c5201d14db32684d9 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 May 2014 19:32:00 -0700 Subject: [PATCH 10/16] rustc: Encode module attributes This will allow for rustdoc to pick up the documentation on the other end. --- src/librustc/metadata/encoder.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index b12de2aee09f5..443a8acfb0cc6 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -536,6 +536,7 @@ fn encode_reexports(ecx: &EncodeContext, fn encode_info_for_mod(ecx: &EncodeContext, ebml_w: &mut Encoder, md: &Mod, + attrs: &[Attribute], id: NodeId, path: PathElems, name: Ident, @@ -584,6 +585,7 @@ fn encode_info_for_mod(ecx: &EncodeContext, debug!("(encoding info for module) encoding reexports for {}", id); encode_reexports(ecx, ebml_w, id, path); } + encode_attributes(ebml_w, attrs); ebml_w.end_tag(); } @@ -938,6 +940,7 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_info_for_mod(ecx, ebml_w, m, + item.attrs.as_slice(), item.id, path, item.ident, @@ -1337,6 +1340,7 @@ fn encode_info_for_items(ecx: &EncodeContext, encode_info_for_mod(ecx, ebml_w, &krate.module, + &[], CRATE_NODE_ID, ast_map::Values([].iter()).chain(None), syntax::parse::token::special_idents::invalid, From a96067077a7536f80e131deaf3355c30ba8f3bff Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 May 2014 19:32:18 -0700 Subject: [PATCH 11/16] rustdoc: Prevent a segfault when using markdown The field passed from markdown could sometimes be null, and it wasn't properly handled. --- src/librustdoc/html/markdown.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 7b8514ab38f62..f49b7f3e98903 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -144,6 +144,8 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result { extern fn block(ob: *mut hoedown_buffer, text: *hoedown_buffer, lang: *hoedown_buffer, opaque: *mut libc::c_void) { unsafe { + if text.is_null() { return } + let opaque = opaque as *mut hoedown_html_renderer_state; let my_opaque: &MyOpaque = &*((*opaque).opaque as *MyOpaque); slice::raw::buf_as_slice((*text).data, (*text).size as uint, |text| { From 837d4d8f35d8db10c9899b35e54f4670ba0cd609 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 May 2014 19:41:24 -0700 Subject: [PATCH 12/16] rustdoc: Link to local reexportations of items Within the documentation for a crate, all hyperlinks to reexported items don't go across crates, but rather to the items in the crate itself. This will allow references to Option in the standard library to link to the standard library's Option, instead of libcore's. This does mean that other crate's links for Option will still link to libcore's Option. --- src/librustdoc/html/format.rs | 2 +- src/librustdoc/html/render.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index e14be8ac6fda2..d60fe3c03884c 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -150,7 +150,7 @@ fn resolved_path(w: &mut fmt::Formatter, did: ast::DefId, p: &clean::Path, print_all: bool) -> fmt::Result { path(w, p, print_all, |cache, loc| { - if ast_util::is_local(did) { + if ast_util::is_local(did) || cache.paths.contains_key(&did) { Some(("../".repeat(loc.len())).to_strbuf()) } else { match *cache.extern_locations.get(&did.krate) { diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 93bd5249a2f71..6d6736eac3f31 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -797,6 +797,7 @@ impl DocFolder for Cache { // not a public item. let id = item.def_id.node; if !self.paths.contains_key(&item.def_id) || + !ast_util::is_local(item.def_id) || self.public_items.contains(&id) { self.paths.insert(item.def_id, (self.stack.clone(), shortty(&item))); From 9f13db2cb2edfd626006bd86e01351a8b1c23401 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 May 2014 19:42:26 -0700 Subject: [PATCH 13/16] rustdoc: Fix rendering of the 'static bound --- src/librustdoc/html/format.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index d60fe3c03884c..9043ffd10ba95 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -99,7 +99,7 @@ impl fmt::Show for clean::TyParamBound { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { clean::RegionBound => { - f.write("::".as_bytes()) + f.write("'static".as_bytes()) } clean::TraitBound(ref ty) => { write!(f, "{}", *ty) From 8dad7f579e029fd883d64848f4abb12630dcc3e6 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 23 May 2014 20:17:27 -0700 Subject: [PATCH 14/16] rustdoc: Get [src] links working for inlined dox These links work by hyperlinking back to the actual documentation page with a query parameter which will be recognized and then auto-click the appropriate [src] link. --- src/librustdoc/clean.rs | 47 +++++++++++++++----- src/librustdoc/html/render.rs | 71 +++++++++++++++++++++--------- src/librustdoc/html/static/main.js | 10 +++++ 3 files changed, 96 insertions(+), 32 deletions(-) diff --git a/src/librustdoc/clean.rs b/src/librustdoc/clean.rs index 4ba59647063ee..ab953419a4171 100644 --- a/src/librustdoc/clean.rs +++ b/src/librustdoc/clean.rs @@ -1575,28 +1575,40 @@ fn try_inline(id: ast::NodeId) -> Option> { }; let did = ast_util::def_id_of_def(def); if ast_util::is_local(did) { return None } - try_inline_def(tcx, def) + try_inline_def(&**cx, tcx, def) } -fn try_inline_def(tcx: &ty::ctxt, def: ast::Def) -> Option> { +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) => TraitItem(build_external_trait(tcx, did)), - ast::DefFn(did, style) => - FunctionItem(build_external_function(tcx, did, style)), + 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) => ModuleItem(build_module(tcx, did)), + 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); @@ -1838,10 +1850,7 @@ fn register_def(cx: &core::DocContext, def: ast::Def) -> ast::DefId { core::Typed(ref t) => t, core::NotTyped(_) => return did }; - let fqn = csearch::get_item_path(tcx, did); - let fqn = fqn.move_iter().map(|i| i.to_str().to_strbuf()).collect(); - debug!("recording {} => {}", did, fqn); - cx.external_paths.borrow_mut().get_mut_ref().insert(did, (fqn, kind)); + record_extern_fqn(cx, did, kind); match kind { TypeTrait => { let t = build_external_trait(tcx, did); @@ -1852,6 +1861,19 @@ fn register_def(cx: &core::DocContext, def: ast::Def) -> ast::DefId { 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); @@ -2000,13 +2022,14 @@ fn build_impl(tcx: &ty::ctxt, did: ast::DefId) -> Item { } } -fn build_module(tcx: &ty::ctxt, did: ast::DefId) -> Module { +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(tcx, def) { + match try_inline_def(cx, tcx, def) { Some(i) => items.extend(i.move_iter()), None => {} } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 6d6736eac3f31..ce7f230ea53f0 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -141,6 +141,10 @@ pub struct Cache { /// necessary. pub paths: HashMap, ItemType)>, + /// Similar to `paths`, but only holds external paths. This is only used for + /// generating explicit hyperlinks to other crates. + 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 /// parent trait if no extra documentation is specified, and default methods @@ -249,7 +253,8 @@ 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 = analysis.as_ref().map(|a| { + 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))| { (k, (v, match t { @@ -265,6 +270,8 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> { }).unwrap_or(HashMap::new()); let mut cache = Cache { impls: HashMap::new(), + external_paths: paths.iter().map(|(&k, &(ref v, _))| (k, v.clone())) + .collect(), paths: paths, implementors: HashMap::new(), stack: Vec::new(), @@ -496,13 +503,15 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> { seen: HashSet::new(), cx: &mut cx, }; + // skip all invalid spans + folder.seen.insert("".to_strbuf()); krate = folder.fold_crate(krate); } for &(n, ref e) in krate.externs.iter() { cache.extern_locations.insert(n, extern_location(e, &cx.dst)); let did = ast::DefId { krate: n, node: ast::CRATE_NODE_ID }; - cache.paths.insert(did, (Vec::new(), item_type::Module)); + cache.paths.insert(did, (vec![e.name.to_strbuf()], item_type::Module)); } // And finally render the whole crate's documentation @@ -1032,23 +1041,38 @@ impl<'a> Item<'a> { } } - fn link(&self) -> String { - let mut path = Vec::new(); - clean_srcpath(self.item.source.filename.as_bytes(), |component| { - path.push(component.to_owned()); - }); - let href = if self.item.source.loline == self.item.source.hiline { - format_strbuf!("{}", self.item.source.loline) + fn link(&self) -> Option { + if ast_util::is_local(self.item.def_id) { + let mut path = Vec::new(); + clean_srcpath(self.item.source.filename.as_bytes(), |component| { + path.push(component.to_owned()); + }); + let href = if self.item.source.loline == self.item.source.hiline { + format!("{}", self.item.source.loline) + } else { + format!("{}-{}", + self.item.source.loline, + self.item.source.hiline) + }; + Some(format!("{root}src/{krate}/{path}.html\\#{href}", + root = self.cx.root_path, + krate = self.cx.layout.krate, + path = path.connect("/"), + href = href)) } else { - format_strbuf!("{}-{}", - self.item.source.loline, - self.item.source.hiline) - }; - format_strbuf!("{root}src/{krate}/{path}.html\\#{href}", - root = self.cx.root_path, - krate = self.cx.layout.krate, - path = path.connect("/"), - href = href) + let cache = cache_key.get().unwrap(); + let path = cache.external_paths.get(&self.item.def_id); + let root = match *cache.extern_locations.get(&self.item.def_id.krate) { + Remote(ref s) => s.to_strbuf(), + Local => format!("{}/..", self.cx.root_path), + Unknown => return None, + }; + Some(format!("{root}/{path}/{file}?gotosrc={goto}", + root = root, + path = path.slice_to(path.len() - 1).connect("/"), + file = item_path(self.item), + goto = self.item.def_id.node)) + } } } @@ -1097,8 +1121,15 @@ impl<'a> fmt::Show for Item<'a> { // Write `src` tag if self.cx.include_sources { - try!(write!(fmt, "[src]", - self.link())); + match self.link() { + Some(l) => { + try!(write!(fmt, + "[src]", + self.item.def_id.node, l)); + } + None => {} + } } try!(write!(fmt, "\n")); diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index c88e6aa586833..ec58162fa9265 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -675,4 +675,14 @@ if (window.pending_implementors) { 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'); + } + } }()); From bd339ced3615c89d439b33f6d6ab7bd04c002f74 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 24 May 2014 11:56:16 -0700 Subject: [PATCH 15/16] doc: Document the new #[doc(no_inline)] attribute --- src/doc/rustdoc.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/doc/rustdoc.md b/src/doc/rustdoc.md index 3880503c8e561..625a7a6d802be 100644 --- a/src/doc/rustdoc.md +++ b/src/doc/rustdoc.md @@ -41,6 +41,27 @@ pub fn recalibrate() { # } ~~~ +Documentation can also be controlled via the `doc` attribute on items. + +~~~ +#[doc = " +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)} } +~~~ + +The `doc` attribute can also be used to control how rustdoc emits documentation +in some cases. + +``` +// Rustdoc will inline documentation of a `pub use` into this crate when the +// `pub use` reaches across crates, but this behavior can also be disabled. +#[doc(no_inline)] +pub use std::option::Option; +``` + Doc comments are markdown, and are currently parsed with the [sundown][sundown] library. rustdoc does not yet do any fanciness such as referencing other items inline, like javadoc's `@see`. One exception to this From 3100bc5b82257820051774eb4aa0447b12f3616a Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 24 May 2014 11:56:38 -0700 Subject: [PATCH 16/16] 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/inline.rs | 278 +++++++++++++++++++ src/librustdoc/{clean.rs => clean/mod.rs} | 309 ++-------------------- src/librustdoc/html/render.rs | 39 ++- src/librustdoc/html/static/main.js | 12 +- src/libstd/lib.rs | 12 +- src/libstd/prelude.rs | 98 +++---- 9 files changed, 406 insertions(+), 352 deletions(-) create mode 100644 src/librustdoc/clean/inline.rs rename src/librustdoc/{clean.rs => clean/mod.rs} (85%) diff --git a/src/doc/rustdoc.md b/src/doc/rustdoc.md index 625a7a6d802be..1034c776ea6dd 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 d7f603d19092d..d407cc046807b 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 26149785653fd..e8be05feae806 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/inline.rs b/src/librustdoc/clean/inline.rs new file mode 100644 index 0000000000000..dd5fddca0db8a --- /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.rs b/src/librustdoc/clean/mod.rs similarity index 85% rename from src/librustdoc/clean.rs rename to src/librustdoc/clean/mod.rs index ab953419a4171..f0f6842642534 100644 --- a/src/librustdoc/clean.rs +++ b/src/librustdoc/clean/mod.rs @@ -37,6 +37,8 @@ use visit_ast; /// 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; } @@ -727,7 +729,7 @@ impl<'a> Clean for (ast::DefId, &'a ty::FnSig) { let cx = super::ctxtkey.get().unwrap(); let tcx = match cx.maybe_typed { core::Typed(ref tcx) => tcx, - core::NotTyped(_) => fail!(), + core::NotTyped(_) => unreachable!(), }; let (did, sig) = *self; let mut names = if did.node != 0 { @@ -738,9 +740,6 @@ impl<'a> Clean for (ast::DefId, &'a ty::FnSig) { 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, @@ -862,7 +861,7 @@ impl Clean for ty::Method { let cx = super::ctxtkey.get().unwrap(); let tcx = match cx.maybe_typed { core::Typed(ref tcx) => tcx, - core::NotTyped(_) => fail!(), + core::NotTyped(_) => unreachable!(), }; let (self_, sig) = match self.explicit_self { ast::SelfStatic => (ast::SelfStatic.clean(), self.fty.sig.clone()), @@ -890,7 +889,7 @@ impl Clean for ty::Method { name: Some(self.ident.clean()), visibility: Some(ast::Inherited), def_id: self.def_id, - attrs: load_attrs(tcx, self.def_id), + attrs: inline::load_attrs(tcx, self.def_id), source: Span::empty(), inner: TyMethodItem(TyMethod { fn_style: self.fty.fn_style, @@ -1035,7 +1034,7 @@ impl Clean for ty::t { let cx = super::ctxtkey.get().unwrap(); let tcx = match cx.maybe_typed { core::Typed(ref tycx) => tycx, - core::NotTyped(_) => fail!(), + core::NotTyped(_) => unreachable!(), }; let fqn = csearch::get_item_path(tcx, did); let fqn: Vec = fqn.move_iter().map(|i| { @@ -1110,12 +1109,12 @@ impl Clean for ty::field_ty { let cx = super::ctxtkey.get().unwrap(); let tcx = match cx.maybe_typed { core::Typed(ref tycx) => tycx, - core::NotTyped(_) => fail!(), + core::NotTyped(_) => unreachable!(), }; let ty = ty::lookup_item_type(tcx, self.id); Item { name: name.clean(), - attrs: load_attrs(tcx, self.id), + attrs: inline::load_attrs(tcx, self.id), source: Span::empty(), visibility: Some(self.vis), def_id: self.id, @@ -1245,7 +1244,11 @@ impl Clean for ty::VariantInfo { name: Some(name.clean()), attrs: Vec::new(), visibility: Some(ast::Public), - def_id: self.id, // FIXME: this is not accurate + // 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()) ) @@ -1256,7 +1259,7 @@ impl Clean for ty::VariantInfo { }; Item { name: Some(self.name.clean()), - attrs: load_attrs(tcx, self.id), + attrs: inline::load_attrs(tcx, self.id), source: Span::empty(), visibility: Some(ast::Public), def_id: self.id, @@ -1377,8 +1380,8 @@ impl Clean for ast::Ident { } } -impl Clean for ast::Name { - fn clean(&self) -> StrBuf { +impl Clean for ast::Name { + fn clean(&self) -> String { token::get_name(*self).get().to_strbuf() } } @@ -1480,9 +1483,7 @@ pub struct Impl { } fn detect_derived(attrs: &[M]) -> bool { - attrs.iter().any(|attr| { - attr.name().get() == "automatically_derived" - }) + attr::contains_name(attrs, "automatically_derived") } impl Clean for doctree::Impl { @@ -1511,9 +1512,12 @@ pub struct ViewItem { 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, "noinline"), + Some(l) => attr::contains_name(l, "no_inline"), None => false, } }); @@ -1533,8 +1537,11 @@ impl Clean> for ast::ViewItem { 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 try_inline(path.node.id) { + match inline::try_inline(path.node.id) { Some(items) => { ret.extend(items.move_iter()); false } @@ -1550,7 +1557,7 @@ impl Clean> for ast::ViewItem { } } ast::ViewPathSimple(_, _, id) => { - match try_inline(id) { + match inline::try_inline(id) { Some(items) => ret.extend(items.move_iter()), None => ret.push(convert(&self.node)), } @@ -1563,82 +1570,6 @@ impl Clean> for ast::ViewItem { } } -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), @@ -1850,10 +1781,10 @@ fn register_def(cx: &core::DocContext, def: ast::Def) -> ast::DefId { core::Typed(ref t) => t, core::NotTyped(_) => return did }; - record_extern_fqn(cx, did, kind); + inline::record_extern_fqn(cx, did, kind); match kind { TypeTrait => { - let t = build_external_trait(tcx, did); + let t = inline::build_external_trait(tcx, did); cx.external_traits.borrow_mut().get_mut_ref().insert(did, t); } _ => {} @@ -1861,190 +1792,6 @@ fn register_def(cx: &core::DocContext, def: ast::Def) -> ast::DefId { 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, diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index ce7f230ea53f0..d601d2ae957fe 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 ec58162fa9265..2fb824653d3db 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 0d42e1743f561..1786cc8062e21 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 ef05f3b167a68..07aaeac64be1c 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;