1mod conversions;
8mod ids;
9mod import_finder;
10
11use std::cell::RefCell;
12use std::fs::{File, create_dir_all};
13use std::io::{BufWriter, Write, stdout};
14use std::path::PathBuf;
15use std::rc::Rc;
16
17use rustc_hir::def_id::{DefId, DefIdSet};
18use rustc_middle::ty::TyCtxt;
19use rustc_session::Session;
20use rustc_span::def_id::LOCAL_CRATE;
21use rustdoc_json_types as types;
22use rustdoc_json_types::FxHashMap;
26use tracing::{debug, trace};
27
28use crate::clean::ItemKind;
29use crate::clean::types::{ExternalCrate, ExternalLocation};
30use crate::config::RenderOptions;
31use crate::docfs::PathError;
32use crate::error::Error;
33use crate::formats::FormatRenderer;
34use crate::formats::cache::Cache;
35use crate::json::conversions::IntoJson;
36use crate::{clean, try_err};
37
38pub(crate) struct JsonRenderer<'tcx> {
39 tcx: TyCtxt<'tcx>,
40 index: FxHashMap<types::Id, types::Item>,
43 out_dir: Option<PathBuf>,
47 cache: Rc<Cache>,
48 imported_items: DefIdSet,
49 id_interner: RefCell<ids::IdInterner>,
50}
51
52impl<'tcx> JsonRenderer<'tcx> {
53 fn sess(&self) -> &'tcx Session {
54 self.tcx.sess
55 }
56
57 fn get_trait_implementors(&mut self, id: DefId) -> Vec<types::Id> {
58 Rc::clone(&self.cache)
59 .implementors
60 .get(&id)
61 .map(|implementors| {
62 implementors
63 .iter()
64 .map(|i| {
65 let item = &i.impl_item;
66 self.item(item).unwrap();
67 self.id_from_item(item)
68 })
69 .collect()
70 })
71 .unwrap_or_default()
72 }
73
74 fn get_impls(&mut self, id: DefId) -> Vec<types::Id> {
75 Rc::clone(&self.cache)
76 .impls
77 .get(&id)
78 .map(|impls| {
79 impls
80 .iter()
81 .filter_map(|i| {
82 let item = &i.impl_item;
83
84 let mut is_primitive_impl = false;
89 if let clean::types::ItemKind::ImplItem(ref impl_) = item.kind
90 && impl_.trait_.is_none()
91 && let clean::types::Type::Primitive(_) = impl_.for_
92 {
93 is_primitive_impl = true;
94 }
95
96 if item.item_id.is_local() || is_primitive_impl {
97 self.item(item).unwrap();
98 Some(self.id_from_item(item))
99 } else {
100 None
101 }
102 })
103 .collect()
104 })
105 .unwrap_or_default()
106 }
107}
108
109impl<'tcx> JsonRenderer<'tcx> {
110 pub(crate) fn init(
111 krate: clean::Crate,
112 options: RenderOptions,
113 cache: Cache,
114 tcx: TyCtxt<'tcx>,
115 ) -> Result<(Self, clean::Crate), Error> {
116 debug!("Initializing json renderer");
117
118 let (krate, imported_items) = import_finder::get_imports(krate);
119
120 Ok((
121 JsonRenderer {
122 tcx,
123 index: FxHashMap::default(),
124 out_dir: if options.output_to_stdout { None } else { Some(options.output) },
125 cache: Rc::new(cache),
126 imported_items,
127 id_interner: Default::default(),
128 },
129 krate,
130 ))
131 }
132}
133
134impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
135 fn descr() -> &'static str {
136 "json"
137 }
138
139 const RUN_ON_MODULE: bool = false;
140 type ModuleData = ();
141
142 fn save_module_data(&mut self) -> Self::ModuleData {
143 unreachable!("RUN_ON_MODULE = false, should never call save_module_data")
144 }
145 fn restore_module_data(&mut self, _info: Self::ModuleData) {
146 unreachable!("RUN_ON_MODULE = false, should never call set_back_info")
147 }
148
149 fn item(&mut self, item: &clean::Item) -> Result<(), Error> {
153 use std::collections::hash_map::Entry;
154
155 let item_type = item.type_();
156 let item_name = item.name;
157 trace!("rendering {item_type} {item_name:?}");
158
159 if let ItemKind::StrippedItem(inner) = &item.kind {
162 inner.inner_items().for_each(|i| self.item(i).unwrap());
163 }
164
165 item.kind.inner_items().for_each(|i| self.item(i).unwrap());
167
168 let item_id = item.item_id;
169 if let Some(mut new_item) = self.convert_item(item) {
170 let can_be_ignored = match new_item.inner {
171 types::ItemEnum::Trait(ref mut t) => {
172 t.implementations = self.get_trait_implementors(item_id.expect_def_id());
173 false
174 }
175 types::ItemEnum::Struct(ref mut s) => {
176 s.impls = self.get_impls(item_id.expect_def_id());
177 false
178 }
179 types::ItemEnum::Enum(ref mut e) => {
180 e.impls = self.get_impls(item_id.expect_def_id());
181 false
182 }
183 types::ItemEnum::Union(ref mut u) => {
184 u.impls = self.get_impls(item_id.expect_def_id());
185 false
186 }
187 types::ItemEnum::Primitive(ref mut p) => {
188 p.impls = self.get_impls(item_id.expect_def_id());
189 false
190 }
191
192 types::ItemEnum::Function(_)
193 | types::ItemEnum::Module(_)
194 | types::ItemEnum::Use(_)
195 | types::ItemEnum::AssocConst { .. }
196 | types::ItemEnum::AssocType { .. } => true,
197 types::ItemEnum::ExternCrate { .. }
198 | types::ItemEnum::StructField(_)
199 | types::ItemEnum::Variant(_)
200 | types::ItemEnum::TraitAlias(_)
201 | types::ItemEnum::Impl(_)
202 | types::ItemEnum::TypeAlias(_)
203 | types::ItemEnum::Constant { .. }
204 | types::ItemEnum::Static(_)
205 | types::ItemEnum::ExternType
206 | types::ItemEnum::Macro(_)
207 | types::ItemEnum::ProcMacro(_) => false,
208 };
209
210 match self.index.entry(new_item.id) {
214 Entry::Vacant(entry) => {
215 entry.insert(new_item);
216 }
217 Entry::Occupied(mut entry) => {
218 let old_item = entry.get_mut();
222 if !can_be_ignored {
223 assert_eq!(*old_item, new_item);
224 }
225 trace!("replaced {old_item:?}\nwith {new_item:?}");
226 *old_item = new_item;
227 }
228 }
229 }
230
231 trace!("done rendering {item_type} {item_name:?}");
232 Ok(())
233 }
234
235 fn mod_item_in(&mut self, _item: &clean::Item) -> Result<(), Error> {
236 unreachable!("RUN_ON_MODULE = false, should never call mod_item_in")
237 }
238
239 fn after_krate(self) -> Result<(), Error> {
240 debug!("Done with crate");
241
242 let e = ExternalCrate { crate_num: LOCAL_CRATE };
243 let sess = self.sess();
244
245 let target = conversions::target(sess);
250
251 debug!("Constructing Output");
252 let output_crate = types::Crate {
253 root: self.id_from_item_default(e.def_id().into()),
254 crate_version: self.cache.crate_version.clone(),
255 includes_private: self.cache.document_private,
256 paths: self
257 .cache
258 .paths
259 .iter()
260 .chain(&self.cache.external_paths)
261 .map(|(&k, &(ref path, kind))| {
262 (
263 self.id_from_item_default(k.into()),
264 types::ItemSummary {
265 crate_id: k.krate.as_u32(),
266 path: path.iter().map(|s| s.to_string()).collect(),
267 kind: kind.into_json(&self),
268 },
269 )
270 })
271 .collect(),
272 external_crates: self
273 .cache
274 .extern_locations
275 .iter()
276 .map(|(crate_num, external_location)| {
277 let e = ExternalCrate { crate_num: *crate_num };
278 (
279 crate_num.as_u32(),
280 types::ExternalCrate {
281 name: e.name(self.tcx).to_string(),
282 html_root_url: match external_location {
283 ExternalLocation::Remote(s) => Some(s.clone()),
284 _ => None,
285 },
286 path: self
287 .tcx
288 .used_crate_source(*crate_num)
289 .paths()
290 .next()
291 .expect("crate should have at least 1 path")
292 .clone(),
293 },
294 )
295 })
296 .collect(),
297 index: self.index,
299 target,
300 format_version: types::FORMAT_VERSION,
301 };
302 if let Some(ref out_dir) = self.out_dir {
303 try_err!(create_dir_all(out_dir), out_dir);
304
305 let mut p = out_dir.clone();
306 p.push(output_crate.index.get(&output_crate.root).unwrap().name.clone().unwrap());
307 p.set_extension("json");
308
309 serialize_and_write(
310 sess,
311 output_crate,
312 try_err!(File::create_buffered(&p), p),
313 &p.display().to_string(),
314 )
315 } else {
316 serialize_and_write(sess, output_crate, BufWriter::new(stdout().lock()), "<stdout>")
317 }
318 }
319}
320
321fn serialize_and_write<T: Write>(
322 sess: &Session,
323 output_crate: types::Crate,
324 mut writer: BufWriter<T>,
325 path: &str,
326) -> Result<(), Error> {
327 sess.time("rustdoc_json_serialize_and_write", || {
328 try_err!(
329 serde_json::ser::to_writer(&mut writer, &output_crate).map_err(|e| e.to_string()),
330 path
331 );
332 try_err!(writer.flush(), path);
333 Ok(())
334 })
335}
336
337#[cfg(target_pointer_width = "64")]
342mod size_asserts {
343 use rustc_data_structures::static_assert_size;
344
345 use super::types::*;
346 static_assert_size!(AssocItemConstraint, 112);
348 static_assert_size!(Crate, 184);
349 static_assert_size!(FunctionPointer, 168);
350 static_assert_size!(GenericArg, 80);
351 static_assert_size!(GenericArgs, 104);
352 static_assert_size!(GenericBound, 72);
353 static_assert_size!(GenericParamDef, 136);
354 static_assert_size!(Impl, 304);
355 static_assert_size!(ItemSummary, 32);
356 static_assert_size!(PolyTrait, 64);
357 static_assert_size!(PreciseCapturingArg, 32);
358 static_assert_size!(TargetFeature, 80);
359 static_assert_size!(Type, 80);
360 static_assert_size!(WherePredicate, 160);
361 static_assert_size!(Item, 528 + size_of::<std::path::PathBuf>());
365 static_assert_size!(ExternalCrate, 48 + size_of::<std::path::PathBuf>());
366}