diff --git a/src/librustdoc/clean.rs b/src/librustdoc/clean.rs index ae7cbf76bcc..623ac82486d 100644 --- a/src/librustdoc/clean.rs +++ b/src/librustdoc/clean.rs @@ -16,6 +16,7 @@ use its = syntax::parse::token::ident_to_str; use syntax; use syntax::ast; use syntax::ast_util; +use syntax::attr; use syntax::attr::AttributeMethods; use std; @@ -149,6 +150,8 @@ pub enum ItemEnum { MethodItem(Method), StructFieldItem(StructField), VariantItem(Variant), + ForeignFunctionItem(Function), + ForeignStaticItem(Static), } #[deriving(Clone, Encodable, Decodable)] @@ -172,6 +175,7 @@ impl Clean for doctree::Module { inner: ModuleItem(Module { items: std::vec::concat(&[self.structs.clean(), self.enums.clean(), self.fns.clean(), + std::vec::concat(self.foreigns.clean()), self.mods.clean(), self.typedefs.clean(), self.statics.clean(), self.traits.clean(), self.impls.clean(), self.view_items.clean()]) @@ -203,6 +207,25 @@ impl Clean for ast::Attribute { } } +// This is a rough approximation that gets us what we want. +impl<'self> attr::AttrMetaMethods for &'self Attribute { + fn name(&self) -> @str { + match **self { + Word(ref n) | List(ref n, _) | NameValue(ref n, _) => + n.to_managed() + } + } + + fn value_str(&self) -> Option<@str> { + match **self { + NameValue(_, ref v) => Some(v.to_managed()), + _ => None, + } + } + fn meta_item_list<'a>(&'a self) -> Option<&'a [@ast::MetaItem]> { None } + fn name_str_pair(&self) -> Option<(@str, @str)> { None } +} + #[deriving(Clone, Encodable, Decodable)] pub struct TyParam { name: ~str, @@ -968,6 +991,41 @@ impl Clean for ast::path_list_ident { } } +impl Clean<~[Item]> for ast::foreign_mod { + fn clean(&self) -> ~[Item] { + self.items.clean() + } +} + +impl Clean for ast::foreign_item { + fn clean(&self) -> Item { + let inner = match self.node { + ast::foreign_item_fn(ref decl, ref generics) => { + ForeignFunctionItem(Function { + decl: decl.clean(), + generics: generics.clean(), + purity: ast::extern_fn, + }) + } + ast::foreign_item_static(ref ty, mutbl) => { + ForeignStaticItem(Static { + type_: ty.clean(), + mutability: if mutbl {Mutable} else {Immutable}, + expr: ~"", + }) + } + }; + Item { + name: Some(self.ident.clean()), + attrs: self.attrs.clean(), + source: self.span.clean(), + id: self.id, + visibility: self.vis.clean(), + inner: inner, + } + } +} + // Utilities trait ToSource { diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index a4e3f795498..835781907f3 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -30,6 +30,7 @@ pub struct Module { traits: ~[Trait], vis: ast::visibility, impls: ~[Impl], + foreigns: ~[ast::foreign_mod], view_items: ~[ast::view_item], } @@ -50,6 +51,7 @@ impl Module { traits : ~[], impls : ~[], view_items : ~[], + foreigns : ~[], } } } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 4f8c11d8285..3320842c046 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -28,6 +28,7 @@ use extra::json::ToJson; use extra::sort; use syntax::ast; +use syntax::attr; use clean; use doctree; @@ -521,6 +522,14 @@ impl Context { } } } + clean::StructItem(s) => { + let mut it = s.fields.move_iter(); + do self.recurse(name) |this| { + for item in it { + f(this, item); + } + } + } _ => {} } } @@ -532,19 +541,21 @@ impl Context { fn shortty(item: &clean::Item) -> &'static str { match item.inner { - clean::ModuleItem(*) => "mod", - clean::StructItem(*) => "struct", - clean::EnumItem(*) => "enum", - clean::FunctionItem(*) => "fn", - clean::TypedefItem(*) => "typedef", - clean::StaticItem(*) => "static", - clean::TraitItem(*) => "trait", - clean::ImplItem(*) => "impl", - clean::ViewItemItem(*) => "viewitem", - clean::TyMethodItem(*) => "tymethod", - clean::MethodItem(*) => "method", - clean::StructFieldItem(*) => "structfield", - clean::VariantItem(*) => "variant", + clean::ModuleItem(*) => "mod", + clean::StructItem(*) => "struct", + clean::EnumItem(*) => "enum", + clean::FunctionItem(*) => "fn", + clean::TypedefItem(*) => "typedef", + clean::StaticItem(*) => "static", + clean::TraitItem(*) => "trait", + clean::ImplItem(*) => "impl", + clean::ViewItemItem(*) => "viewitem", + clean::TyMethodItem(*) => "tymethod", + clean::MethodItem(*) => "method", + clean::StructFieldItem(*) => "structfield", + clean::VariantItem(*) => "variant", + clean::ForeignFunctionItem(*) => "ffi", + clean::ForeignStaticItem(*) => "ffs", } } @@ -558,6 +569,18 @@ impl<'self> Item<'self> { impl<'self> fmt::Default for Item<'self> { fn fmt(it: &Item<'self>, fmt: &mut fmt::Formatter) { + match attr::find_stability(it.item.attrs.iter()) { + Some(stability) => { + write!(fmt.buf, + "{lvl}", + lvl = stability.level.to_str(), + reason = match stability.text { + Some(s) => s, None => @"", + }); + } + None => {} + } + // Write the breadcrumb trail header for the top write!(fmt.buf, "

"); match it.item.inner { @@ -584,12 +607,15 @@ impl<'self> fmt::Default for Item<'self> { match it.item.inner { clean::ModuleItem(ref m) => item_module(fmt.buf, it.cx, it.item, m.items), - clean::FunctionItem(ref f) => item_function(fmt.buf, it.item, f), + clean::FunctionItem(ref f) | clean::ForeignFunctionItem(ref f) => + item_function(fmt.buf, it.item, f), clean::TraitItem(ref t) => item_trait(fmt.buf, it.item, t), clean::StructItem(ref s) => item_struct(fmt.buf, it.item, s), clean::EnumItem(ref e) => item_enum(fmt.buf, it.item, e), clean::TypedefItem(ref t) => item_typedef(fmt.buf, it.item, t), clean::VariantItem(*) => item_variant(fmt.buf, it.cx, it.item), + clean::StructFieldItem(*) => item_struct_field(fmt.buf, it.cx, + it.item), _ => {} } } @@ -663,6 +689,10 @@ fn item_module(w: &mut io::Writer, cx: &Context, (_, &clean::EnumItem(*)) => false, (&clean::StaticItem(*), _) => true, (_, &clean::StaticItem(*)) => false, + (&clean::ForeignFunctionItem(*), _) => true, + (_, &clean::ForeignFunctionItem(*)) => false, + (&clean::ForeignStaticItem(*), _) => true, + (_, &clean::ForeignStaticItem(*)) => false, (&clean::TraitItem(*), _) => true, (_, &clean::TraitItem(*)) => false, (&clean::FunctionItem(*), _) => true, @@ -690,27 +720,31 @@ fn item_module(w: &mut io::Writer, cx: &Context, } curty = myty; write!(w, "

{}

\n", match myitem.inner { - clean::ModuleItem(*) => "Modules", - clean::StructItem(*) => "Structs", - clean::EnumItem(*) => "Enums", - clean::FunctionItem(*) => "Functions", - clean::TypedefItem(*) => "Type Definitions", - clean::StaticItem(*) => "Statics", - clean::TraitItem(*) => "Traits", - clean::ImplItem(*) => "Implementations", - clean::ViewItemItem(*) => "Reexports", - clean::TyMethodItem(*) => "Type Methods", - clean::MethodItem(*) => "Methods", - clean::StructFieldItem(*) => "Struct Fields", - clean::VariantItem(*) => "Variants", + clean::ModuleItem(*) => "Modules", + clean::StructItem(*) => "Structs", + clean::EnumItem(*) => "Enums", + clean::FunctionItem(*) => "Functions", + clean::TypedefItem(*) => "Type Definitions", + clean::StaticItem(*) => "Statics", + clean::TraitItem(*) => "Traits", + clean::ImplItem(*) => "Implementations", + clean::ViewItemItem(*) => "Reexports", + clean::TyMethodItem(*) => "Type Methods", + clean::MethodItem(*) => "Methods", + clean::StructFieldItem(*) => "Struct Fields", + clean::VariantItem(*) => "Variants", + clean::ForeignFunctionItem(*) => "Foreign Functions", + clean::ForeignStaticItem(*) => "Foreign Statics", }); } match myitem.inner { - clean::StaticItem(ref s) => { + clean::StaticItem(ref s) | clean::ForeignStaticItem(ref s) => { struct Initializer<'self>(&'self str); impl<'self> fmt::Default for Initializer<'self> { fn fmt(s: &Initializer<'self>, f: &mut fmt::Formatter) { + if s.len() == 0 { return; } + write!(f.buf, " = "); let tag = if s.contains("\n") { "pre" } else { "code" }; write!(f.buf, "<{tag}>{}", s.as_slice(), tag=tag); @@ -719,7 +753,7 @@ fn item_module(w: &mut io::Writer, cx: &Context, write!(w, " - + ", @@ -980,11 +1014,12 @@ fn render_struct(w: &mut io::Writer, it: &clean::Item, for field in fields.iter() { match field.inner { clean::StructFieldItem(ref ty) => { - write!(w, " {}{}: {},\n{}", + write!(w, " {}{name}: \ + {},\n{}", VisSpace(field.visibility), - field.name.get_ref().as_slice(), ty.type_, - tab); + tab, + name = field.name.get_ref().as_slice()); } _ => unreachable!() } @@ -1170,3 +1205,12 @@ fn item_variant(w: &mut io::Writer, cx: &Context, it: &clean::Item) { *cx.current.last(), it.name.get_ref().as_slice()); } + +fn item_struct_field(w: &mut io::Writer, cx: &Context, it: &clean::Item) { + write!(w, "\ + \ + ", + *cx.current.last(), + it.name.get_ref().as_slice()); +} diff --git a/src/librustdoc/html/static/main.css b/src/librustdoc/html/static/main.css index 97f59798240..11ca7a09311 100644 --- a/src/librustdoc/html/static/main.css +++ b/src/librustdoc/html/static/main.css @@ -269,3 +269,18 @@ a { float: left; padding: 20px; } + +.stability { + border-left: 5px solid #000; + border-radius: 3px; + padding: 0 3px; + float: right; + background: #fff; + text-transform: lowercase; +} +.stability.Deprecated { border-color: #D60027; color: #880017; } +.stability.Experimental { border-color: #EC5315; color: #a53c0e; } +.stability.Unstable { border-color: #FFD700; color: #b39800; } +.stability.Stable { border-color: #AEC516; color: #7c8b10; } +.stability.Frozen { border-color: #009431; color: #007726; } +.stability.Locked { border-color: #0084B6; color: #00668c; } diff --git a/src/librustdoc/passes.rs b/src/librustdoc/passes.rs index 91e2b3bfcf1..bf35c93caae 100644 --- a/src/librustdoc/passes.rs +++ b/src/librustdoc/passes.rs @@ -10,6 +10,7 @@ use std::num; use std::uint; +use std::hashmap::HashSet; use syntax::ast; @@ -50,16 +51,18 @@ pub fn strip_hidden(crate: clean::Crate) -> plugins::PluginResult { /// Strip private items from the point of view of a crate or externally from a /// crate, specified by the `xcrate` flag. -pub fn strip_private(crate: clean::Crate) -> plugins::PluginResult { - struct Stripper; - impl fold::DocFolder for Stripper { +pub fn strip_private(mut crate: clean::Crate) -> plugins::PluginResult { + // This stripper collects all *retained* nodes. + struct Stripper<'self>(&'self mut HashSet); + impl<'self> fold::DocFolder for Stripper<'self> { fn fold_item(&mut self, i: Item) -> Option { match i.inner { // These items can all get re-exported clean::TypedefItem(*) | clean::StaticItem(*) | clean::StructItem(*) | clean::EnumItem(*) | clean::TraitItem(*) | clean::FunctionItem(*) | - clean::ViewItemItem(*) | clean::MethodItem(*) => { + clean::ViewItemItem(*) | clean::MethodItem(*) | + clean::ForeignFunctionItem(*) | clean::ForeignStaticItem(*) => { // XXX: re-exported items should get surfaced in the docs as // well (using the output of resolve analysis) if i.visibility != Some(ast::public) { @@ -97,6 +100,7 @@ pub fn strip_private(crate: clean::Crate) -> plugins::PluginResult { }; let i = if fastreturn { + self.insert(i.id); return Some(i); } else { self.fold_item_recur(i) @@ -108,15 +112,50 @@ pub fn strip_private(crate: clean::Crate) -> plugins::PluginResult { // emptied modules/impls have no need to exist clean::ModuleItem(ref m) if m.items.len() == 0 => None, clean::ImplItem(ref i) if i.methods.len() == 0 => None, - _ => Some(i), + _ => { + self.insert(i.id); + Some(i) + } } } None => None, } } } - let mut stripper = Stripper; - let crate = stripper.fold_crate(crate); + + // This stripper discards all private impls of traits + struct ImplStripper<'self>(&'self HashSet); + impl<'self> fold::DocFolder for ImplStripper<'self> { + fn fold_item(&mut self, i: Item) -> Option { + match i.inner { + clean::ImplItem(ref imp) => { + match imp.trait_ { + Some(clean::ResolvedPath{ id, _ }) => { + if !self.contains(&id) { + return None; + } + } + Some(*) | None => {} + } + } + _ => {} + } + self.fold_item_recur(i) + } + } + + let mut retained = HashSet::new(); + // First, strip all private items + { + let mut stripper = Stripper(&mut retained); + crate = stripper.fold_crate(crate); + } + + // Next, strip all private implementations of traits + { + let mut stripper = ImplStripper(&retained); + crate = stripper.fold_crate(crate); + } (crate, None) } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index c4b9b9efe56..8e89c07ef00 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -174,6 +174,9 @@ impl RustdocVisitor { }; om.impls.push(i); }, + ast::item_foreign_mod(ref fm) => { + om.foreigns.push(fm.clone()); + } _ => (), } } diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 295485d6f6e..47a7d0fbf9e 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -320,7 +320,7 @@ pub struct Stability { } /// The available stability levels. -#[deriving(Eq,Ord,Clone)] +#[deriving(Eq,Ord,Clone,ToStr)] pub enum StabilityLevel { Deprecated, Experimental, diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index cc5143977cf..6c905c252c1 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4219,9 +4219,9 @@ impl Parser { } // parse a function declaration from a foreign module - fn parse_item_foreign_fn(&self, attrs: ~[Attribute]) -> @foreign_item { + fn parse_item_foreign_fn(&self, vis: ast::visibility, + attrs: ~[Attribute]) -> @foreign_item { let lo = self.span.lo; - let vis = self.parse_visibility(); // Parse obsolete purity. let purity = self.parse_fn_purity(); @@ -4755,7 +4755,7 @@ impl Parser { if (self.is_keyword(keywords::Fn) || self.is_keyword(keywords::Pure) || self.is_keyword(keywords::Unsafe)) { // FOREIGN FUNCTION ITEM - let item = self.parse_item_foreign_fn(attrs); + let item = self.parse_item_foreign_fn(visibility, attrs); return iovi_foreign_item(item); } self.parse_macro_use_or_failure(attrs,macros_allowed,lo,visibility)
{}static {}: {} = {}{}static {}: {}{} {}