-
Notifications
You must be signed in to change notification settings - Fork 14k
rustdoc: add support for macro_rules macros of multiple kinds #148005
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -46,6 +46,27 @@ pub(crate) fn try_inline( | |
| attrs: Option<(&[hir::Attribute], Option<LocalDefId>)>, | ||
| visited: &mut DefIdSet, | ||
| ) -> Option<Vec<clean::Item>> { | ||
| fn try_inline_inner( | ||
| cx: &mut DocContext<'_>, | ||
| kind: clean::ItemKind, | ||
| did: DefId, | ||
| name: Symbol, | ||
| import_def_id: Option<LocalDefId>, | ||
| ) -> 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); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we should have a comment noting the fact that we create multiple (pages? search index entries? something else?) for macros that are of multiple kinds, since it's a somewhat unexpected behavior. |
||
| 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() { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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<DefKind> 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<DefKind>) -> Self { | ||
| pub(crate) fn from_def_kind(kind: DefKind, parent_kind: Option<DefKind>) -> &'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:?}"), | ||
|
Comment on lines
+172
to
+186
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Code like this makes me really wish we were using |
||
| 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", | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -443,14 +443,14 @@ fn generate_item_def_id_path( | |
| let fqp: Vec<Symbol> = 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]; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This means that |
||
| 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)) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: These two
matchstatements could be merged into one that returns a tuple.