Make cfg implicitly imply doc(cfg)

This is only active when the `doc_cfg` feature is active.

The implicit cfg can be overridden via #[doc(cfg(...))], so e.g. to
hide a #[cfg] you can use something like:

```rust
 #[cfg(unix)]
 #[doc(cfg(all()))]
pub struct Unix;
```

(since `all()` is always true, it is never shown in the docs)
This commit is contained in:
Wim Looman 2020-11-03 19:45:16 +01:00 committed by Guillaume Gomez
parent 074f63648b
commit 10cdbd847f
8 changed files with 92 additions and 9 deletions

View File

@ -318,10 +318,10 @@ fn merge_attrs(
} else {
Attributes::from_ast(&both, None)
},
both.cfg(cx.sess()),
both.cfg(cx.tcx),
)
} else {
(old_attrs.clean(cx), old_attrs.cfg(cx.sess()))
(old_attrs.clean(cx), old_attrs.cfg(cx.tcx))
}
}

View File

@ -1973,7 +1973,7 @@ fn clean_extern_crate(
def_id: crate_def_id.into(),
visibility: krate.vis.clean(cx),
kind: box ExternCrateItem { src: orig_name },
cfg: attrs.cfg(cx.sess()),
cfg: attrs.cfg(cx.tcx),
}]
}

View File

@ -421,7 +421,7 @@ impl Item {
kind,
box ast_attrs.clean(cx),
cx,
ast_attrs.cfg(cx.sess()),
ast_attrs.cfg(cx.tcx),
)
}
@ -747,7 +747,7 @@ crate trait AttributesExt {
fn other_attrs(&self) -> Vec<ast::Attribute>;
fn cfg(&self, sess: &Session) -> Option<Arc<Cfg>>;
fn cfg(&self, tcx: TyCtxt<'_>) -> Option<Arc<Cfg>>;
}
impl AttributesExt for [ast::Attribute] {
@ -772,8 +772,52 @@ impl AttributesExt for [ast::Attribute] {
self.iter().filter(|attr| attr.doc_str().is_none()).cloned().collect()
}
fn cfg(&self, sess: &Session) -> Option<Arc<Cfg>> {
let mut cfg = Cfg::True;
fn cfg(&self, tcx: TyCtxt<'_>) -> Option<Arc<Cfg>> {
let sess = tcx.sess;
let doc_cfg_active = tcx.features().doc_cfg;
trait SingleExt {
type Item;
fn single(self) -> Option<Self::Item>;
}
impl<T: IntoIterator> SingleExt for T {
type Item = T::Item;
fn single(self) -> Option<Self::Item> {
let mut iter = self.into_iter();
let item = iter.next()?;
iter.next().is_none().then_some(())?;
Some(item)
}
}
let mut cfg = if doc_cfg_active {
let mut doc_cfg = self
.iter()
.filter(|attr| attr.has_name(sym::doc))
.filter_map(|attr| Some(attr.meta_item_list()?.single()?))
.filter(|attr| attr.has_name(sym::cfg))
.filter_map(|attr| Some(attr.meta_item_list()?.single()?.meta_item()?.clone()))
.peekable();
if doc_cfg.peek().is_some() {
doc_cfg
.filter_map(|attr| {
Cfg::parse(&attr).map_err(|e| sess.diagnostic().span_err(e.span, e.msg)).ok()
})
.fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
} else {
self
.iter()
.filter(|attr| attr.has_name(sym::cfg))
.filter_map(|attr| Some(attr.meta_item_list()?.single()?.meta_item()?.clone()))
.filter_map(|attr| {
Cfg::parse(&attr).map_err(|e| sess.diagnostic().span_err(e.span, e.msg)).ok()
})
.fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
}
} else {
Cfg::True
};
for attr in self.iter() {
// #[doc]

View File

@ -1123,7 +1123,7 @@ impl<'a, 'hir, 'tcx> HirCollector<'a, 'hir, 'tcx> {
let ast_attrs = self.tcx.hir().attrs(hir_id);
let mut attrs = Attributes::from_ast(ast_attrs, None);
if let Some(ref cfg) = ast_attrs.cfg(self.sess) {
if let Some(ref cfg) = ast_attrs.cfg(self.tcx) {
if !cfg.matches(&self.sess.parse_sess, Some(&self.sess.features_untracked())) {
return;
}

View File

@ -323,7 +323,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl
let import_item = clean::Item {
def_id: import_def_id.into(),
attrs: import_attrs,
cfg: ast_attrs.cfg(cx.sess()),
cfg: ast_attrs.cfg(cx.tcx()),
..myitem.clone()
};

View File

@ -5,6 +5,7 @@
#![feature(rustc_private)]
#![feature(array_methods)]
#![feature(assert_matches)]
#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(control_flow_enum)]
#![feature(box_syntax)]

View File

@ -0,0 +1,7 @@
// compile-flags:--cfg feature="worricow"
#![crate_name = "xenogenous"]
// @has 'xenogenous/struct.Worricow.html'
// @count - '//*[@class="stab portability"]' 0
#[cfg(feature = "worricow")]
pub struct Worricow;

View File

@ -0,0 +1,31 @@
#![crate_name = "funambulism"]
#![feature(doc_cfg)]
// @has 'funambulism/struct.Disorbed.html'
// @count - '//*[@class="stab portability"]' 1
// @matches - '//*[@class="stab portability"]' 'crate feature disorbed'
// compile-flags:--cfg feature="disorbed"
#[cfg(feature = "disorbed")]
pub struct Disorbed;
// @has 'funambulism/struct.Aesthesia.html'
// @count - '//*[@class="stab portability"]' 1
// @matches - '//*[@class="stab portability"]' 'crate feature aesthesia'
// compile-flags:--cfg feature="aesthesia"
#[doc(cfg(feature = "aesthesia"))]
pub struct Aesthesia;
// @has 'funambulism/struct.Pliothermic.html'
// @count - '//*[@class="stab portability"]' 1
// @matches - '//*[@class="stab portability"]' 'crate feature pliothermic'
// compile-flags:--cfg feature="epopoeist"
#[cfg(feature = "epopoeist")]
#[doc(cfg(feature = "pliothermic"))]
pub struct Pliothermic;
// @has 'funambulism/struct.Simillimum.html'
// @count - '//*[@class="stab portability"]' 0
// compile-flags:--cfg feature="simillimum"
#[cfg(feature = "simillimum")]
#[doc(cfg(all()))]
pub struct Simillimum;