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(args: &clean::GenericArgs, renderer: &JsonRenderer<'_>) -> Self {
198        use clean::GenericArgs::*;
199        if args.is_empty() {
200            return None;
201        }
202        Some(Box::new(match args {
203            AngleBracketed { args, constraints } => GenericArgs::AngleBracketed {
204                args: args.into_json(renderer),
205                constraints: constraints.into_json(renderer),
206            },
207            Parenthesized { inputs, output } => GenericArgs::Parenthesized {
208                inputs: inputs.into_json(renderer),
209                output: output.into_json(renderer),
210            },
211            ReturnTypeNotation => GenericArgs::ReturnTypeNotation,
212        }))
213    }
214}
215
216impl FromClean<clean::GenericArg> for GenericArg {
217    fn from_clean(arg: &clean::GenericArg, renderer: &JsonRenderer<'_>) -> Self {
218        use clean::GenericArg::*;
219        match arg {
220            Lifetime(l) => GenericArg::Lifetime(l.into_json(renderer)),
221            Type(t) => GenericArg::Type(t.into_json(renderer)),
222            Const(box c) => GenericArg::Const(c.into_json(renderer)),
223            Infer => GenericArg::Infer,
224        }
225    }
226}
227
228impl FromClean<clean::ConstantKind> for Constant {
229    // FIXME(generic_const_items): Add support for generic const items.
230    fn from_clean(constant: &clean::ConstantKind, renderer: &JsonRenderer<'_>) -> Self {
231        let tcx = renderer.tcx;
232        let expr = constant.expr(tcx);
233        let value = constant.value(tcx);
234        let is_literal = constant.is_literal(tcx);
235        Constant { expr, value, is_literal }
236    }
237}
238
239impl FromClean<clean::AssocItemConstraint> for AssocItemConstraint {
240    fn from_clean(constraint: &clean::AssocItemConstraint, renderer: &JsonRenderer<'_>) -> Self {
241        AssocItemConstraint {
242            name: constraint.assoc.name.to_string(),
243            args: constraint.assoc.args.into_json(renderer),
244            binding: constraint.kind.into_json(renderer),
245        }
246    }
247}
248
249impl FromClean<clean::AssocItemConstraintKind> for AssocItemConstraintKind {
250    fn from_clean(kind: &clean::AssocItemConstraintKind, renderer: &JsonRenderer<'_>) -> Self {
251        use clean::AssocItemConstraintKind::*;
252        match kind {
253            Equality { term } => AssocItemConstraintKind::Equality(term.into_json(renderer)),
254            Bound { bounds } => AssocItemConstraintKind::Constraint(bounds.into_json(renderer)),
255        }
256    }
257}
258
259fn from_clean_item(item: &clean::Item, renderer: &JsonRenderer<'_>) -> ItemEnum {
260    use clean::ItemKind::*;
261    let name = item.name;
262    let is_crate = item.is_crate();
263    let header = item.fn_header(renderer.tcx);
264
265    match &item.inner.kind {
266        ModuleItem(m) => {
267            ItemEnum::Module(Module { is_crate, items: renderer.ids(&m.items), is_stripped: false })
268        }
269        ImportItem(i) => ItemEnum::Use(i.into_json(renderer)),
270        StructItem(s) => ItemEnum::Struct(s.into_json(renderer)),
271        UnionItem(u) => ItemEnum::Union(u.into_json(renderer)),
272        StructFieldItem(f) => ItemEnum::StructField(f.into_json(renderer)),
273        EnumItem(e) => ItemEnum::Enum(e.into_json(renderer)),
274        VariantItem(v) => ItemEnum::Variant(v.into_json(renderer)),
275        FunctionItem(f) => {
276            ItemEnum::Function(from_clean_function(f, true, header.unwrap(), renderer))
277        }
278        ForeignFunctionItem(f, _) => {
279            ItemEnum::Function(from_clean_function(f, false, header.unwrap(), renderer))
280        }
281        TraitItem(t) => ItemEnum::Trait(t.into_json(renderer)),
282        TraitAliasItem(t) => ItemEnum::TraitAlias(t.into_json(renderer)),
283        MethodItem(m, _) => {
284            ItemEnum::Function(from_clean_function(m, true, header.unwrap(), renderer))
285        }
286        RequiredMethodItem(m) => {
287            ItemEnum::Function(from_clean_function(m, false, header.unwrap(), renderer))
288        }
289        ImplItem(i) => ItemEnum::Impl(i.into_json(renderer)),
290        StaticItem(s) => ItemEnum::Static(from_clean_static(s, rustc_hir::Safety::Safe, renderer)),
291        ForeignStaticItem(s, safety) => ItemEnum::Static(from_clean_static(s, *safety, renderer)),
292        ForeignTypeItem => ItemEnum::ExternType,
293        TypeAliasItem(t) => ItemEnum::TypeAlias(t.into_json(renderer)),
294        // FIXME(generic_const_items): Add support for generic free consts
295        ConstantItem(ci) => ItemEnum::Constant {
296            type_: ci.type_.into_json(renderer),
297            const_: ci.kind.into_json(renderer),
298        },
299        MacroItem(m) => ItemEnum::Macro(m.source.clone()),
300        ProcMacroItem(m) => ItemEnum::ProcMacro(m.into_json(renderer)),
301        PrimitiveItem(p) => {
302            ItemEnum::Primitive(Primitive {
303                name: p.as_sym().to_string(),
304                impls: Vec::new(), // Added in JsonRenderer::item
305            })
306        }
307        // FIXME(generic_const_items): Add support for generic associated consts.
308        RequiredAssocConstItem(_generics, ty) => {
309            ItemEnum::AssocConst { type_: ty.into_json(renderer), value: None }
310        }
311        // FIXME(generic_const_items): Add support for generic associated consts.
312        ProvidedAssocConstItem(ci) | ImplAssocConstItem(ci) => ItemEnum::AssocConst {
313            type_: ci.type_.into_json(renderer),
314            value: Some(ci.kind.expr(renderer.tcx)),
315        },
316        RequiredAssocTypeItem(g, b) => ItemEnum::AssocType {
317            generics: g.into_json(renderer),
318            bounds: b.into_json(renderer),
319            type_: None,
320        },
321        AssocTypeItem(t, b) => ItemEnum::AssocType {
322            generics: t.generics.into_json(renderer),
323            bounds: b.into_json(renderer),
324            type_: Some(t.item_type.as_ref().unwrap_or(&t.type_).into_json(renderer)),
325        },
326        // `convert_item` early returns `None` for stripped items and keywords.
327        KeywordItem => unreachable!(),
328        StrippedItem(inner) => {
329            match inner.as_ref() {
330                ModuleItem(m) => ItemEnum::Module(Module {
331                    is_crate,
332                    items: renderer.ids(&m.items),
333                    is_stripped: true,
334                }),
335                // `convert_item` early returns `None` for stripped items we're not including
336                _ => unreachable!(),
337            }
338        }
339        ExternCrateItem { src } => ItemEnum::ExternCrate {
340            name: name.as_ref().unwrap().to_string(),
341            rename: src.map(|x| x.to_string()),
342        },
343    }
344}
345
346impl FromClean<clean::Struct> for Struct {
347    fn from_clean(struct_: &clean::Struct, renderer: &JsonRenderer<'_>) -> Self {
348        let has_stripped_fields = struct_.has_stripped_entries();
349        let clean::Struct { ctor_kind, generics, fields } = struct_;
350
351        let kind = match ctor_kind {
352            Some(CtorKind::Fn) => StructKind::Tuple(renderer.ids_keeping_stripped(&fields)),
353            Some(CtorKind::Const) => {
354                assert!(fields.is_empty());
355                StructKind::Unit
356            }
357            None => StructKind::Plain { fields: renderer.ids(&fields), has_stripped_fields },
358        };
359
360        Struct {
361            kind,
362            generics: generics.into_json(renderer),
363            impls: Vec::new(), // Added in JsonRenderer::item
364        }
365    }
366}
367
368impl FromClean<clean::Union> for Union {
369    fn from_clean(union_: &clean::Union, renderer: &JsonRenderer<'_>) -> Self {
370        let has_stripped_fields = union_.has_stripped_entries();
371        let clean::Union { generics, fields } = union_;
372        Union {
373            generics: generics.into_json(renderer),
374            has_stripped_fields,
375            fields: renderer.ids(&fields),
376            impls: Vec::new(), // Added in JsonRenderer::item
377        }
378    }
379}
380
381impl FromClean<rustc_hir::FnHeader> for FunctionHeader {
382    fn from_clean(header: &rustc_hir::FnHeader, renderer: &JsonRenderer<'_>) -> Self {
383        FunctionHeader {
384            is_async: header.is_async(),
385            is_const: header.is_const(),
386            is_unsafe: header.is_unsafe(),
387            abi: header.abi.into_json(renderer),
388        }
389    }
390}
391
392impl FromClean<ExternAbi> for Abi {
393    fn from_clean(a: &ExternAbi, _renderer: &JsonRenderer<'_>) -> Self {
394        match *a {
395            ExternAbi::Rust => Abi::Rust,
396            ExternAbi::C { unwind } => Abi::C { unwind },
397            ExternAbi::Cdecl { unwind } => Abi::Cdecl { unwind },
398            ExternAbi::Stdcall { unwind } => Abi::Stdcall { unwind },
399            ExternAbi::Fastcall { unwind } => Abi::Fastcall { unwind },
400            ExternAbi::Aapcs { unwind } => Abi::Aapcs { unwind },
401            ExternAbi::Win64 { unwind } => Abi::Win64 { unwind },
402            ExternAbi::SysV64 { unwind } => Abi::SysV64 { unwind },
403            ExternAbi::System { unwind } => Abi::System { unwind },
404            _ => Abi::Other(a.to_string()),
405        }
406    }
407}
408
409impl FromClean<clean::Lifetime> for String {
410    fn from_clean(l: &clean::Lifetime, _renderer: &JsonRenderer<'_>) -> String {
411        l.0.to_string()
412    }
413}
414
415impl FromClean<clean::Generics> for Generics {
416    fn from_clean(generics: &clean::Generics, renderer: &JsonRenderer<'_>) -> Self {
417        Generics {
418            params: generics.params.into_json(renderer),
419            where_predicates: generics.where_predicates.into_json(renderer),
420        }
421    }
422}
423
424impl FromClean<clean::GenericParamDef> for GenericParamDef {
425    fn from_clean(generic_param: &clean::GenericParamDef, renderer: &JsonRenderer<'_>) -> Self {
426        GenericParamDef {
427            name: generic_param.name.to_string(),
428            kind: generic_param.kind.into_json(renderer),
429        }
430    }
431}
432
433impl FromClean<clean::GenericParamDefKind> for GenericParamDefKind {
434    fn from_clean(kind: &clean::GenericParamDefKind, renderer: &JsonRenderer<'_>) -> Self {
435        use clean::GenericParamDefKind::*;
436        match kind {
437            Lifetime { outlives } => {
438                GenericParamDefKind::Lifetime { outlives: outlives.into_json(renderer) }
439            }
440            Type { bounds, default, synthetic } => GenericParamDefKind::Type {
441                bounds: bounds.into_json(renderer),
442                default: default.into_json(renderer),
443                is_synthetic: *synthetic,
444            },
445            Const { ty, default, synthetic: _ } => GenericParamDefKind::Const {
446                type_: ty.into_json(renderer),
447                default: default.as_ref().map(|x| x.as_ref().clone()),
448            },
449        }
450    }
451}
452
453impl FromClean<clean::WherePredicate> for WherePredicate {
454    fn from_clean(predicate: &clean::WherePredicate, renderer: &JsonRenderer<'_>) -> Self {
455        use clean::WherePredicate::*;
456        match predicate {
457            BoundPredicate { ty, bounds, bound_params } => WherePredicate::BoundPredicate {
458                type_: ty.into_json(renderer),
459                bounds: bounds.into_json(renderer),
460                generic_params: bound_params.into_json(renderer),
461            },
462            RegionPredicate { lifetime, bounds } => WherePredicate::LifetimePredicate {
463                lifetime: lifetime.into_json(renderer),
464                outlives: bounds
465                    .iter()
466                    .map(|bound| match bound {
467                        clean::GenericBound::Outlives(lt) => lt.into_json(renderer),
468                        _ => bug!("found non-outlives-bound on lifetime predicate"),
469                    })
470                    .collect(),
471            },
472            EqPredicate { lhs, rhs } => WherePredicate::EqPredicate {
473                // The LHS currently has type `Type` but it should be a `QualifiedPath` since it may
474                // refer to an associated const. However, `EqPredicate` shouldn't exist in the first
475                // place: <https://github.com/rust-lang/rust/141368>.
476                lhs: lhs.into_json(renderer),
477                rhs: rhs.into_json(renderer),
478            },
479        }
480    }
481}
482
483impl FromClean<clean::GenericBound> for GenericBound {
484    fn from_clean(bound: &clean::GenericBound, renderer: &JsonRenderer<'_>) -> Self {
485        use clean::GenericBound::*;
486        match bound {
487            TraitBound(clean::PolyTrait { trait_, generic_params }, modifier) => {
488                GenericBound::TraitBound {
489                    trait_: trait_.into_json(renderer),
490                    generic_params: generic_params.into_json(renderer),
491                    modifier: modifier.into_json(renderer),
492                }
493            }
494            Outlives(lifetime) => GenericBound::Outlives(lifetime.into_json(renderer)),
495            Use(args) => GenericBound::Use(
496                args.iter()
497                    .map(|arg| match arg {
498                        clean::PreciseCapturingArg::Lifetime(lt) => {
499                            PreciseCapturingArg::Lifetime(lt.into_json(renderer))
500                        }
501                        clean::PreciseCapturingArg::Param(param) => {
502                            PreciseCapturingArg::Param(param.to_string())
503                        }
504                    })
505                    .collect(),
506            ),
507        }
508    }
509}
510
511impl FromClean<rustc_hir::TraitBoundModifiers> for TraitBoundModifier {
512    fn from_clean(
513        modifiers: &rustc_hir::TraitBoundModifiers,
514        _renderer: &JsonRenderer<'_>,
515    ) -> Self {
516        use rustc_hir as hir;
517        let hir::TraitBoundModifiers { constness, polarity } = modifiers;
518        match (constness, polarity) {
519            (hir::BoundConstness::Never, hir::BoundPolarity::Positive) => TraitBoundModifier::None,
520            (hir::BoundConstness::Never, hir::BoundPolarity::Maybe(_)) => TraitBoundModifier::Maybe,
521            (hir::BoundConstness::Maybe(_), hir::BoundPolarity::Positive) => {
522                TraitBoundModifier::MaybeConst
523            }
524            // FIXME: Fill out the rest of this matrix.
525            _ => TraitBoundModifier::None,
526        }
527    }
528}
529
530impl FromClean<clean::Type> for Type {
531    fn from_clean(ty: &clean::Type, renderer: &JsonRenderer<'_>) -> Self {
532        use clean::Type::{
533            Array, BareFunction, BorrowedRef, Generic, ImplTrait, Infer, Primitive, QPath,
534            RawPointer, SelfTy, Slice, Tuple, UnsafeBinder,
535        };
536
537        match ty {
538            clean::Type::Path { path } => Type::ResolvedPath(path.into_json(renderer)),
539            clean::Type::DynTrait(bounds, lt) => Type::DynTrait(DynTrait {
540                lifetime: lt.into_json(renderer),
541                traits: bounds.into_json(renderer),
542            }),
543            Generic(s) => Type::Generic(s.to_string()),
544            // FIXME: add dedicated variant to json Type?
545            SelfTy => Type::Generic("Self".to_owned()),
546            Primitive(p) => Type::Primitive(p.as_sym().to_string()),
547            BareFunction(f) => Type::FunctionPointer(Box::new(f.into_json(renderer))),
548            Tuple(t) => Type::Tuple(t.into_json(renderer)),
549            Slice(t) => Type::Slice(Box::new(t.into_json(renderer))),
550            Array(t, s) => {
551                Type::Array { type_: Box::new(t.into_json(renderer)), len: s.to_string() }
552            }
553            clean::Type::Pat(t, p) => Type::Pat {
554                type_: Box::new(t.into_json(renderer)),
555                __pat_unstable_do_not_use: p.to_string(),
556            },
557            ImplTrait(g) => Type::ImplTrait(g.into_json(renderer)),
558            Infer => Type::Infer,
559            RawPointer(mutability, type_) => Type::RawPointer {
560                is_mutable: *mutability == ast::Mutability::Mut,
561                type_: Box::new(type_.into_json(renderer)),
562            },
563            BorrowedRef { lifetime, mutability, type_ } => Type::BorrowedRef {
564                lifetime: lifetime.into_json(renderer),
565                is_mutable: *mutability == ast::Mutability::Mut,
566                type_: Box::new(type_.into_json(renderer)),
567            },
568            QPath(qpath) => qpath.into_json(renderer),
569            // FIXME(unsafe_binder): Implement rustdoc-json.
570            UnsafeBinder(_) => todo!(),
571        }
572    }
573}
574
575impl FromClean<clean::Path> for Path {
576    fn from_clean(path: &clean::Path, renderer: &JsonRenderer<'_>) -> Self {
577        Path {
578            path: path.whole_name(),
579            id: renderer.id_from_item_default(path.def_id().into()),
580            args: {
581                if let Some((final_seg, rest_segs)) = path.segments.split_last() {
582                    // In general, `clean::Path` can hold things like
583                    // `std::vec::Vec::<u32>::new`, where generic args appear
584                    // in a middle segment. But for the places where `Path` is
585                    // used by rustdoc-json-types, generic args can only be
586                    // used in the final segment, e.g. `std::vec::Vec<u32>`. So
587                    // check that the non-final segments have no generic args.
588                    assert!(rest_segs.iter().all(|seg| seg.args.is_empty()));
589                    final_seg.args.into_json(renderer)
590                } else {
591                    None // no generics on any segments because there are no segments
592                }
593            },
594        }
595    }
596}
597
598impl FromClean<clean::QPathData> for Type {
599    fn from_clean(qpath: &clean::QPathData, renderer: &JsonRenderer<'_>) -> Self {
600        let clean::QPathData { assoc, self_type, should_fully_qualify: _, trait_ } = qpath;
601
602        Self::QualifiedPath {
603            name: assoc.name.to_string(),
604            args: assoc.args.into_json(renderer),
605            self_type: Box::new(self_type.into_json(renderer)),
606            trait_: trait_.into_json(renderer),
607        }
608    }
609}
610
611impl FromClean<clean::Term> for Term {
612    fn from_clean(term: &clean::Term, renderer: &JsonRenderer<'_>) -> Self {
613        match term {
614            clean::Term::Type(ty) => Term::Type(ty.into_json(renderer)),
615            clean::Term::Constant(c) => Term::Constant(c.into_json(renderer)),
616        }
617    }
618}
619
620impl FromClean<clean::BareFunctionDecl> for FunctionPointer {
621    fn from_clean(bare_decl: &clean::BareFunctionDecl, renderer: &JsonRenderer<'_>) -> Self {
622        let clean::BareFunctionDecl { safety, generic_params, decl, abi } = bare_decl;
623        FunctionPointer {
624            header: FunctionHeader {
625                is_unsafe: safety.is_unsafe(),
626                is_const: false,
627                is_async: false,
628                abi: abi.into_json(renderer),
629            },
630            generic_params: generic_params.into_json(renderer),
631            sig: decl.into_json(renderer),
632        }
633    }
634}
635
636impl FromClean<clean::FnDecl> for FunctionSignature {
637    fn from_clean(decl: &clean::FnDecl, renderer: &JsonRenderer<'_>) -> Self {
638        let clean::FnDecl { inputs, output, c_variadic } = decl;
639        FunctionSignature {
640            inputs: inputs
641                .into_iter()
642                .map(|param| {
643                    // `_` is the most sensible name for missing param names.
644                    let name = param.name.unwrap_or(kw::Underscore).to_string();
645                    let type_ = param.type_.into_json(renderer);
646                    (name, type_)
647                })
648                .collect(),
649            output: if output.is_unit() { None } else { Some(output.into_json(renderer)) },
650            is_c_variadic: *c_variadic,
651        }
652    }
653}
654
655impl FromClean<clean::Trait> for Trait {
656    fn from_clean(trait_: &clean::Trait, renderer: &JsonRenderer<'_>) -> Self {
657        let tcx = renderer.tcx;
658        let is_auto = trait_.is_auto(tcx);
659        let is_unsafe = trait_.safety(tcx).is_unsafe();
660        let is_dyn_compatible = trait_.is_dyn_compatible(tcx);
661        let clean::Trait { items, generics, bounds, .. } = trait_;
662        Trait {
663            is_auto,
664            is_unsafe,
665            is_dyn_compatible,
666            items: renderer.ids(&items),
667            generics: generics.into_json(renderer),
668            bounds: bounds.into_json(renderer),
669            implementations: Vec::new(), // Added in JsonRenderer::item
670        }
671    }
672}
673
674impl FromClean<clean::PolyTrait> for PolyTrait {
675    fn from_clean(
676        clean::PolyTrait { trait_, generic_params }: &clean::PolyTrait,
677        renderer: &JsonRenderer<'_>,
678    ) -> Self {
679        PolyTrait {
680            trait_: trait_.into_json(renderer),
681            generic_params: generic_params.into_json(renderer),
682        }
683    }
684}
685
686impl FromClean<clean::Impl> for Impl {
687    fn from_clean(impl_: &clean::Impl, renderer: &JsonRenderer<'_>) -> Self {
688        let provided_trait_methods = impl_.provided_trait_methods(renderer.tcx);
689        let clean::Impl { safety, generics, trait_, for_, items, polarity, kind } = impl_;
690        // FIXME: use something like ImplKind in JSON?
691        let (is_synthetic, blanket_impl) = match kind {
692            clean::ImplKind::Normal | clean::ImplKind::FakeVariadic => (false, None),
693            clean::ImplKind::Auto => (true, None),
694            clean::ImplKind::Blanket(ty) => (false, Some(ty)),
695        };
696        let is_negative = match polarity {
697            ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => false,
698            ty::ImplPolarity::Negative => true,
699        };
700        Impl {
701            is_unsafe: safety.is_unsafe(),
702            generics: generics.into_json(renderer),
703            provided_trait_methods: provided_trait_methods
704                .into_iter()
705                .map(|x| x.to_string())
706                .collect(),
707            trait_: trait_.into_json(renderer),
708            for_: for_.into_json(renderer),
709            items: renderer.ids(&items),
710            is_negative,
711            is_synthetic,
712            blanket_impl: blanket_impl.map(|x| x.into_json(renderer)),
713        }
714    }
715}
716
717pub(crate) fn from_clean_function(
718    clean::Function { decl, generics }: &clean::Function,
719    has_body: bool,
720    header: rustc_hir::FnHeader,
721    renderer: &JsonRenderer<'_>,
722) -> Function {
723    Function {
724        sig: decl.into_json(renderer),
725        generics: generics.into_json(renderer),
726        header: header.into_json(renderer),
727        has_body,
728    }
729}
730
731impl FromClean<clean::Enum> for Enum {
732    fn from_clean(enum_: &clean::Enum, renderer: &JsonRenderer<'_>) -> Self {
733        let has_stripped_variants = enum_.has_stripped_entries();
734        let clean::Enum { variants, generics } = enum_;
735        Enum {
736            generics: generics.into_json(renderer),
737            has_stripped_variants,
738            variants: renderer.ids(&variants.as_slice().raw),
739            impls: Vec::new(), // Added in JsonRenderer::item
740        }
741    }
742}
743
744impl FromClean<clean::Variant> for Variant {
745    fn from_clean(variant: &clean::Variant, renderer: &JsonRenderer<'_>) -> Self {
746        use clean::VariantKind::*;
747
748        let discriminant = variant.discriminant.into_json(renderer);
749
750        let kind = match &variant.kind {
751            CLike => VariantKind::Plain,
752            Tuple(fields) => VariantKind::Tuple(renderer.ids_keeping_stripped(&fields)),
753            Struct(s) => VariantKind::Struct {
754                has_stripped_fields: s.has_stripped_entries(),
755                fields: renderer.ids(&s.fields),
756            },
757        };
758
759        Variant { kind, discriminant }
760    }
761}
762
763impl FromClean<clean::Discriminant> for Discriminant {
764    fn from_clean(disr: &clean::Discriminant, renderer: &JsonRenderer<'_>) -> Self {
765        let tcx = renderer.tcx;
766        Discriminant {
767            // expr is only none if going through the inlining path, which gets
768            // `rustc_middle` types, not `rustc_hir`, but because JSON never inlines
769            // the expr is always some.
770            expr: disr.expr(tcx).unwrap(),
771            value: disr.value(tcx, false),
772        }
773    }
774}
775
776impl FromClean<clean::Import> for Use {
777    fn from_clean(import: &clean::Import, renderer: &JsonRenderer<'_>) -> Self {
778        use clean::ImportKind::*;
779        let (name, is_glob) = match import.kind {
780            Simple(s) => (s.to_string(), false),
781            Glob => (import.source.path.last_opt().unwrap_or(sym::asterisk).to_string(), true),
782        };
783        Use {
784            source: import.source.path.whole_name(),
785            name,
786            id: import.source.did.map(ItemId::from).map(|i| renderer.id_from_item_default(i)),
787            is_glob,
788        }
789    }
790}
791
792impl FromClean<clean::ProcMacro> for ProcMacro {
793    fn from_clean(mac: &clean::ProcMacro, renderer: &JsonRenderer<'_>) -> Self {
794        ProcMacro {
795            kind: mac.kind.into_json(renderer),
796            helpers: mac.helpers.iter().map(|x| x.to_string()).collect(),
797        }
798    }
799}
800
801impl FromClean<rustc_span::hygiene::MacroKind> for MacroKind {
802    fn from_clean(kind: &rustc_span::hygiene::MacroKind, _renderer: &JsonRenderer<'_>) -> Self {
803        use rustc_span::hygiene::MacroKind::*;
804        match kind {
805            Bang => MacroKind::Bang,
806            Attr => MacroKind::Attr,
807            Derive => MacroKind::Derive,
808        }
809    }
810}
811
812impl FromClean<clean::TypeAlias> for TypeAlias {
813    fn from_clean(type_alias: &clean::TypeAlias, renderer: &JsonRenderer<'_>) -> Self {
814        let clean::TypeAlias { type_, generics, item_type: _, inner_type: _ } = type_alias;
815        TypeAlias { type_: type_.into_json(renderer), generics: generics.into_json(renderer) }
816    }
817}
818
819fn from_clean_static(
820    stat: &clean::Static,
821    safety: rustc_hir::Safety,
822    renderer: &JsonRenderer<'_>,
823) -> Static {
824    let tcx = renderer.tcx;
825    Static {
826        type_: stat.type_.as_ref().into_json(renderer),
827        is_mutable: stat.mutability == ast::Mutability::Mut,
828        is_unsafe: safety.is_unsafe(),
829        expr: stat
830            .expr
831            .map(|e| rendered_const(tcx, tcx.hir_body(e), tcx.hir_body_owner_def_id(e)))
832            .unwrap_or_default(),
833    }
834}
835
836impl FromClean<clean::TraitAlias> for TraitAlias {
837    fn from_clean(alias: &clean::TraitAlias, renderer: &JsonRenderer<'_>) -> Self {
838        TraitAlias {
839            generics: alias.generics.into_json(renderer),
840            params: alias.bounds.into_json(renderer),
841        }
842    }
843}
844
845impl FromClean<ItemType> for ItemKind {
846    fn from_clean(kind: &ItemType, _renderer: &JsonRenderer<'_>) -> Self {
847        use ItemType::*;
848        match kind {
849            Module => ItemKind::Module,
850            ExternCrate => ItemKind::ExternCrate,
851            Import => ItemKind::Use,
852            Struct => ItemKind::Struct,
853            Union => ItemKind::Union,
854            Enum => ItemKind::Enum,
855            Function | TyMethod | Method => ItemKind::Function,
856            TypeAlias => ItemKind::TypeAlias,
857            Static => ItemKind::Static,
858            Constant => ItemKind::Constant,
859            Trait => ItemKind::Trait,
860            Impl => ItemKind::Impl,
861            StructField => ItemKind::StructField,
862            Variant => ItemKind::Variant,
863            Macro => ItemKind::Macro,
864            Primitive => ItemKind::Primitive,
865            AssocConst => ItemKind::AssocConst,
866            AssocType => ItemKind::AssocType,
867            ForeignType => ItemKind::ExternType,
868            Keyword => ItemKind::Keyword,
869            TraitAlias => ItemKind::TraitAlias,
870            ProcAttribute => ItemKind::ProcAttribute,
871            ProcDerive => ItemKind::ProcDerive,
872        }
873    }
874}