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::{EmitType, 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 const DESCR: &'static str = "json";
136 const RUN_ON_MODULE: bool = false;
137 const NON_STATIC_FILE_EMIT_TYPE: EmitType = EmitType::JsonFiles;
138
139 type ModuleData = ();
140
141 fn save_module_data(&mut self) -> Self::ModuleData {
142 unreachable!("RUN_ON_MODULE = false, should never call save_module_data")
143 }
144 fn restore_module_data(&mut self, _info: Self::ModuleData) {
145 unreachable!("RUN_ON_MODULE = false, should never call set_back_info")
146 }
147
148 fn item(&mut self, item: &clean::Item) -> Result<(), Error> {
152 use std::collections::hash_map::Entry;
153
154 let item_type = item.type_();
155 let item_name = item.name;
156 trace!("rendering {item_type} {item_name:?}");
157
158 if let ItemKind::StrippedItem(inner) = &item.kind {
161 inner.inner_items().for_each(|i| self.item(i).unwrap());
162 }
163
164 item.kind.inner_items().for_each(|i| self.item(i).unwrap());
166
167 let item_id = item.item_id;
168 if let Some(mut new_item) = self.convert_item(item) {
169 let can_be_ignored = match new_item.inner {
170 types::ItemEnum::Trait(ref mut t) => {
171 t.implementations = self.get_trait_implementors(item_id.expect_def_id());
172 false
173 }
174 types::ItemEnum::Struct(ref mut s) => {
175 s.impls = self.get_impls(item_id.expect_def_id());
176 false
177 }
178 types::ItemEnum::Enum(ref mut e) => {
179 e.impls = self.get_impls(item_id.expect_def_id());
180 false
181 }
182 types::ItemEnum::Union(ref mut u) => {
183 u.impls = self.get_impls(item_id.expect_def_id());
184 false
185 }
186 types::ItemEnum::Primitive(ref mut p) => {
187 p.impls = self.get_impls(item_id.expect_def_id());
188 false
189 }
190
191 types::ItemEnum::Function(_)
192 | types::ItemEnum::Module(_)
193 | types::ItemEnum::Use(_)
194 | types::ItemEnum::AssocConst { .. }
195 | types::ItemEnum::AssocType { .. } => true,
196 types::ItemEnum::ExternCrate { .. }
197 | types::ItemEnum::StructField(_)
198 | types::ItemEnum::Variant(_)
199 | types::ItemEnum::TraitAlias(_)
200 | types::ItemEnum::Impl(_)
201 | types::ItemEnum::TypeAlias(_)
202 | types::ItemEnum::Constant { .. }
203 | types::ItemEnum::Static(_)
204 | types::ItemEnum::ExternType
205 | types::ItemEnum::Macro(_)
206 | types::ItemEnum::ProcMacro(_) => false,
207 };
208
209 match self.index.entry(new_item.id) {
213 Entry::Vacant(entry) => {
214 entry.insert(new_item);
215 }
216 Entry::Occupied(mut entry) => {
217 let old_item = entry.get_mut();
221 if !can_be_ignored {
222 assert_eq!(*old_item, new_item);
223 }
224 trace!("replaced {old_item:?}\nwith {new_item:?}");
225 *old_item = new_item;
226 }
227 }
228 }
229
230 trace!("done rendering {item_type} {item_name:?}");
231 Ok(())
232 }
233
234 fn mod_item_in(&mut self, _item: &clean::Item) -> Result<(), Error> {
235 unreachable!("RUN_ON_MODULE = false, should never call mod_item_in")
236 }
237
238 fn after_krate(self) -> Result<(), Error> {
239 debug!("Done with crate");
240
241 let e = ExternalCrate { crate_num: LOCAL_CRATE };
242 let sess = self.sess();
243
244 let target = conversions::target(sess);
249
250 debug!("Constructing Output");
251 let output_crate = types::Crate {
252 root: self.id_from_item_default(e.def_id().into()),
253 crate_version: self.cache.crate_version.clone(),
254 includes_private: self.cache.document_private,
255 paths: self
256 .cache
257 .paths
258 .iter()
259 .chain(&self.cache.external_paths)
260 .map(|(&k, &(ref path, kind))| {
261 (
262 self.id_from_item_default(k.into()),
263 types::ItemSummary {
264 crate_id: k.krate.as_u32(),
265 path: path.iter().map(|s| s.to_string()).collect(),
266 kind: kind.into_json(&self),
267 },
268 )
269 })
270 .collect(),
271 external_crates: self
272 .cache
273 .extern_locations
274 .iter()
275 .map(|(crate_num, external_location)| {
276 let e = ExternalCrate { crate_num: *crate_num };
277 (
278 crate_num.as_u32(),
279 types::ExternalCrate {
280 name: e.name(self.tcx).to_string(),
281 html_root_url: match external_location {
282 ExternalLocation::Remote { url, .. } => Some(url.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}