Skip to content

Commit 4ad14ac

Browse files
committed
Calculate visibility on-demand, not up-front
- lots of staring really hard at the existing code to make sure the behavior matches - store `inline_stmt_id` and `crate_stmt_id` to be able to get their visibility (rustdoc stores the IDs of the item definition in `clean::Item`, not the re-export)
1 parent 207c80f commit 4ad14ac

File tree

13 files changed

+111
-113
lines changed

13 files changed

+111
-113
lines changed

src/librustdoc/clean/auto_trait.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,6 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
112112
Some(Item {
113113
name: None,
114114
attrs: Default::default(),
115-
visibility: Inherited,
116115
def_id: ItemId::Auto { trait_: trait_def_id, for_: item_def_id },
117116
kind: box ImplItem(Impl {
118117
unsafety: hir::Unsafety::Normal,
@@ -124,6 +123,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
124123
kind: ImplKind::Auto,
125124
}),
126125
cfg: None,
126+
inline_stmt_id: None,
127127
})
128128
}
129129

src/librustdoc/clean/blanket_impl.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,6 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
103103
impls.push(Item {
104104
name: None,
105105
attrs: Default::default(),
106-
visibility: Inherited,
107106
def_id: ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id },
108107
kind: box ImplItem(Impl {
109108
unsafety: hir::Unsafety::Normal,
@@ -127,6 +126,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
127126
kind: ImplKind::Blanket(box trait_ref.self_ty().clean(self.cx)),
128127
}),
129128
cfg: None,
129+
inline_stmt_id: None,
130130
});
131131
}
132132
}

src/librustdoc/clean/inline.rs

+6-20
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use crate::clean::{
2020
use crate::core::DocContext;
2121
use crate::formats::item_type::ItemType;
2222

23-
use super::{Clean, Visibility};
23+
use super::Clean;
2424

2525
type Attrs<'hir> = rustc_middle::ty::Attributes<'hir>;
2626

@@ -125,11 +125,8 @@ crate fn try_inline(
125125
let (attrs, cfg) = merge_attrs(cx, Some(parent_module), load_attrs(cx, did), attrs_clone);
126126
cx.inlined.insert(did.into());
127127
let mut item =
128-
clean::Item::from_def_id_and_attrs_and_parts(did, Some(name), kind, box attrs, cx, cfg);
129-
if let Some(import_def_id) = import_def_id {
130-
// The visibility needs to reflect the one from the reexport and not from the "source" DefId.
131-
item.visibility = cx.tcx.visibility(import_def_id).clean(cx);
132-
}
128+
clean::Item::from_def_id_and_attrs_and_parts(did, Some(name), kind, box attrs, cfg);
129+
item.inline_stmt_id = import_def_id;
133130
ret.push(item);
134131
Some(ret)
135132
}
@@ -194,18 +191,8 @@ crate fn record_extern_fqn(cx: &mut DocContext<'_>, did: DefId, kind: ItemType)
194191
}
195192

196193
crate fn build_external_trait(cx: &mut DocContext<'_>, did: DefId) -> clean::Trait {
197-
let trait_items = cx
198-
.tcx
199-
.associated_items(did)
200-
.in_definition_order()
201-
.map(|item| {
202-
// When building an external trait, the cleaned trait will have all items public,
203-
// which causes methods to have a `pub` prefix, which is invalid since items in traits
204-
// can not have a visibility prefix. Thus we override the visibility here manually.
205-
// See https://github.com/rust-lang/rust/issues/81274
206-
clean::Item { visibility: Visibility::Inherited, ..item.clean(cx) }
207-
})
208-
.collect();
194+
let trait_items =
195+
cx.tcx.associated_items(did).in_definition_order().map(|item| item.clean(cx)).collect();
209196

210197
let predicates = cx.tcx.predicates_of(did);
211198
let generics = (cx.tcx.generics_of(did), predicates).clean(cx);
@@ -497,7 +484,6 @@ crate fn build_impl(
497484
kind: ImplKind::Normal,
498485
}),
499486
box merged_attrs,
500-
cx,
501487
cfg,
502488
));
503489
}
@@ -527,7 +513,6 @@ fn build_module(
527513
name: None,
528514
attrs: box clean::Attributes::default(),
529515
def_id: ItemId::Primitive(prim_ty, did.krate),
530-
visibility: clean::Public,
531516
kind: box clean::ImportItem(clean::Import::new_simple(
532517
item.ident.name,
533518
clean::ImportSource {
@@ -546,6 +531,7 @@ fn build_module(
546531
true,
547532
)),
548533
cfg: None,
534+
inline_stmt_id: None,
549535
});
550536
} else if let Some(i) = try_inline(cx, did, None, res, item.ident.name, None, visited) {
551537
items.extend(i)

src/librustdoc/clean/mod.rs

+20-45
Original file line numberDiff line numberDiff line change
@@ -909,10 +909,7 @@ impl Clean<Item> for hir::TraitItem<'_> {
909909
AssocTypeItem(bounds, default)
910910
}
911911
};
912-
let what_rustc_thinks =
913-
Item::from_def_id_and_parts(local_did, Some(self.ident.name), inner, cx);
914-
// Trait items always inherit the trait's visibility -- we don't want to show `pub`.
915-
Item { visibility: Inherited, ..what_rustc_thinks }
912+
Item::from_def_id_and_parts(local_did, Some(self.ident.name), inner, cx)
916913
})
917914
}
918915
}
@@ -948,20 +945,7 @@ impl Clean<Item> for hir::ImplItem<'_> {
948945
}
949946
};
950947

951-
let what_rustc_thinks =
952-
Item::from_def_id_and_parts(local_did, Some(self.ident.name), inner, cx);
953-
let parent_item = cx.tcx.hir().expect_item(cx.tcx.hir().get_parent_did(self.hir_id()));
954-
if let hir::ItemKind::Impl(impl_) = &parent_item.kind {
955-
if impl_.of_trait.is_some() {
956-
// Trait impl items always inherit the impl's visibility --
957-
// we don't want to show `pub`.
958-
Item { visibility: Inherited, ..what_rustc_thinks }
959-
} else {
960-
what_rustc_thinks
961-
}
962-
} else {
963-
panic!("found impl item with non-impl parent {:?}", parent_item);
964-
}
948+
Item::from_def_id_and_parts(local_did, Some(self.ident.name), inner, cx)
965949
})
966950
}
967951
}
@@ -1570,14 +1554,7 @@ impl Clean<Item> for ty::FieldDef {
15701554
}
15711555

15721556
fn clean_field(def_id: DefId, name: Symbol, ty: Type, cx: &mut DocContext<'_>) -> Item {
1573-
let what_rustc_thinks =
1574-
Item::from_def_id_and_parts(def_id, Some(name), StructFieldItem(ty), cx);
1575-
if is_field_vis_inherited(cx.tcx, def_id) {
1576-
// Variant fields inherit their enum's visibility.
1577-
Item { visibility: Visibility::Inherited, ..what_rustc_thinks }
1578-
} else {
1579-
what_rustc_thinks
1580-
}
1557+
Item::from_def_id_and_parts(def_id, Some(name), StructFieldItem(ty), cx)
15811558
}
15821559

15831560
fn is_field_vis_inherited(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
@@ -1592,17 +1569,21 @@ fn is_field_vis_inherited(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
15921569
}
15931570
}
15941571

1572+
fn clean_vis(vis: ty::Visibility) -> Visibility {
1573+
match vis {
1574+
ty::Visibility::Public => Visibility::Public,
1575+
// NOTE: this is not quite right: `ty` uses `Invisible` to mean 'private',
1576+
// while rustdoc really does mean inherited. That means that for enum variants, such as
1577+
// `pub enum E { V }`, `V` will be marked as `Public` by `ty`, but as `Inherited` by rustdoc.
1578+
// `Item::visibility()` overrides `tcx.visibility` explicitly to make sure this distinction is captured.
1579+
ty::Visibility::Invisible => Visibility::Inherited,
1580+
ty::Visibility::Restricted(module) => Visibility::Restricted(module),
1581+
}
1582+
}
1583+
15951584
impl Clean<Visibility> for ty::Visibility {
15961585
fn clean(&self, _cx: &mut DocContext<'_>) -> Visibility {
1597-
match *self {
1598-
ty::Visibility::Public => Visibility::Public,
1599-
// NOTE: this is not quite right: `ty` uses `Invisible` to mean 'private',
1600-
// while rustdoc really does mean inherited. That means that for enum variants, such as
1601-
// `pub enum E { V }`, `V` will be marked as `Public` by `ty`, but as `Inherited` by rustdoc.
1602-
// Various parts of clean override `tcx.visibility` explicitly to make sure this distinction is captured.
1603-
ty::Visibility::Invisible => Visibility::Inherited,
1604-
ty::Visibility::Restricted(module) => Visibility::Restricted(module),
1605-
}
1586+
clean_vis(*self)
16061587
}
16071588
}
16081589

@@ -1635,10 +1616,7 @@ impl Clean<Item> for ty::VariantDef {
16351616
fields: self.fields.iter().map(|field| field.clean(cx)).collect(),
16361617
}),
16371618
};
1638-
let what_rustc_thinks =
1639-
Item::from_def_id_and_parts(self.def_id, Some(self.ident.name), VariantItem(kind), cx);
1640-
// don't show `pub` for variants, which always inherit visibility
1641-
Item { visibility: Inherited, ..what_rustc_thinks }
1619+
Item::from_def_id_and_parts(self.def_id, Some(self.ident.name), VariantItem(kind), cx)
16421620
}
16431621
}
16441622

@@ -1798,10 +1776,7 @@ impl Clean<Vec<Item>> for (&hir::Item<'_>, Option<Symbol>) {
17981776
impl Clean<Item> for hir::Variant<'_> {
17991777
fn clean(&self, cx: &mut DocContext<'_>) -> Item {
18001778
let kind = VariantItem(self.data.clean(cx));
1801-
let what_rustc_thinks =
1802-
Item::from_hir_id_and_parts(self.id, Some(self.ident.name), kind, cx);
1803-
// don't show `pub` for variants, which are always public
1804-
Item { visibility: Inherited, ..what_rustc_thinks }
1779+
Item::from_hir_id_and_parts(self.id, Some(self.ident.name), kind, cx)
18051780
}
18061781
}
18071782

@@ -1887,9 +1862,9 @@ fn clean_extern_crate(
18871862
name: Some(name),
18881863
attrs: box attrs.clean(cx),
18891864
def_id: crate_def_id.into(),
1890-
visibility: ty_vis.clean(cx),
1891-
kind: box ExternCrateItem { src: orig_name },
1865+
kind: box ExternCrateItem { src: orig_name, crate_stmt_id: krate.def_id },
18921866
cfg: attrs.cfg(cx.tcx, &cx.cache.hidden_cfg),
1867+
inline_stmt_id: None,
18931868
}]
18941869
}
18951870

src/librustdoc/clean/types.rs

+43-14
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
1818
use rustc_data_structures::thin_vec::ThinVec;
1919
use rustc_hir as hir;
2020
use rustc_hir::def::{CtorKind, DefKind, Res};
21-
use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
21+
use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
2222
use rustc_hir::lang_items::LangItem;
2323
use rustc_hir::{BodyId, Mutability};
2424
use rustc_index::vec::IndexVec;
@@ -32,10 +32,10 @@ use rustc_target::abi::VariantIdx;
3232
use rustc_target::spec::abi::Abi;
3333

3434
use crate::clean::cfg::Cfg;
35-
use crate::clean::external_path;
3635
use crate::clean::inline::{self, print_inlined_const};
3736
use crate::clean::utils::{is_literal_expr, print_const_expr, print_evaluated_const};
3837
use crate::clean::Clean;
38+
use crate::clean::{external_path, is_field_vis_inherited};
3939
use crate::core::DocContext;
4040
use crate::formats::cache::Cache;
4141
use crate::formats::item_type::ItemType;
@@ -348,12 +348,12 @@ crate struct Item {
348348
/// Optional because not every item has a name, e.g. impls.
349349
crate name: Option<Symbol>,
350350
crate attrs: Box<Attributes>,
351-
crate visibility: Visibility,
352351
/// Information about this item that is specific to what kind of item it is.
353352
/// E.g., struct vs enum vs function.
354353
crate kind: Box<ItemKind>,
355354
crate def_id: ItemId,
356-
355+
/// If this item was inlined, the DefId of the `use` statement.
356+
crate inline_stmt_id: Option<DefId>,
357357
crate cfg: Option<Arc<Cfg>>,
358358
}
359359

@@ -388,6 +388,42 @@ impl Item {
388388
self.def_id.as_def_id().map(|did| tcx.get_attrs(did).inner_docs()).unwrap_or(false)
389389
}
390390

391+
crate fn visibility(&self, tcx: TyCtxt<'_>) -> Visibility {
392+
let mut def_id = match self.def_id {
393+
// Anything but DefId *shouldn't* matter, but return a reasonable value anyway.
394+
ItemId::Auto { .. } | ItemId::Blanket { .. } => return Visibility::Inherited,
395+
ItemId::Primitive(..) => return Visibility::Public,
396+
ItemId::DefId(did) => did,
397+
};
398+
match *self.kind {
399+
// Variant fields inherit their enum's visibility.
400+
StructFieldItem(..) if is_field_vis_inherited(tcx, def_id) => {
401+
return Visibility::Inherited;
402+
}
403+
// Variants always inherit visibility
404+
VariantItem(..) => return Visibility::Inherited,
405+
// Return the visibility of `extern crate` statement, not the crate itself (which will always be public).
406+
ExternCrateItem { crate_stmt_id, .. } => def_id = crate_stmt_id.to_def_id(),
407+
// Trait items inherit the trait's visibility
408+
AssocConstItem(..) | AssocTypeItem(..) | TyMethodItem(..) | MethodItem(..) => {
409+
let is_trait_item = match tcx.associated_item(def_id).container {
410+
ty::TraitContainer(_) => true,
411+
ty::ImplContainer(impl_id) => tcx.impl_trait_ref(impl_id).is_some(),
412+
};
413+
if is_trait_item {
414+
return Visibility::Inherited;
415+
}
416+
}
417+
_ => {}
418+
}
419+
// If this item was inlined, show the visibility of the `use` statement, not the definition.
420+
let def_id = match self.inline_stmt_id {
421+
Some(inlined) => inlined,
422+
None => def_id,
423+
};
424+
super::clean_vis(tcx.visibility(def_id))
425+
}
426+
391427
crate fn span(&self, tcx: TyCtxt<'_>) -> Span {
392428
let kind = match &*self.kind {
393429
ItemKind::StrippedItem(k) => k,
@@ -443,7 +479,6 @@ impl Item {
443479
name,
444480
kind,
445481
box ast_attrs.clean(cx),
446-
cx,
447482
ast_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg),
448483
)
449484
}
@@ -453,19 +488,11 @@ impl Item {
453488
name: Option<Symbol>,
454489
kind: ItemKind,
455490
attrs: Box<Attributes>,
456-
cx: &mut DocContext<'_>,
457491
cfg: Option<Arc<Cfg>>,
458492
) -> Item {
459493
trace!("name={:?}, def_id={:?}", name, def_id);
460494

461-
Item {
462-
def_id: def_id.into(),
463-
kind: box kind,
464-
name,
465-
attrs,
466-
visibility: cx.tcx.visibility(def_id).clean(cx),
467-
cfg,
468-
}
495+
Item { def_id: def_id.into(), kind: box kind, name, attrs, cfg, inline_stmt_id: None }
469496
}
470497

471498
/// Finds all `doc` attributes as NameValues and returns their corresponding values, joined
@@ -640,6 +667,8 @@ crate enum ItemKind {
640667
ExternCrateItem {
641668
/// The crate's name, *not* the name it's imported as.
642669
src: Option<Symbol>,
670+
/// The id of the `extern crate` statement, not the crate itself.
671+
crate_stmt_id: LocalDefId,
643672
},
644673
ImportItem(Import),
645674
StructItem(Struct),

src/librustdoc/fold.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ crate trait DocFolder: Sized {
6868
}
6969
Variant::CLike => VariantItem(Variant::CLike),
7070
},
71-
ExternCrateItem { src: _ }
71+
ExternCrateItem { .. }
7272
| ImportItem(_)
7373
| FunctionItem(_)
7474
| TypedefItem(_, _)

src/librustdoc/html/render/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -771,7 +771,7 @@ fn assoc_const(
771771
w,
772772
"{}{}const <a href=\"{}\" class=\"constant\">{}</a>: {}",
773773
extra,
774-
it.visibility.print_with_space(it.def_id, cx),
774+
it.visibility(cx.tcx()).print_with_space(it.def_id, cx),
775775
naive_assoc_href(it, link, cx),
776776
it.name.as_ref().unwrap(),
777777
ty.print(cx)
@@ -892,7 +892,7 @@ fn render_assoc_item(
892892
}
893893
}
894894
};
895-
let vis = meth.visibility.print_with_space(meth.def_id, cx).to_string();
895+
let vis = meth.visibility(cx.tcx()).print_with_space(meth.def_id, cx).to_string();
896896
let constness =
897897
print_constness_with_space(&header.constness, meth.const_stability(cx.tcx()));
898898
let asyncness = header.asyncness.print_with_space();

0 commit comments

Comments
 (0)