Skip to content

Commit b3ab695

Browse files
authored
Rollup merge of #133981 - aDotInTheVoid:document-docs-ids, r=fmease
rustdoc-json: Refractor and document Id's Closes#133780 While working on documenting Id's, I realized alot of the way they were generated was weird and unnecessary. Eg: 1. The fully uninterned id type was `(FullItemId, Option<FullItemId>)`, meaning it wasn't actually full! 2. None of the extra fields in `Option<FullItemId>` would ever be used 3. `imported_item_id` was a `rustdoc_json_types::Id` instead of a simpler `DefId`. I believe the new implementation still covers all the same cases, but in a more principled way (and explaining why each piece is needed). This was written to be reviewed commit-by-commit, but it might be easier to review all at once if you're not interested in tracking how the original code became the final code. cc ``@its-the-shrimp`` r? ``@fmease``
2 parents 3b1776d + a05d6ab commit b3ab695

3 files changed

Lines changed: 126 additions & 74 deletions

File tree

‎src/librustdoc/json/conversions.rs‎

Lines changed: 2 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,13 @@
77
use rustc_abi::ExternAbi;
88
use rustc_ast::ast;
99
use rustc_attr_parsing::DeprecatedSince;
10-
use rustc_hir::def::{CtorKind,DefKind};
10+
use rustc_hir::def::CtorKind;
1111
use rustc_hir::def_id::DefId;
1212
use rustc_metadata::rendered_const;
1313
use rustc_middle::{bug, ty};
14-
use rustc_span::{Pos,Symbol, sym};
14+
use rustc_span::{Pos,Symbol};
1515
use rustdoc_json_types::*;
1616

17-
usesuper::FullItemId;
1817
usecrate::clean::{self,ItemId};
1918
usecrate::formats::FormatRenderer;
2019
usecrate::formats::item_type::ItemType;
@@ -108,67 +107,6 @@ impl JsonRenderer<'_> {
108107
}
109108
}
110109

111-
pub(crate)fnid_from_item_default(&self,item_id:ItemId) -> Id{
112-
self.id_from_item_inner(item_id,None,None)
113-
}
114-
115-
pub(crate)fnid_from_item_inner(
116-
&self,
117-
item_id:ItemId,
118-
name:Option<Symbol>,
119-
extra:Option<Id>,
120-
) -> Id{
121-
let make_part = |def_id:DefId,name:Option<Symbol>,extra:Option<Id>| {
122-
let name = match name {
123-
Some(name) => Some(name),
124-
None => {
125-
// We need this workaround because primitive types' DefId actually refers to
126-
// their parent module, which isn't present in the output JSON items. So
127-
// instead, we directly get the primitive symbol
128-
ifmatches!(self.tcx.def_kind(def_id),DefKind::Mod)
129-
&& letSome(prim) = self
130-
.tcx
131-
.get_attrs(def_id, sym::rustc_doc_primitive)
132-
.find_map(|attr| attr.value_str())
133-
{
134-
Some(prim)
135-
}else{
136-
self.tcx.opt_item_name(def_id)
137-
}
138-
}
139-
};
140-
141-
FullItemId{ def_id, name, extra }
142-
};
143-
144-
let key = match item_id {
145-
ItemId::DefId(did) => (make_part(did, name, extra),None),
146-
ItemId::Blanket{ for_, impl_id } => {
147-
(make_part(impl_id,None,None),Some(make_part(for_, name, extra)))
148-
}
149-
ItemId::Auto{ for_, trait_ } => {
150-
(make_part(trait_,None,None),Some(make_part(for_, name, extra)))
151-
}
152-
};
153-
154-
letmut interner = self.id_interner.borrow_mut();
155-
let len = interner.len();
156-
*interner
157-
.entry(key)
158-
.or_insert_with(|| Id(len.try_into().expect("too many items in a crate")))
159-
}
160-
161-
pub(crate)fnid_from_item(&self,item:&clean::Item) -> Id{
162-
match item.kind{
163-
clean::ItemKind::ImportItem(ref import) => {
164-
let extra =
165-
import.source.did.map(ItemId::from).map(|i| self.id_from_item_default(i));
166-
self.id_from_item_inner(item.item_id, item.name, extra)
167-
}
168-
_ => self.id_from_item_inner(item.item_id, item.name,None),
169-
}
170-
}
171-
172110
fnids(&self,items:implIntoIterator<Item = clean::Item>) -> Vec<Id>{
173111
items
174112
.into_iter()

‎src/librustdoc/json/ids.rs‎

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
//! Id handling for rustdoc-json.
2+
//!
3+
//! Manages the creation of [`rustdoc_json_types::Id`] and the
4+
//! fact that these don't correspond exactly to [`DefId`], because
5+
//! [`rustdoc_json_types::Item`] doesn't correspond exactly to what
6+
//! other phases think of as an "item".
7+
8+
use rustc_data_structures::fx::FxHashMap;
9+
use rustc_hir::def::DefKind;
10+
use rustc_hir::def_id::DefId;
11+
use rustc_span::{Symbol, sym};
12+
use rustdoc_json_types as types;
13+
14+
usesuper::JsonRenderer;
15+
usecrate::clean;
16+
17+
pub(super)typeIdInterner = FxHashMap<FullItemId, types::Id>;
18+
19+
#[derive(Debug,Clone,Copy,Hash,PartialEq,Eq)]
20+
/// An uninterned id.
21+
///
22+
/// Each one corresponds to exactly one of both:
23+
/// 1. [`rustdoc_json_types::Item`].
24+
/// 2. [`rustdoc_json_types::Id`] transitively (as each `Item` has an `Id`).
25+
///
26+
/// It's *broadly* equivalent to a [`DefId`], but needs slightly more information
27+
/// to fully disambiguate items, because sometimes we choose to split a single HIR
28+
/// item into multiple JSON items, or have items with no corresponding HIR item.
29+
pub(super)structFullItemId{
30+
/// The "main" id of the item.
31+
///
32+
/// In most cases this uniquely identifies the item, the other fields are just
33+
/// used for edge-cases.
34+
def_id:DefId,
35+
36+
/// An extra [`DefId`], which we need for:
37+
///
38+
/// 1. Auto-trait impls synthesized by rustdoc.
39+
/// 2. Blanket impls synthesized by rustdoc.
40+
/// 3. Splitting of reexports of multiple items.
41+
///
42+
/// E.g:
43+
///
44+
/// ```rust
45+
/// mod module {
46+
/// pub struct Foo {} // Exists in type namespace
47+
/// pub fn Foo(){} // Exists in value namespace
48+
/// }
49+
///
50+
/// pub use module::Foo; // Imports both items
51+
/// ```
52+
///
53+
/// In HIR, the `pub use` is just 1 item, but in rustdoc-json it's 2, so
54+
/// we need to disambiguate.
55+
extra_id:Option<DefId>,
56+
57+
/// Needed for `#[rustc_doc_primitive]` modules.
58+
///
59+
/// For these, 1 [`DefId`] is used for both the primitive and the fake-module
60+
/// that holds its docs.
61+
///
62+
/// N.B. This only matters when documenting the standard library with
63+
/// `--document-private-items`. Maybe we should delete that module, and
64+
/// remove this.
65+
name:Option<Symbol>,
66+
}
67+
68+
implJsonRenderer<'_>{
69+
pub(crate)fnid_from_item_default(&self,item_id: clean::ItemId) -> types::Id{
70+
self.id_from_item_inner(item_id,None,None)
71+
}
72+
73+
fnid_from_item_inner(
74+
&self,
75+
item_id: clean::ItemId,
76+
name:Option<Symbol>,
77+
imported_id:Option<DefId>,
78+
) -> types::Id{
79+
let(def_id, extra_id) = match item_id {
80+
clean::ItemId::DefId(did) => (did, imported_id),
81+
clean::ItemId::Blanket{ for_, impl_id } => (for_,Some(impl_id)),
82+
clean::ItemId::Auto{ for_, trait_ } => (for_,Some(trait_)),
83+
};
84+
85+
let name = match name {
86+
Some(name) => Some(name),
87+
None => {
88+
// We need this workaround because primitive types' DefId actually refers to
89+
// their parent module, which isn't present in the output JSON items. So
90+
// instead, we directly get the primitive symbol
91+
ifmatches!(self.tcx.def_kind(def_id),DefKind::Mod)
92+
&& letSome(prim) = self
93+
.tcx
94+
.get_attrs(def_id, sym::rustc_doc_primitive)
95+
.find_map(|attr| attr.value_str())
96+
{
97+
Some(prim)
98+
}else{
99+
self.tcx.opt_item_name(def_id)
100+
}
101+
}
102+
};
103+
104+
let key = FullItemId{ def_id, extra_id, name };
105+
106+
letmut interner = self.id_interner.borrow_mut();
107+
let len = interner.len();
108+
*interner
109+
.entry(key)
110+
.or_insert_with(|| types::Id(len.try_into().expect("too many items in a crate")))
111+
}
112+
113+
pub(crate)fnid_from_item(&self,item:&clean::Item) -> types::Id{
114+
match item.kind{
115+
clean::ItemKind::ImportItem(ref import) => {
116+
let imported_id = import.source.did;
117+
self.id_from_item_inner(item.item_id, item.name, imported_id)
118+
}
119+
_ => self.id_from_item_inner(item.item_id, item.name,None),
120+
}
121+
}
122+
}

‎src/librustdoc/json/mod.rs‎

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
//! docs for usage and details.
66
77
mod conversions;
8+
mod ids;
89
mod import_finder;
910

1011
use std::cell::RefCell;
@@ -16,7 +17,6 @@ use std::rc::Rc;
1617
use rustc_hir::def_id::{DefId,DefIdSet};
1718
use rustc_middle::ty::TyCtxt;
1819
use rustc_session::Session;
19-
use rustc_span::Symbol;
2020
use rustc_span::def_id::LOCAL_CRATE;
2121
use rustdoc_json_types as types;
2222
// It's important to use the FxHashMap from rustdoc_json_types here, instead of
@@ -35,14 +35,6 @@ use crate::formats::cache::Cache;
3535
usecrate::json::conversions::IntoJson;
3636
usecrate::{clean, try_err};
3737

38-
#[derive(Debug,Clone,Copy,Hash,PartialEq,Eq)]
39-
structFullItemId{
40-
def_id:DefId,
41-
name:Option<Symbol>,
42-
/// Used to distinguish imports of different items with the same name
43-
extra:Option<types::Id>,
44-
}
45-
4638
#[derive(Clone)]
4739
pub(crate)structJsonRenderer<'tcx>{
4840
tcx:TyCtxt<'tcx>,
@@ -55,7 +47,7 @@ pub(crate) struct JsonRenderer<'tcx> {
5547
out_dir:Option<PathBuf>,
5648
cache:Rc<Cache>,
5749
imported_items:DefIdSet,
58-
id_interner:Rc<RefCell<FxHashMap<(FullItemId,Option<FullItemId>), types::Id>>>,
50+
id_interner:Rc<RefCell<ids::IdInterner>>,
5951
}
6052

6153
impl<'tcx>JsonRenderer<'tcx>{

0 commit comments

Comments
 (0)