From 837b550238aa671a591ccf282dddeab29cadb206 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 18 May 2024 04:49:42 +0200 Subject: Merging upstream version 1.71.1+dfsg1. Signed-off-by: Daniel Baumann --- src/librustdoc/clean/auto_trait.rs | 22 ++-- src/librustdoc/clean/blanket_impl.rs | 2 +- src/librustdoc/clean/inline.rs | 16 ++- src/librustdoc/clean/mod.rs | 229 +++++++++++++++++++++++------------ src/librustdoc/clean/types.rs | 152 +++++++++++++++-------- src/librustdoc/clean/types/tests.rs | 5 +- src/librustdoc/clean/utils.rs | 9 +- 7 files changed, 288 insertions(+), 147 deletions(-) (limited to 'src/librustdoc/clean') diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 9479b3ee0..baf2b0a85 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -1,7 +1,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::lang_items::LangItem; -use rustc_middle::ty::{self, Region, RegionVid, TypeFoldable, TypeSuperFoldable}; +use rustc_middle::ty::{self, Region, RegionVid, TypeFoldable}; use rustc_trait_selection::traits::auto_trait::{self, AutoTraitResult}; use thin_vec::ThinVec; @@ -44,7 +44,7 @@ where discard_positive_impl: bool, ) -> Option { let tcx = self.cx.tcx; - let trait_ref = ty::Binder::dummy(tcx.mk_trait_ref(trait_def_id, [ty])); + let trait_ref = ty::Binder::dummy(ty::TraitRef::new(tcx, trait_def_id, [ty])); if !self.cx.generated_synthetics.insert((ty, trait_def_id)) { debug!("get_auto_trait_impl_for({:?}): already generated, aborting", trait_ref); return None; @@ -141,7 +141,7 @@ where let f = auto_trait::AutoTraitFinder::new(tcx); debug!("get_auto_trait_impls({:?})", ty); - let auto_traits: Vec<_> = self.cx.auto_traits.iter().copied().collect(); + let auto_traits: Vec<_> = self.cx.auto_traits.to_vec(); let mut auto_traits: Vec = auto_traits .into_iter() .filter_map(|trait_def_id| { @@ -556,7 +556,10 @@ where WherePredicate::EqPredicate { lhs, rhs, bound_params } => { match *lhs { Type::QPath(box QPathData { - ref assoc, ref self_type, ref trait_, .. + ref assoc, + ref self_type, + trait_: Some(ref trait_), + .. }) => { let ty = &*self_type; let mut new_trait = trait_.clone(); @@ -740,10 +743,11 @@ impl<'a, 'tcx> TypeFolder> for RegionReplacer<'a, 'tcx> { } fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - (match *r { - ty::ReVar(vid) => self.vid_to_region.get(&vid).cloned(), - _ => None, - }) - .unwrap_or_else(|| r.super_fold_with(self)) + match *r { + // These are the regions that can be seen in the AST. + ty::ReVar(vid) => self.vid_to_region.get(&vid).cloned().unwrap_or(r), + ty::ReEarlyBound(_) | ty::ReStatic | ty::ReLateBound(..) | ty::ReError(_) => r, + r => bug!("unexpected region: {r:?}"), + } } } diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index 3a3bf6a7a..e4c05b573 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -20,7 +20,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { trace!("get_blanket_impls({:?})", ty); let mut impls = Vec::new(); for trait_def_id in cx.tcx.all_traits() { - if !cx.cache.effective_visibilities.is_directly_public(cx.tcx, trait_def_id) + if !cx.cache.effective_visibilities.is_reachable(cx.tcx, trait_def_id) || cx.generated_synthetics.get(&(ty.0, trait_def_id)).is_some() { continue; diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index cc5d13808..7dc08b3b1 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -152,8 +152,9 @@ pub(crate) fn try_inline_glob( // reexported by the glob, e.g. because they are shadowed by something else. let reexports = cx .tcx - .module_children_reexports(current_mod) + .module_children_local(current_mod) .iter() + .filter(|child| !child.reexport_chain.is_empty()) .filter_map(|child| child.res.opt_def_id()) .collect(); let mut items = build_module_items(cx, did, visited, inlined_names, Some(&reexports)); @@ -354,9 +355,9 @@ pub(crate) fn build_impl( return; } - let _prof_timer = cx.tcx.sess.prof.generic_activity("build_impl"); - let tcx = cx.tcx; + let _prof_timer = tcx.sess.prof.generic_activity("build_impl"); + let associated_trait = tcx.impl_trait_ref(did).map(ty::EarlyBinder::skip_binder); // Only inline impl if the implemented trait is @@ -528,7 +529,7 @@ pub(crate) fn build_impl( items: trait_items, polarity, kind: if utils::has_doc_flag(tcx, did, sym::fake_variadic) { - ImplKind::FakeVaradic + ImplKind::FakeVariadic } else { ImplKind::Normal }, @@ -705,7 +706,12 @@ fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) -> clean: g.where_predicates.retain(|pred| match pred { clean::WherePredicate::BoundPredicate { - ty: clean::QPath(box clean::QPathData { self_type: clean::Generic(ref s), trait_, .. }), + ty: + clean::QPath(box clean::QPathData { + self_type: clean::Generic(ref s), + trait_: Some(trait_), + .. + }), bounds, .. } => !(bounds.is_empty() || *s == kw::SelfUpper && trait_.def_id() == trait_did), diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 5fa0c120f..03adc19e3 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -119,7 +119,39 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext< }); let kind = ModuleItem(Module { items, span }); - Item::from_def_id_and_parts(doc.def_id.to_def_id(), Some(doc.name), kind, cx) + generate_item_with_correct_attrs(cx, kind, doc.def_id, doc.name, doc.import_id, doc.renamed) +} + +fn generate_item_with_correct_attrs( + cx: &mut DocContext<'_>, + kind: ItemKind, + local_def_id: LocalDefId, + name: Symbol, + import_id: Option, + renamed: Option, +) -> Item { + let def_id = local_def_id.to_def_id(); + let target_attrs = inline::load_attrs(cx, def_id); + let attrs = if let Some(import_id) = import_id { + let is_inline = inline::load_attrs(cx, import_id.to_def_id()) + .lists(sym::doc) + .get_word_attr(sym::inline) + .is_some(); + let mut attrs = get_all_import_attributes(cx, import_id, local_def_id, is_inline); + add_without_unwanted_attributes(&mut attrs, target_attrs, is_inline, None); + attrs + } else { + // We only keep the item's attributes. + target_attrs.iter().map(|attr| (Cow::Borrowed(attr), None)).collect() + }; + + let cfg = attrs.cfg(cx.tcx, &cx.cache.hidden_cfg); + let attrs = Attributes::from_ast_iter(attrs.iter().map(|(attr, did)| (&**attr, *did)), false); + + let name = renamed.or(Some(name)); + let mut item = Item::from_def_id_and_attrs_and_parts(def_id, name, kind, Box::new(attrs), cfg); + item.inline_stmt_id = import_id.map(|local| local.to_def_id()); + item } fn clean_generic_bound<'tcx>( @@ -131,7 +163,7 @@ fn clean_generic_bound<'tcx>( hir::GenericBound::LangItemTrait(lang_item, span, _, generic_args) => { let def_id = cx.tcx.require_lang_item(lang_item, Some(span)); - let trait_ref = ty::TraitRef::identity(cx.tcx, def_id); + let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(cx.tcx, def_id)); let generic_args = clean_generic_args(generic_args, cx); let GenericArgs::AngleBracketed { bindings, .. } = generic_args @@ -304,7 +336,7 @@ pub(crate) fn clean_predicate<'tcx>( clean_region_outlives_predicate(pred) } ty::PredicateKind::Clause(ty::Clause::TypeOutlives(pred)) => { - clean_type_outlives_predicate(pred, cx) + clean_type_outlives_predicate(bound_predicate.rebind(pred), cx) } ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => { Some(clean_projection_predicate(bound_predicate.rebind(pred), cx)) @@ -345,7 +377,7 @@ fn clean_poly_trait_predicate<'tcx>( } fn clean_region_outlives_predicate<'tcx>( - pred: ty::OutlivesPredicate, ty::Region<'tcx>>, + pred: ty::RegionOutlivesPredicate<'tcx>, ) -> Option { let ty::OutlivesPredicate(a, b) = pred; @@ -358,13 +390,13 @@ fn clean_region_outlives_predicate<'tcx>( } fn clean_type_outlives_predicate<'tcx>( - pred: ty::OutlivesPredicate, ty::Region<'tcx>>, + pred: ty::Binder<'tcx, ty::TypeOutlivesPredicate<'tcx>>, cx: &mut DocContext<'tcx>, ) -> Option { - let ty::OutlivesPredicate(ty, lt) = pred; + let ty::OutlivesPredicate(ty, lt) = pred.skip_binder(); Some(WherePredicate::BoundPredicate { - ty: clean_middle_ty(ty::Binder::dummy(ty), cx, None), + ty: clean_middle_ty(pred.rebind(ty), cx, None), bounds: vec![GenericBound::Outlives( clean_middle_region(lt).expect("failed to clean lifetimes"), )], @@ -422,8 +454,8 @@ fn clean_projection<'tcx>( let bounds = cx .tcx .explicit_item_bounds(ty.skip_binder().def_id) - .iter() - .map(|(bound, _)| EarlyBinder(*bound).subst(cx.tcx, ty.skip_binder().substs)) + .subst_iter_copied(cx.tcx, ty.skip_binder().substs) + .map(|(pred, _)| pred) .collect::>(); return clean_middle_opaque_bounds(cx, bounds); } @@ -441,7 +473,7 @@ fn clean_projection<'tcx>( assoc: projection_to_path_segment(ty, cx), should_show_cast, self_type, - trait_, + trait_: Some(trait_), })) } @@ -1315,10 +1347,11 @@ pub(crate) fn clean_middle_assoc_item<'tcx>( } if let ty::TraitContainer = assoc_item.container { - let bounds = tcx.explicit_item_bounds(assoc_item.def_id); + let bounds = + tcx.explicit_item_bounds(assoc_item.def_id).subst_identity_iter_copied(); let predicates = tcx.explicit_predicates_of(assoc_item.def_id).predicates; let predicates = - tcx.arena.alloc_from_iter(bounds.into_iter().chain(predicates).copied()); + tcx.arena.alloc_from_iter(bounds.chain(predicates.iter().copied())); let mut generics = clean_ty_generics( cx, tcx.generics_of(assoc_item.def_id), @@ -1329,7 +1362,13 @@ pub(crate) fn clean_middle_assoc_item<'tcx>( let mut bounds: Vec = Vec::new(); generics.where_predicates.retain_mut(|pred| match *pred { WherePredicate::BoundPredicate { - ty: QPath(box QPathData { ref assoc, ref self_type, ref trait_, .. }), + ty: + QPath(box QPathData { + ref assoc, + ref self_type, + trait_: Some(ref trait_), + .. + }), bounds: ref mut pred_bounds, .. } => { @@ -1491,25 +1530,30 @@ fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type assoc: clean_path_segment(p.segments.last().expect("segments were empty"), cx), should_show_cast, self_type, - trait_, + trait_: Some(trait_), })) } hir::QPath::TypeRelative(qself, segment) => { let ty = hir_ty_to_ty(cx.tcx, hir_ty); - let res = match ty.kind() { + let self_type = clean_ty(qself, cx); + + let (trait_, should_show_cast) = match ty.kind() { ty::Alias(ty::Projection, proj) => { - Res::Def(DefKind::Trait, proj.trait_ref(cx.tcx).def_id) + let res = Res::Def(DefKind::Trait, proj.trait_ref(cx.tcx).def_id); + let trait_ = clean_path(&hir::Path { span, res, segments: &[] }, cx); + register_res(cx, trait_.res); + let self_def_id = res.opt_def_id(); + let should_show_cast = + compute_should_show_cast(self_def_id, &trait_, &self_type); + + (Some(trait_), should_show_cast) } + ty::Alias(ty::Inherent, _) => (None, false), // Rustdoc handles `ty::Error`s by turning them into `Type::Infer`s. ty::Error(_) => return Type::Infer, - // Otherwise, this is an inherent associated type. - _ => return clean_middle_ty(ty::Binder::dummy(ty), cx, None), + _ => bug!("clean: expected associated type, found `{ty:?}`"), }; - let trait_ = clean_path(&hir::Path { span, res, segments: &[] }, cx); - register_res(cx, trait_.res); - let self_def_id = res.opt_def_id(); - let self_type = clean_ty(qself, cx); - let should_show_cast = compute_should_show_cast(self_def_id, &trait_, &self_type); + Type::QPath(Box::new(QPathData { assoc: clean_path_segment(segment, cx), should_show_cast, @@ -1528,7 +1572,9 @@ fn maybe_expand_private_type_alias<'tcx>( let Res::Def(DefKind::TyAlias, def_id) = path.res else { return None }; // Substitute private type aliases let def_id = def_id.as_local()?; - let alias = if !cx.cache.effective_visibilities.is_exported(cx.tcx, def_id.to_def_id()) { + let alias = if !cx.cache.effective_visibilities.is_exported(cx.tcx, def_id.to_def_id()) + && !cx.current_type_aliases.contains_key(&def_id.to_def_id()) + { &cx.tcx.hir().expect_item(def_id).kind } else { return None; @@ -1608,7 +1654,7 @@ fn maybe_expand_private_type_alias<'tcx>( } } - Some(cx.enter_alias(substs, |cx| clean_ty(ty, cx))) + Some(cx.enter_alias(substs, def_id.to_def_id(), |cx| clean_ty(ty, cx))) } pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type { @@ -1699,7 +1745,7 @@ fn normalize<'tcx>( pub(crate) fn clean_middle_ty<'tcx>( bound_ty: ty::Binder<'tcx, Ty<'tcx>>, cx: &mut DocContext<'tcx>, - def_id: Option, + parent_def_id: Option, ) -> Type { let bound_ty = normalize(cx, bound_ty).unwrap_or(bound_ty); match *bound_ty.skip_binder().kind() { @@ -1829,7 +1875,32 @@ pub(crate) fn clean_middle_ty<'tcx>( Tuple(t.iter().map(|t| clean_middle_ty(bound_ty.rebind(t), cx, None)).collect()) } - ty::Alias(ty::Projection, ref data) => clean_projection(bound_ty.rebind(*data), cx, def_id), + ty::Alias(ty::Projection, ref data) => { + clean_projection(bound_ty.rebind(*data), cx, parent_def_id) + } + + ty::Alias(ty::Inherent, alias_ty) => { + let alias_ty = bound_ty.rebind(alias_ty); + let self_type = clean_middle_ty(alias_ty.map_bound(|ty| ty.self_ty()), cx, None); + + Type::QPath(Box::new(QPathData { + assoc: PathSegment { + name: cx.tcx.associated_item(alias_ty.skip_binder().def_id).name, + args: GenericArgs::AngleBracketed { + args: substs_to_args( + cx, + alias_ty.map_bound(|ty| ty.substs.as_slice()), + true, + ) + .into(), + bindings: Default::default(), + }, + }, + should_show_cast: false, + self_type, + trait_: None, + })) + } ty::Param(ref p) => { if let Some(bounds) = cx.impl_trait_bounds.remove(&p.index.into()) { @@ -1840,15 +1911,30 @@ pub(crate) fn clean_middle_ty<'tcx>( } ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { - // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`, - // by looking up the bounds associated with the def_id. - let bounds = cx - .tcx - .explicit_item_bounds(def_id) - .iter() - .map(|(bound, _)| EarlyBinder(*bound).subst(cx.tcx, substs)) - .collect::>(); - clean_middle_opaque_bounds(cx, bounds) + // If it's already in the same alias, don't get an infinite loop. + if cx.current_type_aliases.contains_key(&def_id) { + let path = + external_path(cx, def_id, false, ThinVec::new(), bound_ty.rebind(substs)); + Type::Path { path } + } else { + *cx.current_type_aliases.entry(def_id).or_insert(0) += 1; + // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`, + // by looking up the bounds associated with the def_id. + let bounds = cx + .tcx + .explicit_item_bounds(def_id) + .subst_iter_copied(cx.tcx, substs) + .map(|(bound, _)| bound) + .collect::>(); + let ty = clean_middle_opaque_bounds(cx, bounds); + if let Some(count) = cx.current_type_aliases.get_mut(&def_id) { + *count -= 1; + if *count == 0 { + cx.current_type_aliases.remove(&def_id); + } + } + ty + } } ty::Closure(..) => panic!("Closure"), @@ -2069,9 +2155,9 @@ pub(crate) fn reexport_chain<'tcx>( import_def_id: LocalDefId, target_def_id: LocalDefId, ) -> &'tcx [Reexport] { - for child in tcx.module_children_reexports(tcx.local_parent(import_def_id)) { + for child in tcx.module_children_local(tcx.local_parent(import_def_id)) { if child.res.opt_def_id() == Some(target_def_id.to_def_id()) - && child.reexport_chain[0].id() == Some(import_def_id.to_def_id()) + && child.reexport_chain.first().and_then(|r| r.id()) == Some(import_def_id.to_def_id()) { return &child.reexport_chain; } @@ -2228,13 +2314,17 @@ fn clean_maybe_renamed_item<'tcx>( generics: clean_generics(ty.generics, cx), }), 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(ty::Binder::dummy(hir_ty_to_ty(cx.tcx, hir_ty)), cx, None); - TypedefItem(Box::new(Typedef { - type_: rustdoc_ty, - generics: clean_generics(generics, cx), - item_type: Some(ty), - })) + let generics = clean_generics(generics, cx); + if let Some(count) = cx.current_type_aliases.get_mut(&def_id) { + *count -= 1; + if *count == 0 { + cx.current_type_aliases.remove(&def_id); + } + } + TypedefItem(Box::new(Typedef { type_: rustdoc_ty, generics, item_type: Some(ty) })) } ItemKind::Enum(ref def, generics) => EnumItem(Enum { variants: def.variants.iter().map(|v| clean_variant(v, cx)).collect(), @@ -2287,29 +2377,14 @@ fn clean_maybe_renamed_item<'tcx>( _ => unreachable!("not yet converted"), }; - let target_attrs = inline::load_attrs(cx, def_id); - let attrs = if let Some(import_id) = import_id { - let is_inline = inline::load_attrs(cx, import_id.to_def_id()) - .lists(sym::doc) - .get_word_attr(sym::inline) - .is_some(); - let mut attrs = - get_all_import_attributes(cx, import_id, item.owner_id.def_id, is_inline); - add_without_unwanted_attributes(&mut attrs, target_attrs, is_inline, None); - attrs - } else { - // We only keep the item's attributes. - target_attrs.iter().map(|attr| (Cow::Borrowed(attr), None)).collect() - }; - - let cfg = attrs.cfg(cx.tcx, &cx.cache.hidden_cfg); - let attrs = - Attributes::from_ast_iter(attrs.iter().map(|(attr, did)| (&**attr, *did)), false); - - let mut item = - Item::from_def_id_and_attrs_and_parts(def_id, Some(name), kind, Box::new(attrs), cfg); - item.inline_stmt_id = import_id.map(|local| local.to_def_id()); - vec![item] + vec![generate_item_with_correct_attrs( + cx, + kind, + item.owner_id.def_id, + name, + import_id, + renamed, + )] }) } @@ -2339,14 +2414,15 @@ fn clean_impl<'tcx>( } let for_ = clean_ty(impl_.self_ty, cx); - let type_alias = for_.def_id(&cx.cache).and_then(|did| match tcx.def_kind(did) { - DefKind::TyAlias => Some(clean_middle_ty( - ty::Binder::dummy(tcx.type_of(did).subst_identity()), - cx, - Some(did), - )), - _ => None, - }); + let type_alias = + for_.def_id(&cx.cache).and_then(|alias_def_id: DefId| match tcx.def_kind(alias_def_id) { + DefKind::TyAlias => Some(clean_middle_ty( + ty::Binder::dummy(tcx.type_of(def_id).subst_identity()), + cx, + Some(def_id.to_def_id()), + )), + _ => None, + }); let mut make_item = |trait_: Option, for_: Type, items: Vec| { let kind = ImplItem(Box::new(Impl { unsafety: impl_.unsafety, @@ -2356,7 +2432,7 @@ fn clean_impl<'tcx>( items, polarity: tcx.impl_polarity(def_id), kind: if utils::has_doc_flag(tcx, def_id.to_def_id(), sym::fake_variadic) { - ImplKind::FakeVaradic + ImplKind::FakeVariadic } else { ImplKind::Normal }, @@ -2516,7 +2592,8 @@ fn clean_use_statement_inner<'tcx>( } else { if inline_attr.is_none() && let Res::Def(DefKind::Mod, did) = path.res - && !did.is_local() && did.is_crate_root() + && !did.is_local() + && did.is_crate_root() { // if we're `pub use`ing an extern crate root, don't inline it unless we // were specifically asked for it diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 6d2ce9e28..e9ccea2cf 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -11,6 +11,7 @@ use arrayvec::ArrayVec; use thin_vec::ThinVec; use rustc_ast as ast; +use rustc_ast_pretty::pprust; use rustc_attr::{ConstStability, Deprecation, Stability, StabilityLevel}; use rustc_const_eval::const_eval::is_unstable_const_fn; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -20,7 +21,7 @@ use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_hir::lang_items::LangItem; use rustc_hir::{BodyId, Mutability}; use rustc_hir_analysis::check::intrinsic::intrinsic_operation_unsafety; -use rustc_index::vec::IndexVec; +use rustc_index::IndexVec; 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}; @@ -156,7 +157,7 @@ impl ExternalCrate { } /// Attempts to find where an external crate is located, given that we're - /// rendering in to the specified source destination. + /// rendering into the specified source destination. pub(crate) fn location( &self, extern_url: Option<&str>, @@ -400,12 +401,18 @@ impl Item { .unwrap_or_else(|| self.span(tcx).map_or(rustc_span::DUMMY_SP, |span| span.inner())) } - /// Finds the `doc` attribute as a NameValue and returns the corresponding - /// value found. - pub(crate) fn doc_value(&self) -> Option { + /// Combine all doc strings into a single value handling indentation and newlines as needed. + pub(crate) fn doc_value(&self) -> String { self.attrs.doc_value() } + /// Combine all doc strings into a single value handling indentation and newlines as needed. + /// Returns `None` is there's no documentation at all, and `Some("")` if there is some + /// documentation but it is empty (e.g. `#[doc = ""]`). + pub(crate) fn opt_doc_value(&self) -> Option { + self.attrs.opt_doc_value() + } + pub(crate) fn from_def_id_and_parts( def_id: DefId, name: Option, @@ -442,12 +449,6 @@ impl Item { } } - /// Finds all `doc` attributes as NameValues and returns their corresponding values, joined - /// with newlines. - pub(crate) fn collapsed_doc_value(&self) -> Option { - self.attrs.collapsed_doc_value() - } - pub(crate) fn links(&self, cx: &Context<'_>) -> Vec { use crate::html::format::{href, link_tooltip}; @@ -711,6 +712,78 @@ impl Item { }; Some(tcx.visibility(def_id)) } + + pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, keep_as_is: bool) -> Vec { + const ALLOWED_ATTRIBUTES: &[Symbol] = + &[sym::export_name, sym::link_section, sym::no_mangle, sym::repr, sym::non_exhaustive]; + + use rustc_abi::IntegerType; + use rustc_middle::ty::ReprFlags; + + let mut attrs: Vec = self + .attrs + .other_attrs + .iter() + .filter_map(|attr| { + if keep_as_is { + Some(pprust::attribute_to_string(attr)) + } else if ALLOWED_ATTRIBUTES.contains(&attr.name_or_empty()) { + Some( + pprust::attribute_to_string(attr) + .replace("\\\n", "") + .replace('\n', "") + .replace(" ", " "), + ) + } else { + None + } + }) + .collect(); + if let Some(def_id) = self.item_id.as_def_id() && + !def_id.is_local() && + // This check is needed because `adt_def` will panic if not a compatible type otherwise... + matches!(self.type_(), ItemType::Struct | ItemType::Enum | ItemType::Union) + { + let repr = tcx.adt_def(def_id).repr(); + let mut out = Vec::new(); + if repr.flags.contains(ReprFlags::IS_C) { + out.push("C"); + } + if repr.flags.contains(ReprFlags::IS_TRANSPARENT) { + out.push("transparent"); + } + if repr.flags.contains(ReprFlags::IS_SIMD) { + out.push("simd"); + } + let pack_s; + if let Some(pack) = repr.pack { + pack_s = format!("packed({})", pack.bytes()); + out.push(&pack_s); + } + let align_s; + if let Some(align) = repr.align { + align_s = format!("align({})", align.bytes()); + out.push(&align_s); + } + let int_s; + if let Some(int) = repr.int { + int_s = match int { + IntegerType::Pointer(is_signed) => { + format!("{}size", if is_signed { 'i' } else { 'u' }) + } + IntegerType::Fixed(size, is_signed) => { + format!("{}{}", if is_signed { 'i' } else { 'u' }, size.size().bytes() * 8) + } + }; + out.push(&int_s); + } + if out.is_empty() { + return Vec::new(); + } + attrs.push(format!("#[repr({})]", out.join(", "))); + } + attrs + } } #[derive(Clone, Debug)] @@ -751,7 +824,7 @@ pub(crate) enum ItemKind { PrimitiveItem(PrimitiveType), /// 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. + /// An 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. /// @@ -995,17 +1068,6 @@ impl> NestedAttributesExt for I { } } -/// Collapse a collection of [`DocFragment`]s into one string, -/// handling indentation and newlines as needed. -pub(crate) fn collapse_doc_fragments(doc_strings: &[DocFragment]) -> String { - let mut acc = String::new(); - for frag in doc_strings { - add_doc_fragment(&mut acc, frag); - } - acc.pop(); - acc -} - /// A link that has not yet been rendered. /// /// This link will be turned into a rendered link by [`Item::links`]. @@ -1090,29 +1152,23 @@ impl Attributes { Attributes { doc_strings, other_attrs } } - /// Finds the `doc` attribute as a NameValue and returns the corresponding - /// value found. - pub(crate) fn doc_value(&self) -> Option { - let mut iter = self.doc_strings.iter(); - - let ori = iter.next()?; - let mut out = String::new(); - add_doc_fragment(&mut out, ori); - for new_frag in iter { - add_doc_fragment(&mut out, new_frag); - } - out.pop(); - if out.is_empty() { None } else { Some(out) } + /// Combine all doc strings into a single value handling indentation and newlines as needed. + pub(crate) fn doc_value(&self) -> String { + self.opt_doc_value().unwrap_or_default() } - /// Finds all `doc` attributes as NameValues and returns their corresponding values, joined - /// with newlines. - pub(crate) fn collapsed_doc_value(&self) -> Option { - if self.doc_strings.is_empty() { - None - } else { - Some(collapse_doc_fragments(&self.doc_strings)) - } + /// Combine all doc strings into a single value handling indentation and newlines as needed. + /// Returns `None` is there's no documentation at all, and `Some("")` if there is some + /// documentation but it is empty (e.g. `#[doc = ""]`). + pub(crate) fn opt_doc_value(&self) -> Option { + (!self.doc_strings.is_empty()).then(|| { + let mut res = String::new(); + for frag in &self.doc_strings { + add_doc_fragment(&mut res, frag); + } + res.pop(); + res + }) } pub(crate) fn get_doc_aliases(&self) -> Box<[Symbol]> { @@ -1587,7 +1643,7 @@ impl Type { pub(crate) fn projection(&self) -> Option<(&Type, DefId, PathSegment)> { if let QPath(box QPathData { self_type, trait_, assoc, .. }) = self { - Some((self_type, trait_.def_id(), assoc.clone())) + Some((self_type, trait_.as_ref()?.def_id(), assoc.clone())) } else { None } @@ -1631,7 +1687,7 @@ pub(crate) struct QPathData { pub self_type: Type, /// FIXME: compute this field on demand. pub should_show_cast: bool, - pub trait_: Path, + pub trait_: Option, } /// A primitive (aka, builtin) type. @@ -2305,7 +2361,7 @@ impl Impl { pub(crate) enum ImplKind { Normal, Auto, - FakeVaradic, + FakeVariadic, Blanket(Box), } @@ -2319,7 +2375,7 @@ impl ImplKind { } pub(crate) fn is_fake_variadic(&self) -> bool { - matches!(self, ImplKind::FakeVaradic) + matches!(self, ImplKind::FakeVariadic) } pub(crate) fn as_blanket_ty(&self) -> Option<&Type> { diff --git a/src/librustdoc/clean/types/tests.rs b/src/librustdoc/clean/types/tests.rs index d8c91a968..394954208 100644 --- a/src/librustdoc/clean/types/tests.rs +++ b/src/librustdoc/clean/types/tests.rs @@ -1,7 +1,5 @@ use super::*; -use crate::clean::collapse_doc_fragments; - use rustc_resolve::rustdoc::{unindent_doc_fragments, DocFragment, DocFragmentKind}; use rustc_span::create_default_session_globals_then; use rustc_span::source_map::DUMMY_SP; @@ -22,7 +20,8 @@ fn run_test(input: &str, expected: &str) { create_default_session_globals_then(|| { let mut s = create_doc_fragment(input); unindent_doc_fragments(&mut s); - assert_eq!(collapse_doc_fragments(&s), expected); + let attrs = Attributes { doc_strings: s, other_attrs: Default::default() }; + assert_eq!(attrs.doc_value(), expected); }); } diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index cca50df0d..366f93952 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -193,7 +193,7 @@ pub(crate) fn build_deref_target_impls( }; if let Some(prim) = target.primitive_type() { - let _prof_timer = cx.tcx.sess.prof.generic_activity("build_primitive_inherent_impls"); + let _prof_timer = tcx.sess.prof.generic_activity("build_primitive_inherent_impls"); for did in prim.impls(tcx).filter(|did| !did.is_local()) { inline::build_impl(cx, did, None, ret); } @@ -243,9 +243,9 @@ pub(crate) fn print_const(cx: &DocContext<'_>, n: ty::Const<'_>) -> String { match n.kind() { ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs: _ }) => { let s = if let Some(def) = def.as_local() { - print_const_expr(cx.tcx, cx.tcx.hir().body_owned_by(def.did)) + print_const_expr(cx.tcx, cx.tcx.hir().body_owned_by(def)) } else { - inline::print_inlined_const(cx.tcx, def.did) + inline::print_inlined_const(cx.tcx, def) }; s @@ -594,9 +594,8 @@ pub(super) fn display_macro_source( def_id: DefId, vis: ty::Visibility, ) -> String { - let tts: Vec<_> = def.body.tokens.clone().into_trees().collect(); // Extract the spans of all matchers. They represent the "interface" of the macro. - let matchers = tts.chunks(4).map(|arm| &arm[0]); + let matchers = def.body.tokens.chunks(4).map(|arm| &arm[0]); if def.macro_rules { format!("macro_rules! {} {{\n{}}}", name, render_macro_arms(cx.tcx, matchers, ";")) -- cgit v1.2.3