From 2a28b69948e13ec09a8a7701fa4d9001e880ad5f Mon Sep 17 00:00:00 2001 From: mitaa Date: Sun, 28 Feb 2016 10:12:41 +0100 Subject: [PATCH] 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 6fd80feaac7..32f3706675a 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 96a56a7c113..20bcf759cf7 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 319c9d7d185..f1d83690079 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 53003c5ee52..3c7aadb3533 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 46e801631bf..6293aa3c272 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);