diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index f14437b71b47a..4fc86cf181b8d 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 { +pub fn build_impls(cx: &DocContext, 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().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>) { + impls: &mut Vec) { 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 { +pub fn build_impl(cx: &DocContext, + tcx: &ty::ctxt, + did: ast::DefId, + ret: &mut Vec) { 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::>(); 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 72702dc8d9472..f7fbb67e08a28 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -128,6 +128,10 @@ impl<'a, 'tcx> Clean 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 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 for ast::ImplItem { ast::MacImplItem(_) => { MacroItem(Macro { source: self.span.to_src(cx), + imported_from: None, }) } }; @@ -2169,9 +2190,21 @@ fn detect_derived(attrs: &[M]) -> bool { attr::contains_name(attrs, "automatically_derived") } -impl Clean for doctree::Impl { - fn clean(&self, cx: &DocContext) -> Item { - Item { +impl Clean> for doctree::Impl { + fn clean(&self, cx: &DocContext) -> Vec { + 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 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) { + 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 { #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct Macro { pub source: String, + pub imported_from: Option, } impl Clean for doctree::Macro { @@ -2554,6 +2642,7 @@ impl Clean 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 a637ba9f29706..1b74123c4adcd 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>>, pub inlined: RefCell>>, pub populated_crate_impls: RefCell>, + pub deref_trait_did: Cell>, } impl<'tcx> DocContext<'tcx> { @@ -77,6 +78,7 @@ pub struct CrateAnalysis { pub external_paths: ExternalPaths, pub external_typarams: RefCell>>, pub inlined: RefCell>>, + pub deref_trait_did: Option, } pub type Externs = HashMap>; @@ -147,15 +149,17 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec, 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, 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 862bca1b81338..8fa92304d249c 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -214,6 +214,7 @@ pub struct Macro { pub attrs: Vec, pub whence: Span, pub stab: Option, + pub imported_from: Option, } pub struct ExternCrate { diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index d2dccca362ef8..bb53d532f52f7 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); -/// Wrapper struct for emitting the stability level concisely. -pub struct ConciseStability<'a>(pub &'a Option); /// 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)> { repeat("../").take(loc.len()).collect::() } else { match cache.extern_locations[&did.krate] { - render::Remote(ref s) => s.to_string(), - render::Local => repeat("../").take(loc.len()).collect::(), - 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::()) } - 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, "{lvl}", - 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, "", - lvl = Escape(&*lvl), - colon = if !stability.reason.is_empty() { ": " } else { "" }, - reason = Escape(&*stability.reason)) - } - None => { - write!(f, "") - } - } - } -} - -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, "")); - try!(write!(f, "{}", { - let mut url = context[1..].to_vec(); - url.push("index.html"); - url.connect("/") - }, - path)); - try!(write!(f, "")); - try!(write!(f, " ", - (100 * cnt.stable) as f64/tot as f64)); - try!(write!(f, " ", - (100 * cnt.unstable) as f64/tot as f64)); - try!(write!(f, " ", - (100 * cnt.deprecated) as f64/tot as f64)); - try!(write!(f, " ", - (100 * cnt.unmarked) as f64/tot as f64)); - try!(write!(f, "")); - - 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"

Stability dashboard: crate {name}

-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}): -
- stable ({}%),
- unstable ({}%),
- deprecated ({}%),
- unmarked ({}%) -
-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, "")); - try!(fmt_inner(f, &mut context, self)); - write!(f, "
") - } -} diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 5f4a3e74b6589..f87a86eb3a68c 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); @@ -192,7 +193,7 @@ pub struct Cache { pub implementors: HashMap>, /// Cache of where external crate documentation can be found. - pub extern_locations: HashMap, + pub extern_locations: HashMap, /// Cache of where documentation for primitives can be found. pub primitive_locations: HashMap, @@ -208,6 +209,7 @@ pub struct Cache { privmod: bool, remove_priv: bool, public_items: NodeSet, + deref_trait_did: Option, // 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 { @@ -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 { + 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, "{}", shortty(self.item), self.item.name.as_ref().unwrap())); - // Write stability level - try!(write!(fmt, "{}", Stability(&self.item.stability))); - try!(write!(fmt, "")); // in-band - // Links to out-of-band information, i.e. src and stability dashboard try!(write!(fmt, "")); - - // Write stability dashboard link - match self.item.inner { - clean::ModuleItem(ref m) if m.is_crate => { - try!(write!(fmt, "[stability] ")); - } - _ => {} - }; - try!(write!(fmt, r##" [-] [+] @@ -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, "[src]", + try!(write!(fmt, "[src]", 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, "
{}
", Markdown(s))); - } - None => {} + if let Some(s) = short_stability(item, true) { + try!(write!(w, "
{}
", s)); + } + if let Some(s) = item.doc_value() { + try!(write!(w, "
{}
", 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, " - - {stab}{} - {} + + {name} + + {stab_docs} {docs} + ", - *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, "") } +fn short_stability(item: &clean::Item, show_reason: bool) -> Option { + 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!("{}", + 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, "

{}", - shortty(m), - *m.name.as_ref().unwrap(), - ConciseStability(&m.stability))); + try!(write!(w, "

", + ty = shortty(m), + name = *m.name.as_ref().unwrap(), + stab = m.stability_class())); try!(render_method(w, m, MethodLink::Anchor)); try!(write!(w, "

")); 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, "
  • {}impl{} {} for {}{}
  • ", - ConciseStability(&i.stability), + try!(writeln!(w, "
  • impl{} {} for {}{}
  • ", 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, "

    Fields

    \n")); for field in fields { - try!(write!(w, " + ")); @@ -1974,7 +2001,7 @@ fn item_struct(w: &mut fmt::Formatter, it: &clean::Item, try!(write!(w, "
    \ - {stab}{name}", - stab = ConciseStability(&field.stability), + try!(write!(w, "
    \ + {name}", + stab = field.stability_class(), name = field.name.as_ref().unwrap())); try!(document(w, field)); try!(write!(w, "
    ")); } } - 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, "

    Variants

    \n")); for variant in &e.variants { - try!(write!(w, "
    {stab}{name}", - stab = ConciseStability(&variant.stability), + try!(write!(w, "
    {name}", 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, "
    ")); } - 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, "

    Methods

    ")); + let render_header = match what { + MethodRender::All => { + try!(write!(w, "

    Methods

    ")); + true + } + MethodRender::DerefFor { trait_, type_ } => { + try!(write!(w, "

    Methods from \ + {}<Target={}>

    ", 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, "

    Trait \ Implementations

    ")); - 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, "

    \ @@ -2191,73 +2251,92 @@ fn render_methods(w: &mut fmt::Formatter, it: &clean::Item) -> fmt::Result {

    ")); 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, "

    {}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, "{}{}

    ", i.impl_.for_, - WhereClause(&i.impl_.generics))); - if let Some(ref dox) = i.dox { - try!(write!(w, "
    {}
    ", Markdown(dox))); +} + +fn render_impl(w: &mut fmt::Formatter, i: &Impl, link: MethodLink, + render_header: bool) -> fmt::Result { + if render_header { + try!(write!(w, "

    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, "{}{}

    ", i.impl_.for_, + WhereClause(&i.impl_.generics))); + if let Some(ref dox) = i.dox { + try!(write!(w, "
    {}
    ", 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, "

    {}", + try!(write!(w, "

    ", *item.name.as_ref().unwrap(), - shortty(item), - ConciseStability(&item.stability))); + shortty(item))); try!(render_method(w, item, link)); try!(write!(w, "

    \n")); } clean::TypedefItem(ref tydef) => { let name = item.name.as_ref().unwrap(); - try!(write!(w, "

    {}", + try!(write!(w, "

    ", *name, - shortty(item), - ConciseStability(&item.stability))); + shortty(item))); try!(write!(w, "type {} = {}", name, tydef.type_)); try!(write!(w, "

    \n")); } clean::AssociatedTypeItem(ref bounds, ref default) => { let name = item.name.as_ref().unwrap(); - try!(write!(w, "

    {}", + try!(write!(w, "

    ", *name, - shortty(item), - ConciseStability(&item.stability))); + shortty(item))); try!(assoc_type(w, item, bounds, default)); try!(write!(w, "

    \n")); } _ => panic!("can't make docs for trait item with name {:?}", item.name) } - match item.doc_value() { - Some(s) if dox => { - try!(write!(w, "
    {}
    ", Markdown(s))); - Ok(()) - } - Some(..) | None => Ok(()) + if let MethodLink::Anchor = link { + document(w, item) + } else { + Ok(()) } } try!(write!(w, "
    ")); 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 2af20ce59da57..c94dbc1510332 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 c3ab375a9e24a..0379c04be4d29 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 008da466db010..2682bbf4662e0 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 3e4f6896ee68d..0000000000000 --- 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 or the MIT license -// , 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, -} - -impl PartialOrd for ModuleSummary { - fn partial_cmp(&self, other: &ModuleSummary) -> Option { - 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) { - 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 449f9c79d1d45..bbe0a6f267538 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 e4f4dbaafbe49..4ad693578ccdc 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 0000000000000..435f0176162b8 --- /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 or the MIT license +// , 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 0000000000000..b84ec6d616636 --- /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 or the MIT license +// , 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 0000000000000..c315ea26d2642 --- /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 or the MIT license +// , 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 0000000000000..f011a3e64a6be --- /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 or the MIT license +// , 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)'