]> git.proxmox.com Git - rustc.git/blob - src/librustdoc/clean/mod.rs
Imported Upstream version 1.0.0~beta.3
[rustc.git] / src / librustdoc / clean / mod.rs
1 // Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! This module contains the "cleaned" pieces of the AST, and the functions
12 //! that clean them.
13
14 pub use self::Type::*;
15 pub use self::PrimitiveType::*;
16 pub use self::TypeKind::*;
17 pub use self::StructField::*;
18 pub use self::VariantKind::*;
19 pub use self::Mutability::*;
20 pub use self::Import::*;
21 pub use self::ItemEnum::*;
22 pub use self::Attribute::*;
23 pub use self::TyParamBound::*;
24 pub use self::SelfTy::*;
25 pub use self::FunctionRetTy::*;
26
27 use syntax;
28 use syntax::abi;
29 use syntax::ast;
30 use syntax::ast_util;
31 use syntax::attr;
32 use syntax::attr::{AttributeMethods, AttrMetaMethods};
33 use syntax::codemap;
34 use syntax::codemap::{DUMMY_SP, Pos, Spanned};
35 use syntax::parse::token::{self, InternedString, special_idents};
36 use syntax::ptr::P;
37
38 use rustc_trans::back::link;
39 use rustc::metadata::cstore;
40 use rustc::metadata::csearch;
41 use rustc::metadata::decoder;
42 use rustc::middle::def;
43 use rustc::middle::subst::{self, ParamSpace, VecPerParamSpace};
44 use rustc::middle::ty;
45 use rustc::middle::stability;
46
47 use std::collections::HashMap;
48 use std::path::PathBuf;
49 use std::rc::Rc;
50 use std::u32;
51
52 use core::DocContext;
53 use doctree;
54 use visit_ast;
55
56 /// A stable identifier to the particular version of JSON output.
57 /// Increment this when the `Crate` and related structures change.
58 pub static SCHEMA_VERSION: &'static str = "0.8.3";
59
60 mod inline;
61 mod simplify;
62
63 // extract the stability index for a node from tcx, if possible
64 fn get_stability(cx: &DocContext, def_id: ast::DefId) -> Option<Stability> {
65 cx.tcx_opt().and_then(|tcx| stability::lookup(tcx, def_id)).clean(cx)
66 }
67
68 pub trait Clean<T> {
69 fn clean(&self, cx: &DocContext) -> T;
70 }
71
72 impl<T: Clean<U>, U> Clean<Vec<U>> for [T] {
73 fn clean(&self, cx: &DocContext) -> Vec<U> {
74 self.iter().map(|x| x.clean(cx)).collect()
75 }
76 }
77
78 impl<T: Clean<U>, U> Clean<VecPerParamSpace<U>> for VecPerParamSpace<T> {
79 fn clean(&self, cx: &DocContext) -> VecPerParamSpace<U> {
80 self.map(|x| x.clean(cx))
81 }
82 }
83
84 impl<T: Clean<U>, U> Clean<U> for P<T> {
85 fn clean(&self, cx: &DocContext) -> U {
86 (**self).clean(cx)
87 }
88 }
89
90 impl<T: Clean<U>, U> Clean<U> for Rc<T> {
91 fn clean(&self, cx: &DocContext) -> U {
92 (**self).clean(cx)
93 }
94 }
95
96 impl<T: Clean<U>, U> Clean<Option<U>> for Option<T> {
97 fn clean(&self, cx: &DocContext) -> Option<U> {
98 match self {
99 &None => None,
100 &Some(ref v) => Some(v.clean(cx))
101 }
102 }
103 }
104
105 impl<T, U> Clean<U> for ty::Binder<T> where T: Clean<U> {
106 fn clean(&self, cx: &DocContext) -> U {
107 self.0.clean(cx)
108 }
109 }
110
111 impl<T: Clean<U>, U> Clean<Vec<U>> for syntax::owned_slice::OwnedSlice<T> {
112 fn clean(&self, cx: &DocContext) -> Vec<U> {
113 self.iter().map(|x| x.clean(cx)).collect()
114 }
115 }
116
117 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
118 pub struct Crate {
119 pub name: String,
120 pub src: PathBuf,
121 pub module: Option<Item>,
122 pub externs: Vec<(ast::CrateNum, ExternalCrate)>,
123 pub primitives: Vec<PrimitiveType>,
124 pub external_traits: HashMap<ast::DefId, Trait>,
125 }
126
127 impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> {
128 fn clean(&self, cx: &DocContext) -> Crate {
129 use rustc::session::config::Input;
130
131 let mut externs = Vec::new();
132 cx.sess().cstore.iter_crate_data(|n, meta| {
133 externs.push((n, meta.clean(cx)));
134 });
135 externs.sort_by(|&(a, _), &(b, _)| a.cmp(&b));
136
137 // Figure out the name of this crate
138 let input = &cx.input;
139 let name = link::find_crate_name(None, &self.attrs, input);
140
141 // Clean the crate, translating the entire libsyntax AST to one that is
142 // understood by rustdoc.
143 let mut module = self.module.clean(cx);
144
145 // Collect all inner modules which are tagged as implementations of
146 // primitives.
147 //
148 // Note that this loop only searches the top-level items of the crate,
149 // and this is intentional. If we were to search the entire crate for an
150 // item tagged with `#[doc(primitive)]` then we we would also have to
151 // search the entirety of external modules for items tagged
152 // `#[doc(primitive)]`, which is a pretty inefficient process (decoding
153 // all that metadata unconditionally).
154 //
155 // In order to keep the metadata load under control, the
156 // `#[doc(primitive)]` feature is explicitly designed to only allow the
157 // primitive tags to show up as the top level items in a crate.
158 //
159 // Also note that this does not attempt to deal with modules tagged
160 // duplicately for the same primitive. This is handled later on when
161 // rendering by delegating everything to a hash map.
162 let mut primitives = Vec::new();
163 {
164 let m = match module.inner {
165 ModuleItem(ref mut m) => m,
166 _ => unreachable!(),
167 };
168 let mut tmp = Vec::new();
169 for child in &mut m.items {
170 match child.inner {
171 ModuleItem(..) => {}
172 _ => continue,
173 }
174 let prim = match PrimitiveType::find(&child.attrs) {
175 Some(prim) => prim,
176 None => continue,
177 };
178 primitives.push(prim);
179 tmp.push(Item {
180 source: Span::empty(),
181 name: Some(prim.to_url_str().to_string()),
182 attrs: child.attrs.clone(),
183 visibility: Some(ast::Public),
184 stability: None,
185 def_id: ast_util::local_def(prim.to_node_id()),
186 inner: PrimitiveItem(prim),
187 });
188 }
189 m.items.extend(tmp.into_iter());
190 }
191
192 let src = match cx.input {
193 Input::File(ref path) => path.clone(),
194 Input::Str(_) => PathBuf::new() // FIXME: this is wrong
195 };
196
197 Crate {
198 name: name.to_string(),
199 src: src,
200 module: Some(module),
201 externs: externs,
202 primitives: primitives,
203 external_traits: cx.external_traits.borrow_mut().take()
204 .unwrap_or(HashMap::new()),
205 }
206 }
207 }
208
209 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
210 pub struct ExternalCrate {
211 pub name: String,
212 pub attrs: Vec<Attribute>,
213 pub primitives: Vec<PrimitiveType>,
214 }
215
216 impl Clean<ExternalCrate> for cstore::crate_metadata {
217 fn clean(&self, cx: &DocContext) -> ExternalCrate {
218 let mut primitives = Vec::new();
219 cx.tcx_opt().map(|tcx| {
220 csearch::each_top_level_item_of_crate(&tcx.sess.cstore,
221 self.cnum,
222 |def, _, _| {
223 let did = match def {
224 decoder::DlDef(def::DefMod(did)) => did,
225 _ => return
226 };
227 let attrs = inline::load_attrs(cx, tcx, did);
228 PrimitiveType::find(&attrs).map(|prim| primitives.push(prim));
229 })
230 });
231 ExternalCrate {
232 name: self.name.to_string(),
233 attrs: decoder::get_crate_attributes(self.data()).clean(cx),
234 primitives: primitives,
235 }
236 }
237 }
238
239 /// Anything with a source location and set of attributes and, optionally, a
240 /// name. That is, anything that can be documented. This doesn't correspond
241 /// directly to the AST's concept of an item; it's a strict superset.
242 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
243 pub struct Item {
244 /// Stringified span
245 pub source: Span,
246 /// Not everything has a name. E.g., impls
247 pub name: Option<String>,
248 pub attrs: Vec<Attribute> ,
249 pub inner: ItemEnum,
250 pub visibility: Option<Visibility>,
251 pub def_id: ast::DefId,
252 pub stability: Option<Stability>,
253 }
254
255 impl Item {
256 /// Finds the `doc` attribute as a List and returns the list of attributes
257 /// nested inside.
258 pub fn doc_list<'a>(&'a self) -> Option<&'a [Attribute]> {
259 for attr in &self.attrs {
260 match *attr {
261 List(ref x, ref list) if "doc" == *x => {
262 return Some(list);
263 }
264 _ => {}
265 }
266 }
267 return None;
268 }
269
270 /// Finds the `doc` attribute as a NameValue and returns the corresponding
271 /// value found.
272 pub fn doc_value<'a>(&'a self) -> Option<&'a str> {
273 for attr in &self.attrs {
274 match *attr {
275 NameValue(ref x, ref v) if "doc" == *x => {
276 return Some(v);
277 }
278 _ => {}
279 }
280 }
281 return None;
282 }
283
284 pub fn is_hidden_from_doc(&self) -> bool {
285 match self.doc_list() {
286 Some(l) => {
287 for innerattr in l {
288 match *innerattr {
289 Word(ref s) if "hidden" == *s => {
290 return true
291 }
292 _ => (),
293 }
294 }
295 },
296 None => ()
297 }
298 return false;
299 }
300
301 pub fn is_mod(&self) -> bool {
302 match self.inner { ModuleItem(..) => true, _ => false }
303 }
304 pub fn is_trait(&self) -> bool {
305 match self.inner { TraitItem(..) => true, _ => false }
306 }
307 pub fn is_struct(&self) -> bool {
308 match self.inner { StructItem(..) => true, _ => false }
309 }
310 pub fn is_enum(&self) -> bool {
311 match self.inner { EnumItem(..) => true, _ => false }
312 }
313 pub fn is_fn(&self) -> bool {
314 match self.inner { FunctionItem(..) => true, _ => false }
315 }
316 }
317
318 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
319 pub enum ItemEnum {
320 ExternCrateItem(String, Option<String>),
321 ImportItem(Import),
322 StructItem(Struct),
323 EnumItem(Enum),
324 FunctionItem(Function),
325 ModuleItem(Module),
326 TypedefItem(Typedef),
327 StaticItem(Static),
328 ConstantItem(Constant),
329 TraitItem(Trait),
330 ImplItem(Impl),
331 /// A method signature only. Used for required methods in traits (ie,
332 /// non-default-methods).
333 TyMethodItem(TyMethod),
334 /// A method with a body.
335 MethodItem(Method),
336 StructFieldItem(StructField),
337 VariantItem(Variant),
338 /// `fn`s from an extern block
339 ForeignFunctionItem(Function),
340 /// `static`s from an extern block
341 ForeignStaticItem(Static),
342 MacroItem(Macro),
343 PrimitiveItem(PrimitiveType),
344 AssociatedTypeItem(Vec<TyParamBound>, Option<Type>),
345 DefaultImplItem(DefaultImpl),
346 }
347
348 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
349 pub struct Module {
350 pub items: Vec<Item>,
351 pub is_crate: bool,
352 }
353
354 impl Clean<Item> for doctree::Module {
355 fn clean(&self, cx: &DocContext) -> Item {
356 let name = if self.name.is_some() {
357 self.name.unwrap().clean(cx)
358 } else {
359 "".to_string()
360 };
361
362 let mut items: Vec<Item> = vec![];
363 items.extend(self.extern_crates.iter().map(|x| x.clean(cx)));
364 items.extend(self.imports.iter().flat_map(|x| x.clean(cx).into_iter()));
365 items.extend(self.structs.iter().map(|x| x.clean(cx)));
366 items.extend(self.enums.iter().map(|x| x.clean(cx)));
367 items.extend(self.fns.iter().map(|x| x.clean(cx)));
368 items.extend(self.foreigns.iter().flat_map(|x| x.clean(cx).into_iter()));
369 items.extend(self.mods.iter().map(|x| x.clean(cx)));
370 items.extend(self.typedefs.iter().map(|x| x.clean(cx)));
371 items.extend(self.statics.iter().map(|x| x.clean(cx)));
372 items.extend(self.constants.iter().map(|x| x.clean(cx)));
373 items.extend(self.traits.iter().map(|x| x.clean(cx)));
374 items.extend(self.impls.iter().map(|x| x.clean(cx)));
375 items.extend(self.macros.iter().map(|x| x.clean(cx)));
376 items.extend(self.def_traits.iter().map(|x| x.clean(cx)));
377
378 // determine if we should display the inner contents or
379 // the outer `mod` item for the source code.
380 let whence = {
381 let cm = cx.sess().codemap();
382 let outer = cm.lookup_char_pos(self.where_outer.lo);
383 let inner = cm.lookup_char_pos(self.where_inner.lo);
384 if outer.file.start_pos == inner.file.start_pos {
385 // mod foo { ... }
386 self.where_outer
387 } else {
388 // mod foo; (and a separate FileMap for the contents)
389 self.where_inner
390 }
391 };
392
393 Item {
394 name: Some(name),
395 attrs: self.attrs.clean(cx),
396 source: whence.clean(cx),
397 visibility: self.vis.clean(cx),
398 stability: self.stab.clean(cx),
399 def_id: ast_util::local_def(self.id),
400 inner: ModuleItem(Module {
401 is_crate: self.is_crate,
402 items: items
403 })
404 }
405 }
406 }
407
408 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
409 pub enum Attribute {
410 Word(String),
411 List(String, Vec<Attribute> ),
412 NameValue(String, String)
413 }
414
415 impl Clean<Attribute> for ast::MetaItem {
416 fn clean(&self, cx: &DocContext) -> Attribute {
417 match self.node {
418 ast::MetaWord(ref s) => Word(s.to_string()),
419 ast::MetaList(ref s, ref l) => {
420 List(s.to_string(), l.clean(cx))
421 }
422 ast::MetaNameValue(ref s, ref v) => {
423 NameValue(s.to_string(), lit_to_string(v))
424 }
425 }
426 }
427 }
428
429 impl Clean<Attribute> for ast::Attribute {
430 fn clean(&self, cx: &DocContext) -> Attribute {
431 self.with_desugared_doc(|a| a.node.value.clean(cx))
432 }
433 }
434
435 // This is a rough approximation that gets us what we want.
436 impl attr::AttrMetaMethods for Attribute {
437 fn name(&self) -> InternedString {
438 match *self {
439 Word(ref n) | List(ref n, _) | NameValue(ref n, _) => {
440 token::intern_and_get_ident(n)
441 }
442 }
443 }
444
445 fn value_str(&self) -> Option<InternedString> {
446 match *self {
447 NameValue(_, ref v) => {
448 Some(token::intern_and_get_ident(v))
449 }
450 _ => None,
451 }
452 }
453 fn meta_item_list<'a>(&'a self) -> Option<&'a [P<ast::MetaItem>]> { None }
454 fn span(&self) -> codemap::Span { unimplemented!() }
455 }
456 impl<'a> attr::AttrMetaMethods for &'a Attribute {
457 fn name(&self) -> InternedString { (**self).name() }
458 fn value_str(&self) -> Option<InternedString> { (**self).value_str() }
459 fn meta_item_list(&self) -> Option<&[P<ast::MetaItem>]> { None }
460 fn span(&self) -> codemap::Span { unimplemented!() }
461 }
462
463 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
464 pub struct TyParam {
465 pub name: String,
466 pub did: ast::DefId,
467 pub bounds: Vec<TyParamBound>,
468 pub default: Option<Type>,
469 }
470
471 impl Clean<TyParam> for ast::TyParam {
472 fn clean(&self, cx: &DocContext) -> TyParam {
473 TyParam {
474 name: self.ident.clean(cx),
475 did: ast::DefId { krate: ast::LOCAL_CRATE, node: self.id },
476 bounds: self.bounds.clean(cx),
477 default: self.default.clean(cx),
478 }
479 }
480 }
481
482 impl<'tcx> Clean<TyParam> for ty::TypeParameterDef<'tcx> {
483 fn clean(&self, cx: &DocContext) -> TyParam {
484 cx.external_typarams.borrow_mut().as_mut().unwrap()
485 .insert(self.def_id, self.name.clean(cx));
486 TyParam {
487 name: self.name.clean(cx),
488 did: self.def_id,
489 bounds: vec![], // these are filled in from the where-clauses
490 default: self.default.clean(cx),
491 }
492 }
493 }
494
495 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
496 pub enum TyParamBound {
497 RegionBound(Lifetime),
498 TraitBound(PolyTrait, ast::TraitBoundModifier)
499 }
500
501 impl TyParamBound {
502 fn maybe_sized(cx: &DocContext) -> TyParamBound {
503 use syntax::ast::TraitBoundModifier as TBM;
504 let mut sized_bound = ty::BuiltinBound::BoundSized.clean(cx);
505 if let TyParamBound::TraitBound(_, ref mut tbm) = sized_bound {
506 *tbm = TBM::Maybe
507 };
508 sized_bound
509 }
510
511 fn is_sized_bound(&self, cx: &DocContext) -> bool {
512 use syntax::ast::TraitBoundModifier as TBM;
513 if let Some(tcx) = cx.tcx_opt() {
514 let sized_did = match tcx.lang_items.sized_trait() {
515 Some(did) => did,
516 None => return false
517 };
518 if let TyParamBound::TraitBound(PolyTrait {
519 trait_: Type::ResolvedPath { did, .. }, ..
520 }, TBM::None) = *self {
521 if did == sized_did {
522 return true
523 }
524 }
525 }
526 false
527 }
528 }
529
530 impl Clean<TyParamBound> for ast::TyParamBound {
531 fn clean(&self, cx: &DocContext) -> TyParamBound {
532 match *self {
533 ast::RegionTyParamBound(lt) => RegionBound(lt.clean(cx)),
534 ast::TraitTyParamBound(ref t, modifier) => TraitBound(t.clean(cx), modifier),
535 }
536 }
537 }
538
539 impl<'tcx> Clean<(Vec<TyParamBound>, Vec<TypeBinding>)> for ty::ExistentialBounds<'tcx> {
540 fn clean(&self, cx: &DocContext) -> (Vec<TyParamBound>, Vec<TypeBinding>) {
541 let mut tp_bounds = vec![];
542 self.region_bound.clean(cx).map(|b| tp_bounds.push(RegionBound(b)));
543 for bb in &self.builtin_bounds {
544 tp_bounds.push(bb.clean(cx));
545 }
546
547 let mut bindings = vec![];
548 for &ty::Binder(ref pb) in &self.projection_bounds {
549 bindings.push(TypeBinding {
550 name: pb.projection_ty.item_name.clean(cx),
551 ty: pb.ty.clean(cx)
552 });
553 }
554
555 (tp_bounds, bindings)
556 }
557 }
558
559 fn external_path_params(cx: &DocContext, trait_did: Option<ast::DefId>,
560 bindings: Vec<TypeBinding>, substs: &subst::Substs) -> PathParameters {
561 use rustc::middle::ty::sty;
562 let lifetimes = substs.regions().get_slice(subst::TypeSpace)
563 .iter()
564 .filter_map(|v| v.clean(cx))
565 .collect();
566 let types = substs.types.get_slice(subst::TypeSpace).to_vec();
567
568 match (trait_did, cx.tcx_opt()) {
569 // Attempt to sugar an external path like Fn<(A, B,), C> to Fn(A, B) -> C
570 (Some(did), Some(ref tcx)) if tcx.lang_items.fn_trait_kind(did).is_some() => {
571 assert_eq!(types.len(), 1);
572 let inputs = match types[0].sty {
573 sty::ty_tup(ref tys) => tys.iter().map(|t| t.clean(cx)).collect(),
574 _ => {
575 return PathParameters::AngleBracketed {
576 lifetimes: lifetimes,
577 types: types.clean(cx),
578 bindings: bindings
579 }
580 }
581 };
582 let output = None;
583 // FIXME(#20299) return type comes from a projection now
584 // match types[1].sty {
585 // sty::ty_tup(ref v) if v.is_empty() => None, // -> ()
586 // _ => Some(types[1].clean(cx))
587 // };
588 PathParameters::Parenthesized {
589 inputs: inputs,
590 output: output
591 }
592 },
593 (_, _) => {
594 PathParameters::AngleBracketed {
595 lifetimes: lifetimes,
596 types: types.clean(cx),
597 bindings: bindings
598 }
599 }
600 }
601 }
602
603 // trait_did should be set to a trait's DefId if called on a TraitRef, in order to sugar
604 // from Fn<(A, B,), C> to Fn(A, B) -> C
605 fn external_path(cx: &DocContext, name: &str, trait_did: Option<ast::DefId>,
606 bindings: Vec<TypeBinding>, substs: &subst::Substs) -> Path {
607 Path {
608 global: false,
609 segments: vec![PathSegment {
610 name: name.to_string(),
611 params: external_path_params(cx, trait_did, bindings, substs)
612 }],
613 }
614 }
615
616 impl Clean<TyParamBound> for ty::BuiltinBound {
617 fn clean(&self, cx: &DocContext) -> TyParamBound {
618 let tcx = match cx.tcx_opt() {
619 Some(tcx) => tcx,
620 None => return RegionBound(Lifetime::statik())
621 };
622 let empty = subst::Substs::empty();
623 let (did, path) = match *self {
624 ty::BoundSend =>
625 (tcx.lang_items.send_trait().unwrap(),
626 external_path(cx, "Send", None, vec![], &empty)),
627 ty::BoundSized =>
628 (tcx.lang_items.sized_trait().unwrap(),
629 external_path(cx, "Sized", None, vec![], &empty)),
630 ty::BoundCopy =>
631 (tcx.lang_items.copy_trait().unwrap(),
632 external_path(cx, "Copy", None, vec![], &empty)),
633 ty::BoundSync =>
634 (tcx.lang_items.sync_trait().unwrap(),
635 external_path(cx, "Sync", None, vec![], &empty)),
636 };
637 let fqn = csearch::get_item_path(tcx, did);
638 let fqn = fqn.into_iter().map(|i| i.to_string()).collect();
639 cx.external_paths.borrow_mut().as_mut().unwrap().insert(did,
640 (fqn, TypeTrait));
641 TraitBound(PolyTrait {
642 trait_: ResolvedPath {
643 path: path,
644 typarams: None,
645 did: did,
646 },
647 lifetimes: vec![]
648 }, ast::TraitBoundModifier::None)
649 }
650 }
651
652 impl<'tcx> Clean<TyParamBound> for ty::TraitRef<'tcx> {
653 fn clean(&self, cx: &DocContext) -> TyParamBound {
654 let tcx = match cx.tcx_opt() {
655 Some(tcx) => tcx,
656 None => return RegionBound(Lifetime::statik())
657 };
658 let fqn = csearch::get_item_path(tcx, self.def_id);
659 let fqn = fqn.into_iter().map(|i| i.to_string())
660 .collect::<Vec<String>>();
661 let path = external_path(cx, fqn.last().unwrap(),
662 Some(self.def_id), vec![], self.substs);
663 cx.external_paths.borrow_mut().as_mut().unwrap().insert(self.def_id,
664 (fqn, TypeTrait));
665
666 debug!("ty::TraitRef\n substs.types(TypeSpace): {:?}\n",
667 self.substs.types.get_slice(ParamSpace::TypeSpace));
668
669 // collect any late bound regions
670 let mut late_bounds = vec![];
671 for &ty_s in self.substs.types.get_slice(ParamSpace::TypeSpace) {
672 use rustc::middle::ty::{Region, sty};
673 if let sty::ty_tup(ref ts) = ty_s.sty {
674 for &ty_s in ts {
675 if let sty::ty_rptr(ref reg, _) = ty_s.sty {
676 if let &Region::ReLateBound(_, _) = *reg {
677 debug!(" hit an ReLateBound {:?}", reg);
678 if let Some(lt) = reg.clean(cx) {
679 late_bounds.push(lt)
680 }
681 }
682 }
683 }
684 }
685 }
686
687 TraitBound(PolyTrait {
688 trait_: ResolvedPath { path: path, typarams: None, did: self.def_id, },
689 lifetimes: late_bounds
690 }, ast::TraitBoundModifier::None)
691 }
692 }
693
694 impl<'tcx> Clean<Vec<TyParamBound>> for ty::ParamBounds<'tcx> {
695 fn clean(&self, cx: &DocContext) -> Vec<TyParamBound> {
696 let mut v = Vec::new();
697 for t in &self.trait_bounds {
698 v.push(t.clean(cx));
699 }
700 for r in self.region_bounds.iter().filter_map(|r| r.clean(cx)) {
701 v.push(RegionBound(r));
702 }
703 v
704 }
705 }
706
707 impl<'tcx> Clean<Option<Vec<TyParamBound>>> for subst::Substs<'tcx> {
708 fn clean(&self, cx: &DocContext) -> Option<Vec<TyParamBound>> {
709 let mut v = Vec::new();
710 v.extend(self.regions().iter().filter_map(|r| r.clean(cx)).map(RegionBound));
711 v.extend(self.types.iter().map(|t| TraitBound(PolyTrait {
712 trait_: t.clean(cx),
713 lifetimes: vec![]
714 }, ast::TraitBoundModifier::None)));
715 if !v.is_empty() {Some(v)} else {None}
716 }
717 }
718
719 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
720 pub struct Lifetime(String);
721
722 impl Lifetime {
723 pub fn get_ref<'a>(&'a self) -> &'a str {
724 let Lifetime(ref s) = *self;
725 let s: &'a str = s;
726 return s;
727 }
728
729 pub fn statik() -> Lifetime {
730 Lifetime("'static".to_string())
731 }
732 }
733
734 impl Clean<Lifetime> for ast::Lifetime {
735 fn clean(&self, _: &DocContext) -> Lifetime {
736 Lifetime(token::get_name(self.name).to_string())
737 }
738 }
739
740 impl Clean<Lifetime> for ast::LifetimeDef {
741 fn clean(&self, _: &DocContext) -> Lifetime {
742 Lifetime(token::get_name(self.lifetime.name).to_string())
743 }
744 }
745
746 impl Clean<Lifetime> for ty::RegionParameterDef {
747 fn clean(&self, _: &DocContext) -> Lifetime {
748 Lifetime(token::get_name(self.name).to_string())
749 }
750 }
751
752 impl Clean<Option<Lifetime>> for ty::Region {
753 fn clean(&self, cx: &DocContext) -> Option<Lifetime> {
754 match *self {
755 ty::ReStatic => Some(Lifetime::statik()),
756 ty::ReLateBound(_, ty::BrNamed(_, name)) =>
757 Some(Lifetime(token::get_name(name).to_string())),
758 ty::ReEarlyBound(ref data) => Some(Lifetime(data.name.clean(cx))),
759
760 ty::ReLateBound(..) |
761 ty::ReFree(..) |
762 ty::ReScope(..) |
763 ty::ReInfer(..) |
764 ty::ReEmpty(..) => None
765 }
766 }
767 }
768
769 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
770 pub enum WherePredicate {
771 BoundPredicate { ty: Type, bounds: Vec<TyParamBound> },
772 RegionPredicate { lifetime: Lifetime, bounds: Vec<Lifetime>},
773 EqPredicate { lhs: Type, rhs: Type }
774 }
775
776 impl Clean<WherePredicate> for ast::WherePredicate {
777 fn clean(&self, cx: &DocContext) -> WherePredicate {
778 match *self {
779 ast::WherePredicate::BoundPredicate(ref wbp) => {
780 WherePredicate::BoundPredicate {
781 ty: wbp.bounded_ty.clean(cx),
782 bounds: wbp.bounds.clean(cx)
783 }
784 }
785
786 ast::WherePredicate::RegionPredicate(ref wrp) => {
787 WherePredicate::RegionPredicate {
788 lifetime: wrp.lifetime.clean(cx),
789 bounds: wrp.bounds.clean(cx)
790 }
791 }
792
793 ast::WherePredicate::EqPredicate(_) => {
794 unimplemented!() // FIXME(#20041)
795 }
796 }
797 }
798 }
799
800 impl<'a> Clean<WherePredicate> for ty::Predicate<'a> {
801 fn clean(&self, cx: &DocContext) -> WherePredicate {
802 use rustc::middle::ty::Predicate;
803
804 match *self {
805 Predicate::Trait(ref pred) => pred.clean(cx),
806 Predicate::Equate(ref pred) => pred.clean(cx),
807 Predicate::RegionOutlives(ref pred) => pred.clean(cx),
808 Predicate::TypeOutlives(ref pred) => pred.clean(cx),
809 Predicate::Projection(ref pred) => pred.clean(cx)
810 }
811 }
812 }
813
814 impl<'a> Clean<WherePredicate> for ty::TraitPredicate<'a> {
815 fn clean(&self, cx: &DocContext) -> WherePredicate {
816 WherePredicate::BoundPredicate {
817 ty: self.trait_ref.substs.self_ty().clean(cx).unwrap(),
818 bounds: vec![self.trait_ref.clean(cx)]
819 }
820 }
821 }
822
823 impl<'tcx> Clean<WherePredicate> for ty::EquatePredicate<'tcx> {
824 fn clean(&self, cx: &DocContext) -> WherePredicate {
825 let ty::EquatePredicate(ref lhs, ref rhs) = *self;
826 WherePredicate::EqPredicate {
827 lhs: lhs.clean(cx),
828 rhs: rhs.clean(cx)
829 }
830 }
831 }
832
833 impl Clean<WherePredicate> for ty::OutlivesPredicate<ty::Region, ty::Region> {
834 fn clean(&self, cx: &DocContext) -> WherePredicate {
835 let ty::OutlivesPredicate(ref a, ref b) = *self;
836 WherePredicate::RegionPredicate {
837 lifetime: a.clean(cx).unwrap(),
838 bounds: vec![b.clean(cx).unwrap()]
839 }
840 }
841 }
842
843 impl<'tcx> Clean<WherePredicate> for ty::OutlivesPredicate<ty::Ty<'tcx>, ty::Region> {
844 fn clean(&self, cx: &DocContext) -> WherePredicate {
845 let ty::OutlivesPredicate(ref ty, ref lt) = *self;
846
847 WherePredicate::BoundPredicate {
848 ty: ty.clean(cx),
849 bounds: vec![TyParamBound::RegionBound(lt.clean(cx).unwrap())]
850 }
851 }
852 }
853
854 impl<'tcx> Clean<WherePredicate> for ty::ProjectionPredicate<'tcx> {
855 fn clean(&self, cx: &DocContext) -> WherePredicate {
856 WherePredicate::EqPredicate {
857 lhs: self.projection_ty.clean(cx),
858 rhs: self.ty.clean(cx)
859 }
860 }
861 }
862
863 impl<'tcx> Clean<Type> for ty::ProjectionTy<'tcx> {
864 fn clean(&self, cx: &DocContext) -> Type {
865 let trait_ = match self.trait_ref.clean(cx) {
866 TyParamBound::TraitBound(t, _) => t.trait_,
867 TyParamBound::RegionBound(_) => {
868 panic!("cleaning a trait got a region")
869 }
870 };
871 Type::QPath {
872 name: self.item_name.clean(cx),
873 self_type: box self.trait_ref.self_ty().clean(cx),
874 trait_: box trait_
875 }
876 }
877 }
878
879 // maybe use a Generic enum and use ~[Generic]?
880 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
881 pub struct Generics {
882 pub lifetimes: Vec<Lifetime>,
883 pub type_params: Vec<TyParam>,
884 pub where_predicates: Vec<WherePredicate>
885 }
886
887 impl Clean<Generics> for ast::Generics {
888 fn clean(&self, cx: &DocContext) -> Generics {
889 Generics {
890 lifetimes: self.lifetimes.clean(cx),
891 type_params: self.ty_params.clean(cx),
892 where_predicates: self.where_clause.predicates.clean(cx)
893 }
894 }
895 }
896
897 impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics<'tcx>,
898 &'a ty::GenericPredicates<'tcx>,
899 subst::ParamSpace) {
900 fn clean(&self, cx: &DocContext) -> Generics {
901 use std::collections::HashSet;
902 use self::WherePredicate as WP;
903
904 let (gens, preds, space) = *self;
905
906 // Bounds in the type_params and lifetimes fields are repeated in the
907 // predicates field (see rustc_typeck::collect::ty_generics), so remove
908 // them.
909 let stripped_typarams = gens.types.get_slice(space).iter().map(|tp| {
910 tp.clean(cx)
911 }).collect::<Vec<_>>();
912 let stripped_lifetimes = gens.regions.get_slice(space).iter().map(|rp| {
913 let mut srp = rp.clone();
914 srp.bounds = Vec::new();
915 srp.clean(cx)
916 }).collect::<Vec<_>>();
917
918 let mut where_predicates = preds.predicates.get_slice(space)
919 .to_vec().clean(cx);
920
921 // Type parameters and have a Sized bound by default unless removed with
922 // ?Sized. Scan through the predicates and mark any type parameter with
923 // a Sized bound, removing the bounds as we find them.
924 //
925 // Note that associated types also have a sized bound by default, but we
926 // don't actually konw the set of associated types right here so that's
927 // handled in cleaning associated types
928 let mut sized_params = HashSet::new();
929 where_predicates.retain(|pred| {
930 match *pred {
931 WP::BoundPredicate { ty: Generic(ref g), ref bounds } => {
932 if bounds.iter().any(|b| b.is_sized_bound(cx)) {
933 sized_params.insert(g.clone());
934 false
935 } else {
936 true
937 }
938 }
939 _ => true,
940 }
941 });
942
943 // Run through the type parameters again and insert a ?Sized
944 // unbound for any we didn't find to be Sized.
945 for tp in &stripped_typarams {
946 if !sized_params.contains(&tp.name) {
947 where_predicates.push(WP::BoundPredicate {
948 ty: Type::Generic(tp.name.clone()),
949 bounds: vec![TyParamBound::maybe_sized(cx)],
950 })
951 }
952 }
953
954 // It would be nice to collect all of the bounds on a type and recombine
955 // them if possible, to avoid e.g. `where T: Foo, T: Bar, T: Sized, T: 'a`
956 // and instead see `where T: Foo + Bar + Sized + 'a`
957
958 Generics {
959 type_params: simplify::ty_params(stripped_typarams),
960 lifetimes: stripped_lifetimes,
961 where_predicates: simplify::where_clauses(cx, where_predicates),
962 }
963 }
964 }
965
966 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
967 pub struct Method {
968 pub generics: Generics,
969 pub self_: SelfTy,
970 pub unsafety: ast::Unsafety,
971 pub decl: FnDecl,
972 pub abi: abi::Abi
973 }
974
975 impl Clean<Method> for ast::MethodSig {
976 fn clean(&self, cx: &DocContext) -> Method {
977 let all_inputs = &self.decl.inputs;
978 let inputs = match self.explicit_self.node {
979 ast::SelfStatic => &**all_inputs,
980 _ => &all_inputs[1..]
981 };
982 let decl = FnDecl {
983 inputs: Arguments {
984 values: inputs.clean(cx),
985 },
986 output: self.decl.output.clean(cx),
987 attrs: Vec::new()
988 };
989 Method {
990 generics: self.generics.clean(cx),
991 self_: self.explicit_self.node.clean(cx),
992 unsafety: self.unsafety.clone(),
993 decl: decl,
994 abi: self.abi
995 }
996 }
997 }
998
999 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1000 pub struct TyMethod {
1001 pub unsafety: ast::Unsafety,
1002 pub decl: FnDecl,
1003 pub generics: Generics,
1004 pub self_: SelfTy,
1005 pub abi: abi::Abi
1006 }
1007
1008 impl Clean<TyMethod> for ast::MethodSig {
1009 fn clean(&self, cx: &DocContext) -> TyMethod {
1010 let inputs = match self.explicit_self.node {
1011 ast::SelfStatic => &*self.decl.inputs,
1012 _ => &self.decl.inputs[1..]
1013 };
1014 let decl = FnDecl {
1015 inputs: Arguments {
1016 values: inputs.clean(cx),
1017 },
1018 output: self.decl.output.clean(cx),
1019 attrs: Vec::new()
1020 };
1021 TyMethod {
1022 unsafety: self.unsafety.clone(),
1023 decl: decl,
1024 self_: self.explicit_self.node.clean(cx),
1025 generics: self.generics.clean(cx),
1026 abi: self.abi
1027 }
1028 }
1029 }
1030
1031 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1032 pub enum SelfTy {
1033 SelfStatic,
1034 SelfValue,
1035 SelfBorrowed(Option<Lifetime>, Mutability),
1036 SelfExplicit(Type),
1037 }
1038
1039 impl Clean<SelfTy> for ast::ExplicitSelf_ {
1040 fn clean(&self, cx: &DocContext) -> SelfTy {
1041 match *self {
1042 ast::SelfStatic => SelfStatic,
1043 ast::SelfValue(_) => SelfValue,
1044 ast::SelfRegion(ref lt, ref mt, _) => {
1045 SelfBorrowed(lt.clean(cx), mt.clean(cx))
1046 }
1047 ast::SelfExplicit(ref typ, _) => SelfExplicit(typ.clean(cx)),
1048 }
1049 }
1050 }
1051
1052 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1053 pub struct Function {
1054 pub decl: FnDecl,
1055 pub generics: Generics,
1056 pub unsafety: ast::Unsafety,
1057 pub abi: abi::Abi
1058 }
1059
1060 impl Clean<Item> for doctree::Function {
1061 fn clean(&self, cx: &DocContext) -> Item {
1062 Item {
1063 name: Some(self.name.clean(cx)),
1064 attrs: self.attrs.clean(cx),
1065 source: self.whence.clean(cx),
1066 visibility: self.vis.clean(cx),
1067 stability: self.stab.clean(cx),
1068 def_id: ast_util::local_def(self.id),
1069 inner: FunctionItem(Function {
1070 decl: self.decl.clean(cx),
1071 generics: self.generics.clean(cx),
1072 unsafety: self.unsafety,
1073 abi: self.abi,
1074 }),
1075 }
1076 }
1077 }
1078
1079 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1080 pub struct FnDecl {
1081 pub inputs: Arguments,
1082 pub output: FunctionRetTy,
1083 pub attrs: Vec<Attribute>,
1084 }
1085
1086 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1087 pub struct Arguments {
1088 pub values: Vec<Argument>,
1089 }
1090
1091 impl Clean<FnDecl> for ast::FnDecl {
1092 fn clean(&self, cx: &DocContext) -> FnDecl {
1093 FnDecl {
1094 inputs: Arguments {
1095 values: self.inputs.clean(cx),
1096 },
1097 output: self.output.clean(cx),
1098 attrs: Vec::new()
1099 }
1100 }
1101 }
1102
1103 impl<'tcx> Clean<Type> for ty::FnOutput<'tcx> {
1104 fn clean(&self, cx: &DocContext) -> Type {
1105 match *self {
1106 ty::FnConverging(ty) => ty.clean(cx),
1107 ty::FnDiverging => Bottom
1108 }
1109 }
1110 }
1111
1112 impl<'a, 'tcx> Clean<FnDecl> for (ast::DefId, &'a ty::PolyFnSig<'tcx>) {
1113 fn clean(&self, cx: &DocContext) -> FnDecl {
1114 let (did, sig) = *self;
1115 let mut names = if did.node != 0 {
1116 csearch::get_method_arg_names(&cx.tcx().sess.cstore, did).into_iter()
1117 } else {
1118 Vec::new().into_iter()
1119 }.peekable();
1120 if names.peek().map(|s| &**s) == Some("self") {
1121 let _ = names.next();
1122 }
1123 FnDecl {
1124 output: Return(sig.0.output.clean(cx)),
1125 attrs: Vec::new(),
1126 inputs: Arguments {
1127 values: sig.0.inputs.iter().map(|t| {
1128 Argument {
1129 type_: t.clean(cx),
1130 id: 0,
1131 name: names.next().unwrap_or("".to_string()),
1132 }
1133 }).collect(),
1134 },
1135 }
1136 }
1137 }
1138
1139 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1140 pub struct Argument {
1141 pub type_: Type,
1142 pub name: String,
1143 pub id: ast::NodeId,
1144 }
1145
1146 impl Clean<Argument> for ast::Arg {
1147 fn clean(&self, cx: &DocContext) -> Argument {
1148 Argument {
1149 name: name_from_pat(&*self.pat),
1150 type_: (self.ty.clean(cx)),
1151 id: self.id
1152 }
1153 }
1154 }
1155
1156 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1157 pub enum FunctionRetTy {
1158 Return(Type),
1159 DefaultReturn,
1160 NoReturn
1161 }
1162
1163 impl Clean<FunctionRetTy> for ast::FunctionRetTy {
1164 fn clean(&self, cx: &DocContext) -> FunctionRetTy {
1165 match *self {
1166 ast::Return(ref typ) => Return(typ.clean(cx)),
1167 ast::DefaultReturn(..) => DefaultReturn,
1168 ast::NoReturn(..) => NoReturn
1169 }
1170 }
1171 }
1172
1173 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1174 pub struct Trait {
1175 pub unsafety: ast::Unsafety,
1176 pub items: Vec<Item>,
1177 pub generics: Generics,
1178 pub bounds: Vec<TyParamBound>,
1179 }
1180
1181 impl Clean<Item> for doctree::Trait {
1182 fn clean(&self, cx: &DocContext) -> Item {
1183 Item {
1184 name: Some(self.name.clean(cx)),
1185 attrs: self.attrs.clean(cx),
1186 source: self.whence.clean(cx),
1187 def_id: ast_util::local_def(self.id),
1188 visibility: self.vis.clean(cx),
1189 stability: self.stab.clean(cx),
1190 inner: TraitItem(Trait {
1191 unsafety: self.unsafety,
1192 items: self.items.clean(cx),
1193 generics: self.generics.clean(cx),
1194 bounds: self.bounds.clean(cx),
1195 }),
1196 }
1197 }
1198 }
1199
1200 impl Clean<Type> for ast::TraitRef {
1201 fn clean(&self, cx: &DocContext) -> Type {
1202 resolve_type(cx, self.path.clean(cx), self.ref_id)
1203 }
1204 }
1205
1206 impl Clean<PolyTrait> for ast::PolyTraitRef {
1207 fn clean(&self, cx: &DocContext) -> PolyTrait {
1208 PolyTrait {
1209 trait_: self.trait_ref.clean(cx),
1210 lifetimes: self.bound_lifetimes.clean(cx)
1211 }
1212 }
1213 }
1214
1215 impl Clean<Item> for ast::TraitItem {
1216 fn clean(&self, cx: &DocContext) -> Item {
1217 let inner = match self.node {
1218 ast::MethodTraitItem(ref sig, Some(_)) => {
1219 MethodItem(sig.clean(cx))
1220 }
1221 ast::MethodTraitItem(ref sig, None) => {
1222 TyMethodItem(sig.clean(cx))
1223 }
1224 ast::TypeTraitItem(ref bounds, ref default) => {
1225 AssociatedTypeItem(bounds.clean(cx), default.clean(cx))
1226 }
1227 };
1228 Item {
1229 name: Some(self.ident.clean(cx)),
1230 attrs: self.attrs.clean(cx),
1231 source: self.span.clean(cx),
1232 def_id: ast_util::local_def(self.id),
1233 visibility: None,
1234 stability: get_stability(cx, ast_util::local_def(self.id)),
1235 inner: inner
1236 }
1237 }
1238 }
1239
1240 impl Clean<Item> for ast::ImplItem {
1241 fn clean(&self, cx: &DocContext) -> Item {
1242 let inner = match self.node {
1243 ast::MethodImplItem(ref sig, _) => {
1244 MethodItem(sig.clean(cx))
1245 }
1246 ast::TypeImplItem(ref ty) => TypedefItem(Typedef {
1247 type_: ty.clean(cx),
1248 generics: Generics {
1249 lifetimes: Vec::new(),
1250 type_params: Vec::new(),
1251 where_predicates: Vec::new()
1252 },
1253 }),
1254 ast::MacImplItem(_) => {
1255 MacroItem(Macro {
1256 source: self.span.to_src(cx),
1257 })
1258 }
1259 };
1260 Item {
1261 name: Some(self.ident.clean(cx)),
1262 source: self.span.clean(cx),
1263 attrs: self.attrs.clean(cx),
1264 def_id: ast_util::local_def(self.id),
1265 visibility: self.vis.clean(cx),
1266 stability: get_stability(cx, ast_util::local_def(self.id)),
1267 inner: inner
1268 }
1269 }
1270 }
1271
1272 impl<'tcx> Clean<Item> for ty::Method<'tcx> {
1273 fn clean(&self, cx: &DocContext) -> Item {
1274 let (self_, sig) = match self.explicit_self {
1275 ty::StaticExplicitSelfCategory => (ast::SelfStatic.clean(cx),
1276 self.fty.sig.clone()),
1277 s => {
1278 let sig = ty::Binder(ty::FnSig {
1279 inputs: self.fty.sig.0.inputs[1..].to_vec(),
1280 ..self.fty.sig.0.clone()
1281 });
1282 let s = match s {
1283 ty::ByValueExplicitSelfCategory => SelfValue,
1284 ty::ByReferenceExplicitSelfCategory(..) => {
1285 match self.fty.sig.0.inputs[0].sty {
1286 ty::ty_rptr(r, mt) => {
1287 SelfBorrowed(r.clean(cx), mt.mutbl.clean(cx))
1288 }
1289 _ => unreachable!(),
1290 }
1291 }
1292 ty::ByBoxExplicitSelfCategory => {
1293 SelfExplicit(self.fty.sig.0.inputs[0].clean(cx))
1294 }
1295 ty::StaticExplicitSelfCategory => unreachable!(),
1296 };
1297 (s, sig)
1298 }
1299 };
1300
1301 let generics = (&self.generics, &self.predicates,
1302 subst::FnSpace).clean(cx);
1303 let decl = (self.def_id, &sig).clean(cx);
1304 let provided = match self.container {
1305 ty::ImplContainer(..) => false,
1306 ty::TraitContainer(did) => {
1307 ty::provided_trait_methods(cx.tcx(), did).iter().any(|m| {
1308 m.def_id == self.def_id
1309 })
1310 }
1311 };
1312 let inner = if provided {
1313 MethodItem(Method {
1314 unsafety: self.fty.unsafety,
1315 generics: generics,
1316 self_: self_,
1317 decl: decl,
1318 abi: self.fty.abi
1319 })
1320 } else {
1321 TyMethodItem(TyMethod {
1322 unsafety: self.fty.unsafety,
1323 generics: generics,
1324 self_: self_,
1325 decl: decl,
1326 abi: self.fty.abi
1327 })
1328 };
1329
1330 Item {
1331 name: Some(self.name.clean(cx)),
1332 visibility: Some(ast::Inherited),
1333 stability: get_stability(cx, self.def_id),
1334 def_id: self.def_id,
1335 attrs: inline::load_attrs(cx, cx.tcx(), self.def_id),
1336 source: Span::empty(),
1337 inner: inner,
1338 }
1339 }
1340 }
1341
1342 impl<'tcx> Clean<Item> for ty::ImplOrTraitItem<'tcx> {
1343 fn clean(&self, cx: &DocContext) -> Item {
1344 match *self {
1345 ty::MethodTraitItem(ref mti) => mti.clean(cx),
1346 ty::TypeTraitItem(ref tti) => tti.clean(cx),
1347 }
1348 }
1349 }
1350
1351 /// A trait reference, which may have higher ranked lifetimes.
1352 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1353 pub struct PolyTrait {
1354 pub trait_: Type,
1355 pub lifetimes: Vec<Lifetime>
1356 }
1357
1358 /// A representation of a Type suitable for hyperlinking purposes. Ideally one can get the original
1359 /// type out of the AST/ty::ctxt given one of these, if more information is needed. Most importantly
1360 /// it does not preserve mutability or boxes.
1361 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1362 pub enum Type {
1363 /// structs/enums/traits (anything that'd be an ast::TyPath)
1364 ResolvedPath {
1365 path: Path,
1366 typarams: Option<Vec<TyParamBound>>,
1367 did: ast::DefId,
1368 },
1369 /// For parameterized types, so the consumer of the JSON don't go
1370 /// looking for types which don't exist anywhere.
1371 Generic(String),
1372 /// Primitives are the fixed-size numeric types (plus int/usize/float), char,
1373 /// arrays, slices, and tuples.
1374 Primitive(PrimitiveType),
1375 /// extern "ABI" fn
1376 BareFunction(Box<BareFunctionDecl>),
1377 Tuple(Vec<Type>),
1378 Vector(Box<Type>),
1379 FixedVector(Box<Type>, String),
1380 /// aka TyBot
1381 Bottom,
1382 Unique(Box<Type>),
1383 RawPointer(Mutability, Box<Type>),
1384 BorrowedRef {
1385 lifetime: Option<Lifetime>,
1386 mutability: Mutability,
1387 type_: Box<Type>,
1388 },
1389
1390 // <Type as Trait>::Name
1391 QPath {
1392 name: String,
1393 self_type: Box<Type>,
1394 trait_: Box<Type>
1395 },
1396
1397 // _
1398 Infer,
1399
1400 // for<'a> Foo(&'a)
1401 PolyTraitRef(Vec<TyParamBound>),
1402 }
1403
1404 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Copy, Debug)]
1405 pub enum PrimitiveType {
1406 Isize, I8, I16, I32, I64,
1407 Usize, U8, U16, U32, U64,
1408 F32, F64,
1409 Char,
1410 Bool,
1411 Str,
1412 Slice,
1413 Array,
1414 PrimitiveTuple,
1415 PrimitiveRawPointer,
1416 }
1417
1418 #[derive(Clone, RustcEncodable, RustcDecodable, Copy, Debug)]
1419 pub enum TypeKind {
1420 TypeEnum,
1421 TypeFunction,
1422 TypeModule,
1423 TypeConst,
1424 TypeStatic,
1425 TypeStruct,
1426 TypeTrait,
1427 TypeVariant,
1428 TypeTypedef,
1429 }
1430
1431 impl Type {
1432 pub fn primitive_type(&self) -> Option<PrimitiveType> {
1433 match *self {
1434 Primitive(p) | BorrowedRef { type_: box Primitive(p), ..} => Some(p),
1435 Vector(..) | BorrowedRef{ type_: box Vector(..), .. } => Some(Slice),
1436 FixedVector(..) | BorrowedRef { type_: box FixedVector(..), .. } => {
1437 Some(Array)
1438 }
1439 Tuple(..) => Some(PrimitiveTuple),
1440 RawPointer(..) => Some(PrimitiveRawPointer),
1441 _ => None,
1442 }
1443 }
1444 }
1445
1446 impl PrimitiveType {
1447 fn from_str(s: &str) -> Option<PrimitiveType> {
1448 match s {
1449 "isize" => Some(Isize),
1450 "i8" => Some(I8),
1451 "i16" => Some(I16),
1452 "i32" => Some(I32),
1453 "i64" => Some(I64),
1454 "usize" => Some(Usize),
1455 "u8" => Some(U8),
1456 "u16" => Some(U16),
1457 "u32" => Some(U32),
1458 "u64" => Some(U64),
1459 "bool" => Some(Bool),
1460 "char" => Some(Char),
1461 "str" => Some(Str),
1462 "f32" => Some(F32),
1463 "f64" => Some(F64),
1464 "array" => Some(Array),
1465 "slice" => Some(Slice),
1466 "tuple" => Some(PrimitiveTuple),
1467 "pointer" => Some(PrimitiveRawPointer),
1468 _ => None,
1469 }
1470 }
1471
1472 fn find(attrs: &[Attribute]) -> Option<PrimitiveType> {
1473 for attr in attrs {
1474 let list = match *attr {
1475 List(ref k, ref l) if *k == "doc" => l,
1476 _ => continue,
1477 };
1478 for sub_attr in list {
1479 let value = match *sub_attr {
1480 NameValue(ref k, ref v)
1481 if *k == "primitive" => v,
1482 _ => continue,
1483 };
1484 match PrimitiveType::from_str(value) {
1485 Some(p) => return Some(p),
1486 None => {}
1487 }
1488 }
1489 }
1490 return None
1491 }
1492
1493 pub fn to_string(&self) -> &'static str {
1494 match *self {
1495 Isize => "isize",
1496 I8 => "i8",
1497 I16 => "i16",
1498 I32 => "i32",
1499 I64 => "i64",
1500 Usize => "usize",
1501 U8 => "u8",
1502 U16 => "u16",
1503 U32 => "u32",
1504 U64 => "u64",
1505 F32 => "f32",
1506 F64 => "f64",
1507 Str => "str",
1508 Bool => "bool",
1509 Char => "char",
1510 Array => "array",
1511 Slice => "slice",
1512 PrimitiveTuple => "tuple",
1513 PrimitiveRawPointer => "pointer",
1514 }
1515 }
1516
1517 pub fn to_url_str(&self) -> &'static str {
1518 self.to_string()
1519 }
1520
1521 /// Creates a rustdoc-specific node id for primitive types.
1522 ///
1523 /// These node ids are generally never used by the AST itself.
1524 pub fn to_node_id(&self) -> ast::NodeId {
1525 u32::MAX - 1 - (*self as u32)
1526 }
1527 }
1528
1529 impl Clean<Type> for ast::Ty {
1530 fn clean(&self, cx: &DocContext) -> Type {
1531 use syntax::ast::*;
1532 match self.node {
1533 TyPtr(ref m) => RawPointer(m.mutbl.clean(cx), box m.ty.clean(cx)),
1534 TyRptr(ref l, ref m) =>
1535 BorrowedRef {lifetime: l.clean(cx), mutability: m.mutbl.clean(cx),
1536 type_: box m.ty.clean(cx)},
1537 TyVec(ref ty) => Vector(box ty.clean(cx)),
1538 TyFixedLengthVec(ref ty, ref e) => FixedVector(box ty.clean(cx),
1539 e.span.to_src(cx)),
1540 TyTup(ref tys) => Tuple(tys.clean(cx)),
1541 TyPath(None, ref p) => {
1542 resolve_type(cx, p.clean(cx), self.id)
1543 }
1544 TyPath(Some(ref qself), ref p) => {
1545 let mut trait_path = p.clone();
1546 trait_path.segments.pop();
1547 Type::QPath {
1548 name: p.segments.last().unwrap().identifier.clean(cx),
1549 self_type: box qself.ty.clean(cx),
1550 trait_: box resolve_type(cx, trait_path.clean(cx), self.id)
1551 }
1552 }
1553 TyObjectSum(ref lhs, ref bounds) => {
1554 let lhs_ty = lhs.clean(cx);
1555 match lhs_ty {
1556 ResolvedPath { path, typarams: None, did } => {
1557 ResolvedPath { path: path, typarams: Some(bounds.clean(cx)), did: did}
1558 }
1559 _ => {
1560 lhs_ty // shouldn't happen
1561 }
1562 }
1563 }
1564 TyBareFn(ref barefn) => BareFunction(box barefn.clean(cx)),
1565 TyParen(ref ty) => ty.clean(cx),
1566 TyPolyTraitRef(ref bounds) => {
1567 PolyTraitRef(bounds.clean(cx))
1568 },
1569 TyInfer(..) => {
1570 Infer
1571 },
1572 TyTypeof(..) => {
1573 panic!("Unimplemented type {:?}", self.node)
1574 },
1575 }
1576 }
1577 }
1578
1579 impl<'tcx> Clean<Type> for ty::Ty<'tcx> {
1580 fn clean(&self, cx: &DocContext) -> Type {
1581 match self.sty {
1582 ty::ty_bool => Primitive(Bool),
1583 ty::ty_char => Primitive(Char),
1584 ty::ty_int(ast::TyIs) => Primitive(Isize),
1585 ty::ty_int(ast::TyI8) => Primitive(I8),
1586 ty::ty_int(ast::TyI16) => Primitive(I16),
1587 ty::ty_int(ast::TyI32) => Primitive(I32),
1588 ty::ty_int(ast::TyI64) => Primitive(I64),
1589 ty::ty_uint(ast::TyUs) => Primitive(Usize),
1590 ty::ty_uint(ast::TyU8) => Primitive(U8),
1591 ty::ty_uint(ast::TyU16) => Primitive(U16),
1592 ty::ty_uint(ast::TyU32) => Primitive(U32),
1593 ty::ty_uint(ast::TyU64) => Primitive(U64),
1594 ty::ty_float(ast::TyF32) => Primitive(F32),
1595 ty::ty_float(ast::TyF64) => Primitive(F64),
1596 ty::ty_str => Primitive(Str),
1597 ty::ty_uniq(t) => {
1598 let box_did = cx.tcx_opt().and_then(|tcx| {
1599 tcx.lang_items.owned_box()
1600 });
1601 lang_struct(cx, box_did, t, "Box", Unique)
1602 }
1603 ty::ty_vec(ty, None) => Vector(box ty.clean(cx)),
1604 ty::ty_vec(ty, Some(i)) => FixedVector(box ty.clean(cx),
1605 format!("{}", i)),
1606 ty::ty_ptr(mt) => RawPointer(mt.mutbl.clean(cx), box mt.ty.clean(cx)),
1607 ty::ty_rptr(r, mt) => BorrowedRef {
1608 lifetime: r.clean(cx),
1609 mutability: mt.mutbl.clean(cx),
1610 type_: box mt.ty.clean(cx),
1611 },
1612 ty::ty_bare_fn(_, ref fty) => BareFunction(box BareFunctionDecl {
1613 unsafety: fty.unsafety,
1614 generics: Generics {
1615 lifetimes: Vec::new(),
1616 type_params: Vec::new(),
1617 where_predicates: Vec::new()
1618 },
1619 decl: (ast_util::local_def(0), &fty.sig).clean(cx),
1620 abi: fty.abi.to_string(),
1621 }),
1622 ty::ty_struct(did, substs) |
1623 ty::ty_enum(did, substs) => {
1624 let fqn = csearch::get_item_path(cx.tcx(), did);
1625 let fqn: Vec<_> = fqn.into_iter().map(|i| i.to_string()).collect();
1626 let kind = match self.sty {
1627 ty::ty_struct(..) => TypeStruct,
1628 _ => TypeEnum,
1629 };
1630 let path = external_path(cx, &fqn.last().unwrap().to_string(),
1631 None, vec![], substs);
1632 cx.external_paths.borrow_mut().as_mut().unwrap().insert(did, (fqn, kind));
1633 ResolvedPath {
1634 path: path,
1635 typarams: None,
1636 did: did,
1637 }
1638 }
1639 ty::ty_trait(box ty::TyTrait { ref principal, ref bounds }) => {
1640 let did = principal.def_id();
1641 let fqn = csearch::get_item_path(cx.tcx(), did);
1642 let fqn: Vec<_> = fqn.into_iter().map(|i| i.to_string()).collect();
1643 let (typarams, bindings) = bounds.clean(cx);
1644 let path = external_path(cx, &fqn.last().unwrap().to_string(),
1645 Some(did), bindings, principal.substs());
1646 cx.external_paths.borrow_mut().as_mut().unwrap().insert(did, (fqn, TypeTrait));
1647 ResolvedPath {
1648 path: path,
1649 typarams: Some(typarams),
1650 did: did,
1651 }
1652 }
1653 ty::ty_tup(ref t) => Tuple(t.clean(cx)),
1654
1655 ty::ty_projection(ref data) => data.clean(cx),
1656
1657 ty::ty_param(ref p) => Generic(token::get_name(p.name).to_string()),
1658
1659 ty::ty_closure(..) => Tuple(vec![]), // FIXME(pcwalton)
1660
1661 ty::ty_infer(..) => panic!("ty_infer"),
1662 ty::ty_err => panic!("ty_err"),
1663 }
1664 }
1665 }
1666
1667 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1668 pub enum StructField {
1669 HiddenStructField, // inserted later by strip passes
1670 TypedStructField(Type),
1671 }
1672
1673 impl Clean<Item> for ast::StructField {
1674 fn clean(&self, cx: &DocContext) -> Item {
1675 let (name, vis) = match self.node.kind {
1676 ast::NamedField(id, vis) => (Some(id), vis),
1677 ast::UnnamedField(vis) => (None, vis)
1678 };
1679 Item {
1680 name: name.clean(cx),
1681 attrs: self.node.attrs.clean(cx),
1682 source: self.span.clean(cx),
1683 visibility: Some(vis),
1684 stability: get_stability(cx, ast_util::local_def(self.node.id)),
1685 def_id: ast_util::local_def(self.node.id),
1686 inner: StructFieldItem(TypedStructField(self.node.ty.clean(cx))),
1687 }
1688 }
1689 }
1690
1691 impl Clean<Item> for ty::field_ty {
1692 fn clean(&self, cx: &DocContext) -> Item {
1693 use syntax::parse::token::special_idents::unnamed_field;
1694 use rustc::metadata::csearch;
1695
1696 let attr_map = csearch::get_struct_field_attrs(&cx.tcx().sess.cstore, self.id);
1697
1698 let (name, attrs) = if self.name == unnamed_field.name {
1699 (None, None)
1700 } else {
1701 (Some(self.name), Some(attr_map.get(&self.id.node).unwrap()))
1702 };
1703
1704 let ty = ty::lookup_item_type(cx.tcx(), self.id);
1705
1706 Item {
1707 name: name.clean(cx),
1708 attrs: attrs.unwrap_or(&Vec::new()).clean(cx),
1709 source: Span::empty(),
1710 visibility: Some(self.vis),
1711 stability: get_stability(cx, self.id),
1712 def_id: self.id,
1713 inner: StructFieldItem(TypedStructField(ty.ty.clean(cx))),
1714 }
1715 }
1716 }
1717
1718 pub type Visibility = ast::Visibility;
1719
1720 impl Clean<Option<Visibility>> for ast::Visibility {
1721 fn clean(&self, _: &DocContext) -> Option<Visibility> {
1722 Some(*self)
1723 }
1724 }
1725
1726 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1727 pub struct Struct {
1728 pub struct_type: doctree::StructType,
1729 pub generics: Generics,
1730 pub fields: Vec<Item>,
1731 pub fields_stripped: bool,
1732 }
1733
1734 impl Clean<Item> for doctree::Struct {
1735 fn clean(&self, cx: &DocContext) -> Item {
1736 Item {
1737 name: Some(self.name.clean(cx)),
1738 attrs: self.attrs.clean(cx),
1739 source: self.whence.clean(cx),
1740 def_id: ast_util::local_def(self.id),
1741 visibility: self.vis.clean(cx),
1742 stability: self.stab.clean(cx),
1743 inner: StructItem(Struct {
1744 struct_type: self.struct_type,
1745 generics: self.generics.clean(cx),
1746 fields: self.fields.clean(cx),
1747 fields_stripped: false,
1748 }),
1749 }
1750 }
1751 }
1752
1753 /// This is a more limited form of the standard Struct, different in that
1754 /// it lacks the things most items have (name, id, parameterization). Found
1755 /// only as a variant in an enum.
1756 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1757 pub struct VariantStruct {
1758 pub struct_type: doctree::StructType,
1759 pub fields: Vec<Item>,
1760 pub fields_stripped: bool,
1761 }
1762
1763 impl Clean<VariantStruct> for syntax::ast::StructDef {
1764 fn clean(&self, cx: &DocContext) -> VariantStruct {
1765 VariantStruct {
1766 struct_type: doctree::struct_type_from_def(self),
1767 fields: self.fields.clean(cx),
1768 fields_stripped: false,
1769 }
1770 }
1771 }
1772
1773 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1774 pub struct Enum {
1775 pub variants: Vec<Item>,
1776 pub generics: Generics,
1777 pub variants_stripped: bool,
1778 }
1779
1780 impl Clean<Item> for doctree::Enum {
1781 fn clean(&self, cx: &DocContext) -> Item {
1782 Item {
1783 name: Some(self.name.clean(cx)),
1784 attrs: self.attrs.clean(cx),
1785 source: self.whence.clean(cx),
1786 def_id: ast_util::local_def(self.id),
1787 visibility: self.vis.clean(cx),
1788 stability: self.stab.clean(cx),
1789 inner: EnumItem(Enum {
1790 variants: self.variants.clean(cx),
1791 generics: self.generics.clean(cx),
1792 variants_stripped: false,
1793 }),
1794 }
1795 }
1796 }
1797
1798 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1799 pub struct Variant {
1800 pub kind: VariantKind,
1801 }
1802
1803 impl Clean<Item> for doctree::Variant {
1804 fn clean(&self, cx: &DocContext) -> Item {
1805 Item {
1806 name: Some(self.name.clean(cx)),
1807 attrs: self.attrs.clean(cx),
1808 source: self.whence.clean(cx),
1809 visibility: self.vis.clean(cx),
1810 stability: self.stab.clean(cx),
1811 def_id: ast_util::local_def(self.id),
1812 inner: VariantItem(Variant {
1813 kind: self.kind.clean(cx),
1814 }),
1815 }
1816 }
1817 }
1818
1819 impl<'tcx> Clean<Item> for ty::VariantInfo<'tcx> {
1820 fn clean(&self, cx: &DocContext) -> Item {
1821 // use syntax::parse::token::special_idents::unnamed_field;
1822 let kind = match self.arg_names.as_ref().map(|s| &**s) {
1823 None | Some([]) if self.args.is_empty() => CLikeVariant,
1824 None | Some([]) => {
1825 TupleVariant(self.args.clean(cx))
1826 }
1827 Some(s) => {
1828 StructVariant(VariantStruct {
1829 struct_type: doctree::Plain,
1830 fields_stripped: false,
1831 fields: s.iter().zip(self.args.iter()).map(|(name, ty)| {
1832 Item {
1833 source: Span::empty(),
1834 name: Some(name.clean(cx)),
1835 attrs: Vec::new(),
1836 visibility: Some(ast::Public),
1837 // FIXME: this is not accurate, we need an id for
1838 // the specific field but we're using the id
1839 // for the whole variant. Thus we read the
1840 // stability from the whole variant as well.
1841 // Struct variants are experimental and need
1842 // more infrastructure work before we can get
1843 // at the needed information here.
1844 def_id: self.id,
1845 stability: get_stability(cx, self.id),
1846 inner: StructFieldItem(
1847 TypedStructField(ty.clean(cx))
1848 )
1849 }
1850 }).collect()
1851 })
1852 }
1853 };
1854 Item {
1855 name: Some(self.name.clean(cx)),
1856 attrs: inline::load_attrs(cx, cx.tcx(), self.id),
1857 source: Span::empty(),
1858 visibility: Some(ast::Public),
1859 def_id: self.id,
1860 inner: VariantItem(Variant { kind: kind }),
1861 stability: get_stability(cx, self.id),
1862 }
1863 }
1864 }
1865
1866 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1867 pub enum VariantKind {
1868 CLikeVariant,
1869 TupleVariant(Vec<Type>),
1870 StructVariant(VariantStruct),
1871 }
1872
1873 impl Clean<VariantKind> for ast::VariantKind {
1874 fn clean(&self, cx: &DocContext) -> VariantKind {
1875 match self {
1876 &ast::TupleVariantKind(ref args) => {
1877 if args.is_empty() {
1878 CLikeVariant
1879 } else {
1880 TupleVariant(args.iter().map(|x| x.ty.clean(cx)).collect())
1881 }
1882 },
1883 &ast::StructVariantKind(ref sd) => StructVariant(sd.clean(cx)),
1884 }
1885 }
1886 }
1887
1888 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
1889 pub struct Span {
1890 pub filename: String,
1891 pub loline: usize,
1892 pub locol: usize,
1893 pub hiline: usize,
1894 pub hicol: usize,
1895 }
1896
1897 impl Span {
1898 fn empty() -> Span {
1899 Span {
1900 filename: "".to_string(),
1901 loline: 0, locol: 0,
1902 hiline: 0, hicol: 0,
1903 }
1904 }
1905 }
1906
1907 impl Clean<Span> for syntax::codemap::Span {
1908 fn clean(&self, cx: &DocContext) -> Span {
1909 let cm = cx.sess().codemap();
1910 let filename = cm.span_to_filename(*self);
1911 let lo = cm.lookup_char_pos(self.lo);
1912 let hi = cm.lookup_char_pos(self.hi);
1913 Span {
1914 filename: filename.to_string(),
1915 loline: lo.line,
1916 locol: lo.col.to_usize(),
1917 hiline: hi.line,
1918 hicol: hi.col.to_usize(),
1919 }
1920 }
1921 }
1922
1923 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1924 pub struct Path {
1925 pub global: bool,
1926 pub segments: Vec<PathSegment>,
1927 }
1928
1929 impl Path {
1930 pub fn singleton(name: String) -> Path {
1931 Path {
1932 global: false,
1933 segments: vec![PathSegment {
1934 name: name,
1935 params: PathParameters::AngleBracketed {
1936 lifetimes: Vec::new(),
1937 types: Vec::new(),
1938 bindings: Vec::new()
1939 }
1940 }]
1941 }
1942 }
1943 }
1944
1945 impl Clean<Path> for ast::Path {
1946 fn clean(&self, cx: &DocContext) -> Path {
1947 Path {
1948 global: self.global,
1949 segments: self.segments.clean(cx),
1950 }
1951 }
1952 }
1953
1954 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1955 pub enum PathParameters {
1956 AngleBracketed {
1957 lifetimes: Vec<Lifetime>,
1958 types: Vec<Type>,
1959 bindings: Vec<TypeBinding>
1960 },
1961 Parenthesized {
1962 inputs: Vec<Type>,
1963 output: Option<Type>
1964 }
1965 }
1966
1967 impl Clean<PathParameters> for ast::PathParameters {
1968 fn clean(&self, cx: &DocContext) -> PathParameters {
1969 match *self {
1970 ast::AngleBracketedParameters(ref data) => {
1971 PathParameters::AngleBracketed {
1972 lifetimes: data.lifetimes.clean(cx),
1973 types: data.types.clean(cx),
1974 bindings: data.bindings.clean(cx)
1975 }
1976 }
1977
1978 ast::ParenthesizedParameters(ref data) => {
1979 PathParameters::Parenthesized {
1980 inputs: data.inputs.clean(cx),
1981 output: data.output.clean(cx)
1982 }
1983 }
1984 }
1985 }
1986 }
1987
1988 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
1989 pub struct PathSegment {
1990 pub name: String,
1991 pub params: PathParameters
1992 }
1993
1994 impl Clean<PathSegment> for ast::PathSegment {
1995 fn clean(&self, cx: &DocContext) -> PathSegment {
1996 PathSegment {
1997 name: self.identifier.clean(cx),
1998 params: self.parameters.clean(cx)
1999 }
2000 }
2001 }
2002
2003 fn path_to_string(p: &ast::Path) -> String {
2004 let mut s = String::new();
2005 let mut first = true;
2006 for i in p.segments.iter().map(|x| token::get_ident(x.identifier)) {
2007 if !first || p.global {
2008 s.push_str("::");
2009 } else {
2010 first = false;
2011 }
2012 s.push_str(&i);
2013 }
2014 s
2015 }
2016
2017 impl Clean<String> for ast::Ident {
2018 fn clean(&self, _: &DocContext) -> String {
2019 token::get_ident(*self).to_string()
2020 }
2021 }
2022
2023 impl Clean<String> for ast::Name {
2024 fn clean(&self, _: &DocContext) -> String {
2025 token::get_name(*self).to_string()
2026 }
2027 }
2028
2029 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
2030 pub struct Typedef {
2031 pub type_: Type,
2032 pub generics: Generics,
2033 }
2034
2035 impl Clean<Item> for doctree::Typedef {
2036 fn clean(&self, cx: &DocContext) -> Item {
2037 Item {
2038 name: Some(self.name.clean(cx)),
2039 attrs: self.attrs.clean(cx),
2040 source: self.whence.clean(cx),
2041 def_id: ast_util::local_def(self.id.clone()),
2042 visibility: self.vis.clean(cx),
2043 stability: self.stab.clean(cx),
2044 inner: TypedefItem(Typedef {
2045 type_: self.ty.clean(cx),
2046 generics: self.gen.clean(cx),
2047 }),
2048 }
2049 }
2050 }
2051
2052 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
2053 pub struct BareFunctionDecl {
2054 pub unsafety: ast::Unsafety,
2055 pub generics: Generics,
2056 pub decl: FnDecl,
2057 pub abi: String,
2058 }
2059
2060 impl Clean<BareFunctionDecl> for ast::BareFnTy {
2061 fn clean(&self, cx: &DocContext) -> BareFunctionDecl {
2062 BareFunctionDecl {
2063 unsafety: self.unsafety,
2064 generics: Generics {
2065 lifetimes: self.lifetimes.clean(cx),
2066 type_params: Vec::new(),
2067 where_predicates: Vec::new()
2068 },
2069 decl: self.decl.clean(cx),
2070 abi: self.abi.to_string(),
2071 }
2072 }
2073 }
2074
2075 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
2076 pub struct Static {
2077 pub type_: Type,
2078 pub mutability: Mutability,
2079 /// It's useful to have the value of a static documented, but I have no
2080 /// desire to represent expressions (that'd basically be all of the AST,
2081 /// which is huge!). So, have a string.
2082 pub expr: String,
2083 }
2084
2085 impl Clean<Item> for doctree::Static {
2086 fn clean(&self, cx: &DocContext) -> Item {
2087 debug!("cleaning static {}: {:?}", self.name.clean(cx), self);
2088 Item {
2089 name: Some(self.name.clean(cx)),
2090 attrs: self.attrs.clean(cx),
2091 source: self.whence.clean(cx),
2092 def_id: ast_util::local_def(self.id),
2093 visibility: self.vis.clean(cx),
2094 stability: self.stab.clean(cx),
2095 inner: StaticItem(Static {
2096 type_: self.type_.clean(cx),
2097 mutability: self.mutability.clean(cx),
2098 expr: self.expr.span.to_src(cx),
2099 }),
2100 }
2101 }
2102 }
2103
2104 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
2105 pub struct Constant {
2106 pub type_: Type,
2107 pub expr: String,
2108 }
2109
2110 impl Clean<Item> for doctree::Constant {
2111 fn clean(&self, cx: &DocContext) -> Item {
2112 Item {
2113 name: Some(self.name.clean(cx)),
2114 attrs: self.attrs.clean(cx),
2115 source: self.whence.clean(cx),
2116 def_id: ast_util::local_def(self.id),
2117 visibility: self.vis.clean(cx),
2118 stability: self.stab.clean(cx),
2119 inner: ConstantItem(Constant {
2120 type_: self.type_.clean(cx),
2121 expr: self.expr.span.to_src(cx),
2122 }),
2123 }
2124 }
2125 }
2126
2127 #[derive(Debug, Clone, RustcEncodable, RustcDecodable, PartialEq, Copy)]
2128 pub enum Mutability {
2129 Mutable,
2130 Immutable,
2131 }
2132
2133 impl Clean<Mutability> for ast::Mutability {
2134 fn clean(&self, _: &DocContext) -> Mutability {
2135 match self {
2136 &ast::MutMutable => Mutable,
2137 &ast::MutImmutable => Immutable,
2138 }
2139 }
2140 }
2141
2142 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Copy, Debug)]
2143 pub enum ImplPolarity {
2144 Positive,
2145 Negative,
2146 }
2147
2148 impl Clean<ImplPolarity> for ast::ImplPolarity {
2149 fn clean(&self, _: &DocContext) -> ImplPolarity {
2150 match self {
2151 &ast::ImplPolarity::Positive => ImplPolarity::Positive,
2152 &ast::ImplPolarity::Negative => ImplPolarity::Negative,
2153 }
2154 }
2155 }
2156
2157 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
2158 pub struct Impl {
2159 pub unsafety: ast::Unsafety,
2160 pub generics: Generics,
2161 pub trait_: Option<Type>,
2162 pub for_: Type,
2163 pub items: Vec<Item>,
2164 pub derived: bool,
2165 pub polarity: Option<ImplPolarity>,
2166 }
2167
2168 fn detect_derived<M: AttrMetaMethods>(attrs: &[M]) -> bool {
2169 attr::contains_name(attrs, "automatically_derived")
2170 }
2171
2172 impl Clean<Item> for doctree::Impl {
2173 fn clean(&self, cx: &DocContext) -> Item {
2174 Item {
2175 name: None,
2176 attrs: self.attrs.clean(cx),
2177 source: self.whence.clean(cx),
2178 def_id: ast_util::local_def(self.id),
2179 visibility: self.vis.clean(cx),
2180 stability: self.stab.clean(cx),
2181 inner: ImplItem(Impl {
2182 unsafety: self.unsafety,
2183 generics: self.generics.clean(cx),
2184 trait_: self.trait_.clean(cx),
2185 for_: self.for_.clean(cx),
2186 items: self.items.clean(cx),
2187 derived: detect_derived(&self.attrs),
2188 polarity: Some(self.polarity.clean(cx)),
2189 }),
2190 }
2191 }
2192 }
2193
2194 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
2195 pub struct DefaultImpl {
2196 pub unsafety: ast::Unsafety,
2197 pub trait_: Type,
2198 }
2199
2200 impl Clean<Item> for doctree::DefaultImpl {
2201 fn clean(&self, cx: &DocContext) -> Item {
2202 Item {
2203 name: None,
2204 attrs: self.attrs.clean(cx),
2205 source: self.whence.clean(cx),
2206 def_id: ast_util::local_def(self.id),
2207 visibility: Some(ast::Public),
2208 stability: None,
2209 inner: DefaultImplItem(DefaultImpl {
2210 unsafety: self.unsafety,
2211 trait_: self.trait_.clean(cx),
2212 }),
2213 }
2214 }
2215 }
2216
2217 impl Clean<Item> for doctree::ExternCrate {
2218 fn clean(&self, cx: &DocContext) -> Item {
2219 Item {
2220 name: None,
2221 attrs: self.attrs.clean(cx),
2222 source: self.whence.clean(cx),
2223 def_id: ast_util::local_def(0),
2224 visibility: self.vis.clean(cx),
2225 stability: None,
2226 inner: ExternCrateItem(self.name.clean(cx), self.path.clone())
2227 }
2228 }
2229 }
2230
2231 impl Clean<Vec<Item>> for doctree::Import {
2232 fn clean(&self, cx: &DocContext) -> Vec<Item> {
2233 // We consider inlining the documentation of `pub use` statements, but we
2234 // forcefully don't inline if this is not public or if the
2235 // #[doc(no_inline)] attribute is present.
2236 let denied = self.vis != ast::Public || self.attrs.iter().any(|a| {
2237 &a.name()[..] == "doc" && match a.meta_item_list() {
2238 Some(l) => attr::contains_name(l, "no_inline"),
2239 None => false,
2240 }
2241 });
2242 let (mut ret, inner) = match self.node {
2243 ast::ViewPathGlob(ref p) => {
2244 (vec![], GlobImport(resolve_use_source(cx, p.clean(cx), self.id)))
2245 }
2246 ast::ViewPathList(ref p, ref list) => {
2247 // Attempt to inline all reexported items, but be sure
2248 // to keep any non-inlineable reexports so they can be
2249 // listed in the documentation.
2250 let mut ret = vec![];
2251 let remaining = if !denied {
2252 let mut remaining = vec![];
2253 for path in list {
2254 match inline::try_inline(cx, path.node.id(), None) {
2255 Some(items) => {
2256 ret.extend(items.into_iter());
2257 }
2258 None => {
2259 remaining.push(path.clean(cx));
2260 }
2261 }
2262 }
2263 remaining
2264 } else {
2265 list.clean(cx)
2266 };
2267 if remaining.is_empty() {
2268 return ret;
2269 }
2270 (ret, ImportList(resolve_use_source(cx, p.clean(cx), self.id),
2271 remaining))
2272 }
2273 ast::ViewPathSimple(i, ref p) => {
2274 if !denied {
2275 match inline::try_inline(cx, self.id, Some(i)) {
2276 Some(items) => return items,
2277 None => {}
2278 }
2279 }
2280 (vec![], SimpleImport(i.clean(cx),
2281 resolve_use_source(cx, p.clean(cx), self.id)))
2282 }
2283 };
2284 ret.push(Item {
2285 name: None,
2286 attrs: self.attrs.clean(cx),
2287 source: self.whence.clean(cx),
2288 def_id: ast_util::local_def(0),
2289 visibility: self.vis.clean(cx),
2290 stability: None,
2291 inner: ImportItem(inner)
2292 });
2293 ret
2294 }
2295 }
2296
2297 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
2298 pub enum Import {
2299 // use source as str;
2300 SimpleImport(String, ImportSource),
2301 // use source::*;
2302 GlobImport(ImportSource),
2303 // use source::{a, b, c};
2304 ImportList(ImportSource, Vec<ViewListIdent>),
2305 }
2306
2307 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
2308 pub struct ImportSource {
2309 pub path: Path,
2310 pub did: Option<ast::DefId>,
2311 }
2312
2313 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
2314 pub struct ViewListIdent {
2315 pub name: String,
2316 pub source: Option<ast::DefId>,
2317 }
2318
2319 impl Clean<ViewListIdent> for ast::PathListItem {
2320 fn clean(&self, cx: &DocContext) -> ViewListIdent {
2321 match self.node {
2322 ast::PathListIdent { id, name } => ViewListIdent {
2323 name: name.clean(cx),
2324 source: resolve_def(cx, id)
2325 },
2326 ast::PathListMod { id } => ViewListIdent {
2327 name: "self".to_string(),
2328 source: resolve_def(cx, id)
2329 }
2330 }
2331 }
2332 }
2333
2334 impl Clean<Vec<Item>> for ast::ForeignMod {
2335 fn clean(&self, cx: &DocContext) -> Vec<Item> {
2336 let mut items = self.items.clean(cx);
2337 for item in &mut items {
2338 match item.inner {
2339 ForeignFunctionItem(ref mut f) => f.abi = self.abi,
2340 _ => {}
2341 }
2342 }
2343 items
2344 }
2345 }
2346
2347 impl Clean<Item> for ast::ForeignItem {
2348 fn clean(&self, cx: &DocContext) -> Item {
2349 let inner = match self.node {
2350 ast::ForeignItemFn(ref decl, ref generics) => {
2351 ForeignFunctionItem(Function {
2352 decl: decl.clean(cx),
2353 generics: generics.clean(cx),
2354 unsafety: ast::Unsafety::Unsafe,
2355 abi: abi::Rust,
2356 })
2357 }
2358 ast::ForeignItemStatic(ref ty, mutbl) => {
2359 ForeignStaticItem(Static {
2360 type_: ty.clean(cx),
2361 mutability: if mutbl {Mutable} else {Immutable},
2362 expr: "".to_string(),
2363 })
2364 }
2365 };
2366 Item {
2367 name: Some(self.ident.clean(cx)),
2368 attrs: self.attrs.clean(cx),
2369 source: self.span.clean(cx),
2370 def_id: ast_util::local_def(self.id),
2371 visibility: self.vis.clean(cx),
2372 stability: get_stability(cx, ast_util::local_def(self.id)),
2373 inner: inner,
2374 }
2375 }
2376 }
2377
2378 // Utilities
2379
2380 trait ToSource {
2381 fn to_src(&self, cx: &DocContext) -> String;
2382 }
2383
2384 impl ToSource for syntax::codemap::Span {
2385 fn to_src(&self, cx: &DocContext) -> String {
2386 debug!("converting span {:?} to snippet", self.clean(cx));
2387 let sn = match cx.sess().codemap().span_to_snippet(*self) {
2388 Ok(x) => x.to_string(),
2389 Err(_) => "".to_string()
2390 };
2391 debug!("got snippet {}", sn);
2392 sn
2393 }
2394 }
2395
2396 fn lit_to_string(lit: &ast::Lit) -> String {
2397 match lit.node {
2398 ast::LitStr(ref st, _) => st.to_string(),
2399 ast::LitBinary(ref data) => format!("{:?}", data),
2400 ast::LitByte(b) => {
2401 let mut res = String::from_str("b'");
2402 for c in (b as char).escape_default() {
2403 res.push(c);
2404 }
2405 res.push('\'');
2406 res
2407 },
2408 ast::LitChar(c) => format!("'{}'", c),
2409 ast::LitInt(i, _t) => i.to_string(),
2410 ast::LitFloat(ref f, _t) => f.to_string(),
2411 ast::LitFloatUnsuffixed(ref f) => f.to_string(),
2412 ast::LitBool(b) => b.to_string(),
2413 }
2414 }
2415
2416 fn name_from_pat(p: &ast::Pat) -> String {
2417 use syntax::ast::*;
2418 debug!("Trying to get a name from pattern: {:?}", p);
2419
2420 match p.node {
2421 PatWild(PatWildSingle) => "_".to_string(),
2422 PatWild(PatWildMulti) => "..".to_string(),
2423 PatIdent(_, ref p, _) => token::get_ident(p.node).to_string(),
2424 PatEnum(ref p, _) => path_to_string(p),
2425 PatStruct(ref name, ref fields, etc) => {
2426 format!("{} {{ {}{} }}", path_to_string(name),
2427 fields.iter().map(|&Spanned { node: ref fp, .. }|
2428 format!("{}: {}", fp.ident.as_str(), name_from_pat(&*fp.pat)))
2429 .collect::<Vec<String>>().connect(", "),
2430 if etc { ", ..." } else { "" }
2431 )
2432 },
2433 PatTup(ref elts) => format!("({})", elts.iter().map(|p| name_from_pat(&**p))
2434 .collect::<Vec<String>>().connect(", ")),
2435 PatBox(ref p) => name_from_pat(&**p),
2436 PatRegion(ref p, _) => name_from_pat(&**p),
2437 PatLit(..) => {
2438 warn!("tried to get argument name from PatLit, \
2439 which is silly in function arguments");
2440 "()".to_string()
2441 },
2442 PatRange(..) => panic!("tried to get argument name from PatRange, \
2443 which is not allowed in function arguments"),
2444 PatVec(ref begin, ref mid, ref end) => {
2445 let begin = begin.iter().map(|p| name_from_pat(&**p));
2446 let mid = mid.as_ref().map(|p| format!("..{}", name_from_pat(&**p))).into_iter();
2447 let end = end.iter().map(|p| name_from_pat(&**p));
2448 format!("[{}]", begin.chain(mid).chain(end).collect::<Vec<_>>().connect(", "))
2449 },
2450 PatMac(..) => {
2451 warn!("can't document the name of a function argument \
2452 produced by a pattern macro");
2453 "(argument produced by macro)".to_string()
2454 }
2455 }
2456 }
2457
2458 /// Given a Type, resolve it using the def_map
2459 fn resolve_type(cx: &DocContext,
2460 path: Path,
2461 id: ast::NodeId) -> Type {
2462 let tcx = match cx.tcx_opt() {
2463 Some(tcx) => tcx,
2464 // If we're extracting tests, this return value doesn't matter.
2465 None => return Primitive(Bool),
2466 };
2467 debug!("searching for {} in defmap", id);
2468 let def = match tcx.def_map.borrow().get(&id) {
2469 Some(k) => k.full_def(),
2470 None => panic!("unresolved id not in defmap")
2471 };
2472
2473 match def {
2474 def::DefSelfTy(..) if path.segments.len() == 1 => {
2475 return Generic(token::get_name(special_idents::type_self.name).to_string());
2476 }
2477 def::DefPrimTy(p) => match p {
2478 ast::TyStr => return Primitive(Str),
2479 ast::TyBool => return Primitive(Bool),
2480 ast::TyChar => return Primitive(Char),
2481 ast::TyInt(ast::TyIs) => return Primitive(Isize),
2482 ast::TyInt(ast::TyI8) => return Primitive(I8),
2483 ast::TyInt(ast::TyI16) => return Primitive(I16),
2484 ast::TyInt(ast::TyI32) => return Primitive(I32),
2485 ast::TyInt(ast::TyI64) => return Primitive(I64),
2486 ast::TyUint(ast::TyUs) => return Primitive(Usize),
2487 ast::TyUint(ast::TyU8) => return Primitive(U8),
2488 ast::TyUint(ast::TyU16) => return Primitive(U16),
2489 ast::TyUint(ast::TyU32) => return Primitive(U32),
2490 ast::TyUint(ast::TyU64) => return Primitive(U64),
2491 ast::TyFloat(ast::TyF32) => return Primitive(F32),
2492 ast::TyFloat(ast::TyF64) => return Primitive(F64),
2493 },
2494 def::DefTyParam(_, _, _, n) => {
2495 return Generic(token::get_name(n).to_string())
2496 }
2497 _ => {}
2498 };
2499 let did = register_def(&*cx, def);
2500 ResolvedPath { path: path, typarams: None, did: did }
2501 }
2502
2503 fn register_def(cx: &DocContext, def: def::Def) -> ast::DefId {
2504 let (did, kind) = match def {
2505 def::DefFn(i, _) => (i, TypeFunction),
2506 def::DefTy(i, false) => (i, TypeTypedef),
2507 def::DefTy(i, true) => (i, TypeEnum),
2508 def::DefTrait(i) => (i, TypeTrait),
2509 def::DefStruct(i) => (i, TypeStruct),
2510 def::DefMod(i) => (i, TypeModule),
2511 def::DefStatic(i, _) => (i, TypeStatic),
2512 def::DefVariant(i, _, _) => (i, TypeEnum),
2513 _ => return def.def_id()
2514 };
2515 if ast_util::is_local(did) { return did }
2516 let tcx = match cx.tcx_opt() {
2517 Some(tcx) => tcx,
2518 None => return did
2519 };
2520 inline::record_extern_fqn(cx, did, kind);
2521 if let TypeTrait = kind {
2522 let t = inline::build_external_trait(cx, tcx, did);
2523 cx.external_traits.borrow_mut().as_mut().unwrap().insert(did, t);
2524 }
2525 return did;
2526 }
2527
2528 fn resolve_use_source(cx: &DocContext, path: Path, id: ast::NodeId) -> ImportSource {
2529 ImportSource {
2530 path: path,
2531 did: resolve_def(cx, id),
2532 }
2533 }
2534
2535 fn resolve_def(cx: &DocContext, id: ast::NodeId) -> Option<ast::DefId> {
2536 cx.tcx_opt().and_then(|tcx| {
2537 tcx.def_map.borrow().get(&id).map(|d| register_def(cx, d.full_def()))
2538 })
2539 }
2540
2541 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
2542 pub struct Macro {
2543 pub source: String,
2544 }
2545
2546 impl Clean<Item> for doctree::Macro {
2547 fn clean(&self, cx: &DocContext) -> Item {
2548 Item {
2549 name: Some(format!("{}!", self.name.clean(cx))),
2550 attrs: self.attrs.clean(cx),
2551 source: self.whence.clean(cx),
2552 visibility: ast::Public.clean(cx),
2553 stability: self.stab.clean(cx),
2554 def_id: ast_util::local_def(self.id),
2555 inner: MacroItem(Macro {
2556 source: self.whence.to_src(cx),
2557 }),
2558 }
2559 }
2560 }
2561
2562 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
2563 pub struct Stability {
2564 pub level: attr::StabilityLevel,
2565 pub feature: String,
2566 pub since: String,
2567 pub deprecated_since: String,
2568 pub reason: String
2569 }
2570
2571 impl Clean<Stability> for attr::Stability {
2572 fn clean(&self, _: &DocContext) -> Stability {
2573 Stability {
2574 level: self.level,
2575 feature: self.feature.to_string(),
2576 since: self.since.as_ref().map_or("".to_string(),
2577 |interned| interned.to_string()),
2578 deprecated_since: self.deprecated_since.as_ref().map_or("".to_string(),
2579 |istr| istr.to_string()),
2580 reason: self.reason.as_ref().map_or("".to_string(),
2581 |interned| interned.to_string()),
2582 }
2583 }
2584 }
2585
2586 impl Clean<Item> for ty::AssociatedType {
2587 fn clean(&self, cx: &DocContext) -> Item {
2588 // When loading a cross-crate associated type, the bounds for this type
2589 // are actually located on the trait/impl itself, so we need to load
2590 // all of the generics from there and then look for bounds that are
2591 // applied to this associated type in question.
2592 let predicates = ty::lookup_predicates(cx.tcx(), self.container.id());
2593 let generics = match self.container {
2594 ty::TraitContainer(did) => {
2595 let def = ty::lookup_trait_def(cx.tcx(), did);
2596 (&def.generics, &predicates, subst::TypeSpace).clean(cx)
2597 }
2598 ty::ImplContainer(did) => {
2599 let ty = ty::lookup_item_type(cx.tcx(), did);
2600 (&ty.generics, &predicates, subst::TypeSpace).clean(cx)
2601 }
2602 };
2603 let my_name = self.name.clean(cx);
2604 let mut bounds = generics.where_predicates.iter().filter_map(|pred| {
2605 let (name, self_type, trait_, bounds) = match *pred {
2606 WherePredicate::BoundPredicate {
2607 ty: QPath { ref name, ref self_type, ref trait_ },
2608 ref bounds
2609 } => (name, self_type, trait_, bounds),
2610 _ => return None,
2611 };
2612 if *name != my_name { return None }
2613 match **trait_ {
2614 ResolvedPath { did, .. } if did == self.container.id() => {}
2615 _ => return None,
2616 }
2617 match **self_type {
2618 Generic(ref s) if *s == "Self" => {}
2619 _ => return None,
2620 }
2621 Some(bounds)
2622 }).flat_map(|i| i.iter().cloned()).collect::<Vec<_>>();
2623
2624 // Our Sized/?Sized bound didn't get handled when creating the generics
2625 // because we didn't actually get our whole set of bounds until just now
2626 // (some of them may have come from the trait). If we do have a sized
2627 // bound, we remove it, and if we don't then we add the `?Sized` bound
2628 // at the end.
2629 match bounds.iter().position(|b| b.is_sized_bound(cx)) {
2630 Some(i) => { bounds.remove(i); }
2631 None => bounds.push(TyParamBound::maybe_sized(cx)),
2632 }
2633
2634 Item {
2635 source: DUMMY_SP.clean(cx),
2636 name: Some(self.name.clean(cx)),
2637 attrs: inline::load_attrs(cx, cx.tcx(), self.def_id),
2638 inner: AssociatedTypeItem(bounds, None),
2639 visibility: self.vis.clean(cx),
2640 def_id: self.def_id,
2641 stability: stability::lookup(cx.tcx(), self.def_id).clean(cx),
2642 }
2643 }
2644 }
2645
2646 impl<'a> Clean<Typedef> for (ty::TypeScheme<'a>, ty::GenericPredicates<'a>,
2647 ParamSpace) {
2648 fn clean(&self, cx: &DocContext) -> Typedef {
2649 let (ref ty_scheme, ref predicates, ps) = *self;
2650 Typedef {
2651 type_: ty_scheme.ty.clean(cx),
2652 generics: (&ty_scheme.generics, predicates, ps).clean(cx)
2653 }
2654 }
2655 }
2656
2657 fn lang_struct(cx: &DocContext, did: Option<ast::DefId>,
2658 t: ty::Ty, name: &str,
2659 fallback: fn(Box<Type>) -> Type) -> Type {
2660 let did = match did {
2661 Some(did) => did,
2662 None => return fallback(box t.clean(cx)),
2663 };
2664 let fqn = csearch::get_item_path(cx.tcx(), did);
2665 let fqn: Vec<String> = fqn.into_iter().map(|i| {
2666 i.to_string()
2667 }).collect();
2668 cx.external_paths.borrow_mut().as_mut().unwrap().insert(did, (fqn, TypeStruct));
2669 ResolvedPath {
2670 typarams: None,
2671 did: did,
2672 path: Path {
2673 global: false,
2674 segments: vec![PathSegment {
2675 name: name.to_string(),
2676 params: PathParameters::AngleBracketed {
2677 lifetimes: vec![],
2678 types: vec![t.clean(cx)],
2679 bindings: vec![]
2680 }
2681 }],
2682 },
2683 }
2684 }
2685
2686 /// An equality constraint on an associated type, e.g. `A=Bar` in `Foo<A=Bar>`
2687 #[derive(Clone, PartialEq, RustcDecodable, RustcEncodable, Debug)]
2688 pub struct TypeBinding {
2689 pub name: String,
2690 pub ty: Type
2691 }
2692
2693 impl Clean<TypeBinding> for ast::TypeBinding {
2694 fn clean(&self, cx: &DocContext) -> TypeBinding {
2695 TypeBinding {
2696 name: self.ident.clean(cx),
2697 ty: self.ty.clean(cx)
2698 }
2699 }
2700 }