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 fn serialize_and_write<T: Write>(
109 &self,
110 output_crate: types::Crate,
111 mut writer: BufWriter<T>,
112 path: &str,
113 ) -> Result<(), Error> {
114 self.sess().time("rustdoc_json_serialize_and_write", || {
115 try_err!(
116 serde_json::ser::to_writer(&mut writer, &output_crate).map_err(|e| e.to_string()),
117 path
118 );
119 try_err!(writer.flush(), path);
120 Ok(())
121 })
122 }
123}
124
125impl<'tcx> JsonRenderer<'tcx> {
126 pub(crate) fn init(
127 krate: clean::Crate,
128 options: RenderOptions,
129 cache: Cache,
130 tcx: TyCtxt<'tcx>,
131 ) -> Result<(Self, clean::Crate), Error> {
132 debug!("Initializing json renderer");
133
134 let (krate, imported_items) = import_finder::get_imports(krate);
135
136 Ok((
137 JsonRenderer {
138 tcx,
139 index: FxHashMap::default(),
140 out_dir: if options.output_to_stdout { None } else { Some(options.output) },
141 cache: Rc::new(cache),
142 imported_items,
143 id_interner: Default::default(),
144 },
145 krate,
146 ))
147 }
148}
149
150impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
151 fn descr() -> &'static str {
152 "json"
153 }
154
155 const RUN_ON_MODULE: bool = false;
156 type ModuleData = ();
157
158 fn save_module_data(&mut self) -> Self::ModuleData {
159 unreachable!("RUN_ON_MODULE = false, should never call save_module_data")
160 }
161 fn restore_module_data(&mut self, _info: Self::ModuleData) {
162 unreachable!("RUN_ON_MODULE = false, should never call set_back_info")
163 }
164
165 fn item(&mut self, item: &clean::Item) -> Result<(), Error> {
169 use std::collections::hash_map::Entry;
170
171 let item_type = item.type_();
172 let item_name = item.name;
173 trace!("rendering {item_type} {item_name:?}");
174
175 if let ItemKind::StrippedItem(inner) = &item.kind {
178 inner.inner_items().for_each(|i| self.item(i).unwrap());
179 }
180
181 item.kind.inner_items().for_each(|i| self.item(i).unwrap());
183
184 let item_id = item.item_id;
185 if let Some(mut new_item) = self.convert_item(item) {
186 let can_be_ignored = match new_item.inner {
187 types::ItemEnum::Trait(ref mut t) => {
188 t.implementations = self.get_trait_implementors(item_id.expect_def_id());
189 false
190 }
191 types::ItemEnum::Struct(ref mut s) => {
192 s.impls = self.get_impls(item_id.expect_def_id());
193 false
194 }
195 types::ItemEnum::Enum(ref mut e) => {
196 e.impls = self.get_impls(item_id.expect_def_id());
197 false
198 }
199 types::ItemEnum::Union(ref mut u) => {
200 u.impls = self.get_impls(item_id.expect_def_id());
201 false
202 }
203 types::ItemEnum::Primitive(ref mut p) => {
204 p.impls = self.get_impls(item_id.expect_def_id());
205 false
206 }
207
208 types::ItemEnum::Function(_)
209 | types::ItemEnum::Module(_)
210 | types::ItemEnum::Use(_)
211 | types::ItemEnum::AssocConst { .. }
212 | types::ItemEnum::AssocType { .. } => true,
213 types::ItemEnum::ExternCrate { .. }
214 | types::ItemEnum::StructField(_)
215 | types::ItemEnum::Variant(_)
216 | types::ItemEnum::TraitAlias(_)
217 | types::ItemEnum::Impl(_)
218 | types::ItemEnum::TypeAlias(_)
219 | types::ItemEnum::Constant { .. }
220 | types::ItemEnum::Static(_)
221 | types::ItemEnum::ExternType
222 | types::ItemEnum::Macro(_)
223 | types::ItemEnum::ProcMacro(_) => false,
224 };
225
226 match self.index.entry(new_item.id) {
230 Entry::Vacant(entry) => {
231 entry.insert(new_item);
232 }
233 Entry::Occupied(mut entry) => {
234 let old_item = entry.get_mut();
238 if !can_be_ignored {
239 assert_eq!(*old_item, new_item);
240 }
241 trace!("replaced {old_item:?}\nwith {new_item:?}");
242 *old_item = new_item;
243 }
244 }
245 }
246
247 trace!("done rendering {item_type} {item_name:?}");
248 Ok(())
249 }
250
251 fn mod_item_in(&mut self, _item: &clean::Item) -> Result<(), Error> {
252 unreachable!("RUN_ON_MODULE = false, should never call mod_item_in")
253 }
254
255 fn after_krate(mut self) -> Result<(), Error> {
256 debug!("Done with crate");
257
258 let e = ExternalCrate { crate_num: LOCAL_CRATE };
259
260 let index = std::mem::take(&mut self.index);
262
263 let target = conversions::target(self.tcx.sess);
268
269 debug!("Constructing Output");
270 let output_crate = types::Crate {
271 root: self.id_from_item_default(e.def_id().into()),
272 crate_version: self.cache.crate_version.clone(),
273 includes_private: self.cache.document_private,
274 index,
275 paths: self
276 .cache
277 .paths
278 .iter()
279 .chain(&self.cache.external_paths)
280 .map(|(&k, &(ref path, kind))| {
281 (
282 self.id_from_item_default(k.into()),
283 types::ItemSummary {
284 crate_id: k.krate.as_u32(),
285 path: path.iter().map(|s| s.to_string()).collect(),
286 kind: kind.into_json(&self),
287 },
288 )
289 })
290 .collect(),
291 external_crates: self
292 .cache
293 .extern_locations
294 .iter()
295 .map(|(crate_num, external_location)| {
296 let e = ExternalCrate { crate_num: *crate_num };
297 (
298 crate_num.as_u32(),
299 types::ExternalCrate {
300 name: e.name(self.tcx).to_string(),
301 html_root_url: match external_location {
302 ExternalLocation::Remote(s) => Some(s.clone()),
303 _ => None,
304 },
305 },
306 )
307 })
308 .collect(),
309 target,
310 format_version: types::FORMAT_VERSION,
311 };
312 if let Some(ref out_dir) = self.out_dir {
313 try_err!(create_dir_all(out_dir), out_dir);
314
315 let mut p = out_dir.clone();
316 p.push(output_crate.index.get(&output_crate.root).unwrap().name.clone().unwrap());
317 p.set_extension("json");
318
319 self.serialize_and_write(
320 output_crate,
321 try_err!(File::create_buffered(&p), p),
322 &p.display().to_string(),
323 )
324 } else {
325 self.serialize_and_write(output_crate, BufWriter::new(stdout().lock()), "<stdout>")
326 }
327 }
328}
329
330#[cfg(target_pointer_width = "64")]
335mod size_asserts {
336 use rustc_data_structures::static_assert_size;
337
338 use super::types::*;
339 static_assert_size!(AssocItemConstraint, 112);
341 static_assert_size!(Crate, 184);
342 static_assert_size!(ExternalCrate, 48);
343 static_assert_size!(FunctionPointer, 168);
344 static_assert_size!(GenericArg, 80);
345 static_assert_size!(GenericArgs, 104);
346 static_assert_size!(GenericBound, 72);
347 static_assert_size!(GenericParamDef, 136);
348 static_assert_size!(Impl, 304);
349 static_assert_size!(Item, 528 + size_of::<std::path::PathBuf>());
351 static_assert_size!(ItemSummary, 32);
352 static_assert_size!(PolyTrait, 64);
353 static_assert_size!(PreciseCapturingArg, 32);
354 static_assert_size!(TargetFeature, 80);
355 static_assert_size!(Type, 80);
356 static_assert_size!(WherePredicate, 160);
357 }