diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index d06e4fa1cc2f5..33db6583125ef 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -79,7 +79,7 @@ crate fn try_inline( Res::Def(DefKind::TyAlias, did) => { record_extern_fqn(cx, did, ItemType::Typedef); build_impls(cx, Some(parent_module), did, attrs, &mut ret); - clean::TypedefItem(build_type_alias(cx, did), false) + clean::TypedefItem(build_type_alias(cx, did)) } Res::Def(DefKind::Enum, did) => { record_extern_fqn(cx, did, ItemType::Enum); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 85a3e05e8b213..a6763d2827cec 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -964,11 +964,11 @@ impl Clean for hir::TraitItem<'_> { let local_did = self.def_id.to_def_id(); cx.with_param_env(local_did, |cx| { let inner = match self.kind { - hir::TraitItemKind::Const(ref ty, default) => { - let default = - default.map(|e| ConstantKind::Local { def_id: local_did, body: e }); - AssocConstItem(ty.clean(cx), default) - } + hir::TraitItemKind::Const(ref ty, Some(default)) => AssocConstItem( + ty.clean(cx), + ConstantKind::Local { def_id: local_did, body: default }, + ), + hir::TraitItemKind::Const(ref ty, None) => TyAssocConstItem(ty.clean(cx)), hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => { let m = clean_function(cx, sig, &self.generics, body); MethodItem(m, None) @@ -983,11 +983,19 @@ impl Clean for hir::TraitItem<'_> { }); TyMethodItem(Function { decl, generics }) } - hir::TraitItemKind::Type(bounds, ref default) => { + hir::TraitItemKind::Type(bounds, Some(default)) => { + let generics = enter_impl_trait(cx, |cx| self.generics.clean(cx)); + let bounds = bounds.iter().filter_map(|x| x.clean(cx)).collect(); + let item_type = hir_ty_to_ty(cx.tcx, default).clean(cx); + AssocTypeItem( + Typedef { type_: default.clean(cx), generics, item_type: Some(item_type) }, + bounds, + ) + } + hir::TraitItemKind::Type(bounds, None) => { let generics = enter_impl_trait(cx, |cx| self.generics.clean(cx)); let bounds = bounds.iter().filter_map(|x| x.clean(cx)).collect(); - let default = default.map(|t| t.clean(cx)); - AssocTypeItem(Box::new(generics), bounds, default) + TyAssocTypeItem(Box::new(generics), bounds) } }; let what_rustc_thinks = @@ -1004,7 +1012,7 @@ impl Clean for hir::ImplItem<'_> { cx.with_param_env(local_did, |cx| { let inner = match self.kind { hir::ImplItemKind::Const(ref ty, expr) => { - let default = Some(ConstantKind::Local { def_id: local_did, body: expr }); + let default = ConstantKind::Local { def_id: local_did, body: expr }; AssocConstItem(ty.clean(cx), default) } hir::ImplItemKind::Fn(ref sig, body) => { @@ -1016,7 +1024,10 @@ impl Clean for hir::ImplItem<'_> { let type_ = hir_ty.clean(cx); let generics = self.generics.clean(cx); let item_type = hir_ty_to_ty(cx.tcx, hir_ty).clean(cx); - TypedefItem(Typedef { type_, generics, item_type: Some(item_type) }, true) + AssocTypeItem( + Typedef { type_, generics, item_type: Some(item_type) }, + Vec::new(), + ) } }; @@ -1041,13 +1052,17 @@ impl Clean for ty::AssocItem { let tcx = cx.tcx; let kind = match self.kind { ty::AssocKind::Const => { - let ty = tcx.type_of(self.def_id); - let default = if self.defaultness.has_value() { - Some(ConstantKind::Extern { def_id: self.def_id }) - } else { - None + let ty = tcx.type_of(self.def_id).clean(cx); + + let provided = match self.container { + ty::ImplContainer(_) => true, + ty::TraitContainer(_) => self.defaultness.has_value(), }; - AssocConstItem(ty.clean(cx), default) + if provided { + AssocConstItem(ty, ConstantKind::Extern { def_id: self.def_id }) + } else { + TyAssocConstItem(ty) + } } ty::AssocKind::Fn => { let generics = clean_ty_generics( @@ -1181,23 +1196,28 @@ impl Clean for ty::AssocItem { None => bounds.push(GenericBound::maybe_sized(cx)), } - let ty = if self.defaultness.has_value() { - Some(tcx.type_of(self.def_id)) + if self.defaultness.has_value() { + AssocTypeItem( + Typedef { + type_: tcx.type_of(self.def_id).clean(cx), + generics, + // FIXME: should we obtain the Type from HIR and pass it on here? + item_type: None, + }, + bounds, + ) } else { - None - }; - - AssocTypeItem(Box::new(generics), bounds, ty.map(|t| t.clean(cx))) + TyAssocTypeItem(Box::new(generics), bounds) + } } else { // FIXME: when could this happen? Associated items in inherent impls? - let type_ = tcx.type_of(self.def_id).clean(cx); - TypedefItem( + AssocTypeItem( Typedef { - type_, + type_: tcx.type_of(self.def_id).clean(cx), generics: Generics { params: Vec::new(), where_predicates: Vec::new() }, item_type: None, }, - true, + Vec::new(), ) } } @@ -1837,14 +1857,11 @@ fn clean_maybe_renamed_item( ItemKind::TyAlias(hir_ty, ref generics) => { let rustdoc_ty = hir_ty.clean(cx); let ty = hir_ty_to_ty(cx.tcx, hir_ty).clean(cx); - TypedefItem( - Typedef { - type_: rustdoc_ty, - generics: generics.clean(cx), - item_type: Some(ty), - }, - false, - ) + TypedefItem(Typedef { + type_: rustdoc_ty, + generics: generics.clean(cx), + item_type: Some(ty), + }) } ItemKind::Enum(ref def, ref generics) => EnumItem(Enum { variants: def.variants.iter().map(|v| v.clean(cx)).collect(), diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 7698c2de24d5c..d2abfc35b932c 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -577,10 +577,16 @@ impl Item { self.type_() == ItemType::Variant } crate fn is_associated_type(&self) -> bool { - self.type_() == ItemType::AssocType + matches!(&*self.kind, AssocTypeItem(..) | StrippedItem(box AssocTypeItem(..))) + } + crate fn is_ty_associated_type(&self) -> bool { + matches!(&*self.kind, TyAssocTypeItem(..) | StrippedItem(box TyAssocTypeItem(..))) } crate fn is_associated_const(&self) -> bool { - self.type_() == ItemType::AssocConst + matches!(&*self.kind, AssocConstItem(..) | StrippedItem(box AssocConstItem(..))) + } + crate fn is_ty_associated_const(&self) -> bool { + matches!(&*self.kind, TyAssocConstItem(..) | StrippedItem(box TyAssocConstItem(..))) } crate fn is_method(&self) -> bool { self.type_() == ItemType::Method @@ -726,17 +732,18 @@ crate enum ItemKind { EnumItem(Enum), FunctionItem(Function), ModuleItem(Module), - TypedefItem(Typedef, bool /* is associated type */), + TypedefItem(Typedef), OpaqueTyItem(OpaqueTy), StaticItem(Static), ConstantItem(Constant), TraitItem(Trait), TraitAliasItem(TraitAlias), ImplItem(Impl), - /// A method signature only. Used for required methods in traits (ie, - /// non-default-methods). + /// A required method in a trait declaration meaning it's only a function signature. TyMethodItem(Function), - /// A method with a body. + /// A method in a trait impl or a provided method in a trait declaration. + /// + /// Compared to [TyMethodItem], it also contains a method body. MethodItem(Function, Option), StructFieldItem(Type), VariantItem(Variant), @@ -749,12 +756,16 @@ crate enum ItemKind { MacroItem(Macro), ProcMacroItem(ProcMacro), PrimitiveItem(PrimitiveType), - AssocConstItem(Type, Option), - /// An associated item in a trait or trait impl. + /// A required associated constant in a trait declaration. + TyAssocConstItem(Type), + /// An associated associated constant in a trait impl or a provided one in a trait declaration. + AssocConstItem(Type, ConstantKind), + /// A required associated type in a trait declaration. /// /// The bounds may be non-empty if there is a `where` clause. - /// The `Option` is the default concrete type (e.g. `trait Trait { type Target = usize; }`) - AssocTypeItem(Box, Vec, Option), + TyAssocTypeItem(Box, Vec), + /// An associated type in a trait impl or a provided one in a trait declaration. + AssocTypeItem(Typedef, Vec), /// An item that has been stripped by a rustdoc pass StrippedItem(Box), KeywordItem(Symbol), @@ -776,7 +787,7 @@ impl ItemKind { ExternCrateItem { .. } | ImportItem(_) | FunctionItem(_) - | TypedefItem(_, _) + | TypedefItem(_) | OpaqueTyItem(_) | StaticItem(_) | ConstantItem(_) @@ -791,7 +802,9 @@ impl ItemKind { | MacroItem(_) | ProcMacroItem(_) | PrimitiveItem(_) + | TyAssocConstItem(_) | AssocConstItem(_, _) + | TyAssocTypeItem(..) | AssocTypeItem(..) | StrippedItem(_) | KeywordItem(_) => [].iter(), diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index c85ef0ac05452..fe6d680991f80 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -178,7 +178,7 @@ crate fn build_deref_target_impls(cx: &mut DocContext<'_>, items: &[Item], ret: for item in items { let target = match *item.kind { - ItemKind::TypedefItem(ref t, true) => &t.type_, + ItemKind::AssocTypeItem(ref t, _) => &t.type_, _ => continue, }; diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index fbb8b572ea430..95adc4426b585 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -71,7 +71,7 @@ crate trait DocFolder: Sized { ExternCrateItem { src: _ } | ImportItem(_) | FunctionItem(_) - | TypedefItem(_, _) + | TypedefItem(_) | OpaqueTyItem(_) | StaticItem(_) | ConstantItem(_) @@ -85,7 +85,9 @@ crate trait DocFolder: Sized { | MacroItem(_) | ProcMacroItem(_) | PrimitiveItem(_) - | AssocConstItem(_, _) + | TyAssocConstItem(..) + | AssocConstItem(..) + | TyAssocTypeItem(..) | AssocTypeItem(..) | KeywordItem(_) => kind, } diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 53159709586c6..663e18fe9129f 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -242,14 +242,15 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { if let Some(ref s) = item.name { let (parent, is_inherent_impl_item) = match *item.kind { clean::StrippedItem(..) => ((None, None), false), - clean::AssocConstItem(..) | clean::TypedefItem(_, true) + clean::AssocConstItem(..) | clean::AssocTypeItem(..) if self.cache.parent_is_trait_impl => { // skip associated items in trait impls ((None, None), false) } - clean::AssocTypeItem(..) - | clean::TyMethodItem(..) + clean::TyMethodItem(..) + | clean::TyAssocConstItem(..) + | clean::TyAssocTypeItem(..) | clean::StructFieldItem(..) | clean::VariantItem(..) => ( ( @@ -258,7 +259,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { ), false, ), - clean::MethodItem(..) | clean::AssocConstItem(..) => { + clean::MethodItem(..) | clean::AssocConstItem(..) | clean::AssocTypeItem(..) => { if self.cache.parent_stack.is_empty() { ((None, None), false) } else { @@ -373,7 +374,9 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { | clean::TyMethodItem(..) | clean::MethodItem(..) | clean::StructFieldItem(..) + | clean::TyAssocConstItem(..) | clean::AssocConstItem(..) + | clean::TyAssocTypeItem(..) | clean::AssocTypeItem(..) | clean::StrippedItem(..) | clean::KeywordItem(..) => { diff --git a/src/librustdoc/formats/item_type.rs b/src/librustdoc/formats/item_type.rs index f8660c296cb0b..fb4afb769ad15 100644 --- a/src/librustdoc/formats/item_type.rs +++ b/src/librustdoc/formats/item_type.rs @@ -14,7 +14,7 @@ use crate::clean; /// The search index uses item types encoded as smaller numbers which equal to /// discriminants. JavaScript then is used to decode them into the original value. /// Consequently, every change to this type should be synchronized to -/// the `itemTypes` mapping table in `html/static/main.js`. +/// the `itemTypes` mapping table in `html/static/js/search.js`. /// /// In addition, code in `html::render` uses this enum to generate CSS classes, page prefixes, and /// module headings. If you are adding to this enum and want to ensure that the sidebar also prints @@ -89,8 +89,8 @@ impl<'a> From<&'a clean::Item> for ItemType { clean::ForeignStaticItem(..) => ItemType::Static, // no ForeignStatic clean::MacroItem(..) => ItemType::Macro, clean::PrimitiveItem(..) => ItemType::Primitive, - clean::AssocConstItem(..) => ItemType::AssocConst, - clean::AssocTypeItem(..) => ItemType::AssocType, + clean::TyAssocConstItem(..) | clean::AssocConstItem(..) => ItemType::AssocConst, + clean::TyAssocTypeItem(..) | clean::AssocTypeItem(..) => ItemType::AssocType, clean::ForeignTypeItem => ItemType::ForeignType, clean::KeywordItem(..) => ItemType::Keyword, clean::TraitAliasItem(..) => ItemType::TraitAlias, diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 5c59609d5b8c6..55b0028180f66 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -527,6 +527,21 @@ crate enum HrefError { /// This item is known to rustdoc, but from a crate that does not have documentation generated. /// /// This can only happen for non-local items. + /// + /// # Example + /// + /// Crate `a` defines a public trait and crate `b` – the target crate that depends on `a` – + /// implements it for a local type. + /// We document `b` but **not** `a` (we only _build_ the latter – with `rustc`): + /// + /// ```sh + /// rustc a.rs --crate-type=lib + /// rustdoc b.rs --crate-type=lib --extern=a=liba.rlib + /// ``` + /// + /// Now, the associated items in the trait impl want to link to the corresponding item in the + /// trait declaration (see `html::render::assoc_href_attr`) but it's not available since their + /// *documentation (was) not built*. DocumentationNotBuilt, /// This can only happen for non-local items when `--document-private-items` is not passed. Private, diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 943c521485b18..1ebb41b5933d0 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -1452,8 +1452,10 @@ fn init_id_map() -> FxHashMap { map.insert("trait-implementations".to_owned(), 1); map.insert("synthetic-implementations".to_owned(), 1); map.insert("blanket-implementations".to_owned(), 1); - map.insert("associated-types".to_owned(), 1); - map.insert("associated-const".to_owned(), 1); + map.insert("required-associated-types".to_owned(), 1); + map.insert("provided-associated-types".to_owned(), 1); + map.insert("provided-associated-consts".to_owned(), 1); + map.insert("required-associated-consts".to_owned(), 1); map.insert("required-methods".to_owned(), 1); map.insert("provided-methods".to_owned(), 1); map.insert("implementors".to_owned(), 1); diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 12da16527a0eb..9891c4b676fb4 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -521,7 +521,7 @@ fn document_short( let mut summary_html = MarkdownSummaryLine(&s, &item.links(cx)).into_string(); if s.contains('\n') { - let link = format!(r#" Read more"#, naive_assoc_href(item, link, cx)); + let link = format!(r#" Read more"#, assoc_href_attr(item, link, cx)); if let Some(idx) = summary_html.rfind("

") { summary_html.insert_str(idx, &link); @@ -737,42 +737,82 @@ fn render_impls( w.write_str(&rendered_impls.join("")); } -fn naive_assoc_href(it: &clean::Item, link: AssocItemLink<'_>, cx: &Context<'_>) -> String { - use crate::formats::item_type::ItemType::*; +/// Build a (possibly empty) `href` attribute (a key-value pair) for the given associated item. +fn assoc_href_attr(it: &clean::Item, link: AssocItemLink<'_>, cx: &Context<'_>) -> String { + let name = it.name.unwrap(); + let item_type = it.type_(); - let name = it.name.as_ref().unwrap(); - let ty = match it.type_() { - Typedef | AssocType => AssocType, - s => s, - }; + let href = match link { + AssocItemLink::Anchor(Some(ref id)) => Some(format!("#{}", id)), + AssocItemLink::Anchor(None) => Some(format!("#{}.{}", item_type, name)), + AssocItemLink::GotoSource(did, provided_methods) => { + // We're creating a link from the implementation of an associated item to its + // declaration in the trait declaration. + let item_type = match item_type { + // For historical but not technical reasons, the item type of methods in + // trait declarations depends on whether the method is required (`TyMethod`) or + // provided (`Method`). + ItemType::Method | ItemType::TyMethod => { + if provided_methods.contains(&name) { + ItemType::Method + } else { + ItemType::TyMethod + } + } + // For associated types and constants, no such distinction exists. + item_type => item_type, + }; - let anchor = format!("#{}.{}", ty, name); - match link { - AssocItemLink::Anchor(Some(ref id)) => format!("#{}", id), - AssocItemLink::Anchor(None) => anchor, - AssocItemLink::GotoSource(did, _) => { - href(did.expect_def_id(), cx).map(|p| format!("{}{}", p.0, anchor)).unwrap_or(anchor) + match href(did.expect_def_id(), cx) { + Ok((url, ..)) => Some(format!("{}#{}.{}", url, item_type, name)), + // The link is broken since it points to an external crate that wasn't documented. + // Do not create any link in such case. This is better than falling back to a + // dummy anchor like `#{item_type}.{name}` representing the `id` of *this* impl item + // (that used to happen in older versions). Indeed, in most cases this dummy would + // coincide with the `id`. However, it would not always do so. + // In general, this dummy would be incorrect: + // If the type with the trait impl also had an inherent impl with an assoc. item of + // the *same* name as this impl item, the dummy would link to that one even though + // those two items are distinct! + // In this scenario, the actual `id` of this impl item would be + // `#{item_type}.{name}-{n}` for some number `n` (a disambiguator). + Err(HrefError::DocumentationNotBuilt) => None, + Err(_) => Some(format!("#{}.{}", item_type, name)), + } } - } + }; + + // If there is no `href` for the reason explained above, simply do not render it which is valid: + // https://html.spec.whatwg.org/multipage/links.html#links-created-by-a-and-area-elements + href.map(|href| format!(" href=\"{}\"", href)).unwrap_or_default() } fn assoc_const( w: &mut Buffer, it: &clean::Item, ty: &clean::Type, + default: Option<&clean::ConstantKind>, link: AssocItemLink<'_>, extra: &str, cx: &Context<'_>, ) { write!( w, - "{}{}const {}: {}", - extra, - it.visibility.print_with_space(it.def_id, cx), - naive_assoc_href(it, link, cx), - it.name.as_ref().unwrap(), - ty.print(cx) + "{extra}{vis}const {name}: {ty}", + extra = extra, + vis = it.visibility.print_with_space(it.def_id, cx), + href = assoc_href_attr(it, link, cx), + name = it.name.as_ref().unwrap(), + ty = ty.print(cx), ); + if let Some(default) = default { + // FIXME: `.value()` uses `clean::utils::format_integer_with_underscore_sep` under the + // hood which adds noisy underscores and a type suffix to number literals. + // This hurts readability in this context especially when more complex expressions + // are involved and it doesn't add much of value. + // Find a way to print constants here without all that jazz. + write!(w, " = {}", default.value(cx.tcx()).unwrap_or_else(|| default.expr(cx.tcx()))); + } } fn assoc_type( @@ -787,9 +827,9 @@ fn assoc_type( ) { write!( w, - "{indent}type {name}{generics}", + "{indent}type {name}{generics}", indent = " ".repeat(indent), - href = naive_assoc_href(it, link, cx), + href = assoc_href_attr(it, link, cx), name = it.name.as_ref().unwrap(), generics = generics.print(cx), ); @@ -814,22 +854,6 @@ fn assoc_method( ) { let header = meth.fn_header(cx.tcx()).expect("Trying to get header from a non-function item"); let name = meth.name.as_ref().unwrap(); - let href = match link { - AssocItemLink::Anchor(Some(ref id)) => Some(format!("#{}", id)), - AssocItemLink::Anchor(None) => Some(format!("#{}.{}", meth.type_(), name)), - AssocItemLink::GotoSource(did, provided_methods) => { - // We're creating a link from an impl-item to the corresponding - // trait-item and need to map the anchored type accordingly. - let ty = - if provided_methods.contains(name) { ItemType::Method } else { ItemType::TyMethod }; - - match (href(did.expect_def_id(), cx), ty) { - (Ok(p), ty) => Some(format!("{}#{}.{}", p.0, ty, name)), - (Err(HrefError::DocumentationNotBuilt), ItemType::TyMethod) => None, - (Err(_), ty) => Some(format!("#{}.{}", ty, name)), - } - } - }; let vis = meth.visibility.print_with_space(meth.def_id, cx).to_string(); // FIXME: Once https://github.com/rust-lang/rust/issues/67792 is implemented, we can remove // this condition. @@ -843,6 +867,7 @@ fn assoc_method( let unsafety = header.unsafety.print_with_space(); let defaultness = print_default_space(meth.is_default()); let abi = print_abi_with_space(header.abi).to_string(); + let href = assoc_href_attr(meth, link, cx); // NOTE: `{:#}` does not print HTML formatting, `{}` does. So `g.print` can't be reused between the length calculation and `write!`. let generics_len = format!("{:#}", g.print(cx)).len(); @@ -868,7 +893,7 @@ fn assoc_method( w.reserve(header_len + "{".len() + "".len()); write!( w, - "{indent}{vis}{constness}{asyncness}{unsafety}{defaultness}{abi}fn {name}\ + "{indent}{vis}{constness}{asyncness}{unsafety}{defaultness}{abi}fn {name}\ {generics}{decl}{notable_traits}{where_clause}", indent = indent_str, vis = vis, @@ -877,8 +902,7 @@ fn assoc_method( unsafety = unsafety, defaultness = defaultness, abi = abi, - // links without a href are valid - https://www.w3schools.com/tags/att_a_href.asp - href = href.map(|href| format!("href=\"{}\"", href)).unwrap_or_else(|| "".to_string()), + href = href, name = name, generics = g.print(cx), decl = d.full_print(header_len, indent, header.asyncness, cx), @@ -968,23 +992,43 @@ fn render_assoc_item( cx: &Context<'_>, render_mode: RenderMode, ) { - match *item.kind { + match &*item.kind { clean::StrippedItem(..) => {} - clean::TyMethodItem(ref m) => { + clean::TyMethodItem(m) => { assoc_method(w, item, &m.generics, &m.decl, link, parent, cx, render_mode) } - clean::MethodItem(ref m, _) => { + clean::MethodItem(m, _) => { assoc_method(w, item, &m.generics, &m.decl, link, parent, cx, render_mode) } - clean::AssocConstItem(ref ty, _) => { - assoc_const(w, item, ty, link, if parent == ItemType::Trait { " " } else { "" }, cx) - } - clean::AssocTypeItem(ref generics, ref bounds, ref default) => assoc_type( + kind @ (clean::TyAssocConstItem(ty) | clean::AssocConstItem(ty, _)) => assoc_const( + w, + item, + ty, + match kind { + clean::TyAssocConstItem(_) => None, + clean::AssocConstItem(_, default) => Some(default), + _ => unreachable!(), + }, + link, + if parent == ItemType::Trait { " " } else { "" }, + cx, + ), + clean::TyAssocTypeItem(ref generics, ref bounds) => assoc_type( w, item, generics, bounds, - default.as_ref(), + None, + link, + if parent == ItemType::Trait { 4 } else { 0 }, + cx, + ), + clean::AssocTypeItem(ref ty, ref bounds) => assoc_type( + w, + item, + &ty.generics, + bounds, + Some(ty.item_type.as_ref().unwrap_or(&ty.type_)), link, if parent == ItemType::Trait { 4 } else { 0 }, cx, @@ -1205,7 +1249,7 @@ fn render_deref_methods( .items .iter() .find_map(|item| match *item.kind { - clean::TypedefItem(ref t, true) => Some(match *t { + clean::AssocTypeItem(ref t, _) => Some(match *t { clean::Typedef { item_type: Some(ref type_), .. } => (type_, &t.type_), _ => (&t.type_, &t.type_), }), @@ -1291,7 +1335,7 @@ fn notable_traits_decl(decl: &clean::FnDecl, cx: &Context<'_>) -> String { impl_.print(false, cx) ); for it in &impl_.items { - if let clean::TypedefItem(ref tydef, _) = *it.kind { + if let clean::AssocTypeItem(ref tydef, ref _bounds) = *it.kind { out.push_str(" "); let empty_set = FxHashSet::default(); let src_link = @@ -1300,7 +1344,7 @@ fn notable_traits_decl(decl: &clean::FnDecl, cx: &Context<'_>) -> String { &mut out, it, &tydef.generics, - &[], + &[], // intentionally leaving out bounds Some(&tydef.type_), src_link, 0, @@ -1439,7 +1483,7 @@ fn render_impl( if item_type == ItemType::Method { " method-toggle" } else { "" }; write!(w, "
", method_toggle_class); } - match *item.kind { + match &*item.kind { clean::MethodItem(..) | clean::TyMethodItem(_) => { // Only render when the method is not static or we allow static methods if render_method_item { @@ -1471,63 +1515,68 @@ fn render_impl( w.write_str(""); } } - clean::TypedefItem(ref tydef, _) => { - let source_id = format!("{}.{}", ItemType::AssocType, name); + kind @ (clean::TyAssocConstItem(ty) | clean::AssocConstItem(ty, _)) => { + let source_id = format!("{}.{}", item_type, name); let id = cx.derive_id(source_id.clone()); write!( w, "
", id, item_type, in_trait_class ); + render_rightside(w, cx, item, containing_item, render_mode); write!(w, "", id); w.write_str("

"); - assoc_type( + assoc_const( w, item, - &tydef.generics, - &[], - Some(&tydef.type_), + ty, + match kind { + clean::TyAssocConstItem(_) => None, + clean::AssocConstItem(_, default) => Some(default), + _ => unreachable!(), + }, link.anchor(if trait_.is_some() { &source_id } else { &id }), - 0, + "", cx, ); w.write_str("

"); w.write_str("
"); } - clean::AssocConstItem(ref ty, _) => { + clean::TyAssocTypeItem(generics, bounds) => { let source_id = format!("{}.{}", item_type, name); let id = cx.derive_id(source_id.clone()); - write!( - w, - "
", - id, item_type, in_trait_class - ); - render_rightside(w, cx, item, containing_item, render_mode); + write!(w, "
", id, item_type, in_trait_class); write!(w, "", id); w.write_str("

"); - assoc_const( + assoc_type( w, item, - ty, + generics, + bounds, + None, link.anchor(if trait_.is_some() { &source_id } else { &id }), - "", + 0, cx, ); w.write_str("

"); w.write_str("
"); } - clean::AssocTypeItem(ref generics, ref bounds, ref default) => { + clean::AssocTypeItem(tydef, _bounds) => { let source_id = format!("{}.{}", item_type, name); let id = cx.derive_id(source_id.clone()); - write!(w, "
", id, item_type, in_trait_class,); + write!( + w, + "
", + id, item_type, in_trait_class + ); write!(w, "", id); w.write_str("

"); assoc_type( w, item, - generics, - bounds, - default.as_ref(), + &tydef.generics, + &[], // intentionally leaving out bounds + Some(tydef.item_type.as_ref().unwrap_or(&tydef.type_)), link.anchor(if trait_.is_some() { &source_id } else { &id }), 0, cx, @@ -1748,13 +1797,13 @@ pub(crate) fn render_impl_summary( write!(w, "{}", i.inner_impl().print(use_absolute, cx)); if show_def_docs { for it in &i.inner_impl().items { - if let clean::TypedefItem(ref tydef, _) = *it.kind { + if let clean::AssocTypeItem(ref tydef, ref _bounds) = *it.kind { w.write_str(" "); assoc_type( w, it, &tydef.generics, - &[], + &[], // intentionally leaving out bounds Some(&tydef.type_), AssocItemLink::Anchor(None), 0, @@ -1822,7 +1871,7 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) { clean::PrimitiveItem(_) => sidebar_primitive(cx, buffer, it), clean::UnionItem(ref u) => sidebar_union(cx, buffer, it, u), clean::EnumItem(ref e) => sidebar_enum(cx, buffer, it, e), - clean::TypedefItem(_, _) => sidebar_typedef(cx, buffer, it), + clean::TypedefItem(_) => sidebar_typedef(cx, buffer, it), clean::ModuleItem(ref m) => sidebar_module(buffer, &m.items), clean::ForeignTypeItem => sidebar_foreign_type(cx, buffer, it), _ => {} @@ -1917,7 +1966,7 @@ fn get_methods( if !for_deref || should_render_item(item, deref_mut, tcx) { Some(SidebarLink { name, - url: get_next_url(used_links, format!("method.{}", name)), + url: get_next_url(used_links, format!("{}.{}", ItemType::Method, name)), }) } else { None @@ -1937,7 +1986,7 @@ fn get_associated_constants( .filter_map(|item| match item.name { Some(name) if !name.is_empty() && item.is_associated_const() => Some(SidebarLink { name, - url: get_next_url(used_links, format!("associatedconstant.{}", name)), + url: get_next_url(used_links, format!("{}.{}", ItemType::AssocConst, name)), }), _ => None, }) @@ -2106,7 +2155,7 @@ fn sidebar_deref_methods( debug!("found Deref: {:?}", impl_); if let Some((target, real_target)) = impl_.inner_impl().items.iter().find_map(|item| match *item.kind { - clean::TypedefItem(ref t, true) => Some(match *t { + clean::AssocTypeItem(ref t, _) => Some(match *t { clean::Typedef { item_type: Some(ref type_), .. } => (type_, &t.type_), _ => (&t.type_, &t.type_), }), @@ -2281,19 +2330,37 @@ fn sidebar_trait(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, t: &clean print_sidebar_section( buf, &t.items, - "associated-types", - "Associated Types", + "required-associated-types", + "Required Associated Types", + |m| m.is_ty_associated_type(), + |sym| format!("{0}", sym, ItemType::AssocType), + ); + + print_sidebar_section( + buf, + &t.items, + "provided-associated-types", + "Provided Associated Types", |m| m.is_associated_type(), - |sym| format!("{0}", sym), + |sym| format!("{0}", sym, ItemType::AssocType), + ); + + print_sidebar_section( + buf, + &t.items, + "required-associated-consts", + "Required Associated Constants", + |m| m.is_ty_associated_const(), + |sym| format!("{0}", sym, ItemType::AssocConst), ); print_sidebar_section( buf, &t.items, - "associated-const", - "Associated Constants", + "provided-associated-consts", + "Provided Associated Constants", |m| m.is_associated_const(), - |sym| format!("{0}", sym), + |sym| format!("{0}", sym, ItemType::AssocConst), ); print_sidebar_section( @@ -2302,7 +2369,7 @@ fn sidebar_trait(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, t: &clean "required-methods", "Required Methods", |m| m.is_ty_method(), - |sym| format!("{0}", sym), + |sym| format!("{0}", sym, ItemType::TyMethod), ); print_sidebar_section( @@ -2311,7 +2378,7 @@ fn sidebar_trait(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, t: &clean "provided-methods", "Provided Methods", |m| m.is_method(), - |sym| format!("{0}", sym), + |sym| format!("{0}", sym, ItemType::Method), ); let cache = cx.cache(); diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 99d7475da3396..1ed5c662c41cc 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -141,7 +141,7 @@ pub(super) fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer, item_vars.render_into(buf).unwrap(); - match *item.kind { + match &*item.kind { clean::ModuleItem(ref m) => item_module(buf, cx, item, &m.items), clean::FunctionItem(ref f) | clean::ForeignFunctionItem(ref f) => { item_function(buf, cx, item, f) @@ -150,7 +150,7 @@ pub(super) fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer, clean::StructItem(ref s) => item_struct(buf, cx, item, s), clean::UnionItem(ref s) => item_union(buf, cx, item, s), clean::EnumItem(ref e) => item_enum(buf, cx, item, e), - clean::TypedefItem(ref t, is_associated) => item_typedef(buf, cx, item, t, is_associated), + clean::TypedefItem(ref t) => item_typedef(buf, cx, item, t), clean::MacroItem(ref m) => item_macro(buf, cx, item, m), clean::ProcMacroItem(ref m) => item_proc_macro(buf, cx, item, m), clean::PrimitiveItem(_) => item_primitive(buf, cx, item), @@ -507,13 +507,15 @@ fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean:: fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Trait) { let bounds = bounds(&t.bounds, false, cx); - let types = t.items.iter().filter(|m| m.is_associated_type()).collect::>(); - let consts = t.items.iter().filter(|m| m.is_associated_const()).collect::>(); - let required = t.items.iter().filter(|m| m.is_ty_method()).collect::>(); - let provided = t.items.iter().filter(|m| m.is_method()).collect::>(); - let count_types = types.len(); - let count_consts = consts.len(); - let count_methods = required.len() + provided.len(); + let required_types = t.items.iter().filter(|m| m.is_ty_associated_type()).collect::>(); + let provided_types = t.items.iter().filter(|m| m.is_associated_type()).collect::>(); + let required_consts = t.items.iter().filter(|m| m.is_ty_associated_const()).collect::>(); + let provided_consts = t.items.iter().filter(|m| m.is_associated_const()).collect::>(); + let required_methods = t.items.iter().filter(|m| m.is_ty_method()).collect::>(); + let provided_methods = t.items.iter().filter(|m| m.is_method()).collect::>(); + let count_types = required_types.len() + provided_types.len(); + let count_consts = required_consts.len() + provided_consts.len(); + let count_methods = required_methods.len() + provided_methods.len(); // Output the trait definition wrap_into_docblock(w, |w| { @@ -554,16 +556,18 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra ), ); } - for t in &types { - render_assoc_item( - w, - t, - AssocItemLink::Anchor(None), - ItemType::Trait, - cx, - RenderMode::Normal, - ); - w.write_str(";\n"); + for types in [&required_types, &provided_types] { + for t in types { + render_assoc_item( + w, + t, + AssocItemLink::Anchor(None), + ItemType::Trait, + cx, + RenderMode::Normal, + ); + w.write_str(";\n"); + } } // If there are too many associated constants, hide everything after them // We also do this if the types + consts is large because otherwise we could @@ -582,28 +586,30 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra ), ); } - if !types.is_empty() && !consts.is_empty() { + if count_types != 0 && (count_consts != 0 || count_methods != 0) { w.write_str("\n"); } - for t in &consts { - render_assoc_item( - w, - t, - AssocItemLink::Anchor(None), - ItemType::Trait, - cx, - RenderMode::Normal, - ); - w.write_str(";\n"); + for consts in [&required_consts, &provided_consts] { + for c in consts { + render_assoc_item( + w, + c, + AssocItemLink::Anchor(None), + ItemType::Trait, + cx, + RenderMode::Normal, + ); + w.write_str(";\n"); + } } if !toggle && should_hide_fields(count_methods) { toggle = true; toggle_open(w, format_args!("{} methods", count_methods)); } - if !consts.is_empty() && !required.is_empty() { + if count_consts != 0 && count_methods != 0 { w.write_str("\n"); } - for (pos, m) in required.iter().enumerate() { + for (pos, m) in required_methods.iter().enumerate() { render_assoc_item( w, m, @@ -614,14 +620,14 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra ); w.write_str(";\n"); - if pos < required.len() - 1 { + if pos < required_methods.len() - 1 { w.write_str(""); } } - if !required.is_empty() && !provided.is_empty() { + if !required_methods.is_empty() && !provided_methods.is_empty() { w.write_str("\n"); } - for (pos, m) in provided.iter().enumerate() { + for (pos, m) in provided_methods.iter().enumerate() { render_assoc_item( w, m, @@ -640,7 +646,8 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra w.write_str(" { ... }\n"); } } - if pos < provided.len() - 1 { + + if pos < provided_methods.len() - 1 { w.write_str(""); } } @@ -703,53 +710,77 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra } } - if !types.is_empty() { + if !required_types.is_empty() { write_small_section_header( w, - "associated-types", - "Associated Types", + "required-associated-types", + "Required Associated Types", "
", ); - for t in types { + for t in required_types { + trait_item(w, cx, t, it); + } + w.write_str("
"); + } + if !provided_types.is_empty() { + write_small_section_header( + w, + "provided-associated-types", + "Provided Associated Types", + "
", + ); + for t in provided_types { trait_item(w, cx, t, it); } w.write_str("
"); } - if !consts.is_empty() { + if !required_consts.is_empty() { + write_small_section_header( + w, + "required-associated-consts", + "Required Associated Constants", + "
", + ); + for t in required_consts { + trait_item(w, cx, t, it); + } + w.write_str("
"); + } + if !provided_consts.is_empty() { write_small_section_header( w, - "associated-const", - "Associated Constants", + "provided-associated-consts", + "Provided Associated Constants", "
", ); - for t in consts { + for t in provided_consts { trait_item(w, cx, t, it); } w.write_str("
"); } // Output the documentation for each function individually - if !required.is_empty() { + if !required_methods.is_empty() { write_small_section_header( w, "required-methods", - "Required methods", + "Required Methods", "
", ); - for m in required { + for m in required_methods { trait_item(w, cx, m, it); } w.write_str("
"); } - if !provided.is_empty() { + if !provided_methods.is_empty() { write_small_section_header( w, "provided-methods", - "Provided methods", + "Provided Methods", "
", ); - for m in provided { + for m in provided_methods { trait_item(w, cx, m, it); } w.write_str("
"); @@ -933,25 +964,11 @@ fn item_opaque_ty(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean: render_assoc_items(w, cx, it, it.def_id.expect_def_id(), AssocItemRender::All) } -fn item_typedef( - w: &mut Buffer, - cx: &Context<'_>, - it: &clean::Item, - t: &clean::Typedef, - is_associated: bool, -) { - fn write_content( - w: &mut Buffer, - cx: &Context<'_>, - it: &clean::Item, - t: &clean::Typedef, - is_associated: bool, - ) { +fn item_typedef(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Typedef) { + fn write_content(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Typedef) { wrap_item(w, "typedef", |w| { render_attributes_in_pre(w, it, ""); - if !is_associated { - write!(w, "{}", it.visibility.print_with_space(it.def_id, cx)); - } + write!(w, "{}", it.visibility.print_with_space(it.def_id, cx)); write!( w, "type {}{}{where_clause} = {type_};", @@ -963,14 +980,7 @@ fn item_typedef( }); } - // If this is an associated typedef, we don't want to wrap it into a docblock. - if is_associated { - write_content(w, cx, it, t, is_associated); - } else { - wrap_into_docblock(w, |w| { - write_content(w, cx, it, t, is_associated); - }); - } + wrap_into_docblock(w, |w| write_content(w, cx, it, t)); document(w, cx, it, None, HeadingOffset::H2); diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index b0ce63a4ec1d5..ab52304491a2b 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -3,7 +3,7 @@ (function() { // This mapping table should match the discriminants of -// `rustdoc::html::item_type::ItemType` type in Rust. +// `rustdoc::formats::item_type::ItemType` type in Rust. var itemTypes = [ "mod", "externcrate", diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index bc638200533fd..a9a6a31fccd0d 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -219,20 +219,23 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum { StaticItem(s) => ItemEnum::Static(s.into_tcx(tcx)), ForeignStaticItem(s) => ItemEnum::Static(s.into_tcx(tcx)), ForeignTypeItem => ItemEnum::ForeignType, - TypedefItem(t, _) => ItemEnum::Typedef(t.into_tcx(tcx)), + TypedefItem(t) => ItemEnum::Typedef(t.into_tcx(tcx)), OpaqueTyItem(t) => ItemEnum::OpaqueTy(t.into_tcx(tcx)), ConstantItem(c) => ItemEnum::Constant(c.into_tcx(tcx)), MacroItem(m) => ItemEnum::Macro(m.source), ProcMacroItem(m) => ItemEnum::ProcMacro(m.into_tcx(tcx)), PrimitiveItem(p) => ItemEnum::PrimitiveType(p.as_sym().to_string()), + TyAssocConstItem(ty) => ItemEnum::AssocConst { type_: ty.into_tcx(tcx), default: None }, AssocConstItem(ty, default) => { - ItemEnum::AssocConst { type_: ty.into_tcx(tcx), default: default.map(|c| c.expr(tcx)) } + ItemEnum::AssocConst { type_: ty.into_tcx(tcx), default: Some(default.expr(tcx)) } } - AssocTypeItem(g, b, t) => ItemEnum::AssocType { + TyAssocTypeItem(g, b) => ItemEnum::AssocType { generics: (*g).into_tcx(tcx), bounds: b.into_iter().map(|x| x.into_tcx(tcx)).collect(), - default: t.map(|x| x.into_tcx(tcx)), + default: None, }, + // FIXME: do not map to Typedef but to a custom variant + AssocTypeItem(t, _) => ItemEnum::Typedef(t.into_tcx(tcx)), // `convert_item` early returns `None` for striped items StrippedItem(_) => unreachable!(), KeywordItem(_) => { diff --git a/src/librustdoc/passes/check_doc_test_visibility.rs b/src/librustdoc/passes/check_doc_test_visibility.rs index 2b17e3457d293..b541fb63bd413 100644 --- a/src/librustdoc/passes/check_doc_test_visibility.rs +++ b/src/librustdoc/passes/check_doc_test_visibility.rs @@ -61,9 +61,9 @@ crate fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -> boo *item.kind, clean::StructFieldItem(_) | clean::VariantItem(_) - | clean::AssocConstItem(_, _) + | clean::AssocConstItem(..) | clean::AssocTypeItem(..) - | clean::TypedefItem(_, _) + | clean::TypedefItem(_) | clean::StaticItem(_) | clean::ConstantItem(_) | clean::ExternCrateItem { .. } diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index 2852c3b616df1..4ab942c8f1bdc 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -93,7 +93,7 @@ crate fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate let target = items .iter() .find_map(|item| match *item.kind { - TypedefItem(ref t, true) => Some(&t.type_), + AssocTypeItem(ref t, _) => Some(&t.type_), _ => None, }) .expect("Deref impl without Target type"); diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs index 717dc078b343c..82627aaf7a4cb 100644 --- a/src/librustdoc/passes/stripper.rs +++ b/src/librustdoc/passes/stripper.rs @@ -41,6 +41,7 @@ impl<'a> DocFolder for Stripper<'a> { | clean::ConstantItem(..) | clean::UnionItem(..) | clean::AssocConstItem(..) + | clean::AssocTypeItem(..) | clean::TraitAliasItem(..) | clean::MacroItem(..) | clean::ForeignTypeItem => { @@ -72,8 +73,8 @@ impl<'a> DocFolder for Stripper<'a> { clean::ImplItem(..) => {} - // tymethods have no control over privacy - clean::TyMethodItem(..) => {} + // tymethods etc. have no control over privacy + clean::TyMethodItem(..) | clean::TyAssocConstItem(..) | clean::TyAssocTypeItem(..) => {} // Proc-macros are always public clean::ProcMacroItem(..) => {} @@ -81,9 +82,6 @@ impl<'a> DocFolder for Stripper<'a> { // Primitives are never stripped clean::PrimitiveItem(..) => {} - // Associated types are never stripped - clean::AssocTypeItem(..) => {} - // Keywords are never stripped clean::KeywordItem(..) => {} } diff --git a/src/librustdoc/visit.rs b/src/librustdoc/visit.rs index b16cab1c646f1..ef50292674276 100644 --- a/src/librustdoc/visit.rs +++ b/src/librustdoc/visit.rs @@ -26,7 +26,7 @@ crate trait DocVisitor: Sized { ExternCrateItem { src: _ } | ImportItem(_) | FunctionItem(_) - | TypedefItem(_, _) + | TypedefItem(_) | OpaqueTyItem(_) | StaticItem(_) | ConstantItem(_) @@ -40,7 +40,9 @@ crate trait DocVisitor: Sized { | MacroItem(_) | ProcMacroItem(_) | PrimitiveItem(_) - | AssocConstItem(_, _) + | TyAssocConstItem(..) + | AssocConstItem(..) + | TyAssocTypeItem(..) | AssocTypeItem(..) | KeywordItem(_) => {} } diff --git a/src/test/rustdoc/assoc-consts.rs b/src/test/rustdoc/assoc-consts.rs index ff7fd66391628..0ac6dc763df88 100644 --- a/src/test/rustdoc/assoc-consts.rs +++ b/src/test/rustdoc/assoc-consts.rs @@ -1,8 +1,8 @@ pub trait Foo { // @has assoc_consts/trait.Foo.html '//*[@class="rust trait"]' \ - // 'const FOO: usize;' + // 'const FOO: usize = 13usize;' // @has - '//*[@id="associatedconstant.FOO"]' 'const FOO: usize' - const FOO: usize = 12; + const FOO: usize = 12 + 1; // @has - '//*[@id="associatedconstant.FOO_NO_DEFAULT"]' 'const FOO_NO_DEFAULT: bool' const FOO_NO_DEFAULT: bool; // @!has - FOO_HIDDEN diff --git a/src/test/rustdoc/extern-default-method.no_href_on_anchor.html b/src/test/rustdoc/extern-default-method.no_href_on_anchor.html new file mode 100644 index 0000000000000..dab0a64952955 --- /dev/null +++ b/src/test/rustdoc/extern-default-method.no_href_on_anchor.html @@ -0,0 +1 @@ +provided(&self) \ No newline at end of file diff --git a/src/test/rustdoc/extern-default-method.rs b/src/test/rustdoc/extern-default-method.rs index 93cf16346b6f7..8139f5b2619b3 100644 --- a/src/test/rustdoc/extern-default-method.rs +++ b/src/test/rustdoc/extern-default-method.rs @@ -1,9 +1,23 @@ // aux-build:rustdoc-extern-default-method.rs // ignore-cross-compile +// ignore-tidy-linelength extern crate rustdoc_extern_default_method as ext; +// For this test, the dependency is compiled but not documented. +// +// Still, the struct from the external crate and its impl should be documented since +// the struct is re-exported from this crate. +// However, the method in the trait impl should *not* have a link (an `href` attribute) to +// its corresponding item in the trait declaration since it would otherwise be broken. +// +// In older versions of rustdoc, the impl item (`a[@class="fnname"]`) used to link to +// `#method.provided` – i.e. "to itself". Put in quotes since that was actually incorrect in +// general: If the type `Struct` also had an inherent method called `provided`, the impl item +// would link to that one even though those two methods are distinct items! + // @count extern_default_method/struct.Struct.html '//*[@id="method.provided"]' 1 -// @has extern_default_method/struct.Struct.html '//*[@id="method.provided"]//a[@class="fnname"]/@href' #method.provided +// @count extern_default_method/struct.Struct.html '//*[@id="method.provided"]//a[@class="fnname"]' 1 +// @snapshot no_href_on_anchor - '//*[@id="method.provided"]//a[@class="fnname"]' // @has extern_default_method/struct.Struct.html '//*[@id="method.provided"]//a[@class="anchor"]/@href' #method.provided pub use ext::Struct; diff --git a/src/test/rustdoc/intra-doc/prim-self.rs b/src/test/rustdoc/intra-doc/prim-self.rs index de053d70f0354..c7ce71b15f30c 100644 --- a/src/test/rustdoc/intra-doc/prim-self.rs +++ b/src/test/rustdoc/intra-doc/prim-self.rs @@ -5,6 +5,7 @@ #![feature(no_core)] #![feature(rustdoc_internals)] #![feature(inherent_associated_types)] +#![feature(lang_items)] #![no_core] /// [Self::f] @@ -35,3 +36,6 @@ pub struct S; impl S { pub fn f() {} } + +#[lang = "sized"] +pub trait Sized {} diff --git a/src/test/rustdoc/sidebar-items.rs b/src/test/rustdoc/sidebar-items.rs index 375cad9da7f88..b5b681ab085bf 100644 --- a/src/test/rustdoc/sidebar-items.rs +++ b/src/test/rustdoc/sidebar-items.rs @@ -1,3 +1,4 @@ +#![feature(associated_type_defaults)] #![crate_name = "foo"] // @has foo/trait.Foo.html @@ -5,12 +6,18 @@ // @has - '//*[@class="sidebar-elems"]//section//a' 'bar' // @has - '//*[@class="sidebar-title"]/a[@href="#provided-methods"]' 'Provided Methods' // @has - '//*[@class="sidebar-elems"]//section//a' 'foo' -// @has - '//*[@class="sidebar-title"]/a[@href="#associated-const"]' 'Associated Constants' +// @has - '//*[@class="sidebar-title"]/a[@href="#required-associated-consts"]' 'Required Associated Constants' +// @has - '//*[@class="sidebar-elems"]//section//a' 'FOO' +// @has - '//*[@class="sidebar-title"]/a[@href="#provided-associated-consts"]' 'Provided Associated Constants' // @has - '//*[@class="sidebar-elems"]//section//a' 'BAR' -// @has - '//*[@class="sidebar-title"]/a[@href="#associated-types"]' 'Associated Types' +// @has - '//*[@class="sidebar-title"]/a[@href="#required-associated-types"]' 'Required Associated Types' // @has - '//*[@class="sidebar-elems"]//section//a' 'Output' +// @has - '//*[@class="sidebar-title"]/a[@href="#provided-associated-types"]' 'Provided Associated Types' +// @has - '//*[@class="sidebar-elems"]//section//a' 'Extra' pub trait Foo { + const FOO: usize; const BAR: u32 = 0; + type Extra: Copy = (); type Output: ?Sized; fn foo() {}