diff --git a/src/librustdoc/clean.rs b/src/librustdoc/clean.rs index 68af35acdbe3382eeb25dee0ca72367983cecbf6..8f98ccc04050a46e6f045c7420c61f72037a43dd 100644 --- a/src/librustdoc/clean.rs +++ b/src/librustdoc/clean.rs @@ -15,7 +15,7 @@ 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 @@ fn clean(&self) -> Item { 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 @@ fn clean(&self) -> TraitMethod { 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 @@ fn clean(&self) -> TraitMethod { 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 53e271dafa28da5db2226aea86b442b91a133708..76b7a7a2101e2ca5f3066dddf46ba84583e37078 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 @@ fn fold_item(&mut self, item: clean::Item) -> Option { 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 @@ fn fold_item(&mut self, item: clean::Item) -> Option { }); } (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 @@ fn fold_item(&mut self, item: clean::Item) -> Option { 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 @@ fn fold_item(&mut self, item: clean::Item) -> Option { // 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 }