]> git.lizzy.rs Git - rust.git/blob - src/librustdoc/json/conversions.rs
Rollup merge of #103996 - SUPERCILEX:docs, r=RalfJung
[rust.git] / src / librustdoc / json / conversions.rs
1 //! These from impls are used to create the JSON types which get serialized. They're very close to
2 //! the `clean` types but with some fields removed or stringified to simplify the output and not
3 //! expose unstable compiler internals.
4
5 #![allow(rustc::default_hash_types)]
6
7 use std::convert::From;
8 use std::fmt;
9
10 use rustc_ast::ast;
11 use rustc_hir::{def::CtorKind, def_id::DefId};
12 use rustc_middle::ty::{self, TyCtxt};
13 use rustc_span::{Pos, Symbol};
14 use rustc_target::spec::abi::Abi as RustcAbi;
15
16 use rustdoc_json_types::*;
17
18 use crate::clean::utils::print_const_expr;
19 use crate::clean::{self, ItemId};
20 use crate::formats::item_type::ItemType;
21 use crate::json::JsonRenderer;
22 use crate::passes::collect_intra_doc_links::UrlFragment;
23
24 impl JsonRenderer<'_> {
25     pub(super) fn convert_item(&self, item: clean::Item) -> Option<Item> {
26         let deprecation = item.deprecation(self.tcx);
27         let links = self
28             .cache
29             .intra_doc_links
30             .get(&item.item_id)
31             .into_iter()
32             .flatten()
33             .map(|clean::ItemLink { link, page_id, fragment, .. }| {
34                 let id = match fragment {
35                     Some(UrlFragment::Item(frag_id)) => *frag_id,
36                     // FIXME: Pass the `UserWritten` segment to JSON consumer.
37                     Some(UrlFragment::UserWritten(_)) | None => *page_id,
38                 };
39
40                 (link.clone(), from_item_id(id.into(), self.tcx))
41             })
42             .collect();
43         let docs = item.attrs.collapsed_doc_value();
44         let attrs = item
45             .attrs
46             .other_attrs
47             .iter()
48             .map(rustc_ast_pretty::pprust::attribute_to_string)
49             .collect();
50         let span = item.span(self.tcx);
51         let visibility = item.visibility(self.tcx);
52         let clean::Item { name, attrs: _, kind: _, item_id, cfg: _, .. } = item;
53         let inner = match *item.kind {
54             clean::KeywordItem => return None,
55             clean::StrippedItem(ref inner) => {
56                 match &**inner {
57                     // We document stripped modules as with `Module::is_stripped` set to
58                     // `true`, to prevent contained items from being orphaned for downstream users,
59                     // as JSON does no inlining.
60                     clean::ModuleItem(_)
61                         if self.imported_items.contains(&item_id.expect_def_id()) =>
62                     {
63                         from_clean_item(item, self.tcx)
64                     }
65                     _ => return None,
66                 }
67             }
68             _ => from_clean_item(item, self.tcx),
69         };
70         Some(Item {
71             id: from_item_id_with_name(item_id, self.tcx, name),
72             crate_id: item_id.krate().as_u32(),
73             name: name.map(|sym| sym.to_string()),
74             span: span.and_then(|span| self.convert_span(span)),
75             visibility: self.convert_visibility(visibility),
76             docs,
77             attrs,
78             deprecation: deprecation.map(from_deprecation),
79             inner,
80             links,
81         })
82     }
83
84     fn convert_span(&self, span: clean::Span) -> Option<Span> {
85         match span.filename(self.sess()) {
86             rustc_span::FileName::Real(name) => {
87                 if let Some(local_path) = name.into_local_path() {
88                     let hi = span.hi(self.sess());
89                     let lo = span.lo(self.sess());
90                     Some(Span {
91                         filename: local_path,
92                         begin: (lo.line, lo.col.to_usize()),
93                         end: (hi.line, hi.col.to_usize()),
94                     })
95                 } else {
96                     None
97                 }
98             }
99             _ => None,
100         }
101     }
102
103     fn convert_visibility(&self, v: Option<ty::Visibility<DefId>>) -> Visibility {
104         match v {
105             None => Visibility::Default,
106             Some(ty::Visibility::Public) => Visibility::Public,
107             Some(ty::Visibility::Restricted(did)) if did.is_crate_root() => Visibility::Crate,
108             Some(ty::Visibility::Restricted(did)) => Visibility::Restricted {
109                 parent: from_item_id(did.into(), self.tcx),
110                 path: self.tcx.def_path(did).to_string_no_crate_verbose(),
111             },
112         }
113     }
114 }
115
116 pub(crate) trait FromWithTcx<T> {
117     fn from_tcx(f: T, tcx: TyCtxt<'_>) -> Self;
118 }
119
120 pub(crate) trait IntoWithTcx<T> {
121     fn into_tcx(self, tcx: TyCtxt<'_>) -> T;
122 }
123
124 impl<T, U> IntoWithTcx<U> for T
125 where
126     U: FromWithTcx<T>,
127 {
128     fn into_tcx(self, tcx: TyCtxt<'_>) -> U {
129         U::from_tcx(self, tcx)
130     }
131 }
132
133 impl<I, T, U> FromWithTcx<I> for Vec<U>
134 where
135     I: IntoIterator<Item = T>,
136     U: FromWithTcx<T>,
137 {
138     fn from_tcx(f: I, tcx: TyCtxt<'_>) -> Vec<U> {
139         f.into_iter().map(|x| x.into_tcx(tcx)).collect()
140     }
141 }
142
143 pub(crate) fn from_deprecation(deprecation: rustc_attr::Deprecation) -> Deprecation {
144     #[rustfmt::skip]
145     let rustc_attr::Deprecation { since, note, is_since_rustc_version: _, suggestion: _ } = deprecation;
146     Deprecation { since: since.map(|s| s.to_string()), note: note.map(|s| s.to_string()) }
147 }
148
149 impl FromWithTcx<clean::GenericArgs> for GenericArgs {
150     fn from_tcx(args: clean::GenericArgs, tcx: TyCtxt<'_>) -> Self {
151         use clean::GenericArgs::*;
152         match args {
153             AngleBracketed { args, bindings } => GenericArgs::AngleBracketed {
154                 args: args.into_vec().into_tcx(tcx),
155                 bindings: bindings.into_tcx(tcx),
156             },
157             Parenthesized { inputs, output } => GenericArgs::Parenthesized {
158                 inputs: inputs.into_vec().into_tcx(tcx),
159                 output: output.map(|a| (*a).into_tcx(tcx)),
160             },
161         }
162     }
163 }
164
165 impl FromWithTcx<clean::GenericArg> for GenericArg {
166     fn from_tcx(arg: clean::GenericArg, tcx: TyCtxt<'_>) -> Self {
167         use clean::GenericArg::*;
168         match arg {
169             Lifetime(l) => GenericArg::Lifetime(convert_lifetime(l)),
170             Type(t) => GenericArg::Type(t.into_tcx(tcx)),
171             Const(box c) => GenericArg::Const(c.into_tcx(tcx)),
172             Infer => GenericArg::Infer,
173         }
174     }
175 }
176
177 impl FromWithTcx<clean::Constant> for Constant {
178     fn from_tcx(constant: clean::Constant, tcx: TyCtxt<'_>) -> Self {
179         let expr = constant.expr(tcx);
180         let value = constant.value(tcx);
181         let is_literal = constant.is_literal(tcx);
182         Constant { type_: constant.type_.into_tcx(tcx), expr, value, is_literal }
183     }
184 }
185
186 impl FromWithTcx<clean::TypeBinding> for TypeBinding {
187     fn from_tcx(binding: clean::TypeBinding, tcx: TyCtxt<'_>) -> Self {
188         TypeBinding {
189             name: binding.assoc.name.to_string(),
190             args: binding.assoc.args.into_tcx(tcx),
191             binding: binding.kind.into_tcx(tcx),
192         }
193     }
194 }
195
196 impl FromWithTcx<clean::TypeBindingKind> for TypeBindingKind {
197     fn from_tcx(kind: clean::TypeBindingKind, tcx: TyCtxt<'_>) -> Self {
198         use clean::TypeBindingKind::*;
199         match kind {
200             Equality { term } => TypeBindingKind::Equality(term.into_tcx(tcx)),
201             Constraint { bounds } => TypeBindingKind::Constraint(bounds.into_tcx(tcx)),
202         }
203     }
204 }
205
206 /// It generates an ID as follows:
207 ///
208 /// `CRATE_ID:ITEM_ID[:NAME_ID]` (if there is no name, NAME_ID is not generated).
209 pub(crate) fn from_item_id(item_id: ItemId, tcx: TyCtxt<'_>) -> Id {
210     from_item_id_with_name(item_id, tcx, None)
211 }
212
213 // FIXME: this function (and appending the name at the end of the ID) should be removed when
214 // reexports are not inlined anymore for json format. It should be done in #93518.
215 pub(crate) fn from_item_id_with_name(item_id: ItemId, tcx: TyCtxt<'_>, name: Option<Symbol>) -> Id {
216     struct DisplayDefId<'a>(DefId, TyCtxt<'a>, Option<Symbol>);
217
218     impl<'a> fmt::Display for DisplayDefId<'a> {
219         fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
220             let name = match self.2 {
221                 Some(name) => format!(":{}", name.as_u32()),
222                 None => self
223                     .1
224                     .opt_item_name(self.0)
225                     .map(|n| format!(":{}", n.as_u32()))
226                     .unwrap_or_default(),
227             };
228             write!(f, "{}:{}{}", self.0.krate.as_u32(), u32::from(self.0.index), name)
229         }
230     }
231
232     match item_id {
233         ItemId::DefId(did) => Id(format!("{}", DisplayDefId(did, tcx, name))),
234         ItemId::Blanket { for_, impl_id } => {
235             Id(format!("b:{}-{}", DisplayDefId(impl_id, tcx, None), DisplayDefId(for_, tcx, name)))
236         }
237         ItemId::Auto { for_, trait_ } => {
238             Id(format!("a:{}-{}", DisplayDefId(trait_, tcx, None), DisplayDefId(for_, tcx, name)))
239         }
240         ItemId::Primitive(ty, krate) => Id(format!("p:{}:{}", krate.as_u32(), ty.as_sym())),
241     }
242 }
243
244 fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum {
245     use clean::ItemKind::*;
246     let name = item.name;
247     let is_crate = item.is_crate();
248     let header = item.fn_header(tcx);
249
250     match *item.kind {
251         ModuleItem(m) => {
252             ItemEnum::Module(Module { is_crate, items: ids(m.items, tcx), is_stripped: false })
253         }
254         ImportItem(i) => ItemEnum::Import(i.into_tcx(tcx)),
255         StructItem(s) => ItemEnum::Struct(s.into_tcx(tcx)),
256         UnionItem(u) => ItemEnum::Union(u.into_tcx(tcx)),
257         StructFieldItem(f) => ItemEnum::StructField(f.into_tcx(tcx)),
258         EnumItem(e) => ItemEnum::Enum(e.into_tcx(tcx)),
259         VariantItem(v) => ItemEnum::Variant(v.into_tcx(tcx)),
260         FunctionItem(f) => ItemEnum::Function(from_function(f, header.unwrap(), tcx)),
261         ForeignFunctionItem(f) => ItemEnum::Function(from_function(f, header.unwrap(), tcx)),
262         TraitItem(t) => ItemEnum::Trait((*t).into_tcx(tcx)),
263         TraitAliasItem(t) => ItemEnum::TraitAlias(t.into_tcx(tcx)),
264         MethodItem(m, _) => ItemEnum::Method(from_function_method(m, true, header.unwrap(), tcx)),
265         TyMethodItem(m) => ItemEnum::Method(from_function_method(m, false, header.unwrap(), tcx)),
266         ImplItem(i) => ItemEnum::Impl((*i).into_tcx(tcx)),
267         StaticItem(s) => ItemEnum::Static(s.into_tcx(tcx)),
268         ForeignStaticItem(s) => ItemEnum::Static(s.into_tcx(tcx)),
269         ForeignTypeItem => ItemEnum::ForeignType,
270         TypedefItem(t) => ItemEnum::Typedef(t.into_tcx(tcx)),
271         OpaqueTyItem(t) => ItemEnum::OpaqueTy(t.into_tcx(tcx)),
272         ConstantItem(c) => ItemEnum::Constant(c.into_tcx(tcx)),
273         MacroItem(m) => ItemEnum::Macro(m.source),
274         ProcMacroItem(m) => ItemEnum::ProcMacro(m.into_tcx(tcx)),
275         PrimitiveItem(p) => {
276             ItemEnum::Primitive(Primitive {
277                 name: p.as_sym().to_string(),
278                 impls: Vec::new(), // Added in JsonRenderer::item
279             })
280         }
281         TyAssocConstItem(ty) => ItemEnum::AssocConst { type_: ty.into_tcx(tcx), default: None },
282         AssocConstItem(ty, default) => {
283             ItemEnum::AssocConst { type_: ty.into_tcx(tcx), default: Some(default.expr(tcx)) }
284         }
285         TyAssocTypeItem(g, b) => ItemEnum::AssocType {
286             generics: g.into_tcx(tcx),
287             bounds: b.into_tcx(tcx),
288             default: None,
289         },
290         AssocTypeItem(t, b) => ItemEnum::AssocType {
291             generics: t.generics.into_tcx(tcx),
292             bounds: b.into_tcx(tcx),
293             default: Some(t.item_type.unwrap_or(t.type_).into_tcx(tcx)),
294         },
295         // `convert_item` early returns `None` for stripped items and keywords.
296         KeywordItem => unreachable!(),
297         StrippedItem(inner) => {
298             match *inner {
299                 ModuleItem(m) => ItemEnum::Module(Module {
300                     is_crate,
301                     items: ids(m.items, tcx),
302                     is_stripped: true,
303                 }),
304                 // `convert_item` early returns `None` for stripped items we're not including
305                 _ => unreachable!(),
306             }
307         }
308         ExternCrateItem { ref src } => ItemEnum::ExternCrate {
309             name: name.as_ref().unwrap().to_string(),
310             rename: src.map(|x| x.to_string()),
311         },
312     }
313 }
314
315 impl FromWithTcx<clean::Struct> for Struct {
316     fn from_tcx(struct_: clean::Struct, tcx: TyCtxt<'_>) -> Self {
317         let fields_stripped = struct_.has_stripped_entries();
318         let clean::Struct { struct_type, generics, fields } = struct_;
319
320         let kind = match struct_type {
321             CtorKind::Fn => StructKind::Tuple(ids_keeping_stripped(fields, tcx)),
322             CtorKind::Const => {
323                 assert!(fields.is_empty());
324                 StructKind::Unit
325             }
326             CtorKind::Fictive => StructKind::Plain { fields: ids(fields, tcx), fields_stripped },
327         };
328
329         Struct {
330             kind,
331             generics: generics.into_tcx(tcx),
332             impls: Vec::new(), // Added in JsonRenderer::item
333         }
334     }
335 }
336
337 impl FromWithTcx<clean::Union> for Union {
338     fn from_tcx(union_: clean::Union, tcx: TyCtxt<'_>) -> Self {
339         let fields_stripped = union_.has_stripped_entries();
340         let clean::Union { generics, fields } = union_;
341         Union {
342             generics: generics.into_tcx(tcx),
343             fields_stripped,
344             fields: ids(fields, tcx),
345             impls: Vec::new(), // Added in JsonRenderer::item
346         }
347     }
348 }
349
350 pub(crate) fn from_fn_header(header: &rustc_hir::FnHeader) -> Header {
351     Header {
352         async_: header.is_async(),
353         const_: header.is_const(),
354         unsafe_: header.is_unsafe(),
355         abi: convert_abi(header.abi),
356     }
357 }
358
359 fn convert_abi(a: RustcAbi) -> Abi {
360     match a {
361         RustcAbi::Rust => Abi::Rust,
362         RustcAbi::C { unwind } => Abi::C { unwind },
363         RustcAbi::Cdecl { unwind } => Abi::Cdecl { unwind },
364         RustcAbi::Stdcall { unwind } => Abi::Stdcall { unwind },
365         RustcAbi::Fastcall { unwind } => Abi::Fastcall { unwind },
366         RustcAbi::Aapcs { unwind } => Abi::Aapcs { unwind },
367         RustcAbi::Win64 { unwind } => Abi::Win64 { unwind },
368         RustcAbi::SysV64 { unwind } => Abi::SysV64 { unwind },
369         RustcAbi::System { unwind } => Abi::System { unwind },
370         _ => Abi::Other(a.to_string()),
371     }
372 }
373
374 fn convert_lifetime(l: clean::Lifetime) -> String {
375     l.0.to_string()
376 }
377
378 impl FromWithTcx<clean::Generics> for Generics {
379     fn from_tcx(generics: clean::Generics, tcx: TyCtxt<'_>) -> Self {
380         Generics {
381             params: generics.params.into_tcx(tcx),
382             where_predicates: generics.where_predicates.into_tcx(tcx),
383         }
384     }
385 }
386
387 impl FromWithTcx<clean::GenericParamDef> for GenericParamDef {
388     fn from_tcx(generic_param: clean::GenericParamDef, tcx: TyCtxt<'_>) -> Self {
389         GenericParamDef {
390             name: generic_param.name.to_string(),
391             kind: generic_param.kind.into_tcx(tcx),
392         }
393     }
394 }
395
396 impl FromWithTcx<clean::GenericParamDefKind> for GenericParamDefKind {
397     fn from_tcx(kind: clean::GenericParamDefKind, tcx: TyCtxt<'_>) -> Self {
398         use clean::GenericParamDefKind::*;
399         match kind {
400             Lifetime { outlives } => GenericParamDefKind::Lifetime {
401                 outlives: outlives.into_iter().map(convert_lifetime).collect(),
402             },
403             Type { did: _, bounds, default, synthetic } => GenericParamDefKind::Type {
404                 bounds: bounds.into_tcx(tcx),
405                 default: default.map(|x| (*x).into_tcx(tcx)),
406                 synthetic,
407             },
408             Const { did: _, ty, default } => GenericParamDefKind::Const {
409                 type_: (*ty).into_tcx(tcx),
410                 default: default.map(|x| *x),
411             },
412         }
413     }
414 }
415
416 impl FromWithTcx<clean::WherePredicate> for WherePredicate {
417     fn from_tcx(predicate: clean::WherePredicate, tcx: TyCtxt<'_>) -> Self {
418         use clean::WherePredicate::*;
419         match predicate {
420             BoundPredicate { ty, bounds, bound_params } => WherePredicate::BoundPredicate {
421                 type_: ty.into_tcx(tcx),
422                 bounds: bounds.into_tcx(tcx),
423                 generic_params: bound_params
424                     .into_iter()
425                     .map(|x| GenericParamDef {
426                         name: x.0.to_string(),
427                         kind: GenericParamDefKind::Lifetime { outlives: vec![] },
428                     })
429                     .collect(),
430             },
431             RegionPredicate { lifetime, bounds } => WherePredicate::RegionPredicate {
432                 lifetime: convert_lifetime(lifetime),
433                 bounds: bounds.into_tcx(tcx),
434             },
435             // FIXME(fmease): Convert bound parameters as well.
436             EqPredicate { lhs, rhs, bound_params: _ } => {
437                 WherePredicate::EqPredicate { lhs: (*lhs).into_tcx(tcx), rhs: (*rhs).into_tcx(tcx) }
438             }
439         }
440     }
441 }
442
443 impl FromWithTcx<clean::GenericBound> for GenericBound {
444     fn from_tcx(bound: clean::GenericBound, tcx: TyCtxt<'_>) -> Self {
445         use clean::GenericBound::*;
446         match bound {
447             TraitBound(clean::PolyTrait { trait_, generic_params }, modifier) => {
448                 GenericBound::TraitBound {
449                     trait_: trait_.into_tcx(tcx),
450                     generic_params: generic_params.into_tcx(tcx),
451                     modifier: from_trait_bound_modifier(modifier),
452                 }
453             }
454             Outlives(lifetime) => GenericBound::Outlives(convert_lifetime(lifetime)),
455         }
456     }
457 }
458
459 pub(crate) fn from_trait_bound_modifier(
460     modifier: rustc_hir::TraitBoundModifier,
461 ) -> TraitBoundModifier {
462     use rustc_hir::TraitBoundModifier::*;
463     match modifier {
464         None => TraitBoundModifier::None,
465         Maybe => TraitBoundModifier::Maybe,
466         MaybeConst => TraitBoundModifier::MaybeConst,
467     }
468 }
469
470 impl FromWithTcx<clean::Type> for Type {
471     fn from_tcx(ty: clean::Type, tcx: TyCtxt<'_>) -> Self {
472         use clean::Type::{
473             Array, BareFunction, BorrowedRef, Generic, ImplTrait, Infer, Primitive, QPath,
474             RawPointer, Slice, Tuple,
475         };
476
477         match ty {
478             clean::Type::Path { path } => Type::ResolvedPath(path.into_tcx(tcx)),
479             clean::Type::DynTrait(bounds, lt) => Type::DynTrait(DynTrait {
480                 lifetime: lt.map(convert_lifetime),
481                 traits: bounds.into_tcx(tcx),
482             }),
483             Generic(s) => Type::Generic(s.to_string()),
484             Primitive(p) => Type::Primitive(p.as_sym().to_string()),
485             BareFunction(f) => Type::FunctionPointer(Box::new((*f).into_tcx(tcx))),
486             Tuple(t) => Type::Tuple(t.into_tcx(tcx)),
487             Slice(t) => Type::Slice(Box::new((*t).into_tcx(tcx))),
488             Array(t, s) => Type::Array { type_: Box::new((*t).into_tcx(tcx)), len: s.to_string() },
489             ImplTrait(g) => Type::ImplTrait(g.into_tcx(tcx)),
490             Infer => Type::Infer,
491             RawPointer(mutability, type_) => Type::RawPointer {
492                 mutable: mutability == ast::Mutability::Mut,
493                 type_: Box::new((*type_).into_tcx(tcx)),
494             },
495             BorrowedRef { lifetime, mutability, type_ } => Type::BorrowedRef {
496                 lifetime: lifetime.map(convert_lifetime),
497                 mutable: mutability == ast::Mutability::Mut,
498                 type_: Box::new((*type_).into_tcx(tcx)),
499             },
500             QPath(box clean::QPathData { assoc, self_type, trait_, .. }) => Type::QualifiedPath {
501                 name: assoc.name.to_string(),
502                 args: Box::new(assoc.args.into_tcx(tcx)),
503                 self_type: Box::new(self_type.into_tcx(tcx)),
504                 trait_: trait_.into_tcx(tcx),
505             },
506         }
507     }
508 }
509
510 impl FromWithTcx<clean::Path> for Path {
511     fn from_tcx(path: clean::Path, tcx: TyCtxt<'_>) -> Path {
512         Path {
513             name: path.whole_name(),
514             id: from_item_id(path.def_id().into(), tcx),
515             args: path.segments.last().map(|args| Box::new(args.clone().args.into_tcx(tcx))),
516         }
517     }
518 }
519
520 impl FromWithTcx<clean::Term> for Term {
521     fn from_tcx(term: clean::Term, tcx: TyCtxt<'_>) -> Term {
522         match term {
523             clean::Term::Type(ty) => Term::Type(FromWithTcx::from_tcx(ty, tcx)),
524             clean::Term::Constant(c) => Term::Constant(FromWithTcx::from_tcx(c, tcx)),
525         }
526     }
527 }
528
529 impl FromWithTcx<clean::BareFunctionDecl> for FunctionPointer {
530     fn from_tcx(bare_decl: clean::BareFunctionDecl, tcx: TyCtxt<'_>) -> Self {
531         let clean::BareFunctionDecl { unsafety, generic_params, decl, abi } = bare_decl;
532         FunctionPointer {
533             header: Header {
534                 unsafe_: matches!(unsafety, rustc_hir::Unsafety::Unsafe),
535                 const_: false,
536                 async_: false,
537                 abi: convert_abi(abi),
538             },
539             generic_params: generic_params.into_tcx(tcx),
540             decl: decl.into_tcx(tcx),
541         }
542     }
543 }
544
545 impl FromWithTcx<clean::FnDecl> for FnDecl {
546     fn from_tcx(decl: clean::FnDecl, tcx: TyCtxt<'_>) -> Self {
547         let clean::FnDecl { inputs, output, c_variadic } = decl;
548         FnDecl {
549             inputs: inputs
550                 .values
551                 .into_iter()
552                 .map(|arg| (arg.name.to_string(), arg.type_.into_tcx(tcx)))
553                 .collect(),
554             output: match output {
555                 clean::FnRetTy::Return(t) => Some(t.into_tcx(tcx)),
556                 clean::FnRetTy::DefaultReturn => None,
557             },
558             c_variadic,
559         }
560     }
561 }
562
563 impl FromWithTcx<clean::Trait> for Trait {
564     fn from_tcx(trait_: clean::Trait, tcx: TyCtxt<'_>) -> Self {
565         let is_auto = trait_.is_auto(tcx);
566         let is_unsafe = trait_.unsafety(tcx) == rustc_hir::Unsafety::Unsafe;
567         let clean::Trait { items, generics, bounds, .. } = trait_;
568         Trait {
569             is_auto,
570             is_unsafe,
571             items: ids(items, tcx),
572             generics: generics.into_tcx(tcx),
573             bounds: bounds.into_tcx(tcx),
574             implementations: Vec::new(), // Added in JsonRenderer::item
575         }
576     }
577 }
578
579 impl FromWithTcx<clean::PolyTrait> for PolyTrait {
580     fn from_tcx(
581         clean::PolyTrait { trait_, generic_params }: clean::PolyTrait,
582         tcx: TyCtxt<'_>,
583     ) -> Self {
584         PolyTrait { trait_: trait_.into_tcx(tcx), generic_params: generic_params.into_tcx(tcx) }
585     }
586 }
587
588 impl FromWithTcx<clean::Impl> for Impl {
589     fn from_tcx(impl_: clean::Impl, tcx: TyCtxt<'_>) -> Self {
590         let provided_trait_methods = impl_.provided_trait_methods(tcx);
591         let clean::Impl { unsafety, generics, trait_, for_, items, polarity, kind } = impl_;
592         // FIXME: use something like ImplKind in JSON?
593         let (synthetic, blanket_impl) = match kind {
594             clean::ImplKind::Normal | clean::ImplKind::FakeVaradic => (false, None),
595             clean::ImplKind::Auto => (true, None),
596             clean::ImplKind::Blanket(ty) => (false, Some(*ty)),
597         };
598         let negative_polarity = match polarity {
599             ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => false,
600             ty::ImplPolarity::Negative => true,
601         };
602         Impl {
603             is_unsafe: unsafety == rustc_hir::Unsafety::Unsafe,
604             generics: generics.into_tcx(tcx),
605             provided_trait_methods: provided_trait_methods
606                 .into_iter()
607                 .map(|x| x.to_string())
608                 .collect(),
609             trait_: trait_.map(|path| path.into_tcx(tcx)),
610             for_: for_.into_tcx(tcx),
611             items: ids(items, tcx),
612             negative: negative_polarity,
613             synthetic,
614             blanket_impl: blanket_impl.map(|x| x.into_tcx(tcx)),
615         }
616     }
617 }
618
619 pub(crate) fn from_function(
620     function: Box<clean::Function>,
621     header: rustc_hir::FnHeader,
622     tcx: TyCtxt<'_>,
623 ) -> Function {
624     let clean::Function { decl, generics } = *function;
625     Function {
626         decl: decl.into_tcx(tcx),
627         generics: generics.into_tcx(tcx),
628         header: from_fn_header(&header),
629     }
630 }
631
632 pub(crate) fn from_function_method(
633     function: Box<clean::Function>,
634     has_body: bool,
635     header: rustc_hir::FnHeader,
636     tcx: TyCtxt<'_>,
637 ) -> Method {
638     let clean::Function { decl, generics } = *function;
639     Method {
640         decl: decl.into_tcx(tcx),
641         generics: generics.into_tcx(tcx),
642         header: from_fn_header(&header),
643         has_body,
644     }
645 }
646
647 impl FromWithTcx<clean::Enum> for Enum {
648     fn from_tcx(enum_: clean::Enum, tcx: TyCtxt<'_>) -> Self {
649         let variants_stripped = enum_.has_stripped_entries();
650         let clean::Enum { variants, generics } = enum_;
651         Enum {
652             generics: generics.into_tcx(tcx),
653             variants_stripped,
654             variants: ids(variants, tcx),
655             impls: Vec::new(), // Added in JsonRenderer::item
656         }
657     }
658 }
659
660 impl FromWithTcx<clean::Variant> for Variant {
661     fn from_tcx(variant: clean::Variant, tcx: TyCtxt<'_>) -> Self {
662         use clean::Variant::*;
663         match variant {
664             CLike(disr) => Variant::Plain(disr.map(|disr| disr.into_tcx(tcx))),
665             Tuple(fields) => Variant::Tuple(ids_keeping_stripped(fields, tcx)),
666             Struct(s) => Variant::Struct {
667                 fields_stripped: s.has_stripped_entries(),
668                 fields: ids(s.fields, tcx),
669             },
670         }
671     }
672 }
673
674 impl FromWithTcx<clean::Discriminant> for Discriminant {
675     fn from_tcx(disr: clean::Discriminant, tcx: TyCtxt<'_>) -> Self {
676         Discriminant {
677             // expr is only none if going throught the inlineing path, which gets
678             // `rustc_middle` types, not `rustc_hir`, but because JSON never inlines
679             // the expr is always some.
680             expr: disr.expr(tcx).unwrap(),
681             value: disr.value(tcx),
682         }
683     }
684 }
685
686 impl FromWithTcx<clean::Import> for Import {
687     fn from_tcx(import: clean::Import, tcx: TyCtxt<'_>) -> Self {
688         use clean::ImportKind::*;
689         let (name, glob) = match import.kind {
690             Simple(s) => (s.to_string(), false),
691             Glob => (
692                 import.source.path.last_opt().unwrap_or_else(|| Symbol::intern("*")).to_string(),
693                 true,
694             ),
695         };
696         Import {
697             source: import.source.path.whole_name(),
698             name,
699             id: import.source.did.map(ItemId::from).map(|i| from_item_id(i, tcx)),
700             glob,
701         }
702     }
703 }
704
705 impl FromWithTcx<clean::ProcMacro> for ProcMacro {
706     fn from_tcx(mac: clean::ProcMacro, _tcx: TyCtxt<'_>) -> Self {
707         ProcMacro {
708             kind: from_macro_kind(mac.kind),
709             helpers: mac.helpers.iter().map(|x| x.to_string()).collect(),
710         }
711     }
712 }
713
714 pub(crate) fn from_macro_kind(kind: rustc_span::hygiene::MacroKind) -> MacroKind {
715     use rustc_span::hygiene::MacroKind::*;
716     match kind {
717         Bang => MacroKind::Bang,
718         Attr => MacroKind::Attr,
719         Derive => MacroKind::Derive,
720     }
721 }
722
723 impl FromWithTcx<Box<clean::Typedef>> for Typedef {
724     fn from_tcx(typedef: Box<clean::Typedef>, tcx: TyCtxt<'_>) -> Self {
725         let clean::Typedef { type_, generics, item_type: _ } = *typedef;
726         Typedef { type_: type_.into_tcx(tcx), generics: generics.into_tcx(tcx) }
727     }
728 }
729
730 impl FromWithTcx<clean::OpaqueTy> for OpaqueTy {
731     fn from_tcx(opaque: clean::OpaqueTy, tcx: TyCtxt<'_>) -> Self {
732         OpaqueTy { bounds: opaque.bounds.into_tcx(tcx), generics: opaque.generics.into_tcx(tcx) }
733     }
734 }
735
736 impl FromWithTcx<clean::Static> for Static {
737     fn from_tcx(stat: clean::Static, tcx: TyCtxt<'_>) -> Self {
738         Static {
739             type_: stat.type_.into_tcx(tcx),
740             mutable: stat.mutability == ast::Mutability::Mut,
741             expr: stat.expr.map(|e| print_const_expr(tcx, e)).unwrap_or_default(),
742         }
743     }
744 }
745
746 impl FromWithTcx<clean::TraitAlias> for TraitAlias {
747     fn from_tcx(alias: clean::TraitAlias, tcx: TyCtxt<'_>) -> Self {
748         TraitAlias { generics: alias.generics.into_tcx(tcx), params: alias.bounds.into_tcx(tcx) }
749     }
750 }
751
752 impl FromWithTcx<ItemType> for ItemKind {
753     fn from_tcx(kind: ItemType, _tcx: TyCtxt<'_>) -> Self {
754         use ItemType::*;
755         match kind {
756             Module => ItemKind::Module,
757             ExternCrate => ItemKind::ExternCrate,
758             Import => ItemKind::Import,
759             Struct => ItemKind::Struct,
760             Union => ItemKind::Union,
761             Enum => ItemKind::Enum,
762             Function => ItemKind::Function,
763             Typedef => ItemKind::Typedef,
764             OpaqueTy => ItemKind::OpaqueTy,
765             Static => ItemKind::Static,
766             Constant => ItemKind::Constant,
767             Trait => ItemKind::Trait,
768             Impl => ItemKind::Impl,
769             TyMethod | Method => ItemKind::Method,
770             StructField => ItemKind::StructField,
771             Variant => ItemKind::Variant,
772             Macro => ItemKind::Macro,
773             Primitive => ItemKind::Primitive,
774             AssocConst => ItemKind::AssocConst,
775             AssocType => ItemKind::AssocType,
776             ForeignType => ItemKind::ForeignType,
777             Keyword => ItemKind::Keyword,
778             TraitAlias => ItemKind::TraitAlias,
779             ProcAttribute => ItemKind::ProcAttribute,
780             ProcDerive => ItemKind::ProcDerive,
781         }
782     }
783 }
784
785 fn ids(items: impl IntoIterator<Item = clean::Item>, tcx: TyCtxt<'_>) -> Vec<Id> {
786     items
787         .into_iter()
788         .filter(|x| !x.is_stripped() && !x.is_keyword())
789         .map(|i| from_item_id_with_name(i.item_id, tcx, i.name))
790         .collect()
791 }
792
793 fn ids_keeping_stripped(
794     items: impl IntoIterator<Item = clean::Item>,
795     tcx: TyCtxt<'_>,
796 ) -> Vec<Option<Id>> {
797     items
798         .into_iter()
799         .map(|i| {
800             if !i.is_stripped() && !i.is_keyword() {
801                 Some(from_item_id_with_name(i.item_id, tcx, i.name))
802             } else {
803                 None
804             }
805         })
806         .collect()
807 }