From 62267470f630c6bf8553feb65d5c130e6890ba70 Mon Sep 17 00:00:00 2001 From: mitaa Date: Sat, 27 Feb 2016 07:35:05 +0100 Subject: [PATCH 1/6] Refactor src-link creation for local sources Since we emit the sources beforhand we actually **know** whether we can safely create src-links to these files and where they are stored. --- src/librustdoc/html/render.rs | 73 +++++++++++++++-------------------- 1 file changed, 32 insertions(+), 41 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index af6dec8dc8688..c9c9f1968133e 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -104,6 +104,8 @@ pub struct Context { /// the source files are present in the html rendering, then this will be /// `true`. pub include_sources: bool, + /// The local file sources we've emitted and their respective url-paths. + pub local_sources: HashMap, /// A flag, which when turned off, will render pages which redirect to the /// real location of an item. This is used to allow external links to /// publicly reused items to redirect to the right location. @@ -262,8 +264,6 @@ pub struct Cache { struct SourceCollector<'a> { cx: &'a mut Context, - /// Processed source-file paths - seen: HashSet, /// Root destination to place all HTML output into dst: PathBuf, } @@ -423,6 +423,7 @@ pub fn run(mut krate: clean::Crate, playground_url: "".to_string(), }, include_sources: true, + local_sources: HashMap::new(), render_redirect_pages: false, issue_tracker_base_url: None, }; @@ -770,11 +771,8 @@ fn render_sources(cx: &mut Context, try_err!(mkdir(&dst), &dst); let mut folder = SourceCollector { dst: dst, - seen: HashSet::new(), cx: cx, }; - // skip all invalid spans - folder.seen.insert("".to_string()); Ok(folder.fold_crate(krate)) } @@ -866,7 +864,13 @@ impl<'a> DocFolder for SourceCollector<'a> { fn fold_item(&mut self, item: clean::Item) -> Option { // If we're including source files, and we haven't seen this file yet, // then we need to render it out to the filesystem - if self.cx.include_sources && !self.seen.contains(&item.source.filename) { + if self.cx.include_sources + // skip all invalid spans + && item.source.filename != "" + // macros from other libraries get special filenames which we can + // safely ignore + && !(item.source.filename.starts_with("<") + && item.source.filename.ends_with("macros>")) { // If it turns out that we couldn't read this file, then we probably // can't read any of the files (generating html output from json or @@ -884,7 +888,6 @@ impl<'a> DocFolder for SourceCollector<'a> { false } }; - self.seen.insert(item.source.filename.clone()); } self.fold_item_recur(item) @@ -895,19 +898,14 @@ impl<'a> SourceCollector<'a> { /// Renders the given filename into its corresponding HTML source file. fn emit_source(&mut self, filename: &str) -> io::Result<()> { let p = PathBuf::from(filename); + if self.cx.local_sources.contains_key(&p) { + // We've already emitted this source + return Ok(()); + } - // If we couldn't open this file, then just returns because it - // probably means that it's some standard library macro thing and we - // can't have the source to it anyway. let mut contents = Vec::new(); - match File::open(&p).and_then(|mut f| f.read_to_end(&mut contents)) { - Ok(r) => r, - // macros from other libraries get special filenames which we can - // safely ignore - Err(..) if filename.starts_with("<") && - filename.ends_with("macros>") => return Ok(()), - Err(e) => return Err(e) - }; + try!(File::open(&p).and_then(|mut f| f.read_to_end(&mut contents))); + let contents = str::from_utf8(&contents).unwrap(); // Remove the utf-8 BOM if any @@ -920,16 +918,20 @@ impl<'a> SourceCollector<'a> { // Create the intermediate directories let mut cur = self.dst.clone(); let mut root_path = String::from("../../"); + let mut href = String::new(); clean_srcpath(&self.cx.src_root, &p, false, |component| { cur.push(component); mkdir(&cur).unwrap(); root_path.push_str("../"); + href.push_str(component); + href.push('/'); }); - let mut fname = p.file_name().expect("source has no filename") .to_os_string(); fname.push(".html"); cur.push(&fname[..]); + href.push_str(&fname.to_string_lossy()); + let mut w = BufWriter::new(try!(File::create(&cur))); let title = format!("{} -- source", cur.file_name().unwrap() .to_string_lossy()); @@ -944,7 +946,8 @@ impl<'a> SourceCollector<'a> { try!(layout::render(&mut w, &self.cx.layout, &page, &(""), &Source(contents))); try!(w.flush()); - return Ok(()); + self.cx.local_sources.insert(p, href); + Ok(()) } } @@ -1459,7 +1462,7 @@ impl<'a> Item<'a> { /// If `None` is returned, then a source link couldn't be generated. This /// may happen, for example, with externally inlined items where the source /// of their crate documentation isn't known. - fn href(&self, cx: &Context) -> Option { + fn href(&self) -> Option { let href = if self.item.source.loline == self.item.source.hiline { format!("{}", self.item.source.loline) } else { @@ -1492,25 +1495,13 @@ impl<'a> Item<'a> { // 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. } else if self.item.def_id.is_local() { - let mut path = Vec::new(); - clean_srcpath(&cx.src_root, Path::new(&self.item.source.filename), - true, |component| { - path.push(component.to_string()); - }); - - // If the span points into an external macro the - // source-file will be bogus, i.e `` - let filename = &self.item.source.filename; - if !(filename.starts_with("<") && filename.ends_with("macros>")) { - Some(format!("{root}src/{krate}/{path}.html#{href}", - root = self.cx.root_path, - krate = self.cx.layout.krate, - path = path.join("/"), - href = href)) - } else { - None - } - + self.cx.local_sources.get(&PathBuf::from(&self.item.source.filename)).map(|path| { + format!("{root}src/{krate}/{path}.html#{href}", + root = self.cx.root_path, + krate = self.cx.layout.krate, + path = path, + href = href) + }) // If this item is not part of the local crate, then things get a little // trickier. We don't actually know the span of the external item, but // we know that the documentation on the other end knows the span! @@ -1590,7 +1581,7 @@ impl<'a> fmt::Display for Item<'a> { // this page, and this link will be auto-clicked. The `id` attribute is // used to find the link to auto-click. if self.cx.include_sources && !is_primitive { - match self.href(self.cx) { + match self.href() { Some(l) => { try!(write!(fmt, "[src]", From 8f6e09a956d65dbd81bb5ea12791208aed322704 Mon Sep 17 00:00:00 2001 From: mitaa Date: Sun, 28 Feb 2016 12:11:13 +0100 Subject: [PATCH 2/6] Simplify `if let`/`match` expressions --- src/librustdoc/clean/inline.rs | 25 +-- src/librustdoc/clean/mod.rs | 83 ++++----- src/librustdoc/fold.rs | 1 + src/librustdoc/html/render.rs | 306 +++++++++++++++------------------ src/librustdoc/lib.rs | 55 ++---- src/librustdoc/passes.rs | 33 ++-- src/librustdoc/test.rs | 21 +-- src/librustdoc/visit_ast.rs | 6 +- 8 files changed, 211 insertions(+), 319 deletions(-) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 02ea83615a372..6fd80feaac747 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -138,13 +138,10 @@ pub fn load_attrs(cx: &DocContext, tcx: &TyCtxt, /// These names are used later on by HTML rendering to generate things like /// source links back to the original item. pub fn record_extern_fqn(cx: &DocContext, did: DefId, kind: clean::TypeKind) { - match cx.tcx_opt() { - Some(tcx) => { - let fqn = tcx.sess.cstore.extern_item_path(did); - let fqn = fqn.into_iter().map(|i| i.to_string()).collect(); - cx.external_paths.borrow_mut().as_mut().unwrap().insert(did, (fqn, kind)); - } - None => {} + if let Some(tcx) = cx.tcx_opt() { + let fqn = tcx.sess.cstore.extern_item_path(did); + let fqn = fqn.into_iter().map(|i| i.to_string()).collect(); + cx.external_paths.borrow_mut().as_mut().unwrap().insert(did, (fqn, kind)); } } @@ -230,12 +227,9 @@ pub fn build_impls(cx: &DocContext, tcx: &TyCtxt, tcx.populate_inherent_implementations_for_type_if_necessary(did); let mut impls = Vec::new(); - match tcx.inherent_impls.borrow().get(&did) { - None => {} - Some(i) => { - for &did in i.iter() { - build_impl(cx, tcx, did, &mut impls); - } + if let Some(i) = tcx.inherent_impls.borrow().get(&did) { + for &did in i.iter() { + build_impl(cx, tcx, did, &mut impls); } } @@ -464,9 +458,8 @@ fn build_module(cx: &DocContext, tcx: &TyCtxt, } cstore::DlDef(def) if item.vis == hir::Public => { if !visited.insert(def) { continue } - match try_inline_def(cx, tcx, def) { - Some(i) => items.extend(i), - None => {} + if let Some(i) = try_inline_def(cx, tcx, def) { + items.extend(i) } } cstore::DlDef(..) => {} diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index b6da5b0ef20e8..96a56a7c113f3 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -100,10 +100,7 @@ impl, U> Clean for Rc { impl, U> Clean> for Option { fn clean(&self, cx: &DocContext) -> Option { - match self { - &None => None, - &Some(ref v) => Some(v.clean(cx)) - } + self.as_ref().map(|v| v.clean(cx)) } } @@ -332,27 +329,20 @@ impl Item { } pub fn stability_class(&self) -> String { - match self.stability { - Some(ref s) => { - let mut base = match s.level { - stability::Unstable => "unstable".to_string(), - stability::Stable => String::new(), - }; - if !s.deprecated_since.is_empty() { - base.push_str(" deprecated"); - } - base + self.stability.as_ref().map(|ref s| { + let mut base = match s.level { + stability::Unstable => "unstable".to_string(), + stability::Stable => String::new(), + }; + if !s.deprecated_since.is_empty() { + base.push_str(" deprecated"); } - _ => String::new(), - } + base + }).unwrap_or(String::new()) } pub fn stable_since(&self) -> Option<&str> { - if let Some(ref s) = self.stability { - return Some(&s.since[..]); - } - - None + self.stability.as_ref().map(|s| &s.since[..]) } } @@ -711,7 +701,7 @@ impl<'tcx> Clean for ty::TraitRef<'tcx> { if let &ty::Region::ReLateBound(_, _) = *reg { debug!(" hit an ReLateBound {:?}", reg); if let Some(lt) = reg.clean(cx) { - late_bounds.push(lt) + late_bounds.push(lt); } } } @@ -780,8 +770,7 @@ impl Clean> for ty::Region { fn clean(&self, cx: &DocContext) -> Option { match *self { ty::ReStatic => Some(Lifetime::statik()), - ty::ReLateBound(_, ty::BrNamed(_, name)) => - Some(Lifetime(name.to_string())), + ty::ReLateBound(_, ty::BrNamed(_, name)) => Some(Lifetime(name.to_string())), ty::ReEarlyBound(ref data) => Some(Lifetime(data.name.clean(cx))), ty::ReLateBound(..) | @@ -1151,12 +1140,12 @@ impl<'tcx> Clean for ty::FnOutput<'tcx> { impl<'a, 'tcx> Clean for (DefId, &'a ty::PolyFnSig<'tcx>) { fn clean(&self, cx: &DocContext) -> FnDecl { let (did, sig) = *self; - let mut names = if let Some(_) = cx.map.as_local_node_id(did) { + let mut names = if cx.map.as_local_node_id(did).is_some() { vec![].into_iter() } else { cx.tcx().sess.cstore.method_arg_names(did).into_iter() }.peekable(); - if names.peek().map(|s| &**s) == Some("self") { + if let Some("self") = names.peek().map(|s| &s[..]) { let _ = names.next(); } FnDecl { @@ -1627,15 +1616,9 @@ impl Clean for hir::Ty { } } TyBareFn(ref barefn) => BareFunction(box barefn.clean(cx)), - TyPolyTraitRef(ref bounds) => { - PolyTraitRef(bounds.clean(cx)) - }, - TyInfer => { - Infer - }, - TyTypeof(..) => { - panic!("Unimplemented type {:?}", self.node) - }, + TyPolyTraitRef(ref bounds) => PolyTraitRef(bounds.clean(cx)), + TyInfer => Infer, + TyTypeof(..) => panic!("Unimplemented type {:?}", self.node), } } } @@ -2253,7 +2236,7 @@ impl Clean> for doctree::Impl { polarity: Some(self.polarity.clean(cx)), }), }); - return ret; + ret } } @@ -2393,9 +2376,8 @@ impl Clean> for doctree::Import { } hir::ViewPathSimple(name, ref p) => { if !denied { - match inline::try_inline(cx, self.id, Some(name)) { - Some(items) => return items, - None => {} + if let Some(items) = inline::try_inline(cx, self.id, Some(name)) { + return items; } } (vec![], SimpleImport(name.clean(cx), @@ -2460,9 +2442,8 @@ impl Clean> for hir::ForeignMod { fn clean(&self, cx: &DocContext) -> Vec { let mut items = self.items.clean(cx); for item in &mut items { - match item.inner { - ForeignFunctionItem(ref mut f) => f.abi = self.abi, - _ => {} + if let ForeignFunctionItem(ref mut f) = item.inner { + f.abi = self.abi; } } items @@ -2598,11 +2579,7 @@ fn resolve_type(cx: &DocContext, }; } }; - let def = match tcx.def_map.borrow().get(&id) { - Some(k) => k.full_def(), - None => panic!("unresolved id not in defmap") - }; - + let def = tcx.def_map.borrow().get(&id).expect("unresolved id not in defmap").full_def(); debug!("resolve_type: def={:?}", def); let is_generic = match def { @@ -2659,7 +2636,7 @@ fn register_def(cx: &DocContext, def: Def) -> DefId { let t = inline::build_external_trait(cx, tcx, did); cx.external_traits.borrow_mut().as_mut().unwrap().insert(did, t); } - return did; + did } fn resolve_use_source(cx: &DocContext, path: Path, id: ast::NodeId) -> ImportSource { @@ -2732,12 +2709,10 @@ impl Clean for attr::Stability { _=> "".to_string(), }, reason: { - if let Some(ref depr) = self.rustc_depr { - depr.reason.to_string() - } else if let attr::Unstable {reason: Some(ref reason), ..} = self.level { - reason.to_string() - } else { - "".to_string() + match (&self.rustc_depr, &self.level) { + (&Some(ref depr), _) => depr.reason.to_string(), + (&None, &attr::Unstable {reason: Some(ref reason), ..}) => reason.to_string(), + _ => "".to_string(), } }, issue: match self.level { diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index 5a4f95d1a1a5a..afe1387ad9fe6 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -81,6 +81,7 @@ pub trait DocFolder : Sized { c.module = match replace(&mut c.module, None) { Some(module) => self.fold_item(module), None => None }; + let external_traits = replace(&mut c.external_traits, HashMap::new()); c.external_traits = external_traits.into_iter().map(|(k, mut v)| { let items = replace(&mut v.items, Vec::new()); diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index c9c9f1968133e..319c9d7d18560 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -433,41 +433,38 @@ pub fn run(mut krate: clean::Crate, // Crawl the crate attributes looking for attributes which control how we're // going to emit HTML let default: &[_] = &[]; - match krate.module.as_ref().map(|m| m.doc_list().unwrap_or(default)) { - Some(attrs) => { - for attr in attrs { - match *attr { - clean::NameValue(ref x, ref s) - if "html_favicon_url" == *x => { - cx.layout.favicon = s.to_string(); - } - clean::NameValue(ref x, ref s) - if "html_logo_url" == *x => { - cx.layout.logo = s.to_string(); - } - clean::NameValue(ref x, ref s) - if "html_playground_url" == *x => { - cx.layout.playground_url = s.to_string(); - markdown::PLAYGROUND_KRATE.with(|slot| { - if slot.borrow().is_none() { - let name = krate.name.clone(); - *slot.borrow_mut() = Some(Some(name)); - } - }); - } - clean::NameValue(ref x, ref s) - if "issue_tracker_base_url" == *x => { - cx.issue_tracker_base_url = Some(s.to_string()); - } - clean::Word(ref x) - if "html_no_source" == *x => { - cx.include_sources = false; - } - _ => {} + if let Some(attrs) = krate.module.as_ref().map(|m| m.doc_list().unwrap_or(default)) { + for attr in attrs { + match *attr { + clean::NameValue(ref x, ref s) + if "html_favicon_url" == *x => { + cx.layout.favicon = s.to_string(); + } + clean::NameValue(ref x, ref s) + if "html_logo_url" == *x => { + cx.layout.logo = s.to_string(); + } + clean::NameValue(ref x, ref s) + if "html_playground_url" == *x => { + cx.layout.playground_url = s.to_string(); + markdown::PLAYGROUND_KRATE.with(|slot| { + if slot.borrow().is_none() { + let name = krate.name.clone(); + *slot.borrow_mut() = Some(Some(name)); + } + }); + } + clean::NameValue(ref x, ref s) + if "issue_tracker_base_url" == *x => { + cx.issue_tracker_base_url = Some(s.to_string()); + } + clean::Word(ref x) + if "html_no_source" == *x => { + cx.include_sources = false; } + _ => {} } } - None => {} } // Crawl the crate to build various caches used for the output @@ -986,15 +983,12 @@ impl DocFolder for Cache { // Collect all the implementors of traits. if let clean::ImplItem(ref i) = item.inner { - match i.trait_ { - Some(clean::ResolvedPath{ did, .. }) => { - self.implementors.entry(did).or_insert(vec![]).push(Implementor { - def_id: item.def_id, - stability: item.stability.clone(), - impl_: i.clone(), - }); - } - Some(..) | None => {} + if let Some(clean::ResolvedPath{ did, .. }) = i.trait_ { + self.implementors.entry(did).or_insert(vec![]).push(Implementor { + def_id: item.def_id, + stability: item.stability.clone(), + impl_: i.clone(), + }); } } @@ -1054,6 +1048,9 @@ impl DocFolder for Cache { } }); + // A crate has a module at its root, containing all items, + // which should not be indexed. The crate-item itself is + // inserted later on when serializing the search-index. if item.def_id.index != CRATE_DEF_INDEX { self.search_index.push(IndexItem { ty: shortty(&item), @@ -1078,13 +1075,14 @@ impl DocFolder for Cache { } // Keep track of the fully qualified path for this item. - let pushed = if item.name.is_some() { - let n = item.name.as_ref().unwrap(); - if !n.is_empty() { + let pushed = match item.name { + Some(ref n) if !n.is_empty() => { self.stack.push(n.to_string()); true - } else { false } - } else { false }; + } + _ => false, + }; + match item.inner { clean::StructItem(..) | clean::EnumItem(..) | clean::TypedefItem(..) | clean::TraitItem(..) | @@ -1153,60 +1151,53 @@ impl DocFolder for Cache { // Once we've recursively found all the generics, then hoard off all the // implementations elsewhere - let ret = match self.fold_item_recur(item) { - Some(item) => { - match item { - clean::Item{ attrs, inner: clean::ImplItem(i), .. } => { - // extract relevant documentation for this impl - let dox = match attrs.into_iter().find(|a| { - match *a { - clean::NameValue(ref x, _) - if "doc" == *x => { - true - } - _ => false - } - }) { - Some(clean::NameValue(_, dox)) => Some(dox), - Some(..) | None => None, - }; - - // Figure out the id of this impl. This may map to a - // primitive rather than always to a struct/enum. - let did = match i.for_ { - clean::ResolvedPath { did, .. } | - clean::BorrowedRef { - type_: box clean::ResolvedPath { did, .. }, .. - } => { - Some(did) - } - - ref t => { - t.primitive_type().and_then(|t| { - self.primitive_locations.get(&t).map(|n| { - let id = t.to_def_index(); - DefId { krate: *n, index: id } - }) - }) - } - }; - - if let Some(did) = did { - self.impls.entry(did).or_insert(vec![]).push(Impl { - impl_: i, - dox: dox, - stability: item.stability.clone(), - }); + let ret = self.fold_item_recur(item).and_then(|item| { + if let clean::Item { attrs, inner: clean::ImplItem(i), .. } = item { + // extract relevant documentation for this impl + let dox = match attrs.into_iter().find(|a| { + match *a { + clean::NameValue(ref x, _) + if "doc" == *x => { + true } + _ => false + } + }) { + Some(clean::NameValue(_, dox)) => Some(dox), + Some(..) | None => None, + }; + // Figure out the id of this impl. This may map to a + // primitive rather than always to a struct/enum. + let did = match i.for_ { + clean::ResolvedPath { did, .. } | + clean::BorrowedRef { + type_: box clean::ResolvedPath { did, .. }, .. + } => { + Some(did) + } - None + ref t => { + t.primitive_type().and_then(|t| { + self.primitive_locations.get(&t).map(|n| { + let id = t.to_def_index(); + DefId { krate: *n, index: id } + }) + }) } + }; - i => Some(i), + if let Some(did) = did { + self.impls.entry(did).or_insert(vec![]).push(Impl { + impl_: i, + dox: dox, + stability: item.stability.clone(), + }); } + None + } else { + Some(item) } - i => i, - }; + }); if pushed { self.stack.pop().unwrap(); } if parent_pushed { self.parent_stack.pop().unwrap(); } @@ -1581,13 +1572,10 @@ impl<'a> fmt::Display for Item<'a> { // this page, and this link will be auto-clicked. The `id` attribute is // used to find the link to auto-click. if self.cx.include_sources && !is_primitive { - match self.href() { - Some(l) => { - try!(write!(fmt, "[src]", - self.item.def_id.index.as_usize(), l, "goto source code")); - } - None => {} + if let Some(l) = self.href() { + try!(write!(fmt, "[src]", + self.item.def_id.index.as_usize(), l, "goto source code")); } } @@ -1801,7 +1789,7 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, } fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Option { - let mut result = item.stability.as_ref().and_then(|stab| { + item.stability.as_ref().and_then(|stab| { let reason = if show_reason && !stab.reason.is_empty() { format!(": {}", stab.reason) } else { @@ -1836,10 +1824,8 @@ fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Optio }; Some(format!("{}", item.stability_class(), text)) - }); - - if result.is_none() { - result = item.deprecation.as_ref().and_then(|depr| { + }).or_else(|| { + item.deprecation.as_ref().and_then(|depr| { let note = if show_reason && !depr.note.is_empty() { format!(": {}", depr.note) } else { @@ -1853,10 +1839,8 @@ fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Optio let text = format!("Deprecated{}{}", since, Markdown(¬e)); Some(format!("{}", text)) - }); - } - - result + }) + }) } struct Initializer<'a>(&'a str); @@ -2108,17 +2092,12 @@ fn assoc_type(w: &mut fmt::Formatter, it: &clean::Item, fn render_stability_since_raw<'a>(w: &mut fmt::Formatter, ver: Option<&'a str>, containing_ver: Option<&'a str>) -> fmt::Result { - if containing_ver != ver { - match ver { - Some(v) => - if v.len() > 0 { - try!(write!(w, "{}", - v)) - }, - None => {} + if let Some(v) = ver { + if containing_ver != ver && v.len() > 0 { + try!(write!(w, "{}", + v)) } } - Ok(()) } @@ -2289,43 +2268,33 @@ fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, try!(write!(w, "{name}", name = variant.name.as_ref().unwrap())); try!(document(w, cx, variant)); - match variant.inner { - clean::VariantItem(ref var) => { - match var.kind { - clean::StructVariant(ref s) => { - let fields = s.fields.iter().filter(|f| { - match f.inner { - clean::StructFieldItem(ref t) => match *t { - clean::HiddenStructField => false, - clean::TypedStructField(..) => true, - }, - _ => false, - } - }); - try!(write!(w, "

Fields

\n - ")); - for field in fields { - try!(write!(w, "")); - } - try!(write!(w, "
\ - {f}", - v = variant.name.as_ref().unwrap(), - f = field.name.as_ref().unwrap())); - try!(document(w, cx, field)); - try!(write!(w, "
")); - } - _ => () + + use clean::{Variant, StructVariant}; + if let clean::VariantItem( Variant { kind: StructVariant(ref s) } ) = variant.inner { + let fields = s.fields.iter().filter(|f| { + match f.inner { + clean::StructFieldItem(clean::TypedStructField(..)) => true, + _ => false, } + }); + try!(write!(w, "

Fields

\n + ")); + for field in fields { + try!(write!(w, "")); } - _ => () + try!(write!(w, "
\ + {f}", + v = variant.name.as_ref().unwrap(), + f = field.name.as_ref().unwrap())); + try!(document(w, cx, field)); + try!(write!(w, "
")); } try!(write!(w, "")); try!(render_stability_since(w, variant, it)); try!(write!(w, "")); } try!(write!(w, "")); - } try!(render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)); Ok(()) @@ -2356,9 +2325,8 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item, VisSpace(it.visibility), if structhead {"struct "} else {""}, it.name.as_ref().unwrap())); - match g { - Some(g) => try!(write!(w, "{}{}", *g, WhereClause(g))), - None => {} + if let Some(g) = g { + try!(write!(w, "{}{}", *g, WhereClause(g))) } match ty { doctree::Plain => { @@ -2452,7 +2420,7 @@ fn render_assoc_items(w: &mut fmt::Formatter, } } if let AssocItemRender::DerefFor { .. } = what { - return Ok(()) + return Ok(()); } if !traits.is_empty() { let deref_impl = traits.iter().find(|t| { @@ -2533,10 +2501,17 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi link: AssocItemLink, render_static: bool, outer_version: Option<&str>) -> fmt::Result { let name = item.name.as_ref().unwrap(); + + let is_static = match item.inner { + clean::MethodItem(ref method) => method.self_ == SelfTy::SelfStatic, + clean::TyMethodItem(ref method) => method.self_ == SelfTy::SelfStatic, + _ => false + }; + match item.inner { clean::MethodItem(..) | clean::TyMethodItem(..) => { // Only render when the method is not static or we allow static methods - if !is_static_method(item) || render_static { + if !is_static || render_static { let id = derive_id(format!("method.{}", name)); try!(write!(w, "

", id, shortty(item))); try!(render_stability_since_raw(w, item.stable_since(), outer_version)); @@ -2572,22 +2547,11 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi _ => panic!("can't make docs for trait item with name {:?}", item.name) } - return if let AssocItemLink::Anchor = link { - if is_static_method(item) && !render_static { - Ok(()) - } else { + match link { + AssocItemLink::Anchor if !is_static || render_static => { document(w, cx, item) - } - } else { - Ok(()) - }; - - fn is_static_method(item: &clean::Item) -> bool { - match item.inner { - clean::MethodItem(ref method) => method.self_ == SelfTy::SelfStatic, - clean::TyMethodItem(ref method) => method.self_ == SelfTy::SelfStatic, - _ => false - } + }, + _ => Ok(()), } } @@ -2605,9 +2569,8 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi outer_version: Option<&str>) -> fmt::Result { for trait_item in &t.items { let n = trait_item.name.clone(); - match i.items.iter().find(|m| { m.name == n }) { - Some(..) => continue, - None => {} + if i.items.iter().find(|m| { m.name == n }).is_some() { + continue; } try!(doctraititem(w, cx, trait_item, AssocItemLink::GotoSource(did), render_static, @@ -2623,7 +2586,6 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi if let Some(clean::ResolvedPath { did, .. }) = i.impl_.trait_ { if let Some(t) = cache().traits.get(&did) { try!(render_default_items(w, cx, did, t, &i.impl_, render_header, outer_version)); - } } try!(write!(w, "")); diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index ffb15d157b066..53003c5ee52ad 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -283,19 +283,15 @@ pub fn main_args(args: &[String]) -> isize { info!("going to format"); match matches.opt_str("w").as_ref().map(|s| &**s) { Some("html") | None => { - match html::render::run(krate, &external_html, - output.unwrap_or(PathBuf::from("doc")), - passes.into_iter().collect()) { - Ok(()) => {} - Err(e) => panic!("failed to generate documentation: {}", e), - } + html::render::run(krate, &external_html, + output.unwrap_or(PathBuf::from("doc")), + passes.into_iter().collect()) + .expect("failed to generate documentation") } Some("json") => { - match json_output(krate, json_plugins, - output.unwrap_or(PathBuf::from("doc.json"))) { - Ok(()) => {} - Err(e) => panic!("failed to write json: {}", e), - } + json_output(krate, json_plugins, + output.unwrap_or(PathBuf::from("doc.json"))) + .expect("failed to write json") } Some(s) => { println!("unknown output format: {}", s); @@ -332,18 +328,10 @@ fn parse_externs(matches: &getopts::Matches) -> Result { let mut externs = HashMap::new(); for arg in &matches.opt_strs("extern") { let mut parts = arg.splitn(2, '='); - let name = match parts.next() { - Some(s) => s, - None => { - return Err("--extern value must not be empty".to_string()); - } - }; - let location = match parts.next() { - Some(s) => s, - None => { - return Err("--extern value must be of the format `foo=bar`".to_string()); - } - }; + let name = try!(parts.next().ok_or("--extern value must not be empty".to_string())); + let location = try!(parts.next() + .ok_or("--extern value must be of the format `foo=bar`" + .to_string())); let name = name.to_string(); externs.entry(name).or_insert(vec![]).push(location.to_string()); } @@ -448,17 +436,16 @@ fn rust_input(cratefile: &str, externs: core::Externs, matches: &getopts::Matche // Run everything! info!("Executing passes/plugins"); let (krate, json) = pm.run_plugins(krate); - return Output { krate: krate, json_plugins: json, passes: passes, }; + Output { krate: krate, json_plugins: json, passes: passes } } /// This input format purely deserializes the json output file. No passes are /// run over the deserialized output. fn json_input(input: &str) -> Result { let mut bytes = Vec::new(); - match File::open(input).and_then(|mut f| f.read_to_end(&mut bytes)) { - Ok(_) => {} - Err(e) => return Err(format!("couldn't open {}: {}", input, e)), - }; + if let Err(e) = File::open(input).and_then(|mut f| f.read_to_end(&mut bytes)) { + return Err(format!("couldn't open {}: {}", input, e)) + } match json::from_reader(&mut &bytes[..]) { Err(s) => Err(format!("{:?}", s)), Ok(Json::Object(obj)) => { @@ -507,21 +494,13 @@ fn json_output(krate: clean::Crate, res: Vec , json.insert("schema".to_string(), Json::String(SCHEMA_VERSION.to_string())); let plugins_json = res.into_iter() .filter_map(|opt| { - match opt { - None => None, - Some((string, json)) => { - Some((string.to_string(), json)) - } - } + opt.map(|(string, json)| (string.to_string(), json)) }).collect(); // FIXME #8335: yuck, Rust -> str -> JSON round trip! No way to .encode // straight to the Rust JSON representation. let crate_json_str = format!("{}", json::as_json(&krate)); - let crate_json = match json::from_str(&crate_json_str) { - Ok(j) => j, - Err(e) => panic!("Rust generated JSON is invalid: {:?}", e) - }; + let crate_json = json::from_str(&crate_json_str).expect("Rust generated JSON is invalid"); json.insert("crate".to_string(), crate_json); json.insert("plugins".to_string(), Json::Object(plugins_json)); diff --git a/src/librustdoc/passes.rs b/src/librustdoc/passes.rs index 957957eaec6e5..46e801631bf5b 100644 --- a/src/librustdoc/passes.rs +++ b/src/librustdoc/passes.rs @@ -205,22 +205,19 @@ impl<'a> fold::DocFolder for Stripper<'a> { self.fold_item_recur(i) }; - match i { - Some(i) => { - match i.inner { - // emptied modules/impls have no need to exist - clean::ModuleItem(ref m) - if m.items.is_empty() && - i.doc_value().is_none() => None, - clean::ImplItem(ref i) if i.items.is_empty() => None, - _ => { - self.retained.insert(i.def_id); - Some(i) - } + i.and_then(|i| { + match i.inner { + // emptied modules/impls have no need to exist + clean::ModuleItem(ref m) + if m.items.is_empty() && + i.doc_value().is_none() => None, + clean::ImplItem(ref i) if i.items.is_empty() => None, + _ => { + self.retained.insert(i.def_id); + Some(i) } } - None => None, - } + }) } } @@ -275,13 +272,11 @@ pub fn collapse_docs(krate: clean::Crate) -> plugins::PluginResult { let mut docstr = String::new(); let mut i = i; for attr in &i.attrs { - match *attr { - clean::NameValue(ref x, ref s) - if "doc" == *x => { + if let clean::NameValue(ref x, ref s) = *attr { + if "doc" == *x { docstr.push_str(s); docstr.push('\n'); - }, - _ => () + } } } let mut a: Vec = i.attrs.iter().filter(|&a| match a { diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 39550488a9e87..e97357f98898b 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -121,9 +121,8 @@ pub fn run(input: &str, let mut v = RustdocVisitor::new(&ctx, None); v.visit(ctx.map.krate()); let mut krate = v.clean(&ctx); - match crate_name { - Some(name) => krate.name = name, - None => {} + if let Some(name) = crate_name { + krate.name = name; } let (krate, _) = passes::collapse_docs(krate); let (krate, _) = passes::unindent_comments(krate); @@ -334,13 +333,10 @@ pub fn maketest(s: &str, cratename: Option<&str>, dont_insert_main: bool, // Don't inject `extern crate std` because it's already injected by the // compiler. if !s.contains("extern crate") && !opts.no_crate_inject && cratename != Some("std") { - match cratename { - Some(cratename) => { - if s.contains(cratename) { - prog.push_str(&format!("extern crate {};\n", cratename)); - } + if let Some(cratename) = cratename { + if s.contains(cratename) { + prog.push_str(&format!("extern crate {};\n", cratename)); } - None => {} } } if dont_insert_main || s.contains("fn main") { @@ -476,12 +472,7 @@ impl DocFolder for Collector { _ => typename_if_impl(&item) }; - let pushed = if let Some(name) = current_name { - self.names.push(name); - true - } else { - false - }; + let pushed = current_name.map(|name| self.names.push(name)).is_some(); if let Some(doc) = item.doc_value() { self.cnt = 0; diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index ba389bc42b78c..bc6b4f83984b0 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -263,13 +263,9 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { let name = renamed.unwrap_or(item.name); match item.node { hir::ItemExternCrate(ref p) => { - let path = match *p { - None => None, - Some(x) => Some(x.to_string()), - }; om.extern_crates.push(ExternCrate { name: name, - path: path, + path: p.map(|x|x.to_string()), vis: item.vis, attrs: item.attrs.clone(), whence: item.span, From 2a28b69948e13ec09a8a7701fa4d9001e880ad5f Mon Sep 17 00:00:00 2001 From: mitaa Date: Sun, 28 Feb 2016 10:12:41 +0100 Subject: [PATCH 3/6] Refactor rustdocs attribute handling --- src/librustdoc/clean/inline.rs | 20 +----- src/librustdoc/clean/mod.rs | 111 ++++++++++++++++----------------- src/librustdoc/html/render.rs | 47 +++----------- src/librustdoc/lib.rs | 39 +++++------- src/librustdoc/passes.rs | 4 +- 5 files changed, 85 insertions(+), 136 deletions(-) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 6fd80feaac747..32f3706675ad2 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -26,7 +26,7 @@ use rustc::middle::const_eval; use core::DocContext; use doctree; -use clean; +use clean::{self, Attributes}; use super::{Clean, ToSource}; @@ -253,7 +253,7 @@ pub fn build_impls(cx: &DocContext, tcx: &TyCtxt, cstore::DlImpl(did) => build_impl(cx, tcx, did, impls), cstore::DlDef(Def::Mod(did)) => { // Don't recurse if this is a #[doc(hidden)] module - if load_attrs(cx, tcx, did).iter().any(|a| is_doc_hidden(a)) { + if load_attrs(cx, tcx, did).list_def("doc").has_word("hidden") { return; } @@ -282,7 +282,7 @@ pub fn build_impl(cx: &DocContext, if let Some(ref t) = associated_trait { // 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)) { + if trait_attrs.list_def("doc").has_word("hidden") { return } } @@ -422,20 +422,6 @@ pub fn build_impl(cx: &DocContext, }); } -fn is_doc_hidden(a: &clean::Attribute) -> bool { - match *a { - clean::List(ref name, ref inner) if *name == "doc" => { - inner.iter().any(|a| { - match *a { - clean::Word(ref s) => *s == "hidden", - _ => false, - } - }) - } - _ => false - } -} - fn build_module(cx: &DocContext, tcx: &TyCtxt, did: DefId) -> clean::Module { let mut items = Vec::new(); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 96a56a7c113f3..20bcf759cf7c4 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -258,7 +258,7 @@ pub struct Item { pub source: Span, /// Not everything has a name. E.g., impls pub name: Option, - pub attrs: Vec , + pub attrs: Vec, pub inner: ItemEnum, pub visibility: Option, pub def_id: DefId, @@ -267,49 +267,10 @@ pub struct Item { } impl Item { - /// Finds the `doc` attribute as a List and returns the list of attributes - /// nested inside. - pub fn doc_list<'a>(&'a self) -> Option<&'a [Attribute]> { - for attr in &self.attrs { - match *attr { - List(ref x, ref list) if "doc" == *x => { - return Some(list); - } - _ => {} - } - } - return None; - } - /// Finds the `doc` attribute as a NameValue and returns the corresponding /// value found. pub fn doc_value<'a>(&'a self) -> Option<&'a str> { - for attr in &self.attrs { - match *attr { - NameValue(ref x, ref v) if "doc" == *x => { - return Some(v); - } - _ => {} - } - } - return None; - } - - pub fn is_hidden_from_doc(&self) -> bool { - match self.doc_list() { - Some(l) => { - for innerattr in l { - match *innerattr { - Word(ref s) if "hidden" == *s => { - return true - } - _ => (), - } - } - }, - None => () - } - return false; + self.attrs.value("doc") } pub fn is_mod(&self) -> bool { @@ -438,10 +399,54 @@ impl Clean for doctree::Module { } } +pub trait Attributes { + fn has_word(&self, &str) -> bool; + fn value<'a>(&'a self, &str) -> Option<&'a str>; + fn list_def<'a>(&'a self, &str) -> &'a [Attribute]; +} + +impl Attributes for [Attribute] { + /// Returns whether the attribute list contains a specific `Word` + fn has_word(&self, word: &str) -> bool { + for attr in self { + if let Word(ref w) = *attr { + if word == *w { + return true; + } + } + } + false + } + + /// Finds an attribute as NameValue and returns the corresponding value found. + fn value<'a>(&'a self, name: &str) -> Option<&'a str> { + for attr in self { + if let NameValue(ref x, ref v) = *attr { + if name == *x { + return Some(v); + } + } + } + None + } + + /// Finds an attribute as List and returns the list of attributes nested inside. + fn list_def<'a>(&'a self, name: &str) -> &'a [Attribute] { + for attr in self { + if let List(ref x, ref list) = *attr { + if name == *x { + return &list[..]; + } + } + } + &[] + } +} + #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)] pub enum Attribute { Word(String), - List(String, Vec ), + List(String, Vec), NameValue(String, String) } @@ -1513,24 +1518,16 @@ impl PrimitiveType { } fn find(attrs: &[Attribute]) -> Option { - for attr in attrs { - let list = match *attr { - List(ref k, ref l) if *k == "doc" => l, - _ => continue, - }; - for sub_attr in list { - let value = match *sub_attr { - NameValue(ref k, ref v) - if *k == "primitive" => v, - _ => continue, - }; - match PrimitiveType::from_str(value) { - Some(p) => return Some(p), - None => {} + for attr in attrs.list_def("doc") { + if let NameValue(ref k, ref v) = *attr { + if "primitive" == *k { + if let ret@Some(..) = PrimitiveType::from_str(v) { + return ret; + } } } } - return None + None } pub fn to_string(&self) -> &'static str { diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 319c9d7d18560..f1d8369007983 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -62,7 +62,7 @@ use rustc::middle::stability; use rustc::session::config::get_unstable_features_setting; use rustc_front::hir; -use clean::{self, SelfTy}; +use clean::{self, SelfTy, Attributes}; use doctree; use fold::DocFolder; use html::escape::Escape; @@ -432,8 +432,7 @@ pub fn run(mut krate: clean::Crate, // Crawl the crate attributes looking for attributes which control how we're // going to emit HTML - let default: &[_] = &[]; - if let Some(attrs) = krate.module.as_ref().map(|m| m.doc_list().unwrap_or(default)) { + if let Some(attrs) = krate.module.as_ref().map(|m| m.attrs.list_def("doc")) { for attr in attrs { match *attr { clean::NameValue(ref x, ref s) @@ -833,28 +832,13 @@ fn extern_location(e: &clean::ExternalCrate, dst: &Path) -> ExternalLocation { // Failing that, see if there's an attribute specifying where to find this // external crate - for attr in &e.attrs { - match *attr { - clean::List(ref x, ref list) if "doc" == *x => { - for attr in list { - match *attr { - clean::NameValue(ref x, ref s) - if "html_root_url" == *x => { - if s.ends_with("/") { - return Remote(s.to_string()); - } - return Remote(format!("{}/", s)); - } - _ => {} - } - } - } - _ => {} + e.attrs.list_def("doc").value("html_root_url").map(|url| { + let mut url = url.to_owned(); + if !url.ends_with("/") { + url.push('/') } - } - - // Well, at least we tried. - return Unknown; + Remote(url) + }).unwrap_or(Unknown) // Well, at least we tried. } impl<'a> DocFolder for SourceCollector<'a> { @@ -1153,19 +1137,6 @@ impl DocFolder for Cache { // implementations elsewhere let ret = self.fold_item_recur(item).and_then(|item| { if let clean::Item { attrs, inner: clean::ImplItem(i), .. } = item { - // extract relevant documentation for this impl - let dox = match attrs.into_iter().find(|a| { - match *a { - clean::NameValue(ref x, _) - if "doc" == *x => { - true - } - _ => false - } - }) { - Some(clean::NameValue(_, dox)) => Some(dox), - Some(..) | None => None, - }; // Figure out the id of this impl. This may map to a // primitive rather than always to a struct/enum. let did = match i.for_ { @@ -1189,7 +1160,7 @@ impl DocFolder for Cache { if let Some(did) = did { self.impls.entry(did).or_insert(vec![]).push(Impl { impl_: i, - dox: dox, + dox: attrs.value("doc").map(|s|s.to_owned()), stability: item.stability.clone(), }); } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 53003c5ee52ad..3c7aadb3533c4 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -94,6 +94,8 @@ pub mod visit_ast; pub mod test; mod flock; +use clean::Attributes; + type Pass = (&'static str, // name fn(clean::Crate) -> plugins::PluginResult, // fn &'static str); // description @@ -379,32 +381,25 @@ fn rust_input(cratefile: &str, externs: core::Externs, matches: &getopts::Matche // Process all of the crate attributes, extracting plugin metadata along // with the passes which we are supposed to run. - match krate.module.as_ref().unwrap().doc_list() { - Some(nested) => { - for inner in nested { - match *inner { - clean::Word(ref x) - if "no_default_passes" == *x => { - default_passes = false; - } - clean::NameValue(ref x, ref value) - if "passes" == *x => { - for pass in value.split_whitespace() { - passes.push(pass.to_string()); - } - } - clean::NameValue(ref x, ref value) - if "plugins" == *x => { - for p in value.split_whitespace() { - plugins.push(p.to_string()); - } - } - _ => {} + for attr in krate.module.as_ref().unwrap().attrs.list_def("doc") { + match *attr { + clean::Word(ref w) if "no_default_passes" == *w => { + default_passes = false; + }, + clean::NameValue(ref name, ref value) => { + let sink = match &name[..] { + "passes" => &mut passes, + "plugins" => &mut plugins, + _ => continue, + }; + for p in value.split_whitespace() { + sink.push(p.to_string()); } } + _ => (), } - None => {} } + if default_passes { for name in DEFAULT_PASSES.iter().rev() { passes.insert(0, name.to_string()); diff --git a/src/librustdoc/passes.rs b/src/librustdoc/passes.rs index 46e801631bf5b..6293aa3c2725c 100644 --- a/src/librustdoc/passes.rs +++ b/src/librustdoc/passes.rs @@ -16,7 +16,7 @@ use std::string::String; use std::usize; use rustc_front::hir; -use clean; +use clean::{self, Attributes}; use clean::Item; use plugins; use fold; @@ -33,7 +33,7 @@ pub fn strip_hidden(krate: clean::Crate) -> plugins::PluginResult { } impl<'a> fold::DocFolder for Stripper<'a> { fn fold_item(&mut self, i: Item) -> Option { - if i.is_hidden_from_doc() { + if i.attrs.list_def("doc").has_word("hidden") { debug!("found one in strip_hidden; removing"); self.stripped.insert(i.def_id); From 032156210deaf71fddc4f8577fa2b541606ed547 Mon Sep 17 00:00:00 2001 From: mitaa Date: Sun, 28 Feb 2016 12:23:07 +0100 Subject: [PATCH 4/6] Use `Item::is_*` methods consistently --- src/librustdoc/clean/mod.rs | 24 ++++++++++++++++++++---- src/librustdoc/html/render.rs | 24 ++++++------------------ 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 20bcf759cf7c4..c2a37a555d693 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -175,9 +175,8 @@ impl<'a, 'tcx> Clean for visit_ast::RustdocVisitor<'a, 'tcx> { }; let mut tmp = Vec::new(); for child in &mut m.items { - match child.inner { - ModuleItem(..) => {} - _ => continue, + if !child.is_mod() { + continue; } let prim = match PrimitiveType::find(&child.attrs) { Some(prim) => prim, @@ -272,7 +271,12 @@ impl Item { pub fn doc_value<'a>(&'a self) -> Option<&'a str> { self.attrs.value("doc") } - + pub fn is_crate(&self) -> bool { + match self.inner { + ModuleItem(Module { items: _, is_crate: true }) => true, + _ => false + } + } pub fn is_mod(&self) -> bool { match self.inner { ModuleItem(..) => true, _ => false } } @@ -288,6 +292,18 @@ impl Item { pub fn is_fn(&self) -> bool { match self.inner { FunctionItem(..) => true, _ => false } } + pub fn is_associated_type(&self) -> bool { + match self.inner { AssociatedTypeItem(..) => true, _ => false } + } + pub fn is_associated_const(&self) -> bool { + match self.inner { AssociatedConstItem(..) => true, _ => false } + } + pub fn is_method(&self) -> bool { + match self.inner { MethodItem(..) => true, _ => false } + } + pub fn is_ty_method(&self) -> bool { + match self.inner { TyMethodItem(..) => true, _ => false } + } pub fn stability_class(&self) -> String { self.stability.as_ref().map(|ref s| { diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index f1d8369007983..88f21b67a5ac6 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1266,11 +1266,7 @@ impl Context { } title.push_str(" - Rust"); let tyname = shortty(it).to_static_str(); - let is_crate = match it.inner { - clean::ModuleItem(clean::Module { items: _, is_crate: true }) => true, - _ => false - }; - let desc = if is_crate { + let desc = if it.is_crate() { format!("API documentation for the Rust `{}` crate.", cx.layout.krate) } else { @@ -1891,18 +1887,10 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, bounds, WhereClause(&t.generics))); - let types = t.items.iter().filter(|m| { - match m.inner { clean::AssociatedTypeItem(..) => true, _ => false } - }).collect::>(); - let consts = t.items.iter().filter(|m| { - match m.inner { clean::AssociatedConstItem(..) => true, _ => false } - }).collect::>(); - let required = t.items.iter().filter(|m| { - match m.inner { clean::TyMethodItem(_) => true, _ => false } - }).collect::>(); - let provided = t.items.iter().filter(|m| { - match m.inner { clean::MethodItem(_) => true, _ => false } - }).collect::>(); + let types = t.items.iter().filter(|m| m.is_associated_type()).collect::>(); + let consts = t.items.iter().filter(|m| m.is_associated_const()).collect::>(); + let required = t.items.iter().filter(|m| m.is_ty_method()).collect::>(); + let provided = t.items.iter().filter(|m| m.is_method()).collect::>(); if t.items.is_empty() { try!(write!(w, "{{ }}")); @@ -2600,7 +2588,7 @@ impl<'a> fmt::Display for Sidebar<'a> { try!(write!(fmt, "

")); // sidebar refers to the enclosing module, not this module - let relpath = if shortty(it) == ItemType::Module { "../" } else { "" }; + let relpath = if it.is_mod() { "../" } else { "" }; try!(write!(fmt, "