Implemented #[doc(cfg(...))].

This attribute has two effects:

1. Items with this attribute and their children will have the "This is
   supported on **** only" message attached in the documentation.

2. The items' doc tests will be skipped if the configuration does not
   match.
This commit is contained in:
kennytm
2017-08-05 14:38:52 +08:00
parent 8f935fbb5b
commit a2b888675a
12 changed files with 1129 additions and 16 deletions

View File

@@ -52,8 +52,11 @@ use visit_ast;
use html::item_type::ItemType;
pub mod inline;
pub mod cfg;
mod simplify;
use self::cfg::Cfg;
// extract the stability index for a node from tcx, if possible
fn get_stability(cx: &DocContext, def_id: DefId) -> Option<Stability> {
cx.tcx.lookup_stability(def_id).clean(cx)
@@ -536,31 +539,67 @@ impl<I: IntoIterator<Item=ast::NestedMetaItem>> NestedAttributesExt for I {
pub struct Attributes {
pub doc_strings: Vec<String>,
pub other_attrs: Vec<ast::Attribute>,
pub cfg: Option<Rc<Cfg>>,
pub span: Option<syntax_pos::Span>,
}
impl Attributes {
pub fn from_ast(attrs: &[ast::Attribute]) -> Attributes {
let mut doc_strings = vec![];
let mut sp = None;
let other_attrs = attrs.iter().filter_map(|attr| {
attr.with_desugared_doc(|attr| {
if let Some(value) = attr.value_str() {
if attr.check_name("doc") {
doc_strings.push(value.to_string());
if sp.is_none() {
sp = Some(attr.span);
/// Extracts the content from an attribute `#[doc(cfg(content))]`.
fn extract_cfg(mi: &ast::MetaItem) -> Option<&ast::MetaItem> {
use syntax::ast::NestedMetaItemKind::MetaItem;
if let ast::MetaItemKind::List(ref nmis) = mi.node {
if nmis.len() == 1 {
if let MetaItem(ref cfg_mi) = nmis[0].node {
if cfg_mi.check_name("cfg") {
if let ast::MetaItemKind::List(ref cfg_nmis) = cfg_mi.node {
if cfg_nmis.len() == 1 {
if let MetaItem(ref content_mi) = cfg_nmis[0].node {
return Some(content_mi);
}
}
}
return None;
}
}
}
}
None
}
pub fn from_ast(diagnostic: &::errors::Handler, attrs: &[ast::Attribute]) -> Attributes {
let mut doc_strings = vec![];
let mut sp = None;
let mut cfg = Cfg::True;
let other_attrs = attrs.iter().filter_map(|attr| {
attr.with_desugared_doc(|attr| {
if attr.check_name("doc") {
if let Some(mi) = attr.meta() {
if let Some(value) = mi.value_str() {
// Extracted #[doc = "..."]
doc_strings.push(value.to_string());
if sp.is_none() {
sp = Some(attr.span);
}
return None;
} else if let Some(cfg_mi) = Attributes::extract_cfg(&mi) {
// Extracted #[doc(cfg(...))]
match Cfg::parse(cfg_mi) {
Ok(new_cfg) => cfg &= new_cfg,
Err(e) => diagnostic.span_err(e.span, e.msg),
}
return None;
}
}
}
Some(attr.clone())
})
}).collect();
Attributes {
doc_strings: doc_strings,
other_attrs: other_attrs,
doc_strings,
other_attrs,
cfg: if cfg == Cfg::True { None } else { Some(Rc::new(cfg)) },
span: sp,
}
}
@@ -579,8 +618,8 @@ impl AttributesExt for Attributes {
}
impl Clean<Attributes> for [ast::Attribute] {
fn clean(&self, _cx: &DocContext) -> Attributes {
Attributes::from_ast(self)
fn clean(&self, cx: &DocContext) -> Attributes {
Attributes::from_ast(cx.sess().diagnostic(), self)
}
}