diff options
| author | The Miri Conjob Bot <miri@cron.bot> | 2023-09-12 05:31:58 +0000 |
|---|---|---|
| committer | The Miri Conjob Bot <miri@cron.bot> | 2023-09-12 05:31:58 +0000 |
| commit | 5e992f334ca9f6e92d48cb2fdc5d5777f9ba0c0e (patch) | |
| tree | 600322ffa0911b1e5b459f5ba395672a260d3a41 /src/librustdoc | |
| parent | 44738528abe0f4da222c514ab49b360e1079cbe1 (diff) | |
| parent | 366dab13f711df90a6891411458544199d159cbc (diff) | |
Merge from rustc
Diffstat (limited to 'src/librustdoc')
24 files changed, 675 insertions, 343 deletions
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index cc86a3d7475..dd43ee03383 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -20,7 +20,8 @@ use rustc_span::symbol::{kw, sym, Symbol}; use crate::clean::{ self, clean_fn_decl_from_did_and_sig, clean_generics, clean_impl_item, clean_middle_assoc_item, clean_middle_field, clean_middle_ty, clean_trait_ref_with_bindings, clean_ty, - clean_ty_generics, clean_variant_def, utils, Attributes, AttributesExt, ImplKind, ItemId, Type, + clean_ty_alias_inner_type, clean_ty_generics, clean_variant_def, utils, Attributes, + AttributesExt, ImplKind, ItemId, Type, }; use crate::core::DocContext; use crate::formats::item_type::ItemType; @@ -289,16 +290,14 @@ fn build_union(cx: &mut DocContext<'_>, did: DefId) -> clean::Union { fn build_type_alias(cx: &mut DocContext<'_>, did: DefId) -> Box<clean::TypeAlias> { let predicates = cx.tcx.explicit_predicates_of(did); - let type_ = clean_middle_ty( - ty::Binder::dummy(cx.tcx.type_of(did).instantiate_identity()), - cx, - Some(did), - None, - ); + let ty = cx.tcx.type_of(did).instantiate_identity(); + let type_ = clean_middle_ty(ty::Binder::dummy(ty), cx, Some(did), None); + let inner_type = clean_ty_alias_inner_type(ty, cx); Box::new(clean::TypeAlias { type_, generics: clean_ty_generics(cx, cx.tcx.generics_of(did), predicates), + inner_type, item_type: None, }) } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index b584c32a4c7..f30384701cb 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -24,6 +24,7 @@ use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData}; use rustc_middle::metadata::Reexport; use rustc_middle::middle::resolve_bound_vars as rbv; use rustc_middle::ty::fold::TypeFolder; +use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::TypeVisitableExt; use rustc_middle::ty::{self, AdtKind, EarlyBinder, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; @@ -541,7 +542,7 @@ fn clean_generic_param_def<'tcx>( }, ) } - ty::GenericParamDefKind::Const { has_default } => ( + ty::GenericParamDefKind::Const { has_default, .. } => ( def.name, GenericParamDefKind::Const { ty: Box::new(clean_middle_ty( @@ -955,6 +956,43 @@ fn clean_ty_generics<'tcx>( } } +fn clean_ty_alias_inner_type<'tcx>( + ty: Ty<'tcx>, + cx: &mut DocContext<'tcx>, +) -> Option<TypeAliasInnerType> { + let ty::Adt(adt_def, args) = ty.kind() else { + return None; + }; + + Some(if adt_def.is_enum() { + let variants: rustc_index::IndexVec<_, _> = adt_def + .variants() + .iter() + .map(|variant| clean_variant_def_with_args(variant, args, cx)) + .collect(); + + TypeAliasInnerType::Enum { + variants, + is_non_exhaustive: adt_def.is_variant_list_non_exhaustive(), + } + } else { + let variant = adt_def + .variants() + .iter() + .next() + .unwrap_or_else(|| bug!("a struct or union should always have one variant def")); + + let fields: Vec<_> = + clean_variant_def_with_args(variant, args, cx).kind.inner_items().cloned().collect(); + + if adt_def.is_struct() { + TypeAliasInnerType::Struct { ctor_kind: variant.ctor_kind(), fields } + } else { + TypeAliasInnerType::Union { fields } + } + }) +} + fn clean_proc_macro<'tcx>( item: &hir::Item<'tcx>, name: &mut Symbol, @@ -1222,6 +1260,7 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext Box::new(TypeAlias { type_: clean_ty(default, cx), generics, + inner_type: None, item_type: Some(item_type), }), bounds, @@ -1264,7 +1303,12 @@ pub(crate) fn clean_impl_item<'tcx>( None, ); AssocTypeItem( - Box::new(TypeAlias { type_, generics, item_type: Some(item_type) }), + Box::new(TypeAlias { + type_, + generics, + inner_type: None, + item_type: Some(item_type), + }), Vec::new(), ) } @@ -1471,6 +1515,7 @@ pub(crate) fn clean_middle_assoc_item<'tcx>( None, ), generics, + inner_type: None, item_type: None, }), bounds, @@ -1490,6 +1535,7 @@ pub(crate) fn clean_middle_assoc_item<'tcx>( None, ), generics, + inner_type: None, item_type: None, }), // Associated types inside trait or inherent impls are not allowed to have @@ -2363,6 +2409,83 @@ pub(crate) fn clean_variant_def<'tcx>(variant: &ty::VariantDef, cx: &mut DocCont ) } +pub(crate) fn clean_variant_def_with_args<'tcx>( + variant: &ty::VariantDef, + args: &GenericArgsRef<'tcx>, + cx: &mut DocContext<'tcx>, +) -> Item { + let discriminant = match variant.discr { + ty::VariantDiscr::Explicit(def_id) => Some(Discriminant { expr: None, value: def_id }), + ty::VariantDiscr::Relative(_) => None, + }; + + use rustc_middle::traits::ObligationCause; + use rustc_trait_selection::infer::TyCtxtInferExt; + use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; + + let infcx = cx.tcx.infer_ctxt().build(); + let kind = match variant.ctor_kind() { + Some(CtorKind::Const) => VariantKind::CLike, + Some(CtorKind::Fn) => VariantKind::Tuple( + variant + .fields + .iter() + .map(|field| { + let ty = cx.tcx.type_of(field.did).instantiate(cx.tcx, args); + + // normalize the type to only show concrete types + // note: we do not use try_normalize_erasing_regions since we + // do care about showing the regions + let ty = infcx + .at(&ObligationCause::dummy(), cx.param_env) + .query_normalize(ty) + .map(|normalized| normalized.value) + .unwrap_or(ty); + + clean_field_with_def_id( + field.did, + field.name, + clean_middle_ty(ty::Binder::dummy(ty), cx, Some(field.did), None), + cx, + ) + }) + .collect(), + ), + None => VariantKind::Struct(VariantStruct { + fields: variant + .fields + .iter() + .map(|field| { + let ty = cx.tcx.type_of(field.did).instantiate(cx.tcx, args); + + // normalize the type to only show concrete types + // note: we do not use try_normalize_erasing_regions since we + // do care about showing the regions + let ty = infcx + .at(&ObligationCause::dummy(), cx.param_env) + .query_normalize(ty) + .map(|normalized| normalized.value) + .unwrap_or(ty); + + clean_field_with_def_id( + field.did, + field.name, + clean_middle_ty(ty::Binder::dummy(ty), cx, Some(field.did), None), + cx, + ) + }) + .collect(), + }), + }; + + Item::from_def_id_and_parts( + variant.def_id, + Some(variant.name), + VariantItem(Variant { kind, discriminant }), + cx, + ) +} + fn clean_variant_data<'tcx>( variant: &hir::VariantData<'tcx>, disr_expr: &Option<hir::AnonConst>, @@ -2617,7 +2740,7 @@ fn clean_maybe_renamed_item<'tcx>( ItemKind::TyAlias(hir_ty, generics) => { *cx.current_type_aliases.entry(def_id).or_insert(0) += 1; let rustdoc_ty = clean_ty(hir_ty, cx); - let ty = clean_middle_ty( + let type_ = clean_middle_ty( ty::Binder::dummy(hir_ty_to_ty(cx.tcx, hir_ty)), cx, None, @@ -2630,10 +2753,15 @@ fn clean_maybe_renamed_item<'tcx>( cx.current_type_aliases.remove(&def_id); } } + + let ty = cx.tcx.type_of(def_id).instantiate_identity(); + let inner_type = clean_ty_alias_inner_type(ty, cx); + TypeAliasItem(Box::new(TypeAlias { - type_: rustdoc_ty, generics, - item_type: Some(ty), + inner_type, + type_: rustdoc_ty, + item_type: Some(type_), })) } ItemKind::Enum(ref def, generics) => EnumItem(Enum { diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 9134d5268da..b276745f317 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -25,7 +25,9 @@ use rustc_index::IndexVec; use rustc_metadata::rendered_const; use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::{self, TyCtxt, Visibility}; -use rustc_resolve::rustdoc::{add_doc_fragment, attrs_to_doc_fragments, inner_docs, DocFragment}; +use rustc_resolve::rustdoc::{ + add_doc_fragment, attrs_to_doc_fragments, inner_docs, span_of_fragments, DocFragment, +}; use rustc_session::Session; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Ident, Symbol}; @@ -397,7 +399,7 @@ impl Item { } pub(crate) fn attr_span(&self, tcx: TyCtxt<'_>) -> rustc_span::Span { - crate::passes::span_of_attrs(&self.attrs) + span_of_fragments(&self.attrs.doc_strings) .unwrap_or_else(|| self.span(tcx).map_or(rustc_span::DUMMY_SP, |span| span.inner())) } @@ -2231,9 +2233,19 @@ pub(crate) struct PathSegment { } #[derive(Clone, Debug)] +pub(crate) enum TypeAliasInnerType { + Enum { variants: IndexVec<VariantIdx, Item>, is_non_exhaustive: bool }, + Union { fields: Vec<Item> }, + Struct { ctor_kind: Option<CtorKind>, fields: Vec<Item> }, +} + +#[derive(Clone, Debug)] pub(crate) struct TypeAlias { pub(crate) type_: Type, pub(crate) generics: Generics, + /// Inner `AdtDef` type, ie `type TyKind = IrTyKind<Adt, Ty>`, + /// to be shown directly on the typedef page. + pub(crate) inner_type: Option<TypeAliasInnerType>, /// `type_` can come from either the HIR or from metadata. If it comes from HIR, it may be a type /// alias instead of the final type. This will always have the final type, regardless of whether /// `type_` came from HIR or from metadata. diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 1ce7efdfc20..974dc1c5135 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -157,6 +157,12 @@ pub(crate) struct Options { /// Note: this field is duplicated in `RenderOptions` because it's useful /// to have it in both places. pub(crate) unstable_features: rustc_feature::UnstableFeatures, + + /// All commandline args used to invoke the compiler, with @file args fully expanded. + /// This will only be used within debug info, e.g. in the pdb file on windows + /// This is mainly useful for other tools that reads that debuginfo to figure out + /// how to call the compiler with the same arguments. + pub(crate) expanded_args: Vec<String>, } impl fmt::Debug for Options { @@ -744,6 +750,7 @@ impl Options { json_unused_externs, scrape_examples_options, unstable_features, + expanded_args: args, }; let render_options = RenderOptions { output, diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index eadff37b592..7cd25ef444b 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -194,6 +194,7 @@ pub(crate) fn create_config( describe_lints, lint_cap, scrape_examples_options, + expanded_args, .. }: RustdocOptions, RenderOptions { document_private, .. }: &RenderOptions, @@ -291,6 +292,7 @@ pub(crate) fn create_config( make_codegen_backend: None, registry: rustc_driver::diagnostics_registry(), ice_file: None, + expanded_args, } } diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 36d5adb6304..ea87268877f 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -10,6 +10,7 @@ use rustc_middle::hir::nested_filter; use rustc_middle::ty::TyCtxt; use rustc_parse::maybe_new_parser_from_source_str; use rustc_parse::parser::attr::InnerAttrPolicy; +use rustc_resolve::rustdoc::span_of_fragments; use rustc_session::config::{self, CrateType, ErrorOutputType}; use rustc_session::parse::ParseSess; use rustc_session::{lint, EarlyErrorHandler, Session}; @@ -33,7 +34,6 @@ use crate::clean::{types::AttributesExt, Attributes}; use crate::config::Options as RustdocOptions; use crate::html::markdown::{self, ErrorCodes, Ignore, LangString}; use crate::lint::init_lints; -use crate::passes::span_of_attrs; /// Options that apply to all doctests in a crate or Markdown file (for `rustdoc foo.md`). #[derive(Clone, Default)] @@ -109,6 +109,7 @@ pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> { make_codegen_backend: None, registry: rustc_driver::diagnostics_registry(), ice_file: None, + expanded_args: options.expanded_args.clone(), }; let test_args = options.test_args.clone(); @@ -1240,7 +1241,7 @@ impl<'a, 'hir, 'tcx> HirCollector<'a, 'hir, 'tcx> { Some(&crate::html::markdown::ExtraInfo::new( self.tcx, def_id.to_def_id(), - span_of_attrs(&attrs).unwrap_or(sp), + span_of_fragments(&attrs.doc_strings).unwrap_or(sp), )), ); } diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index ceba643ed5f..cf11e2d7899 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -52,10 +52,31 @@ pub(crate) trait DocFolder: Sized { VariantItem(Variant { kind, discriminant }) } + TypeAliasItem(mut typealias) => { + typealias.inner_type = typealias.inner_type.map(|inner_type| match inner_type { + TypeAliasInnerType::Enum { variants, is_non_exhaustive } => { + let variants = variants + .into_iter_enumerated() + .filter_map(|(_, x)| self.fold_item(x)) + .collect(); + + TypeAliasInnerType::Enum { variants, is_non_exhaustive } + } + TypeAliasInnerType::Union { fields } => { + let fields = fields.into_iter().filter_map(|x| self.fold_item(x)).collect(); + TypeAliasInnerType::Union { fields } + } + TypeAliasInnerType::Struct { ctor_kind, fields } => { + let fields = fields.into_iter().filter_map(|x| self.fold_item(x)).collect(); + TypeAliasInnerType::Struct { ctor_kind, fields } + } + }); + + TypeAliasItem(typealias) + } ExternCrateItem { src: _ } | ImportItem(_) | FunctionItem(_) - | TypeAliasItem(_) | OpaqueTyItem(_) | StaticItem(_) | ConstantItem(_) diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 9a34e7cce8a..4c6e7dfb987 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -457,6 +457,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { | clean::StructItem(..) | clean::UnionItem(..) | clean::VariantItem(..) + | clean::TypeAliasItem(..) | clean::ImplItem(..) => { self.cache.parent_stack.push(ParentStackItem::new(&item)); (self.fold_item_recur(item), true) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 98cc38a10d4..b28019e3f91 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -1574,7 +1574,6 @@ fn init_id_map() -> FxHashMap<Cow<'static, str>, usize> { map.insert("crate-search-div".into(), 1); // This is the list of IDs used in HTML generated in Rust (including the ones // used in tera template files). - map.insert("mainThemeStyle".into(), 1); map.insert("themeStyle".into(), 1); map.insert("settings-menu".into(), 1); map.insert("help-button".into(), 1); @@ -1610,6 +1609,7 @@ fn init_id_map() -> FxHashMap<Cow<'static, str>, usize> { map.insert("blanket-implementations-list".into(), 1); map.insert("deref-methods".into(), 1); map.insert("layout".into(), 1); + map.insert("aliased-type".into(), 1); map } diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index bb1c186668c..0bc10c5e10f 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -7,8 +7,10 @@ use std::sync::mpsc::{channel, Receiver}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def_id::{DefIdMap, LOCAL_CRATE}; +use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; +use rustc_span::def_id::DefId; use rustc_span::edition::Edition; use rustc_span::source_map::FileName; use rustc_span::{sym, Symbol}; @@ -22,13 +24,13 @@ use super::{ sidebar::{sidebar_module_like, Sidebar}, AllTypes, LinkFromSrc, StylePath, }; -use crate::clean::{self, types::ExternalLocation, ExternalCrate}; +use crate::clean::{self, types::ExternalLocation, ExternalCrate, TypeAliasItem}; use crate::config::{ModuleSorting, RenderOptions}; use crate::docfs::{DocFS, PathError}; use crate::error::Error; use crate::formats::cache::Cache; use crate::formats::item_type::ItemType; -use crate::formats::FormatRenderer; +use crate::formats::{self, FormatRenderer}; use crate::html::escape::Escape; use crate::html::format::{join_with_double_colon, Buffer}; use crate::html::markdown::{self, plain_text_summary, ErrorCodes, IdMap}; @@ -147,6 +149,53 @@ impl SharedContext<'_> { pub(crate) fn edition(&self) -> Edition { self.tcx.sess.edition() } + + /// Returns a list of impls on the given type, and, if it's a type alias, + /// other types that it aliases. + pub(crate) fn all_impls_for_item<'a>( + &'a self, + it: &clean::Item, + did: DefId, + ) -> Vec<&'a formats::Impl> { + let tcx = self.tcx; + let cache = &self.cache; + let mut saw_impls = FxHashSet::default(); + let mut v: Vec<&formats::Impl> = cache + .impls + .get(&did) + .map(Vec::as_slice) + .unwrap_or(&[]) + .iter() + .filter(|i| saw_impls.insert(i.def_id())) + .collect(); + if let TypeAliasItem(ait) = &*it.kind && + let aliased_clean_type = ait.item_type.as_ref().unwrap_or(&ait.type_) && + let Some(aliased_type_defid) = aliased_clean_type.def_id(cache) && + let Some(av) = cache.impls.get(&aliased_type_defid) && + let Some(alias_def_id) = it.item_id.as_def_id() + { + // This branch of the compiler compares types structually, but does + // not check trait bounds. That's probably fine, since type aliases + // don't normally constrain on them anyway. + // https://github.com/rust-lang/rust/issues/21903 + // + // FIXME(lazy_type_alias): Once the feature is complete or stable, rewrite this to use type unification. + // Be aware of `tests/rustdoc/issue-112515-impl-ty-alias.rs` which might regress. + let aliased_ty = tcx.type_of(alias_def_id).skip_binder(); + let reject_cx = DeepRejectCtxt { + treat_obligation_params: TreatParams::AsCandidateKey, + }; + v.extend(av.iter().filter(|impl_| { + if let Some(impl_def_id) = impl_.impl_item.item_id.as_def_id() { + reject_cx.types_may_unify(aliased_ty, tcx.type_of(impl_def_id).skip_binder()) + && saw_impls.insert(impl_def_id) + } else { + false + } + })); + } + v + } } impl<'tcx> Context<'tcx> { diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index aef8f1a74fb..5adbecd6d04 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1117,13 +1117,13 @@ pub(crate) fn render_all_impls( fn render_assoc_items<'a, 'cx: 'a>( cx: &'a mut Context<'cx>, containing_item: &'a clean::Item, - it: DefId, + did: DefId, what: AssocItemRender<'a>, ) -> impl fmt::Display + 'a + Captures<'cx> { let mut derefs = DefIdSet::default(); - derefs.insert(it); + derefs.insert(did); display_fn(move |f| { - render_assoc_items_inner(f, cx, containing_item, it, what, &mut derefs); + render_assoc_items_inner(f, cx, containing_item, did, what, &mut derefs); Ok(()) }) } @@ -1132,15 +1132,17 @@ fn render_assoc_items_inner( mut w: &mut dyn fmt::Write, cx: &mut Context<'_>, containing_item: &clean::Item, - it: DefId, + did: DefId, what: AssocItemRender<'_>, derefs: &mut DefIdSet, ) { info!("Documenting associated items of {:?}", containing_item.name); let shared = Rc::clone(&cx.shared); - let cache = &shared.cache; - let Some(v) = cache.impls.get(&it) else { return }; - let (non_trait, traits): (Vec<_>, _) = v.iter().partition(|i| i.inner_impl().trait_.is_none()); + let v = shared.all_impls_for_item(containing_item, did); + let v = v.as_slice(); + let (non_trait, traits): (Vec<&Impl>, _) = + v.iter().partition(|i| i.inner_impl().trait_.is_none()); + let mut saw_impls = FxHashSet::default(); if !non_trait.is_empty() { let mut tmp_buf = Buffer::html(); let (render_mode, id, class_html) = match what { @@ -1169,6 +1171,9 @@ fn render_assoc_items_inner( }; let mut impls_buf = Buffer::html(); for i in &non_trait { + if !saw_impls.insert(i.def_id()) { + continue; + } render_impl( &mut impls_buf, cx, @@ -1214,8 +1219,10 @@ fn render_assoc_items_inner( let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) = traits.into_iter().partition(|t| t.inner_impl().kind.is_auto()); - let (blanket_impl, concrete): (Vec<&Impl>, _) = - concrete.into_iter().partition(|t| t.inner_impl().kind.is_blanket()); + let (blanket_impl, concrete): (Vec<&Impl>, _) = concrete + .into_iter() + .filter(|t| saw_impls.insert(t.def_id())) + .partition(|t| t.inner_impl().kind.is_blanket()); render_all_impls(w, cx, containing_item, &concrete, &synthetic, &blanket_impl); } diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index cb78f903462..c6751c9585e 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1237,6 +1237,75 @@ fn item_type_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &c write!(w, "{}", document(cx, it, None, HeadingOffset::H2)); + if let Some(inner_type) = &t.inner_type { + write!( + w, + "<h2 id=\"aliased-type\" class=\"small-section-header\">\ + Aliased Type<a href=\"#aliased-type\" class=\"anchor\">§</a></h2>" + ); + + match inner_type { + clean::TypeAliasInnerType::Enum { variants, is_non_exhaustive } => { + let variants_iter = || variants.iter().filter(|i| !i.is_stripped()); + wrap_item(w, |w| { + let variants_len = variants.len(); + let variants_count = variants_iter().count(); + let has_stripped_entries = variants_len != variants_count; + + write!(w, "enum {}{}", it.name.unwrap(), t.generics.print(cx)); + render_enum_fields( + w, + cx, + Some(&t.generics), + variants_iter(), + variants_count, + has_stripped_entries, + *is_non_exhaustive, + ) + }); + item_variants(w, cx, it, variants_iter()); + } + clean::TypeAliasInnerType::Union { fields } => { + wrap_item(w, |w| { + let fields_count = fields.iter().filter(|i| !i.is_stripped()).count(); + let has_stripped_fields = fields.len() != fields_count; + + write!(w, "union {}{}", it.name.unwrap(), t.generics.print(cx)); + render_struct_fields( + w, + Some(&t.generics), + None, + fields, + "", + true, + has_stripped_fields, + cx, + ); + }); + item_fields(w, cx, it, fields, None); + } + clean::TypeAliasInnerType::Struct { ctor_kind, fields } => { + wrap_item(w, |w| { + let fields_count = fields.iter().filter(|i| !i.is_stripped()).count(); + let has_stripped_fields = fields.len() != fields_count; + + write!(w, "struct {}{}", it.name.unwrap(), t.generics.print(cx)); + render_struct_fields( + w, + Some(&t.generics), + *ctor_kind, + fields, + "", + true, + has_stripped_fields, + cx, + ); + }); + item_fields(w, cx, it, fields, None); + } + } + } + let def_id = it.item_id.expect_def_id(); // Render any items associated directly to this alias, as otherwise they // won't be visible anywhere in the docs. It would be nice to also show @@ -1315,6 +1384,12 @@ fn print_tuple_struct_fields<'a, 'cx: 'a>( s: &'a [clean::Item], ) -> impl fmt::Display + 'a + Captures<'cx> { display_fn(|f| { + if s.iter() + .all(|field| matches!(*field.kind, clean::StrippedItem(box clean::StructFieldItem(..)))) + { + return f.write_str("/* private fields */"); + } + for (i, ty) in s.iter().enumerate() { if i > 0 { f.write_str(", ")?; @@ -1332,7 +1407,7 @@ fn print_tuple_struct_fields<'a, 'cx: 'a>( fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::Enum) { let tcx = cx.tcx(); let count_variants = e.variants().count(); - wrap_item(w, |mut w| { + wrap_item(w, |w| { render_attributes_in_code(w, it, tcx); write!( w, @@ -1341,148 +1416,179 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean:: it.name.unwrap(), e.generics.print(cx), ); - if !print_where_clause_and_check(w, &e.generics, cx) { - // If there wasn't a `where` clause, we add a whitespace. - w.write_str(" "); - } + render_enum_fields( + w, + cx, + Some(&e.generics), + e.variants(), + count_variants, + e.has_stripped_entries(), + it.is_non_exhaustive(), + ); + }); - let variants_stripped = e.has_stripped_entries(); - if count_variants == 0 && !variants_stripped { - w.write_str("{}"); - } else { - w.write_str("{\n"); - let toggle = should_hide_fields(count_variants); - if toggle { - toggle_open(&mut w, format_args!("{count_variants} variants")); - } - for v in e.variants() { - w.write_str(" "); - let name = v.name.unwrap(); - match *v.kind { - // FIXME(#101337): Show discriminant - clean::VariantItem(ref var) => match var.kind { - clean::VariantKind::CLike => w.write_str(name.as_str()), - clean::VariantKind::Tuple(ref s) => { - write!(w, "{name}({})", print_tuple_struct_fields(cx, s),); - } - clean::VariantKind::Struct(ref s) => { - render_struct(w, v, None, None, &s.fields, " ", false, cx); - } - }, - _ => unreachable!(), - } - w.write_str(",\n"); - } + write!(w, "{}", document(cx, it, None, HeadingOffset::H2)); - if variants_stripped && !it.is_non_exhaustive() { - w.write_str(" // some variants omitted\n"); - } - if toggle { - toggle_close(&mut w); + if count_variants != 0 { + item_variants(w, cx, it, e.variants()); + } + let def_id = it.item_id.expect_def_id(); + write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All)); + write!(w, "{}", document_type_layout(cx, def_id)); +} + +fn render_enum_fields<'a>( + mut w: &mut Buffer, + cx: &mut Context<'_>, + g: Option<&clean::Generics>, + variants: impl Iterator<Item = &'a clean::Item>, + count_variants: usize, + has_stripped_entries: bool, + is_non_exhaustive: bool, +) { + if !g.is_some_and(|g| print_where_clause_and_check(w, g, cx)) { + // If there wasn't a `where` clause, we add a whitespace. + w.write_str(" "); + } + + let variants_stripped = has_stripped_entries; + if count_variants == 0 && !variants_stripped { + w.write_str("{}"); + } else { + w.write_str("{\n"); + let toggle = should_hide_fields(count_variants); + if toggle { + toggle_open(&mut w, format_args!("{count_variants} variants")); + } + const TAB: &str = " "; + for v in variants { + w.write_str(TAB); + let name = v.name.unwrap(); + match *v.kind { + // FIXME(#101337): Show discriminant + clean::VariantItem(ref var) => match var.kind { + clean::VariantKind::CLike => w.write_str(name.as_str()), + clean::VariantKind::Tuple(ref s) => { + write!(w, "{name}({})", print_tuple_struct_fields(cx, s),); + } + clean::VariantKind::Struct(ref s) => { + render_struct(w, v, None, None, &s.fields, TAB, false, cx); + } + }, + _ => unreachable!(), } - w.write_str("}"); + w.write_str(",\n"); } - }); - write!(w, "{}", document(cx, it, None, HeadingOffset::H2)); + if variants_stripped && !is_non_exhaustive { + w.write_str(" // some variants omitted\n"); + } + if toggle { + toggle_close(&mut w); + } + w.write_str("}"); + } +} - if count_variants != 0 { +fn item_variants<'a>( + w: &mut Buffer, + cx: &mut Context<'_>, + it: &clean::Item, + variants: impl Iterator<Item = &'a clean::Item>, +) { + let tcx = cx.tcx(); + write!( + w, + "<h2 id=\"variants\" class=\"variants small-section-header\">\ + Variants{}<a href=\"#variants\" class=\"anchor\">§</a>\ + </h2>\ + {}\ + <div class=\"variants\">", + document_non_exhaustive_header(it), + document_non_exhaustive(it) + ); + for variant in variants { + let id = cx.derive_id(format!("{}.{}", ItemType::Variant, variant.name.unwrap())); write!( w, - "<h2 id=\"variants\" class=\"variants small-section-header\">\ - Variants{}<a href=\"#variants\" class=\"anchor\">§</a>\ - </h2>\ - {}\ - <div class=\"variants\">", - document_non_exhaustive_header(it), - document_non_exhaustive(it) + "<section id=\"{id}\" class=\"variant\">\ + <a href=\"#{id}\" class=\"anchor\">§</a>", ); - for variant in e.variants() { - let id = cx.derive_id(format!("{}.{}", ItemType::Variant, variant.name.unwrap())); - write!( - w, - "<section id=\"{id}\" class=\"variant\">\ - <a href=\"#{id}\" class=\"anchor\">§</a>", - ); - render_stability_since_raw_with_extra( - w, - variant.stable_since(tcx), - variant.const_stability(tcx), - it.stable_since(tcx), - it.const_stable_since(tcx), - " rightside", - ); - write!(w, "<h3 class=\"code-header\">{name}", name = variant.name.unwrap()); + render_stability_since_raw_with_extra( + w, + variant.stable_since(tcx), + variant.const_stability(tcx), + it.stable_since(tcx), + it.const_stable_since(tcx), + " rightside", + ); + write!(w, "<h3 class=\"code-header\">{name}", name = variant.name.unwrap()); - let clean::VariantItem(variant_data) = &*variant.kind else { unreachable!() }; + let clean::VariantItem(variant_data) = &*variant.kind else { unreachable!() }; - if let clean::VariantKind::Tuple(ref s) = variant_data.kind { - write!(w, "({})", print_tuple_struct_fields(cx, s)); - } - w.write_str("</h3></section>"); - - let heading_and_fields = match &variant_data.kind { - clean::VariantKind::Struct(s) => Some(("Fields", &s.fields)), - clean::VariantKind::Tuple(fields) => { - // Documentation on tuple variant fields is rare, so to reduce noise we only emit - // the section if at least one field is documented. - if fields.iter().any(|f| !f.doc_value().is_empty()) { - Some(("Tuple Fields", fields)) - } else { - None - } + if let clean::VariantKind::Tuple(ref s) = variant_data.kind { + write!(w, "({})", print_tuple_struct_fields(cx, s)); + } + w.write_str("</h3></section>"); + + let heading_and_fields = match &variant_data.kind { + clean::VariantKind::Struct(s) => Some(("Fields", &s.fields)), + clean::VariantKind::Tuple(fields) => { + // Documentation on tuple variant fields is rare, so to reduce noise we only emit + // the section if at least one field is documented. + if fields.iter().any(|f| !f.doc_value().is_empty()) { + Some(("Tuple Fields", fields)) + } else { + None } - clean::VariantKind::CLike => None, - }; + } + clean::VariantKind::CLike => None, + }; - if let Some((heading, fields)) = heading_and_fields { - let variant_id = - cx.derive_id(format!("{}.{}.fields", ItemType::Variant, variant.name.unwrap())); - write!( - w, - "<div class=\"sub-variant\" id=\"{variant_id}\">\ - <h4>{heading}</h4>\ - {}", - document_non_exhaustive(variant) - ); - for field in fields { - match *field.kind { - clean::StrippedItem(box clean::StructFieldItem(_)) => {} - clean::StructFieldItem(ref ty) => { - let id = cx.derive_id(format!( - "variant.{}.field.{}", - variant.name.unwrap(), - field.name.unwrap() - )); - write!( - w, - "<div class=\"sub-variant-field\">\ + if let Some((heading, fields)) = heading_and_fields { + let variant_id = + cx.derive_id(format!("{}.{}.fields", ItemType::Variant, variant.name.unwrap())); + write!( + w, + "<div class=\"sub-variant\" id=\"{variant_id}\">\ + <h4>{heading}</h4>\ + {}", + document_non_exhaustive(variant) + ); + for field in fields { + match *field.kind { + clean::StrippedItem(box clean::StructFieldItem(_)) => {} + clean::StructFieldItem(ref ty) => { + let id = cx.derive_id(format!( + "variant.{}.field.{}", + variant.name.unwrap(), + field.name.unwrap() + )); + write!( + w, + "<div class=\"sub-variant-field\">\ <span id=\"{id}\" class=\"small-section-header\">\ <a href=\"#{id}\" class=\"anchor field\">§</a>\ <code>{f}: {t}</code>\ </span>", - f = field.name.unwrap(), - t = ty.print(cx), - ); - write!( - w, - "{}</div>", - document(cx, field, Some(variant), HeadingOffset::H5) - ); - } - _ => unreachable!(), + f = field.name.unwrap(), + t = ty.print(cx), + ); + write!( + w, + "{}</div>", + document(cx, field, Some(variant), HeadingOffset::H5) + ); } + _ => unreachable!(), } - w.write_str("</div>"); } - - write!(w, "{}", document(cx, variant, Some(it), HeadingOffset::H4)); + w.write_str("</div>"); } - write!(w, "</div>"); + + write!(w, "{}", document(cx, variant, Some(it), HeadingOffset::H4)); } - let def_id = it.item_id.expect_def_id(); - write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All)); - write!(w, "{}", document_type_layout(cx, def_id)); + write!(w, "</div>"); } fn item_macro(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::Macro) { @@ -1593,15 +1699,28 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean write!(w, "{}", document(cx, it, None, HeadingOffset::H2)); - let mut fields = s - .fields + item_fields(w, cx, it, &s.fields, s.ctor_kind); + + let def_id = it.item_id.expect_def_id(); + write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All)); + write!(w, "{}", document_type_layout(cx, def_id)); +} + +fn item_fields( + w: &mut Buffer, + cx: &mut Context<'_>, + it: &clean::Item, + fields: &Vec<clean::Item>, + ctor_kind: Option<CtorKind>, +) { + let mut fields = fields .iter() .filter_map(|f| match *f.kind { clean::StructFieldItem(ref ty) => Some((f, ty)), _ => None, }) .peekable(); - if let None | Some(CtorKind::Fn) = s.ctor_kind { + if let None | Some(CtorKind::Fn) = ctor_kind { if fields.peek().is_some() { write!( w, @@ -1609,7 +1728,7 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean {}{}<a href=\"#fields\" class=\"anchor\">§</a>\ </h2>\ {}", - if s.ctor_kind.is_none() { "Fields" } else { "Tuple Fields" }, + if ctor_kind.is_none() { "Fields" } else { "Tuple Fields" }, document_non_exhaustive_header(it), document_non_exhaustive(it) ); @@ -1630,9 +1749,6 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean } } } - let def_id = it.item_id.expect_def_id(); - write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All)); - write!(w, "{}", document_type_layout(cx, def_id)); } fn item_static(w: &mut impl fmt::Write, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Static) { @@ -1871,7 +1987,7 @@ fn render_union<'a, 'cx: 'a>( } fn render_struct( - mut w: &mut Buffer, + w: &mut Buffer, it: &clean::Item, g: Option<&clean::Generics>, ty: Option<CtorKind>, @@ -1891,6 +2007,29 @@ fn render_struct( if let Some(g) = g { write!(w, "{}", g.print(cx)) } + render_struct_fields( + w, + g, + ty, + fields, + tab, + structhead, + it.has_stripped_entries().unwrap_or(false), + cx, + ) +} + +fn render_struct_fields( + mut w: &mut Buffer, + g: Option<&clean::Generics>, + ty: Option<CtorKind>, + fields: &[clean::Item], + tab: &str, + structhead: bool, + has_stripped_entries: bool, + cx: &Context<'_>, +) { + let tcx = cx.tcx(); match ty { None => { let where_displayed = @@ -1922,11 +2061,11 @@ fn render_struct( } if has_visible_fields { - if it.has_stripped_entries().unwrap() { + if has_stripped_entries { write!(w, "\n{tab} /* private fields */"); } write!(w, "\n{tab}"); - } else if it.has_stripped_entries().unwrap() { + } else if has_stripped_entries { write!(w, " /* private fields */ "); } if toggle { @@ -1936,21 +2075,31 @@ fn render_struct( } Some(CtorKind::Fn) => { w.write_str("("); - for (i, field) in fields.iter().enumerate() { - if i > 0 { - w.write_str(", "); - } - match *field.kind { - clean::StrippedItem(box clean::StructFieldItem(..)) => write!(w, "_"), - clean::StructFieldItem(ref ty) => { - write!( - w, - "{}{}", - visibility_print_with_space(field.visibility(tcx), field.item_id, cx), - ty.print(cx), - ) + if fields.iter().all(|field| { + matches!(*field.kind, clean::StrippedItem(box clean::StructFieldItem(..))) + }) { + write!(w, "/* private fields */"); + } else { + for (i, field) in fields.iter().enumerate() { + if i > 0 { + w.write_str(", "); + } + match *field.kind { + clean::StrippedItem(box clean::StructFieldItem(..)) => write!(w, "_"), + clean::StructFieldItem(ref ty) => { + write!( + w, + "{}{}", + visibility_print_with_space( + field.visibility(tcx), + field.item_id, + cx + ), + ty.print(cx), + ) + } + _ => unreachable!(), } - _ => unreachable!(), } } w.write_str(")"); diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs index b96b1536156..76f63c6f63e 100644 --- a/src/librustdoc/html/render/sidebar.rs +++ b/src/librustdoc/html/render/sidebar.rs @@ -82,7 +82,7 @@ pub(super) fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buf clean::PrimitiveItem(_) => sidebar_primitive(cx, it), clean::UnionItem(ref u) => sidebar_union(cx, it, u), clean::EnumItem(ref e) => sidebar_enum(cx, it, e), - clean::TypeAliasItem(_) => sidebar_type_alias(cx, it), + clean::TypeAliasItem(ref t) => sidebar_type_alias(cx, it, t), clean::ModuleItem(ref m) => vec![sidebar_module(&m.items)], clean::ForeignTypeItem => sidebar_foreign_type(cx, it), _ => vec![], @@ -230,8 +230,33 @@ fn sidebar_primitive<'a>(cx: &'a Context<'_>, it: &'a clean::Item) -> Vec<LinkBl } } -fn sidebar_type_alias<'a>(cx: &'a Context<'_>, it: &'a clean::Item) -> Vec<LinkBlock<'a>> { +fn sidebar_type_alias<'a>( + cx: &'a Context<'_>, + it: &'a clean::Item, + t: &'a clean::TypeAlias, +) -> Vec<LinkBlock<'a>> { let mut items = vec![]; + if let Some(inner_type) = &t.inner_type { + items.push(LinkBlock::forced(Link::new("aliased-type", "Aliased type"))); + match inner_type { + clean::TypeAliasInnerType::Enum { variants, is_non_exhaustive: _ } => { + let mut variants = variants + .iter() + .filter(|i| !i.is_stripped()) + .filter_map(|v| v.name) + .map(|name| Link::new(format!("variant.{name}"), name.to_string())) + .collect::<Vec<_>>(); + variants.sort_unstable(); + + items.push(LinkBlock::new(Link::new("variants", "Variants"), variants)); + } + clean::TypeAliasInnerType::Union { fields } + | clean::TypeAliasInnerType::Struct { ctor_kind: _, fields } => { + let fields = get_struct_fields_name(fields); + items.push(LinkBlock::new(Link::new("fields", "Fields"), fields)); + } + } + } sidebar_assoc_items(cx, it, &mut items); items } @@ -254,11 +279,12 @@ fn sidebar_assoc_items<'a>( links: &mut Vec<LinkBlock<'a>>, ) { let did = it.item_id.expect_def_id(); - let cache = cx.cache(); + let v = cx.shared.all_impls_for_item(it, it.item_id.expect_def_id()); + let v = v.as_slice(); let mut assoc_consts = Vec::new(); let mut methods = Vec::new(); - if let Some(v) = cache.impls.get(&did) { + if !v.is_empty() { let mut used_links = FxHashSet::default(); let mut id_map = IdMap::new(); @@ -294,7 +320,7 @@ fn sidebar_assoc_items<'a>( cx, &mut deref_methods, impl_, - v, + v.iter().copied(), &mut derefs, &mut used_links, ); @@ -324,7 +350,7 @@ fn sidebar_deref_methods<'a>( cx: &'a Context<'_>, out: &mut Vec<LinkBlock<'a>>, impl_: &Impl, - v: &[Impl], + v: impl Iterator<Item = &'a Impl>, derefs: &mut DefIdSet, used_links: &mut FxHashSet<String>, ) { @@ -349,7 +375,7 @@ fn sidebar_deref_methods<'a>( // Avoid infinite cycles return; } - let deref_mut = v.iter().any(|i| i.trait_did() == cx.tcx().lang_items().deref_mut_trait()); + let deref_mut = { v }.any(|i| i.trait_did() == cx.tcx().lang_items().deref_mut_trait()); let inner_impl = target .def_id(c) .or_else(|| { @@ -400,7 +426,7 @@ fn sidebar_deref_methods<'a>( cx, out, target_deref_impl, - target_impls, + target_impls.iter(), derefs, used_links, ); diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index cb653d6b8df..a5ae988f348 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -852,14 +852,14 @@ function preLoadCss(cssUrl) { window.CURRENT_TOOLTIP_ELEMENT = wrapper; window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE = e; clearTooltipHoverTimeout(window.CURRENT_TOOLTIP_ELEMENT); - wrapper.onpointerenter = function(ev) { + wrapper.onpointerenter = ev => { // If this is a synthetic touch event, ignore it. A click event will be along shortly. if (ev.pointerType !== "mouse") { return; } clearTooltipHoverTimeout(e); }; - wrapper.onpointerleave = function(ev) { + wrapper.onpointerleave = ev => { // If this is a synthetic touch event, ignore it. A click event will be along shortly. if (ev.pointerType !== "mouse") { return; @@ -963,38 +963,38 @@ function preLoadCss(cssUrl) { } onEachLazy(document.getElementsByClassName("tooltip"), e => { - e.onclick = function() { - this.TOOLTIP_FORCE_VISIBLE = this.TOOLTIP_FORCE_VISIBLE ? false : true; - if (window.CURRENT_TOOLTIP_ELEMENT && !this.TOOLTIP_FORCE_VISIBLE) { + e.onclick = () => { + e.TOOLTIP_FORCE_VISIBLE = e.TOOLTIP_FORCE_VISIBLE ? false : true; + if (window.CURRENT_TOOLTIP_ELEMENT && !e.TOOLTIP_FORCE_VISIBLE) { hideTooltip(true); } else { - showTooltip(this); + showTooltip(e); window.CURRENT_TOOLTIP_ELEMENT.setAttribute("tabindex", "0"); window.CURRENT_TOOLTIP_ELEMENT.focus(); window.CURRENT_TOOLTIP_ELEMENT.onblur = tooltipBlurHandler; } return false; }; - e.onpointerenter = function(ev) { + e.onpointerenter = ev => { // If this is a synthetic touch event, ignore it. A click event will be along shortly. if (ev.pointerType !== "mouse") { return; } - setTooltipHoverTimeout(this, true); + setTooltipHoverTimeout(e, true); }; - e.onpointermove = function(ev) { + e.onpointermove = ev => { // If this is a synthetic touch event, ignore it. A click event will be along shortly. if (ev.pointerType !== "mouse") { return; } - setTooltipHoverTimeout(this, true); + setTooltipHoverTimeout(e, true); }; - e.onpointerleave = function(ev) { + e.onpointerleave = ev => { // If this is a synthetic touch event, ignore it. A click event will be along shortly. if (ev.pointerType !== "mouse") { return; } - if (!this.TOOLTIP_FORCE_VISIBLE && + if (!e.TOOLTIP_FORCE_VISIBLE && !elemIsInParent(ev.relatedTarget, window.CURRENT_TOOLTIP_ELEMENT)) { // Tooltip pointer leave gesture: // @@ -1139,7 +1139,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/how-to-read-rustdoc.html\ * * Pass "true" to reset focus for tooltip popovers. */ - window.hideAllModals = function(switchFocus) { + window.hideAllModals = switchFocus => { hideSidebar(); window.hidePopoverMenus(); hideTooltip(switchFocus); @@ -1148,7 +1148,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/how-to-read-rustdoc.html\ /** * Hide all the popover menus. */ - window.hidePopoverMenus = function() { + window.hidePopoverMenus = () => { onEachLazy(document.querySelectorAll(".search-form .popover"), elem => { elem.style.display = "none"; }); diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js index 2cba32c1b50..63947789c54 100644 --- a/src/librustdoc/html/static/js/settings.js +++ b/src/librustdoc/html/static/js/settings.js @@ -59,8 +59,8 @@ if (settingValue !== null) { toggle.checked = settingValue === "true"; } - toggle.onchange = function() { - changeSetting(this.id, this.checked); + toggle.onchange = () => { + changeSetting(toggle.id, toggle.checked); }; }); onEachLazy(settingsElement.querySelectorAll("input[type=\"radio\"]"), elem => { @@ -224,14 +224,14 @@ if (isSettingsPage) { // We replace the existing "onclick" callback to do nothing if clicked. - getSettingsButton().onclick = function(event) { + getSettingsButton().onclick = event => { event.preventDefault(); }; } else { // We replace the existing "onclick" callback. const settingsButton = getSettingsButton(); const settingsMenu = document.getElementById("settings"); - settingsButton.onclick = function(event) { + settingsButton.onclick = event => { if (elemIsInParent(event.target, settingsMenu)) { return; } diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html index 60ccfe4da44..8cb43634377 100644 --- a/src/librustdoc/html/templates/page.html +++ b/src/librustdoc/html/templates/page.html @@ -15,8 +15,7 @@ <link rel="stylesheet" {#+ #} href="{{static_root_path|safe}}{{files.normalize_css}}"> {# #} <link rel="stylesheet" {#+ #} - href="{{static_root_path|safe}}{{files.rustdoc_css}}" {#+ #} - id="mainThemeStyle"> {# #} + href="{{static_root_path|safe}}{{files.rustdoc_css}}"> {# #} {% if !layout.default_settings.is_empty() %} <script id="default-settings" {#+ #} {%~ for (k, v) in layout.default_settings ~%} diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 0c18f5687f5..08865015960 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -789,7 +789,7 @@ pub(crate) fn from_macro_kind(kind: rustc_span::hygiene::MacroKind) -> MacroKind impl FromWithTcx<Box<clean::TypeAlias>> for TypeAlias { fn from_tcx(type_alias: Box<clean::TypeAlias>, tcx: TyCtxt<'_>) -> Self { - let clean::TypeAlias { type_, generics, item_type: _ } = *type_alias; + let clean::TypeAlias { type_, generics, item_type: _, inner_type: _ } = *type_alias; TypeAlias { type_: type_.into_tcx(tcx), generics: generics.into_tcx(tcx) } } } diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 7b0a7a90d31..0db846bfc7e 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -16,7 +16,9 @@ use rustc_hir::Mutability; use rustc_middle::ty::{Ty, TyCtxt}; use rustc_middle::{bug, span_bug, ty}; use rustc_resolve::rustdoc::{has_primitive_or_keyword_docs, prepare_to_doc_link_resolution}; -use rustc_resolve::rustdoc::{strip_generics_from_path, MalformedGenerics}; +use rustc_resolve::rustdoc::{ + source_span_for_markdown_range, strip_generics_from_path, MalformedGenerics, +}; use rustc_session::lint::Lint; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{sym, Ident, Symbol}; @@ -1211,11 +1213,11 @@ impl LinkCollector<'_, '_> { ori_link: &MarkdownLinkRange, item: &Item, ) { - let span = super::source_span_for_markdown_range( + let span = source_span_for_markdown_range( self.cx.tcx, dox, ori_link.inner_range(), - &item.attrs, + &item.attrs.doc_strings, ) .unwrap_or_else(|| item.attr_span(self.cx.tcx)); rustc_session::parse::feature_err( @@ -1702,26 +1704,27 @@ fn report_diagnostic( let (span, link_range) = match link_range { MarkdownLinkRange::Destination(md_range) => { let mut md_range = md_range.clone(); - let sp = super::source_span_for_markdown_range(tcx, dox, &md_range, &item.attrs) - .map(|mut sp| { - while dox.as_bytes().get(md_range.start) == Some(&b' ') - || dox.as_bytes().get(md_range.start) == Some(&b'`') - { - md_range.start += 1; - sp = sp.with_lo(sp.lo() + BytePos(1)); - } - while dox.as_bytes().get(md_range.end - 1) == Some(&b' ') - || dox.as_bytes().get(md_range.end - 1) == Some(&b'`') - { - md_range.end -= 1; - sp = sp.with_hi(sp.hi() - BytePos(1)); - } - sp - }); + let sp = + source_span_for_markdown_range(tcx, dox, &md_range, &item.attrs.doc_strings) + .map(|mut sp| { + while dox.as_bytes().get(md_range.start) == Some(&b' ') + || dox.as_bytes().get(md_range.start) == Some(&b'`') + { + md_range.start += 1; + sp = sp.with_lo(sp.lo() + BytePos(1)); + } + while dox.as_bytes().get(md_range.end - 1) == Some(&b' ') + || dox.as_bytes().get(md_range.end - 1) == Some(&b'`') + { + md_range.end -= 1; + sp = sp.with_hi(sp.hi() - BytePos(1)); + } + sp + }); (sp, MarkdownLinkRange::Destination(md_range)) } MarkdownLinkRange::WholeLink(md_range) => ( - super::source_span_for_markdown_range(tcx, dox, &md_range, &item.attrs), + source_span_for_markdown_range(tcx, dox, &md_range, &item.attrs.doc_strings), link_range.clone(), ), }; diff --git a/src/librustdoc/passes/lint/bare_urls.rs b/src/librustdoc/passes/lint/bare_urls.rs index 97078a5cb16..0c5cfffe1be 100644 --- a/src/librustdoc/passes/lint/bare_urls.rs +++ b/src/librustdoc/passes/lint/bare_urls.rs @@ -4,11 +4,11 @@ use crate::clean::*; use crate::core::DocContext; use crate::html::markdown::main_body_opts; -use crate::passes::source_span_for_markdown_range; use core::ops::Range; use pulldown_cmark::{Event, Parser, Tag}; use regex::Regex; use rustc_errors::Applicability; +use rustc_resolve::rustdoc::source_span_for_markdown_range; use std::mem; use std::sync::LazyLock; @@ -21,8 +21,9 @@ pub(super) fn visit_item(cx: &DocContext<'_>, item: &Item) { if !dox.is_empty() { let report_diag = |cx: &DocContext<'_>, msg: &'static str, url: &str, range: Range<usize>| { - let sp = source_span_for_markdown_range(cx.tcx, &dox, &range, &item.attrs) - .unwrap_or_else(|| item.attr_span(cx.tcx)); + let sp = + source_span_for_markdown_range(cx.tcx, &dox, &range, &item.attrs.doc_strings) + .unwrap_or_else(|| item.attr_span(cx.tcx)); cx.tcx.struct_span_lint_hir(crate::lint::BARE_URLS, hir_id, sp, msg, |lint| { lint.note("bare URLs are not automatically turned into clickable links") .span_suggestion( diff --git a/src/librustdoc/passes/lint/check_code_block_syntax.rs b/src/librustdoc/passes/lint/check_code_block_syntax.rs index 37e28e1fbca..316b1a41c7d 100644 --- a/src/librustdoc/passes/lint/check_code_block_syntax.rs +++ b/src/librustdoc/passes/lint/check_code_block_syntax.rs @@ -6,6 +6,7 @@ use rustc_errors::{ Applicability, Diagnostic, Handler, LazyFallbackBundle, }; use rustc_parse::parse_stream_from_source_str; +use rustc_resolve::rustdoc::source_span_for_markdown_range; use rustc_session::parse::ParseSess; use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId}; use rustc_span::source_map::{FilePathMapping, SourceMap}; @@ -14,7 +15,6 @@ use rustc_span::{FileName, InnerSpan, DUMMY_SP}; use crate::clean; use crate::core::DocContext; use crate::html::markdown::{self, RustCodeBlock}; -use crate::passes::source_span_for_markdown_range; pub(crate) fn visit_item(cx: &DocContext<'_>, item: &clean::Item) { if let Some(dox) = &item.opt_doc_value() { @@ -77,11 +77,15 @@ fn check_rust_syntax( let is_ignore = code_block.lang_string.ignore != markdown::Ignore::None; // The span and whether it is precise or not. - let (sp, precise_span) = - match source_span_for_markdown_range(cx.tcx, dox, &code_block.range, &item.attrs) { - Some(sp) => (sp, true), - None => (item.attr_span(cx.tcx), false), - }; + let (sp, precise_span) = match source_span_for_markdown_range( + cx.tcx, + dox, + &code_block.range, + &item.attrs.doc_strings, + ) { + Some(sp) => (sp, true), + None => (item.attr_span(cx.tcx), false), + }; let msg = if buffer.has_errors { "could not parse code block as Rust code" diff --git a/src/librustdoc/passes/lint/html_tags.rs b/src/librustdoc/passes/lint/html_tags.rs index c135c584cec..79fc599e176 100644 --- a/src/librustdoc/passes/lint/html_tags.rs +++ b/src/librustdoc/passes/lint/html_tags.rs @@ -2,9 +2,9 @@ use crate::clean::*; use crate::core::DocContext; use crate::html::markdown::main_body_opts; -use crate::passes::source_span_for_markdown_range; use pulldown_cmark::{BrokenLink, Event, LinkType, Parser, Tag}; +use rustc_resolve::rustdoc::source_span_for_markdown_range; use std::iter::Peekable; use std::ops::Range; @@ -20,7 +20,8 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) { let dox = item.doc_value(); if !dox.is_empty() { let report_diag = |msg: String, range: &Range<usize>, is_open_tag: bool| { - let sp = match source_span_for_markdown_range(tcx, &dox, range, &item.attrs) { + let sp = match source_span_for_markdown_range(tcx, &dox, range, &item.attrs.doc_strings) + { Some(sp) => sp, None => item.attr_span(tcx), }; @@ -60,7 +61,7 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) { tcx, &dox, &(generics_start..generics_end), - &item.attrs, + &item.attrs.doc_strings, ) { Some(sp) => sp, None => item.attr_span(tcx), diff --git a/src/librustdoc/passes/lint/redundant_explicit_links.rs b/src/librustdoc/passes/lint/redundant_explicit_links.rs index 67cd2cc9732..0c15bf5f764 100644 --- a/src/librustdoc/passes/lint/redundant_explicit_links.rs +++ b/src/librustdoc/passes/lint/redundant_explicit_links.rs @@ -6,6 +6,7 @@ use rustc_errors::SuggestionStyle; use rustc_hir::def::{DefKind, DocLinkResMap, Namespace, Res}; use rustc_hir::HirId; use rustc_lint_defs::Applicability; +use rustc_resolve::rustdoc::source_span_for_markdown_range; use rustc_span::Symbol; use crate::clean::utils::find_nearest_parent_module; @@ -13,7 +14,6 @@ use crate::clean::utils::inherits_doc_hidden; use crate::clean::Item; use crate::core::DocContext; use crate::html::markdown::main_body_opts; -use crate::passes::source_span_for_markdown_range; #[derive(Debug)] struct LinkData { @@ -160,16 +160,21 @@ fn check_inline_or_reference_unknown_redundancy( (find_resolution(resolutions, &dest)?, find_resolution(resolutions, resolvable_link)?); if dest_res == display_res { - let link_span = source_span_for_markdown_range(cx.tcx, &doc, &link_range, &item.attrs) - .unwrap_or(item.attr_span(cx.tcx)); + let link_span = + source_span_for_markdown_range(cx.tcx, &doc, &link_range, &item.attrs.doc_strings) + .unwrap_or(item.attr_span(cx.tcx)); let explicit_span = source_span_for_markdown_range( cx.tcx, &doc, &offset_explicit_range(doc, link_range, open, close), - &item.attrs, + &item.attrs.doc_strings, + )?; + let display_span = source_span_for_markdown_range( + cx.tcx, + &doc, + &resolvable_link_range, + &item.attrs.doc_strings, )?; - let display_span = - source_span_for_markdown_range(cx.tcx, &doc, &resolvable_link_range, &item.attrs)?; cx.tcx.struct_span_lint_hir(crate::lint::REDUNDANT_EXPLICIT_LINKS, hir_id, explicit_span, "redundant explicit link target", |lint| { lint.span_label(explicit_span, "explicit target is redundant") @@ -201,21 +206,26 @@ fn check_reference_redundancy( (find_resolution(resolutions, &dest)?, find_resolution(resolutions, resolvable_link)?); if dest_res == display_res { - let link_span = source_span_for_markdown_range(cx.tcx, &doc, &link_range, &item.attrs) - .unwrap_or(item.attr_span(cx.tcx)); + let link_span = + source_span_for_markdown_range(cx.tcx, &doc, &link_range, &item.attrs.doc_strings) + .unwrap_or(item.attr_span(cx.tcx)); let explicit_span = source_span_for_markdown_range( cx.tcx, &doc, &offset_explicit_range(doc, link_range.clone(), b'[', b']'), - &item.attrs, + &item.attrs.doc_strings, + )?; + let display_span = source_span_for_markdown_range( + cx.tcx, + &doc, + &resolvable_link_range, + &item.attrs.doc_strings, )?; - let display_span = - source_span_for_markdown_range(cx.tcx, &doc, &resolvable_link_range, &item.attrs)?; let def_span = source_span_for_markdown_range( cx.tcx, &doc, &offset_reference_def_range(doc, dest, link_range), - &item.attrs, + &item.attrs.doc_strings, )?; cx.tcx.struct_span_lint_hir(crate::lint::REDUNDANT_EXPLICIT_LINKS, hir_id, explicit_span, "redundant explicit link target", |lint| { diff --git a/src/librustdoc/passes/lint/unescaped_backticks.rs b/src/librustdoc/passes/lint/unescaped_backticks.rs index 256958d7160..8b7fdd6ab1f 100644 --- a/src/librustdoc/passes/lint/unescaped_backticks.rs +++ b/src/librustdoc/passes/lint/unescaped_backticks.rs @@ -3,10 +3,10 @@ use crate::clean::Item; use crate::core::DocContext; use crate::html::markdown::main_body_opts; -use crate::passes::source_span_for_markdown_range; use pulldown_cmark::{BrokenLink, Event, Parser}; use rustc_errors::DiagnosticBuilder; use rustc_lint_defs::Applicability; +use rustc_resolve::rustdoc::source_span_for_markdown_range; use std::ops::Range; pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) { @@ -52,7 +52,7 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) { tcx, &dox, &(backtick_index..backtick_index + 1), - &item.attrs, + &item.attrs.doc_strings, ) .unwrap_or_else(|| item.attr_span(tcx)); @@ -378,9 +378,12 @@ fn suggest_insertion( /// Maximum bytes of context to show around the insertion. const CONTEXT_MAX_LEN: usize = 80; - if let Some(span) = - source_span_for_markdown_range(cx.tcx, &dox, &(insert_index..insert_index), &item.attrs) - { + if let Some(span) = source_span_for_markdown_range( + cx.tcx, + &dox, + &(insert_index..insert_index), + &item.attrs.doc_strings, + ) { lint.span_suggestion(span, message, suggestion, Applicability::MaybeIncorrect); } else { let line_start = dox[..insert_index].rfind('\n').map_or(0, |idx| idx + 1); diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index 4b1ff68df50..bb678e33888 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -1,11 +1,6 @@ //! Contains information about "passes", used to modify crate information during the documentation //! process. -use rustc_middle::ty::TyCtxt; -use rustc_resolve::rustdoc::DocFragmentKind; -use rustc_span::{InnerSpan, Span, DUMMY_SP}; -use std::ops::Range; - use self::Condition::*; use crate::clean; use crate::core::DocContext; @@ -115,89 +110,3 @@ impl ConditionalPass { pub(crate) fn defaults(show_coverage: bool) -> &'static [ConditionalPass] { if show_coverage { COVERAGE_PASSES } else { DEFAULT_PASSES } } - -/// Returns a span encompassing all the given attributes. -pub(crate) fn span_of_attrs(attrs: &clean::Attributes) -> Option<Span> { - if attrs.doc_strings.is_empty() { - return None; - } - let start = attrs.doc_strings[0].span; - if start == DUMMY_SP { - return None; - } - let end = attrs.doc_strings.last().expect("no doc strings provided").span; - Some(start.to(end)) -} - -/// Attempts to match a range of bytes from parsed markdown to a `Span` in the source code. -/// -/// This method will return `None` if we cannot construct a span from the source map or if the -/// attributes are not all sugared doc comments. It's difficult to calculate the correct span in -/// that case due to escaping and other source features. -pub(crate) fn source_span_for_markdown_range( - tcx: TyCtxt<'_>, - markdown: &str, - md_range: &Range<usize>, - attrs: &clean::Attributes, -) -> Option<Span> { - let is_all_sugared_doc = - attrs.doc_strings.iter().all(|frag| frag.kind == DocFragmentKind::SugaredDoc); - - if !is_all_sugared_doc { - return None; - } - - let snippet = tcx.sess.source_map().span_to_snippet(span_of_attrs(attrs)?).ok()?; - - let starting_line = markdown[..md_range.start].matches('\n').count(); - let ending_line = starting_line + markdown[md_range.start..md_range.end].matches('\n').count(); - - // We use `split_terminator('\n')` instead of `lines()` when counting bytes so that we treat - // CRLF and LF line endings the same way. - let mut src_lines = snippet.split_terminator('\n'); - let md_lines = markdown.split_terminator('\n'); - - // The number of bytes from the source span to the markdown span that are not part - // of the markdown, like comment markers. - let mut start_bytes = 0; - let mut end_bytes = 0; - - 'outer: for (line_no, md_line) in md_lines.enumerate() { - loop { - let source_line = src_lines.next()?; - match source_line.find(md_line) { - Some(offset) => { - if line_no == starting_line { - start_bytes += offset; - - if starting_line == ending_line { - break 'outer; - } - } else if line_no == ending_line { - end_bytes += offset; - break 'outer; - } else if line_no < starting_line { - start_bytes += source_line.len() - md_line.len(); - } else { - end_bytes += source_line.len() - md_line.len(); - } - break; - } - None => { - // Since this is a source line that doesn't include a markdown line, - // we have to count the newline that we split from earlier. - if line_no <= starting_line { - start_bytes += source_line.len() + 1; - } else { - end_bytes += source_line.len() + 1; - } - } - } - } - } - - Some(span_of_attrs(attrs)?.from_inner(InnerSpan::new( - md_range.start + start_bytes, - md_range.end + start_bytes + end_bytes, - ))) -} |
