diff options
| author | bors <bors@rust-lang.org> | 2015-04-16 20:34:55 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2015-04-16 20:34:55 +0000 |
| commit | 1014ac44f6271a55249b0488a2ce1cc49deed338 (patch) | |
| tree | c827a7db48525741f0e91758c1df38082bee30aa | |
| parent | e9080ec39d9a44eb0773d648b348575b19f655e5 (diff) | |
| parent | 71c1b5b704ca3955e5ca22d77a0d59b55c9af4f1 (diff) | |
| download | rust-1014ac44f6271a55249b0488a2ce1cc49deed338.tar.gz rust-1014ac44f6271a55249b0488a2ce1cc49deed338.zip | |
Auto merge of #24396 - alexcrichton:rustdoc2, r=aturon
A few final improvements to rustdoc for 1.0: * Improve how rustdoc handles stability * Fix cross-crate macro source links * Improve experience of types inheriting methods through `Deref` Some more details can be found in the commits. [Preview](http://people.mozilla.org/~acrichton/doc/std/)
| -rw-r--r-- | src/librustdoc/clean/inline.rs | 49 | ||||
| -rw-r--r-- | src/librustdoc/clean/mod.rs | 101 | ||||
| -rw-r--r-- | src/librustdoc/core.rs | 9 | ||||
| -rw-r--r-- | src/librustdoc/doctree.rs | 1 | ||||
| -rw-r--r-- | src/librustdoc/html/format.rs | 134 | ||||
| -rw-r--r-- | src/librustdoc/html/render.rs | 360 | ||||
| -rw-r--r-- | src/librustdoc/html/static/main.css | 63 | ||||
| -rw-r--r-- | src/librustdoc/html/static/main.js | 3 | ||||
| -rw-r--r-- | src/librustdoc/lib.rs | 1 | ||||
| -rw-r--r-- | src/librustdoc/stability_summary.rs | 199 | ||||
| -rw-r--r-- | src/librustdoc/test.rs | 3 | ||||
| -rw-r--r-- | src/librustdoc/visit_ast.rs | 1 | ||||
| -rw-r--r-- | src/test/auxiliary/issue-19190-3.rs | 30 | ||||
| -rw-r--r-- | src/test/rustdoc/issue-19190-2.rs | 22 | ||||
| -rw-r--r-- | src/test/rustdoc/issue-19190-3.rs | 35 | ||||
| -rw-r--r-- | src/test/rustdoc/issue-19190.rs | 26 |
16 files changed, 510 insertions, 527 deletions
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index f14437b71b4..4fc86cf181b 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -218,15 +218,17 @@ fn build_type(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId) -> clean::ItemEn }) } -fn build_impls(cx: &DocContext, tcx: &ty::ctxt, - did: ast::DefId) -> Vec<clean::Item> { +pub fn build_impls(cx: &DocContext, tcx: &ty::ctxt, + did: ast::DefId) -> Vec<clean::Item> { ty::populate_implementations_for_type_if_necessary(tcx, did); let mut impls = Vec::new(); match tcx.inherent_impls.borrow().get(&did) { None => {} Some(i) => { - impls.extend(i.iter().map(|&did| { build_impl(cx, tcx, did) })); + for &did in i.iter() { + build_impl(cx, tcx, did, &mut impls); + } } } @@ -247,9 +249,9 @@ fn build_impls(cx: &DocContext, tcx: &ty::ctxt, fn populate_impls(cx: &DocContext, tcx: &ty::ctxt, def: decoder::DefLike, - impls: &mut Vec<Option<clean::Item>>) { + impls: &mut Vec<clean::Item>) { match def { - decoder::DlImpl(did) => impls.push(build_impl(cx, tcx, did)), + decoder::DlImpl(did) => build_impl(cx, tcx, did, impls), decoder::DlDef(def::DefMod(did)) => { csearch::each_child_of_item(&tcx.sess.cstore, did, @@ -262,14 +264,15 @@ fn build_impls(cx: &DocContext, tcx: &ty::ctxt, } } - impls.into_iter().filter_map(|a| a).collect() + return impls; } -fn build_impl(cx: &DocContext, - tcx: &ty::ctxt, - did: ast::DefId) -> Option<clean::Item> { +pub fn build_impl(cx: &DocContext, + tcx: &ty::ctxt, + did: ast::DefId, + ret: &mut Vec<clean::Item>) { if !cx.inlined.borrow_mut().as_mut().unwrap().insert(did) { - return None + return } let attrs = load_attrs(cx, tcx, did); @@ -278,13 +281,13 @@ fn build_impl(cx: &DocContext, // If this is an impl for a #[doc(hidden)] trait, be sure to not inline let trait_attrs = load_attrs(cx, tcx, t.def_id); if trait_attrs.iter().any(|a| is_doc_hidden(a)) { - return None + return } } // If this is a defaulted impl, then bail out early here if csearch::is_default_impl(&tcx.sess.cstore, did) { - return Some(clean::Item { + return ret.push(clean::Item { inner: clean::DefaultImplItem(clean::DefaultImpl { // FIXME: this should be decoded unsafety: ast::Unsafety::Normal, @@ -352,19 +355,25 @@ fn build_impl(cx: &DocContext, }) } } - }).collect(); + }).collect::<Vec<_>>(); let polarity = csearch::get_impl_polarity(tcx, did); let ty = ty::lookup_item_type(tcx, did); - return Some(clean::Item { + let trait_ = associated_trait.clean(cx).map(|bound| { + match bound { + clean::TraitBound(polyt, _) => polyt.trait_, + clean::RegionBound(..) => unreachable!(), + } + }); + if let Some(clean::ResolvedPath { did, .. }) = trait_ { + if Some(did) == cx.deref_trait_did.get() { + super::build_deref_target_impls(cx, &trait_items, ret); + } + } + ret.push(clean::Item { inner: clean::ImplItem(clean::Impl { unsafety: ast::Unsafety::Normal, // FIXME: this should be decoded derived: clean::detect_derived(&attrs), - trait_: associated_trait.clean(cx).map(|bound| { - match bound { - clean::TraitBound(polyt, _) => polyt.trait_, - clean::RegionBound(..) => unreachable!(), - } - }), + trait_: trait_, for_: ty.ty.clean(cx), generics: (&ty.generics, &predicates, subst::TypeSpace).clean(cx), items: trait_items, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 72702dc8d94..f7fbb67e08a 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -128,6 +128,10 @@ impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> { fn clean(&self, cx: &DocContext) -> Crate { use rustc::session::config::Input; + if let Some(t) = cx.tcx_opt() { + cx.deref_trait_did.set(t.lang_items.deref_trait()); + } + let mut externs = Vec::new(); cx.sess().cstore.iter_crate_data(|n, meta| { externs.push((n, meta.clean(cx))); @@ -313,6 +317,22 @@ impl Item { pub fn is_fn(&self) -> bool { match self.inner { FunctionItem(..) => true, _ => false } } + + pub fn stability_class(&self) -> String { + match self.stability { + Some(ref s) => { + let mut base = match s.level { + attr::Unstable => "unstable".to_string(), + attr::Stable => String::new(), + }; + if !s.deprecated_since.is_empty() { + base.push_str(" deprecated"); + } + base + } + _ => String::new(), + } + } } #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] @@ -371,7 +391,7 @@ impl Clean<Item> for doctree::Module { items.extend(self.statics.iter().map(|x| x.clean(cx))); items.extend(self.constants.iter().map(|x| x.clean(cx))); items.extend(self.traits.iter().map(|x| x.clean(cx))); - items.extend(self.impls.iter().map(|x| x.clean(cx))); + items.extend(self.impls.iter().flat_map(|x| x.clean(cx).into_iter())); items.extend(self.macros.iter().map(|x| x.clean(cx))); items.extend(self.def_traits.iter().map(|x| x.clean(cx))); @@ -1254,6 +1274,7 @@ impl Clean<Item> for ast::ImplItem { ast::MacImplItem(_) => { MacroItem(Macro { source: self.span.to_src(cx), + imported_from: None, }) } }; @@ -2169,9 +2190,21 @@ fn detect_derived<M: AttrMetaMethods>(attrs: &[M]) -> bool { attr::contains_name(attrs, "automatically_derived") } -impl Clean<Item> for doctree::Impl { - fn clean(&self, cx: &DocContext) -> Item { - Item { +impl Clean<Vec<Item>> for doctree::Impl { + fn clean(&self, cx: &DocContext) -> Vec<Item> { + let mut ret = Vec::new(); + let trait_ = self.trait_.clean(cx); + let items = self.items.clean(cx); + + // If this impl block is an implementation of the Deref trait, then we + // need to try inlining the target's inherent impl blocks as well. + if let Some(ResolvedPath { did, .. }) = trait_ { + if Some(did) == cx.deref_trait_did.get() { + build_deref_target_impls(cx, &items, &mut ret); + } + } + + ret.push(Item { name: None, attrs: self.attrs.clean(cx), source: self.whence.clean(cx), @@ -2181,12 +2214,66 @@ impl Clean<Item> for doctree::Impl { inner: ImplItem(Impl { unsafety: self.unsafety, generics: self.generics.clean(cx), - trait_: self.trait_.clean(cx), + trait_: trait_, for_: self.for_.clean(cx), - items: self.items.clean(cx), + items: items, derived: detect_derived(&self.attrs), polarity: Some(self.polarity.clean(cx)), }), + }); + return ret; + } +} + +fn build_deref_target_impls(cx: &DocContext, + items: &[Item], + ret: &mut Vec<Item>) { + let tcx = match cx.tcx_opt() { + Some(t) => t, + None => return, + }; + + for item in items { + let target = match item.inner { + TypedefItem(ref t) => &t.type_, + _ => continue, + }; + let primitive = match *target { + ResolvedPath { did, .. } if ast_util::is_local(did) => continue, + ResolvedPath { did, .. } => { + ret.extend(inline::build_impls(cx, tcx, did)); + continue + } + _ => match target.primitive_type() { + Some(prim) => prim, + None => continue, + } + }; + let did = match primitive { + Isize => tcx.lang_items.isize_impl(), + I8 => tcx.lang_items.i8_impl(), + I16 => tcx.lang_items.i16_impl(), + I32 => tcx.lang_items.i32_impl(), + I64 => tcx.lang_items.i64_impl(), + Usize => tcx.lang_items.usize_impl(), + U8 => tcx.lang_items.u8_impl(), + U16 => tcx.lang_items.u16_impl(), + U32 => tcx.lang_items.u32_impl(), + U64 => tcx.lang_items.u64_impl(), + F32 => tcx.lang_items.f32_impl(), + F64 => tcx.lang_items.f64_impl(), + Char => tcx.lang_items.char_impl(), + Bool => None, + Str => tcx.lang_items.str_impl(), + Slice => tcx.lang_items.slice_impl(), + Array => tcx.lang_items.slice_impl(), + PrimitiveTuple => None, + PrimitiveRawPointer => tcx.lang_items.const_ptr_impl(), + }; + if let Some(did) = did { + if !ast_util::is_local(did) { + inline::build_impl(cx, tcx, did, ret); + } } } } @@ -2541,6 +2628,7 @@ fn resolve_def(cx: &DocContext, id: ast::NodeId) -> Option<ast::DefId> { #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct Macro { pub source: String, + pub imported_from: Option<String>, } impl Clean<Item> for doctree::Macro { @@ -2554,6 +2642,7 @@ impl Clean<Item> for doctree::Macro { def_id: ast_util::local_def(self.id), inner: MacroItem(Macro { source: self.whence.to_src(cx), + imported_from: self.imported_from.clean(cx), }), } } diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index a637ba9f297..1b74123c4ad 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -20,7 +20,7 @@ use rustc_resolve as resolve; use syntax::{ast, ast_map, codemap, diagnostic}; -use std::cell::RefCell; +use std::cell::{RefCell, Cell}; use std::collections::{HashMap, HashSet}; use visit_ast::RustdocVisitor; @@ -48,6 +48,7 @@ pub struct DocContext<'tcx> { pub external_typarams: RefCell<Option<HashMap<ast::DefId, String>>>, pub inlined: RefCell<Option<HashSet<ast::DefId>>>, pub populated_crate_impls: RefCell<HashSet<ast::CrateNum>>, + pub deref_trait_did: Cell<Option<ast::DefId>>, } impl<'tcx> DocContext<'tcx> { @@ -77,6 +78,7 @@ pub struct CrateAnalysis { pub external_paths: ExternalPaths, pub external_typarams: RefCell<Option<HashMap<ast::DefId, String>>>, pub inlined: RefCell<Option<HashSet<ast::DefId>>>, + pub deref_trait_did: Option<ast::DefId>, } pub type Externs = HashMap<String, Vec<String>>; @@ -147,15 +149,17 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec<String>, externs: Externs, external_paths: RefCell::new(Some(HashMap::new())), inlined: RefCell::new(Some(HashSet::new())), populated_crate_impls: RefCell::new(HashSet::new()), + deref_trait_did: Cell::new(None), }; debug!("crate: {:?}", ctxt.krate); - let analysis = CrateAnalysis { + let mut analysis = CrateAnalysis { exported_items: exported_items, public_items: public_items, external_paths: RefCell::new(None), external_typarams: RefCell::new(None), inlined: RefCell::new(None), + deref_trait_did: None, }; let krate = { @@ -170,5 +174,6 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec<String>, externs: Externs, *analysis.external_typarams.borrow_mut() = map; let map = ctxt.inlined.borrow_mut().take(); *analysis.inlined.borrow_mut() = map; + analysis.deref_trait_did = ctxt.deref_trait_did.get(); (krate, analysis) } diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index 862bca1b813..8fa92304d24 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -214,6 +214,7 @@ pub struct Macro { pub attrs: Vec<ast::Attribute>, pub whence: Span, pub stab: Option<attr::Stability>, + pub imported_from: Option<Ident>, } pub struct ExternCrate { diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index d2dccca362e..bb53d532f52 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -23,10 +23,8 @@ use syntax::ast; use syntax::ast_util; use clean; -use stability_summary::ModuleSummary; use html::item_type::ItemType; use html::render; -use html::escape::Escape; use html::render::{cache, CURRENT_LOCATION_KEY}; /// Helper to render an optional visibility with a space after it (if the @@ -45,10 +43,6 @@ pub struct MutableSpace(pub clean::Mutability); /// Similar to VisSpace, but used for mutability #[derive(Copy, Clone)] pub struct RawMutableSpace(pub clean::Mutability); -/// Wrapper struct for properly emitting the stability level. -pub struct Stability<'a>(pub &'a Option<clean::Stability>); -/// Wrapper struct for emitting the stability level concisely. -pub struct ConciseStability<'a>(pub &'a Option<clean::Stability>); /// Wrapper struct for emitting a where clause from Generics. pub struct WhereClause<'a>(pub &'a clean::Generics); /// Wrapper struct for emitting type parameter bounds. @@ -294,9 +288,9 @@ pub fn href(did: ast::DefId) -> Option<(String, ItemType, Vec<String>)> { repeat("../").take(loc.len()).collect::<String>() } else { match cache.extern_locations[&did.krate] { - render::Remote(ref s) => s.to_string(), - render::Local => repeat("../").take(loc.len()).collect::<String>(), - render::Unknown => return None, + (_, render::Remote(ref s)) => s.to_string(), + (_, render::Local) => repeat("../").take(loc.len()).collect(), + (_, render::Unknown) => return None, } }; for component in &fqp[..fqp.len() - 1] { @@ -385,12 +379,12 @@ fn primitive_link(f: &mut fmt::Formatter, node: ast::CRATE_NODE_ID, }]; let loc = match m.extern_locations[&cnum] { - render::Remote(ref s) => Some(s.to_string()), - render::Local => { + (_, render::Remote(ref s)) => Some(s.to_string()), + (_, render::Local) => { let len = CURRENT_LOCATION_KEY.with(|s| s.borrow().len()); Some(repeat("../").take(len).collect::<String>()) } - render::Unknown => None, + (_, render::Unknown) => None, }; match loc { Some(root) => { @@ -702,119 +696,3 @@ impl fmt::Display for AbiSpace { } } } - -impl<'a> fmt::Display for Stability<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let Stability(stab) = *self; - match *stab { - Some(ref stability) => { - let lvl = if stability.deprecated_since.is_empty() { - format!("{}", stability.level) - } else { - "Deprecated".to_string() - }; - write!(f, "<a class='stability {lvl}' title='{reason}'>{lvl}</a>", - lvl = Escape(&*lvl), - reason = Escape(&*stability.reason)) - } - None => Ok(()) - } - } -} - -impl<'a> fmt::Display for ConciseStability<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let ConciseStability(stab) = *self; - match *stab { - Some(ref stability) => { - let lvl = if stability.deprecated_since.is_empty() { - format!("{}", stability.level) - } else { - "Deprecated".to_string() - }; - write!(f, "<a class='stability {lvl}' title='{lvl}{colon}{reason}'></a>", - lvl = Escape(&*lvl), - colon = if !stability.reason.is_empty() { ": " } else { "" }, - reason = Escape(&*stability.reason)) - } - None => { - write!(f, "<a class='stability Unmarked' title='No stability level'></a>") - } - } - } -} - -impl fmt::Display for ModuleSummary { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fn fmt_inner<'a>(f: &mut fmt::Formatter, - context: &mut Vec<&'a str>, - m: &'a ModuleSummary) - -> fmt::Result { - let cnt = m.counts; - let tot = cnt.total(); - if tot == 0 { return Ok(()) } - - context.push(&m.name); - let path = context.connect("::"); - - try!(write!(f, "<tr>")); - try!(write!(f, "<td><a href='{}'>{}</a></td>", { - let mut url = context[1..].to_vec(); - url.push("index.html"); - url.connect("/") - }, - path)); - try!(write!(f, "<td class='summary-column'>")); - try!(write!(f, "<span class='summary Stable' \ - style='width: {:.4}%; display: inline-block'> </span>", - (100 * cnt.stable) as f64/tot as f64)); - try!(write!(f, "<span class='summary Unstable' \ - style='width: {:.4}%; display: inline-block'> </span>", - (100 * cnt.unstable) as f64/tot as f64)); - try!(write!(f, "<span class='summary Deprecated' \ - style='width: {:.4}%; display: inline-block'> </span>", - (100 * cnt.deprecated) as f64/tot as f64)); - try!(write!(f, "<span class='summary Unmarked' \ - style='width: {:.4}%; display: inline-block'> </span>", - (100 * cnt.unmarked) as f64/tot as f64)); - try!(write!(f, "</td></tr>")); - - for submodule in &m.submodules { - try!(fmt_inner(f, context, submodule)); - } - context.pop(); - Ok(()) - } - - let mut context = Vec::new(); - - let tot = self.counts.total(); - let (stable, unstable, deprecated, unmarked) = if tot == 0 { - (0, 0, 0, 0) - } else { - ((100 * self.counts.stable)/tot, - (100 * self.counts.unstable)/tot, - (100 * self.counts.deprecated)/tot, - (100 * self.counts.unmarked)/tot) - }; - - try!(write!(f, -r"<h1 class='fqn'>Stability dashboard: crate <a class='mod' href='index.html'>{name}</a></h1> -This dashboard summarizes the stability levels for all of the public modules of -the crate, according to the total number of items at each level in the module and -its children (percentages total for {name}): -<blockquote> -<a class='stability Stable'></a> stable ({}%),<br/> -<a class='stability Unstable'></a> unstable ({}%),<br/> -<a class='stability Deprecated'></a> deprecated ({}%),<br/> -<a class='stability Unmarked'></a> unmarked ({}%) -</blockquote> -The counts do not include methods or trait -implementations that are visible only through a re-exported type.", -stable, unstable, deprecated, unmarked, -name=self.name)); - try!(write!(f, "<table>")); - try!(fmt_inner(f, &mut context, self)); - write!(f, "</table>") - } -} diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 5f4a3e74b65..f87a86eb3a6 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -56,19 +56,20 @@ use serialize::json::ToJson; use syntax::abi; use syntax::ast; use syntax::ast_util; +use syntax::attr; use rustc::util::nodemap::NodeSet; use clean; use doctree; use fold::DocFolder; -use html::format::{VisSpace, Method, UnsafetySpace, MutableSpace, Stability}; -use html::format::{ConciseStability, TyParamBounds, WhereClause, href, AbiSpace}; +use html::escape::Escape; +use html::format::{TyParamBounds, WhereClause, href, AbiSpace}; +use html::format::{VisSpace, Method, UnsafetySpace, MutableSpace}; use html::highlight; use html::item_type::ItemType; use html::layout; use html::markdown::Markdown; use html::markdown; -use stability_summary; /// A pair of name and its optional document. pub type NameDoc = (String, Option<String>); @@ -192,7 +193,7 @@ pub struct Cache { pub implementors: HashMap<ast::DefId, Vec<Implementor>>, /// Cache of where external crate documentation can be found. - pub extern_locations: HashMap<ast::CrateNum, ExternalLocation>, + pub extern_locations: HashMap<ast::CrateNum, (String, ExternalLocation)>, /// Cache of where documentation for primitives can be found. pub primitive_locations: HashMap<clean::PrimitiveType, ast::CrateNum>, @@ -208,6 +209,7 @@ pub struct Cache { privmod: bool, remove_priv: bool, public_items: NodeSet, + deref_trait_did: Option<ast::DefId>, // In rare case where a structure is defined in one module but implemented // in another, if the implementing module is parsed before defining module, @@ -395,6 +397,7 @@ pub fn run(mut krate: clean::Crate, public_items: public_items, orphan_methods: Vec::new(), traits: mem::replace(&mut krate.external_traits, HashMap::new()), + deref_trait_did: analysis.as_ref().and_then(|a| a.deref_trait_did), typarams: analysis.as_ref().map(|a| { a.external_typarams.borrow_mut().take().unwrap() }).unwrap_or(HashMap::new()), @@ -402,12 +405,11 @@ pub fn run(mut krate: clean::Crate, a.inlined.borrow_mut().take().unwrap() }).unwrap_or(HashSet::new()), }; - cache.stack.push(krate.name.clone()); - krate = cache.fold_crate(krate); // Cache where all our extern crates are located for &(n, ref e) in &krate.externs { - cache.extern_locations.insert(n, extern_location(e, &cx.dst)); + cache.extern_locations.insert(n, (e.name.clone(), + extern_location(e, &cx.dst))); let did = ast::DefId { krate: n, node: ast::CRATE_NODE_ID }; cache.paths.insert(did, (vec![e.name.to_string()], ItemType::Module)); } @@ -425,6 +427,9 @@ pub fn run(mut krate: clean::Crate, cache.primitive_locations.insert(prim, ast::LOCAL_CRATE); } + cache.stack.push(krate.name.clone()); + krate = cache.fold_crate(krate); + // Build our search index let index = try!(build_index(&krate, &mut cache)); @@ -437,11 +442,8 @@ pub fn run(mut krate: clean::Crate, try!(write_shared(&cx, &krate, &*cache, index)); let krate = try!(render_sources(&mut cx, krate)); - // Crawl the crate, building a summary of the stability levels. - let summary = stability_summary::build(&krate); - // And finally render the whole crate's documentation - cx.krate(krate, summary) + cx.krate(krate) } fn build_index(krate: &clean::Crate, cache: &mut Cache) -> io::Result<String> { @@ -645,8 +647,7 @@ fn write_shared(cx: &Context, // going on). If they're in different crates then the crate defining // the trait will be interested in our implementation. if imp.def_id.krate == did.krate { continue } - try!(write!(&mut f, r#""{}impl{} {}{} for {}","#, - ConciseStability(&imp.stability), + try!(write!(&mut f, r#""impl{} {}{} for {}","#, imp.generics, if imp.polarity == Some(clean::ImplPolarity::Negative) { "!" } else { "" }, imp.trait_, imp.for_)); @@ -1071,8 +1072,11 @@ impl DocFolder for Cache { } ref t => { - t.primitive_type().map(|p| { - ast_util::local_def(p.to_node_id()) + t.primitive_type().and_then(|t| { + self.primitive_locations.get(&t).map(|n| { + let id = t.to_node_id(); + ast::DefId { krate: *n, node: id } + }) }) } }; @@ -1143,38 +1147,13 @@ impl Context { /// /// This currently isn't parallelized, but it'd be pretty easy to add /// parallelization to this function. - fn krate(mut self, mut krate: clean::Crate, - stability: stability_summary::ModuleSummary) -> io::Result<()> { + fn krate(self, mut krate: clean::Crate) -> io::Result<()> { let mut item = match krate.module.take() { Some(i) => i, None => return Ok(()) }; item.name = Some(krate.name); - // render stability dashboard - try!(self.recurse(stability.name.clone(), |this| { - let json_dst = &this.dst.join("stability.json"); - let mut json_out = BufWriter::new(try!(File::create(json_dst))); - try!(write!(&mut json_out, "{}", json::as_json(&stability))); - - let mut title = stability.name.clone(); - title.push_str(" - Stability dashboard"); - let desc = format!("API stability overview for the Rust `{}` crate.", - this.layout.krate); - let page = layout::Page { - ty: "mod", - root_path: &this.root_path, - title: &title, - description: &desc, - keywords: get_basic_keywords(), - }; - let html_dst = &this.dst.join("stability.html"); - let mut html_out = BufWriter::new(try!(File::create(html_dst))); - layout::render(&mut html_out, &this.layout, &page, - &Sidebar{ cx: this, item: &item }, - &stability) - })); - // render the crate documentation let mut work = vec!((self, item)); loop { @@ -1371,22 +1350,43 @@ impl<'a> Item<'a> { /// may happen, for example, with externally inlined items where the source /// of their crate documentation isn't known. fn href(&self, cx: &Context) -> Option<String> { + 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) + }; + + // First check to see if this is an imported macro source. In this case + // we need to handle it specially as cross-crate inlined macros have... + // odd locations! + let imported_macro_from = match self.item.inner { + clean::MacroItem(ref m) => m.imported_from.as_ref(), + _ => None, + }; + if let Some(krate) = imported_macro_from { + let cache = cache(); + let root = cache.extern_locations.values().find(|&&(ref n, _)| { + *krate == *n + }).map(|l| &l.1); + let root = match root { + Some(&Remote(ref s)) => s.to_string(), + Some(&Local) => self.cx.root_path.clone(), + None | Some(&Unknown) => return None, + }; + Some(format!("{root}/{krate}/macro.{name}.html?gotomacrosrc=1", + root = root, + krate = krate, + name = self.item.name.as_ref().unwrap())) + // 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) { + } else if ast_util::is_local(self.item.def_id) { let mut path = Vec::new(); clean_srcpath(&cx.src_root, Path::new(&self.item.source.filename), true, |component| { path.push(component.to_string()); }); - 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, @@ -1408,9 +1408,9 @@ impl<'a> Item<'a> { let cache = cache(); let path = &cache.external_paths[&self.item.def_id]; let root = match cache.extern_locations[&self.item.def_id.krate] { - Remote(ref s) => s.to_string(), - Local => self.cx.root_path.clone(), - Unknown => return None, + (_, Remote(ref s)) => s.to_string(), + (_, Local) => self.cx.root_path.clone(), + (_, Unknown) => return None, }; Some(format!("{root}{path}/{file}?gotosrc={goto}", root = root, @@ -1456,21 +1456,8 @@ impl<'a> fmt::Display for Item<'a> { try!(write!(fmt, "<a class='{}' href=''>{}</a>", shortty(self.item), self.item.name.as_ref().unwrap())); - // Write stability level - try!(write!(fmt, "<wbr>{}", Stability(&self.item.stability))); - try!(write!(fmt, "</span>")); // in-band - // Links to out-of-band information, i.e. src and stability dashboard try!(write!(fmt, "<span class='out-of-band'>")); - - // Write stability dashboard link - match self.item.inner { - clean::ModuleItem(ref m) if m.is_crate => { - try!(write!(fmt, "<a href='stability.html'>[stability]</a> ")); - } - _ => {} - }; - try!(write!(fmt, r##"<span id='render-detail'> <a id="collapse-all" href="#">[-]</a> <a id="expand-all" href="#">[+]</a> @@ -1485,7 +1472,8 @@ impl<'a> fmt::Display for Item<'a> { if self.cx.include_sources && !is_primitive { match self.href(self.cx) { Some(l) => { - try!(write!(fmt, "<a id='src-{}' href='{}'>[src]</a>", + try!(write!(fmt, "<a id='src-{}' class='srclink' \ + href='{}'>[src]</a>", self.item.def_id.node, l)); } None => {} @@ -1554,11 +1542,11 @@ fn plain_summary_line(s: Option<&str>) -> String { } fn document(w: &mut fmt::Formatter, item: &clean::Item) -> fmt::Result { - match item.doc_value() { - Some(s) => { - try!(write!(w, "<div class='docblock'>{}</div>", Markdown(s))); - } - None => {} + if let Some(s) = short_stability(item, true) { + try!(write!(w, "<div class='stability'>{}</div>", s)); + } + if let Some(s) = item.doc_value() { + try!(write!(w, "<div class='docblock'>{}</div>", Markdown(s))); } Ok(()) } @@ -1593,10 +1581,17 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, fn cmp(i1: &clean::Item, i2: &clean::Item, idx1: usize, idx2: usize) -> Ordering { let ty1 = shortty(i1); let ty2 = shortty(i2); - if ty1 == ty2 { - return i1.name.cmp(&i2.name); + if ty1 != ty2 { + return (reorder(ty1), idx1).cmp(&(reorder(ty2), idx2)) + } + let s1 = i1.stability.as_ref().map(|s| s.level); + let s2 = i2.stability.as_ref().map(|s| s.level); + match (s1, s2) { + (Some(attr::Unstable), Some(attr::Stable)) => return Ordering::Greater, + (Some(attr::Stable), Some(attr::Unstable)) => return Ordering::Less, + _ => {} } - (reorder(ty1), idx1).cmp(&(reorder(ty2), idx2)) + i1.name.cmp(&i2.name) } indices.sort_by(|&i1, &i2| cmp(&items[i1], &items[i2], i1, i2)); @@ -1665,19 +1660,27 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, _ => { if myitem.name.is_none() { continue } + let stab_docs = if let Some(s) = short_stability(myitem, false) { + format!("[{}]", s) + } else { + String::new() + }; try!(write!(w, " - <tr> - <td>{stab}<a class='{class}' href='{href}' - title='{title}'>{}</a></td> - <td class='docblock short'>{}</td> + <tr class='{stab} module-item'> + <td><a class='{class}' href='{href}' + title='{title}'>{name}</a></td> + <td class='docblock short'> + {stab_docs} {docs} + </td> </tr> ", - *myitem.name.as_ref().unwrap(), - Markdown(&shorter(myitem.doc_value())[..]), + name = *myitem.name.as_ref().unwrap(), + stab_docs = stab_docs, + docs = Markdown(&shorter(myitem.doc_value())), class = shortty(myitem), + stab = myitem.stability_class(), href = item_path(myitem), - title = full_path(cx, myitem), - stab = ConciseStability(&myitem.stability))); + title = full_path(cx, myitem))); } } } @@ -1685,6 +1688,30 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, write!(w, "</table>") } +fn short_stability(item: &clean::Item, show_reason: bool) -> Option<String> { + item.stability.as_ref().and_then(|stab| { + let reason = if show_reason && !stab.reason.is_empty() { + format!(": {}", stab.reason) + } else { + String::new() + }; + let text = if !stab.deprecated_since.is_empty() { + let since = if show_reason { + format!(" since {}", Escape(&stab.deprecated_since)) + } else { + String::new() + }; + format!("Deprecated{}{}", since, Markdown(&reason)) + } else if stab.level == attr::Unstable { + format!("Unstable{}", Markdown(&reason)) + } else { + return None + }; + Some(format!("<em class='stab {}'>{}</em>", + item.stability_class(), text)) + }) +} + struct Initializer<'a>(&'a str); impl<'a> fmt::Display for Initializer<'a> { @@ -1800,10 +1827,10 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, fn trait_item(w: &mut fmt::Formatter, m: &clean::Item) -> fmt::Result { - try!(write!(w, "<h3 id='{}.{}' class='method'>{}<code>", - shortty(m), - *m.name.as_ref().unwrap(), - ConciseStability(&m.stability))); + try!(write!(w, "<h3 id='{ty}.{name}' class='method stab {stab}'><code>", + ty = shortty(m), + name = *m.name.as_ref().unwrap(), + stab = m.stability_class())); try!(render_method(w, m, MethodLink::Anchor)); try!(write!(w, "</code></h3>")); try!(document(w, m)); @@ -1844,7 +1871,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, } // If there are methods directly on this trait object, render them here. - try!(render_methods(w, it)); + try!(render_methods(w, it.def_id, MethodRender::All)); let cache = cache(); try!(write!(w, " @@ -1854,8 +1881,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, match cache.implementors.get(&it.def_id) { Some(implementors) => { for i in implementors { - try!(writeln!(w, "<li>{}<code>impl{} {} for {}{}</code></li>", - ConciseStability(&i.stability), + try!(writeln!(w, "<li><code>impl{} {} for {}{}</code></li>", i.generics, i.trait_, i.for_, WhereClause(&i.generics))); } } @@ -1964,9 +1990,10 @@ fn item_struct(w: &mut fmt::Formatter, it: &clean::Item, if fields.peek().is_some() { try!(write!(w, "<h2 class='fields'>Fields</h2>\n<table>")); for field in fields { - try!(write!(w, "<tr><td id='structfield.{name}'>\ - {stab}<code>{name}</code></td><td>", - stab = ConciseStability(&field.stability), + try!(write!(w, "<tr class='stab {stab}'> + <td id='structfield.{name}'>\ + <code>{name}</code></td><td>", + stab = field.stability_class(), name = field.name.as_ref().unwrap())); try!(document(w, field)); try!(write!(w, "</td></tr>")); @@ -1974,7 +2001,7 @@ fn item_struct(w: &mut fmt::Formatter, it: &clean::Item, try!(write!(w, "</table>")); } } - render_methods(w, it) + render_methods(w, it.def_id, MethodRender::All) } fn item_enum(w: &mut fmt::Formatter, it: &clean::Item, @@ -2034,8 +2061,7 @@ fn item_enum(w: &mut fmt::Formatter, it: &clean::Item, if !e.variants.is_empty() { try!(write!(w, "<h2 class='variants'>Variants</h2>\n<table>")); for variant in &e.variants { - try!(write!(w, "<tr><td id='variant.{name}'>{stab}<code>{name}</code></td><td>", - stab = ConciseStability(&variant.stability), + try!(write!(w, "<tr><td id='variant.{name}'><code>{name}</code></td><td>", name = variant.name.as_ref().unwrap())); try!(document(w, variant)); match variant.inner { @@ -2074,7 +2100,7 @@ fn item_enum(w: &mut fmt::Formatter, it: &clean::Item, try!(write!(w, "</table>")); } - try!(render_methods(w, it)); + try!(render_methods(w, it.def_id, MethodRender::All)); Ok(()) } @@ -2163,27 +2189,61 @@ enum MethodLink { GotoSource(ast::DefId), } -fn render_methods(w: &mut fmt::Formatter, it: &clean::Item) -> fmt::Result { - let v = match cache().impls.get(&it.def_id) { - Some(v) => v.clone(), +enum MethodRender<'a> { + All, + DerefFor { trait_: &'a clean::Type, type_: &'a clean::Type }, +} + +fn render_methods(w: &mut fmt::Formatter, + it: ast::DefId, + what: MethodRender) -> fmt::Result { + let c = cache(); + let v = match c.impls.get(&it) { + Some(v) => v, None => return Ok(()), }; - let (non_trait, traits): (Vec<_>, _) = v.into_iter() - .partition(|i| i.impl_.trait_.is_none()); + let (non_trait, traits): (Vec<_>, _) = v.iter().partition(|i| { + i.impl_.trait_.is_none() + }); if !non_trait.is_empty() { - try!(write!(w, "<h2 id='methods'>Methods</h2>")); + let render_header = match what { + MethodRender::All => { + try!(write!(w, "<h2 id='methods'>Methods</h2>")); + true + } + MethodRender::DerefFor { trait_, type_ } => { + try!(write!(w, "<h2 id='deref-methods'>Methods from \ + {}<Target={}></h2>", trait_, type_)); + false + } + }; for i in &non_trait { - try!(render_impl(w, i, MethodLink::Anchor)); + try!(render_impl(w, i, MethodLink::Anchor, render_header)); } } + if let MethodRender::DerefFor { .. } = what { + return Ok(()) + } if !traits.is_empty() { + let deref_impl = traits.iter().find(|t| { + match *t.impl_.trait_.as_ref().unwrap() { + clean::ResolvedPath { did, .. } => { + Some(did) == c.deref_trait_did + } + _ => false + } + }); + if let Some(impl_) = deref_impl { + try!(render_deref_methods(w, impl_)); + } try!(write!(w, "<h2 id='implementations'>Trait \ Implementations</h2>")); - let (derived, manual): (Vec<_>, _) = traits.into_iter() - .partition(|i| i.impl_.derived); + let (derived, manual): (Vec<_>, _) = traits.iter().partition(|i| { + i.impl_.derived + }); for i in &manual { let did = i.trait_did().unwrap(); - try!(render_impl(w, i, MethodLink::GotoSource(did))); + try!(render_impl(w, i, MethodLink::GotoSource(did), true)); } if !derived.is_empty() { try!(write!(w, "<h3 id='derived_implementations'>\ @@ -2191,73 +2251,92 @@ fn render_methods(w: &mut fmt::Formatter, it: &clean::Item) -> fmt::Result { </h3>")); for i in &derived { let did = i.trait_did().unwrap(); - try!(render_impl(w, i, MethodLink::GotoSource(did))); + try!(render_impl(w, i, MethodLink::GotoSource(did), true)); } } } Ok(()) } -fn render_impl(w: &mut fmt::Formatter, i: &Impl, link: MethodLink) - -> fmt::Result { - try!(write!(w, "<h3 class='impl'>{}<code>impl{} ", - ConciseStability(&i.stability), - i.impl_.generics)); - if let Some(clean::ImplPolarity::Negative) = i.impl_.polarity { - try!(write!(w, "!")); - } - if let Some(ref ty) = i.impl_.trait_ { - try!(write!(w, "{} for ", *ty)); +fn render_deref_methods(w: &mut fmt::Formatter, impl_: &Impl) -> fmt::Result { + let deref_type = impl_.impl_.trait_.as_ref().unwrap(); + let target = impl_.impl_.items.iter().filter_map(|item| { + match item.inner { + clean::TypedefItem(ref t) => Some(&t.type_), + _ => None, + } + }).next().unwrap(); + let what = MethodRender::DerefFor { trait_: deref_type, type_: target }; + match *target { + clean::ResolvedPath { did, .. } => render_methods(w, did, what), + _ => { + if let Some(prim) = target.primitive_type() { + if let Some(c) = cache().primitive_locations.get(&prim) { + let did = ast::DefId { krate: *c, node: prim.to_node_id() }; + try!(render_methods(w, did, what)); + } + } + Ok(()) + } } - try!(write!(w, "{}{}</code></h3>", i.impl_.for_, - WhereClause(&i.impl_.generics))); - if let Some(ref dox) = i.dox { - try!(write!(w, "<div class='docblock'>{}</div>", Markdown(dox))); +} + +fn render_impl(w: &mut fmt::Formatter, i: &Impl, link: MethodLink, + render_header: bool) -> fmt::Result { + if render_header { + try!(write!(w, "<h3 class='impl'><code>impl{} ", + i.impl_.generics)); + if let Some(clean::ImplPolarity::Negative) = i.impl_.polarity { + try!(write!(w, "!")); + } + if let Some(ref ty) = i.impl_.trait_ { + try!(write!(w, "{} for ", *ty)); + } + try!(write!(w, "{}{}</code></h3>", i.impl_.for_, + WhereClause(&i.impl_.generics))); + if let Some(ref dox) = i.dox { + try!(write!(w, "<div class='docblock'>{}</div>", Markdown(dox))); + } } fn doctraititem(w: &mut fmt::Formatter, item: &clean::Item, - dox: bool, link: MethodLink) -> fmt::Result { + link: MethodLink) -> fmt::Result { match item.inner { clean::MethodItem(..) | clean::TyMethodItem(..) => { - try!(write!(w, "<h4 id='method.{}' class='{}'>{}<code>", + try!(write!(w, "<h4 id='method.{}' class='{}'><code>", *item.name.as_ref().unwrap(), - shortty(item), - ConciseStability(&item.stability))); + shortty(item))); try!(render_method(w, item, link)); try!(write!(w, "</code></h4>\n")); } clean::TypedefItem(ref tydef) => { let name = item.name.as_ref().unwrap(); - try!(write!(w, "<h4 id='assoc_type.{}' class='{}'>{}<code>", + try!(write!(w, "<h4 id='assoc_type.{}' class='{}'><code>", *name, - shortty(item), - ConciseStability(&item.stability))); + shortty(item))); try!(write!(w, "type {} = {}", name, tydef.type_)); try!(write!(w, "</code></h4>\n")); } clean::AssociatedTypeItem(ref bounds, ref default) => { let name = item.name.as_ref().unwrap(); - try!(write!(w, "<h4 id='assoc_type.{}' class='{}'>{}<code>", + try!(write!(w, "<h4 id='assoc_type.{}' class='{}'><code>", *name, - shortty(item), - ConciseStability(&item.stability))); + shortty(item))); try!(assoc_type(w, item, bounds, default)); try!(write!(w, "</code></h4>\n")); } _ => panic!("can't make docs for trait item with name {:?}", item.name) } - match item.doc_value() { - Some(s) if dox => { - try!(write!(w, "<div class='docblock'>{}</div>", Markdown(s))); - Ok(()) - } - Some(..) | None => Ok(()) + if let MethodLink::Anchor = link { + document(w, item) + } else { + Ok(()) } } try!(write!(w, "<div class='impl-items'>")); for trait_item in i.impl_.items.iter() { - try!(doctraititem(w, trait_item, true, link)); + try!(doctraititem(w, trait_item, link)); } fn render_default_methods(w: &mut fmt::Formatter, @@ -2271,8 +2350,7 @@ fn render_impl(w: &mut fmt::Formatter, i: &Impl, link: MethodLink) None => {} } - try!(doctraititem(w, trait_item, false, - MethodLink::GotoSource(did))); + try!(doctraititem(w, trait_item, MethodLink::GotoSource(did))); } Ok(()) } @@ -2380,7 +2458,7 @@ fn item_primitive(w: &mut fmt::Formatter, it: &clean::Item, _p: &clean::PrimitiveType) -> fmt::Result { try!(document(w, it)); - render_methods(w, it) + render_methods(w, it.def_id, MethodRender::All) } fn get_basic_keywords() -> &'static str { diff --git a/src/librustdoc/html/static/main.css b/src/librustdoc/html/static/main.css index 2af20ce59da..c94dbc15103 100644 --- a/src/librustdoc/html/static/main.css +++ b/src/librustdoc/html/static/main.css @@ -245,6 +245,10 @@ nav.sub { .content .highlighted.tymethod { background-color: #c6afb3; } .content .highlighted.type { background-color: #c6afb3; } +.docblock.short p { + display: inline; +} + .docblock.short.nowrap { display: block; overflow: hidden; @@ -337,11 +341,16 @@ nav.sub { /* Shift "where ..." part of method definition down a line */ .content .method .where { display: block; } /* Bit of whitespace to indent it */ -.content .method .where::before { content: ' '; } +.content .method .where::before { content: ' '; } -.content .methods .docblock { margin-left: 40px; } +.content .methods > div { margin-left: 40px; } -.content .impl-items .docblock { margin-left: 40px; } +.content .impl-items .docblock, .content .impl-items .stability { + margin-left: 40px; +} +.content .impl-items .method, .content .impl-items .type { + margin-left: 20px; +} nav { border-bottom: 1px solid #e0e0e0; @@ -468,30 +477,31 @@ a { padding: 20px; } -.stability { - border-left: 6px solid; - padding: 3px 6px; - border-radius: 3px; +em.stab.unstable { background: #FFF5D6; border-color: #FFC600; } +em.stab.deprecated { background: #F3DFFF; border-color: #7F0087; } +em.stab { + display: inline-block; + border-width: 1px; + border-style: solid; + padding: 3px; + margin-bottom: 5px; + font-size: 90%; + font-style: normal; } - -h1 .stability { - text-transform: lowercase; - font-weight: 400; - margin-left: 14px; - padding: 4px 10px; +em.stab p { + display: inline; } -.impl-items .stability, .methods .stability { - margin-right: 20px; +.module-item .stab { + border-width: 0; + padding: 0; + margin: 0; + background: inherit !important; } -.stability.Deprecated { border-color: #A071A8; color: #82478C; } -.stability.Experimental { border-color: #D46D6A; color: #AA3C39; } -.stability.Unstable { border-color: #D4B16A; color: #AA8439; } -.stability.Stable { border-color: #54A759; color: #2D8632; } -.stability.Frozen { border-color: #009431; color: #007726; } -.stability.Locked { border-color: #0084B6; color: #00668c; } -.stability.Unmarked { border-color: #BBBBBB; } +.module-item.unstable { + opacity: 0.65; +} td.summary-column { width: 100%; @@ -500,11 +510,6 @@ td.summary-column { .summary { padding-right: 0px; } -.summary.Deprecated { background-color: #A071A8; } -.summary.Experimental { background-color: #D46D6A; } -.summary.Unstable { background-color: #D4B16A; } -.summary.Stable { background-color: #54A759; } -.summary.Unmarked { background-color: #BBBBBB; } :target { background: #FDFFD3; } .line-numbers :target { background-color: transparent; } @@ -555,9 +560,9 @@ pre.rust { position: relative; } .collapse-toggle { font-weight: 300; position: absolute; - left: 13px; + left: -23px; color: #999; - margin-top: 2px; + top: 0; } .toggle-wrapper > .collapse-toggle { diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index c3ab375a9e2..0379c04be4d 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -802,6 +802,9 @@ if (query['gotosrc']) { window.location = $('#src-' + query['gotosrc']).attr('href'); } + if (query['gotomacrosrc']) { + window.location = $('.srclink').attr('href'); + } $("#expand-all").on("click", function() { $(".docblock").show(); diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 008da466db0..2682bbf4662 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -91,7 +91,6 @@ pub mod html { pub mod markdown; pub mod passes; pub mod plugins; -pub mod stability_summary; pub mod visit_ast; pub mod test; mod flock; diff --git a/src/librustdoc/stability_summary.rs b/src/librustdoc/stability_summary.rs deleted file mode 100644 index 3e4f6896ee6..00000000000 --- a/src/librustdoc/stability_summary.rs +++ /dev/null @@ -1,199 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! This module crawls a `clean::Crate` and produces a summarization of the -//! stability levels within the crate. The summary contains the module -//! hierarchy, with item counts for every stability level per module. A parent -//! module's count includes its children's. - -use std::cmp::Ordering; -use std::ops::Add; - -use syntax::attr::{Unstable, Stable}; -use syntax::ast::Public; - -use clean::{Crate, Item, ModuleItem, Module, EnumItem, Enum}; -use clean::{ImplItem, Impl, Trait, TraitItem}; -use clean::{ExternCrateItem, ImportItem, PrimitiveItem, Stability}; - -use html::render::cache; - -#[derive(RustcEncodable, RustcDecodable, PartialEq, Eq)] -/// The counts for each stability level. -#[derive(Copy, Clone)] -pub struct Counts { - pub deprecated: u64, - pub unstable: u64, - pub stable: u64, - - /// No stability level, inherited or otherwise. - pub unmarked: u64, -} - -impl Add for Counts { - type Output = Counts; - - fn add(self, other: Counts) -> Counts { - Counts { - deprecated: self.deprecated + other.deprecated, - unstable: self.unstable + other.unstable, - stable: self.stable + other.stable, - unmarked: self.unmarked + other.unmarked, - } - } -} - -impl Counts { - fn zero() -> Counts { - Counts { - deprecated: 0, - unstable: 0, - stable: 0, - unmarked: 0, - } - } - - pub fn total(&self) -> u64 { - self.deprecated + self.unstable + self.stable + self.unmarked - } -} - -#[derive(RustcEncodable, RustcDecodable, PartialEq, Eq)] -/// A summarized module, which includes total counts and summarized children -/// modules. -pub struct ModuleSummary { - pub name: String, - pub counts: Counts, - pub submodules: Vec<ModuleSummary>, -} - -impl PartialOrd for ModuleSummary { - fn partial_cmp(&self, other: &ModuleSummary) -> Option<Ordering> { - self.name.partial_cmp(&other.name) - } -} - -impl Ord for ModuleSummary { - fn cmp(&self, other: &ModuleSummary) -> Ordering { - self.name.cmp(&other.name) - } -} - -// is the item considered publicly visible? -fn visible(item: &Item) -> bool { - match item.inner { - ImplItem(_) => true, - _ => item.visibility == Some(Public) - } -} - -fn count_stability(stab: Option<&Stability>) -> Counts { - match stab { - None => Counts { unmarked: 1, .. Counts::zero() }, - Some(ref stab) => { - if !stab.deprecated_since.is_empty() { - return Counts { deprecated: 1, .. Counts::zero() }; - } - match stab.level { - Unstable => Counts { unstable: 1, .. Counts::zero() }, - Stable => Counts { stable: 1, .. Counts::zero() }, - } - } - } -} - -fn summarize_methods(item: &Item) -> Counts { - match cache().impls.get(&item.def_id) { - Some(v) => { - v.iter().map(|i| { - let count = count_stability(i.stability.as_ref()); - if i.impl_.trait_.is_none() { - count + i.impl_.items.iter() - .map(|ti| summarize_item(ti).0) - .fold(Counts::zero(), |acc, c| acc + c) - } else { - count - } - }).fold(Counts::zero(), |acc, c| acc + c) - }, - None => { - Counts::zero() - }, - } -} - - -// Produce the summary for an arbitrary item. If the item is a module, include a -// module summary. The counts for items with nested items (e.g. modules, traits, -// impls) include all children counts. -fn summarize_item(item: &Item) -> (Counts, Option<ModuleSummary>) { - let item_counts = count_stability(item.stability.as_ref()) + summarize_methods(item); - - // Count this item's children, if any. Note that a trait impl is - // considered to have no children. - match item.inner { - // Require explicit `pub` to be visible - ImplItem(Impl { ref items, trait_: None, .. }) => { - let subcounts = items.iter().filter(|i| visible(*i)) - .map(summarize_item) - .map(|s| s.0) - .fold(Counts::zero(), |acc, x| acc + x); - (subcounts, None) - } - // `pub` automatically - EnumItem(Enum { variants: ref subitems, .. }) => { - let subcounts = subitems.iter().map(summarize_item) - .map(|s| s.0) - .fold(Counts::zero(), |acc, x| acc + x); - (item_counts + subcounts, None) - } - TraitItem(Trait { ref items, .. }) => { - let subcounts = items.iter().map(summarize_item) - .map(|s| s.0) - .fold(Counts::zero(), |acc, x| acc + x); - (item_counts + subcounts, None) - } - ModuleItem(Module { ref items, .. }) => { - let mut counts = item_counts; - let mut submodules = Vec::new(); - - for (subcounts, submodule) in items.iter().filter(|i| visible(*i)) - .map(summarize_item) { - counts = counts + subcounts; - submodule.map(|m| submodules.push(m)); - } - submodules.sort(); - - (counts, Some(ModuleSummary { - name: item.name.as_ref().map_or("".to_string(), |n| n.clone()), - counts: counts, - submodules: submodules, - })) - } - // no stability information for the following items: - ExternCrateItem(..) | ImportItem(_) | - PrimitiveItem(_) => (Counts::zero(), None), - _ => (item_counts, None) - } -} - -/// Summarizes the stability levels in a crate. -pub fn build(krate: &Crate) -> ModuleSummary { - match krate.module { - None => ModuleSummary { - name: krate.name.clone(), - counts: Counts::zero(), - submodules: Vec::new(), - }, - Some(ref item) => ModuleSummary { - name: krate.name.clone(), .. summarize_item(item).1.unwrap() - } - } -} diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 449f9c79d1d..bbe0a6f2675 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::cell::RefCell; +use std::cell::{RefCell, Cell}; use std::collections::{HashSet, HashMap}; use std::dynamic_lib::DynamicLibrary; use std::env; @@ -92,6 +92,7 @@ pub fn run(input: &str, external_typarams: RefCell::new(None), inlined: RefCell::new(None), populated_crate_impls: RefCell::new(HashSet::new()), + deref_trait_did: Cell::new(None), }; let mut v = RustdocVisitor::new(&ctx, None); diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index e4f4dbaafbe..4ad693578cc 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -398,6 +398,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { name: def.ident, whence: def.span, stab: self.stability(def.id), + imported_from: def.imported_from, } } } diff --git a/src/test/auxiliary/issue-19190-3.rs b/src/test/auxiliary/issue-19190-3.rs new file mode 100644 index 00000000000..435f0176162 --- /dev/null +++ b/src/test/auxiliary/issue-19190-3.rs @@ -0,0 +1,30 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::ops::Deref; + +pub struct Foo; + +impl Deref for Foo { + type Target = i32; + fn deref(&self) -> &i32 { loop {} } +} + +pub struct Bar; +pub struct Baz; + +impl Baz { + pub fn baz(&self) {} +} + +impl Deref for Bar { + type Target = Baz; + fn deref(&self) -> &Baz { loop {} } +} diff --git a/src/test/rustdoc/issue-19190-2.rs b/src/test/rustdoc/issue-19190-2.rs new file mode 100644 index 00000000000..b84ec6d6166 --- /dev/null +++ b/src/test/rustdoc/issue-19190-2.rs @@ -0,0 +1,22 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::ops::Deref; + +pub struct Bar; + +impl Deref for Bar { + type Target = i32; + fn deref(&self) -> &i32 { loop {} } +} + +// @has issue_19190_2/struct.Bar.html +// @has - '//*[@id="method.count_ones"]' 'fn count_ones(self) -> u32' + diff --git a/src/test/rustdoc/issue-19190-3.rs b/src/test/rustdoc/issue-19190-3.rs new file mode 100644 index 00000000000..c315ea26d26 --- /dev/null +++ b/src/test/rustdoc/issue-19190-3.rs @@ -0,0 +1,35 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:issue-19190-3.rs +// ignore-android + +extern crate issue_19190_3; + +use std::ops::Deref; +use issue_19190_3::Baz; + +// @has issue_19190_3/struct.Foo.html +// @has - '//*[@id="method.count_ones"]' 'fn count_ones(self) -> u32' +pub use issue_19190_3::Foo; + +// @has issue_19190_3/struct.Bar.html +// @has - '//*[@id="method.baz"]' 'fn baz(&self)' +pub use issue_19190_3::Bar; + +// @has issue_19190_3/struct.MyBar.html +// @has - '//*[@id="method.baz"]' 'fn baz(&self)' +pub struct MyBar; + +impl Deref for MyBar { + type Target = Baz; + fn deref(&self) -> &Baz { loop {} } +} + diff --git a/src/test/rustdoc/issue-19190.rs b/src/test/rustdoc/issue-19190.rs new file mode 100644 index 00000000000..f011a3e64a6 --- /dev/null +++ b/src/test/rustdoc/issue-19190.rs @@ -0,0 +1,26 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::ops::Deref; + +pub struct Foo; +pub struct Bar; + +impl Foo { + pub fn foo(&self) {} +} + +impl Deref for Bar { + type Target = Foo; + fn deref(&self) -> &Foo { loop {} } +} + +// @has issue_19190/struct.Bar.html +// @has - '//*[@id="method.foo"]' 'fn foo(&self)' |
