Allow adding a set of cfg's to hide from being implicitly doc(cfg)'d

By adding #![doc(cfg_hide(foobar))] to the crate attributes the cfg
 #[cfg(foobar)] (and _only_ that _exact_ cfg) will not be implicitly
treated as a doc(cfg) to render a message in the documentation.
This commit is contained in:
Wim Looman 2020-11-04 21:59:35 +01:00 committed by Guillaume Gomez
parent 10cdbd847f
commit 18fdd816b7
11 changed files with 74 additions and 9 deletions

View File

@ -279,6 +279,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
gate_doc!( gate_doc!(
cfg => doc_cfg cfg => doc_cfg
cfg_hide => doc_cfg_hide
masked => doc_masked masked => doc_masked
notable_trait => doc_notable_trait notable_trait => doc_notable_trait
keyword => doc_keyword keyword => doc_keyword

View File

@ -380,6 +380,9 @@ declare_features! (
/// Allows `#[doc(cfg(...))]`. /// Allows `#[doc(cfg(...))]`.
(active, doc_cfg, "1.21.0", Some(43781), None), (active, doc_cfg, "1.21.0", Some(43781), None),
/// Allows `#[doc(cfg_hide(...))]`.
(active, doc_cfg_hide, "1.49.0", Some(43781), None),
/// Allows `#[doc(masked)]`. /// Allows `#[doc(masked)]`.
(active, doc_masked, "1.21.0", Some(44027), None), (active, doc_masked, "1.21.0", Some(44027), None),

View File

@ -399,6 +399,7 @@ symbols! {
cfg_attr_multi, cfg_attr_multi,
cfg_doctest, cfg_doctest,
cfg_eval, cfg_eval,
cfg_hide,
cfg_panic, cfg_panic,
cfg_sanitize, cfg_sanitize,
cfg_target_abi, cfg_target_abi,
@ -547,6 +548,7 @@ symbols! {
doc, doc,
doc_alias, doc_alias,
doc_cfg, doc_cfg,
doc_cfg_hide,
doc_keyword, doc_keyword,
doc_masked, doc_masked,
doc_notable_trait, doc_notable_trait,

View File

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

View File

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

View File

@ -421,7 +421,7 @@ impl Item {
kind, kind,
box ast_attrs.clean(cx), box ast_attrs.clean(cx),
cx, cx,
ast_attrs.cfg(cx.tcx), ast_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg),
) )
} }
@ -747,7 +747,7 @@ crate trait AttributesExt {
fn other_attrs(&self) -> Vec<ast::Attribute>; fn other_attrs(&self) -> Vec<ast::Attribute>;
fn cfg(&self, tcx: TyCtxt<'_>) -> Option<Arc<Cfg>>; fn cfg(&self, tcx: TyCtxt<'_>, hidden_cfg: &FxHashSet<Cfg>) -> Option<Arc<Cfg>>;
} }
impl AttributesExt for [ast::Attribute] { impl AttributesExt for [ast::Attribute] {
@ -772,7 +772,7 @@ impl AttributesExt for [ast::Attribute] {
self.iter().filter(|attr| attr.doc_str().is_none()).cloned().collect() self.iter().filter(|attr| attr.doc_str().is_none()).cloned().collect()
} }
fn cfg(&self, tcx: TyCtxt<'_>) -> Option<Arc<Cfg>> { fn cfg(&self, tcx: TyCtxt<'_>, hidden_cfg: &FxHashSet<Cfg>) -> Option<Arc<Cfg>> {
let sess = tcx.sess; let sess = tcx.sess;
let doc_cfg_active = tcx.features().doc_cfg; let doc_cfg_active = tcx.features().doc_cfg;
@ -813,6 +813,7 @@ impl AttributesExt for [ast::Attribute] {
.filter_map(|attr| { .filter_map(|attr| {
Cfg::parse(&attr).map_err(|e| sess.diagnostic().span_err(e.span, e.msg)).ok() Cfg::parse(&attr).map_err(|e| sess.diagnostic().span_err(e.span, e.msg)).ok()
}) })
.filter(|cfg| !hidden_cfg.contains(cfg))
.fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg) .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
} }
} else { } else {
@ -844,6 +845,8 @@ impl AttributesExt for [ast::Attribute] {
} }
} }
// treat #[target_feature(enable = "feat")] attributes as if they were
// #[doc(cfg(target_feature = "feat"))] attributes as well
for attr in self.lists(sym::target_feature) { for attr in self.lists(sym::target_feature) {
if attr.has_name(sym::enable) { if attr.has_name(sym::enable) {
if let Some(feat) = attr.value_str() { if let Some(feat) = attr.value_str() {

View File

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

View File

@ -119,6 +119,8 @@ crate struct Cache {
/// ///
/// Links are indexed by the DefId of the item they document. /// Links are indexed by the DefId of the item they document.
crate intra_doc_links: FxHashMap<ItemId, Vec<clean::ItemLink>>, crate intra_doc_links: FxHashMap<ItemId, Vec<clean::ItemLink>>,
/// Cfg that have been hidden via #![doc(cfg_hide(...))]
crate hidden_cfg: FxHashSet<clean::cfg::Cfg>,
} }
/// This struct is used to wrap the `cache` and `tcx` in order to run `DocFolder`. /// This struct is used to wrap the `cache` and `tcx` in order to run `DocFolder`.

View File

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

View File

@ -3,6 +3,7 @@
use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::CRATE_HIR_ID;
use rustc_hir::def::{DefKind, Res}; use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_hir::Node; use rustc_hir::Node;
@ -15,7 +16,7 @@ use rustc_span::symbol::{kw, sym, Symbol};
use std::mem; use std::mem;
use crate::clean::{self, AttributesExt, NestedAttributesExt}; use crate::clean::{self, cfg::Cfg, AttributesExt, NestedAttributesExt};
use crate::core; use crate::core;
use crate::doctree::*; use crate::doctree::*;
@ -97,6 +98,27 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
} }
} }
} }
self.cx.cache.hidden_cfg = self.cx.tcx.hir().attrs(CRATE_HIR_ID)
.iter()
.filter(|attr| attr.has_name(sym::doc))
.flat_map(|attr| attr.meta_item_list().into_iter().flatten())
.filter(|attr| attr.has_name(sym::cfg_hide))
.flat_map(|attr| {
attr.meta_item_list()
.unwrap_or(&[])
.iter()
.filter_map(|attr| {
Some(
Cfg::parse(attr.meta_item()?)
.map_err(|e| self.cx.sess().diagnostic().span_err(e.span, e.msg))
.ok()?,
)
})
.collect::<Vec<_>>()
})
.collect();
self.cx.cache.exact_paths = self.exact_paths; self.cx.cache.exact_paths = self.exact_paths;
top_level_module top_level_module
} }

View File

@ -0,0 +1,32 @@
#![crate_name = "oud"]
#![feature(doc_cfg, doc_cfg_hide)]
#![doc(cfg_hide(feature = "solecism"))]
// @has 'oud/struct.Solecism.html'
// @count - '//*[@class="stab portability"]' 0
// compile-flags:--cfg feature="solecism"
#[cfg(feature = "solecism")]
pub struct Solecism;
// @has 'oud/struct.Scribacious.html'
// @count - '//*[@class="stab portability"]' 1
// @matches - '//*[@class="stab portability"]' 'crate feature solecism'
#[cfg(feature = "solecism")]
#[doc(cfg(feature = "solecism"))]
pub struct Scribacious;
// @has 'oud/struct.Hyperdulia.html'
// @count - '//*[@class="stab portability"]' 1
// @matches - '//*[@class="stab portability"]' 'crate feature hyperdulia'
// compile-flags:--cfg feature="hyperdulia"
#[cfg(feature = "solecism")]
#[cfg(feature = "hyperdulia")]
pub struct Hyperdulia;
// @has 'oud/struct.Oystercatcher.html'
// @count - '//*[@class="stab portability"]' 1
// @matches - '//*[@class="stab portability"]' 'crate features solecism and oystercatcher'
// compile-flags:--cfg feature="oystercatcher"
#[cfg(all(feature = "solecism", feature = "oystercatcher"))]
pub struct Oystercatcher;