]> git.lizzy.rs Git - rust.git/blob - src/librustdoc/clean/mod.rs
22aab89ef6279c1841223523413f4310fd658cd5
[rust.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 use syntax;
15 use syntax::ast;
16 use syntax::ast_util;
17 use syntax::attr;
18 use syntax::attr::{AttributeMethods, AttrMetaMethods};
19 use syntax::codemap::Pos;
20 use syntax::parse::token::InternedString;
21 use syntax::parse::token;
22
23 use rustc::back::link;
24 use rustc::driver::driver;
25 use rustc::metadata::cstore;
26 use rustc::metadata::csearch;
27 use rustc::metadata::decoder;
28 use rustc::middle::ty;
29
30 use std::rc::Rc;
31 use std::u32;
32
33 use core;
34 use doctree;
35 use visit_ast;
36
37 /// A stable identifier to the particular version of JSON output.
38 /// Increment this when the `Crate` and related structures change.
39 pub static SCHEMA_VERSION: &'static str = "0.8.2";
40
41 mod inline;
42
43 pub trait Clean<T> {
44     fn clean(&self) -> T;
45 }
46
47 impl<T: Clean<U>, U> Clean<Vec<U>> for Vec<T> {
48     fn clean(&self) -> Vec<U> {
49         self.iter().map(|x| x.clean()).collect()
50     }
51 }
52
53 impl<T: Clean<U>, U> Clean<U> for @T {
54     fn clean(&self) -> U {
55         (**self).clean()
56     }
57 }
58
59 impl<T: Clean<U>, U> Clean<U> for Rc<T> {
60     fn clean(&self) -> U {
61         (**self).clean()
62     }
63 }
64
65 impl<T: Clean<U>, U> Clean<Option<U>> for Option<T> {
66     fn clean(&self) -> Option<U> {
67         match self {
68             &None => None,
69             &Some(ref v) => Some(v.clean())
70         }
71     }
72 }
73
74 impl<T: Clean<U>, U> Clean<Vec<U>> for syntax::owned_slice::OwnedSlice<T> {
75     fn clean(&self) -> Vec<U> {
76         self.iter().map(|x| x.clean()).collect()
77     }
78 }
79
80 #[deriving(Clone, Encodable, Decodable)]
81 pub struct Crate {
82     pub name: String,
83     pub module: Option<Item>,
84     pub externs: Vec<(ast::CrateNum, ExternalCrate)>,
85     pub primitives: Vec<Primitive>,
86 }
87
88 impl<'a> Clean<Crate> for visit_ast::RustdocVisitor<'a> {
89     fn clean(&self) -> Crate {
90         let cx = super::ctxtkey.get().unwrap();
91
92         let mut externs = Vec::new();
93         cx.sess().cstore.iter_crate_data(|n, meta| {
94             externs.push((n, meta.clean()));
95         });
96
97         // Figure out the name of this crate
98         let input = driver::FileInput(cx.src.clone());
99         let t_outputs = driver::build_output_filenames(&input,
100                                                        &None,
101                                                        &None,
102                                                        self.attrs.as_slice(),
103                                                        cx.sess());
104         let id = link::find_crate_id(self.attrs.as_slice(),
105                                      t_outputs.out_filestem.as_slice());
106
107         // Clean the crate, translating the entire libsyntax AST to one that is
108         // understood by rustdoc.
109         let mut module = self.module.clean();
110
111         // Collect all inner modules which are tagged as implementations of
112         // primitives.
113         //
114         // Note that this loop only searches the top-level items of the crate,
115         // and this is intentional. If we were to search the entire crate for an
116         // item tagged with `#[doc(primitive)]` then we we would also have to
117         // search the entirety of external modules for items tagged
118         // `#[doc(primitive)]`, which is a pretty inefficient process (decoding
119         // all that metadata unconditionally).
120         //
121         // In order to keep the metadata load under control, the
122         // `#[doc(primitive)]` feature is explicitly designed to only allow the
123         // primitive tags to show up as the top level items in a crate.
124         //
125         // Also note that this does not attempt to deal with modules tagged
126         // duplicately for the same primitive. This is handled later on when
127         // rendering by delegating everything to a hash map.
128         let mut primitives = Vec::new();
129         {
130             let m = match module.inner {
131                 ModuleItem(ref mut m) => m,
132                 _ => unreachable!(),
133             };
134             let mut tmp = Vec::new();
135             for child in m.items.iter() {
136                 match child.inner {
137                     ModuleItem(..) => {},
138                     _ => continue,
139                 }
140                 let prim = match Primitive::find(child.attrs.as_slice()) {
141                     Some(prim) => prim,
142                     None => continue,
143                 };
144                 primitives.push(prim);
145                 tmp.push(Item {
146                     source: Span::empty(),
147                     name: Some(prim.to_url_str().to_string()),
148                     attrs: child.attrs.clone(),
149                     visibility: Some(ast::Public),
150                     def_id: ast_util::local_def(prim.to_node_id()),
151                     inner: PrimitiveItem(prim),
152                 });
153             }
154             m.items.extend(tmp.move_iter());
155         }
156
157         Crate {
158             name: id.name.to_string(),
159             module: Some(module),
160             externs: externs,
161             primitives: primitives,
162         }
163     }
164 }
165
166 #[deriving(Clone, Encodable, Decodable)]
167 pub struct ExternalCrate {
168     pub name: String,
169     pub attrs: Vec<Attribute>,
170     pub primitives: Vec<Primitive>,
171 }
172
173 impl Clean<ExternalCrate> for cstore::crate_metadata {
174     fn clean(&self) -> ExternalCrate {
175         let mut primitives = Vec::new();
176         let cx = super::ctxtkey.get().unwrap();
177         match cx.maybe_typed {
178             core::Typed(ref tcx) => {
179                 csearch::each_top_level_item_of_crate(&tcx.sess.cstore,
180                                                       self.cnum,
181                                                       |def, _, _| {
182                     let did = match def {
183                         decoder::DlDef(ast::DefMod(did)) => did,
184                         _ => return
185                     };
186                     let attrs = inline::load_attrs(tcx, did);
187                     match Primitive::find(attrs.as_slice()) {
188                         Some(prim) => primitives.push(prim),
189                         None => {}
190                     }
191                 });
192             }
193             core::NotTyped(..) => {}
194         }
195         ExternalCrate {
196             name: self.name.to_string(),
197             attrs: decoder::get_crate_attributes(self.data()).clean(),
198             primitives: primitives,
199         }
200     }
201 }
202
203 /// Anything with a source location and set of attributes and, optionally, a
204 /// name. That is, anything that can be documented. This doesn't correspond
205 /// directly to the AST's concept of an item; it's a strict superset.
206 #[deriving(Clone, Encodable, Decodable)]
207 pub struct Item {
208     /// Stringified span
209     pub source: Span,
210     /// Not everything has a name. E.g., impls
211     pub name: Option<String>,
212     pub attrs: Vec<Attribute> ,
213     pub inner: ItemEnum,
214     pub visibility: Option<Visibility>,
215     pub def_id: ast::DefId,
216 }
217
218 impl Item {
219     /// Finds the `doc` attribute as a List and returns the list of attributes
220     /// nested inside.
221     pub fn doc_list<'a>(&'a self) -> Option<&'a [Attribute]> {
222         for attr in self.attrs.iter() {
223             match *attr {
224                 List(ref x, ref list) if "doc" == x.as_slice() => {
225                     return Some(list.as_slice());
226                 }
227                 _ => {}
228             }
229         }
230         return None;
231     }
232
233     /// Finds the `doc` attribute as a NameValue and returns the corresponding
234     /// value found.
235     pub fn doc_value<'a>(&'a self) -> Option<&'a str> {
236         for attr in self.attrs.iter() {
237             match *attr {
238                 NameValue(ref x, ref v) if "doc" == x.as_slice() => {
239                     return Some(v.as_slice());
240                 }
241                 _ => {}
242             }
243         }
244         return None;
245     }
246
247     pub fn is_hidden_from_doc(&self) -> bool {
248         match self.doc_list() {
249             Some(ref l) => {
250                 for innerattr in l.iter() {
251                     match *innerattr {
252                         Word(ref s) if "hidden" == s.as_slice() => {
253                             return true
254                         }
255                         _ => (),
256                     }
257                 }
258             },
259             None => ()
260         }
261         return false;
262     }
263
264     pub fn is_mod(&self) -> bool {
265         match self.inner { ModuleItem(..) => true, _ => false }
266     }
267     pub fn is_trait(&self) -> bool {
268         match self.inner { TraitItem(..) => true, _ => false }
269     }
270     pub fn is_struct(&self) -> bool {
271         match self.inner { StructItem(..) => true, _ => false }
272     }
273     pub fn is_enum(&self) -> bool {
274         match self.inner { EnumItem(..) => true, _ => false }
275     }
276     pub fn is_fn(&self) -> bool {
277         match self.inner { FunctionItem(..) => true, _ => false }
278     }
279 }
280
281 #[deriving(Clone, Encodable, Decodable)]
282 pub enum ItemEnum {
283     StructItem(Struct),
284     EnumItem(Enum),
285     FunctionItem(Function),
286     ModuleItem(Module),
287     TypedefItem(Typedef),
288     StaticItem(Static),
289     TraitItem(Trait),
290     ImplItem(Impl),
291     /// `use` and `extern crate`
292     ViewItemItem(ViewItem),
293     /// A method signature only. Used for required methods in traits (ie,
294     /// non-default-methods).
295     TyMethodItem(TyMethod),
296     /// A method with a body.
297     MethodItem(Method),
298     StructFieldItem(StructField),
299     VariantItem(Variant),
300     /// `fn`s from an extern block
301     ForeignFunctionItem(Function),
302     /// `static`s from an extern block
303     ForeignStaticItem(Static),
304     MacroItem(Macro),
305     PrimitiveItem(Primitive),
306 }
307
308 #[deriving(Clone, Encodable, Decodable)]
309 pub struct Module {
310     pub items: Vec<Item>,
311     pub is_crate: bool,
312 }
313
314 impl Clean<Item> for doctree::Module {
315     fn clean(&self) -> Item {
316         let name = if self.name.is_some() {
317             self.name.unwrap().clean()
318         } else {
319             "".to_string()
320         };
321         let mut foreigns = Vec::new();
322         for subforeigns in self.foreigns.clean().move_iter() {
323             for foreign in subforeigns.move_iter() {
324                 foreigns.push(foreign)
325             }
326         }
327         let items: Vec<Vec<Item> > = vec!(
328             self.structs.clean().move_iter().collect(),
329             self.enums.clean().move_iter().collect(),
330             self.fns.clean().move_iter().collect(),
331             foreigns,
332             self.mods.clean().move_iter().collect(),
333             self.typedefs.clean().move_iter().collect(),
334             self.statics.clean().move_iter().collect(),
335             self.traits.clean().move_iter().collect(),
336             self.impls.clean().move_iter().collect(),
337             self.view_items.clean().move_iter()
338                            .flat_map(|s| s.move_iter()).collect(),
339             self.macros.clean().move_iter().collect()
340         );
341
342         // determine if we should display the inner contents or
343         // the outer `mod` item for the source code.
344         let where = {
345             let ctxt = super::ctxtkey.get().unwrap();
346             let cm = ctxt.sess().codemap();
347             let outer = cm.lookup_char_pos(self.where_outer.lo);
348             let inner = cm.lookup_char_pos(self.where_inner.lo);
349             if outer.file.start_pos == inner.file.start_pos {
350                 // mod foo { ... }
351                 self.where_outer
352             } else {
353                 // mod foo; (and a separate FileMap for the contents)
354                 self.where_inner
355             }
356         };
357
358         Item {
359             name: Some(name),
360             attrs: self.attrs.clean(),
361             source: where.clean(),
362             visibility: self.vis.clean(),
363             def_id: ast_util::local_def(self.id),
364             inner: ModuleItem(Module {
365                is_crate: self.is_crate,
366                items: items.iter()
367                            .flat_map(|x| x.iter().map(|x| (*x).clone()))
368                            .collect(),
369             })
370         }
371     }
372 }
373
374 #[deriving(Clone, Encodable, Decodable)]
375 pub enum Attribute {
376     Word(String),
377     List(String, Vec<Attribute> ),
378     NameValue(String, String)
379 }
380
381 impl Clean<Attribute> for ast::MetaItem {
382     fn clean(&self) -> Attribute {
383         match self.node {
384             ast::MetaWord(ref s) => Word(s.get().to_string()),
385             ast::MetaList(ref s, ref l) => {
386                 List(s.get().to_string(), l.clean().move_iter().collect())
387             }
388             ast::MetaNameValue(ref s, ref v) => {
389                 NameValue(s.get().to_string(), lit_to_str(v))
390             }
391         }
392     }
393 }
394
395 impl Clean<Attribute> for ast::Attribute {
396     fn clean(&self) -> Attribute {
397         self.desugar_doc().node.value.clean()
398     }
399 }
400
401 // This is a rough approximation that gets us what we want.
402 impl attr::AttrMetaMethods for Attribute {
403     fn name(&self) -> InternedString {
404         match *self {
405             Word(ref n) | List(ref n, _) | NameValue(ref n, _) => {
406                 token::intern_and_get_ident(n.as_slice())
407             }
408         }
409     }
410
411     fn value_str(&self) -> Option<InternedString> {
412         match *self {
413             NameValue(_, ref v) => {
414                 Some(token::intern_and_get_ident(v.as_slice()))
415             }
416             _ => None,
417         }
418     }
419     fn meta_item_list<'a>(&'a self) -> Option<&'a [@ast::MetaItem]> { None }
420     fn name_str_pair(&self) -> Option<(InternedString, InternedString)> {
421         None
422     }
423 }
424 impl<'a> attr::AttrMetaMethods for &'a Attribute {
425     fn name(&self) -> InternedString { (**self).name() }
426     fn value_str(&self) -> Option<InternedString> { (**self).value_str() }
427     fn meta_item_list<'a>(&'a self) -> Option<&'a [@ast::MetaItem]> { None }
428     fn name_str_pair(&self) -> Option<(InternedString, InternedString)> {
429         None
430     }
431 }
432
433 #[deriving(Clone, Encodable, Decodable)]
434 pub struct TyParam {
435     pub name: String,
436     pub did: ast::DefId,
437     pub bounds: Vec<TyParamBound>,
438 }
439
440 impl Clean<TyParam> for ast::TyParam {
441     fn clean(&self) -> TyParam {
442         TyParam {
443             name: self.ident.clean(),
444             did: ast::DefId { krate: ast::LOCAL_CRATE, node: self.id },
445             bounds: self.bounds.clean().move_iter().collect(),
446         }
447     }
448 }
449
450 impl Clean<TyParam> for ty::TypeParameterDef {
451     fn clean(&self) -> TyParam {
452         let cx = super::ctxtkey.get().unwrap();
453         cx.external_typarams.borrow_mut().get_mut_ref().insert(self.def_id,
454                                                                self.ident.clean());
455         TyParam {
456             name: self.ident.clean(),
457             did: self.def_id,
458             bounds: self.bounds.clean(),
459         }
460     }
461 }
462
463 #[deriving(Clone, Encodable, Decodable)]
464 pub enum TyParamBound {
465     RegionBound,
466     TraitBound(Type)
467 }
468
469 impl Clean<TyParamBound> for ast::TyParamBound {
470     fn clean(&self) -> TyParamBound {
471         match *self {
472             ast::StaticRegionTyParamBound => RegionBound,
473             ast::OtherRegionTyParamBound(_) => RegionBound,
474             ast::TraitTyParamBound(ref t) => TraitBound(t.clean()),
475         }
476     }
477 }
478
479 fn external_path(name: &str, substs: &ty::substs) -> Path {
480     Path {
481         global: false,
482         segments: vec![PathSegment {
483             name: name.to_string(),
484             lifetimes: match substs.regions {
485                 ty::ErasedRegions => Vec::new(),
486                 ty::NonerasedRegions(ref v) => {
487                     v.iter().filter_map(|v| v.clean()).collect()
488                 }
489             },
490             types: substs.tps.clean(),
491         }],
492     }
493 }
494
495 impl Clean<TyParamBound> for ty::BuiltinBound {
496     fn clean(&self) -> TyParamBound {
497         let cx = super::ctxtkey.get().unwrap();
498         let tcx = match cx.maybe_typed {
499             core::Typed(ref tcx) => tcx,
500             core::NotTyped(_) => return RegionBound,
501         };
502         let empty = ty::substs::empty();
503         let (did, path) = match *self {
504             ty::BoundStatic => return RegionBound,
505             ty::BoundSend =>
506                 (tcx.lang_items.send_trait().unwrap(),
507                  external_path("Send", &empty)),
508             ty::BoundSized =>
509                 (tcx.lang_items.sized_trait().unwrap(),
510                  external_path("Sized", &empty)),
511             ty::BoundCopy =>
512                 (tcx.lang_items.copy_trait().unwrap(),
513                  external_path("Copy", &empty)),
514             ty::BoundShare =>
515                 (tcx.lang_items.share_trait().unwrap(),
516                  external_path("Share", &empty)),
517         };
518         let fqn = csearch::get_item_path(tcx, did);
519         let fqn = fqn.move_iter().map(|i| i.to_str().to_string()).collect();
520         cx.external_paths.borrow_mut().get_mut_ref().insert(did,
521                                                             (fqn, TypeTrait));
522         TraitBound(ResolvedPath {
523             path: path,
524             typarams: None,
525             did: did,
526         })
527     }
528 }
529
530 impl Clean<TyParamBound> for ty::TraitRef {
531     fn clean(&self) -> TyParamBound {
532         let cx = super::ctxtkey.get().unwrap();
533         let tcx = match cx.maybe_typed {
534             core::Typed(ref tcx) => tcx,
535             core::NotTyped(_) => return RegionBound,
536         };
537         let fqn = csearch::get_item_path(tcx, self.def_id);
538         let fqn = fqn.move_iter().map(|i| i.to_str().to_string())
539                      .collect::<Vec<String>>();
540         let path = external_path(fqn.last().unwrap().as_slice(),
541                                  &self.substs);
542         cx.external_paths.borrow_mut().get_mut_ref().insert(self.def_id,
543                                                             (fqn, TypeTrait));
544         TraitBound(ResolvedPath {
545             path: path,
546             typarams: None,
547             did: self.def_id,
548         })
549     }
550 }
551
552 impl Clean<Vec<TyParamBound>> for ty::ParamBounds {
553     fn clean(&self) -> Vec<TyParamBound> {
554         let mut v = Vec::new();
555         for b in self.builtin_bounds.iter() {
556             if b != ty::BoundSized {
557                 v.push(b.clean());
558             }
559         }
560         for t in self.trait_bounds.iter() {
561             v.push(t.clean());
562         }
563         return v;
564     }
565 }
566
567 impl Clean<Option<Vec<TyParamBound>>> for ty::substs {
568     fn clean(&self) -> Option<Vec<TyParamBound>> {
569         let mut v = Vec::new();
570         match self.regions {
571             ty::NonerasedRegions(..) => v.push(RegionBound),
572             ty::ErasedRegions => {}
573         }
574         v.extend(self.tps.iter().map(|t| TraitBound(t.clean())));
575
576         if v.len() > 0 {Some(v)} else {None}
577     }
578 }
579
580 #[deriving(Clone, Encodable, Decodable, PartialEq)]
581 pub struct Lifetime(String);
582
583 impl Lifetime {
584     pub fn get_ref<'a>(&'a self) -> &'a str {
585         let Lifetime(ref s) = *self;
586         let s: &'a str = s.as_slice();
587         return s;
588     }
589 }
590
591 impl Clean<Lifetime> for ast::Lifetime {
592     fn clean(&self) -> Lifetime {
593         Lifetime(token::get_name(self.name).get().to_string())
594     }
595 }
596
597 impl Clean<Lifetime> for ty::RegionParameterDef {
598     fn clean(&self) -> Lifetime {
599         Lifetime(token::get_name(self.name).get().to_string())
600     }
601 }
602
603 impl Clean<Option<Lifetime>> for ty::Region {
604     fn clean(&self) -> Option<Lifetime> {
605         match *self {
606             ty::ReStatic => Some(Lifetime("static".to_string())),
607             ty::ReLateBound(_, ty::BrNamed(_, name)) =>
608                 Some(Lifetime(token::get_name(name).get().to_string())),
609             ty::ReEarlyBound(_, _, name) => Some(Lifetime(name.clean())),
610
611             ty::ReLateBound(..) |
612             ty::ReFree(..) |
613             ty::ReScope(..) |
614             ty::ReInfer(..) |
615             ty::ReEmpty(..) => None
616         }
617     }
618 }
619
620 // maybe use a Generic enum and use ~[Generic]?
621 #[deriving(Clone, Encodable, Decodable)]
622 pub struct Generics {
623     pub lifetimes: Vec<Lifetime>,
624     pub type_params: Vec<TyParam>,
625 }
626
627 impl Clean<Generics> for ast::Generics {
628     fn clean(&self) -> Generics {
629         Generics {
630             lifetimes: self.lifetimes.clean().move_iter().collect(),
631             type_params: self.ty_params.clean().move_iter().collect(),
632         }
633     }
634 }
635
636 impl Clean<Generics> for ty::Generics {
637     fn clean(&self) -> Generics {
638         Generics {
639             lifetimes: self.region_param_defs.clean(),
640             type_params: self.type_param_defs.clean(),
641         }
642     }
643 }
644
645 #[deriving(Clone, Encodable, Decodable)]
646 pub struct Method {
647     pub generics: Generics,
648     pub self_: SelfTy,
649     pub fn_style: ast::FnStyle,
650     pub decl: FnDecl,
651 }
652
653 impl Clean<Item> for ast::Method {
654     fn clean(&self) -> Item {
655         let inputs = match self.explicit_self.node {
656             ast::SelfStatic => self.decl.inputs.as_slice(),
657             _ => self.decl.inputs.slice_from(1)
658         };
659         let decl = FnDecl {
660             inputs: Arguments {
661                 values: inputs.iter().map(|x| x.clean()).collect(),
662             },
663             output: (self.decl.output.clean()),
664             cf: self.decl.cf.clean(),
665             attrs: Vec::new()
666         };
667         Item {
668             name: Some(self.ident.clean()),
669             attrs: self.attrs.clean().move_iter().collect(),
670             source: self.span.clean(),
671             def_id: ast_util::local_def(self.id.clone()),
672             visibility: self.vis.clean(),
673             inner: MethodItem(Method {
674                 generics: self.generics.clean(),
675                 self_: self.explicit_self.node.clean(),
676                 fn_style: self.fn_style.clone(),
677                 decl: decl,
678             }),
679         }
680     }
681 }
682
683 #[deriving(Clone, Encodable, Decodable)]
684 pub struct TyMethod {
685     pub fn_style: ast::FnStyle,
686     pub decl: FnDecl,
687     pub generics: Generics,
688     pub self_: SelfTy,
689 }
690
691 impl Clean<Item> for ast::TypeMethod {
692     fn clean(&self) -> Item {
693         let inputs = match self.explicit_self.node {
694             ast::SelfStatic => self.decl.inputs.as_slice(),
695             _ => self.decl.inputs.slice_from(1)
696         };
697         let decl = FnDecl {
698             inputs: Arguments {
699                 values: inputs.iter().map(|x| x.clean()).collect(),
700             },
701             output: (self.decl.output.clean()),
702             cf: self.decl.cf.clean(),
703             attrs: Vec::new()
704         };
705         Item {
706             name: Some(self.ident.clean()),
707             attrs: self.attrs.clean().move_iter().collect(),
708             source: self.span.clean(),
709             def_id: ast_util::local_def(self.id),
710             visibility: None,
711             inner: TyMethodItem(TyMethod {
712                 fn_style: self.fn_style.clone(),
713                 decl: decl,
714                 self_: self.explicit_self.node.clean(),
715                 generics: self.generics.clean(),
716             }),
717         }
718     }
719 }
720
721 #[deriving(Clone, Encodable, Decodable, PartialEq)]
722 pub enum SelfTy {
723     SelfStatic,
724     SelfValue,
725     SelfBorrowed(Option<Lifetime>, Mutability),
726     SelfOwned,
727 }
728
729 impl Clean<SelfTy> for ast::ExplicitSelf_ {
730     fn clean(&self) -> SelfTy {
731         match *self {
732             ast::SelfStatic => SelfStatic,
733             ast::SelfValue => SelfValue,
734             ast::SelfUniq => SelfOwned,
735             ast::SelfRegion(lt, mt) => SelfBorrowed(lt.clean(), mt.clean()),
736         }
737     }
738 }
739
740 #[deriving(Clone, Encodable, Decodable)]
741 pub struct Function {
742     pub decl: FnDecl,
743     pub generics: Generics,
744     pub fn_style: ast::FnStyle,
745 }
746
747 impl Clean<Item> for doctree::Function {
748     fn clean(&self) -> Item {
749         Item {
750             name: Some(self.name.clean()),
751             attrs: self.attrs.clean(),
752             source: self.where.clean(),
753             visibility: self.vis.clean(),
754             def_id: ast_util::local_def(self.id),
755             inner: FunctionItem(Function {
756                 decl: self.decl.clean(),
757                 generics: self.generics.clean(),
758                 fn_style: self.fn_style,
759             }),
760         }
761     }
762 }
763
764 #[deriving(Clone, Encodable, Decodable)]
765 pub struct ClosureDecl {
766     pub lifetimes: Vec<Lifetime>,
767     pub decl: FnDecl,
768     pub onceness: ast::Onceness,
769     pub fn_style: ast::FnStyle,
770     pub bounds: Vec<TyParamBound>,
771 }
772
773 impl Clean<ClosureDecl> for ast::ClosureTy {
774     fn clean(&self) -> ClosureDecl {
775         ClosureDecl {
776             lifetimes: self.lifetimes.clean(),
777             decl: self.decl.clean(),
778             onceness: self.onceness,
779             fn_style: self.fn_style,
780             bounds: match self.bounds {
781                 Some(ref x) => x.clean().move_iter().collect(),
782                 None        => Vec::new()
783             },
784         }
785     }
786 }
787
788 #[deriving(Clone, Encodable, Decodable)]
789 pub struct FnDecl {
790     pub inputs: Arguments,
791     pub output: Type,
792     pub cf: RetStyle,
793     pub attrs: Vec<Attribute>,
794 }
795
796 #[deriving(Clone, Encodable, Decodable)]
797 pub struct Arguments {
798     pub values: Vec<Argument>,
799 }
800
801 impl Clean<FnDecl> for ast::FnDecl {
802     fn clean(&self) -> FnDecl {
803         FnDecl {
804             inputs: Arguments {
805                 values: self.inputs.iter().map(|x| x.clean()).collect(),
806             },
807             output: (self.output.clean()),
808             cf: self.cf.clean(),
809             attrs: Vec::new()
810         }
811     }
812 }
813
814 impl<'a> Clean<FnDecl> for (ast::DefId, &'a ty::FnSig) {
815     fn clean(&self) -> FnDecl {
816         let cx = super::ctxtkey.get().unwrap();
817         let tcx = match cx.maybe_typed {
818             core::Typed(ref tcx) => tcx,
819             core::NotTyped(_) => unreachable!(),
820         };
821         let (did, sig) = *self;
822         let mut names = if did.node != 0 {
823             csearch::get_method_arg_names(&tcx.sess.cstore, did).move_iter()
824         } else {
825             Vec::new().move_iter()
826         }.peekable();
827         if names.peek().map(|s| s.as_slice()) == Some("self") {
828             let _ = names.next();
829         }
830         FnDecl {
831             output: sig.output.clean(),
832             cf: Return,
833             attrs: Vec::new(),
834             inputs: Arguments {
835                 values: sig.inputs.iter().map(|t| {
836                     Argument {
837                         type_: t.clean(),
838                         id: 0,
839                         name: names.next().unwrap_or("".to_string()),
840                     }
841                 }).collect(),
842             },
843         }
844     }
845 }
846
847 #[deriving(Clone, Encodable, Decodable)]
848 pub struct Argument {
849     pub type_: Type,
850     pub name: String,
851     pub id: ast::NodeId,
852 }
853
854 impl Clean<Argument> for ast::Arg {
855     fn clean(&self) -> Argument {
856         Argument {
857             name: name_from_pat(self.pat),
858             type_: (self.ty.clean()),
859             id: self.id
860         }
861     }
862 }
863
864 #[deriving(Clone, Encodable, Decodable)]
865 pub enum RetStyle {
866     NoReturn,
867     Return
868 }
869
870 impl Clean<RetStyle> for ast::RetStyle {
871     fn clean(&self) -> RetStyle {
872         match *self {
873             ast::Return => Return,
874             ast::NoReturn => NoReturn
875         }
876     }
877 }
878
879 #[deriving(Clone, Encodable, Decodable)]
880 pub struct Trait {
881     pub methods: Vec<TraitMethod>,
882     pub generics: Generics,
883     pub parents: Vec<Type>,
884 }
885
886 impl Clean<Item> for doctree::Trait {
887     fn clean(&self) -> Item {
888         Item {
889             name: Some(self.name.clean()),
890             attrs: self.attrs.clean(),
891             source: self.where.clean(),
892             def_id: ast_util::local_def(self.id),
893             visibility: self.vis.clean(),
894             inner: TraitItem(Trait {
895                 methods: self.methods.clean(),
896                 generics: self.generics.clean(),
897                 parents: self.parents.clean(),
898             }),
899         }
900     }
901 }
902
903 impl Clean<Type> for ast::TraitRef {
904     fn clean(&self) -> Type {
905         resolve_type(self.path.clean(), None, self.ref_id)
906     }
907 }
908
909 #[deriving(Clone, Encodable, Decodable)]
910 pub enum TraitMethod {
911     Required(Item),
912     Provided(Item),
913 }
914
915 impl TraitMethod {
916     pub fn is_req(&self) -> bool {
917         match self {
918             &Required(..) => true,
919             _ => false,
920         }
921     }
922     pub fn is_def(&self) -> bool {
923         match self {
924             &Provided(..) => true,
925             _ => false,
926         }
927     }
928     pub fn item<'a>(&'a self) -> &'a Item {
929         match *self {
930             Required(ref item) => item,
931             Provided(ref item) => item,
932         }
933     }
934 }
935
936 impl Clean<TraitMethod> for ast::TraitMethod {
937     fn clean(&self) -> TraitMethod {
938         match self {
939             &ast::Required(ref t) => Required(t.clean()),
940             &ast::Provided(ref t) => Provided(t.clean()),
941         }
942     }
943 }
944
945 impl Clean<TraitMethod> for ty::Method {
946     fn clean(&self) -> TraitMethod {
947         let m = if self.provided_source.is_some() {Provided} else {Required};
948         let cx = super::ctxtkey.get().unwrap();
949         let tcx = match cx.maybe_typed {
950             core::Typed(ref tcx) => tcx,
951             core::NotTyped(_) => unreachable!(),
952         };
953         let (self_, sig) = match self.explicit_self {
954             ast::SelfStatic => (ast::SelfStatic.clean(), self.fty.sig.clone()),
955             s => {
956                 let sig = ty::FnSig {
957                     inputs: Vec::from_slice(self.fty.sig.inputs.slice_from(1)),
958                     ..self.fty.sig.clone()
959                 };
960                 let s = match s {
961                     ast::SelfRegion(..) => {
962                         match ty::get(*self.fty.sig.inputs.get(0)).sty {
963                             ty::ty_rptr(r, mt) => {
964                                 SelfBorrowed(r.clean(), mt.mutbl.clean())
965                             }
966                             _ => s.clean(),
967                         }
968                     }
969                     s => s.clean(),
970                 };
971                 (s, sig)
972             }
973         };
974
975         m(Item {
976             name: Some(self.ident.clean()),
977             visibility: Some(ast::Inherited),
978             def_id: self.def_id,
979             attrs: inline::load_attrs(tcx, self.def_id),
980             source: Span::empty(),
981             inner: TyMethodItem(TyMethod {
982                 fn_style: self.fty.fn_style,
983                 generics: self.generics.clean(),
984                 self_: self_,
985                 decl: (self.def_id, &sig).clean(),
986             })
987         })
988     }
989 }
990
991 /// A representation of a Type suitable for hyperlinking purposes. Ideally one can get the original
992 /// type out of the AST/ty::ctxt given one of these, if more information is needed. Most importantly
993 /// it does not preserve mutability or boxes.
994 #[deriving(Clone, Encodable, Decodable)]
995 pub enum Type {
996     /// structs/enums/traits (anything that'd be an ast::TyPath)
997     ResolvedPath {
998         pub path: Path,
999         pub typarams: Option<Vec<TyParamBound>>,
1000         pub did: ast::DefId,
1001     },
1002     // I have no idea how to usefully use this.
1003     TyParamBinder(ast::NodeId),
1004     /// For parameterized types, so the consumer of the JSON don't go looking
1005     /// for types which don't exist anywhere.
1006     Generic(ast::DefId),
1007     /// For references to self
1008     Self(ast::DefId),
1009     /// Primitives are just the fixed-size numeric types (plus int/uint/float), and char.
1010     Primitive(Primitive),
1011     Closure(Box<ClosureDecl>, Option<Lifetime>),
1012     Proc(Box<ClosureDecl>),
1013     /// extern "ABI" fn
1014     BareFunction(Box<BareFunctionDecl>),
1015     Tuple(Vec<Type>),
1016     Vector(Box<Type>),
1017     FixedVector(Box<Type>, String),
1018     /// aka TyBot
1019     Bottom,
1020     Unique(Box<Type>),
1021     Managed(Box<Type>),
1022     RawPointer(Mutability, Box<Type>),
1023     BorrowedRef {
1024         pub lifetime: Option<Lifetime>,
1025         pub mutability: Mutability,
1026         pub type_: Box<Type>,
1027     },
1028     // region, raw, other boxes, mutable
1029 }
1030
1031 #[deriving(Clone, Encodable, Decodable, Eq, TotalEq, Hash)]
1032 pub enum Primitive {
1033     Int, I8, I16, I32, I64,
1034     Uint, U8, U16, U32, U64,
1035     F32, F64, F128,
1036     Char,
1037     Bool,
1038     Nil,
1039     Str,
1040     Slice,
1041     PrimitiveTuple,
1042 }
1043
1044 #[deriving(Clone, Encodable, Decodable)]
1045 pub enum TypeKind {
1046     TypeEnum,
1047     TypeFunction,
1048     TypeModule,
1049     TypeStatic,
1050     TypeStruct,
1051     TypeTrait,
1052     TypeVariant,
1053 }
1054
1055 impl Primitive {
1056     fn from_str(s: &str) -> Option<Primitive> {
1057         match s.as_slice() {
1058             "int" => Some(Int),
1059             "i8" => Some(I8),
1060             "i16" => Some(I16),
1061             "i32" => Some(I32),
1062             "i64" => Some(I64),
1063             "uint" => Some(Uint),
1064             "u8" => Some(U8),
1065             "u16" => Some(U16),
1066             "u32" => Some(U32),
1067             "u64" => Some(U64),
1068             "bool" => Some(Bool),
1069             "nil" => Some(Nil),
1070             "char" => Some(Char),
1071             "str" => Some(Str),
1072             "f32" => Some(F32),
1073             "f64" => Some(F64),
1074             "f128" => Some(F128),
1075             "slice" => Some(Slice),
1076             "tuple" => Some(PrimitiveTuple),
1077             _ => None,
1078         }
1079     }
1080
1081     fn find(attrs: &[Attribute]) -> Option<Primitive> {
1082         for attr in attrs.iter() {
1083             let list = match *attr {
1084                 List(ref k, ref l) if k.as_slice() == "doc" => l,
1085                 _ => continue,
1086             };
1087             for sub_attr in list.iter() {
1088                 let value = match *sub_attr {
1089                     NameValue(ref k, ref v)
1090                         if k.as_slice() == "primitive" => v.as_slice(),
1091                     _ => continue,
1092                 };
1093                 match Primitive::from_str(value) {
1094                     Some(p) => return Some(p),
1095                     None => {}
1096                 }
1097             }
1098         }
1099         return None
1100     }
1101
1102     pub fn to_str(&self) -> &'static str {
1103         match *self {
1104             Int => "int",
1105             I8 => "i8",
1106             I16 => "i16",
1107             I32 => "i32",
1108             I64 => "i64",
1109             Uint => "uint",
1110             U8 => "u8",
1111             U16 => "u16",
1112             U32 => "u32",
1113             U64 => "u64",
1114             F32 => "f32",
1115             F64 => "f64",
1116             F128 => "f128",
1117             Str => "str",
1118             Bool => "bool",
1119             Char => "char",
1120             Nil => "()",
1121             Slice => "slice",
1122             PrimitiveTuple => "tuple",
1123         }
1124     }
1125
1126     pub fn to_url_str(&self) -> &'static str {
1127         match *self {
1128             Nil => "nil",
1129             other => other.to_str(),
1130         }
1131     }
1132
1133     /// Creates a rustdoc-specific node id for primitive types.
1134     ///
1135     /// These node ids are generally never used by the AST itself.
1136     pub fn to_node_id(&self) -> ast::NodeId {
1137         u32::MAX - 1 - (*self as u32)
1138     }
1139 }
1140
1141 impl Clean<Type> for ast::Ty {
1142     fn clean(&self) -> Type {
1143         use syntax::ast::*;
1144         match self.node {
1145             TyNil => Primitive(Nil),
1146             TyPtr(ref m) => RawPointer(m.mutbl.clean(), box m.ty.clean()),
1147             TyRptr(ref l, ref m) =>
1148                 BorrowedRef {lifetime: l.clean(), mutability: m.mutbl.clean(),
1149                              type_: box m.ty.clean()},
1150             TyBox(ty) => Managed(box ty.clean()),
1151             TyUniq(ty) => Unique(box ty.clean()),
1152             TyVec(ty) => Vector(box ty.clean()),
1153             TyFixedLengthVec(ty, ref e) => FixedVector(box ty.clean(),
1154                                                        e.span.to_src()),
1155             TyTup(ref tys) => Tuple(tys.iter().map(|x| x.clean()).collect()),
1156             TyPath(ref p, ref tpbs, id) => {
1157                 resolve_type(p.clean(),
1158                              tpbs.clean().map(|x| x.move_iter().collect()),
1159                              id)
1160             }
1161             TyClosure(ref c, region) => Closure(box c.clean(), region.clean()),
1162             TyProc(ref c) => Proc(box c.clean()),
1163             TyBareFn(ref barefn) => BareFunction(box barefn.clean()),
1164             TyBot => Bottom,
1165             ref x => fail!("Unimplemented type {:?}", x),
1166         }
1167     }
1168 }
1169
1170 impl Clean<Type> for ty::t {
1171     fn clean(&self) -> Type {
1172         match ty::get(*self).sty {
1173             ty::ty_bot => Bottom,
1174             ty::ty_nil => Primitive(Nil),
1175             ty::ty_bool => Primitive(Bool),
1176             ty::ty_char => Primitive(Char),
1177             ty::ty_int(ast::TyI) => Primitive(Int),
1178             ty::ty_int(ast::TyI8) => Primitive(I8),
1179             ty::ty_int(ast::TyI16) => Primitive(I16),
1180             ty::ty_int(ast::TyI32) => Primitive(I32),
1181             ty::ty_int(ast::TyI64) => Primitive(I64),
1182             ty::ty_uint(ast::TyU) => Primitive(Uint),
1183             ty::ty_uint(ast::TyU8) => Primitive(U8),
1184             ty::ty_uint(ast::TyU16) => Primitive(U16),
1185             ty::ty_uint(ast::TyU32) => Primitive(U32),
1186             ty::ty_uint(ast::TyU64) => Primitive(U64),
1187             ty::ty_float(ast::TyF32) => Primitive(F32),
1188             ty::ty_float(ast::TyF64) => Primitive(F64),
1189             ty::ty_float(ast::TyF128) => Primitive(F128),
1190             ty::ty_str => Primitive(Str),
1191             ty::ty_box(t) => Managed(box t.clean()),
1192             ty::ty_uniq(t) => Unique(box t.clean()),
1193             ty::ty_vec(mt, None) => Vector(box mt.ty.clean()),
1194             ty::ty_vec(mt, Some(i)) => FixedVector(box mt.ty.clean(),
1195                                                    format!("{}", i)),
1196             ty::ty_ptr(mt) => RawPointer(mt.mutbl.clean(), box mt.ty.clean()),
1197             ty::ty_rptr(r, mt) => BorrowedRef {
1198                 lifetime: r.clean(),
1199                 mutability: mt.mutbl.clean(),
1200                 type_: box mt.ty.clean(),
1201             },
1202             ty::ty_bare_fn(ref fty) => BareFunction(box BareFunctionDecl {
1203                 fn_style: fty.fn_style,
1204                 generics: Generics {
1205                     lifetimes: Vec::new(), type_params: Vec::new()
1206                 },
1207                 decl: (ast_util::local_def(0), &fty.sig).clean(),
1208                 abi: fty.abi.to_str(),
1209             }),
1210             ty::ty_closure(ref fty) => {
1211                 let decl = box ClosureDecl {
1212                     lifetimes: Vec::new(), // FIXME: this looks wrong...
1213                     decl: (ast_util::local_def(0), &fty.sig).clean(),
1214                     onceness: fty.onceness,
1215                     fn_style: fty.fn_style,
1216                     bounds: fty.bounds.iter().map(|i| i.clean()).collect(),
1217                 };
1218                 match fty.store {
1219                     ty::UniqTraitStore => Proc(decl),
1220                     ty::RegionTraitStore(ref r, _) => Closure(decl, r.clean()),
1221                 }
1222             }
1223             ty::ty_struct(did, ref substs) |
1224             ty::ty_enum(did, ref substs) |
1225             ty::ty_trait(box ty::TyTrait { def_id: did, ref substs, .. }) => {
1226                 let cx = super::ctxtkey.get().unwrap();
1227                 let tcx = match cx.maybe_typed {
1228                     core::Typed(ref tycx) => tycx,
1229                     core::NotTyped(_) => unreachable!(),
1230                 };
1231                 let fqn = csearch::get_item_path(tcx, did);
1232                 let fqn: Vec<String> = fqn.move_iter().map(|i| {
1233                     i.to_str().to_string()
1234                 }).collect();
1235                 let kind = match ty::get(*self).sty {
1236                     ty::ty_struct(..) => TypeStruct,
1237                     ty::ty_trait(..) => TypeTrait,
1238                     _ => TypeEnum,
1239                 };
1240                 let path = external_path(fqn.last().unwrap().to_str().as_slice(),
1241                                          substs);
1242                 cx.external_paths.borrow_mut().get_mut_ref().insert(did,
1243                                                                     (fqn, kind));
1244                 ResolvedPath {
1245                     path: path,
1246                     typarams: None,
1247                     did: did,
1248                 }
1249             }
1250             ty::ty_tup(ref t) => Tuple(t.iter().map(|t| t.clean()).collect()),
1251
1252             ty::ty_param(ref p) => Generic(p.def_id),
1253             ty::ty_self(did) => Self(did),
1254
1255             ty::ty_infer(..) => fail!("ty_infer"),
1256             ty::ty_err => fail!("ty_err"),
1257         }
1258     }
1259 }
1260
1261 #[deriving(Clone, Encodable, Decodable)]
1262 pub enum StructField {
1263     HiddenStructField, // inserted later by strip passes
1264     TypedStructField(Type),
1265 }
1266
1267 impl Clean<Item> for ast::StructField {
1268     fn clean(&self) -> Item {
1269         let (name, vis) = match self.node.kind {
1270             ast::NamedField(id, vis) => (Some(id), vis),
1271             ast::UnnamedField(vis) => (None, vis)
1272         };
1273         Item {
1274             name: name.clean(),
1275             attrs: self.node.attrs.clean().move_iter().collect(),
1276             source: self.span.clean(),
1277             visibility: Some(vis),
1278             def_id: ast_util::local_def(self.node.id),
1279             inner: StructFieldItem(TypedStructField(self.node.ty.clean())),
1280         }
1281     }
1282 }
1283
1284 impl Clean<Item> for ty::field_ty {
1285     fn clean(&self) -> Item {
1286         use syntax::parse::token::special_idents::unnamed_field;
1287         let name = if self.name == unnamed_field.name {
1288             None
1289         } else {
1290             Some(self.name)
1291         };
1292         let cx = super::ctxtkey.get().unwrap();
1293         let tcx = match cx.maybe_typed {
1294             core::Typed(ref tycx) => tycx,
1295             core::NotTyped(_) => unreachable!(),
1296         };
1297         let ty = ty::lookup_item_type(tcx, self.id);
1298         Item {
1299             name: name.clean(),
1300             attrs: inline::load_attrs(tcx, self.id),
1301             source: Span::empty(),
1302             visibility: Some(self.vis),
1303             def_id: self.id,
1304             inner: StructFieldItem(TypedStructField(ty.ty.clean())),
1305         }
1306     }
1307 }
1308
1309 pub type Visibility = ast::Visibility;
1310
1311 impl Clean<Option<Visibility>> for ast::Visibility {
1312     fn clean(&self) -> Option<Visibility> {
1313         Some(*self)
1314     }
1315 }
1316
1317 #[deriving(Clone, Encodable, Decodable)]
1318 pub struct Struct {
1319     pub struct_type: doctree::StructType,
1320     pub generics: Generics,
1321     pub fields: Vec<Item>,
1322     pub fields_stripped: bool,
1323 }
1324
1325 impl Clean<Item> for doctree::Struct {
1326     fn clean(&self) -> Item {
1327         Item {
1328             name: Some(self.name.clean()),
1329             attrs: self.attrs.clean(),
1330             source: self.where.clean(),
1331             def_id: ast_util::local_def(self.id),
1332             visibility: self.vis.clean(),
1333             inner: StructItem(Struct {
1334                 struct_type: self.struct_type,
1335                 generics: self.generics.clean(),
1336                 fields: self.fields.clean(),
1337                 fields_stripped: false,
1338             }),
1339         }
1340     }
1341 }
1342
1343 /// This is a more limited form of the standard Struct, different in that
1344 /// it lacks the things most items have (name, id, parameterization). Found
1345 /// only as a variant in an enum.
1346 #[deriving(Clone, Encodable, Decodable)]
1347 pub struct VariantStruct {
1348     pub struct_type: doctree::StructType,
1349     pub fields: Vec<Item>,
1350     pub fields_stripped: bool,
1351 }
1352
1353 impl Clean<VariantStruct> for syntax::ast::StructDef {
1354     fn clean(&self) -> VariantStruct {
1355         VariantStruct {
1356             struct_type: doctree::struct_type_from_def(self),
1357             fields: self.fields.clean().move_iter().collect(),
1358             fields_stripped: false,
1359         }
1360     }
1361 }
1362
1363 #[deriving(Clone, Encodable, Decodable)]
1364 pub struct Enum {
1365     pub variants: Vec<Item>,
1366     pub generics: Generics,
1367     pub variants_stripped: bool,
1368 }
1369
1370 impl Clean<Item> for doctree::Enum {
1371     fn clean(&self) -> Item {
1372         Item {
1373             name: Some(self.name.clean()),
1374             attrs: self.attrs.clean(),
1375             source: self.where.clean(),
1376             def_id: ast_util::local_def(self.id),
1377             visibility: self.vis.clean(),
1378             inner: EnumItem(Enum {
1379                 variants: self.variants.clean(),
1380                 generics: self.generics.clean(),
1381                 variants_stripped: false,
1382             }),
1383         }
1384     }
1385 }
1386
1387 #[deriving(Clone, Encodable, Decodable)]
1388 pub struct Variant {
1389     pub kind: VariantKind,
1390 }
1391
1392 impl Clean<Item> for doctree::Variant {
1393     fn clean(&self) -> Item {
1394         Item {
1395             name: Some(self.name.clean()),
1396             attrs: self.attrs.clean(),
1397             source: self.where.clean(),
1398             visibility: self.vis.clean(),
1399             def_id: ast_util::local_def(self.id),
1400             inner: VariantItem(Variant {
1401                 kind: self.kind.clean(),
1402             }),
1403         }
1404     }
1405 }
1406
1407 impl Clean<Item> for ty::VariantInfo {
1408     fn clean(&self) -> Item {
1409         // use syntax::parse::token::special_idents::unnamed_field;
1410         let cx = super::ctxtkey.get().unwrap();
1411         let tcx = match cx.maybe_typed {
1412             core::Typed(ref tycx) => tycx,
1413             core::NotTyped(_) => fail!("tcx not present"),
1414         };
1415         let kind = match self.arg_names.as_ref().map(|s| s.as_slice()) {
1416             None | Some([]) if self.args.len() == 0 => CLikeVariant,
1417             None | Some([]) => {
1418                 TupleVariant(self.args.iter().map(|t| t.clean()).collect())
1419             }
1420             Some(s) => {
1421                 StructVariant(VariantStruct {
1422                     struct_type: doctree::Plain,
1423                     fields_stripped: false,
1424                     fields: s.iter().zip(self.args.iter()).map(|(name, ty)| {
1425                         Item {
1426                             source: Span::empty(),
1427                             name: Some(name.clean()),
1428                             attrs: Vec::new(),
1429                             visibility: Some(ast::Public),
1430                             // FIXME: this is not accurate, we need an id for
1431                             //        the specific field but we're using the id
1432                             //        for the whole variant. Nothing currently
1433                             //        uses this so we should be good for now.
1434                             def_id: self.id,
1435                             inner: StructFieldItem(
1436                                 TypedStructField(ty.clean())
1437                             )
1438                         }
1439                     }).collect()
1440                 })
1441             }
1442         };
1443         Item {
1444             name: Some(self.name.clean()),
1445             attrs: inline::load_attrs(tcx, self.id),
1446             source: Span::empty(),
1447             visibility: Some(ast::Public),
1448             def_id: self.id,
1449             inner: VariantItem(Variant { kind: kind }),
1450         }
1451     }
1452 }
1453
1454 #[deriving(Clone, Encodable, Decodable)]
1455 pub enum VariantKind {
1456     CLikeVariant,
1457     TupleVariant(Vec<Type>),
1458     StructVariant(VariantStruct),
1459 }
1460
1461 impl Clean<VariantKind> for ast::VariantKind {
1462     fn clean(&self) -> VariantKind {
1463         match self {
1464             &ast::TupleVariantKind(ref args) => {
1465                 if args.len() == 0 {
1466                     CLikeVariant
1467                 } else {
1468                     TupleVariant(args.iter().map(|x| x.ty.clean()).collect())
1469                 }
1470             },
1471             &ast::StructVariantKind(ref sd) => StructVariant(sd.clean()),
1472         }
1473     }
1474 }
1475
1476 #[deriving(Clone, Encodable, Decodable)]
1477 pub struct Span {
1478     pub filename: String,
1479     pub loline: uint,
1480     pub locol: uint,
1481     pub hiline: uint,
1482     pub hicol: uint,
1483 }
1484
1485 impl Span {
1486     fn empty() -> Span {
1487         Span {
1488             filename: "".to_string(),
1489             loline: 0, locol: 0,
1490             hiline: 0, hicol: 0,
1491         }
1492     }
1493 }
1494
1495 impl Clean<Span> for syntax::codemap::Span {
1496     fn clean(&self) -> Span {
1497         let ctxt = super::ctxtkey.get().unwrap();
1498         let cm = ctxt.sess().codemap();
1499         let filename = cm.span_to_filename(*self);
1500         let lo = cm.lookup_char_pos(self.lo);
1501         let hi = cm.lookup_char_pos(self.hi);
1502         Span {
1503             filename: filename.to_string(),
1504             loline: lo.line,
1505             locol: lo.col.to_uint(),
1506             hiline: hi.line,
1507             hicol: hi.col.to_uint(),
1508         }
1509     }
1510 }
1511
1512 #[deriving(Clone, Encodable, Decodable)]
1513 pub struct Path {
1514     pub global: bool,
1515     pub segments: Vec<PathSegment>,
1516 }
1517
1518 impl Clean<Path> for ast::Path {
1519     fn clean(&self) -> Path {
1520         Path {
1521             global: self.global,
1522             segments: self.segments.clean().move_iter().collect(),
1523         }
1524     }
1525 }
1526
1527 #[deriving(Clone, Encodable, Decodable)]
1528 pub struct PathSegment {
1529     pub name: String,
1530     pub lifetimes: Vec<Lifetime>,
1531     pub types: Vec<Type>,
1532 }
1533
1534 impl Clean<PathSegment> for ast::PathSegment {
1535     fn clean(&self) -> PathSegment {
1536         PathSegment {
1537             name: self.identifier.clean(),
1538             lifetimes: self.lifetimes.clean().move_iter().collect(),
1539             types: self.types.clean().move_iter().collect()
1540         }
1541     }
1542 }
1543
1544 fn path_to_str(p: &ast::Path) -> String {
1545     use syntax::parse::token;
1546
1547     let mut s = String::new();
1548     let mut first = true;
1549     for i in p.segments.iter().map(|x| token::get_ident(x.identifier)) {
1550         if !first || p.global {
1551             s.push_str("::");
1552         } else {
1553             first = false;
1554         }
1555         s.push_str(i.get());
1556     }
1557     s
1558 }
1559
1560 impl Clean<String> for ast::Ident {
1561     fn clean(&self) -> String {
1562         token::get_ident(*self).get().to_string()
1563     }
1564 }
1565
1566 impl Clean<String> for ast::Name {
1567     fn clean(&self) -> String {
1568         token::get_name(*self).get().to_string()
1569     }
1570 }
1571
1572 #[deriving(Clone, Encodable, Decodable)]
1573 pub struct Typedef {
1574     pub type_: Type,
1575     pub generics: Generics,
1576 }
1577
1578 impl Clean<Item> for doctree::Typedef {
1579     fn clean(&self) -> Item {
1580         Item {
1581             name: Some(self.name.clean()),
1582             attrs: self.attrs.clean(),
1583             source: self.where.clean(),
1584             def_id: ast_util::local_def(self.id.clone()),
1585             visibility: self.vis.clean(),
1586             inner: TypedefItem(Typedef {
1587                 type_: self.ty.clean(),
1588                 generics: self.gen.clean(),
1589             }),
1590         }
1591     }
1592 }
1593
1594 #[deriving(Clone, Encodable, Decodable)]
1595 pub struct BareFunctionDecl {
1596     pub fn_style: ast::FnStyle,
1597     pub generics: Generics,
1598     pub decl: FnDecl,
1599     pub abi: String,
1600 }
1601
1602 impl Clean<BareFunctionDecl> for ast::BareFnTy {
1603     fn clean(&self) -> BareFunctionDecl {
1604         BareFunctionDecl {
1605             fn_style: self.fn_style,
1606             generics: Generics {
1607                 lifetimes: self.lifetimes.clean().move_iter().collect(),
1608                 type_params: Vec::new(),
1609             },
1610             decl: self.decl.clean(),
1611             abi: self.abi.to_str().to_string(),
1612         }
1613     }
1614 }
1615
1616 #[deriving(Clone, Encodable, Decodable)]
1617 pub struct Static {
1618     pub type_: Type,
1619     pub mutability: Mutability,
1620     /// It's useful to have the value of a static documented, but I have no
1621     /// desire to represent expressions (that'd basically be all of the AST,
1622     /// which is huge!). So, have a string.
1623     pub expr: String,
1624 }
1625
1626 impl Clean<Item> for doctree::Static {
1627     fn clean(&self) -> Item {
1628         debug!("claning static {}: {:?}", self.name.clean(), self);
1629         Item {
1630             name: Some(self.name.clean()),
1631             attrs: self.attrs.clean(),
1632             source: self.where.clean(),
1633             def_id: ast_util::local_def(self.id),
1634             visibility: self.vis.clean(),
1635             inner: StaticItem(Static {
1636                 type_: self.type_.clean(),
1637                 mutability: self.mutability.clean(),
1638                 expr: self.expr.span.to_src(),
1639             }),
1640         }
1641     }
1642 }
1643
1644 #[deriving(Show, Clone, Encodable, Decodable, PartialEq)]
1645 pub enum Mutability {
1646     Mutable,
1647     Immutable,
1648 }
1649
1650 impl Clean<Mutability> for ast::Mutability {
1651     fn clean(&self) -> Mutability {
1652         match self {
1653             &ast::MutMutable => Mutable,
1654             &ast::MutImmutable => Immutable,
1655         }
1656     }
1657 }
1658
1659 #[deriving(Clone, Encodable, Decodable)]
1660 pub struct Impl {
1661     pub generics: Generics,
1662     pub trait_: Option<Type>,
1663     pub for_: Type,
1664     pub methods: Vec<Item>,
1665     pub derived: bool,
1666 }
1667
1668 fn detect_derived<M: AttrMetaMethods>(attrs: &[M]) -> bool {
1669     attr::contains_name(attrs, "automatically_derived")
1670 }
1671
1672 impl Clean<Item> for doctree::Impl {
1673     fn clean(&self) -> Item {
1674         Item {
1675             name: None,
1676             attrs: self.attrs.clean(),
1677             source: self.where.clean(),
1678             def_id: ast_util::local_def(self.id),
1679             visibility: self.vis.clean(),
1680             inner: ImplItem(Impl {
1681                 generics: self.generics.clean(),
1682                 trait_: self.trait_.clean(),
1683                 for_: self.for_.clean(),
1684                 methods: self.methods.clean(),
1685                 derived: detect_derived(self.attrs.as_slice()),
1686             }),
1687         }
1688     }
1689 }
1690
1691 #[deriving(Clone, Encodable, Decodable)]
1692 pub struct ViewItem {
1693     pub inner: ViewItemInner,
1694 }
1695
1696 impl Clean<Vec<Item>> for ast::ViewItem {
1697     fn clean(&self) -> Vec<Item> {
1698         // We consider inlining the documentation of `pub use` statments, but we
1699         // forcefully don't inline if this is not public or if the
1700         // #[doc(no_inline)] attribute is present.
1701         let denied = self.vis != ast::Public || self.attrs.iter().any(|a| {
1702             a.name().get() == "doc" && match a.meta_item_list() {
1703                 Some(l) => attr::contains_name(l, "no_inline"),
1704                 None => false,
1705             }
1706         });
1707         let convert = |node: &ast::ViewItem_| {
1708             Item {
1709                 name: None,
1710                 attrs: self.attrs.clean().move_iter().collect(),
1711                 source: self.span.clean(),
1712                 def_id: ast_util::local_def(0),
1713                 visibility: self.vis.clean(),
1714                 inner: ViewItemItem(ViewItem { inner: node.clean() }),
1715             }
1716         };
1717         let mut ret = Vec::new();
1718         match self.node {
1719             ast::ViewItemUse(ref path) if !denied => {
1720                 match path.node {
1721                     ast::ViewPathGlob(..) => ret.push(convert(&self.node)),
1722                     ast::ViewPathList(ref a, ref list, ref b) => {
1723                         // Attempt to inline all reexported items, but be sure
1724                         // to keep any non-inlineable reexports so they can be
1725                         // listed in the documentation.
1726                         let remaining = list.iter().filter(|path| {
1727                             match inline::try_inline(path.node.id) {
1728                                 Some(items) => {
1729                                     ret.extend(items.move_iter()); false
1730                                 }
1731                                 None => true,
1732                             }
1733                         }).map(|a| a.clone()).collect::<Vec<ast::PathListIdent>>();
1734                         if remaining.len() > 0 {
1735                             let path = ast::ViewPathList(a.clone(),
1736                                                          remaining,
1737                                                          b.clone());
1738                             let path = syntax::codemap::dummy_spanned(path);
1739                             ret.push(convert(&ast::ViewItemUse(@path)));
1740                         }
1741                     }
1742                     ast::ViewPathSimple(_, _, id) => {
1743                         match inline::try_inline(id) {
1744                             Some(items) => ret.extend(items.move_iter()),
1745                             None => ret.push(convert(&self.node)),
1746                         }
1747                     }
1748                 }
1749             }
1750             ref n => ret.push(convert(n)),
1751         }
1752         return ret;
1753     }
1754 }
1755
1756 #[deriving(Clone, Encodable, Decodable)]
1757 pub enum ViewItemInner {
1758     ExternCrate(String, Option<String>, ast::NodeId),
1759     Import(ViewPath)
1760 }
1761
1762 impl Clean<ViewItemInner> for ast::ViewItem_ {
1763     fn clean(&self) -> ViewItemInner {
1764         match self {
1765             &ast::ViewItemExternCrate(ref i, ref p, ref id) => {
1766                 let string = match *p {
1767                     None => None,
1768                     Some((ref x, _)) => Some(x.get().to_string()),
1769                 };
1770                 ExternCrate(i.clean(), string, *id)
1771             }
1772             &ast::ViewItemUse(ref vp) => {
1773                 Import(vp.clean())
1774             }
1775         }
1776     }
1777 }
1778
1779 #[deriving(Clone, Encodable, Decodable)]
1780 pub enum ViewPath {
1781     // use str = source;
1782     SimpleImport(String, ImportSource),
1783     // use source::*;
1784     GlobImport(ImportSource),
1785     // use source::{a, b, c};
1786     ImportList(ImportSource, Vec<ViewListIdent>),
1787 }
1788
1789 #[deriving(Clone, Encodable, Decodable)]
1790 pub struct ImportSource {
1791     pub path: Path,
1792     pub did: Option<ast::DefId>,
1793 }
1794
1795 impl Clean<ViewPath> for ast::ViewPath {
1796     fn clean(&self) -> ViewPath {
1797         match self.node {
1798             ast::ViewPathSimple(ref i, ref p, id) =>
1799                 SimpleImport(i.clean(), resolve_use_source(p.clean(), id)),
1800             ast::ViewPathGlob(ref p, id) =>
1801                 GlobImport(resolve_use_source(p.clean(), id)),
1802             ast::ViewPathList(ref p, ref pl, id) => {
1803                 ImportList(resolve_use_source(p.clean(), id),
1804                            pl.clean().move_iter().collect())
1805             }
1806         }
1807     }
1808 }
1809
1810 #[deriving(Clone, Encodable, Decodable)]
1811 pub struct ViewListIdent {
1812     pub name: String,
1813     pub source: Option<ast::DefId>,
1814 }
1815
1816 impl Clean<ViewListIdent> for ast::PathListIdent {
1817     fn clean(&self) -> ViewListIdent {
1818         ViewListIdent {
1819             name: self.node.name.clean(),
1820             source: resolve_def(self.node.id),
1821         }
1822     }
1823 }
1824
1825 impl Clean<Vec<Item>> for ast::ForeignMod {
1826     fn clean(&self) -> Vec<Item> {
1827         self.items.clean()
1828     }
1829 }
1830
1831 impl Clean<Item> for ast::ForeignItem {
1832     fn clean(&self) -> Item {
1833         let inner = match self.node {
1834             ast::ForeignItemFn(ref decl, ref generics) => {
1835                 ForeignFunctionItem(Function {
1836                     decl: decl.clean(),
1837                     generics: generics.clean(),
1838                     fn_style: ast::UnsafeFn,
1839                 })
1840             }
1841             ast::ForeignItemStatic(ref ty, mutbl) => {
1842                 ForeignStaticItem(Static {
1843                     type_: ty.clean(),
1844                     mutability: if mutbl {Mutable} else {Immutable},
1845                     expr: "".to_string(),
1846                 })
1847             }
1848         };
1849         Item {
1850             name: Some(self.ident.clean()),
1851             attrs: self.attrs.clean().move_iter().collect(),
1852             source: self.span.clean(),
1853             def_id: ast_util::local_def(self.id),
1854             visibility: self.vis.clean(),
1855             inner: inner,
1856         }
1857     }
1858 }
1859
1860 // Utilities
1861
1862 trait ToSource {
1863     fn to_src(&self) -> String;
1864 }
1865
1866 impl ToSource for syntax::codemap::Span {
1867     fn to_src(&self) -> String {
1868         debug!("converting span {:?} to snippet", self.clean());
1869         let ctxt = super::ctxtkey.get().unwrap();
1870         let cm = ctxt.sess().codemap().clone();
1871         let sn = match cm.span_to_snippet(*self) {
1872             Some(x) => x.to_string(),
1873             None    => "".to_string()
1874         };
1875         debug!("got snippet {}", sn);
1876         sn
1877     }
1878 }
1879
1880 fn lit_to_str(lit: &ast::Lit) -> String {
1881     match lit.node {
1882         ast::LitStr(ref st, _) => st.get().to_string(),
1883         ast::LitBinary(ref data) => format!("{:?}", data.as_slice()),
1884         ast::LitChar(c) => format!("'{}'", c),
1885         ast::LitInt(i, _t) => i.to_str().to_string(),
1886         ast::LitUint(u, _t) => u.to_str().to_string(),
1887         ast::LitIntUnsuffixed(i) => i.to_str().to_string(),
1888         ast::LitFloat(ref f, _t) => f.get().to_string(),
1889         ast::LitFloatUnsuffixed(ref f) => f.get().to_string(),
1890         ast::LitBool(b) => b.to_str().to_string(),
1891         ast::LitNil => "".to_string(),
1892     }
1893 }
1894
1895 fn name_from_pat(p: &ast::Pat) -> String {
1896     use syntax::ast::*;
1897     debug!("Trying to get a name from pattern: {:?}", p);
1898
1899     match p.node {
1900         PatWild => "_".to_string(),
1901         PatWildMulti => "..".to_string(),
1902         PatIdent(_, ref p, _) => path_to_str(p),
1903         PatEnum(ref p, _) => path_to_str(p),
1904         PatStruct(..) => fail!("tried to get argument name from pat_struct, \
1905                                 which is not allowed in function arguments"),
1906         PatTup(..) => "(tuple arg NYI)".to_string(),
1907         PatBox(p) => name_from_pat(p),
1908         PatRegion(p) => name_from_pat(p),
1909         PatLit(..) => {
1910             warn!("tried to get argument name from PatLit, \
1911                   which is silly in function arguments");
1912             "()".to_string()
1913         },
1914         PatRange(..) => fail!("tried to get argument name from PatRange, \
1915                               which is not allowed in function arguments"),
1916         PatVec(..) => fail!("tried to get argument name from pat_vec, \
1917                              which is not allowed in function arguments"),
1918         PatMac(..) => {
1919             warn!("can't document the name of a function argument \
1920                    produced by a pattern macro");
1921             "(argument produced by macro)".to_string()
1922         }
1923     }
1924 }
1925
1926 /// Given a Type, resolve it using the def_map
1927 fn resolve_type(path: Path, tpbs: Option<Vec<TyParamBound>>,
1928                 id: ast::NodeId) -> Type {
1929     let cx = super::ctxtkey.get().unwrap();
1930     let tycx = match cx.maybe_typed {
1931         core::Typed(ref tycx) => tycx,
1932         // If we're extracting tests, this return value doesn't matter.
1933         core::NotTyped(_) => return Primitive(Bool),
1934     };
1935     debug!("searching for {:?} in defmap", id);
1936     let def = match tycx.def_map.borrow().find(&id) {
1937         Some(&k) => k,
1938         None => fail!("unresolved id not in defmap")
1939     };
1940
1941     match def {
1942         ast::DefSelfTy(i) => return Self(ast_util::local_def(i)),
1943         ast::DefPrimTy(p) => match p {
1944             ast::TyStr => return Primitive(Str),
1945             ast::TyBool => return Primitive(Bool),
1946             ast::TyChar => return Primitive(Char),
1947             ast::TyInt(ast::TyI) => return Primitive(Int),
1948             ast::TyInt(ast::TyI8) => return Primitive(I8),
1949             ast::TyInt(ast::TyI16) => return Primitive(I16),
1950             ast::TyInt(ast::TyI32) => return Primitive(I32),
1951             ast::TyInt(ast::TyI64) => return Primitive(I64),
1952             ast::TyUint(ast::TyU) => return Primitive(Uint),
1953             ast::TyUint(ast::TyU8) => return Primitive(U8),
1954             ast::TyUint(ast::TyU16) => return Primitive(U16),
1955             ast::TyUint(ast::TyU32) => return Primitive(U32),
1956             ast::TyUint(ast::TyU64) => return Primitive(U64),
1957             ast::TyFloat(ast::TyF32) => return Primitive(F32),
1958             ast::TyFloat(ast::TyF64) => return Primitive(F64),
1959             ast::TyFloat(ast::TyF128) => return Primitive(F128),
1960         },
1961         ast::DefTyParam(i, _) => return Generic(i),
1962         ast::DefTyParamBinder(i) => return TyParamBinder(i),
1963         _ => {}
1964     };
1965     let did = register_def(&**cx, def);
1966     ResolvedPath { path: path, typarams: tpbs, did: did }
1967 }
1968
1969 fn register_def(cx: &core::DocContext, def: ast::Def) -> ast::DefId {
1970     let (did, kind) = match def {
1971         ast::DefFn(i, _) => (i, TypeFunction),
1972         ast::DefTy(i) => (i, TypeEnum),
1973         ast::DefTrait(i) => (i, TypeTrait),
1974         ast::DefStruct(i) => (i, TypeStruct),
1975         ast::DefMod(i) => (i, TypeModule),
1976         ast::DefStatic(i, _) => (i, TypeStatic),
1977         ast::DefVariant(i, _, _) => (i, TypeEnum),
1978         _ => return ast_util::def_id_of_def(def),
1979     };
1980     if ast_util::is_local(did) { return did }
1981     let tcx = match cx.maybe_typed {
1982         core::Typed(ref t) => t,
1983         core::NotTyped(_) => return did
1984     };
1985     inline::record_extern_fqn(cx, did, kind);
1986     match kind {
1987         TypeTrait => {
1988             let t = inline::build_external_trait(tcx, did);
1989             cx.external_traits.borrow_mut().get_mut_ref().insert(did, t);
1990         }
1991         _ => {}
1992     }
1993     return did;
1994 }
1995
1996 fn resolve_use_source(path: Path, id: ast::NodeId) -> ImportSource {
1997     ImportSource {
1998         path: path,
1999         did: resolve_def(id),
2000     }
2001 }
2002
2003 fn resolve_def(id: ast::NodeId) -> Option<ast::DefId> {
2004     let cx = super::ctxtkey.get().unwrap();
2005     match cx.maybe_typed {
2006         core::Typed(ref tcx) => {
2007             tcx.def_map.borrow().find(&id).map(|&def| register_def(&**cx, def))
2008         }
2009         core::NotTyped(_) => None
2010     }
2011 }
2012
2013 #[deriving(Clone, Encodable, Decodable)]
2014 pub struct Macro {
2015     pub source: String,
2016 }
2017
2018 impl Clean<Item> for doctree::Macro {
2019     fn clean(&self) -> Item {
2020         Item {
2021             name: Some(format!("{}!", self.name.clean())),
2022             attrs: self.attrs.clean(),
2023             source: self.where.clean(),
2024             visibility: ast::Public.clean(),
2025             def_id: ast_util::local_def(self.id),
2026             inner: MacroItem(Macro {
2027                 source: self.where.to_src(),
2028             }),
2029         }
2030     }
2031 }