diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index b470af50f68fe..d8e56868d6cf5 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -46,6 +46,27 @@ pub(crate) fn try_inline( attrs: Option<(&[hir::Attribute], Option)>, visited: &mut DefIdSet, ) -> Option> { + fn try_inline_inner( + cx: &mut DocContext<'_>, + kind: clean::ItemKind, + did: DefId, + name: Symbol, + import_def_id: Option, + ) -> clean::Item { + cx.inlined.insert(did.into()); + let mut item = crate::clean::generate_item_with_correct_attrs( + cx, + kind, + did, + name, + import_def_id.as_slice(), + None, + ); + // The visibility needs to reflect the one from the reexport and not from the "source" DefId. + item.inner.inline_stmt_id = import_def_id; + item + } + let did = res.opt_def_id()?; if did.is_local() { return None; @@ -138,34 +159,37 @@ pub(crate) fn try_inline( }) } Res::Def(DefKind::Macro(kinds), did) => { - let mac = build_macro(cx, did, name, kinds); - - // FIXME: handle attributes and derives that aren't proc macros, and macros with - // multiple kinds - let type_kind = match kinds { - MacroKinds::BANG => ItemType::Macro, - MacroKinds::ATTR => ItemType::ProcAttribute, - MacroKinds::DERIVE => ItemType::ProcDerive, - _ => todo!("Handle macros with multiple kinds"), - }; - record_extern_fqn(cx, did, type_kind); - mac + for mac_kind in kinds { + let kind = build_macro( + cx, + did, + name, + match mac_kind { + MacroKinds::BANG => MacroKind::Bang, + MacroKinds::ATTR => MacroKind::Attr, + MacroKinds::DERIVE => MacroKind::Derive, + _ => unreachable!( + "Iterating over macro kinds always yields one kind at a time" + ), + }, + ); + let type_kind = match mac_kind { + MacroKinds::BANG => ItemType::Macro, + MacroKinds::ATTR => ItemType::MacroAttribute, + MacroKinds::DERIVE => ItemType::MacroDerive, + _ => { + unreachable!("Iterating over macro kinds always yields one kind at a time") + } + }; + record_extern_fqn(cx, did, type_kind); + ret.push(try_inline_inner(cx, kind, did, name, import_def_id)); + } + return Some(ret); } _ => return None, }; - cx.inlined.insert(did.into()); - let mut item = crate::clean::generate_item_with_correct_attrs( - cx, - kind, - did, - name, - import_def_id.as_slice(), - None, - ); - // The visibility needs to reflect the one from the reexport and not from the "source" DefId. - item.inner.inline_stmt_id = import_def_id; - ret.push(item); + ret.push(try_inline_inner(cx, kind, did, name, import_def_id)); Some(ret) } @@ -761,26 +785,14 @@ fn build_macro( cx: &mut DocContext<'_>, def_id: DefId, name: Symbol, - macro_kinds: MacroKinds, + kind: MacroKind, ) -> clean::ItemKind { match CStore::from_tcx(cx.tcx).load_macro_untracked(def_id, cx.tcx) { - // FIXME: handle attributes and derives that aren't proc macros, and macros with multiple - // kinds - LoadedMacro::MacroDef { def, .. } => match macro_kinds { - MacroKinds::BANG => clean::MacroItem(clean::Macro { - source: utils::display_macro_source(cx, name, &def), - macro_rules: def.macro_rules, - }), - MacroKinds::DERIVE => clean::ProcMacroItem(clean::ProcMacro { - kind: MacroKind::Derive, - helpers: Vec::new(), - }), - MacroKinds::ATTR => clean::ProcMacroItem(clean::ProcMacro { - kind: MacroKind::Attr, - helpers: Vec::new(), - }), - _ => todo!("Handle macros with multiple kinds"), - }, + LoadedMacro::MacroDef { def, .. } => clean::MacroItem(clean::Macro { + source: utils::display_macro_source(cx, name, &def), + macro_rules: def.macro_rules, + kind, + }), LoadedMacro::ProcMacro(ext) => { // Proc macros can only have a single kind let kind = match ext.macro_kinds() { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 4a95f21a3a5bd..5ea8d064d456e 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -249,7 +249,7 @@ pub(crate) fn clean_trait_ref_with_constraints<'tcx>( trait_ref: ty::PolyTraitRef<'tcx>, constraints: ThinVec, ) -> Path { - let kind = cx.tcx.def_kind(trait_ref.def_id()).into(); + let kind = ItemType::from_def_kind(cx.tcx.def_kind(trait_ref.def_id()), None)[0]; if !matches!(kind, ItemType::Trait | ItemType::TraitAlias) { span_bug!(cx.tcx.def_span(trait_ref.def_id()), "`TraitRef` had unexpected kind {kind:?}"); } @@ -2841,19 +2841,33 @@ fn clean_maybe_renamed_item<'tcx>( generics: clean_generics(generics, cx), fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(), }), - // FIXME: handle attributes and derives that aren't proc macros, and macros with - // multiple kinds - ItemKind::Macro(_, macro_def, MacroKinds::BANG) => MacroItem(Macro { - source: display_macro_source(cx, name, macro_def), - macro_rules: macro_def.macro_rules, - }), - ItemKind::Macro(_, _, MacroKinds::ATTR) => { - clean_proc_macro(item, &mut name, MacroKind::Attr, cx) - } - ItemKind::Macro(_, _, MacroKinds::DERIVE) => { - clean_proc_macro(item, &mut name, MacroKind::Derive, cx) + ItemKind::Macro(_, macro_def, macro_kinds) => { + return macro_kinds + .into_iter() + .map(|macro_kind| { + let kind = MacroItem(Macro { + source: display_macro_source(cx, name, macro_def), + macro_rules: macro_def.macro_rules, + kind: match macro_kind { + MacroKinds::BANG => MacroKind::Bang, + MacroKinds::ATTR => MacroKind::Attr, + MacroKinds::DERIVE => MacroKind::Derive, + _ => unreachable!( + "Iterating over macro kinds always yields one kind at a time" + ), + }, + }); + generate_item_with_correct_attrs( + cx, + kind, + item.owner_id.def_id.to_def_id(), + name, + import_ids, + renamed, + ) + }) + .collect(); } - ItemKind::Macro(_, _, _) => todo!("Handle macros with multiple kinds"), // proc macros can have a name set by attributes ItemKind::Fn { ref sig, generics, body: body_id, .. } => { clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 73d0f40275404..ed92614eba07f 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -2367,6 +2367,7 @@ pub(crate) struct Macro { pub(crate) source: String, /// Whether the macro was defined via `macro_rules!` as opposed to `macro`. pub(crate) macro_rules: bool, + pub(crate) kind: MacroKind, } #[derive(Clone, Debug)] diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index bfb7962213972..cd96477c4b0d8 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -26,6 +26,7 @@ use crate::clean::{ }; use crate::core::DocContext; use crate::display::Joined as _; +use crate::formats::item_type::ItemType; #[cfg(test)] mod tests; @@ -495,7 +496,7 @@ pub(crate) fn register_res(cx: &mut DocContext<'_>, res: Res) -> DefId { use DefKind::*; debug!("register_res({res:?})"); - let (kind, did) = match res { + let (kinds, did) = match res { Res::Def( kind @ (AssocTy | AssocFn @@ -514,14 +515,16 @@ pub(crate) fn register_res(cx: &mut DocContext<'_>, res: Res) -> DefId { | Macro(..) | TraitAlias), did, - ) => (kind.into(), did), + ) => (ItemType::from_def_kind(kind, None), did), _ => panic!("register_res: unexpected {res:?}"), }; if did.is_local() { return did; } - inline::record_extern_fqn(cx, did, kind); + for kind in kinds.iter().copied() { + inline::record_extern_fqn(cx, did, kind); + } did } diff --git a/src/librustdoc/formats/item_type.rs b/src/librustdoc/formats/item_type.rs index ab40c01cb369d..c8d6f56a06a9c 100644 --- a/src/librustdoc/formats/item_type.rs +++ b/src/librustdoc/formats/item_type.rs @@ -93,8 +93,8 @@ item_type! { Union = 20, ForeignType = 21, // OpaqueTy used to be here, but it was removed in #127276 - ProcAttribute = 23, - ProcDerive = 24, + MacroAttribute = 23, + MacroDerive = 24, TraitAlias = 25, // This number is reserved for use in JavaScript // Generic = 26, @@ -127,7 +127,11 @@ impl<'a> From<&'a clean::Item> for ItemType { clean::VariantItem(..) => ItemType::Variant, clean::ForeignFunctionItem(..) => ItemType::Function, // no ForeignFunction clean::ForeignStaticItem(..) => ItemType::Static, // no ForeignStatic - clean::MacroItem(..) => ItemType::Macro, + clean::MacroItem(mac) => match mac.kind { + MacroKind::Bang => ItemType::Macro, + MacroKind::Attr => ItemType::MacroAttribute, + MacroKind::Derive => ItemType::MacroDerive, + }, clean::PrimitiveItem(..) => ItemType::Primitive, clean::RequiredAssocConstItem(..) | clean::ProvidedAssocConstItem(..) @@ -139,48 +143,56 @@ impl<'a> From<&'a clean::Item> for ItemType { clean::TraitAliasItem(..) => ItemType::TraitAlias, clean::ProcMacroItem(mac) => match mac.kind { MacroKind::Bang => ItemType::Macro, - MacroKind::Attr => ItemType::ProcAttribute, - MacroKind::Derive => ItemType::ProcDerive, + MacroKind::Attr => ItemType::MacroAttribute, + MacroKind::Derive => ItemType::MacroDerive, }, clean::StrippedItem(..) => unreachable!(), } } } -impl From for ItemType { - fn from(other: DefKind) -> Self { - Self::from_def_kind(other, None) - } -} - impl ItemType { /// Depending on the parent kind, some variants have a different translation (like a `Method` /// becoming a `TyMethod`). - pub(crate) fn from_def_kind(kind: DefKind, parent_kind: Option) -> Self { + pub(crate) fn from_def_kind(kind: DefKind, parent_kind: Option) -> &'static [Self] { match kind { - DefKind::Enum => Self::Enum, - DefKind::Fn => Self::Function, - DefKind::Mod => Self::Module, - DefKind::Const => Self::Constant, - DefKind::Static { .. } => Self::Static, - DefKind::Struct => Self::Struct, - DefKind::Union => Self::Union, - DefKind::Trait => Self::Trait, - DefKind::TyAlias => Self::TypeAlias, - DefKind::TraitAlias => Self::TraitAlias, - DefKind::Macro(MacroKinds::BANG) => ItemType::Macro, - DefKind::Macro(MacroKinds::ATTR) => ItemType::ProcAttribute, - DefKind::Macro(MacroKinds::DERIVE) => ItemType::ProcDerive, - DefKind::Macro(_) => todo!("Handle macros with multiple kinds"), - DefKind::ForeignTy => Self::ForeignType, - DefKind::Variant => Self::Variant, - DefKind::Field => Self::StructField, - DefKind::AssocTy => Self::AssocType, - DefKind::AssocFn if let Some(DefKind::Trait) = parent_kind => Self::TyMethod, - DefKind::AssocFn => Self::Method, - DefKind::Ctor(CtorOf::Struct, _) => Self::Struct, - DefKind::Ctor(CtorOf::Variant, _) => Self::Variant, - DefKind::AssocConst => Self::AssocConst, + DefKind::Enum => &[Self::Enum], + DefKind::Fn => &[Self::Function], + DefKind::Mod => &[Self::Module], + DefKind::Const => &[Self::Constant], + DefKind::Static { .. } => &[Self::Static], + DefKind::Struct => &[Self::Struct], + DefKind::Union => &[Self::Union], + DefKind::Trait => &[Self::Trait], + DefKind::TyAlias => &[Self::TypeAlias], + DefKind::TraitAlias => &[Self::TraitAlias], + DefKind::Macro(MacroKinds::ATTR) => &[ItemType::MacroAttribute], + DefKind::Macro(MacroKinds::DERIVE) => &[ItemType::MacroDerive], + DefKind::Macro(MacroKinds::BANG) => &[ItemType::Macro], + DefKind::Macro(kinds) if kinds == MacroKinds::ATTR | MacroKinds::DERIVE => { + &[ItemType::MacroAttribute, ItemType::MacroDerive] + } + DefKind::Macro(kinds) if kinds == MacroKinds::ATTR | MacroKinds::BANG => { + &[ItemType::Macro, ItemType::MacroAttribute] + } + DefKind::Macro(kinds) if kinds == MacroKinds::DERIVE | MacroKinds::BANG => { + &[ItemType::Macro, ItemType::MacroDerive] + } + DefKind::Macro(kinds) + if kinds == MacroKinds::BANG | MacroKinds::ATTR | MacroKinds::DERIVE => + { + &[ItemType::Macro, ItemType::MacroAttribute, ItemType::MacroDerive] + } + DefKind::Macro(kinds) => unimplemented!("unsupported macro kinds {kinds:?}"), + DefKind::ForeignTy => &[Self::ForeignType], + DefKind::Variant => &[Self::Variant], + DefKind::Field => &[Self::StructField], + DefKind::AssocTy => &[Self::AssocType], + DefKind::AssocFn if let Some(DefKind::Trait) = parent_kind => &[Self::TyMethod], + DefKind::AssocFn => &[Self::Method], + DefKind::Ctor(CtorOf::Struct, _) => &[Self::Struct], + DefKind::Ctor(CtorOf::Variant, _) => &[Self::Variant], + DefKind::AssocConst => &[Self::AssocConst], DefKind::TyParam | DefKind::ConstParam | DefKind::ExternCrate @@ -193,7 +205,7 @@ impl ItemType { | DefKind::GlobalAsm | DefKind::Impl { .. } | DefKind::Closure - | DefKind::SyntheticCoroutineBody => Self::ForeignType, + | DefKind::SyntheticCoroutineBody => &[Self::ForeignType], } } @@ -221,8 +233,8 @@ impl ItemType { ItemType::AssocConst => "associatedconstant", ItemType::ForeignType => "foreigntype", ItemType::Keyword => "keyword", - ItemType::ProcAttribute => "attr", - ItemType::ProcDerive => "derive", + ItemType::MacroAttribute => "attr", + ItemType::MacroDerive => "derive", ItemType::TraitAlias => "traitalias", ItemType::Attribute => "attribute", } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 856e637a4587b..9633adfea7687 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -443,14 +443,14 @@ fn generate_item_def_id_path( let fqp: Vec = once(crate_name).chain(relative).collect(); let def_kind = tcx.def_kind(def_id); - let shortty = def_kind.into(); + let shortty = ItemType::from_def_kind(def_kind, None)[0]; let module_fqp = to_module_fqp(shortty, &fqp); let mut is_remote = false; let url_parts = url_parts(cx.cache(), def_id, module_fqp, &cx.current, &mut is_remote)?; let mut url_parts = make_href(root_path, shortty, url_parts, &fqp, is_remote); if def_id != original_def_id { - let kind = ItemType::from_def_kind(original_def_kind, Some(def_kind)); + let kind = ItemType::from_def_kind(original_def_kind, Some(def_kind))[0]; url_parts = format!("{url_parts}#{kind}.{}", tcx.item_name(original_def_id)) }; Ok((url_parts, shortty, fqp)) diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 13178ee4e9934..792e12d257965 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -522,10 +522,10 @@ impl AllTypes { ItemType::TypeAlias => self.type_aliases.insert(ItemEntry::new(new_url, name)), ItemType::Static => self.statics.insert(ItemEntry::new(new_url, name)), ItemType::Constant => self.constants.insert(ItemEntry::new(new_url, name)), - ItemType::ProcAttribute => { + ItemType::MacroAttribute => { self.attribute_macros.insert(ItemEntry::new(new_url, name)) } - ItemType::ProcDerive => self.derive_macros.insert(ItemEntry::new(new_url, name)), + ItemType::MacroDerive => self.derive_macros.insert(ItemEntry::new(new_url, name)), ItemType::TraitAlias => self.trait_aliases.insert(ItemEntry::new(new_url, name)), _ => true, }; @@ -2548,7 +2548,7 @@ impl ItemSection { Self::ForeignTypes => "foreign-types", Self::Keywords => "keywords", Self::Attributes => "attributes", - Self::AttributeMacros => "attributes", + Self::AttributeMacros => "attribute-macros", Self::DeriveMacros => "derives", Self::TraitAliases => "trait-aliases", } @@ -2609,8 +2609,8 @@ fn item_ty_to_section(ty: ItemType) -> ItemSection { ItemType::ForeignType => ItemSection::ForeignTypes, ItemType::Keyword => ItemSection::Keywords, ItemType::Attribute => ItemSection::Attributes, - ItemType::ProcAttribute => ItemSection::AttributeMacros, - ItemType::ProcDerive => ItemSection::DeriveMacros, + ItemType::MacroAttribute => ItemSection::AttributeMacros, + ItemType::MacroDerive => ItemSection::DeriveMacros, ItemType::TraitAlias => ItemSection::TraitAliases, } } diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index adfc7481c73ae..5df1a33a8e88a 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -162,7 +162,11 @@ pub(super) fn print_item(cx: &Context<'_>, item: &clean::Item) -> impl fmt::Disp clean::UnionItem(..) => "Union ", clean::EnumItem(..) => "Enum ", clean::TypeAliasItem(..) => "Type Alias ", - clean::MacroItem(..) => "Macro ", + clean::MacroItem(ref mac) => match mac.kind { + MacroKind::Bang => "Macro ", + MacroKind::Attr => "Attribute Macro ", + MacroKind::Derive => "Derive Macro ", + }, clean::ProcMacroItem(ref mac) => match mac.kind { MacroKind::Bang => "Macro ", MacroKind::Attr => "Attribute Macro ", diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 3ea9de381eca6..93ecd600198fa 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -791,7 +791,7 @@ function preLoadCss(cssUrl) { block("foreigntype", "foreign-types", "Foreign Types"); block("keyword", "keywords", "Keywords"); block("attribute", "attributes", "Attributes"); - block("attr", "attributes", "Attribute Macros"); + block("attr", "attribute-macros", "Attribute Macros"); block("derive", "derives", "Derive Macros"); block("traitalias", "trait-aliases", "Trait Aliases"); } diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 909262d563e9f..b57f27f529738 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -892,8 +892,8 @@ impl FromClean for ItemKind { Keyword => ItemKind::Keyword, Attribute => ItemKind::Attribute, TraitAlias => ItemKind::TraitAlias, - ProcAttribute => ItemKind::ProcAttribute, - ProcDerive => ItemKind::ProcDerive, + MacroAttribute => ItemKind::ProcAttribute, + MacroDerive => ItemKind::ProcDerive, } } } diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 658d3791d2578..ebc28754cf8bb 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -531,13 +531,15 @@ pub enum ItemKind { /// Corresponds to either `ItemEnum::Macro(_)` /// or `ItemEnum::ProcMacro(ProcMacro { kind: MacroKind::Bang })` Macro, - /// A procedural macro attribute. + /// A macro attribute. /// /// Corresponds to `ItemEnum::ProcMacro(ProcMacro { kind: MacroKind::Attr })` + /// and `ItemEnum::Macro(_)`; this should probably be renamed. ProcAttribute, /// A procedural macro usable in the `#[derive()]` attribute. /// /// Corresponds to `ItemEnum::ProcMacro(ProcMacro { kind: MacroKind::Derive })` + /// and `ItemEnum::Macro(_)`; this should probably be renamed. ProcDerive, /// An associated constant of a trait or a type. AssocConst, diff --git a/tests/rustdoc-gui/attr-macros.goml b/tests/rustdoc-gui/attr-macros.goml new file mode 100644 index 0000000000000..6223a1d101598 --- /dev/null +++ b/tests/rustdoc-gui/attr-macros.goml @@ -0,0 +1,89 @@ +// This test ensures that a bang macro which is also an attribute macro is listed correctly in +// the sidebar and in the module. + +go-to: "file://" + |DOC_PATH| + "/test_docs/macro.b.html" +// We check that the current item in the sidebar is the correct one. +assert-text: ("#rustdoc-modnav .block.macro .current", "b") + +define-function: ( + "check_macro", + [name, kind], + block { + // It should be present twice in the sidebar. + assert-count: ("#rustdoc-modnav a[href='macro." + |name| + ".html']", 1) + assert-count: ("#rustdoc-modnav a[href='" + |kind| + "." + |name| + ".html']", 1) + assert-count: ("//*[@id='rustdoc-modnav']//a[text()='" + |name| + "']", 2) + + // We now go to the macro page. + click: "#rustdoc-modnav a[href='macro." + |name| + ".html']" + // It should be present twice in the sidebar. + assert-count: ("#rustdoc-modnav a[href='macro." + |name| + ".html']", 1) + assert-count: ("#rustdoc-modnav a[href='" + |kind| + "." + |name| + ".html']", 1) + assert-count: ("//*[@id='rustdoc-modnav']//a[text()='" + |name| + "']", 2) + // We check that the current item is the macro. + assert-text: ("#rustdoc-modnav .block.macro .current", |name|) + // This is still only one page, and should only activate one of them. + assert-count: ("#rustdoc-modnav .current", 1) + + // We now go to the |kind| page. + click: "#rustdoc-modnav a[href='" + |kind| + "." + |name| + ".html']" + // It should be present twice in the sidebar. + assert-count: ("#rustdoc-modnav a[href='macro." + |name| + ".html']", 1) + assert-count: ("#rustdoc-modnav a[href='" + |kind| + "." + |name| + ".html']", 1) + assert-count: ("//*[@id='rustdoc-modnav']//a[text()='" + |name| + "']", 2) + // We check that the current item is the macro. + assert-text: ("#rustdoc-modnav .block." + |kind| + " .current", |name|) + // This is still only one page, and should only activate one of them. + assert-count: ("#rustdoc-modnav .current", 1) + } +) + +call-function: ("check_macro", {"name": "attr_macro", "kind": "attr"}) +call-function: ("check_macro", {"name": "derive_macro", "kind": "derive"}) + +define-function: ( + "crate_page", + [name, kind, section_id], + block { + // It should be only present twice. + assert-count: ("#main-content a[href='macro." + |name| + ".html']", 1) + assert-count: ("#main-content a[href='" + |kind| + "." + |name| + ".html']", 1) + // First in the "Macros" section. + assert-text: ("#macros + .item-table a[href='macro." + |name| + ".html']", |name|) + // Then in the other macro section. + assert-text: ( + "#" + |section_id| + " + .item-table a[href='" + |kind| + "." + |name| + ".html']", + |name|, + ) + } +) + +// Now we check it's correctly listed in the crate page. +go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" +call-function: ("crate_page", {"name": "attr_macro", "kind": "attr", "section_id": "attribute-macros"}) +call-function: ("crate_page", {"name": "derive_macro", "kind": "derive", "section_id": "derives"}) +// We also check we don't have duplicated sections. +assert-count: ("//*[@id='main-content']/h2[text()='Attribute Macros']", 1) +assert-count: ("//*[@id='main-content']/h2[text()='Derive Macros']", 1) + +define-function: ( + "all_items_page", + [name, kind, section_id], + block { + // It should be only present twice. + assert-count: ("#main-content a[href='macro." + |name| + ".html']", 1) + assert-count: ("#main-content a[href='" + |kind| + "." + |name| + ".html']", 1) + // First in the "Macros" section. + assert-text: ("#macros + .all-items a[href='macro." + |name| + ".html']", |name|) + // Then in the "Attribute Macros" section. + assert-text: ( + "#" + |section_id| + " + .all-items a[href='" + |kind| + "." + |name| + ".html']", + |name|, + ) + } +) + +// And finally we check it's correctly listed in the "all items" page. +go-to: "file://" + |DOC_PATH| + "/test_docs/all.html" +call-function: ("all_items_page", {"name": "attr_macro", "kind": "attr", "section_id": "attribute-macros"}) +call-function: ("all_items_page", {"name": "derive_macro", "kind": "derive", "section_id": "derives"}) diff --git a/tests/rustdoc-gui/module-items-font.goml b/tests/rustdoc-gui/module-items-font.goml index bed95b378c6ab..7547ddc6e666e 100644 --- a/tests/rustdoc-gui/module-items-font.goml +++ b/tests/rustdoc-gui/module-items-font.goml @@ -74,3 +74,13 @@ assert-css: ( "#attributes + .item-table dd", {"font-family": '"Source Serif 4", NanumBarunGothic, serif'}, ) + +// attribute macros +assert-css: ( + "#attribute-macros + .item-table dt a", + {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'}, +) +assert-css: ( + "#attribute-macros + .item-table dd", + {"font-family": '"Source Serif 4", NanumBarunGothic, serif'}, +) diff --git a/tests/rustdoc-gui/src/test_docs/lib.rs b/tests/rustdoc-gui/src/test_docs/lib.rs index c0771583ab658..7f1d495d27993 100644 --- a/tests/rustdoc-gui/src/test_docs/lib.rs +++ b/tests/rustdoc-gui/src/test_docs/lib.rs @@ -8,6 +8,8 @@ #![feature(rustdoc_internals)] #![feature(doc_cfg)] #![feature(associated_type_defaults)] +#![feature(macro_attr)] +#![feature(macro_derive)] /*! Enable the feature some-feature to enjoy diff --git a/tests/rustdoc-gui/src/test_docs/macros.rs b/tests/rustdoc-gui/src/test_docs/macros.rs index 07b2b97926d43..56e8e67c58b5a 100644 --- a/tests/rustdoc-gui/src/test_docs/macros.rs +++ b/tests/rustdoc-gui/src/test_docs/macros.rs @@ -2,3 +2,23 @@ macro_rules! a{ () => {}} #[macro_export] macro_rules! b{ () => {}} +/// An attribute bang macro. +#[macro_export] +macro_rules! attr_macro { + attr() () => {}; + () => {}; +} + +/// An attribute bang macro. +#[macro_export] +macro_rules! derive_macro { + derive() () => {}; + () => {}; +} + +#[macro_export] +macro_rules! one_for_all_macro { + attr() () => {}; + derive() () => {}; + () => {}; +} diff --git a/tests/rustdoc-js/macro-kinds.js b/tests/rustdoc-js/macro-kinds.js new file mode 100644 index 0000000000000..352b80ee42a6d --- /dev/null +++ b/tests/rustdoc-js/macro-kinds.js @@ -0,0 +1,33 @@ +// exact-check + +const EXPECTED = [ + { + 'query': 'macro:macro', + 'others': [ + { 'path': 'macro_kinds', 'name': 'macro1', 'href': '../macro_kinds/macro.macro1.html' }, + { 'path': 'macro_kinds', 'name': 'macro3', 'href': '../macro_kinds/macro.macro3.html' }, + ], + }, + { + 'query': 'attr:macro', + 'others': [ + { 'path': 'macro_kinds', 'name': 'macro1', 'href': '../macro_kinds/attr.macro1.html' }, + { 'path': 'macro_kinds', 'name': 'macro2', 'href': '../macro_kinds/attr.macro2.html' }, + { 'path': 'macro_kinds', 'name': 'macro5', 'href': '../macro_kinds/attr.macro5.html' }, + ], + }, + { + 'query': 'derive:macro', + 'others': [ + { + 'path': 'macro_kinds', 'name': 'macro1', 'href': '../macro_kinds/derive.macro1.html' + }, + { + 'path': 'macro_kinds', 'name': 'macro5', 'href': '../macro_kinds/derive.macro5.html' + }, + { + 'path': 'macro_kinds', 'name': 'macro4', 'href': '../macro_kinds/derive.macro4.html' + }, + ], + }, +]; diff --git a/tests/rustdoc-js/macro-kinds.rs b/tests/rustdoc-js/macro-kinds.rs new file mode 100644 index 0000000000000..dd0fc1c110a06 --- /dev/null +++ b/tests/rustdoc-js/macro-kinds.rs @@ -0,0 +1,34 @@ +// Test which ensures that attribute macros are correctly handled by the search. +// For example: `macro1` should appear in both `attr` and `macro` filters whereas +// `macro2` and `macro3` should only appear in `attr` or `macro` filters respectively. + +#![feature(macro_attr)] +#![feature(macro_derive)] + +#[macro_export] +macro_rules! macro1 { + attr() () => {}; + derive() () => {}; + () => {}; +} + +#[macro_export] +macro_rules! macro2 { + attr() () => {}; +} + +#[macro_export] +macro_rules! macro3 { + () => {}; +} + +#[macro_export] +macro_rules! macro4 { + derive() () => {}; +} + +#[macro_export] +macro_rules! macro5 { + attr() () => {}; + derive() () => {}; +}