summaryrefslogtreecommitdiffstats
path: root/src/librustdoc/clean
diff options
context:
space:
mode:
Diffstat (limited to 'src/librustdoc/clean')
-rw-r--r--src/librustdoc/clean/auto_trait.rs22
-rw-r--r--src/librustdoc/clean/blanket_impl.rs2
-rw-r--r--src/librustdoc/clean/inline.rs16
-rw-r--r--src/librustdoc/clean/mod.rs229
-rw-r--r--src/librustdoc/clean/types.rs152
-rw-r--r--src/librustdoc/clean/types/tests.rs5
-rw-r--r--src/librustdoc/clean/utils.rs9
7 files changed, 288 insertions, 147 deletions
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<Item> {
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<Item> = 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<TyCtxt<'tcx>> 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<LocalDefId>,
+ renamed: Option<Symbol>,
+) -> 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>, ty::Region<'tcx>>,
+ pred: ty::RegionOutlivesPredicate<'tcx>,
) -> Option<WherePredicate> {
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<'tcx>, ty::Region<'tcx>>,
+ pred: ty::Binder<'tcx, ty::TypeOutlivesPredicate<'tcx>>,
cx: &mut DocContext<'tcx>,
) -> Option<WherePredicate> {
- 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::<Vec<_>>();
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<GenericBound> = 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<DefId>,
+ parent_def_id: Option<DefId>,
) -> 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::<Vec<_>>();
- 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::<Vec<_>>();
+ 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<Path>, for_: Type, items: Vec<Item>| {
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<String> {
+ /// 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<String> {
+ self.attrs.opt_doc_value()
+ }
+
pub(crate) fn from_def_id_and_parts(
def_id: DefId,
name: Option<Symbol>,
@@ -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<String> {
- self.attrs.collapsed_doc_value()
- }
-
pub(crate) fn links(&self, cx: &Context<'_>) -> Vec<RenderedLink> {
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<String> {
+ 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<String> = 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<I: Iterator<Item = ast::NestedMetaItem>> 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<String> {
- 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<String> {
- 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<String> {
+ (!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<Path>,
}
/// A primitive (aka, builtin) type.
@@ -2305,7 +2361,7 @@ impl Impl {
pub(crate) enum ImplKind {
Normal,
Auto,
- FakeVaradic,
+ FakeVariadic,
Blanket(Box<Type>),
}
@@ -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<DefId>,
) -> 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, ";"))