From 14ed92c33f2505241001e06c6d34f1c7d538fb66 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 26 Jun 2023 13:47:19 +0200 Subject: [PATCH 1/4] Don't merge cfg and doc(cfg) attributes for re-exports --- src/librustdoc/clean/mod.rs | 74 +++++++++++++----------- src/librustdoc/html/render/print_item.rs | 13 +---- 2 files changed, 42 insertions(+), 45 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index dc9098d3ade7b..6619288f9cb41 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2648,6 +2648,38 @@ fn filter_tokens_from_list( tokens } +fn filter_doc_attr_ident(ident: Symbol, is_inline: bool) -> bool { + if is_inline { + ident == sym::hidden || ident == sym::inline || ident == sym::no_inline + } else { + ident == sym::cfg + } +} + +fn filter_doc_attr(normal: &mut ast::NormalAttr, is_inline: bool) { + match normal.item.args { + ast::AttrArgs::Delimited(ref mut args) => { + let tokens = filter_tokens_from_list(&args.tokens, |token| { + !matches!( + token, + TokenTree::Token( + Token { + kind: TokenKind::Ident( + ident, + _, + ), + .. + }, + _, + ) if filter_doc_attr_ident(*ident, is_inline), + ) + }); + args.tokens = TokenStream::new(tokens); + } + ast::AttrArgs::Empty | ast::AttrArgs::Eq(..) => {} + } +} + /// When inlining items, we merge their attributes (and all the reexports attributes too) with the /// final reexport. For example: /// @@ -2674,13 +2706,6 @@ fn add_without_unwanted_attributes<'hir>( is_inline: bool, import_parent: Option, ) { - // If it's not `#[doc(inline)]`, we don't want all attributes, otherwise we keep everything. - if !is_inline { - for attr in new_attrs { - attrs.push((Cow::Borrowed(attr), import_parent)); - } - return; - } for attr in new_attrs { if matches!(attr.kind, ast::AttrKind::DocComment(..)) { attrs.push((Cow::Borrowed(attr), import_parent)); @@ -2689,33 +2714,14 @@ fn add_without_unwanted_attributes<'hir>( let mut attr = attr.clone(); match attr.kind { ast::AttrKind::Normal(ref mut normal) => { - if let [ident] = &*normal.item.path.segments - && let ident = ident.ident.name - && ident == sym::doc - { - match normal.item.args { - ast::AttrArgs::Delimited(ref mut args) => { - let tokens = filter_tokens_from_list(&args.tokens, |token| { - !matches!( - token, - TokenTree::Token( - Token { - kind: TokenKind::Ident( - sym::hidden | sym::inline | sym::no_inline, - _, - ), - .. - }, - _, - ), - ) - }); - args.tokens = TokenStream::new(tokens); - attrs.push((Cow::Owned(attr), import_parent)); - } - ast::AttrArgs::Empty | ast::AttrArgs::Eq(..) => { - attrs.push((Cow::Owned(attr), import_parent)); - } + if let [ident] = &*normal.item.path.segments { + let ident = ident.ident.name; + if ident == sym::doc { + filter_doc_attr(normal, is_inline); + attrs.push((Cow::Owned(attr), import_parent)); + } else if ident != sym::cfg { + // If it's not a `cfg()` attribute, we keep it. + attrs.push((Cow::Owned(attr), import_parent)); } } } diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 8fdbef65135c1..8e009ba2294a2 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1,5 +1,3 @@ -use clean::AttributesExt; - use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; @@ -464,16 +462,9 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: clean::ImportItem(ref import) => { let stab_tags = if let Some(import_def_id) = import.source.did { - let ast_attrs = tcx.get_attrs_unchecked(import_def_id); - let import_attrs = Box::new(clean::Attributes::from_ast(ast_attrs)); - // Just need an item with the correct def_id and attrs - let import_item = clean::Item { - item_id: import_def_id.into(), - attrs: import_attrs, - cfg: ast_attrs.cfg(tcx, &cx.cache().hidden_cfg), - ..myitem.clone() - }; + let import_item = + clean::Item { item_id: import_def_id.into(), ..myitem.clone() }; let stab_tags = Some(extra_info_tags(&import_item, item, tcx).to_string()); stab_tags From 7953d5df0e5b2d335005b9a88b61dfde65e9bf73 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 27 Jun 2023 13:12:56 +0200 Subject: [PATCH 2/4] Add regression test for cfg merging on re-exports --- tests/rustdoc/reexport-cfg.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 tests/rustdoc/reexport-cfg.rs diff --git a/tests/rustdoc/reexport-cfg.rs b/tests/rustdoc/reexport-cfg.rs new file mode 100644 index 0000000000000..a6179fad8733e --- /dev/null +++ b/tests/rustdoc/reexport-cfg.rs @@ -0,0 +1,30 @@ +// This test ensures that only the re-export `cfg` will be displayed and that it won't +// include `cfg`s from the previous chained items. + +#![crate_name = "foo"] +#![feature(doc_auto_cfg, doc_cfg)] + +mod foo { + #[cfg(not(feature = "foo"))] + pub struct Bar; + + #[doc(cfg(not(feature = "bar")))] + pub struct Bar2; +} + +// @has 'foo/index.html' +// @has - '//*[@class="item-name"]' 'BabarNon-lie' +#[cfg(not(feature = "lie"))] +pub use crate::foo::Bar as Babar; + +// @has - '//*[@class="item-name"]' 'Babar2Non-cake' +#[doc(cfg(not(feature = "cake")))] +pub use crate::foo::Bar2 as Babar2; + +// @has - '//*[@class="item-table"]/li' 'pub use crate::Babar as Elephant;Non-robot' +#[cfg(not(feature = "robot"))] +pub use crate::Babar as Elephant; + +// @has - '//*[@class="item-table"]/li' 'pub use crate::Babar2 as Elephant2;Non-cat' +#[doc(cfg(not(feature = "cat")))] +pub use crate::Babar2 as Elephant2; From 0ccd5c4898c813a6cdf844a6025fa40d9433fe2d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 28 Jun 2023 14:12:49 +0200 Subject: [PATCH 3/4] Update existing tests --- .../reexport-stability-tags-deprecated-and-portability.rs | 4 ++-- .../reexport-stability-tags-unstable-and-portability.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/rustdoc/reexport-stability-tags-deprecated-and-portability.rs b/tests/rustdoc/reexport-stability-tags-deprecated-and-portability.rs index a79d05904e31c..c81c654a20ee8 100644 --- a/tests/rustdoc/reexport-stability-tags-deprecated-and-portability.rs +++ b/tests/rustdoc/reexport-stability-tags-deprecated-and-portability.rs @@ -27,7 +27,7 @@ pub mod mod1 { pub mod mod2 { // @has - '//code' 'pub use tag::Portability;' // @!has - '//span' 'Deprecated' - // @has - '//span' 'sync' + // @!has - '//span' 'sync' pub use tag::Portability; } @@ -35,7 +35,7 @@ pub mod mod2 { pub mod mod3 { // @has - '//code' 'pub use tag::Both;' // @has - '//span' 'Deprecated' - // @has - '//span' 'sync' + // @!has - '//span' 'sync' pub use tag::Both; } diff --git a/tests/rustdoc/reexport-stability-tags-unstable-and-portability.rs b/tests/rustdoc/reexport-stability-tags-unstable-and-portability.rs index ff8a910f59f98..423838e251bb1 100644 --- a/tests/rustdoc/reexport-stability-tags-unstable-and-portability.rs +++ b/tests/rustdoc/reexport-stability-tags-unstable-and-portability.rs @@ -35,7 +35,7 @@ pub mod mod1 { pub mod mod2 { // @has - '//code' 'pub use tag::Portability;' // @!has - '//span' 'Experimental' - // @has - '//span' 'sync' + // @!has - '//span' 'sync' #[stable(feature = "rust1", since = "1.0.0")] pub use tag::Portability; } @@ -45,7 +45,7 @@ pub mod mod2 { pub mod mod3 { // @has - '//code' 'pub use tag::Both;' // @has - '//span' 'Experimental' - // @has - '//span' 'sync' + // @!has - '//span' 'sync' #[stable(feature = "rust1", since = "1.0.0")] pub use tag::Both; } From 823148fa849eb9b6fb896a0ac1772a2be3bdb043 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 28 Jun 2023 20:32:47 +0200 Subject: [PATCH 4/4] Add documentation on `filter_doc_attr` --- src/librustdoc/clean/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 6619288f9cb41..03b7c939d4859 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2656,6 +2656,8 @@ fn filter_doc_attr_ident(ident: Symbol, is_inline: bool) -> bool { } } +/// Remove attributes from `normal` that should not be inherited by `use` re-export. +/// Before calling this function, make sure `normal` is a `#[doc]` attribute. fn filter_doc_attr(normal: &mut ast::NormalAttr, is_inline: bool) { match normal.item.args { ast::AttrArgs::Delimited(ref mut args) => {