1use rustc_abi::ExternAbi;
6use rustc_ast::ast;
7use rustc_hir as hir;
8use rustc_hir::attrs::{self, DeprecatedSince};
9use rustc_hir::def::CtorKind;
10use rustc_hir::def_id::DefId;
11use rustc_hir::{HeaderSafety, Safety};
12use rustc_metadata::rendered_const;
13use rustc_middle::ty::TyCtxt;
14use rustc_middle::{bug, ty};
15use rustc_span::{Pos, kw, sym};
16use rustdoc_json_types::*;
17use thin_vec::ThinVec;
18
19use crate::clean::{self, ItemId};
20use crate::formats::item_type::ItemType;
21use crate::json::JsonRenderer;
22use crate::passes::collect_intra_doc_links::UrlFragment;
23
24impl 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 Some(UrlFragment::UserWritten(_)) | None => *page_id,
38 };
39
40 (String::from(&**link), self.id_from_item_default(id.into()))
41 })
42 .collect();
43 let docs = item.opt_doc_value();
44 let attrs = item
45 .attrs
46 .other_attrs
47 .iter()
48 .filter_map(|a| maybe_from_hir_attr(a, item.item_id, self.tcx))
49 .collect();
50 let span = item.span(self.tcx);
51 let visibility = item.visibility(self.tcx);
52 let clean::ItemInner { name, item_id, .. } = *item.inner;
53 let id = self.id_from_item(item);
54 let inner = match item.kind {
55 clean::KeywordItem => return None,
56 clean::StrippedItem(ref inner) => {
57 match &**inner {
58 clean::ModuleItem(_)
62 if self.imported_items.contains(&item_id.expect_def_id()) =>
63 {
64 from_clean_item(item, self)
65 }
66 _ => return None,
67 }
68 }
69 _ => from_clean_item(item, self),
70 };
71 Some(Item {
72 id,
73 crate_id: item_id.krate().as_u32(),
74 name: name.map(|sym| sym.to_string()),
75 span: span.and_then(|span| span.into_json(self)),
76 visibility: visibility.into_json(self),
77 docs,
78 attrs,
79 deprecation: deprecation.into_json(self),
80 inner,
81 links,
82 })
83 }
84
85 fn ids(&self, items: &[clean::Item]) -> Vec<Id> {
86 items
87 .iter()
88 .filter(|i| !i.is_stripped() && !i.is_keyword())
89 .map(|i| self.id_from_item(i))
90 .collect()
91 }
92
93 fn ids_keeping_stripped(&self, items: &[clean::Item]) -> Vec<Option<Id>> {
94 items
95 .iter()
96 .map(|i| (!i.is_stripped() && !i.is_keyword()).then(|| self.id_from_item(i)))
97 .collect()
98 }
99}
100
101pub(crate) trait FromClean<T> {
102 fn from_clean(f: &T, renderer: &JsonRenderer<'_>) -> Self;
103}
104
105pub(crate) trait IntoJson<T> {
106 fn into_json(&self, renderer: &JsonRenderer<'_>) -> T;
107}
108
109impl<T, U> IntoJson<U> for T
110where
111 U: FromClean<T>,
112{
113 fn into_json(&self, renderer: &JsonRenderer<'_>) -> U {
114 U::from_clean(self, renderer)
115 }
116}
117
118impl<T, U> FromClean<Box<T>> for U
119where
120 U: FromClean<T>,
121{
122 fn from_clean(opt: &Box<T>, renderer: &JsonRenderer<'_>) -> Self {
123 opt.as_ref().into_json(renderer)
124 }
125}
126
127impl<T, U> FromClean<Option<T>> for Option<U>
128where
129 U: FromClean<T>,
130{
131 fn from_clean(opt: &Option<T>, renderer: &JsonRenderer<'_>) -> Self {
132 opt.as_ref().map(|x| x.into_json(renderer))
133 }
134}
135
136impl<T, U> FromClean<Vec<T>> for Vec<U>
137where
138 U: FromClean<T>,
139{
140 fn from_clean(items: &Vec<T>, renderer: &JsonRenderer<'_>) -> Self {
141 items.iter().map(|i| i.into_json(renderer)).collect()
142 }
143}
144
145impl<T, U> FromClean<ThinVec<T>> for Vec<U>
146where
147 U: FromClean<T>,
148{
149 fn from_clean(items: &ThinVec<T>, renderer: &JsonRenderer<'_>) -> Self {
150 items.iter().map(|i| i.into_json(renderer)).collect()
151 }
152}
153
154impl FromClean<clean::Span> for Option<Span> {
155 fn from_clean(span: &clean::Span, renderer: &JsonRenderer<'_>) -> Self {
156 match span.filename(renderer.sess()) {
157 rustc_span::FileName::Real(name) => {
158 if let Some(local_path) = name.into_local_path() {
159 let hi = span.hi(renderer.sess());
160 let lo = span.lo(renderer.sess());
161 Some(Span {
162 filename: local_path,
163 begin: (lo.line, lo.col.to_usize() + 1),
164 end: (hi.line, hi.col.to_usize() + 1),
165 })
166 } else {
167 None
168 }
169 }
170 _ => None,
171 }
172 }
173}
174
175impl FromClean<Option<ty::Visibility<DefId>>> for Visibility {
176 fn from_clean(v: &Option<ty::Visibility<DefId>>, renderer: &JsonRenderer<'_>) -> Self {
177 match v {
178 None => Visibility::Default,
179 Some(ty::Visibility::Public) => Visibility::Public,
180 Some(ty::Visibility::Restricted(did)) if did.is_crate_root() => Visibility::Crate,
181 Some(ty::Visibility::Restricted(did)) => Visibility::Restricted {
182 parent: renderer.id_from_item_default((*did).into()),
183 path: renderer.tcx.def_path(*did).to_string_no_crate_verbose(),
184 },
185 }
186 }
187}
188
189impl FromClean<attrs::Deprecation> for Deprecation {
190 fn from_clean(deprecation: &attrs::Deprecation, _renderer: &JsonRenderer<'_>) -> Self {
191 let attrs::Deprecation { since, note, suggestion: _ } = deprecation;
192 let since = match since {
193 DeprecatedSince::RustcVersion(version) => Some(version.to_string()),
194 DeprecatedSince::Future => Some("TBD".to_string()),
195 DeprecatedSince::NonStandard(since) => Some(since.to_string()),
196 DeprecatedSince::Unspecified | DeprecatedSince::Err => None,
197 };
198 Deprecation { since, note: note.map(|sym| sym.to_string()) }
199 }
200}
201
202impl FromClean<clean::GenericArgs> for Option<Box<GenericArgs>> {
203 fn from_clean(generic_args: &clean::GenericArgs, renderer: &JsonRenderer<'_>) -> Self {
204 use clean::GenericArgs::*;
205 match generic_args {
206 AngleBracketed { args, constraints } => {
207 if generic_args.is_empty() {
208 None
209 } else {
210 Some(Box::new(GenericArgs::AngleBracketed {
211 args: args.into_json(renderer),
212 constraints: constraints.into_json(renderer),
213 }))
214 }
215 }
216 Parenthesized { inputs, output } => Some(Box::new(GenericArgs::Parenthesized {
217 inputs: inputs.into_json(renderer),
218 output: output.into_json(renderer),
219 })),
220 ReturnTypeNotation => Some(Box::new(GenericArgs::ReturnTypeNotation)),
221 }
222 }
223}
224
225impl FromClean<clean::GenericArg> for GenericArg {
226 fn from_clean(arg: &clean::GenericArg, renderer: &JsonRenderer<'_>) -> Self {
227 use clean::GenericArg::*;
228 match arg {
229 Lifetime(l) => GenericArg::Lifetime(l.into_json(renderer)),
230 Type(t) => GenericArg::Type(t.into_json(renderer)),
231 Const(box c) => GenericArg::Const(c.into_json(renderer)),
232 Infer => GenericArg::Infer,
233 }
234 }
235}
236
237impl FromClean<clean::ConstantKind> for Constant {
238 fn from_clean(constant: &clean::ConstantKind, renderer: &JsonRenderer<'_>) -> Self {
240 let tcx = renderer.tcx;
241 let expr = constant.expr(tcx);
242 let value = constant.value(tcx);
243 let is_literal = constant.is_literal(tcx);
244 Constant { expr, value, is_literal }
245 }
246}
247
248impl FromClean<clean::AssocItemConstraint> for AssocItemConstraint {
249 fn from_clean(constraint: &clean::AssocItemConstraint, renderer: &JsonRenderer<'_>) -> Self {
250 AssocItemConstraint {
251 name: constraint.assoc.name.to_string(),
252 args: constraint.assoc.args.into_json(renderer),
253 binding: constraint.kind.into_json(renderer),
254 }
255 }
256}
257
258impl FromClean<clean::AssocItemConstraintKind> for AssocItemConstraintKind {
259 fn from_clean(kind: &clean::AssocItemConstraintKind, renderer: &JsonRenderer<'_>) -> Self {
260 use clean::AssocItemConstraintKind::*;
261 match kind {
262 Equality { term } => AssocItemConstraintKind::Equality(term.into_json(renderer)),
263 Bound { bounds } => AssocItemConstraintKind::Constraint(bounds.into_json(renderer)),
264 }
265 }
266}
267
268fn from_clean_item(item: &clean::Item, renderer: &JsonRenderer<'_>) -> ItemEnum {
269 use clean::ItemKind::*;
270 let name = item.name;
271 let is_crate = item.is_crate();
272 let header = item.fn_header(renderer.tcx);
273
274 match &item.inner.kind {
275 ModuleItem(m) => {
276 ItemEnum::Module(Module { is_crate, items: renderer.ids(&m.items), is_stripped: false })
277 }
278 ImportItem(i) => ItemEnum::Use(i.into_json(renderer)),
279 StructItem(s) => ItemEnum::Struct(s.into_json(renderer)),
280 UnionItem(u) => ItemEnum::Union(u.into_json(renderer)),
281 StructFieldItem(f) => ItemEnum::StructField(f.into_json(renderer)),
282 EnumItem(e) => ItemEnum::Enum(e.into_json(renderer)),
283 VariantItem(v) => ItemEnum::Variant(v.into_json(renderer)),
284 FunctionItem(f) => {
285 ItemEnum::Function(from_clean_function(f, true, header.unwrap(), renderer))
286 }
287 ForeignFunctionItem(f, _) => {
288 ItemEnum::Function(from_clean_function(f, false, header.unwrap(), renderer))
289 }
290 TraitItem(t) => ItemEnum::Trait(t.into_json(renderer)),
291 TraitAliasItem(t) => ItemEnum::TraitAlias(t.into_json(renderer)),
292 MethodItem(m, _) => {
293 ItemEnum::Function(from_clean_function(m, true, header.unwrap(), renderer))
294 }
295 RequiredMethodItem(m) => {
296 ItemEnum::Function(from_clean_function(m, false, header.unwrap(), renderer))
297 }
298 ImplItem(i) => ItemEnum::Impl(i.into_json(renderer)),
299 StaticItem(s) => ItemEnum::Static(from_clean_static(s, rustc_hir::Safety::Safe, renderer)),
300 ForeignStaticItem(s, safety) => ItemEnum::Static(from_clean_static(s, *safety, renderer)),
301 ForeignTypeItem => ItemEnum::ExternType,
302 TypeAliasItem(t) => ItemEnum::TypeAlias(t.into_json(renderer)),
303 ConstantItem(ci) => ItemEnum::Constant {
305 type_: ci.type_.into_json(renderer),
306 const_: ci.kind.into_json(renderer),
307 },
308 MacroItem(m) => ItemEnum::Macro(m.source.clone()),
309 ProcMacroItem(m) => ItemEnum::ProcMacro(m.into_json(renderer)),
310 PrimitiveItem(p) => {
311 ItemEnum::Primitive(Primitive {
312 name: p.as_sym().to_string(),
313 impls: Vec::new(), })
315 }
316 RequiredAssocConstItem(_generics, ty) => {
318 ItemEnum::AssocConst { type_: ty.into_json(renderer), value: None }
319 }
320 ProvidedAssocConstItem(ci) | ImplAssocConstItem(ci) => ItemEnum::AssocConst {
322 type_: ci.type_.into_json(renderer),
323 value: Some(ci.kind.expr(renderer.tcx)),
324 },
325 RequiredAssocTypeItem(g, b) => ItemEnum::AssocType {
326 generics: g.into_json(renderer),
327 bounds: b.into_json(renderer),
328 type_: None,
329 },
330 AssocTypeItem(t, b) => ItemEnum::AssocType {
331 generics: t.generics.into_json(renderer),
332 bounds: b.into_json(renderer),
333 type_: Some(t.item_type.as_ref().unwrap_or(&t.type_).into_json(renderer)),
334 },
335 KeywordItem => unreachable!(),
337 StrippedItem(inner) => {
338 match inner.as_ref() {
339 ModuleItem(m) => ItemEnum::Module(Module {
340 is_crate,
341 items: renderer.ids(&m.items),
342 is_stripped: true,
343 }),
344 _ => unreachable!(),
346 }
347 }
348 ExternCrateItem { src } => ItemEnum::ExternCrate {
349 name: name.as_ref().unwrap().to_string(),
350 rename: src.map(|x| x.to_string()),
351 },
352 }
353}
354
355impl FromClean<clean::Struct> for Struct {
356 fn from_clean(struct_: &clean::Struct, renderer: &JsonRenderer<'_>) -> Self {
357 let has_stripped_fields = struct_.has_stripped_entries();
358 let clean::Struct { ctor_kind, generics, fields } = struct_;
359
360 let kind = match ctor_kind {
361 Some(CtorKind::Fn) => StructKind::Tuple(renderer.ids_keeping_stripped(fields)),
362 Some(CtorKind::Const) => {
363 assert!(fields.is_empty());
364 StructKind::Unit
365 }
366 None => StructKind::Plain { fields: renderer.ids(fields), has_stripped_fields },
367 };
368
369 Struct {
370 kind,
371 generics: generics.into_json(renderer),
372 impls: Vec::new(), }
374 }
375}
376
377impl FromClean<clean::Union> for Union {
378 fn from_clean(union_: &clean::Union, renderer: &JsonRenderer<'_>) -> Self {
379 let has_stripped_fields = union_.has_stripped_entries();
380 let clean::Union { generics, fields } = union_;
381 Union {
382 generics: generics.into_json(renderer),
383 has_stripped_fields,
384 fields: renderer.ids(fields),
385 impls: Vec::new(), }
387 }
388}
389
390impl FromClean<rustc_hir::FnHeader> for FunctionHeader {
391 fn from_clean(header: &rustc_hir::FnHeader, renderer: &JsonRenderer<'_>) -> Self {
392 let is_unsafe = match header.safety {
393 HeaderSafety::SafeTargetFeatures => {
394 false
400 }
401 HeaderSafety::Normal(Safety::Safe) => false,
402 HeaderSafety::Normal(Safety::Unsafe) => true,
403 };
404 FunctionHeader {
405 is_async: header.is_async(),
406 is_const: header.is_const(),
407 is_unsafe,
408 abi: header.abi.into_json(renderer),
409 }
410 }
411}
412
413impl FromClean<ExternAbi> for Abi {
414 fn from_clean(a: &ExternAbi, _renderer: &JsonRenderer<'_>) -> Self {
415 match *a {
416 ExternAbi::Rust => Abi::Rust,
417 ExternAbi::C { unwind } => Abi::C { unwind },
418 ExternAbi::Cdecl { unwind } => Abi::Cdecl { unwind },
419 ExternAbi::Stdcall { unwind } => Abi::Stdcall { unwind },
420 ExternAbi::Fastcall { unwind } => Abi::Fastcall { unwind },
421 ExternAbi::Aapcs { unwind } => Abi::Aapcs { unwind },
422 ExternAbi::Win64 { unwind } => Abi::Win64 { unwind },
423 ExternAbi::SysV64 { unwind } => Abi::SysV64 { unwind },
424 ExternAbi::System { unwind } => Abi::System { unwind },
425 _ => Abi::Other(a.to_string()),
426 }
427 }
428}
429
430impl FromClean<clean::Lifetime> for String {
431 fn from_clean(l: &clean::Lifetime, _renderer: &JsonRenderer<'_>) -> String {
432 l.0.to_string()
433 }
434}
435
436impl FromClean<clean::Generics> for Generics {
437 fn from_clean(generics: &clean::Generics, renderer: &JsonRenderer<'_>) -> Self {
438 Generics {
439 params: generics.params.into_json(renderer),
440 where_predicates: generics.where_predicates.into_json(renderer),
441 }
442 }
443}
444
445impl FromClean<clean::GenericParamDef> for GenericParamDef {
446 fn from_clean(generic_param: &clean::GenericParamDef, renderer: &JsonRenderer<'_>) -> Self {
447 GenericParamDef {
448 name: generic_param.name.to_string(),
449 kind: generic_param.kind.into_json(renderer),
450 }
451 }
452}
453
454impl FromClean<clean::GenericParamDefKind> for GenericParamDefKind {
455 fn from_clean(kind: &clean::GenericParamDefKind, renderer: &JsonRenderer<'_>) -> Self {
456 use clean::GenericParamDefKind::*;
457 match kind {
458 Lifetime { outlives } => {
459 GenericParamDefKind::Lifetime { outlives: outlives.into_json(renderer) }
460 }
461 Type { bounds, default, synthetic } => GenericParamDefKind::Type {
462 bounds: bounds.into_json(renderer),
463 default: default.into_json(renderer),
464 is_synthetic: *synthetic,
465 },
466 Const { ty, default, synthetic: _ } => GenericParamDefKind::Const {
467 type_: ty.into_json(renderer),
468 default: default.as_ref().map(|x| x.as_ref().clone()),
469 },
470 }
471 }
472}
473
474impl FromClean<clean::WherePredicate> for WherePredicate {
475 fn from_clean(predicate: &clean::WherePredicate, renderer: &JsonRenderer<'_>) -> Self {
476 use clean::WherePredicate::*;
477 match predicate {
478 BoundPredicate { ty, bounds, bound_params } => WherePredicate::BoundPredicate {
479 type_: ty.into_json(renderer),
480 bounds: bounds.into_json(renderer),
481 generic_params: bound_params.into_json(renderer),
482 },
483 RegionPredicate { lifetime, bounds } => WherePredicate::LifetimePredicate {
484 lifetime: lifetime.into_json(renderer),
485 outlives: bounds
486 .iter()
487 .map(|bound| match bound {
488 clean::GenericBound::Outlives(lt) => lt.into_json(renderer),
489 _ => bug!("found non-outlives-bound on lifetime predicate"),
490 })
491 .collect(),
492 },
493 EqPredicate { lhs, rhs } => WherePredicate::EqPredicate {
494 lhs: lhs.into_json(renderer),
498 rhs: rhs.into_json(renderer),
499 },
500 }
501 }
502}
503
504impl FromClean<clean::GenericBound> for GenericBound {
505 fn from_clean(bound: &clean::GenericBound, renderer: &JsonRenderer<'_>) -> Self {
506 use clean::GenericBound::*;
507 match bound {
508 TraitBound(clean::PolyTrait { trait_, generic_params }, modifier) => {
509 GenericBound::TraitBound {
510 trait_: trait_.into_json(renderer),
511 generic_params: generic_params.into_json(renderer),
512 modifier: modifier.into_json(renderer),
513 }
514 }
515 Outlives(lifetime) => GenericBound::Outlives(lifetime.into_json(renderer)),
516 Use(args) => GenericBound::Use(
517 args.iter()
518 .map(|arg| match arg {
519 clean::PreciseCapturingArg::Lifetime(lt) => {
520 PreciseCapturingArg::Lifetime(lt.into_json(renderer))
521 }
522 clean::PreciseCapturingArg::Param(param) => {
523 PreciseCapturingArg::Param(param.to_string())
524 }
525 })
526 .collect(),
527 ),
528 }
529 }
530}
531
532impl FromClean<rustc_hir::TraitBoundModifiers> for TraitBoundModifier {
533 fn from_clean(
534 modifiers: &rustc_hir::TraitBoundModifiers,
535 _renderer: &JsonRenderer<'_>,
536 ) -> Self {
537 use rustc_hir as hir;
538 let hir::TraitBoundModifiers { constness, polarity } = modifiers;
539 match (constness, polarity) {
540 (hir::BoundConstness::Never, hir::BoundPolarity::Positive) => TraitBoundModifier::None,
541 (hir::BoundConstness::Never, hir::BoundPolarity::Maybe(_)) => TraitBoundModifier::Maybe,
542 (hir::BoundConstness::Maybe(_), hir::BoundPolarity::Positive) => {
543 TraitBoundModifier::MaybeConst
544 }
545 _ => TraitBoundModifier::None,
547 }
548 }
549}
550
551impl FromClean<clean::Type> for Type {
552 fn from_clean(ty: &clean::Type, renderer: &JsonRenderer<'_>) -> Self {
553 use clean::Type::{
554 Array, BareFunction, BorrowedRef, Generic, ImplTrait, Infer, Primitive, QPath,
555 RawPointer, SelfTy, Slice, Tuple, UnsafeBinder,
556 };
557
558 match ty {
559 clean::Type::Path { path } => Type::ResolvedPath(path.into_json(renderer)),
560 clean::Type::DynTrait(bounds, lt) => Type::DynTrait(DynTrait {
561 lifetime: lt.into_json(renderer),
562 traits: bounds.into_json(renderer),
563 }),
564 Generic(s) => Type::Generic(s.to_string()),
565 SelfTy => Type::Generic("Self".to_owned()),
567 Primitive(p) => Type::Primitive(p.as_sym().to_string()),
568 BareFunction(f) => Type::FunctionPointer(Box::new(f.into_json(renderer))),
569 Tuple(t) => Type::Tuple(t.into_json(renderer)),
570 Slice(t) => Type::Slice(Box::new(t.into_json(renderer))),
571 Array(t, s) => {
572 Type::Array { type_: Box::new(t.into_json(renderer)), len: s.to_string() }
573 }
574 clean::Type::Pat(t, p) => Type::Pat {
575 type_: Box::new(t.into_json(renderer)),
576 __pat_unstable_do_not_use: p.to_string(),
577 },
578 ImplTrait(g) => Type::ImplTrait(g.into_json(renderer)),
579 Infer => Type::Infer,
580 RawPointer(mutability, type_) => Type::RawPointer {
581 is_mutable: *mutability == ast::Mutability::Mut,
582 type_: Box::new(type_.into_json(renderer)),
583 },
584 BorrowedRef { lifetime, mutability, type_ } => Type::BorrowedRef {
585 lifetime: lifetime.into_json(renderer),
586 is_mutable: *mutability == ast::Mutability::Mut,
587 type_: Box::new(type_.into_json(renderer)),
588 },
589 QPath(qpath) => qpath.into_json(renderer),
590 UnsafeBinder(_) => todo!(),
592 }
593 }
594}
595
596impl FromClean<clean::Path> for Path {
597 fn from_clean(path: &clean::Path, renderer: &JsonRenderer<'_>) -> Self {
598 Path {
599 path: path.whole_name(),
600 id: renderer.id_from_item_default(path.def_id().into()),
601 args: {
602 if let Some((final_seg, rest_segs)) = path.segments.split_last() {
603 assert!(rest_segs.iter().all(|seg| seg.args.is_empty()));
610 final_seg.args.into_json(renderer)
611 } else {
612 None }
614 },
615 }
616 }
617}
618
619impl FromClean<clean::QPathData> for Type {
620 fn from_clean(qpath: &clean::QPathData, renderer: &JsonRenderer<'_>) -> Self {
621 let clean::QPathData { assoc, self_type, should_fully_qualify: _, trait_ } = qpath;
622
623 Self::QualifiedPath {
624 name: assoc.name.to_string(),
625 args: assoc.args.into_json(renderer),
626 self_type: Box::new(self_type.into_json(renderer)),
627 trait_: trait_.into_json(renderer),
628 }
629 }
630}
631
632impl FromClean<clean::Term> for Term {
633 fn from_clean(term: &clean::Term, renderer: &JsonRenderer<'_>) -> Self {
634 match term {
635 clean::Term::Type(ty) => Term::Type(ty.into_json(renderer)),
636 clean::Term::Constant(c) => Term::Constant(c.into_json(renderer)),
637 }
638 }
639}
640
641impl FromClean<clean::BareFunctionDecl> for FunctionPointer {
642 fn from_clean(bare_decl: &clean::BareFunctionDecl, renderer: &JsonRenderer<'_>) -> Self {
643 let clean::BareFunctionDecl { safety, generic_params, decl, abi } = bare_decl;
644 FunctionPointer {
645 header: FunctionHeader {
646 is_unsafe: safety.is_unsafe(),
647 is_const: false,
648 is_async: false,
649 abi: abi.into_json(renderer),
650 },
651 generic_params: generic_params.into_json(renderer),
652 sig: decl.into_json(renderer),
653 }
654 }
655}
656
657impl FromClean<clean::FnDecl> for FunctionSignature {
658 fn from_clean(decl: &clean::FnDecl, renderer: &JsonRenderer<'_>) -> Self {
659 let clean::FnDecl { inputs, output, c_variadic } = decl;
660 FunctionSignature {
661 inputs: inputs
662 .iter()
663 .map(|param| {
664 let name = param.name.unwrap_or(kw::Underscore).to_string();
666 let type_ = param.type_.into_json(renderer);
667 (name, type_)
668 })
669 .collect(),
670 output: if output.is_unit() { None } else { Some(output.into_json(renderer)) },
671 is_c_variadic: *c_variadic,
672 }
673 }
674}
675
676impl FromClean<clean::Trait> for Trait {
677 fn from_clean(trait_: &clean::Trait, renderer: &JsonRenderer<'_>) -> Self {
678 let tcx = renderer.tcx;
679 let is_auto = trait_.is_auto(tcx);
680 let is_unsafe = trait_.safety(tcx).is_unsafe();
681 let is_dyn_compatible = trait_.is_dyn_compatible(tcx);
682 let clean::Trait { items, generics, bounds, .. } = trait_;
683 Trait {
684 is_auto,
685 is_unsafe,
686 is_dyn_compatible,
687 items: renderer.ids(items),
688 generics: generics.into_json(renderer),
689 bounds: bounds.into_json(renderer),
690 implementations: Vec::new(), }
692 }
693}
694
695impl FromClean<clean::PolyTrait> for PolyTrait {
696 fn from_clean(
697 clean::PolyTrait { trait_, generic_params }: &clean::PolyTrait,
698 renderer: &JsonRenderer<'_>,
699 ) -> Self {
700 PolyTrait {
701 trait_: trait_.into_json(renderer),
702 generic_params: generic_params.into_json(renderer),
703 }
704 }
705}
706
707impl FromClean<clean::Impl> for Impl {
708 fn from_clean(impl_: &clean::Impl, renderer: &JsonRenderer<'_>) -> Self {
709 let provided_trait_methods = impl_.provided_trait_methods(renderer.tcx);
710 let clean::Impl { safety, generics, trait_, for_, items, polarity, kind } = impl_;
711 let (is_synthetic, blanket_impl) = match kind {
713 clean::ImplKind::Normal | clean::ImplKind::FakeVariadic => (false, None),
714 clean::ImplKind::Auto => (true, None),
715 clean::ImplKind::Blanket(ty) => (false, Some(ty)),
716 };
717 let is_negative = match polarity {
718 ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => false,
719 ty::ImplPolarity::Negative => true,
720 };
721 Impl {
722 is_unsafe: safety.is_unsafe(),
723 generics: generics.into_json(renderer),
724 provided_trait_methods: provided_trait_methods
725 .into_iter()
726 .map(|x| x.to_string())
727 .collect(),
728 trait_: trait_.into_json(renderer),
729 for_: for_.into_json(renderer),
730 items: renderer.ids(items),
731 is_negative,
732 is_synthetic,
733 blanket_impl: blanket_impl.map(|x| x.into_json(renderer)),
734 }
735 }
736}
737
738pub(crate) fn from_clean_function(
739 clean::Function { decl, generics }: &clean::Function,
740 has_body: bool,
741 header: rustc_hir::FnHeader,
742 renderer: &JsonRenderer<'_>,
743) -> Function {
744 Function {
745 sig: decl.into_json(renderer),
746 generics: generics.into_json(renderer),
747 header: header.into_json(renderer),
748 has_body,
749 }
750}
751
752impl FromClean<clean::Enum> for Enum {
753 fn from_clean(enum_: &clean::Enum, renderer: &JsonRenderer<'_>) -> Self {
754 let has_stripped_variants = enum_.has_stripped_entries();
755 let clean::Enum { variants, generics } = enum_;
756 Enum {
757 generics: generics.into_json(renderer),
758 has_stripped_variants,
759 variants: renderer.ids(&variants.as_slice().raw),
760 impls: Vec::new(), }
762 }
763}
764
765impl FromClean<clean::Variant> for Variant {
766 fn from_clean(variant: &clean::Variant, renderer: &JsonRenderer<'_>) -> Self {
767 use clean::VariantKind::*;
768
769 let discriminant = variant.discriminant.into_json(renderer);
770
771 let kind = match &variant.kind {
772 CLike => VariantKind::Plain,
773 Tuple(fields) => VariantKind::Tuple(renderer.ids_keeping_stripped(fields)),
774 Struct(s) => VariantKind::Struct {
775 has_stripped_fields: s.has_stripped_entries(),
776 fields: renderer.ids(&s.fields),
777 },
778 };
779
780 Variant { kind, discriminant }
781 }
782}
783
784impl FromClean<clean::Discriminant> for Discriminant {
785 fn from_clean(disr: &clean::Discriminant, renderer: &JsonRenderer<'_>) -> Self {
786 let tcx = renderer.tcx;
787 Discriminant {
788 expr: disr.expr(tcx).unwrap(),
792 value: disr.value(tcx, false),
793 }
794 }
795}
796
797impl FromClean<clean::Import> for Use {
798 fn from_clean(import: &clean::Import, renderer: &JsonRenderer<'_>) -> Self {
799 use clean::ImportKind::*;
800 let (name, is_glob) = match import.kind {
801 Simple(s) => (s.to_string(), false),
802 Glob => (import.source.path.last_opt().unwrap_or(sym::asterisk).to_string(), true),
803 };
804 Use {
805 source: import.source.path.whole_name(),
806 name,
807 id: import.source.did.map(ItemId::from).map(|i| renderer.id_from_item_default(i)),
808 is_glob,
809 }
810 }
811}
812
813impl FromClean<clean::ProcMacro> for ProcMacro {
814 fn from_clean(mac: &clean::ProcMacro, renderer: &JsonRenderer<'_>) -> Self {
815 ProcMacro {
816 kind: mac.kind.into_json(renderer),
817 helpers: mac.helpers.iter().map(|x| x.to_string()).collect(),
818 }
819 }
820}
821
822impl FromClean<rustc_span::hygiene::MacroKind> for MacroKind {
823 fn from_clean(kind: &rustc_span::hygiene::MacroKind, _renderer: &JsonRenderer<'_>) -> Self {
824 use rustc_span::hygiene::MacroKind::*;
825 match kind {
826 Bang => MacroKind::Bang,
827 Attr => MacroKind::Attr,
828 Derive => MacroKind::Derive,
829 }
830 }
831}
832
833impl FromClean<clean::TypeAlias> for TypeAlias {
834 fn from_clean(type_alias: &clean::TypeAlias, renderer: &JsonRenderer<'_>) -> Self {
835 let clean::TypeAlias { type_, generics, item_type: _, inner_type: _ } = type_alias;
836 TypeAlias { type_: type_.into_json(renderer), generics: generics.into_json(renderer) }
837 }
838}
839
840fn from_clean_static(
841 stat: &clean::Static,
842 safety: rustc_hir::Safety,
843 renderer: &JsonRenderer<'_>,
844) -> Static {
845 let tcx = renderer.tcx;
846 Static {
847 type_: stat.type_.as_ref().into_json(renderer),
848 is_mutable: stat.mutability == ast::Mutability::Mut,
849 is_unsafe: safety.is_unsafe(),
850 expr: stat
851 .expr
852 .map(|e| rendered_const(tcx, tcx.hir_body(e), tcx.hir_body_owner_def_id(e)))
853 .unwrap_or_default(),
854 }
855}
856
857impl FromClean<clean::TraitAlias> for TraitAlias {
858 fn from_clean(alias: &clean::TraitAlias, renderer: &JsonRenderer<'_>) -> Self {
859 TraitAlias {
860 generics: alias.generics.into_json(renderer),
861 params: alias.bounds.into_json(renderer),
862 }
863 }
864}
865
866impl FromClean<ItemType> for ItemKind {
867 fn from_clean(kind: &ItemType, _renderer: &JsonRenderer<'_>) -> Self {
868 use ItemType::*;
869 match kind {
870 Module => ItemKind::Module,
871 ExternCrate => ItemKind::ExternCrate,
872 Import => ItemKind::Use,
873 Struct => ItemKind::Struct,
874 Union => ItemKind::Union,
875 Enum => ItemKind::Enum,
876 Function | TyMethod | Method => ItemKind::Function,
877 TypeAlias => ItemKind::TypeAlias,
878 Static => ItemKind::Static,
879 Constant => ItemKind::Constant,
880 Trait => ItemKind::Trait,
881 Impl => ItemKind::Impl,
882 StructField => ItemKind::StructField,
883 Variant => ItemKind::Variant,
884 Macro => ItemKind::Macro,
885 Primitive => ItemKind::Primitive,
886 AssocConst => ItemKind::AssocConst,
887 AssocType => ItemKind::AssocType,
888 ForeignType => ItemKind::ExternType,
889 Keyword => ItemKind::Keyword,
890 TraitAlias => ItemKind::TraitAlias,
891 ProcAttribute => ItemKind::ProcAttribute,
892 ProcDerive => ItemKind::ProcDerive,
893 }
894 }
895}
896
897fn maybe_from_hir_attr(
901 attr: &hir::Attribute,
902 item_id: ItemId,
903 tcx: TyCtxt<'_>,
904) -> Option<Attribute> {
905 use attrs::AttributeKind as AK;
906
907 let kind = match attr {
908 hir::Attribute::Parsed(kind) => kind,
909
910 hir::Attribute::Unparsed(_) => {
911 return Some(if attr.has_name(sym::macro_export) {
912 Attribute::MacroExport
913 } else {
915 other_attr(tcx, attr)
916 });
917 }
918 };
919
920 Some(match kind {
921 AK::Deprecation { .. } => return None, AK::DocComment { .. } => unreachable!("doc comments stripped out earlier"),
923
924 AK::MustUse { reason, span: _ } => {
925 Attribute::MustUse { reason: reason.map(|s| s.to_string()) }
926 }
927 AK::Repr { .. } => repr_attr(
928 tcx,
929 item_id.as_def_id().expect("all items that could have #[repr] have a DefId"),
930 ),
931 AK::ExportName { name, span: _ } => Attribute::ExportName(name.to_string()),
932 AK::LinkSection { name, span: _ } => Attribute::LinkSection(name.to_string()),
933 AK::TargetFeature { features, .. } => Attribute::TargetFeature {
934 enable: features.iter().map(|(feat, _span)| feat.to_string()).collect(),
935 },
936
937 AK::NoMangle(_) => Attribute::NoMangle,
938 AK::NonExhaustive(_) => Attribute::NonExhaustive,
939 AK::AutomaticallyDerived(_) => Attribute::AutomaticallyDerived,
940
941 _ => other_attr(tcx, attr),
942 })
943}
944
945fn other_attr(tcx: TyCtxt<'_>, attr: &hir::Attribute) -> Attribute {
946 let mut s = rustc_hir_pretty::attribute_to_string(&tcx, attr);
947 assert_eq!(s.pop(), Some('\n'));
948 Attribute::Other(s)
949}
950
951fn repr_attr(tcx: TyCtxt<'_>, def_id: DefId) -> Attribute {
952 let repr = tcx.adt_def(def_id).repr();
953
954 let kind = if repr.c() {
955 ReprKind::C
956 } else if repr.transparent() {
957 ReprKind::Transparent
958 } else if repr.simd() {
959 ReprKind::Simd
960 } else {
961 ReprKind::Rust
962 };
963
964 let align = repr.align.map(|a| a.bytes());
965 let packed = repr.pack.map(|p| p.bytes());
966 let int = repr.int.map(format_integer_type);
967
968 Attribute::Repr(AttributeRepr { kind, align, packed, int })
969}
970
971fn format_integer_type(it: rustc_abi::IntegerType) -> String {
972 use rustc_abi::Integer::*;
973 use rustc_abi::IntegerType::*;
974 match it {
975 Pointer(true) => "isize",
976 Pointer(false) => "usize",
977 Fixed(I8, true) => "i8",
978 Fixed(I8, false) => "u8",
979 Fixed(I16, true) => "i16",
980 Fixed(I16, false) => "u16",
981 Fixed(I32, true) => "i32",
982 Fixed(I32, false) => "u32",
983 Fixed(I64, true) => "i64",
984 Fixed(I64, false) => "u64",
985 Fixed(I128, true) => "i128",
986 Fixed(I128, false) => "u128",
987 }
988 .to_owned()
989}