From 79762b8c1863d767b7c3457a821cc6e4b7e51ac5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Sun, 24 Aug 2025 06:43:24 +0200 Subject: [PATCH] [WIP] --- compiler/rustc_passes/src/check_attr.rs | 66 +++++++++++---- library/std/src/keyword_docs.rs | 83 +++++++++---------- src/librustdoc/clean/types.rs | 39 +++++++-- src/librustdoc/clean/utils.rs | 9 +- src/librustdoc/fold.rs | 2 +- src/librustdoc/formats/cache.rs | 6 +- src/librustdoc/formats/item_type.rs | 2 +- src/librustdoc/html/render/context.rs | 13 ++- src/librustdoc/html/render/mod.rs | 2 + src/librustdoc/html/render/print_item.rs | 18 +++- src/librustdoc/html/render/search_index.rs | 28 +++++-- src/librustdoc/html/static/js/main.js | 1 + src/librustdoc/html/static/js/rustdoc.d.ts | 3 +- src/librustdoc/html/static/js/search.js | 11 ++- src/librustdoc/json/conversions.rs | 4 +- .../passes/check_doc_test_visibility.rs | 2 +- src/librustdoc/passes/propagate_stability.rs | 2 +- src/librustdoc/passes/stripper.rs | 2 +- src/librustdoc/visit.rs | 2 +- 19 files changed, 201 insertions(+), 94 deletions(-) diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 70eae82392cc5..e8cca86fc1f52 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -677,6 +677,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } + #[expect(dead_code)] // FIXME: remove fn etc. entirely fn doc_attr_str_error(&self, meta: &MetaItemInner, attr_name: &str) { self.dcx().emit_err(errors::DocExpectStr { attr_span: meta.span(), attr_name }); } @@ -821,17 +822,60 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } fn check_doc_keyword(&self, meta: &MetaItemInner, hir_id: HirId) { + fn is_doc_keyword(s: Symbol) -> bool { - // FIXME: Once rustdoc can handle URL conflicts on case insensitive file systems, we - // can remove the `SelfTy` case here, remove `sym::SelfTy`, and update the - // `#[doc(keyword = "SelfTy")` attribute in `library/std/src/keyword_docs.rs`. - s.is_reserved(|| edition::LATEST_STABLE_EDITION) || s.is_weak() || s == sym::SelfTy + s.is_reserved(|| edition::LATEST_STABLE_EDITION) || s.is_weak() } - let doc_keyword = match meta.value_str() { - Some(value) if value != sym::empty => value, - _ => return self.doc_attr_str_error(meta, "keyword"), - }; + // FIXME: Reject unsafe in various places. + if let Some(values) = meta.meta_item_list() { + let mut keyword = None; + // XXX XXX XXX docs + let mut xx_url_name_override_xx = None; + for value in values { + match value { + MetaItemInner::MetaItem(meta) => { + if meta.has_name(sym::encode) + && let Some(x) = meta.value_str() + { + if xx_url_name_override_xx.is_some() { + self.dcx() + .span_err(meta.span, "[[ encoding provided more than once ]]"); + } + xx_url_name_override_xx = Some(x); + } else { + self.dcx().span_err(meta.span, "[[ invalid format ]]"); + } + } + MetaItemInner::Lit(lit) => { + if let Some(kw) = lit.value_str() { + if keyword.is_some() { + self.dcx() + .span_err(meta.span(), "[[ keyword provided more than once ]]"); + } + keyword = Some(kw); + } else { + self.dcx().span_err(meta.span(), "[[ invalid format ]]"); + } + } + } + } + + _ = xx_url_name_override_xx; + + if let Some(keyword) = keyword { + if !is_doc_keyword(keyword) { + self.dcx().emit_err(errors::DocKeywordNotKeyword { + span: meta.name_value_literal_span().unwrap_or_else(|| meta.span()), + keyword, + }); + } + } else { + self.dcx().span_err(meta.span(), "[[ no keyword provided ]]"); + } + } else { + self.dcx().span_err(meta.span(), "[[ invalid format ]]"); + } let item_kind = match self.tcx.hir_node(hir_id) { hir::Node::Item(item) => Some(&item.kind), @@ -849,12 +893,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { return; } } - if !is_doc_keyword(doc_keyword) { - self.dcx().emit_err(errors::DocKeywordNotKeyword { - span: meta.name_value_literal_span().unwrap_or_else(|| meta.span()), - keyword: doc_keyword, - }); - } } fn check_doc_fake_variadic(&self, meta: &MetaItemInner, hir_id: HirId) { diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index 1c55824ab9061..8777b984ce67a 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -1,4 +1,4 @@ -#[doc(keyword = "as")] +#[doc(keyword("as"))] // /// Cast between types, or rename an import. /// @@ -46,7 +46,7 @@ /// [mut-cast]: primitive.pointer.html#method.cast-1 mod as_keyword {} -#[doc(keyword = "break")] +#[doc(keyword("break"))] // /// Exit early from a loop or labelled block. /// @@ -144,7 +144,7 @@ mod as_keyword {} /// ../reference/expressions/loop-expr.html#break-and-loop-values mod break_keyword {} -#[doc(keyword = "const")] +#[doc(keyword("const"))] // /// Compile-time constants, compile-time blocks, compile-time evaluable functions, and raw pointers. /// @@ -221,7 +221,7 @@ mod break_keyword {} /// [const-eval]: ../reference/const_eval.html mod const_keyword {} -#[doc(keyword = "continue")] +#[doc(keyword("continue"))] // /// Skip to the next iteration of a loop. /// @@ -261,7 +261,7 @@ mod const_keyword {} /// [continue expressions]: ../reference/expressions/loop-expr.html#continue-expressions mod continue_keyword {} -#[doc(keyword = "crate")] +#[doc(keyword("crate"))] // /// A Rust binary or library. /// @@ -298,7 +298,7 @@ mod continue_keyword {} /// [Reference]: ../reference/items/extern-crates.html mod crate_keyword {} -#[doc(keyword = "else")] +#[doc(keyword("else"))] // /// What expression to evaluate when an [`if`] condition evaluates to [`false`]. /// @@ -351,7 +351,7 @@ mod crate_keyword {} /// [`if`]: keyword.if.html mod else_keyword {} -#[doc(keyword = "enum")] +#[doc(keyword("enum"))] // /// A type that can be any one of several variants. /// @@ -406,7 +406,7 @@ mod else_keyword {} /// [Reference]: ../reference/items/enumerations.html mod enum_keyword {} -#[doc(keyword = "extern")] +#[doc(keyword("extern"))] // /// Link to or import external code. /// @@ -453,7 +453,7 @@ mod enum_keyword {} /// [`crate`]: keyword.crate.html mod extern_keyword {} -#[doc(keyword = "false")] +#[doc(keyword("false"))] // /// A value of type [`bool`] representing logical **false**. /// @@ -464,7 +464,7 @@ mod extern_keyword {} /// [`true`]: keyword.true.html mod false_keyword {} -#[doc(keyword = "fn")] +#[doc(keyword("fn"))] // /// A function or function pointer. /// @@ -531,7 +531,7 @@ mod false_keyword {} /// [Reference]: ../reference/items/functions.html mod fn_keyword {} -#[doc(keyword = "for")] +#[doc(keyword("for"))] // /// Iteration with [`in`], trait implementation with [`impl`], or [higher-ranked trait bounds] /// (`for<'a>`). @@ -613,7 +613,7 @@ mod fn_keyword {} /// [Reference]: ../reference/expressions/loop-expr.html#iterator-loops mod for_keyword {} -#[doc(keyword = "if")] +#[doc(keyword("if"))] // /// Evaluate a block if a condition holds. /// @@ -687,7 +687,7 @@ mod for_keyword {} /// [Reference]: ../reference/expressions/if-expr.html mod if_keyword {} -#[doc(keyword = "impl")] +#[doc(keyword("impl"))] // /// Implementations of functionality for a type, or a type implementing some functionality. /// @@ -777,7 +777,7 @@ mod if_keyword {} /// [book2]: ../book/ch10-02-traits.html#returning-types-that-implement-traits mod impl_keyword {} -#[doc(keyword = "in")] +#[doc(keyword("in"))] // /// Iterate over a series of values with [`for`]. /// @@ -809,7 +809,7 @@ mod impl_keyword {} /// [Reference]: ../reference/visibility-and-privacy.html#pubin-path-pubcrate-pubsuper-and-pubself mod in_keyword {} -#[doc(keyword = "let")] +#[doc(keyword("let"))] // /// Bind a value to a variable. /// @@ -872,7 +872,7 @@ mod in_keyword {} /// [Reference]: ../reference/statements.html#let-statements mod let_keyword {} -#[doc(keyword = "loop")] +#[doc(keyword("loop"))] // /// Loop indefinitely. /// @@ -922,7 +922,7 @@ mod let_keyword {} /// [Reference]: ../reference/expressions/loop-expr.html mod loop_keyword {} -#[doc(keyword = "match")] +#[doc(keyword("match"))] // /// Control flow based on pattern matching. /// @@ -972,7 +972,7 @@ mod loop_keyword {} /// [Reference]: ../reference/expressions/match-expr.html mod match_keyword {} -#[doc(keyword = "mod")] +#[doc(keyword("mod"))] // /// Organize code into [modules]. /// @@ -1000,7 +1000,7 @@ mod match_keyword {} /// [modules]: ../reference/items/modules.html mod mod_keyword {} -#[doc(keyword = "move")] +#[doc(keyword("move"))] // /// Capture a [closure]'s environment by value. /// @@ -1057,7 +1057,7 @@ mod mod_keyword {} /// [threads]: ../book/ch16-01-threads.html#using-move-closures-with-threads mod move_keyword {} -#[doc(keyword = "mut")] +#[doc(keyword("mut"))] // /// A mutable variable, reference, or pointer. /// @@ -1115,7 +1115,7 @@ mod move_keyword {} /// [Reference]: ../reference/types/pointer.html#mutable-references-mut mod mut_keyword {} -#[doc(keyword = "pub")] +#[doc(keyword("pub"))] // /// Make an item visible to others. /// @@ -1130,7 +1130,7 @@ mod mut_keyword {} /// [Rust by Example]:../rust-by-example/mod/visibility.html mod pub_keyword {} -#[doc(keyword = "ref")] +#[doc(keyword("ref"))] // /// Bind by reference during pattern matching. /// @@ -1180,7 +1180,7 @@ mod pub_keyword {} /// [Reference]: ../reference/patterns.html#identifier-patterns mod ref_keyword {} -#[doc(keyword = "return")] +#[doc(keyword("return"))] // /// Returns a value from a function. /// @@ -1257,7 +1257,7 @@ mod ref_keyword {} /// [`async`]: ../std/keyword.async.html mod return_keyword {} -#[doc(keyword = "self")] +#[doc(keyword("self"))] // /// The receiver of a method, or the current module. /// @@ -1350,11 +1350,8 @@ mod return_keyword {} /// [Reference]: ../reference/items/associated-items.html#methods mod self_keyword {} -// FIXME: Once rustdoc can handle URL conflicts on case insensitive file systems, we can replace -// these two lines with `#[doc(keyword = "Self")]` and update `is_doc_keyword` in -// `CheckAttrVisitor`. -#[doc(alias = "Self")] -#[doc(keyword = "SelfTy")] +// XXX XXX XXX +#[doc(keyword("Self", encode = "SelfTy"))] // /// The implementing type within a [`trait`] or [`impl`] block, or the current type within a type /// definition. @@ -1421,7 +1418,7 @@ mod self_keyword {} /// [`trait`]: keyword.trait.html mod self_upper_keyword {} -#[doc(keyword = "static")] +#[doc(keyword("static"))] // /// A static item is a value which is valid for the entire duration of your /// program (a `'static` lifetime). @@ -1507,7 +1504,7 @@ mod self_upper_keyword {} /// [Reference]: ../reference/items/static-items.html mod static_keyword {} -#[doc(keyword = "struct")] +#[doc(keyword("struct"))] // /// A type that is composed of other types. /// @@ -1615,7 +1612,7 @@ mod static_keyword {} /// [reference]: ../reference/items/structs.html mod struct_keyword {} -#[doc(keyword = "super")] +#[doc(keyword("super"))] // /// The parent of the current [module]. /// @@ -1641,7 +1638,7 @@ mod struct_keyword {} /// [Reference]: ../reference/paths.html#super mod super_keyword {} -#[doc(keyword = "trait")] +#[doc(keyword("trait"))] // /// A common interface for a group of types. /// @@ -1826,7 +1823,7 @@ mod super_keyword {} /// [Ref-Trait-Objects]: ../reference/types/trait-object.html mod trait_keyword {} -#[doc(keyword = "true")] +#[doc(keyword("true"))] // /// A value of type [`bool`] representing logical **true**. /// @@ -1853,7 +1850,7 @@ mod trait_keyword {} /// [`false`]: keyword.false.html mod true_keyword {} -#[doc(keyword = "type")] +#[doc(keyword("type"))] // /// Define an [alias] for an existing type. /// @@ -1905,7 +1902,7 @@ mod true_keyword {} /// [alias]: ../reference/items/type-aliases.html mod type_keyword {} -#[doc(keyword = "unsafe")] +#[doc(keyword("unsafe"))] // /// Code or interfaces whose [memory safety] cannot be verified by the type /// system. @@ -2174,7 +2171,7 @@ mod type_keyword {} /// [discussion on Rust Internals]: https://internals.rust-lang.org/t/what-does-unsafe-mean/6696 mod unsafe_keyword {} -#[doc(keyword = "use")] +#[doc(keyword("use"))] // /// Import or rename items from other crates or modules, use values under ergonomic clones /// semantic, or specify precise capturing with `use<..>`. @@ -2272,7 +2269,7 @@ mod unsafe_keyword {} /// [ref-impl-trait]: ../reference/types/impl-trait.html mod use_keyword {} -#[doc(keyword = "where")] +#[doc(keyword("where"))] // /// Add constraints that must be upheld to use an item. /// @@ -2372,7 +2369,7 @@ mod use_keyword {} /// [RFC]: https://github.com/rust-lang/rfcs/blob/master/text/0135-where.md mod where_keyword {} -#[doc(keyword = "while")] +#[doc(keyword("while"))] // /// Loop while a condition is upheld. /// @@ -2433,7 +2430,7 @@ mod while_keyword {} // 2018 Edition keywords #[doc(alias = "promise")] -#[doc(keyword = "async")] +#[doc(keyword("async"))] // /// Returns a [`Future`] instead of blocking the current thread. /// @@ -2492,7 +2489,7 @@ mod while_keyword {} /// [async book blocks]: https://rust-lang.github.io/async-book/part-guide/more-async-await.html#async-blocks mod async_keyword {} -#[doc(keyword = "await")] +#[doc(keyword("await"))] // /// Suspend execution until the result of a [`Future`] is ready. /// @@ -2512,7 +2509,7 @@ mod async_keyword {} /// [`async`]: ../std/keyword.async.html mod await_keyword {} -#[doc(keyword = "dyn")] +#[doc(keyword("dyn"))] // /// `dyn` is a prefix of a [trait object]'s type. /// @@ -2548,7 +2545,7 @@ mod await_keyword {} /// [^1]: Formerly known as *object safe*. mod dyn_keyword {} -#[doc(keyword = "union")] +#[doc(keyword("union"))] // /// The [Rust equivalent of a C-style union][union]. /// diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 46aaa0068dee6..aefa8c167dac0 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -201,8 +201,8 @@ impl ExternalCrate { fn mapped_root_modules( &self, tcx: TyCtxt<'_>, - f: impl Fn(DefId, TyCtxt<'_>) -> Option<(DefId, T)>, - ) -> impl Iterator { + f: impl Fn(DefId, TyCtxt<'_>) -> Option, + ) -> impl Iterator { let root = self.def_id(); if root.is_local() { @@ -225,13 +225,30 @@ impl ExternalCrate { } } - pub(crate) fn keywords(&self, tcx: TyCtxt<'_>) -> impl Iterator { - fn as_keyword(did: DefId, tcx: TyCtxt<'_>) -> Option<(DefId, Symbol)> { + pub(crate) fn keywords( + &self, + tcx: TyCtxt<'_>, + ) -> impl Iterator)> { + fn as_keyword(did: DefId, tcx: TyCtxt<'_>) -> Option<(DefId, Symbol, Option)> { tcx.get_attrs(did, sym::doc) .flat_map(|attr| attr.meta_item_list().unwrap_or_default()) .filter(|meta| meta.has_name(sym::keyword)) - .find_map(|meta| meta.value_str()) - .map(|value| (did, value)) + .find_map(|meta| { + let mut keyword = None; + let mut xx_url_name_override_xx = None; + for value in meta.meta_item_list()? { + match value { + ast::MetaItemInner::MetaItem(meta) => { + if !meta.has_name(sym::encode) { + return None; + } + xx_url_name_override_xx = Some(meta.value_str()?); + } + ast::MetaItemInner::Lit(lit) => keyword = Some(lit.value_str()?), + } + } + keyword.map(|keyword| (did, keyword, xx_url_name_override_xx)) + }) } self.mapped_root_modules(tcx, as_keyword) @@ -735,7 +752,9 @@ impl Item { // Primitives and Keywords are written in the source code as private modules. // The modules need to be private so that nobody actually uses them, but the // keywords and primitives that they are documenting are public. - ItemKind::KeywordItem | ItemKind::PrimitiveItem(_) => return Some(Visibility::Public), + ItemKind::KeywordItem { .. } | ItemKind::PrimitiveItem(_) => { + return Some(Visibility::Public); + } // Variant fields inherit their enum's visibility. StructFieldItem(..) if is_field_vis_inherited(tcx, def_id) => { return None; @@ -942,7 +961,9 @@ pub(crate) enum ItemKind { AssocTypeItem(Box, Vec), /// An item that has been stripped by a rustdoc pass StrippedItem(Box), - KeywordItem, + KeywordItem { + xx_url_name_override_xx: Option, + }, } impl ItemKind { @@ -983,7 +1004,7 @@ impl ItemKind { | RequiredAssocTypeItem(..) | AssocTypeItem(..) | StrippedItem(_) - | KeywordItem => [].iter(), + | KeywordItem { .. } => [].iter(), } } diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 813fdee57e17a..4f6d3297fe9c6 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -70,8 +70,13 @@ pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate { cx, ) })); - m.items.extend(keywords.map(|(def_id, kw)| { - Item::from_def_id_and_parts(def_id, Some(kw), ItemKind::KeywordItem, cx) + m.items.extend(keywords.map(|(def_id, kw, xx_url_name_override_xx)| { + Item::from_def_id_and_parts( + def_id, + Some(kw), + ItemKind::KeywordItem { xx_url_name_override_xx }, + cx, + ) })); } diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index c03d16ad081bf..bdc6f48e1b1cd 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -96,7 +96,7 @@ pub(crate) trait DocFolder: Sized { | ImplAssocConstItem(..) | RequiredAssocTypeItem(..) | AssocTypeItem(..) - | KeywordItem => kind, + | KeywordItem { .. } => kind, } } diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index cb6837dd6140d..9bde0ff580233 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -372,7 +372,7 @@ impl DocFolder for CacheBuilder<'_, '_> { | clean::RequiredAssocTypeItem(..) | clean::AssocTypeItem(..) | clean::StrippedItem(..) - | clean::KeywordItem => { + | clean::KeywordItem { .. } => { // FIXME: Do these need handling? // The person writing this comment doesn't know. // So would rather leave them to an expert, @@ -591,6 +591,10 @@ fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::It ty: item.type_(), defid: Some(defid), name, + xx_url_name_override_xx: match item.kind { + clean::ItemKind::KeywordItem { xx_url_name_override_xx: x } => x, + _ => None, + }, module_path: parent_path.to_vec(), desc, parent: parent_did, diff --git a/src/librustdoc/formats/item_type.rs b/src/librustdoc/formats/item_type.rs index 142a9d7d8af25..ed2434bbece7a 100644 --- a/src/librustdoc/formats/item_type.rs +++ b/src/librustdoc/formats/item_type.rs @@ -147,7 +147,7 @@ impl<'a> From<&'a clean::Item> for ItemType { | clean::ImplAssocConstItem(..) => ItemType::AssocConst, clean::RequiredAssocTypeItem(..) | clean::AssocTypeItem(..) => ItemType::AssocType, clean::ForeignTypeItem => ItemType::ForeignType, - clean::KeywordItem => ItemType::Keyword, + clean::KeywordItem { .. } => ItemType::Keyword, clean::TraitAliasItem(..) => ItemType::TraitAlias, clean::ProcMacroItem(mac) => match mac.kind { MacroKind::Bang => ItemType::Macro, diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index e4fca09d64ff7..fc80465f64888 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -303,10 +303,11 @@ impl<'tcx> Context<'tcx> { } /// Construct a map of items shown in the sidebar to a plain-text summary of their docs. + // FIXME: Propagate xx_url_name_override_xx, it's gonna be nasty tho fn build_sidebar_items(&self, m: &clean::Module) -> BTreeMap> { // BTreeMap instead of HashMap to get a sorted output - let mut map: BTreeMap<_, Vec<_>> = BTreeMap::new(); - let mut inserted: FxHashMap> = FxHashMap::default(); + let mut map = BTreeMap::<_, Vec<_>>::new(); + let mut inserted = FxHashMap::<_, FxHashSet<_>>::default(); for item in &m.items { if item.is_stripped() { @@ -849,7 +850,13 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { let buf = self.render_item(item, false); // buf will be empty if the item is stripped and there is no redirect for it if !buf.is_empty() { - let name = item.name.as_ref().unwrap(); + let name = match item.kind { + clean::ItemKind::KeywordItem { xx_url_name_override_xx } => { + xx_url_name_override_xx + } + _ => None, + }.or(item.name) + .unwrap(); let item_type = item.type_(); let file_name = print_item_path(item_type, name.as_str()).to_string(); self.shared.ensure_dir(&self.dst)?; diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 8d7f05775064f..cd6b6c18acdc3 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -130,6 +130,8 @@ pub(crate) struct IndexItem { pub(crate) ty: ItemType, pub(crate) defid: Option, pub(crate) name: Symbol, + // XXX + pub(crate) xx_url_name_override_xx: Option, pub(crate) module_path: Vec, pub(crate) desc: String, pub(crate) parent: Option, diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 407238d66b8cd..5c7abf681024d 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -179,7 +179,7 @@ pub(super) fn print_item(cx: &Context<'_>, item: &clean::Item) -> impl fmt::Disp clean::StaticItem(..) | clean::ForeignStaticItem(..) => "Static ", clean::ConstantItem(..) => "Constant ", clean::ForeignTypeItem => "Foreign Type ", - clean::KeywordItem => "Keyword ", + clean::KeywordItem { .. } => "Keyword ", clean::TraitAliasItem(..) => "Trait Alias ", _ => { // We don't generate pages for any other type. @@ -259,7 +259,9 @@ pub(super) fn print_item(cx: &Context<'_>, item: &clean::Item) -> impl fmt::Disp clean::ForeignTypeItem => { write!(buf, "{}", item_foreign_type(cx, item)) } - clean::KeywordItem => write!(buf, "{}", item_keyword(cx, item)), + clean::KeywordItem { .. } => { + write!(buf, "{}", item_keyword(cx, item)) + } clean::TraitAliasItem(ta) => { write!(buf, "{}", item_trait_alias(cx, item, ta)) } @@ -504,7 +506,7 @@ fn item_module(cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) -> i write!( w, "
\ - \ + \ {name}\ \ {visibility_and_hidden}\ @@ -517,7 +519,15 @@ fn item_module(cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) -> i stab_tags = print_extra_info_tags(tcx, myitem, item, None), class = myitem.type_(), unsafety_flag = unsafety_flag, - href = print_item_path(myitem.type_(), myitem.name.unwrap().as_str()), + href = print_item_path( + myitem.type_(), + match myitem.kind { + clean::ItemKind::KeywordItem { xx_url_name_override_xx } => + xx_url_name_override_xx, + _ => None, + } + .or(myitem.name).unwrap().as_str() + ), title1 = myitem.type_(), title2 = full_path(cx, myitem), )?; diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index 41657e290ea21..91fa3417d851b 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -257,7 +257,7 @@ impl SerializedSearchIndex { slot.insert(self.path_data.len()); let (name, module_path) = path.split_last().unwrap(); self.push_path( - name.as_str().to_string(), + name.to_string(), PathData { ty, module_path: module_path.to_vec(), exact_module_path: None }, ) } @@ -523,6 +523,7 @@ impl SerializedSearchIndex { parent, deprecated, associated_item_disambiguator, + xx_url_name_override_xx, }| EntryData { krate: *map.get(krate).unwrap(), ty: *ty, @@ -532,6 +533,7 @@ impl SerializedSearchIndex { parent: parent.and_then(|path_id| map.get(&path_id).copied()), deprecated: *deprecated, associated_item_disambiguator: associated_item_disambiguator.clone(), + xx_url_name_override_xx: xx_url_name_override_xx.clone(), }, ), self.descs[id].clone(), @@ -790,6 +792,7 @@ struct EntryData { parent: Option, deprecated: bool, associated_item_disambiguator: Option, + xx_url_name_override_xx: Option, } impl Serialize for EntryData { @@ -805,7 +808,14 @@ impl Serialize for EntryData { seq.serialize_element(&self.parent.map(|id| id + 1).unwrap_or(0))?; seq.serialize_element(&if self.deprecated { 1 } else { 0 })?; if let Some(disambig) = &self.associated_item_disambiguator { - seq.serialize_element(&disambig)?; + seq.serialize_element(disambig)?; + } + if let Some(x) = &self.xx_url_name_override_xx { + // FIXME: temp approach + if self.associated_item_disambiguator.is_none() { + seq.serialize_element(&self.associated_item_disambiguator)?; + } + seq.serialize_element(x)?; } seq.end() } @@ -835,7 +845,9 @@ impl<'de> Deserialize<'de> for EntryData { let parent: SerializedOptional32 = v.next_element()?.ok_or_else(|| A::Error::missing_field("parent"))?; let deprecated: u32 = v.next_element()?.unwrap_or(0); + // XXX: This doesn't work. let associated_item_disambiguator: Option = v.next_element()?; + let xx_url_name_override_xx: Option = v.next_element()?; Ok(EntryData { krate, ty, @@ -845,6 +857,7 @@ impl<'de> Deserialize<'de> for EntryData { parent: Option::::from(parent).map(|path| path as usize), deprecated: deprecated != 0, associated_item_disambiguator, + xx_url_name_override_xx, }) } } @@ -1175,6 +1188,7 @@ pub(crate) fn build_index( ty: item.type_(), defid: item.item_id.as_def_id(), name: item.name.unwrap(), + xx_url_name_override_xx: None, module_path: fqp[..fqp.len() - 1].to_vec(), desc, parent: Some(parent), @@ -1263,7 +1277,7 @@ pub(crate) fn build_index( let krate = serialized_index.names.len(); slot.insert(krate); serialized_index.push( - crate_name.as_str().to_string(), + crate_name.to_string(), Some(PathData { ty: ItemType::ExternCrate, module_path: vec![], @@ -1277,6 +1291,7 @@ pub(crate) fn build_index( parent: None, deprecated: false, associated_item_disambiguator: None, + xx_url_name_override_xx: None, }), crate_doc, None, @@ -1301,7 +1316,7 @@ pub(crate) fn build_index( entry.insert(pathid); let (name, path) = fqp.split_last().unwrap(); serialized_index.push_path( - name.as_str().to_string(), + name.to_string(), PathData { ty, module_path: path.to_vec(), @@ -1398,7 +1413,7 @@ pub(crate) fn build_index( .map(|path| serialized_index.get_id_by_module_path(path)); let new_entry_id = serialized_index.push( - item.name.as_str().to_string(), + item.name.to_string(), None, Some(EntryData { ty: item.ty, @@ -1418,6 +1433,7 @@ pub(crate) fn build_index( } else { None }, + xx_url_name_override_xx: item.xx_url_name_override_xx.map(|x| x.to_string()), krate: crate_idx, }), item.desc.to_string(), @@ -1429,7 +1445,7 @@ pub(crate) fn build_index( // Aliases // ------- for alias in &item.aliases[..] { - serialized_index.push_alias(alias.as_str().to_string(), new_entry_id); + serialized_index.push_alias(alias.to_string(), new_entry_id); } // Function signature reverse index diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 20fc6b75d3773..9597905ad66e2 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -743,6 +743,7 @@ function preLoadCss(cssUrl) { if (shortty === "mod") { path = `${modpath}${name}/index.html`; } else { + // FIXME: Take into account override path = `${modpath}${shortty}.${name}.html`; } let current_page = document.location.href.toString(); diff --git a/src/librustdoc/html/static/js/rustdoc.d.ts b/src/librustdoc/html/static/js/rustdoc.d.ts index 28852125fe17a..5768b23141a8b 100644 --- a/src/librustdoc/html/static/js/rustdoc.d.ts +++ b/src/librustdoc/html/static/js/rustdoc.d.ts @@ -236,6 +236,7 @@ declare namespace rustdoc { parent: number?, deprecated: boolean, associatedItemDisambiguator: string?, + xxUrlNameOverrideXx: string?, } /** @@ -338,7 +339,7 @@ declare namespace rustdoc { returned: rustdoc.QueryElement[], is_alias: boolean, alias?: string, - original?: rustdoc.Rlow, + original?: rustdoc.Row, } /** diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 42b87d562529b..15d3e8792d927 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -1541,6 +1541,7 @@ class DocSearch { * parent, * deprecated, * associated_item_disambiguator + * xx_url_name_override_xx * @type {rustdoc.ArrayWithOptionals<[ * number, * rustdoc.ItemType, @@ -1548,7 +1549,7 @@ class DocSearch { * number, * number, * number, - * ], [string]>} + * ], [string, string]>} */ const raw = JSON.parse(encoded); return { @@ -1558,7 +1559,8 @@ class DocSearch { exactModulePath: raw[3] === 0 ? null : raw[3] - 1, parent: raw[4] === 0 ? null : raw[4] - 1, deprecated: raw[5] === 1 ? true : false, - associatedItemDisambiguator: raw.length === 6 ? null : raw[6], + associatedItemDisambiguator: raw.length <= 6 ? null : raw[6], + xxUrlNameOverrideXx: raw.length <= 7 ? null : raw[7], }; } @@ -2045,8 +2047,11 @@ class DocSearch { } else if (type === "primitive" || type === "keyword") { displayPath = ""; exactPath = ""; + const xxActualNameXx = type === "keyword" + && item.entry && item.entry.xxUrlNameOverrideXx + ? item.entry.xxUrlNameOverrideXx : name; href = this.rootPath + path.replace(/::/g, "/") + - "/" + type + "." + name + ".html"; + "/" + type + "." + xxActualNameXx + ".html"; } else if (type === "externcrate") { displayPath = ""; href = this.rootPath + name + "/index.html"; diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index f966d9265628b..ec8fe8683810e 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -52,7 +52,7 @@ impl JsonRenderer<'_> { let clean::ItemInner { name, item_id, .. } = *item.inner; let id = self.id_from_item(item); let inner = match item.kind { - clean::KeywordItem => return None, + clean::KeywordItem { .. } => return None, clean::StrippedItem(ref inner) => { match &**inner { // We document stripped modules as with `Module::is_stripped` set to @@ -333,7 +333,7 @@ fn from_clean_item(item: &clean::Item, renderer: &JsonRenderer<'_>) -> ItemEnum type_: Some(t.item_type.as_ref().unwrap_or(&t.type_).into_json(renderer)), }, // `convert_item` early returns `None` for stripped items and keywords. - KeywordItem => unreachable!(), + KeywordItem { .. } => unreachable!(), StrippedItem(inner) => { match inner.as_ref() { ModuleItem(m) => ItemEnum::Module(Module { diff --git a/src/librustdoc/passes/check_doc_test_visibility.rs b/src/librustdoc/passes/check_doc_test_visibility.rs index 8028afea363d5..517ae8632c176 100644 --- a/src/librustdoc/passes/check_doc_test_visibility.rs +++ b/src/librustdoc/passes/check_doc_test_visibility.rs @@ -66,7 +66,7 @@ pub(crate) fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) - | clean::ExternCrateItem { .. } | clean::ImportItem(_) | clean::PrimitiveItem(_) - | clean::KeywordItem + | clean::KeywordItem { .. } | clean::ModuleItem(_) | clean::TraitAliasItem(_) | clean::ForeignFunctionItem(..) diff --git a/src/librustdoc/passes/propagate_stability.rs b/src/librustdoc/passes/propagate_stability.rs index 14ec58702e356..5b4213e522a94 100644 --- a/src/librustdoc/passes/propagate_stability.rs +++ b/src/librustdoc/passes/propagate_stability.rs @@ -106,7 +106,7 @@ impl DocFolder for StabilityPropagator<'_, '_> { | ItemKind::RequiredAssocTypeItem(..) | ItemKind::AssocTypeItem(..) | ItemKind::PrimitiveItem(..) - | ItemKind::KeywordItem => own_stability, + | ItemKind::KeywordItem { .. } => own_stability, ItemKind::StrippedItem(..) => unreachable!(), } diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs index eedbbca0f8dfc..1033ec14a7af1 100644 --- a/src/librustdoc/passes/stripper.rs +++ b/src/librustdoc/passes/stripper.rs @@ -132,7 +132,7 @@ impl DocFolder for Stripper<'_, '_> { clean::PrimitiveItem(..) => {} // Keywords are never stripped - clean::KeywordItem => {} + clean::KeywordItem { .. } => {} } let fastreturn = match i.kind { diff --git a/src/librustdoc/visit.rs b/src/librustdoc/visit.rs index b8b619514aad9..d88e4d9725db9 100644 --- a/src/librustdoc/visit.rs +++ b/src/librustdoc/visit.rs @@ -49,7 +49,7 @@ pub(crate) trait DocVisitor<'a>: Sized { | ImplAssocConstItem(..) | RequiredAssocTypeItem(..) | AssocTypeItem(..) - | KeywordItem => {} + | KeywordItem { .. } => {} } }