diff options
| author | Ralf Jung <post@ralfj.de> | 2022-11-05 12:35:40 +0100 |
|---|---|---|
| committer | Ralf Jung <post@ralfj.de> | 2022-11-05 15:21:50 +0100 |
| commit | 83239c2c1ebed372dd34016bdd75d02e4429589d (patch) | |
| tree | f76015608b2a3fcdbdc5dc7f50049e089c6666d6 /src/librustdoc | |
| parent | 4492c029eff7b42e91e759576ab0c7ca88f873dc (diff) | |
| parent | 452cf4f7109f58433ac38be7d3da527408571054 (diff) | |
| download | rust-83239c2c1ebed372dd34016bdd75d02e4429589d.tar.gz rust-83239c2c1ebed372dd34016bdd75d02e4429589d.zip | |
Merge from rustc
Diffstat (limited to 'src/librustdoc')
29 files changed, 539 insertions, 559 deletions
diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 7bc35c7d551..0da69202e67 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -20,7 +20,7 @@ serde_json = "1.0" serde = { version = "1.0", features = ["derive"] } smallvec = "1.8.1" tempfile = "3" -thin-vec = "0.2.8" +thin-vec = "0.2.9" tracing = "0.1" tracing-tree = "0.2.0" diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 764a6d3aa48..84e77e69ecf 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -3,6 +3,7 @@ use rustc_hir as hir; use rustc_hir::lang_items::LangItem; use rustc_middle::ty::{self, Region, RegionVid, TypeFoldable, TypeSuperFoldable}; use rustc_trait_selection::traits::auto_trait::{self, AutoTraitResult}; +use thin_vec::ThinVec; use std::fmt::Debug; @@ -110,7 +111,7 @@ where ); let params = raw_generics.params; - Generics { params, where_predicates: Vec::new() } + Generics { params, where_predicates: ThinVec::new() } } AutoTraitResult::ExplicitImpl => return None, }; @@ -118,7 +119,6 @@ where Some(Item { name: None, attrs: Default::default(), - visibility: Inherited, item_id: ItemId::Auto { trait_: trait_def_id, for_: item_def_id }, kind: Box::new(ImplItem(Box::new(Impl { unsafety: hir::Unsafety::Normal, @@ -130,6 +130,7 @@ where kind: ImplKind::Auto, }))), cfg: None, + inline_stmt_id: None, }) } @@ -183,7 +184,7 @@ where fn handle_lifetimes<'cx>( regions: &RegionConstraintData<'cx>, names_map: &FxHashMap<Symbol, Lifetime>, - ) -> Vec<WherePredicate> { + ) -> ThinVec<WherePredicate> { // Our goal is to 'flatten' the list of constraints by eliminating // all intermediate RegionVids. At the end, all constraints should // be between Regions (aka region variables). This gives us the information @@ -429,7 +430,7 @@ where &mut self, item_def_id: DefId, param_env: ty::ParamEnv<'tcx>, - mut existing_predicates: Vec<WherePredicate>, + mut existing_predicates: ThinVec<WherePredicate>, vid_to_region: FxHashMap<ty::RegionVid, ty::Region<'tcx>>, ) -> Generics { debug!( @@ -663,7 +664,7 @@ where /// both for visual consistency between 'rustdoc' runs, and to /// make writing tests much easier #[inline] - fn sort_where_predicates(&self, predicates: &mut Vec<WherePredicate>) { + fn sort_where_predicates(&self, predicates: &mut [WherePredicate]) { // We should never have identical bounds - and if we do, // they're visually identical as well. Therefore, using // an unstable sort is fine. @@ -710,7 +711,7 @@ where /// approach is probably somewhat slower, but the small number of items /// involved (impls rarely have more than a few bounds) means that it /// shouldn't matter in practice. - fn unstable_debug_sort<T: Debug>(&self, vec: &mut Vec<T>) { + fn unstable_debug_sort<T: Debug>(&self, vec: &mut [T]) { vec.sort_by_cached_key(|x| format!("{:?}", x)) } diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index 8b63c3db3c3..d8063705582 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(trait_def_id) + if !cx.cache.effective_visibilities.is_directly_public(cx.tcx, trait_def_id) || cx.generated_synthetics.get(&(ty.0, trait_def_id)).is_some() { continue; @@ -97,7 +97,6 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { impls.push(Item { name: None, attrs: Default::default(), - visibility: Inherited, item_id: ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id }, kind: Box::new(ImplItem(Box::new(Impl { unsafety: hir::Unsafety::Normal, @@ -128,6 +127,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { ))), }))), cfg: None, + inline_stmt_id: None, }); } } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index b9f787729c1..841c4f9d530 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -19,8 +19,7 @@ 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, clean_visibility, utils, Attributes, AttributesExt, - ImplKind, ItemId, Type, Visibility, + clean_ty_generics, clean_variant_def, utils, Attributes, AttributesExt, ImplKind, ItemId, Type, }; use crate::core::DocContext; use crate::formats::item_type::ItemType; @@ -152,18 +151,10 @@ pub(crate) fn try_inline( let (attrs, cfg) = merge_attrs(cx, Some(parent_module), load_attrs(cx, did), attrs); cx.inlined.insert(did.into()); - let mut item = clean::Item::from_def_id_and_attrs_and_parts( - did, - Some(name), - kind, - Box::new(attrs), - cx, - cfg, - ); - if let Some(import_def_id) = import_def_id { - // The visibility needs to reflect the one from the reexport and not from the "source" DefId. - item.visibility = clean_visibility(cx.tcx.visibility(import_def_id)); - } + let mut item = + clean::Item::from_def_id_and_attrs_and_parts(did, Some(name), kind, Box::new(attrs), cfg); + // The visibility needs to reflect the one from the reexport and not from the "source" DefId. + item.inline_stmt_id = import_def_id; ret.push(item); Some(ret) } @@ -239,13 +230,7 @@ pub(crate) fn build_external_trait(cx: &mut DocContext<'_>, did: DefId) -> clean .tcx .associated_items(did) .in_definition_order() - .map(|item| { - // When building an external trait, the cleaned trait will have all items public, - // which causes methods to have a `pub` prefix, which is invalid since items in traits - // can not have a visibility prefix. Thus we override the visibility here manually. - // See https://github.com/rust-lang/rust/issues/81274 - clean::Item { visibility: Visibility::Inherited, ..clean_middle_assoc_item(item, cx) } - }) + .map(|item| clean_middle_assoc_item(item, cx)) .collect(); let predicates = cx.tcx.predicates_of(did); @@ -323,6 +308,21 @@ pub(crate) fn build_impls( for &did in tcx.inherent_impls(did).iter() { build_impl(cx, parent_module, did, attrs, ret); } + + // This pretty much exists expressly for `dyn Error` traits that exist in the `alloc` crate. + // See also: + // + // * https://github.com/rust-lang/rust/issues/103170 โ where it didn't used to get documented + // * https://github.com/rust-lang/rust/pull/99917 โ where the feature got used + // * https://github.com/rust-lang/rust/issues/53487 โ overall tracking issue for Error + if tcx.has_attr(did, sym::rustc_has_incoherent_inherent_impls) { + use rustc_middle::ty::fast_reject::SimplifiedTypeGen::*; + let type_ = + if tcx.is_trait(did) { TraitSimplifiedType(did) } else { AdtSimplifiedType(did) }; + for &did in tcx.incoherent_impls(type_) { + build_impl(cx, parent_module, did, attrs, ret); + } + } } /// `parent_module` refers to the parent of the re-export, not the original item @@ -374,7 +374,7 @@ pub(crate) fn build_impl( if !did.is_local() { if let Some(traitref) = associated_trait { let did = traitref.def_id; - if !cx.cache.effective_visibilities.is_directly_public(did) { + if !cx.cache.effective_visibilities.is_directly_public(tcx, did) { return; } @@ -403,7 +403,7 @@ pub(crate) fn build_impl( // reachable in rustdoc generated documentation if !did.is_local() { if let Some(did) = for_.def_id(&cx.cache) { - if !cx.cache.effective_visibilities.is_directly_public(did) { + if !cx.cache.effective_visibilities.is_directly_public(tcx, did) { return; } @@ -544,7 +544,6 @@ pub(crate) fn build_impl( }, })), Box::new(merged_attrs), - cx, cfg, )); } @@ -592,7 +591,6 @@ fn build_module_items( name: None, attrs: Box::new(clean::Attributes::default()), item_id: ItemId::Primitive(prim_ty, did.krate), - visibility: clean::Public, kind: Box::new(clean::ImportItem(clean::Import::new_simple( item.ident.name, clean::ImportSource { @@ -611,6 +609,7 @@ fn build_module_items( true, ))), cfg: None, + inline_stmt_id: None, }); } else if let Some(i) = try_inline(cx, did, None, res, item.ident.name, None, visited) { items.extend(i) @@ -654,7 +653,7 @@ fn build_macro( match CStore::from_tcx(cx.tcx).load_macro_untracked(def_id, cx.sess()) { LoadedMacro::MacroDef(item_def, _) => { if let ast::ItemKind::MacroDef(ref def) = item_def.kind { - let vis = clean_visibility(cx.tcx.visibility(import_def_id.unwrap_or(def_id))); + let vis = cx.tcx.visibility(import_def_id.unwrap_or(def_id)); clean::MacroItem(clean::Macro { source: utils::display_macro_source(cx, name, def, def_id, vis), }) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 64a18757b26..16e2d9a3cfc 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -74,12 +74,12 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext< // This covers the case where somebody does an import which should pull in an item, // but there's already an item with the same namespace and same name. Rust gives // priority to the not-imported one, so we should, too. - items.extend(doc.items.iter().flat_map(|(item, renamed)| { + items.extend(doc.items.iter().flat_map(|(item, renamed, import_id)| { // First, lower everything other than imports. if matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) { return Vec::new(); } - let v = clean_maybe_renamed_item(cx, item, *renamed); + let v = clean_maybe_renamed_item(cx, item, *renamed, *import_id); for item in &v { if let Some(name) = item.name && !item.attrs.lists(sym::doc).has_word(sym::hidden) { inserted.insert((item.type_(), name)); @@ -87,7 +87,7 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext< } v })); - items.extend(doc.items.iter().flat_map(|(item, renamed)| { + items.extend(doc.items.iter().flat_map(|(item, renamed, _)| { // Now we actually lower the imports, skipping everything else. if let hir::ItemKind::Use(path, hir::UseKind::Glob) = item.kind { let name = renamed.unwrap_or_else(|| cx.tcx.hir().name(item.hir_id())); @@ -601,7 +601,7 @@ pub(crate) fn clean_generics<'tcx>( }) .collect::<Vec<_>>(); - let mut params = Vec::with_capacity(gens.params.len()); + let mut params = ThinVec::with_capacity(gens.params.len()); for p in gens.params.iter().filter(|p| !is_impl_trait(p) && !is_elided_lifetime(p)) { let p = clean_generic_param(cx, Some(gens), p); params.push(p); @@ -675,7 +675,7 @@ fn clean_ty_generics<'tcx>( } ty::GenericParamDefKind::Const { .. } => Some(clean_generic_param_def(param, cx)), }) - .collect::<Vec<GenericParamDef>>(); + .collect::<ThinVec<GenericParamDef>>(); // param index -> [(trait DefId, associated type name & generics, type, higher-ranked params)] let mut impl_trait_proj = @@ -880,7 +880,7 @@ fn clean_fn_or_proc_macro<'tcx>( ProcMacroItem(ProcMacro { kind, helpers }) } None => { - let mut func = clean_function(cx, sig, generics, body_id); + let mut func = clean_function(cx, sig, generics, FunctionArgs::Body(body_id)); clean_fn_decl_legacy_const_generics(&mut func, attrs); FunctionItem(func) } @@ -917,16 +917,28 @@ fn clean_fn_decl_legacy_const_generics(func: &mut Function, attrs: &[ast::Attrib } } +enum FunctionArgs<'tcx> { + Body(hir::BodyId), + Names(&'tcx [Ident]), +} + fn clean_function<'tcx>( cx: &mut DocContext<'tcx>, sig: &hir::FnSig<'tcx>, generics: &hir::Generics<'tcx>, - body_id: hir::BodyId, + args: FunctionArgs<'tcx>, ) -> Box<Function> { let (generics, decl) = enter_impl_trait(cx, |cx| { // NOTE: generics must be cleaned before args let generics = clean_generics(generics, cx); - let args = clean_args_from_types_and_body_id(cx, sig.decl.inputs, body_id); + let args = match args { + FunctionArgs::Body(body_id) => { + clean_args_from_types_and_body_id(cx, sig.decl.inputs, body_id) + } + FunctionArgs::Names(names) => { + clean_args_from_types_and_names(cx, sig.decl.inputs, names) + } + }; let mut decl = clean_fn_decl_with_args(cx, sig.decl, args); if sig.header.is_async() { decl.output = decl.sugared_async_return_type(); @@ -1051,18 +1063,12 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext ), hir::TraitItemKind::Const(ty, None) => TyAssocConstItem(clean_ty(ty, cx)), hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => { - let m = clean_function(cx, sig, trait_item.generics, body); + let m = clean_function(cx, sig, trait_item.generics, FunctionArgs::Body(body)); MethodItem(m, None) } hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(names)) => { - let (generics, decl) = enter_impl_trait(cx, |cx| { - // NOTE: generics must be cleaned before args - let generics = clean_generics(trait_item.generics, cx); - let args = clean_args_from_types_and_names(cx, sig.decl.inputs, names); - let decl = clean_fn_decl_with_args(cx, sig.decl, args); - (generics, decl) - }); - TyMethodItem(Box::new(Function { decl, generics })) + let m = clean_function(cx, sig, trait_item.generics, FunctionArgs::Names(names)); + TyMethodItem(m) } hir::TraitItemKind::Type(bounds, Some(default)) => { let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx)); @@ -1080,13 +1086,10 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext hir::TraitItemKind::Type(bounds, None) => { let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx)); let bounds = bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(); - TyAssocTypeItem(Box::new(generics), bounds) + TyAssocTypeItem(generics, bounds) } }; - let what_rustc_thinks = - Item::from_def_id_and_parts(local_did, Some(trait_item.ident.name), inner, cx); - // Trait items always inherit the trait's visibility -- we don't want to show `pub`. - Item { visibility: Inherited, ..what_rustc_thinks } + Item::from_def_id_and_parts(local_did, Some(trait_item.ident.name), inner, cx) }) } @@ -1102,7 +1105,7 @@ pub(crate) fn clean_impl_item<'tcx>( AssocConstItem(clean_ty(ty, cx), default) } hir::ImplItemKind::Fn(ref sig, body) => { - let m = clean_function(cx, sig, impl_.generics, body); + let m = clean_function(cx, sig, impl_.generics, FunctionArgs::Body(body)); let defaultness = cx.tcx.impl_defaultness(impl_.owner_id); MethodItem(m, Some(defaultness)) } @@ -1117,18 +1120,7 @@ pub(crate) fn clean_impl_item<'tcx>( } }; - let mut what_rustc_thinks = - Item::from_def_id_and_parts(local_did, Some(impl_.ident.name), inner, cx); - - let impl_ref = cx.tcx.impl_trait_ref(cx.tcx.local_parent(impl_.owner_id.def_id)); - - // Trait impl items always inherit the impl's visibility -- - // we don't want to show `pub`. - if impl_ref.is_some() { - what_rustc_thinks.visibility = Inherited; - } - - what_rustc_thinks + Item::from_def_id_and_parts(local_did, Some(impl_.ident.name), inner, cx) }) } @@ -1225,56 +1217,47 @@ pub(crate) fn clean_middle_assoc_item<'tcx>( tcx.generics_of(assoc_item.def_id), ty::GenericPredicates { parent: None, predicates }, ); - // Move bounds that are (likely) directly attached to the associated type - // from the where clause to the associated type. - // There is no guarantee that this is what the user actually wrote but we have - // no way of knowing. - let mut bounds = generics - .where_predicates - .drain_filter(|pred| match *pred { - WherePredicate::BoundPredicate { - ty: QPath(box QPathData { ref assoc, ref self_type, ref trait_, .. }), - .. - } => { - if assoc.name != my_name { - return false; - } - if trait_.def_id() != assoc_item.container_id(tcx) { - return false; - } - match *self_type { - Generic(ref s) if *s == kw::SelfUpper => {} - _ => return false, - } - match &assoc.args { - GenericArgs::AngleBracketed { args, bindings } => { - if !bindings.is_empty() - || generics - .params - .iter() - .zip(args.iter()) - .any(|(param, arg)| !param_eq_arg(param, arg)) - { - return false; - } - } - GenericArgs::Parenthesized { .. } => { - // The only time this happens is if we're inside the rustdoc for Fn(), - // which only has one associated type, which is not a GAT, so whatever. + // Filter out the bounds that are (likely?) directly attached to the associated type, + // as opposed to being located in the where clause. + 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_, .. }), + bounds: ref mut pred_bounds, + .. + } => { + if assoc.name != my_name { + return true; + } + if trait_.def_id() != assoc_item.container_id(tcx) { + return true; + } + match *self_type { + Generic(ref s) if *s == kw::SelfUpper => {} + _ => return true, + } + match &assoc.args { + GenericArgs::AngleBracketed { args, bindings } => { + if !bindings.is_empty() + || generics + .params + .iter() + .zip(args.iter()) + .any(|(param, arg)| !param_eq_arg(param, arg)) + { + return true; } } - true - } - _ => false, - }) - .flat_map(|pred| { - if let WherePredicate::BoundPredicate { bounds, .. } = pred { - bounds - } else { - unreachable!() + GenericArgs::Parenthesized { .. } => { + // The only time this happens is if we're inside the rustdoc for Fn(), + // which only has one associated type, which is not a GAT, so whatever. + } } - }) - .collect::<Vec<_>>(); + bounds.extend(mem::replace(pred_bounds, Vec::new())); + false + } + _ => true, + }); // Our Sized/?Sized bound didn't get handled when creating the generics // because we didn't actually get our whole set of bounds until just now // (some of them may have come from the trait). If we do have a sized @@ -1290,7 +1273,7 @@ pub(crate) fn clean_middle_assoc_item<'tcx>( // (generic) associated type from the where clause to the respective parameter. // There is no guarantee that this is what the user actually wrote but we have // no way of knowing. - let mut where_predicates = Vec::new(); + let mut where_predicates = ThinVec::new(); for mut pred in generics.where_predicates { if let WherePredicate::BoundPredicate { ty: Generic(arg), bounds, .. } = &mut pred && let Some(GenericParamDef { @@ -1320,7 +1303,7 @@ pub(crate) fn clean_middle_assoc_item<'tcx>( bounds, ) } else { - TyAssocTypeItem(Box::new(generics), bounds) + TyAssocTypeItem(generics, bounds) } } else { // FIXME: when could this happen? Associated items in inherent impls? @@ -1331,7 +1314,10 @@ pub(crate) fn clean_middle_assoc_item<'tcx>( cx, Some(assoc_item.def_id), ), - generics: Generics { params: Vec::new(), where_predicates: Vec::new() }, + generics: Generics { + params: ThinVec::new(), + where_predicates: ThinVec::new(), + }, item_type: None, }), Vec::new(), @@ -1340,18 +1326,7 @@ pub(crate) fn clean_middle_assoc_item<'tcx>( } }; - let mut what_rustc_thinks = - Item::from_def_id_and_parts(assoc_item.def_id, Some(assoc_item.name), kind, cx); - - let impl_ref = tcx.impl_trait_ref(tcx.parent(assoc_item.def_id)); - - // Trait impl items always inherit the impl's visibility -- - // we don't want to show `pub`. - if impl_ref.is_some() { - what_rustc_thinks.visibility = Visibility::Inherited; - } - - what_rustc_thinks + Item::from_def_id_and_parts(assoc_item.def_id, Some(assoc_item.name), kind, cx) } fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type { @@ -1406,7 +1381,8 @@ fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type ty::Projection(proj) => Res::Def(DefKind::Trait, proj.trait_ref(cx.tcx).def_id), // Rustdoc handles `ty::Error`s by turning them into `Type::Infer`s. ty::Error(_) => return Type::Infer, - _ => bug!("clean: expected associated type, found `{:?}`", ty), + // Otherwise, this is an inherent associated type. + _ => return clean_middle_ty(ty, cx, None), }; let trait_ = clean_path(&hir::Path { span, res, segments: &[] }, cx); register_res(cx, trait_.res); @@ -1431,7 +1407,7 @@ 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(def_id.to_def_id()) { + let alias = if !cx.cache.effective_visibilities.is_exported(cx.tcx, def_id.to_def_id()) { &cx.tcx.hir().expect_item(def_id).kind } else { return None; @@ -1821,30 +1797,7 @@ pub(crate) fn clean_field_with_def_id( ty: Type, cx: &mut DocContext<'_>, ) -> Item { - let what_rustc_thinks = - Item::from_def_id_and_parts(def_id, Some(name), StructFieldItem(ty), cx); - if is_field_vis_inherited(cx.tcx, def_id) { - // Variant fields inherit their enum's visibility. - Item { visibility: Visibility::Inherited, ..what_rustc_thinks } - } else { - what_rustc_thinks - } -} - -fn is_field_vis_inherited(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - let parent = tcx.parent(def_id); - match tcx.def_kind(parent) { - DefKind::Struct | DefKind::Union => false, - DefKind::Variant => true, - parent_kind => panic!("unexpected parent kind: {:?}", parent_kind), - } -} - -pub(crate) fn clean_visibility(vis: ty::Visibility<DefId>) -> Visibility { - match vis { - ty::Visibility::Public => Visibility::Public, - ty::Visibility::Restricted(module) => Visibility::Restricted(module), - } + Item::from_def_id_and_parts(def_id, Some(name), StructFieldItem(ty), cx) } pub(crate) fn clean_variant_def<'tcx>(variant: &ty::VariantDef, cx: &mut DocContext<'tcx>) -> Item { @@ -1861,10 +1814,7 @@ pub(crate) fn clean_variant_def<'tcx>(variant: &ty::VariantDef, cx: &mut DocCont fields: variant.fields.iter().map(|field| clean_middle_field(field, cx)).collect(), }), }; - let what_rustc_thinks = - Item::from_def_id_and_parts(variant.def_id, Some(variant.name), VariantItem(kind), cx); - // don't show `pub` for variants, which always inherit visibility - Item { visibility: Inherited, ..what_rustc_thinks } + Item::from_def_id_and_parts(variant.def_id, Some(variant.name), VariantItem(kind), cx) } fn clean_variant_data<'tcx>( @@ -1955,6 +1905,7 @@ fn clean_maybe_renamed_item<'tcx>( cx: &mut DocContext<'tcx>, item: &hir::Item<'tcx>, renamed: Option<Symbol>, + import_id: Option<hir::HirId>, ) -> Vec<Item> { use hir::ItemKind; @@ -2005,7 +1956,7 @@ fn clean_maybe_renamed_item<'tcx>( clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx) } ItemKind::Macro(ref macro_def, _) => { - let ty_vis = clean_visibility(cx.tcx.visibility(def_id)); + let ty_vis = cx.tcx.visibility(def_id); MacroItem(Macro { source: display_macro_source(cx, name, macro_def, def_id, ty_vis), }) @@ -2031,17 +1982,29 @@ fn clean_maybe_renamed_item<'tcx>( } _ => unreachable!("not yet converted"), }; - - vec![Item::from_def_id_and_parts(def_id, Some(name), kind, cx)] + if let Some(import_id) = import_id { + let (attrs, cfg) = inline::merge_attrs( + cx, + Some(cx.tcx.parent_module(import_id).to_def_id()), + inline::load_attrs(cx, def_id), + Some(inline::load_attrs(cx, cx.tcx.hir().local_def_id(import_id).to_def_id())), + ); + vec![Item::from_def_id_and_attrs_and_parts( + def_id, + Some(name), + kind, + Box::new(attrs), + cfg, + )] + } else { + vec![Item::from_def_id_and_parts(def_id, Some(name), kind, cx)] + } }) } fn clean_variant<'tcx>(variant: &hir::Variant<'tcx>, cx: &mut DocContext<'tcx>) -> Item { let kind = VariantItem(clean_variant_data(&variant.data, &variant.disr_expr, cx)); - let what_rustc_thinks = - Item::from_hir_id_and_parts(variant.id, Some(variant.ident.name), kind, cx); - // don't show `pub` for variants, which are always public - Item { visibility: Inherited, ..what_rustc_thinks } + Item::from_hir_id_and_parts(variant.id, Some(variant.ident.name), kind, cx) } fn clean_impl<'tcx>( @@ -2114,6 +2077,7 @@ fn clean_extern_crate<'tcx>( } }); + let krate_owner_def_id = krate.owner_id.to_def_id(); if please_inline { let mut visited = FxHashSet::default(); @@ -2122,7 +2086,7 @@ fn clean_extern_crate<'tcx>( if let Some(items) = inline::try_inline( cx, cx.tcx.parent_module(krate.hir_id()).to_def_id(), - Some(krate.owner_id.to_def_id()), + Some(krate_owner_def_id), res, name, Some(attrs), @@ -2137,9 +2101,9 @@ fn clean_extern_crate<'tcx>( name: Some(name), attrs: Box::new(Attributes::from_ast(attrs)), item_id: crate_def_id.into(), - visibility: clean_visibility(ty_vis), kind: Box::new(ExternCrateItem { src: orig_name }), cfg: attrs.cfg(cx.tcx, &cx.cache.hidden_cfg), + inline_stmt_id: Some(krate_owner_def_id), }] } diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index 1bcb9fcd5a4..1c184f9b269 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -14,13 +14,14 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_hir::def_id::DefId; use rustc_middle::ty; +use thin_vec::ThinVec; use crate::clean; use crate::clean::GenericArgs as PP; use crate::clean::WherePredicate as WP; use crate::core::DocContext; -pub(crate) fn where_clauses(cx: &DocContext<'_>, clauses: Vec<WP>) -> Vec<WP> { +pub(crate) fn where_clauses(cx: &DocContext<'_>, clauses: Vec<WP>) -> ThinVec<WP> { // First, partition the where clause into its separate components. // // We use `FxIndexMap` so that the insertion order is preserved to prevent messing up to @@ -59,7 +60,7 @@ pub(crate) fn where_clauses(cx: &DocContext<'_>, clauses: Vec<WP>) -> Vec<WP> { }); // And finally, let's reassemble everything - let mut clauses = Vec::new(); + let mut clauses = ThinVec::with_capacity(lifetimes.len() + tybounds.len() + equalities.len()); clauses.extend( lifetimes.into_iter().map(|(lt, bounds)| WP::RegionPredicate { lifetime: lt, bounds }), ); diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index cd1f972dce8..fea3690e50a 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -24,7 +24,7 @@ use rustc_hir::{BodyId, Mutability}; use rustc_hir_analysis::check::intrinsic::intrinsic_operation_unsafety; use rustc_index::vec::IndexVec; use rustc_middle::ty::fast_reject::SimplifiedType; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::{self, DefIdTree, TyCtxt, Visibility}; use rustc_session::Session; use rustc_span::hygiene::MacroKind; use rustc_span::source_map::DUMMY_SP; @@ -34,7 +34,6 @@ use rustc_target::abi::VariantIdx; use rustc_target::spec::abi::Abi; use crate::clean::cfg::Cfg; -use crate::clean::clean_visibility; use crate::clean::external_path; use crate::clean::inline::{self, print_inlined_const}; use crate::clean::utils::{is_literal_expr, print_const_expr, print_evaluated_const}; @@ -51,7 +50,6 @@ pub(crate) use self::Type::{ Array, BareFunction, BorrowedRef, DynTrait, Generic, ImplTrait, Infer, Primitive, QPath, RawPointer, Slice, Tuple, }; -pub(crate) use self::Visibility::{Inherited, Public}; #[cfg(test)] mod tests; @@ -348,12 +346,12 @@ pub(crate) struct Item { /// Optional because not every item has a name, e.g. impls. pub(crate) name: Option<Symbol>, pub(crate) attrs: Box<Attributes>, - pub(crate) visibility: Visibility, /// Information about this item that is specific to what kind of item it is. /// E.g., struct vs enum vs function. pub(crate) kind: Box<ItemKind>, pub(crate) item_id: ItemId, - + /// This is the `DefId` of the `use` statement if the item was inlined. + pub(crate) inline_stmt_id: Option<DefId>, pub(crate) cfg: Option<Arc<Cfg>>, } @@ -364,9 +362,7 @@ impl fmt::Debug for Item { let alternate = f.alternate(); // hand-picked fields that don't bloat the logs too much let mut fmt = f.debug_struct("Item"); - fmt.field("name", &self.name) - .field("visibility", &self.visibility) - .field("item_id", &self.item_id); + fmt.field("name", &self.name).field("item_id", &self.item_id); // allow printing the full item if someone really wants to if alternate { fmt.field("attrs", &self.attrs).field("kind", &self.kind).field("cfg", &self.cfg); @@ -388,6 +384,15 @@ pub(crate) fn rustc_span(def_id: DefId, tcx: TyCtxt<'_>) -> Span { )) } +fn is_field_vis_inherited(tcx: TyCtxt<'_>, def_id: DefId) -> bool { + let parent = tcx.parent(def_id); + match tcx.def_kind(parent) { + DefKind::Struct | DefKind::Union => false, + DefKind::Variant => true, + parent_kind => panic!("unexpected parent kind: {:?}", parent_kind), + } +} + impl Item { pub(crate) fn stability<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Option<Stability> { self.item_id.as_def_id().and_then(|did| tcx.lookup_stability(did)) @@ -462,7 +467,6 @@ impl Item { name, kind, Box::new(Attributes::from_ast(ast_attrs)), - cx, ast_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg), ) } @@ -472,21 +476,18 @@ impl Item { name: Option<Symbol>, kind: ItemKind, attrs: Box<Attributes>, - cx: &mut DocContext<'_>, cfg: Option<Arc<Cfg>>, ) -> Item { trace!("name={:?}, def_id={:?} cfg={:?}", name, def_id, cfg); - // Primitives and Keywords are written in the source code as private modules. - // The modules need to be private so that nobody actually uses them, but the - // keywords and primitives that they are documenting are public. - let visibility = if matches!(&kind, ItemKind::KeywordItem | ItemKind::PrimitiveItem(..)) { - Visibility::Public - } else { - clean_visibility(cx.tcx.visibility(def_id)) - }; - - Item { item_id: def_id.into(), kind: Box::new(kind), name, attrs, visibility, cfg } + Item { + item_id: def_id.into(), + kind: Box::new(kind), + name, + attrs, + cfg, + inline_stmt_id: None, + } } /// Finds all `doc` attributes as NameValues and returns their corresponding values, joined @@ -691,17 +692,61 @@ impl Item { asyncness: hir::IsAsync::NotAsync, } } - ItemKind::FunctionItem(_) | ItemKind::MethodItem(_, _) => { + ItemKind::FunctionItem(_) | ItemKind::MethodItem(_, _) | ItemKind::TyMethodItem(_) => { let def_id = self.item_id.as_def_id().unwrap(); build_fn_header(def_id, tcx, tcx.asyncness(def_id)) } - ItemKind::TyMethodItem(_) => { - build_fn_header(self.item_id.as_def_id().unwrap(), tcx, hir::IsAsync::NotAsync) - } _ => return None, }; Some(header) } + + /// Returns the visibility of the current item. If the visibility is "inherited", then `None` + /// is returned. + pub(crate) fn visibility(&self, tcx: TyCtxt<'_>) -> Option<Visibility<DefId>> { + let def_id = match self.item_id { + // Anything but DefId *shouldn't* matter, but return a reasonable value anyway. + ItemId::Auto { .. } | ItemId::Blanket { .. } => return None, + // Primitives and Keywords are written in the source code as private modules. + // The modules need to be private so that nobody actually uses them, but the + // keywords and primitives that they are documenting are public. + ItemId::Primitive(..) => return Some(Visibility::Public), + ItemId::DefId(def_id) => def_id, + }; + + match *self.kind { + // Explication on `ItemId::Primitive` just above. + ItemKind::KeywordItem | ItemKind::PrimitiveItem(_) => return Some(Visibility::Public), + // Variant fields inherit their enum's visibility. + StructFieldItem(..) if is_field_vis_inherited(tcx, def_id) => { + return None; + } + // Variants always inherit visibility + VariantItem(..) => return None, + // Trait items inherit the trait's visibility + AssocConstItem(..) | TyAssocConstItem(..) | AssocTypeItem(..) | TyAssocTypeItem(..) + | TyMethodItem(..) | MethodItem(..) => { + let assoc_item = tcx.associated_item(def_id); + let is_trait_item = match assoc_item.container { + ty::TraitContainer => true, + ty::ImplContainer => { + // Trait impl items always inherit the impl's visibility -- + // we don't want to show `pub`. + tcx.impl_trait_ref(tcx.parent(assoc_item.def_id)).is_some() + } + }; + if is_trait_item { + return None; + } + } + _ => {} + } + let def_id = match self.inline_stmt_id { + Some(inlined) => inlined, + None => def_id, + }; + Some(tcx.visibility(def_id)) + } } #[derive(Clone, Debug)] @@ -747,7 +792,7 @@ pub(crate) enum ItemKind { /// A required associated type in a trait declaration. /// /// The bounds may be non-empty if there is a `where` clause. - TyAssocTypeItem(Box<Generics>, Vec<GenericBound>), + TyAssocTypeItem(Generics, Vec<GenericBound>), /// An associated type in a trait impl or a provided one in a trait declaration. AssocTypeItem(Box<Typedef>, Vec<GenericBound>), /// An item that has been stripped by a rustdoc pass @@ -1414,8 +1459,8 @@ impl GenericParamDef { // maybe use a Generic enum and use Vec<Generic>? #[derive(Clone, Debug, Default)] pub(crate) struct Generics { - pub(crate) params: Vec<GenericParamDef>, - pub(crate) where_predicates: Vec<WherePredicate>, + pub(crate) params: ThinVec<GenericParamDef>, + pub(crate) where_predicates: ThinVec<WherePredicate>, } impl Generics { @@ -2030,24 +2075,6 @@ impl From<hir::PrimTy> for PrimitiveType { } } -#[derive(Copy, Clone, Debug)] -pub(crate) enum Visibility { - /// `pub` - Public, - /// Visibility inherited from parent. - /// - /// For example, this is the visibility of private items and of enum variants. - Inherited, - /// `pub(crate)`, `pub(super)`, or `pub(in path::to::somewhere)` - Restricted(DefId), -} - -impl Visibility { - pub(crate) fn is_public(&self) -> bool { - matches!(self, Visibility::Public) - } -} - #[derive(Clone, Debug)] pub(crate) struct Struct { pub(crate) struct_type: CtorKind, @@ -2546,6 +2573,7 @@ mod size_asserts { static_assert_size!(GenericArg, 48); static_assert_size!(GenericArgs, 32); static_assert_size!(GenericParamDef, 56); + static_assert_size!(Generics, 16); static_assert_size!(Item, 56); static_assert_size!(ItemKind, 88); static_assert_size!(PathSegment, 40); diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 4572a712258..df20dc3fc3f 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -4,11 +4,10 @@ use crate::clean::render_macro_matchers::render_macro_matcher; use crate::clean::{ clean_doc_module, clean_middle_const, clean_middle_region, clean_middle_ty, inline, Crate, ExternalCrate, Generic, GenericArg, GenericArgs, ImportSource, Item, ItemKind, Lifetime, Path, - PathSegment, Primitive, PrimitiveType, Type, TypeBinding, Visibility, + PathSegment, Primitive, PrimitiveType, Type, TypeBinding, }; use crate::core::DocContext; -use crate::formats::item_type::ItemType; -use crate::visit_lib::LibEmbargoVisitor; +use crate::html::format::visibility_to_src_with_space; use rustc_ast as ast; use rustc_ast::tokenstream::TokenTree; @@ -32,7 +31,7 @@ pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate { for &cnum in cx.tcx.crates(()) { // Analyze doc-reachability for extern items - LibEmbargoVisitor::new(cx).visit_lib(cnum); + crate::visit_lib::lib_embargo_visit_item(cx, cnum.as_def_id()); } // Clean the crate, translating the entire librustc_ast AST to one that is @@ -504,9 +503,6 @@ pub(crate) fn register_res(cx: &mut DocContext<'_>, res: Res) -> DefId { return did; } inline::record_extern_fqn(cx, did, kind); - if let ItemType::Trait = kind { - inline::record_extern_trait(cx, did); - } did } @@ -588,7 +584,7 @@ pub(super) fn display_macro_source( name: Symbol, def: &ast::MacroDef, def_id: DefId, - vis: Visibility, + vis: ty::Visibility<DefId>, ) -> String { let tts: Vec<_> = def.body.inner_tokens().into_trees().collect(); // Extract the spans of all matchers. They represent the "interface" of the macro. @@ -600,14 +596,14 @@ pub(super) fn display_macro_source( if matchers.len() <= 1 { format!( "{}macro {}{} {{\n ...\n}}", - vis.to_src_with_space(cx.tcx, def_id), + visibility_to_src_with_space(Some(vis), cx.tcx, def_id), name, matchers.map(|matcher| render_macro_matcher(cx.tcx, matcher)).collect::<String>(), ) } else { format!( "{}macro {} {{\n{}}}", - vis.to_src_with_space(cx.tcx, def_id), + visibility_to_src_with_space(Some(vis), cx.tcx, def_id), name, render_macro_arms(cx.tcx, matchers, ","), ) diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 3e5f42b7a80..893249e88cf 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -166,6 +166,7 @@ pub(crate) fn new_handler( unstable_opts.teach, diagnostic_width, false, + unstable_opts.track_diagnostics, ) .ui_testing(unstable_opts.ui_testing), ) @@ -184,6 +185,7 @@ pub(crate) fn new_handler( json_rendered, diagnostic_width, false, + unstable_opts.track_diagnostics, ) .ui_testing(unstable_opts.ui_testing), ) @@ -348,7 +350,6 @@ pub(crate) fn run_global_ctxt( let auto_traits = tcx.all_traits().filter(|&trait_def_id| tcx.trait_is_auto(trait_def_id)).collect(); - let effective_visibilities = tcx.effective_visibilities(()).map_id(Into::into); let mut ctxt = DocContext { tcx, @@ -361,7 +362,7 @@ pub(crate) fn run_global_ctxt( impl_trait_bounds: Default::default(), generated_synthetics: Default::default(), auto_traits, - cache: Cache::new(effective_visibilities, render_options.document_private), + cache: Cache::new(render_options.document_private), inlined: FxHashSet::default(), output_format, render_options, diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index db70029f6ec..7cbe2f1e227 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -551,6 +551,7 @@ pub(crate) fn make_test( false, Some(80), false, + false, ) .supports_color(); @@ -564,6 +565,7 @@ pub(crate) fn make_test( false, None, false, + false, ); // FIXME(misdreavus): pass `-Z treat-err-as-bug` to the doctest parser @@ -748,6 +750,7 @@ fn check_if_attr_is_complete(source: &str, edition: Edition) -> bool { false, None, false, + false, ); let handler = Handler::with_emitter(false, None, Box::new(emitter)); diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index afe2264e8bf..d027fb6e876 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -2,7 +2,6 @@ use std::mem; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def_id::{CrateNum, DefId}; -use rustc_middle::middle::privacy::EffectiveVisibilities; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::Symbol; @@ -15,6 +14,7 @@ use crate::html::format::join_with_double_colon; use crate::html::markdown::short_markdown_summary; use crate::html::render::search_index::get_function_type_for_search; use crate::html::render::IndexItem; +use crate::visit_lib::RustdocEffectiveVisibilities; /// This cache is used to store information about the [`clean::Crate`] being /// rendered in order to provide more useful documentation. This contains @@ -78,7 +78,7 @@ pub(crate) struct Cache { // Note that external items for which `doc(hidden)` applies to are shown as // non-reachable while local items aren't. This is because we're reusing // the effective visibilities from the privacy check pass. - pub(crate) effective_visibilities: EffectiveVisibilities<DefId>, + pub(crate) effective_visibilities: RustdocEffectiveVisibilities, /// The version of the crate being documented, if given from the `--crate-version` flag. pub(crate) crate_version: Option<String>, @@ -132,11 +132,8 @@ struct CacheBuilder<'a, 'tcx> { } impl Cache { - pub(crate) fn new( - effective_visibilities: EffectiveVisibilities<DefId>, - document_private: bool, - ) -> Self { - Cache { effective_visibilities, document_private, ..Cache::default() } + pub(crate) fn new(document_private: bool) -> Self { + Cache { document_private, ..Cache::default() } } /// Populates the `Cache` with more data. The returned `Crate` will be missing some data that was @@ -319,21 +316,28 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { let desc = item.doc_value().map_or_else(String::new, |x| { short_markdown_summary(x.as_str(), &item.link_names(self.cache)) }); - self.cache.search_index.push(IndexItem { - ty: item.type_(), - name: s.to_string(), - path: join_with_double_colon(path), - desc, - parent, - parent_idx: None, - search_type: get_function_type_for_search( - &item, - self.tcx, - clean_impl_generics(self.cache.parent_stack.last()).as_ref(), - self.cache, - ), - aliases: item.attrs.get_doc_aliases(), - }); + let ty = item.type_(); + let name = s.to_string(); + if ty != ItemType::StructField || u16::from_str_radix(&name, 10).is_err() { + // In case this is a field from a tuple struct, we don't add it into + // the search index because its name is something like "0", which is + // not useful for rustdoc search. + self.cache.search_index.push(IndexItem { + ty, + name, + path: join_with_double_colon(path), + desc, + parent, + parent_idx: None, + search_type: get_function_type_for_search( + &item, + self.tcx, + clean_impl_generics(self.cache.parent_stack.last()).as_ref(), + self.cache, + ), + aliases: item.attrs.get_doc_aliases(), + }); + } } } (Some(parent), None) if is_inherent_impl_item => { @@ -387,7 +391,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { || self .cache .effective_visibilities - .is_directly_public(item.item_id.expect_def_id()) + .is_directly_public(self.tcx, item.item_id.expect_def_id()) { self.cache.paths.insert( item.item_id.expect_def_id(), diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 92e7f2739af..06db3fb0ec4 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -659,7 +659,7 @@ pub(crate) fn href_with_root_path( } if !did.is_local() - && !cache.effective_visibilities.is_directly_public(did) + && !cache.effective_visibilities.is_directly_public(tcx, did) && !cache.document_private && !cache.primitive_locations.values().any(|&id| id == did) { @@ -1420,87 +1420,84 @@ impl clean::FnDecl { } } -impl clean::Visibility { - pub(crate) fn print_with_space<'a, 'tcx: 'a>( - self, - item_did: ItemId, - cx: &'a Context<'tcx>, - ) -> impl fmt::Display + 'a + Captures<'tcx> { - use std::fmt::Write as _; - - let to_print: Cow<'static, str> = match self { - clean::Public => "pub ".into(), - clean::Inherited => "".into(), - clean::Visibility::Restricted(vis_did) => { - // FIXME(camelid): This may not work correctly if `item_did` is a module. - // However, rustdoc currently never displays a module's - // visibility, so it shouldn't matter. - let parent_module = find_nearest_parent_module(cx.tcx(), item_did.expect_def_id()); - - if vis_did.is_crate_root() { - "pub(crate) ".into() - } else if parent_module == Some(vis_did) { - // `pub(in foo)` where `foo` is the parent module - // is the same as no visibility modifier - "".into() - } else if parent_module - .and_then(|parent| find_nearest_parent_module(cx.tcx(), parent)) - == Some(vis_did) - { - "pub(super) ".into() - } else { - let path = cx.tcx().def_path(vis_did); - debug!("path={:?}", path); - // modified from `resolved_path()` to work with `DefPathData` - let last_name = path.data.last().unwrap().data.get_opt_name().unwrap(); - let anchor = anchor(vis_did, last_name, cx).to_string(); - - let mut s = "pub(in ".to_owned(); - for seg in &path.data[..path.data.len() - 1] { - let _ = write!(s, "{}::", seg.data.get_opt_name().unwrap()); - } - let _ = write!(s, "{}) ", anchor); - s.into() +pub(crate) fn visibility_print_with_space<'a, 'tcx: 'a>( + visibility: Option<ty::Visibility<DefId>>, + item_did: ItemId, + cx: &'a Context<'tcx>, +) -> impl fmt::Display + 'a + Captures<'tcx> { + use std::fmt::Write as _; + + let to_print: Cow<'static, str> = match visibility { + None => "".into(), + Some(ty::Visibility::Public) => "pub ".into(), + Some(ty::Visibility::Restricted(vis_did)) => { + // FIXME(camelid): This may not work correctly if `item_did` is a module. + // However, rustdoc currently never displays a module's + // visibility, so it shouldn't matter. + let parent_module = find_nearest_parent_module(cx.tcx(), item_did.expect_def_id()); + + if vis_did.is_crate_root() { + "pub(crate) ".into() + } else if parent_module == Some(vis_did) { + // `pub(in foo)` where `foo` is the parent module + // is the same as no visibility modifier + "".into() + } else if parent_module.and_then(|parent| find_nearest_parent_module(cx.tcx(), parent)) + == Some(vis_did) + { + "pub(super) ".into() + } else { + let path = cx.tcx().def_path(vis_did); + debug!("path={:?}", path); + // modified from `resolved_path()` to work with `DefPathData` + let last_name = path.data.last().unwrap().data.get_opt_name().unwrap(); + let anchor = anchor(vis_did, last_name, cx).to_string(); + + let mut s = "pub(in ".to_owned(); + for seg in &path.data[..path.data.len() - 1] { + let _ = write!(s, "{}::", seg.data.get_opt_name().unwrap()); } + let _ = write!(s, "{}) ", anchor); + s.into() } - }; - display_fn(move |f| write!(f, "{}", to_print)) - } + } + }; + display_fn(move |f| write!(f, "{}", to_print)) +} - /// This function is the same as print_with_space, except that it renders no links. - /// It's used for macros' rendered source view, which is syntax highlighted and cannot have - /// any HTML in it. - pub(crate) fn to_src_with_space<'a, 'tcx: 'a>( - self, - tcx: TyCtxt<'tcx>, - item_did: DefId, - ) -> impl fmt::Display + 'a + Captures<'tcx> { - let to_print = match self { - clean::Public => "pub ".to_owned(), - clean::Inherited => String::new(), - clean::Visibility::Restricted(vis_did) => { - // FIXME(camelid): This may not work correctly if `item_did` is a module. - // However, rustdoc currently never displays a module's - // visibility, so it shouldn't matter. - let parent_module = find_nearest_parent_module(tcx, item_did); - - if vis_did.is_crate_root() { - "pub(crate) ".to_owned() - } else if parent_module == Some(vis_did) { - // `pub(in foo)` where `foo` is the parent module - // is the same as no visibility modifier - String::new() - } else if parent_module.and_then(|parent| find_nearest_parent_module(tcx, parent)) - == Some(vis_did) - { - "pub(super) ".to_owned() - } else { - format!("pub(in {}) ", tcx.def_path_str(vis_did)) - } +/// This function is the same as print_with_space, except that it renders no links. +/// It's used for macros' rendered source view, which is syntax highlighted and cannot have +/// any HTML in it. +pub(crate) fn visibility_to_src_with_space<'a, 'tcx: 'a>( + visibility: Option<ty::Visibility<DefId>>, + tcx: TyCtxt<'tcx>, + item_did: DefId, +) -> impl fmt::Display + 'a + Captures<'tcx> { + let to_print = match visibility { + None => String::new(), + Some(ty::Visibility::Public) => "pub ".to_owned(), + Some(ty::Visibility::Restricted(vis_did)) => { + // FIXME(camelid): This may not work correctly if `item_did` is a module. + // However, rustdoc currently never displays a module's + // visibility, so it shouldn't matter. + let parent_module = find_nearest_parent_module(tcx, item_did); + + if vis_did.is_crate_root() { + "pub(crate) ".to_owned() + } else if parent_module == Some(vis_did) { + // `pub(in foo)` where `foo` is the parent module + // is the same as no visibility modifier + String::new() + } else if parent_module.and_then(|parent| find_nearest_parent_module(tcx, parent)) + == Some(vis_did) + { + "pub(super) ".to_owned() + } else { + format!("pub(in {}) ", tcx.def_path_str(vis_did)) } - }; - display_fn(move |f| f.write_str(&to_print)) - } + } + }; + display_fn(move |f| f.write_str(&to_print)) } pub(crate) trait PrintWithSpace { diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 28136cc48d6..cd8c8c463b1 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -362,7 +362,7 @@ impl Class { match self { Class::Comment => "comment", Class::DocComment => "doccomment", - Class::Attribute => "attribute", + Class::Attribute => "attr", Class::KeyWord => "kw", Class::RefKeyWord => "kw-2", Class::Self_(_) => "self", diff --git a/src/librustdoc/html/highlight/fixtures/sample.html b/src/librustdoc/html/highlight/fixtures/sample.html index 4a5a3cf609c..fced2eacd9e 100644 --- a/src/librustdoc/html/highlight/fixtures/sample.html +++ b/src/librustdoc/html/highlight/fixtures/sample.html @@ -3,16 +3,16 @@ .kw { color: #8959A8; } .kw-2, .prelude-ty { color: #4271AE; } .number, .string { color: #718C00; } -.self, .bool-val, .prelude-val, .attribute, .attribute .ident { color: #C82829; } +.self, .bool-val, .prelude-val, .attr, .attr .ident { color: #C82829; } .macro, .macro-nonterminal { color: #3E999F; } .lifetime { color: #B76514; } .question-mark { color: #ff9011; } </style> -<pre><code><span class="attribute">#![crate_type = <span class="string">"lib"</span>] +<pre><code><span class="attr">#![crate_type = <span class="string">"lib"</span>] </span><span class="kw">use </span>std::path::{Path, PathBuf}; -<span class="attribute">#[cfg(target_os = <span class="string">"linux"</span>)] +<span class="attr">#[cfg(target_os = <span class="string">"linux"</span>)] #[cfg(target_os = <span class="string">"windows"</span>)] </span><span class="kw">fn </span>main() -> () { <span class="kw">let </span>foo = <span class="bool-val">true </span>&& <span class="bool-val">false </span>|| <span class="bool-val">true</span>; @@ -23,7 +23,7 @@ <span class="macro">mac!</span>(foo, <span class="kw-2">&mut </span>bar); <span class="macro">assert!</span>(<span class="self">self</span>.length < N && index <= <span class="self">self</span>.length); ::std::env::var(<span class="string">"gateau"</span>).is_ok(); - <span class="attribute">#[rustfmt::skip] + <span class="attr">#[rustfmt::skip] </span><span class="kw">let </span>s:std::path::PathBuf = std::path::PathBuf::new(); <span class="kw">let </span><span class="kw-2">mut </span>s = String::new(); diff --git a/src/librustdoc/html/highlight/tests.rs b/src/librustdoc/html/highlight/tests.rs index a5e633df434..2c93b9a097f 100644 --- a/src/librustdoc/html/highlight/tests.rs +++ b/src/librustdoc/html/highlight/tests.rs @@ -9,7 +9,7 @@ const STYLE: &str = r#" .kw { color: #8959A8; } .kw-2, .prelude-ty { color: #4271AE; } .number, .string { color: #718C00; } -.self, .bool-val, .prelude-val, .attribute, .attribute .ident { color: #C82829; } +.self, .bool-val, .prelude-val, .attr, .attr .ident { color: #C82829; } .macro, .macro-nonterminal { color: #3E999F; } .lifetime { color: #B76514; } .question-mark { color: #ff9011; } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 27dea8ec0b3..3a041ae15d6 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -70,8 +70,8 @@ use crate::formats::{AssocItemRender, Impl, RenderMode}; use crate::html::escape::Escape; use crate::html::format::{ href, join_with_double_colon, print_abi_with_space, print_constness_with_space, - print_default_space, print_generic_bounds, print_where_clause, Buffer, Ending, HrefError, - PrintWithSpace, + print_default_space, print_generic_bounds, print_where_clause, visibility_print_with_space, + Buffer, Ending, HrefError, PrintWithSpace, }; use crate::html::highlight; use crate::html::markdown::{ @@ -747,11 +747,12 @@ fn assoc_const( extra: &str, cx: &Context<'_>, ) { + let tcx = cx.tcx(); write!( w, "{extra}{vis}const <a{href} class=\"constant\">{name}</a>: {ty}", extra = extra, - vis = it.visibility.print_with_space(it.item_id, cx), + vis = visibility_print_with_space(it.visibility(tcx), it.item_id, cx), href = assoc_href_attr(it, link, cx), name = it.name.as_ref().unwrap(), ty = ty.print(cx), @@ -764,7 +765,7 @@ fn assoc_const( // This hurts readability in this context especially when more complex expressions // are involved and it doesn't add much of value. // Find a way to print constants here without all that jazz. - write!(w, "{}", Escape(&default.value(cx.tcx()).unwrap_or_else(|| default.expr(cx.tcx())))); + write!(w, "{}", Escape(&default.value(tcx).unwrap_or_else(|| default.expr(tcx)))); } } @@ -805,14 +806,15 @@ fn assoc_method( cx: &Context<'_>, render_mode: RenderMode, ) { - let header = meth.fn_header(cx.tcx()).expect("Trying to get header from a non-function item"); + let tcx = cx.tcx(); + let header = meth.fn_header(tcx).expect("Trying to get header from a non-function item"); let name = meth.name.as_ref().unwrap(); - let vis = meth.visibility.print_with_space(meth.item_id, cx).to_string(); + let vis = visibility_print_with_space(meth.visibility(tcx), meth.item_id, cx).to_string(); // FIXME: Once https://github.com/rust-lang/rust/issues/67792 is implemented, we can remove // this condition. let constness = match render_mode { RenderMode::Normal => { - print_constness_with_space(&header.constness, meth.const_stability(cx.tcx())) + print_constness_with_space(&header.constness, meth.const_stability(tcx)) } RenderMode::ForDeref { .. } => "", }; diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 6327817364a..3225ddabe2e 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -7,7 +7,7 @@ use rustc_hir::def_id::DefId; use rustc_middle::middle::stability; use rustc_middle::span_bug; use rustc_middle::ty::layout::LayoutError; -use rustc_middle::ty::{Adt, TyCtxt}; +use rustc_middle::ty::{self, Adt, TyCtxt}; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_target::abi::{Layout, Primitive, TagEncoding, Variants}; @@ -28,7 +28,7 @@ use crate::formats::{AssocItemRender, Impl, RenderMode}; use crate::html::escape::Escape; use crate::html::format::{ join_with_double_colon, print_abi_with_space, print_constness_with_space, print_where_clause, - Buffer, Ending, PrintWithSpace, + visibility_print_with_space, Buffer, Ending, PrintWithSpace, }; use crate::html::highlight; use crate::html::layout::Page; @@ -318,6 +318,7 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: ); } + let tcx = cx.tcx(); match *myitem.kind { clean::ExternCrateItem { ref src } => { use crate::html::format::anchor; @@ -327,14 +328,14 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: Some(src) => write!( w, "<div class=\"item-left\"><code>{}extern crate {} as {};", - myitem.visibility.print_with_space(myitem.item_id, cx), + visibility_print_with_space(myitem.visibility(tcx), myitem.item_id, cx), anchor(myitem.item_id.expect_def_id(), src, cx), myitem.name.unwrap(), ), None => write!( w, "<div class=\"item-left\"><code>{}extern crate {};", - myitem.visibility.print_with_space(myitem.item_id, cx), + visibility_print_with_space(myitem.visibility(tcx), myitem.item_id, cx), anchor(myitem.item_id.expect_def_id(), myitem.name.unwrap(), cx), ), } @@ -384,7 +385,7 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: </div>\ {stab_tags_before}{stab_tags}{stab_tags_after}", stab = stab.unwrap_or_default(), - vis = myitem.visibility.print_with_space(myitem.item_id, cx), + vis = visibility_print_with_space(myitem.visibility(tcx), myitem.item_id, cx), imp = import.print(cx), ); w.write_str(ITEM_TABLE_ROW_CLOSE); @@ -408,8 +409,8 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: let stab = myitem.stability_class(cx.tcx()); let add = if stab.is_some() { " " } else { "" }; - let visibility_emoji = match myitem.visibility { - clean::Visibility::Restricted(_) => { + let visibility_emoji = match myitem.visibility(tcx) { + Some(ty::Visibility::Restricted(_)) => { "<span title=\"Restricted Visibility\"> ๐</span> " } _ => "", @@ -496,12 +497,13 @@ fn extra_info_tags(item: &clean::Item, parent: &clean::Item, tcx: TyCtxt<'_>) -> } fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &clean::Function) { - let header = it.fn_header(cx.tcx()).expect("printing a function which isn't a function"); - let constness = print_constness_with_space(&header.constness, it.const_stability(cx.tcx())); + let tcx = cx.tcx(); + let header = it.fn_header(tcx).expect("printing a function which isn't a function"); + let constness = print_constness_with_space(&header.constness, it.const_stability(tcx)); let unsafety = header.unsafety.print_with_space(); let abi = print_abi_with_space(header.abi).to_string(); let asyncness = header.asyncness.print_with_space(); - let visibility = it.visibility.print_with_space(it.item_id, cx).to_string(); + let visibility = visibility_print_with_space(it.visibility(tcx), it.item_id, cx).to_string(); let name = it.name.unwrap(); let generics_len = format!("{:#}", f.generics.print(cx)).len(); @@ -539,6 +541,7 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &cle } fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::Trait) { + let tcx = cx.tcx(); let bounds = bounds(&t.bounds, false, cx); let required_types = t.items.iter().filter(|m| m.is_ty_associated_type()).collect::<Vec<_>>(); let provided_types = t.items.iter().filter(|m| m.is_associated_type()).collect::<Vec<_>>(); @@ -549,8 +552,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: let count_types = required_types.len() + provided_types.len(); let count_consts = required_consts.len() + provided_consts.len(); let count_methods = required_methods.len() + provided_methods.len(); - let must_implement_one_of_functions = - cx.tcx().trait_def(t.def_id).must_implement_one_of.clone(); + let must_implement_one_of_functions = tcx.trait_def(t.def_id).must_implement_one_of.clone(); // Output the trait definition wrap_into_item_decl(w, |w| { @@ -559,9 +561,9 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: write!( w, "{}{}{}trait {}{}{}", - it.visibility.print_with_space(it.item_id, cx), - t.unsafety(cx.tcx()).print_with_space(), - if t.is_auto(cx.tcx()) { "auto " } else { "" }, + visibility_print_with_space(it.visibility(tcx), it.item_id, cx), + t.unsafety(tcx).print_with_space(), + if t.is_auto(tcx) { "auto " } else { "" }, it.name.unwrap(), t.generics.print(cx), bounds @@ -1020,7 +1022,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: } let extern_crates = extern_crates .into_iter() - .map(|cnum| cx.shared.tcx.crate_name(cnum).to_string()) + .map(|cnum| tcx.crate_name(cnum).to_string()) .collect::<Vec<_>>() .join(","); let (extern_before, extern_after) = @@ -1084,7 +1086,7 @@ fn item_typedef(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clea fn write_content(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Typedef) { wrap_item(w, "typedef", |w| { render_attributes_in_pre(w, it, ""); - write!(w, "{}", it.visibility.print_with_space(it.item_id, cx)); + write!(w, "{}", visibility_print_with_space(it.visibility(cx.tcx()), it.item_id, cx)); write!( w, "type {}{}{where_clause} = {type_};", @@ -1173,6 +1175,7 @@ fn print_tuple_struct_fields(w: &mut Buffer, cx: &Context<'_>, s: &[clean::Item] } 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_into_item_decl(w, |w| { wrap_item(w, "enum", |w| { @@ -1180,7 +1183,7 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean:: write!( w, "{}enum {}{}", - it.visibility.print_with_space(it.item_id, cx), + visibility_print_with_space(it.visibility(tcx), it.item_id, cx), it.name.unwrap(), e.generics.print(cx), ); @@ -1268,10 +1271,10 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean:: w.write_str("</code>"); render_stability_since_raw( w, - variant.stable_since(cx.tcx()), - variant.const_stability(cx.tcx()), - it.stable_since(cx.tcx()), - it.const_stable_since(cx.tcx()), + variant.stable_since(tcx), + variant.const_stability(tcx), + it.stable_since(tcx), + it.const_stable_since(tcx), ); w.write_str("</h3>"); @@ -1389,12 +1392,13 @@ fn item_primitive(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) { fn item_constant(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, c: &clean::Constant) { wrap_into_item_decl(w, |w| { wrap_item(w, "const", |w| { + let tcx = cx.tcx(); render_attributes_in_code(w, it); write!( w, "{vis}const {name}: {typ}", - vis = it.visibility.print_with_space(it.item_id, cx), + vis = visibility_print_with_space(it.visibility(tcx), it.item_id, cx), name = it.name.unwrap(), typ = c.type_.print(cx), ); @@ -1408,9 +1412,9 @@ fn item_constant(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, c: &cle // ` = 100i32;` // instead? - let value = c.value(cx.tcx()); - let is_literal = c.is_literal(cx.tcx()); - let expr = c.expr(cx.tcx()); + let value = c.value(tcx); + let is_literal = c.is_literal(tcx); + let expr = c.expr(tcx); if value.is_some() || is_literal { write!(w, " = {expr};", expr = Escape(&expr)); } else { @@ -1495,7 +1499,7 @@ fn item_static(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean write!( w, "{vis}static {mutability}{name}: {typ}", - vis = it.visibility.print_with_space(it.item_id, cx), + vis = visibility_print_with_space(it.visibility(cx.tcx()), it.item_id, cx), mutability = s.mutability.print_with_space(), name = it.name.unwrap(), typ = s.type_.print(cx) @@ -1513,7 +1517,7 @@ fn item_foreign_type(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) { write!( w, " {}type {};\n}}", - it.visibility.print_with_space(it.item_id, cx), + visibility_print_with_space(it.visibility(cx.tcx()), it.item_id, cx), it.name.unwrap(), ); }); @@ -1666,7 +1670,13 @@ fn render_union( tab: &str, cx: &Context<'_>, ) { - write!(w, "{}union {}", it.visibility.print_with_space(it.item_id, cx), it.name.unwrap(),); + let tcx = cx.tcx(); + write!( + w, + "{}union {}", + visibility_print_with_space(it.visibility(tcx), it.item_id, cx), + it.name.unwrap(), + ); let where_displayed = g .map(|g| { @@ -1693,7 +1703,7 @@ fn render_union( write!( w, " {}{}: {},\n{}", - field.visibility.print_with_space(field.item_id, cx), + visibility_print_with_space(field.visibility(tcx), field.item_id, cx), field.name.unwrap(), ty.print(cx), tab @@ -1720,10 +1730,11 @@ fn render_struct( structhead: bool, cx: &Context<'_>, ) { + let tcx = cx.tcx(); write!( w, "{}{}{}", - it.visibility.print_with_space(it.item_id, cx), + visibility_print_with_space(it.visibility(tcx), it.item_id, cx), if structhead { "struct " } else { "" }, it.name.unwrap() ); @@ -1753,7 +1764,7 @@ fn render_struct( w, "\n{} {}{}: {},", tab, - field.visibility.print_with_space(field.item_id, cx), + visibility_print_with_space(field.visibility(tcx), field.item_id, cx), field.name.unwrap(), ty.print(cx), ); @@ -1785,7 +1796,7 @@ fn render_struct( write!( w, "{}{}", - field.visibility.print_with_space(field.item_id, cx), + visibility_print_with_space(field.visibility(tcx), field.item_id, cx), ty.print(cx), ) } diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 330bdb45465..7c0dab1c527 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -163,9 +163,6 @@ h1.fqn { padding-bottom: 6px; margin-bottom: 15px; } -#toggle-all-docs { - text-decoration: none; -} /* The only headings that get underlines are: Markdown-generated headings within the top-doc Rustdoc-generated h2 section headings (e.g. "Implementations", "Required Methods", etc) @@ -209,7 +206,7 @@ ul.all-items { font-family: "Fira Sans", Arial, NanumBarunGothic, sans-serif; } -a#toggle-all-docs, +#toggle-all-docs, a.anchor, .small-section-header a, #source-sidebar a, @@ -299,6 +296,16 @@ button { padding: 1px 6px; } +button#toggle-all-docs { + padding: 0; + background: none; + border: none; + cursor: pointer; + /* iOS button gradient: https://stackoverflow.com/q/5438567 */ + -webkit-appearance: none; + opacity: 1; +} + /* end tweaks for normalize.css 8 */ .rustdoc { @@ -670,7 +677,6 @@ pre, .rustdoc.source .example-wrap { } #main-content > .item-info { - margin-top: 0; margin-left: 0; } @@ -869,40 +875,30 @@ so that we can apply CSS-filters to change the arrow color in themes */ .search-results { display: none; - padding-bottom: 2em; } .search-results.active { display: block; - /* prevent overhanging tabs from moving the first result */ - clear: both; -} - -.search-results .desc > span { - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; - display: block; } .search-results > a { - display: block; + display: flex; /* A little margin ensures the browser's outlining of focused links has room to display. */ margin-left: 2px; margin-right: 2px; - border-bottom: 1px solid #aaa3; + border-bottom: 1px solid var(--border-color); + gap: 1em; } .search-results > a > div { - display: flex; - flex-flow: row wrap; + flex: 1; } -.search-results .result-name, .search-results div.desc { - width: 50%; -} -.search-results .result-name { - padding-right: 1em; +.search-results > a > div.desc { + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + display: block; } .search-results a:hover, @@ -1086,7 +1082,7 @@ pre.rust .bool-val { pre.rust .self { color: var(--code-highlight-self-color); } -pre.rust .attribute { +pre.rust .attr { color: var(--code-highlight-attribute-color); } pre.rust .macro, @@ -1673,7 +1669,6 @@ in storage.js } .rustdoc { - padding-top: 0px; /* Sidebar should overlay main content, rather than pushing main content to the right. Turn off `display: flex` on the body element. */ display: block; @@ -1793,7 +1788,6 @@ in storage.js .sidebar-elems { margin-top: 1em; - background-color: var(--sidebar-background-color); } .content { @@ -1866,26 +1860,16 @@ in storage.js } /* Display an alternating layout on tablets and phones */ - .item-table { + .item-table, .item-row, .item-left, .item-right, + .search-results > a, .search-results > a > div { display: block; } - .item-row { - display: flex; - flex-flow: column wrap; - } - .item-left, .item-right { - width: 100%; - } /* Display an alternating layout on tablets and phones */ .search-results > a { - border-bottom: 1px solid #aaa9; padding: 5px 0px; } - .search-results .result-name, .search-results div.desc { - width: 100%; - } - .search-results div.desc, .item-right { + .search-results > a > div.desc, .item-right { padding-left: 2em; } @@ -1962,24 +1946,26 @@ in storage.js } } -.method-toggle > summary, .implementors-toggle > summary, .impl, #implementors-list > .docblock, .impl-items > section, -.methods > section +.impl-items > .rustdoc-toggle > summary, +.methods > section, +.methods > .rustdoc-toggle > summary { margin-bottom: 0.75em; } -.method-toggle[open]:not(:last-child), +.impl-items > .rustdoc-toggle[open]:not(:last-child), +.methods > .rustdoc-toggle[open]:not(:last-child), .implementors-toggle[open]:not(:last-child) { margin-bottom: 2em; } -#trait-implementations-list .method-toggle:not(:last-child), -#synthetic-implementations-list .method-toggle:not(:last-child), -#blanket-implementations-list .method-toggle:not(:last-child) { +#trait-implementations-list .impl-items > .rustdoc-toggle:not(:last-child), +#synthetic-implementations-list .impl-items > .rustdoc-toggle:not(:last-child), +#blanket-implementations-list .impl-items > .rustdoc-toggle:not(:last-child) { margin-bottom: 1em; } diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index d04ec357c40..dd0531c5e70 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -1593,7 +1593,6 @@ function initSearch(rawSearchIndex) { link.className = "result-" + type; link.href = item.href; - const wrapper = document.createElement("div"); const resultName = document.createElement("div"); resultName.className = "result-name"; @@ -1614,16 +1613,13 @@ function initSearch(rawSearchIndex) { resultName.insertAdjacentHTML( "beforeend", item.displayPath + "<span class=\"" + type + "\">" + name + extra + "</span>"); - wrapper.appendChild(resultName); + link.appendChild(resultName); const description = document.createElement("div"); description.className = "desc"; - const spanDesc = document.createElement("span"); - spanDesc.insertAdjacentHTML("beforeend", item.desc); + description.insertAdjacentHTML("beforeend", item.desc); - description.appendChild(spanDesc); - wrapper.appendChild(description); - link.appendChild(wrapper); + link.appendChild(description); output.appendChild(link); }); } else if (query.error === null) { diff --git a/src/librustdoc/html/templates/print_item.html b/src/librustdoc/html/templates/print_item.html index b6ce3ea3dee..e497b619366 100644 --- a/src/librustdoc/html/templates/print_item.html +++ b/src/librustdoc/html/templates/print_item.html @@ -21,8 +21,8 @@ <a class="srclink" href="{{href|safe}}">source</a> ยท {# -#} {%- else -%} {%- endmatch -%} - <a id="toggle-all-docs" href="javascript:void(0)" title="collapse all docs"> {#- -#} - [<span class="inner">−</span>] {#- -#} - </a> {#- -#} + <button id="toggle-all-docs" title="collapse all docs"> {#- -#} + [<span>−</span>] {#- -#} + </button> {#- -#} </span> {#- -#} </div> {#- -#} diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index cdf59cdd328..cb8b7c18029 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -48,7 +48,8 @@ impl JsonRenderer<'_> { .map(rustc_ast_pretty::pprust::attribute_to_string) .collect(); let span = item.span(self.tcx); - let clean::Item { name, attrs: _, kind: _, visibility, item_id, cfg: _ } = item; + let visibility = item.visibility(self.tcx); + let clean::Item { name, attrs: _, kind: _, item_id, cfg: _, .. } = item; let inner = match *item.kind { clean::KeywordItem => return None, clean::StrippedItem(ref inner) => { @@ -99,13 +100,12 @@ impl JsonRenderer<'_> { } } - fn convert_visibility(&self, v: clean::Visibility) -> Visibility { - use clean::Visibility::*; + fn convert_visibility(&self, v: Option<ty::Visibility<DefId>>) -> Visibility { match v { - Public => Visibility::Public, - Inherited => Visibility::Default, - Restricted(did) if did.is_crate_root() => Visibility::Crate, - Restricted(did) => Visibility::Restricted { + None => Visibility::Default, + Some(ty::Visibility::Public) => Visibility::Public, + Some(ty::Visibility::Restricted(did)) if did.is_crate_root() => Visibility::Crate, + Some(ty::Visibility::Restricted(did)) => Visibility::Restricted { parent: from_item_id(did.into(), self.tcx), path: self.tcx.def_path(did).to_string_no_crate_verbose(), }, @@ -283,7 +283,7 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum { ItemEnum::AssocConst { type_: ty.into_tcx(tcx), default: Some(default.expr(tcx)) } } TyAssocTypeItem(g, b) => ItemEnum::AssocType { - generics: (*g).into_tcx(tcx), + generics: g.into_tcx(tcx), bounds: b.into_tcx(tcx), default: None, }, diff --git a/src/librustdoc/passes/check_doc_test_visibility.rs b/src/librustdoc/passes/check_doc_test_visibility.rs index 7740c6d5bbb..057d2fdd9d5 100644 --- a/src/librustdoc/passes/check_doc_test_visibility.rs +++ b/src/librustdoc/passes/check_doc_test_visibility.rs @@ -56,7 +56,7 @@ impl crate::doctest::Tester for Tests { } pub(crate) fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -> bool { - if !cx.cache.effective_visibilities.is_directly_public(item.item_id.expect_def_id()) + if !cx.cache.effective_visibilities.is_directly_public(cx.tcx, item.item_id.expect_def_id()) || matches!( *item.kind, clean::StructFieldItem(_) @@ -130,7 +130,7 @@ pub(crate) fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item ); } } else if tests.found_tests > 0 - && !cx.cache.effective_visibilities.is_exported(item.item_id.expect_def_id()) + && !cx.cache.effective_visibilities.is_exported(cx.tcx, item.item_id.expect_def_id()) { cx.tcx.struct_span_lint_hir( crate::lint::PRIVATE_DOC_TESTS, diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 8aa0abd369c..0bd0dbbeb70 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -1893,7 +1893,7 @@ fn disambiguator_error( diag_info.link_range = disambiguator_range; report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, &diag_info, |diag, _sp| { let msg = format!( - "see {}/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators", + "see {}/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators", crate::DOC_RUST_LANG_ORG_CHANNEL ); diag.note(&msg); diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs index 9914edf3036..e07a788a72a 100644 --- a/src/librustdoc/passes/strip_hidden.rs +++ b/src/librustdoc/passes/strip_hidden.rs @@ -27,6 +27,7 @@ pub(crate) fn strip_hidden(krate: clean::Crate, cx: &mut DocContext<'_>) -> clea // strip all impls referencing stripped items let mut stripper = ImplStripper { + tcx: cx.tcx, retained: &retained, cache: &cx.cache, is_json_output, diff --git a/src/librustdoc/passes/strip_priv_imports.rs b/src/librustdoc/passes/strip_priv_imports.rs index 85be8fa109a..3bac5a8e5d7 100644 --- a/src/librustdoc/passes/strip_priv_imports.rs +++ b/src/librustdoc/passes/strip_priv_imports.rs @@ -11,6 +11,6 @@ pub(crate) const STRIP_PRIV_IMPORTS: Pass = Pass { description: "strips all private import statements (`use`, `extern crate`) from a crate", }; -pub(crate) fn strip_priv_imports(krate: clean::Crate, _: &mut DocContext<'_>) -> clean::Crate { - ImportStripper.fold_crate(krate) +pub(crate) fn strip_priv_imports(krate: clean::Crate, cx: &mut DocContext<'_>) -> clean::Crate { + ImportStripper { tcx: cx.tcx }.fold_crate(krate) } diff --git a/src/librustdoc/passes/strip_private.rs b/src/librustdoc/passes/strip_private.rs index 450f69e15d1..8fc42462de9 100644 --- a/src/librustdoc/passes/strip_private.rs +++ b/src/librustdoc/passes/strip_private.rs @@ -26,12 +26,14 @@ pub(crate) fn strip_private(mut krate: clean::Crate, cx: &mut DocContext<'_>) -> effective_visibilities: &cx.cache.effective_visibilities, update_retained: true, is_json_output, + tcx: cx.tcx, }; - krate = ImportStripper.fold_crate(stripper.fold_crate(krate)); + krate = ImportStripper { tcx: cx.tcx }.fold_crate(stripper.fold_crate(krate)); } // strip all impls referencing private items let mut stripper = ImplStripper { + tcx: cx.tcx, retained: &retained, cache: &cx.cache, is_json_output, diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs index 0089ce63d07..995fb5dcc1c 100644 --- a/src/librustdoc/passes/stripper.rs +++ b/src/librustdoc/passes/stripper.rs @@ -1,19 +1,20 @@ //! A collection of utility functions for the `strip_*` passes. use rustc_hir::def_id::DefId; -use rustc_middle::middle::privacy::EffectiveVisibilities; +use rustc_middle::ty::{TyCtxt, Visibility}; use rustc_span::symbol::sym; - use std::mem; use crate::clean::{self, Item, ItemId, ItemIdSet, NestedAttributesExt}; use crate::fold::{strip_item, DocFolder}; use crate::formats::cache::Cache; +use crate::visit_lib::RustdocEffectiveVisibilities; -pub(crate) struct Stripper<'a> { +pub(crate) struct Stripper<'a, 'tcx> { pub(crate) retained: &'a mut ItemIdSet, - pub(crate) effective_visibilities: &'a EffectiveVisibilities<DefId>, + pub(crate) effective_visibilities: &'a RustdocEffectiveVisibilities, pub(crate) update_retained: bool, pub(crate) is_json_output: bool, + pub(crate) tcx: TyCtxt<'tcx>, } // We need to handle this differently for the JSON output because some non exported items could @@ -21,18 +22,19 @@ pub(crate) struct Stripper<'a> { // are in the public API, which is not enough. #[inline] fn is_item_reachable( + tcx: TyCtxt<'_>, is_json_output: bool, - effective_visibilities: &EffectiveVisibilities<DefId>, + effective_visibilities: &RustdocEffectiveVisibilities, item_id: ItemId, ) -> bool { if is_json_output { - effective_visibilities.is_reachable(item_id.expect_def_id()) + effective_visibilities.is_reachable(tcx, item_id.expect_def_id()) } else { - effective_visibilities.is_exported(item_id.expect_def_id()) + effective_visibilities.is_exported(tcx, item_id.expect_def_id()) } } -impl<'a> DocFolder for Stripper<'a> { +impl<'a, 'tcx> DocFolder for Stripper<'a, 'tcx> { fn fold_item(&mut self, i: Item) -> Option<Item> { match *i.kind { clean::StrippedItem(..) => { @@ -66,7 +68,12 @@ impl<'a> DocFolder for Stripper<'a> { | clean::ForeignTypeItem => { let item_id = i.item_id; if item_id.is_local() - && !is_item_reachable(self.is_json_output, self.effective_visibilities, item_id) + && !is_item_reachable( + self.tcx, + self.is_json_output, + self.effective_visibilities, + item_id, + ) { debug!("Stripper: stripping {:?} {:?}", i.type_(), i.name); return None; @@ -74,13 +81,13 @@ impl<'a> DocFolder for Stripper<'a> { } clean::StructFieldItem(..) => { - if !i.visibility.is_public() { + if i.visibility(self.tcx) != Some(Visibility::Public) { return Some(strip_item(i)); } } clean::ModuleItem(..) => { - if i.item_id.is_local() && !i.visibility.is_public() { + if i.item_id.is_local() && i.visibility(self.tcx) != Some(Visibility::Public) { debug!("Stripper: stripping module {:?}", i.name); let old = mem::replace(&mut self.update_retained, false); let ret = strip_item(self.fold_item_recur(i)); @@ -146,14 +153,15 @@ impl<'a> DocFolder for Stripper<'a> { } /// This stripper discards all impls which reference stripped items -pub(crate) struct ImplStripper<'a> { +pub(crate) struct ImplStripper<'a, 'tcx> { + pub(crate) tcx: TyCtxt<'tcx>, pub(crate) retained: &'a ItemIdSet, pub(crate) cache: &'a Cache, pub(crate) is_json_output: bool, pub(crate) document_private: bool, } -impl<'a> ImplStripper<'a> { +impl<'a> ImplStripper<'a, '_> { #[inline] fn should_keep_impl(&self, item: &Item, for_def_id: DefId) -> bool { if !for_def_id.is_local() || self.retained.contains(&for_def_id.into()) { @@ -161,7 +169,7 @@ impl<'a> ImplStripper<'a> { } else if self.is_json_output { // If the "for" item is exported and the impl block isn't `#[doc(hidden)]`, then we // need to keep it. - self.cache.effective_visibilities.is_exported(for_def_id) + self.cache.effective_visibilities.is_exported(self.tcx, for_def_id) && !item.attrs.lists(sym::doc).has_word(sym::hidden) } else { false @@ -169,7 +177,7 @@ impl<'a> ImplStripper<'a> { } } -impl<'a> DocFolder for ImplStripper<'a> { +impl<'a> DocFolder for ImplStripper<'a, '_> { fn fold_item(&mut self, i: Item) -> Option<Item> { if let clean::ImplItem(ref imp) = *i.kind { // Impl blocks can be skipped if they are: empty; not a trait impl; and have no @@ -185,6 +193,7 @@ impl<'a> DocFolder for ImplStripper<'a> { let item_id = i.item_id; item_id.is_local() && !is_item_reachable( + self.tcx, self.is_json_output, &self.cache.effective_visibilities, item_id, @@ -229,12 +238,16 @@ impl<'a> DocFolder for ImplStripper<'a> { } /// This stripper discards all private import statements (`use`, `extern crate`) -pub(crate) struct ImportStripper; +pub(crate) struct ImportStripper<'tcx> { + pub(crate) tcx: TyCtxt<'tcx>, +} -impl DocFolder for ImportStripper { +impl<'tcx> DocFolder for ImportStripper<'tcx> { fn fold_item(&mut self, i: Item) -> Option<Item> { match *i.kind { - clean::ExternCrateItem { .. } | clean::ImportItem(..) if !i.visibility.is_public() => { + clean::ExternCrateItem { .. } | clean::ImportItem(..) + if i.visibility(self.tcx) != Some(Visibility::Public) => + { None } _ => Some(self.fold_item_recur(i)), diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 06dffce555f..c788b9f4093 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -7,15 +7,14 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::Node; use rustc_hir::CRATE_HIR_ID; -use rustc_middle::middle::privacy::Level; -use rustc_middle::ty::{TyCtxt, Visibility}; +use rustc_middle::ty::TyCtxt; use rustc_span::def_id::{CRATE_DEF_ID, LOCAL_CRATE}; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; use std::mem; -use crate::clean::{self, cfg::Cfg, AttributesExt, NestedAttributesExt}; +use crate::clean::{cfg::Cfg, AttributesExt, NestedAttributesExt}; use crate::core; /// This module is used to store stuff from Rust's AST in a more convenient @@ -26,8 +25,8 @@ pub(crate) struct Module<'hir> { pub(crate) where_inner: Span, pub(crate) mods: Vec<Module<'hir>>, pub(crate) id: hir::HirId, - // (item, renamed) - pub(crate) items: Vec<(&'hir hir::Item<'hir>, Option<Symbol>)>, + // (item, renamed, import_id) + pub(crate) items: Vec<(&'hir hir::Item<'hir>, Option<Symbol>, Option<hir::HirId>)>, pub(crate) foreigns: Vec<(&'hir hir::ForeignItem<'hir>, Option<Symbol>)>, } @@ -94,6 +93,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { hir::CRATE_HIR_ID, self.cx.tcx.hir().root_module(), self.cx.tcx.crate_name(LOCAL_CRATE), + None, ); // `#[macro_export] macro_rules!` items are reexported at the top level of the @@ -114,7 +114,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { if self.cx.tcx.has_attr(def_id, sym::macro_export) { if inserted.insert(def_id) { let item = self.cx.tcx.hir().expect_item(local_def_id); - top_level_module.items.push((item, None)); + top_level_module.items.push((item, None, None)); } } } @@ -156,6 +156,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { id: hir::HirId, m: &'tcx hir::Mod<'tcx>, name: Symbol, + parent_id: Option<hir::HirId>, ) -> Module<'tcx> { let mut om = Module::new(name, id, m.spans.inner_span); let def_id = self.cx.tcx.hir().local_def_id(id).to_def_id(); @@ -167,7 +168,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { if matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) { continue; } - self.visit_item(item, None, &mut om); + self.visit_item(item, None, &mut om, parent_id); } for &i in m.item_ids { let item = self.cx.tcx.hir().item(i); @@ -175,7 +176,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { // Later passes in rustdoc will de-duplicate by name and kind, so if glob- // imported items appear last, then they'll be the ones that get discarded. if matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) { - self.visit_item(item, None, &mut om); + self.visit_item(item, None, &mut om, parent_id); } } self.inside_public_path = orig_inside_public_path; @@ -221,23 +222,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { // made reachable by cross-crate inlining which we're checking here. // (this is done here because we need to know this upfront). if !res_did.is_local() && !is_no_inline { - let attrs = clean::inline::load_attrs(self.cx, res_did); - let self_is_hidden = attrs.lists(sym::doc).has_word(sym::hidden); - if !self_is_hidden { - if let Res::Def(kind, did) = res { - if kind == DefKind::Mod { - crate::visit_lib::LibEmbargoVisitor::new(self.cx).visit_mod(did) - } else { - // All items need to be handled here in case someone wishes to link - // to them with intra-doc links - self.cx.cache.effective_visibilities.set_public_at_level( - did, - || Visibility::Restricted(CRATE_DEF_ID), - Level::Direct, - ); - } - } - } + crate::visit_lib::lib_embargo_visit_item(self.cx, res_did); return false; } @@ -246,7 +231,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { None => return false, }; - let is_private = !self.cx.cache.effective_visibilities.is_directly_public(res_did); + let is_private = + !self.cx.cache.effective_visibilities.is_directly_public(self.cx.tcx, res_did); let is_hidden = inherits_doc_hidden(self.cx.tcx, res_hir_id); // Only inline if requested or if the item would otherwise be stripped. @@ -263,14 +249,14 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { let prev = mem::replace(&mut self.inlining, true); for &i in m.item_ids { let i = self.cx.tcx.hir().item(i); - self.visit_item(i, None, om); + self.visit_item(i, None, om, Some(id)); } self.inlining = prev; true } Node::Item(it) if !glob => { let prev = mem::replace(&mut self.inlining, true); - self.visit_item(it, renamed, om); + self.visit_item(it, renamed, om, Some(id)); self.inlining = prev; true } @@ -291,6 +277,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { item: &'tcx hir::Item<'_>, renamed: Option<Symbol>, om: &mut Module<'tcx>, + parent_id: Option<hir::HirId>, ) { debug!("visiting item {:?}", item); let name = renamed.unwrap_or(item.ident.name); @@ -346,7 +333,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } } - om.items.push((item, renamed)) + om.items.push((item, renamed, parent_id)) } hir::ItemKind::Macro(ref macro_def, _) => { // `#[macro_export] macro_rules!` items are handled separately in `visit()`, @@ -365,11 +352,11 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { let nonexported = !self.cx.tcx.has_attr(def_id, sym::macro_export); if is_macro_2_0 || nonexported || self.inlining { - om.items.push((item, renamed)); + om.items.push((item, renamed, None)); } } hir::ItemKind::Mod(ref m) => { - om.mods.push(self.visit_mod_contents(item.hir_id(), m, name)); + om.mods.push(self.visit_mod_contents(item.hir_id(), m, name, parent_id)); } hir::ItemKind::Fn(..) | hir::ItemKind::ExternCrate(..) @@ -380,19 +367,19 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { | hir::ItemKind::OpaqueTy(..) | hir::ItemKind::Static(..) | hir::ItemKind::Trait(..) - | hir::ItemKind::TraitAlias(..) => om.items.push((item, renamed)), + | hir::ItemKind::TraitAlias(..) => om.items.push((item, renamed, parent_id)), hir::ItemKind::Const(..) => { // Underscore constants do not correspond to a nameable item and // so are never useful in documentation. if name != kw::Underscore { - om.items.push((item, renamed)); + om.items.push((item, renamed, parent_id)); } } hir::ItemKind::Impl(impl_) => { // Don't duplicate impls when inlining or if it's implementing a trait, we'll pick // them up regardless of where they're located. if !self.inlining && impl_.of_trait.is_none() { - om.items.push((item, None)); + om.items.push((item, None, None)); } } } diff --git a/src/librustdoc/visit_lib.rs b/src/librustdoc/visit_lib.rs index 70214e2adba..e490559b0e9 100644 --- a/src/librustdoc/visit_lib.rs +++ b/src/librustdoc/visit_lib.rs @@ -1,86 +1,74 @@ +use crate::core::DocContext; use rustc_data_structures::fx::FxHashSet; -use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_ID}; -use rustc_middle::middle::privacy::{EffectiveVisibilities, Level}; -use rustc_middle::ty::{TyCtxt, Visibility}; +use rustc_hir::def::DefKind; +use rustc_hir::def_id::DefId; +use rustc_middle::ty::TyCtxt; // FIXME: this may not be exhaustive, but is sufficient for rustdocs current uses +#[derive(Default)] +pub(crate) struct RustdocEffectiveVisibilities { + extern_public: FxHashSet<DefId>, +} + +macro_rules! define_method { + ($method:ident) => { + pub(crate) fn $method(&self, tcx: TyCtxt<'_>, def_id: DefId) -> bool { + match def_id.as_local() { + Some(def_id) => tcx.effective_visibilities(()).$method(def_id), + None => self.extern_public.contains(&def_id), + } + } + }; +} + +impl RustdocEffectiveVisibilities { + define_method!(is_directly_public); + define_method!(is_exported); + define_method!(is_reachable); +} + +pub(crate) fn lib_embargo_visit_item(cx: &mut DocContext<'_>, def_id: DefId) { + assert!(!def_id.is_local()); + LibEmbargoVisitor { + tcx: cx.tcx, + extern_public: &mut cx.cache.effective_visibilities.extern_public, + visited_mods: Default::default(), + } + .visit_item(def_id) +} + /// Similar to `librustc_privacy::EmbargoVisitor`, but also takes /// specific rustdoc annotations into account (i.e., `doc(hidden)`) -pub(crate) struct LibEmbargoVisitor<'a, 'tcx> { +struct LibEmbargoVisitor<'a, 'tcx> { tcx: TyCtxt<'tcx>, // Effective visibilities for reachable nodes - effective_visibilities: &'a mut EffectiveVisibilities<DefId>, - // Previous level, None means unreachable - prev_level: Option<Level>, + extern_public: &'a mut FxHashSet<DefId>, // Keeps track of already visited modules, in case a module re-exports its parent visited_mods: FxHashSet<DefId>, } -impl<'a, 'tcx> LibEmbargoVisitor<'a, 'tcx> { - pub(crate) fn new(cx: &'a mut crate::core::DocContext<'tcx>) -> LibEmbargoVisitor<'a, 'tcx> { - LibEmbargoVisitor { - tcx: cx.tcx, - effective_visibilities: &mut cx.cache.effective_visibilities, - prev_level: Some(Level::Direct), - visited_mods: FxHashSet::default(), - } - } - - pub(crate) fn visit_lib(&mut self, cnum: CrateNum) { - let did = cnum.as_def_id(); - self.update(did, Some(Level::Direct)); - self.visit_mod(did); - } - - // Updates node level and returns the updated level - fn update(&mut self, did: DefId, level: Option<Level>) -> Option<Level> { - let is_hidden = self.tcx.is_doc_hidden(did); - - let old_level = self.effective_visibilities.public_at_level(did); - // Visibility levels can only grow - if level > old_level && !is_hidden { - self.effective_visibilities.set_public_at_level( - did, - || Visibility::Restricted(CRATE_DEF_ID), - level.unwrap(), - ); - level - } else { - old_level - } - } - - pub(crate) fn visit_mod(&mut self, def_id: DefId) { +impl LibEmbargoVisitor<'_, '_> { + fn visit_mod(&mut self, def_id: DefId) { if !self.visited_mods.insert(def_id) { return; } for item in self.tcx.module_children(def_id).iter() { if let Some(def_id) = item.res.opt_def_id() { - if self.tcx.def_key(def_id).parent.map_or(false, |d| d == def_id.index) - || item.vis.is_public() - { - self.visit_item(item.res); + if item.vis.is_public() { + self.visit_item(def_id); } } } } - fn visit_item(&mut self, res: Res<!>) { - let def_id = res.def_id(); - let vis = self.tcx.visibility(def_id); - let inherited_item_level = if vis.is_public() { self.prev_level } else { None }; - - let item_level = self.update(def_id, inherited_item_level); - - if let Res::Def(DefKind::Mod, _) = res { - let orig_level = self.prev_level; - - self.prev_level = item_level; - self.visit_mod(def_id); - self.prev_level = orig_level; + fn visit_item(&mut self, def_id: DefId) { + if !self.tcx.is_doc_hidden(def_id) { + self.extern_public.insert(def_id); + if self.tcx.def_kind(def_id) == DefKind::Mod { + self.visit_mod(def_id); + } } } } |
