From 682ef4db8060a0b26266cdcf5631c5776cd45e0a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 13 Jan 2022 15:50:11 +0100 Subject: [PATCH 1/4] Exclude "test" from doc_auto_cfg rendering --- src/librustdoc/clean/cfg.rs | 107 ++++++++++++++++++++++------------ src/librustdoc/clean/types.rs | 5 +- 2 files changed, 73 insertions(+), 39 deletions(-) diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index dfee2b702c1..2c1dcad1afc 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -43,15 +43,81 @@ crate struct InvalidCfgError { impl Cfg { /// Parses a `NestedMetaItem` into a `Cfg`. - fn parse_nested(nested_cfg: &NestedMetaItem) -> Result { + fn parse_nested( + nested_cfg: &NestedMetaItem, + exclude: &[Symbol], + ) -> Result, InvalidCfgError> { match nested_cfg { - NestedMetaItem::MetaItem(ref cfg) => Cfg::parse(cfg), + NestedMetaItem::MetaItem(ref cfg) => Cfg::parse_without(cfg, exclude), NestedMetaItem::Literal(ref lit) => { Err(InvalidCfgError { msg: "unexpected literal", span: lit.span }) } } } + crate fn parse_without( + cfg: &MetaItem, + exclude: &[Symbol], + ) -> Result, InvalidCfgError> { + let name = match cfg.ident() { + Some(ident) => ident.name, + None => { + return Err(InvalidCfgError { + msg: "expected a single identifier", + span: cfg.span, + }); + } + }; + match cfg.kind { + MetaItemKind::Word => { + if exclude.contains(&name) { + Ok(None) + } else { + Ok(Some(Cfg::Cfg(name, None))) + } + } + MetaItemKind::NameValue(ref lit) => match lit.kind { + LitKind::Str(value, _) => { + if exclude.contains(&name) { + Ok(None) + } else { + Ok(Some(Cfg::Cfg(name, Some(value)))) + } + } + _ => Err(InvalidCfgError { + // FIXME: if the main #[cfg] syntax decided to support non-string literals, + // this should be changed as well. + msg: "value of cfg option should be a string literal", + span: lit.span, + }), + }, + MetaItemKind::List(ref items) => { + let sub_cfgs = items.iter().filter_map(|i| match Cfg::parse_nested(i, exclude) { + Ok(Some(c)) => Some(Ok(c)), + Err(e) => Some(Err(e)), + _ => None, + }); + let ret = match name { + sym::all => sub_cfgs.fold(Ok(Cfg::True), |x, y| Ok(x? & y?)), + sym::any => sub_cfgs.fold(Ok(Cfg::False), |x, y| Ok(x? | y?)), + sym::not => { + let mut sub_cfgs = sub_cfgs.collect::>(); + if sub_cfgs.len() == 1 { + Ok(!sub_cfgs.pop().unwrap()?) + } else { + Err(InvalidCfgError { msg: "expected 1 cfg-pattern", span: cfg.span }) + } + } + _ => Err(InvalidCfgError { msg: "invalid predicate", span: cfg.span }), + }; + match ret { + Ok(c) => Ok(Some(c)), + Err(e) => Err(e), + } + } + } + } + /// Parses a `MetaItem` into a `Cfg`. /// /// The `MetaItem` should be the content of the `#[cfg(...)]`, e.g., `unix` or @@ -60,42 +126,7 @@ impl Cfg { /// If the content is not properly formatted, it will return an error indicating what and where /// the error is. crate fn parse(cfg: &MetaItem) -> Result { - let name = match cfg.ident() { - Some(ident) => ident.name, - None => { - return Err(InvalidCfgError { - msg: "expected a single identifier", - span: cfg.span, - }); - } - }; - match cfg.kind { - MetaItemKind::Word => Ok(Cfg::Cfg(name, None)), - MetaItemKind::NameValue(ref lit) => match lit.kind { - LitKind::Str(value, _) => Ok(Cfg::Cfg(name, Some(value))), - _ => Err(InvalidCfgError { - // FIXME: if the main #[cfg] syntax decided to support non-string literals, - // this should be changed as well. - msg: "value of cfg option should be a string literal", - span: lit.span, - }), - }, - MetaItemKind::List(ref items) => { - let mut sub_cfgs = items.iter().map(Cfg::parse_nested); - match name { - sym::all => sub_cfgs.fold(Ok(Cfg::True), |x, y| Ok(x? & y?)), - sym::any => sub_cfgs.fold(Ok(Cfg::False), |x, y| Ok(x? | y?)), - sym::not => { - if sub_cfgs.len() == 1 { - Ok(!sub_cfgs.next().unwrap()?) - } else { - Err(InvalidCfgError { msg: "expected 1 cfg-pattern", span: cfg.span }) - } - } - _ => Err(InvalidCfgError { msg: "invalid predicate", span: cfg.span }), - } - } - } + Self::parse_without(cfg, &[]).map(|ret| ret.unwrap()) } /// Checks whether the given configuration can be matched in the current session. diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index fac1a0817e0..347f9d0a47c 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -831,7 +831,10 @@ impl AttributesExt for [ast::Attribute] { self.iter() .filter(|attr| attr.has_name(sym::cfg)) .filter_map(|attr| single(attr.meta_item_list()?)) - .filter_map(|attr| Cfg::parse(attr.meta_item()?).ok()) + .filter_map(|attr| match Cfg::parse_without(attr.meta_item()?, &[sym::test]) { + Ok(Some(c)) => Some(c), + _ => None, + }) .filter(|cfg| !hidden_cfg.contains(cfg)) .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg) } else { From fd005f53c204136732c446dc476afc1266de730b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 13 Jan 2022 15:50:21 +0100 Subject: [PATCH 2/4] Update doc_auto_cfg test --- src/test/rustdoc/doc-auto-cfg.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/test/rustdoc/doc-auto-cfg.rs b/src/test/rustdoc/doc-auto-cfg.rs index fcdd8354569..57dd0529535 100644 --- a/src/test/rustdoc/doc-auto-cfg.rs +++ b/src/test/rustdoc/doc-auto-cfg.rs @@ -3,6 +3,12 @@ #![crate_name = "foo"] // @has foo/fn.foo.html -// @has - '//*[@class="item-info"]/*[@class="stab portability"]' 'non-test' -#[cfg(not(test))] +// @has - '//*[@class="item-info"]/*[@class="stab portability"]' 'non-doctest' +#[cfg(not(doctest))] pub fn foo() {} + +// @has foo/fn.bar.html +// @has - '//*[@class="item-info"]/*[@class="stab portability"]' 'doc' +// @!has - '//*[@class="item-info"]/*[@class="stab portability"]' 'test' +#[cfg(any(test, doc))] +pub fn bar() {} From caec4a23f201ff4e2bbfc3f8fd8b97e5e64fc20d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 16 Jan 2022 21:03:16 +0100 Subject: [PATCH 3/4] Extra cfg_hide a bit to handle inner cfgs --- src/librustdoc/clean/cfg.rs | 21 ++++++++------------- src/librustdoc/clean/types.rs | 3 +-- src/librustdoc/visit_ast.rs | 1 + src/test/rustdoc/doc-cfg-hide.rs | 2 +- 4 files changed, 11 insertions(+), 16 deletions(-) diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 2c1dcad1afc..afa02f1e5c7 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -8,6 +8,7 @@ use std::mem; use std::ops; use rustc_ast::{LitKind, MetaItem, MetaItemKind, NestedMetaItem}; +use rustc_data_structures::fx::FxHashSet; use rustc_feature::Features; use rustc_session::parse::ParseSess; use rustc_span::symbol::{sym, Symbol}; @@ -45,7 +46,7 @@ impl Cfg { /// Parses a `NestedMetaItem` into a `Cfg`. fn parse_nested( nested_cfg: &NestedMetaItem, - exclude: &[Symbol], + exclude: &FxHashSet, ) -> Result, InvalidCfgError> { match nested_cfg { NestedMetaItem::MetaItem(ref cfg) => Cfg::parse_without(cfg, exclude), @@ -57,7 +58,7 @@ impl Cfg { crate fn parse_without( cfg: &MetaItem, - exclude: &[Symbol], + exclude: &FxHashSet, ) -> Result, InvalidCfgError> { let name = match cfg.ident() { Some(ident) => ident.name, @@ -70,19 +71,13 @@ impl Cfg { }; match cfg.kind { MetaItemKind::Word => { - if exclude.contains(&name) { - Ok(None) - } else { - Ok(Some(Cfg::Cfg(name, None))) - } + let cfg = Cfg::Cfg(name, None); + if exclude.contains(&cfg) { Ok(None) } else { Ok(Some(cfg)) } } MetaItemKind::NameValue(ref lit) => match lit.kind { LitKind::Str(value, _) => { - if exclude.contains(&name) { - Ok(None) - } else { - Ok(Some(Cfg::Cfg(name, Some(value)))) - } + let cfg = Cfg::Cfg(name, Some(value)); + if exclude.contains(&cfg) { Ok(None) } else { Ok(Some(cfg)) } } _ => Err(InvalidCfgError { // FIXME: if the main #[cfg] syntax decided to support non-string literals, @@ -126,7 +121,7 @@ impl Cfg { /// If the content is not properly formatted, it will return an error indicating what and where /// the error is. crate fn parse(cfg: &MetaItem) -> Result { - Self::parse_without(cfg, &[]).map(|ret| ret.unwrap()) + Self::parse_without(cfg, &FxHashSet::default()).map(|ret| ret.unwrap()) } /// Checks whether the given configuration can be matched in the current session. diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 347f9d0a47c..92e8b893115 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -831,11 +831,10 @@ impl AttributesExt for [ast::Attribute] { self.iter() .filter(|attr| attr.has_name(sym::cfg)) .filter_map(|attr| single(attr.meta_item_list()?)) - .filter_map(|attr| match Cfg::parse_without(attr.meta_item()?, &[sym::test]) { + .filter_map(|attr| match Cfg::parse_without(attr.meta_item()?, hidden_cfg) { Ok(Some(c)) => Some(c), _ => None, }) - .filter(|cfg| !hidden_cfg.contains(cfg)) .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg) } else { Cfg::True diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 90cb5d586c2..2cbb3324a5e 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -141,6 +141,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { }) .collect::>() }) + .chain([Cfg::Cfg(sym::test, None)].into_iter()) .collect(); self.cx.cache.exact_paths = self.exact_paths; diff --git a/src/test/rustdoc/doc-cfg-hide.rs b/src/test/rustdoc/doc-cfg-hide.rs index 424fa6d6a91..636957fe998 100644 --- a/src/test/rustdoc/doc-cfg-hide.rs +++ b/src/test/rustdoc/doc-cfg-hide.rs @@ -26,7 +26,7 @@ pub struct Hyperdulia; // @has 'oud/struct.Oystercatcher.html' // @count - '//*[@class="stab portability"]' 1 -// @matches - '//*[@class="stab portability"]' 'crate features solecism and oystercatcher' +// @matches - '//*[@class="stab portability"]' 'crate feature oystercatcher only' // compile-flags:--cfg feature="oystercatcher" #[cfg(all(feature = "solecism", feature = "oystercatcher"))] pub struct Oystercatcher; From b0df7653d0cc7256e9bb34a0bc3c7e00f3afaea7 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 20 Jan 2022 22:13:32 +0100 Subject: [PATCH 4/4] More clean up --- src/librustdoc/clean/cfg.rs | 7 ++----- src/librustdoc/clean/types.rs | 5 ++--- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index afa02f1e5c7..b72d2624177 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -87,11 +87,8 @@ impl Cfg { }), }, MetaItemKind::List(ref items) => { - let sub_cfgs = items.iter().filter_map(|i| match Cfg::parse_nested(i, exclude) { - Ok(Some(c)) => Some(Ok(c)), - Err(e) => Some(Err(e)), - _ => None, - }); + let sub_cfgs = + items.iter().filter_map(|i| Cfg::parse_nested(i, exclude).transpose()); let ret = match name { sym::all => sub_cfgs.fold(Ok(Cfg::True), |x, y| Ok(x? & y?)), sym::any => sub_cfgs.fold(Ok(Cfg::False), |x, y| Ok(x? | y?)), diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 92e8b893115..7ae7b940f26 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -831,9 +831,8 @@ impl AttributesExt for [ast::Attribute] { self.iter() .filter(|attr| attr.has_name(sym::cfg)) .filter_map(|attr| single(attr.meta_item_list()?)) - .filter_map(|attr| match Cfg::parse_without(attr.meta_item()?, hidden_cfg) { - Ok(Some(c)) => Some(c), - _ => None, + .filter_map(|attr| { + Cfg::parse_without(attr.meta_item()?, hidden_cfg).ok().flatten() }) .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg) } else {