rustdoc/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
7use rustc_abi::ExternAbi;
8use rustc_ast::ast;
9use rustc_attr_data_structures::{self as attrs, DeprecatedSince};
10use rustc_hir::def::CtorKind;
11use rustc_hir::def_id::DefId;
12use rustc_metadata::rendered_const;
13use rustc_middle::{bug, ty};
14use rustc_span::{Pos, kw, sym};
15use rustdoc_json_types::*;
16use thin_vec::ThinVec;
17
18use crate::clean::{self, ItemId};
19use crate::formats::item_type::ItemType;
20use crate::json::JsonRenderer;
21use crate::passes::collect_intra_doc_links::UrlFragment;
22
23impl JsonRenderer<'_> {
24    pub(super) fn convert_item(&self, item: &clean::Item) -> Option<Item> {
25        let deprecation = item.deprecation(self.tcx);
26        let links = self
27            .cache
28            .intra_doc_links
29            .get(&item.item_id)
30            .into_iter()
31            .flatten()
32            .map(|clean::ItemLink { link, page_id, fragment, .. }| {
33                let id = match fragment {
34                    Some(UrlFragment::Item(frag_id)) => *frag_id,
35                    // FIXME: Pass the `UserWritten` segment to JSON consumer.
36                    Some(UrlFragment::UserWritten(_)) | None => *page_id,
37                };
38
39                (String::from(&**link), self.id_from_item_default(id.into()))
40            })
41            .collect();
42        let docs = item.opt_doc_value();
43        let attrs = item.attributes(self.tcx, &self.cache, true);
44        let span = item.span(self.tcx);
45        let visibility = item.visibility(self.tcx);
46        let clean::ItemInner { name, item_id, .. } = *item.inner;
47        let id = self.id_from_item(&item);
48        let inner = match item.kind {
49            clean::KeywordItem => return None,
50            clean::StrippedItem(ref inner) => {
51                match &**inner {
52                    // We document stripped modules as with `Module::is_stripped` set to
53                    // `true`, to prevent contained items from being orphaned for downstream users,
54                    // as JSON does no inlining.
55                    clean::ModuleItem(_)
56                        if self.imported_items.contains(&item_id.expect_def_id()) =>
57                    {
58                        from_clean_item(item, self)
59                    }
60                    _ => return None,
61                }
62            }
63            _ => from_clean_item(item, self),
64        };
65        Some(Item {
66            id,
67            crate_id: item_id.krate().as_u32(),
68            name: name.map(|sym| sym.to_string()),
69            span: span.and_then(|span| span.into_json(self)),
70            visibility: visibility.into_json(self),
71            docs,
72            attrs,
73            deprecation: deprecation.into_json(self),
74            inner,
75            links,
76        })
77    }
78
79    fn ids(&self, items: &[clean::Item]) -> Vec<Id> {
80        items
81            .iter()
82            .filter(|i| !i.is_stripped() && !i.is_keyword())
83            .map(|i| self.id_from_item(&i))
84            .collect()
85    }
86
87    fn ids_keeping_stripped(&self, items: &[clean::Item]) -> Vec<Option<Id>> {
88        items
89            .iter()
90            .map(|i| (!i.is_stripped() && !i.is_keyword()).then(|| self.id_from_item(&i)))
91            .collect()
92    }
93}
94
95pub(crate) trait FromClean<T> {
96    fn from_clean(f: &T, renderer: &JsonRenderer<'_>) -> Self;
97}
98
99pub(crate) trait IntoJson<T> {
100    fn into_json(&self, renderer: &JsonRenderer<'_>) -> T;
101}
102
103impl<T, U> IntoJson<U> for T
104where
105    U: FromClean<T>,
106{
107    fn into_json(&self, renderer: &JsonRenderer<'_>) -> U {
108        U::from_clean(self, renderer)
109    }
110}
111
112impl<T, U> FromClean<Box<T>> for U
113where
114    U: FromClean<T>,
115{
116    fn from_clean(opt: &Box<T>, renderer: &JsonRenderer<'_>) -> Self {
117        opt.as_ref().into_json(renderer)
118    }
119}
120
121impl<T, U> FromClean<Option<T>> for Option<U>
122where
123    U: FromClean<T>,
124{
125    fn from_clean(opt: &Option<T>, renderer: &JsonRenderer<'_>) -> Self {
126        opt.as_ref().map(|x| x.into_json(renderer))
127    }
128}
129
130impl<T, U> FromClean<Vec<T>> for Vec<U>
131where
132    U: FromClean<T>,
133{
134    fn from_clean(items: &Vec<T>, renderer: &JsonRenderer<'_>) -> Self {
135        items.iter().map(|i| i.into_json(renderer)).collect()
136    }
137}
138
139impl<T, U> FromClean<ThinVec<T>> for Vec<U>
140where
141    U: FromClean<T>,
142{
143    fn from_clean(items: &ThinVec<T>, renderer: &JsonRenderer<'_>) -> Self {
144        items.iter().map(|i| i.into_json(renderer)).collect()
145    }
146}
147
148impl FromClean<clean::Span> for Option<Span> {
149    fn from_clean(span: &clean::Span, renderer: &JsonRenderer<'_>) -> Self {
150        match span.filename(renderer.sess()) {
151            rustc_span::FileName::Real(name) => {
152                if let Some(local_path) = name.into_local_path() {
153                    let hi = span.hi(renderer.sess());
154                    let lo = span.lo(renderer.sess());
155                    Some(Span {
156                        filename: local_path,
157                        begin: (lo.line, lo.col.to_usize() + 1),
158                        end: (hi.line, hi.col.to_usize() + 1),
159                    })
160                } else {
161                    None
162                }
163            }
164            _ => None,
165        }
166    }
167}
168
169impl FromClean<Option<ty::Visibility<DefId>>> for Visibility {
170    fn from_clean(v: &Option<ty::Visibility<DefId>>, renderer: &JsonRenderer<'_>) -> Self {
171        match v {
172            None => Visibility::Default,
173            Some(ty::Visibility::Public) => Visibility::Public,
174            Some(ty::Visibility::Restricted(did)) if did.is_crate_root() => Visibility::Crate,
175            Some(ty::Visibility::Restricted(did)) => Visibility::Restricted {
176                parent: renderer.id_from_item_default((*did).into()),
177                path: renderer.tcx.def_path(*did).to_string_no_crate_verbose(),
178            },
179        }
180    }
181}
182
183impl FromClean<attrs::Deprecation> for Deprecation {
184    fn from_clean(deprecation: &attrs::Deprecation, _renderer: &JsonRenderer<'_>) -> Self {
185        let attrs::Deprecation { since, note, suggestion: _ } = deprecation;
186        let since = match since {
187            DeprecatedSince::RustcVersion(version) => Some(version.to_string()),
188            DeprecatedSince::Future => Some("TBD".to_string()),
189            DeprecatedSince::NonStandard(since) => Some(since.to_string()),
190            DeprecatedSince::Unspecified | DeprecatedSince::Err => None,
191        };
192        Deprecation { since, note: note.map(|sym| sym.to_string()) }
193    }
194}
195
196impl FromClean<clean::GenericArgs> for Option<Box<GenericArgs>> {
197    fn from_clean(generic_args: &clean::GenericArgs, renderer: &JsonRenderer<'_>) -> Self {
198        use clean::GenericArgs::*;
199        match generic_args {
200            AngleBracketed { args, constraints } => {
201                if generic_args.is_empty() {
202                    None
203                } else {
204                    Some(Box::new(GenericArgs::AngleBracketed {
205                        args: args.into_json(renderer),
206                        constraints: constraints.into_json(renderer),
207                    }))
208                }
209            }
210            Parenthesized { inputs, output } => Some(Box::new(GenericArgs::Parenthesized {
211                inputs: inputs.into_json(renderer),
212                output: output.into_json(renderer),
213            })),
214            ReturnTypeNotation => Some(Box::new(GenericArgs::ReturnTypeNotation)),
215        }
216    }
217}
218
219impl FromClean<clean::GenericArg> for GenericArg {
220    fn from_clean(arg: &clean::GenericArg, renderer: &JsonRenderer<'_>) -> Self {
221        use clean::GenericArg::*;
222        match arg {
223            Lifetime(l) => GenericArg::Lifetime(l.into_json(renderer)),
224            Type(t) => GenericArg::Type(t.into_json(renderer)),
225            Const(box c) => GenericArg::Const(c.into_json(renderer)),
226            Infer => GenericArg::Infer,
227        }
228    }
229}
230
231impl FromClean<clean::ConstantKind> for Constant {
232    // FIXME(generic_const_items): Add support for generic const items.
233    fn from_clean(constant: &clean::ConstantKind, renderer: &JsonRenderer<'_>) -> Self {
234        let tcx = renderer.tcx;
235        let expr = constant.expr(tcx);
236        let value = constant.value(tcx);
237        let is_literal = constant.is_literal(tcx);
238        Constant { expr, value, is_literal }
239    }
240}
241
242impl FromClean<clean::AssocItemConstraint> for AssocItemConstraint {
243    fn from_clean(constraint: &clean::AssocItemConstraint, renderer: &JsonRenderer<'_>) -> Self {
244        AssocItemConstraint {
245            name: constraint.assoc.name.to_string(),
246            args: constraint.assoc.args.into_json(renderer),
247            binding: constraint.kind.into_json(renderer),
248        }
249    }
250}
251
252impl FromClean<clean::AssocItemConstraintKind> for AssocItemConstraintKind {
253    fn from_clean(kind: &clean::AssocItemConstraintKind, renderer: &JsonRenderer<'_>) -> Self {
254        use clean::AssocItemConstraintKind::*;
255        match kind {
256            Equality { term } => AssocItemConstraintKind::Equality(term.into_json(renderer)),
257            Bound { bounds } => AssocItemConstraintKind::Constraint(bounds.into_json(renderer)),
258        }
259    }
260}
261
262fn from_clean_item(item: &clean::Item, renderer: &JsonRenderer<'_>) -> ItemEnum {
263    use clean::ItemKind::*;
264    let name = item.name;
265    let is_crate = item.is_crate();
266    let header = item.fn_header(renderer.tcx);
267
268    match &item.inner.kind {
269        ModuleItem(m) => {
270            ItemEnum::Module(Module { is_crate, items: renderer.ids(&m.items), is_stripped: false })
271        }
272        ImportItem(i) => ItemEnum::Use(i.into_json(renderer)),
273        StructItem(s) => ItemEnum::Struct(s.into_json(renderer)),
274        UnionItem(u) => ItemEnum::Union(u.into_json(renderer)),
275        StructFieldItem(f) => ItemEnum::StructField(f.into_json(renderer)),
276        EnumItem(e) => ItemEnum::Enum(e.into_json(renderer)),
277        VariantItem(v) => ItemEnum::Variant(v.into_json(renderer)),
278        FunctionItem(f) => {
279            ItemEnum::Function(from_clean_function(f, true, header.unwrap(), renderer))
280        }
281        ForeignFunctionItem(f, _) => {
282            ItemEnum::Function(from_clean_function(f, false, header.unwrap(), renderer))
283        }
284        TraitItem(t) => ItemEnum::Trait(t.into_json(renderer)),
285        TraitAliasItem(t) => ItemEnum::TraitAlias(t.into_json(renderer)),
286        MethodItem(m, _) => {
287            ItemEnum::Function(from_clean_function(m, true, header.unwrap(), renderer))
288        }
289        RequiredMethodItem(m) => {
290            ItemEnum::Function(from_clean_function(m, false, header.unwrap(), renderer))
291        }
292        ImplItem(i) => ItemEnum::Impl(i.into_json(renderer)),
293        StaticItem(s) => ItemEnum::Static(from_clean_static(s, rustc_hir::Safety::Safe, renderer)),
294        ForeignStaticItem(s, safety) => ItemEnum::Static(from_clean_static(s, *safety, renderer)),
295        ForeignTypeItem => ItemEnum::ExternType,
296        TypeAliasItem(t) => ItemEnum::TypeAlias(t.into_json(renderer)),
297        // FIXME(generic_const_items): Add support for generic free consts
298        ConstantItem(ci) => ItemEnum::Constant {
299            type_: ci.type_.into_json(renderer),
300            const_: ci.kind.into_json(renderer),
301        },
302        MacroItem(m) => ItemEnum::Macro(m.source.clone()),
303        ProcMacroItem(m) => ItemEnum::ProcMacro(m.into_json(renderer)),
304        PrimitiveItem(p) => {
305            ItemEnum::Primitive(Primitive {
306                name: p.as_sym().to_string(),
307                impls: Vec::new(), // Added in JsonRenderer::item
308            })
309        }
310        // FIXME(generic_const_items): Add support for generic associated consts.
311        RequiredAssocConstItem(_generics, ty) => {
312            ItemEnum::AssocConst { type_: ty.into_json(renderer), value: None }
313        }
314        // FIXME(generic_const_items): Add support for generic associated consts.
315        ProvidedAssocConstItem(ci) | ImplAssocConstItem(ci) => ItemEnum::AssocConst {
316            type_: ci.type_.into_json(renderer),
317            value: Some(ci.kind.expr(renderer.tcx)),
318        },
319        RequiredAssocTypeItem(g, b) => ItemEnum::AssocType {
320            generics: g.into_json(renderer),
321            bounds: b.into_json(renderer),
322            type_: None,
323        },
324        AssocTypeItem(t, b) => ItemEnum::AssocType {
325            generics: t.generics.into_json(renderer),
326            bounds: b.into_json(renderer),
327            type_: Some(t.item_type.as_ref().unwrap_or(&t.type_).into_json(renderer)),
328        },
329        // `convert_item` early returns `None` for stripped items and keywords.
330        KeywordItem => unreachable!(),
331        StrippedItem(inner) => {
332            match inner.as_ref() {
333                ModuleItem(m) => ItemEnum::Module(Module {
334                    is_crate,
335                    items: renderer.ids(&m.items),
336                    is_stripped: true,
337                }),
338                // `convert_item` early returns `None` for stripped items we're not including
339                _ => unreachable!(),
340            }
341        }
342        ExternCrateItem { src } => ItemEnum::ExternCrate {
343            name: name.as_ref().unwrap().to_string(),
344            rename: src.map(|x| x.to_string()),
345        },
346    }
347}
348
349impl FromClean<clean::Struct> for Struct {
350    fn from_clean(struct_: &clean::Struct, renderer: &JsonRenderer<'_>) -> Self {
351        let has_stripped_fields = struct_.has_stripped_entries();
352        let clean::Struct { ctor_kind, generics, fields } = struct_;
353
354        let kind = match ctor_kind {
355            Some(CtorKind::Fn) => StructKind::Tuple(renderer.ids_keeping_stripped(&fields)),
356            Some(CtorKind::Const) => {
357                assert!(fields.is_empty());
358                StructKind::Unit
359            }
360            None => StructKind::Plain { fields: renderer.ids(&fields), has_stripped_fields },
361        };
362
363        Struct {
364            kind,
365            generics: generics.into_json(renderer),
366            impls: Vec::new(), // Added in JsonRenderer::item
367        }
368    }
369}
370
371impl FromClean<clean::Union> for Union {
372    fn from_clean(union_: &clean::Union, renderer: &JsonRenderer<'_>) -> Self {
373        let has_stripped_fields = union_.has_stripped_entries();
374        let clean::Union { generics, fields } = union_;
375        Union {
376            generics: generics.into_json(renderer),
377            has_stripped_fields,
378            fields: renderer.ids(&fields),
379            impls: Vec::new(), // Added in JsonRenderer::item
380        }
381    }
382}
383
384impl FromClean<rustc_hir::FnHeader> for FunctionHeader {
385    fn from_clean(header: &rustc_hir::FnHeader, renderer: &JsonRenderer<'_>) -> Self {
386        FunctionHeader {
387            is_async: header.is_async(),
388            is_const: header.is_const(),
389            is_unsafe: header.is_unsafe(),
390            abi: header.abi.into_json(renderer),
391        }
392    }
393}
394
395impl FromClean<ExternAbi> for Abi {
396    fn from_clean(a: &ExternAbi, _renderer: &JsonRenderer<'_>) -> Self {
397        match *a {
398            ExternAbi::Rust => Abi::Rust,
399            ExternAbi::C { unwind } => Abi::C { unwind },
400            ExternAbi::Cdecl { unwind } => Abi::Cdecl { unwind },
401            ExternAbi::Stdcall { unwind } => Abi::Stdcall { unwind },
402            ExternAbi::Fastcall { unwind } => Abi::Fastcall { unwind },
403            ExternAbi::Aapcs { unwind } => Abi::Aapcs { unwind },
404            ExternAbi::Win64 { unwind } => Abi::Win64 { unwind },
405            ExternAbi::SysV64 { unwind } => Abi::SysV64 { unwind },
406            ExternAbi::System { unwind } => Abi::System { unwind },
407            _ => Abi::Other(a.to_string()),
408        }
409    }
410}
411
412impl FromClean<clean::Lifetime> for String {
413    fn from_clean(l: &clean::Lifetime, _renderer: &JsonRenderer<'_>) -> String {
414        l.0.to_string()
415    }
416}
417
418impl FromClean<clean::Generics> for Generics {
419    fn from_clean(generics: &clean::Generics, renderer: &JsonRenderer<'_>) -> Self {
420        Generics {
421            params: generics.params.into_json(renderer),
422            where_predicates: generics.where_predicates.into_json(renderer),
423        }
424    }
425}
426
427impl FromClean<clean::GenericParamDef> for GenericParamDef {
428    fn from_clean(generic_param: &clean::GenericParamDef, renderer: &JsonRenderer<'_>) -> Self {
429        GenericParamDef {
430            name: generic_param.name.to_string(),
431            kind: generic_param.kind.into_json(renderer),
432        }
433    }
434}
435
436impl FromClean<clean::GenericParamDefKind> for GenericParamDefKind {
437    fn from_clean(kind: &clean::GenericParamDefKind, renderer: &JsonRenderer<'_>) -> Self {
438        use clean::GenericParamDefKind::*;
439        match kind {
440            Lifetime { outlives } => {
441                GenericParamDefKind::Lifetime { outlives: outlives.into_json(renderer) }
442            }
443            Type { bounds, default, synthetic } => GenericParamDefKind::Type {
444                bounds: bounds.into_json(renderer),
445                default: default.into_json(renderer),
446                is_synthetic: *synthetic,
447            },
448            Const { ty, default, synthetic: _ } => GenericParamDefKind::Const {
449                type_: ty.into_json(renderer),
450                default: default.as_ref().map(|x| x.as_ref().clone()),
451            },
452        }
453    }
454}
455
456impl FromClean<clean::WherePredicate> for WherePredicate {
457    fn from_clean(predicate: &clean::WherePredicate, renderer: &JsonRenderer<'_>) -> Self {
458        use clean::WherePredicate::*;
459        match predicate {
460            BoundPredicate { ty, bounds, bound_params } => WherePredicate::BoundPredicate {
461                type_: ty.into_json(renderer),
462                bounds: bounds.into_json(renderer),
463                generic_params: bound_params.into_json(renderer),
464            },
465            RegionPredicate { lifetime, bounds } => WherePredicate::LifetimePredicate {
466                lifetime: lifetime.into_json(renderer),
467                outlives: bounds
468                    .iter()
469                    .map(|bound| match bound {
470                        clean::GenericBound::Outlives(lt) => lt.into_json(renderer),
471                        _ => bug!("found non-outlives-bound on lifetime predicate"),
472                    })
473                    .collect(),
474            },
475            EqPredicate { lhs, rhs } => WherePredicate::EqPredicate {
476                // The LHS currently has type `Type` but it should be a `QualifiedPath` since it may
477                // refer to an associated const. However, `EqPredicate` shouldn't exist in the first
478                // place: <https://github.com/rust-lang/rust/141368>.
479                lhs: lhs.into_json(renderer),
480                rhs: rhs.into_json(renderer),
481            },
482        }
483    }
484}
485
486impl FromClean<clean::GenericBound> for GenericBound {
487    fn from_clean(bound: &clean::GenericBound, renderer: &JsonRenderer<'_>) -> Self {
488        use clean::GenericBound::*;
489        match bound {
490            TraitBound(clean::PolyTrait { trait_, generic_params }, modifier) => {
491                GenericBound::TraitBound {
492                    trait_: trait_.into_json(renderer),
493                    generic_params: generic_params.into_json(renderer),
494                    modifier: modifier.into_json(renderer),
495                }
496            }
497            Outlives(lifetime) => GenericBound::Outlives(lifetime.into_json(renderer)),
498            Use(args) => GenericBound::Use(
499                args.iter()
500                    .map(|arg| match arg {
501                        clean::PreciseCapturingArg::Lifetime(lt) => {
502                            PreciseCapturingArg::Lifetime(lt.into_json(renderer))
503                        }
504                        clean::PreciseCapturingArg::Param(param) => {
505                            PreciseCapturingArg::Param(param.to_string())
506                        }
507                    })
508                    .collect(),
509            ),
510        }
511    }
512}
513
514impl FromClean<rustc_hir::TraitBoundModifiers> for TraitBoundModifier {
515    fn from_clean(
516        modifiers: &rustc_hir::TraitBoundModifiers,
517        _renderer: &JsonRenderer<'_>,
518    ) -> Self {
519        use rustc_hir as hir;
520        let hir::TraitBoundModifiers { constness, polarity } = modifiers;
521        match (constness, polarity) {
522            (hir::BoundConstness::Never, hir::BoundPolarity::Positive) => TraitBoundModifier::None,
523            (hir::BoundConstness::Never, hir::BoundPolarity::Maybe(_)) => TraitBoundModifier::Maybe,
524            (hir::BoundConstness::Maybe(_), hir::BoundPolarity::Positive) => {
525                TraitBoundModifier::MaybeConst
526            }
527            // FIXME: Fill out the rest of this matrix.
528            _ => TraitBoundModifier::None,
529        }
530    }
531}
532
533impl FromClean<clean::Type> for Type {
534    fn from_clean(ty: &clean::Type, renderer: &JsonRenderer<'_>) -> Self {
535        use clean::Type::{
536            Array, BareFunction, BorrowedRef, Generic, ImplTrait, Infer, Primitive, QPath,
537            RawPointer, SelfTy, Slice, Tuple, UnsafeBinder,
538        };
539
540        match ty {
541            clean::Type::Path { path } => Type::ResolvedPath(path.into_json(renderer)),
542            clean::Type::DynTrait(bounds, lt) => Type::DynTrait(DynTrait {
543                lifetime: lt.into_json(renderer),
544                traits: bounds.into_json(renderer),
545            }),
546            Generic(s) => Type::Generic(s.to_string()),
547            // FIXME: add dedicated variant to json Type?
548            SelfTy => Type::Generic("Self".to_owned()),
549            Primitive(p) => Type::Primitive(p.as_sym().to_string()),
550            BareFunction(f) => Type::FunctionPointer(Box::new(f.into_json(renderer))),
551            Tuple(t) => Type::Tuple(t.into_json(renderer)),
552            Slice(t) => Type::Slice(Box::new(t.into_json(renderer))),
553            Array(t, s) => {
554                Type::Array { type_: Box::new(t.into_json(renderer)), len: s.to_string() }
555            }
556            clean::Type::Pat(t, p) => Type::Pat {
557                type_: Box::new(t.into_json(renderer)),
558                __pat_unstable_do_not_use: p.to_string(),
559            },
560            ImplTrait(g) => Type::ImplTrait(g.into_json(renderer)),
561            Infer => Type::Infer,
562            RawPointer(mutability, type_) => Type::RawPointer {
563                is_mutable: *mutability == ast::Mutability::Mut,
564                type_: Box::new(type_.into_json(renderer)),
565            },
566            BorrowedRef { lifetime, mutability, type_ } => Type::BorrowedRef {
567                lifetime: lifetime.into_json(renderer),
568                is_mutable: *mutability == ast::Mutability::Mut,
569                type_: Box::new(type_.into_json(renderer)),
570            },
571            QPath(qpath) => qpath.into_json(renderer),
572            // FIXME(unsafe_binder): Implement rustdoc-json.
573            UnsafeBinder(_) => todo!(),
574        }
575    }
576}
577
578impl FromClean<clean::Path> for Path {
579    fn from_clean(path: &clean::Path, renderer: &JsonRenderer<'_>) -> Self {
580        Path {
581            path: path.whole_name(),
582            id: renderer.id_from_item_default(path.def_id().into()),
583            args: {
584                if let Some((final_seg, rest_segs)) = path.segments.split_last() {
585                    // In general, `clean::Path` can hold things like
586                    // `std::vec::Vec::<u32>::new`, where generic args appear
587                    // in a middle segment. But for the places where `Path` is
588                    // used by rustdoc-json-types, generic args can only be
589                    // used in the final segment, e.g. `std::vec::Vec<u32>`. So
590                    // check that the non-final segments have no generic args.
591                    assert!(rest_segs.iter().all(|seg| seg.args.is_empty()));
592                    final_seg.args.into_json(renderer)
593                } else {
594                    None // no generics on any segments because there are no segments
595                }
596            },
597        }
598    }
599}
600
601impl FromClean<clean::QPathData> for Type {
602    fn from_clean(qpath: &clean::QPathData, renderer: &JsonRenderer<'_>) -> Self {
603        let clean::QPathData { assoc, self_type, should_fully_qualify: _, trait_ } = qpath;
604
605        Self::QualifiedPath {
606            name: assoc.name.to_string(),
607            args: assoc.args.into_json(renderer),
608            self_type: Box::new(self_type.into_json(renderer)),
609            trait_: trait_.into_json(renderer),
610        }
611    }
612}
613
614impl FromClean<clean::Term> for Term {
615    fn from_clean(term: &clean::Term, renderer: &JsonRenderer<'_>) -> Self {
616        match term {
617            clean::Term::Type(ty) => Term::Type(ty.into_json(renderer)),
618            clean::Term::Constant(c) => Term::Constant(c.into_json(renderer)),
619        }
620    }
621}
622
623impl FromClean<clean::BareFunctionDecl> for FunctionPointer {
624    fn from_clean(bare_decl: &clean::BareFunctionDecl, renderer: &JsonRenderer<'_>) -> Self {
625        let clean::BareFunctionDecl { safety, generic_params, decl, abi } = bare_decl;
626        FunctionPointer {
627            header: FunctionHeader {
628                is_unsafe: safety.is_unsafe(),
629                is_const: false,
630                is_async: false,
631                abi: abi.into_json(renderer),
632            },
633            generic_params: generic_params.into_json(renderer),
634            sig: decl.into_json(renderer),
635        }
636    }
637}
638
639impl FromClean<clean::FnDecl> for FunctionSignature {
640    fn from_clean(decl: &clean::FnDecl, renderer: &JsonRenderer<'_>) -> Self {
641        let clean::FnDecl { inputs, output, c_variadic } = decl;
642        FunctionSignature {
643            inputs: inputs
644                .into_iter()
645                .map(|param| {
646                    // `_` is the most sensible name for missing param names.
647                    let name = param.name.unwrap_or(kw::Underscore).to_string();
648                    let type_ = param.type_.into_json(renderer);
649                    (name, type_)
650                })
651                .collect(),
652            output: if output.is_unit() { None } else { Some(output.into_json(renderer)) },
653            is_c_variadic: *c_variadic,
654        }
655    }
656}
657
658impl FromClean<clean::Trait> for Trait {
659    fn from_clean(trait_: &clean::Trait, renderer: &JsonRenderer<'_>) -> Self {
660        let tcx = renderer.tcx;
661        let is_auto = trait_.is_auto(tcx);
662        let is_unsafe = trait_.safety(tcx).is_unsafe();
663        let is_dyn_compatible = trait_.is_dyn_compatible(tcx);
664        let clean::Trait { items, generics, bounds, .. } = trait_;
665        Trait {
666            is_auto,
667            is_unsafe,
668            is_dyn_compatible,
669            items: renderer.ids(&items),
670            generics: generics.into_json(renderer),
671            bounds: bounds.into_json(renderer),
672            implementations: Vec::new(), // Added in JsonRenderer::item
673        }
674    }
675}
676
677impl FromClean<clean::PolyTrait> for PolyTrait {
678    fn from_clean(
679        clean::PolyTrait { trait_, generic_params }: &clean::PolyTrait,
680        renderer: &JsonRenderer<'_>,
681    ) -> Self {
682        PolyTrait {
683            trait_: trait_.into_json(renderer),
684            generic_params: generic_params.into_json(renderer),
685        }
686    }
687}
688
689impl FromClean<clean::Impl> for Impl {
690    fn from_clean(impl_: &clean::Impl, renderer: &JsonRenderer<'_>) -> Self {
691        let provided_trait_methods = impl_.provided_trait_methods(renderer.tcx);
692        let clean::Impl { safety, generics, trait_, for_, items, polarity, kind } = impl_;
693        // FIXME: use something like ImplKind in JSON?
694        let (is_synthetic, blanket_impl) = match kind {
695            clean::ImplKind::Normal | clean::ImplKind::FakeVariadic => (false, None),
696            clean::ImplKind::Auto => (true, None),
697            clean::ImplKind::Blanket(ty) => (false, Some(ty)),
698        };
699        let is_negative = match polarity {
700            ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => false,
701            ty::ImplPolarity::Negative => true,
702        };
703        Impl {
704            is_unsafe: safety.is_unsafe(),
705            generics: generics.into_json(renderer),
706            provided_trait_methods: provided_trait_methods
707                .into_iter()
708                .map(|x| x.to_string())
709                .collect(),
710            trait_: trait_.into_json(renderer),
711            for_: for_.into_json(renderer),
712            items: renderer.ids(&items),
713            is_negative,
714            is_synthetic,
715            blanket_impl: blanket_impl.map(|x| x.into_json(renderer)),
716        }
717    }
718}
719
720pub(crate) fn from_clean_function(
721    clean::Function { decl, generics }: &clean::Function,
722    has_body: bool,
723    header: rustc_hir::FnHeader,
724    renderer: &JsonRenderer<'_>,
725) -> Function {
726    Function {
727        sig: decl.into_json(renderer),
728        generics: generics.into_json(renderer),
729        header: header.into_json(renderer),
730        has_body,
731    }
732}
733
734impl FromClean<clean::Enum> for Enum {
735    fn from_clean(enum_: &clean::Enum, renderer: &JsonRenderer<'_>) -> Self {
736        let has_stripped_variants = enum_.has_stripped_entries();
737        let clean::Enum { variants, generics } = enum_;
738        Enum {
739            generics: generics.into_json(renderer),
740            has_stripped_variants,
741            variants: renderer.ids(&variants.as_slice().raw),
742            impls: Vec::new(), // Added in JsonRenderer::item
743        }
744    }
745}
746
747impl FromClean<clean::Variant> for Variant {
748    fn from_clean(variant: &clean::Variant, renderer: &JsonRenderer<'_>) -> Self {
749        use clean::VariantKind::*;
750
751        let discriminant = variant.discriminant.into_json(renderer);
752
753        let kind = match &variant.kind {
754            CLike => VariantKind::Plain,
755            Tuple(fields) => VariantKind::Tuple(renderer.ids_keeping_stripped(&fields)),
756            Struct(s) => VariantKind::Struct {
757                has_stripped_fields: s.has_stripped_entries(),
758                fields: renderer.ids(&s.fields),
759            },
760        };
761
762        Variant { kind, discriminant }
763    }
764}
765
766impl FromClean<clean::Discriminant> for Discriminant {
767    fn from_clean(disr: &clean::Discriminant, renderer: &JsonRenderer<'_>) -> Self {
768        let tcx = renderer.tcx;
769        Discriminant {
770            // expr is only none if going through the inlining path, which gets
771            // `rustc_middle` types, not `rustc_hir`, but because JSON never inlines
772            // the expr is always some.
773            expr: disr.expr(tcx).unwrap(),
774            value: disr.value(tcx, false),
775        }
776    }
777}
778
779impl FromClean<clean::Import> for Use {
780    fn from_clean(import: &clean::Import, renderer: &JsonRenderer<'_>) -> Self {
781        use clean::ImportKind::*;
782        let (name, is_glob) = match import.kind {
783            Simple(s) => (s.to_string(), false),
784            Glob => (import.source.path.last_opt().unwrap_or(sym::asterisk).to_string(), true),
785        };
786        Use {
787            source: import.source.path.whole_name(),
788            name,
789            id: import.source.did.map(ItemId::from).map(|i| renderer.id_from_item_default(i)),
790            is_glob,
791        }
792    }
793}
794
795impl FromClean<clean::ProcMacro> for ProcMacro {
796    fn from_clean(mac: &clean::ProcMacro, renderer: &JsonRenderer<'_>) -> Self {
797        ProcMacro {
798            kind: mac.kind.into_json(renderer),
799            helpers: mac.helpers.iter().map(|x| x.to_string()).collect(),
800        }
801    }
802}
803
804impl FromClean<rustc_span::hygiene::MacroKind> for MacroKind {
805    fn from_clean(kind: &rustc_span::hygiene::MacroKind, _renderer: &JsonRenderer<'_>) -> Self {
806        use rustc_span::hygiene::MacroKind::*;
807        match kind {
808            Bang => MacroKind::Bang,
809            Attr => MacroKind::Attr,
810            Derive => MacroKind::Derive,
811        }
812    }
813}
814
815impl FromClean<clean::TypeAlias> for TypeAlias {
816    fn from_clean(type_alias: &clean::TypeAlias, renderer: &JsonRenderer<'_>) -> Self {
817        let clean::TypeAlias { type_, generics, item_type: _, inner_type: _ } = type_alias;
818        TypeAlias { type_: type_.into_json(renderer), generics: generics.into_json(renderer) }
819    }
820}
821
822fn from_clean_static(
823    stat: &clean::Static,
824    safety: rustc_hir::Safety,
825    renderer: &JsonRenderer<'_>,
826) -> Static {
827    let tcx = renderer.tcx;
828    Static {
829        type_: stat.type_.as_ref().into_json(renderer),
830        is_mutable: stat.mutability == ast::Mutability::Mut,
831        is_unsafe: safety.is_unsafe(),
832        expr: stat
833            .expr
834            .map(|e| rendered_const(tcx, tcx.hir_body(e), tcx.hir_body_owner_def_id(e)))
835            .unwrap_or_default(),
836    }
837}
838
839impl FromClean<clean::TraitAlias> for TraitAlias {
840    fn from_clean(alias: &clean::TraitAlias, renderer: &JsonRenderer<'_>) -> Self {
841        TraitAlias {
842            generics: alias.generics.into_json(renderer),
843            params: alias.bounds.into_json(renderer),
844        }
845    }
846}
847
848impl FromClean<ItemType> for ItemKind {
849    fn from_clean(kind: &ItemType, _renderer: &JsonRenderer<'_>) -> Self {
850        use ItemType::*;
851        match kind {
852            Module => ItemKind::Module,
853            ExternCrate => ItemKind::ExternCrate,
854            Import => ItemKind::Use,
855            Struct => ItemKind::Struct,
856            Union => ItemKind::Union,
857            Enum => ItemKind::Enum,
858            Function | TyMethod | Method => ItemKind::Function,
859            TypeAlias => ItemKind::TypeAlias,
860            Static => ItemKind::Static,
861            Constant => ItemKind::Constant,
862            Trait => ItemKind::Trait,
863            Impl => ItemKind::Impl,
864            StructField => ItemKind::StructField,
865            Variant => ItemKind::Variant,
866            Macro => ItemKind::Macro,
867            Primitive => ItemKind::Primitive,
868            AssocConst => ItemKind::AssocConst,
869            AssocType => ItemKind::AssocType,
870            ForeignType => ItemKind::ExternType,
871            Keyword => ItemKind::Keyword,
872            TraitAlias => ItemKind::TraitAlias,
873            ProcAttribute => ItemKind::ProcAttribute,
874            ProcDerive => ItemKind::ProcDerive,
875        }
876    }
877}