]> git.lizzy.rs Git - rust.git/blob - src/librustdoc/clean.rs
53bae09f58c94e4d893394c552b11788c49c3d10
[rust.git] / src / librustdoc / clean.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_map;
17 use syntax::ast_util;
18 use syntax::attr;
19 use syntax::attr::AttributeMethods;
20 use syntax::codemap::Pos;
21 use syntax::parse::token::InternedString;
22 use syntax::parse::token;
23
24 use rustc::metadata::cstore;
25 use rustc::metadata::csearch;
26 use rustc::metadata::decoder;
27
28 use std;
29 use std::hashmap::HashMap;
30
31 use doctree;
32 use visit_ast;
33 use std::local_data;
34
35 pub trait Clean<T> {
36     fn clean(&self) -> T;
37 }
38
39 impl<T: Clean<U>, U> Clean<~[U]> for ~[T] {
40     fn clean(&self) -> ~[U] {
41         self.iter().map(|x| x.clean()).collect()
42     }
43 }
44 impl<T: Clean<U>, U> Clean<U> for @T {
45     fn clean(&self) -> U {
46         (**self).clean()
47     }
48 }
49
50 impl<T: Clean<U>, U> Clean<Option<U>> for Option<T> {
51     fn clean(&self) -> Option<U> {
52         match self {
53             &None => None,
54             &Some(ref v) => Some(v.clean())
55         }
56     }
57 }
58
59 impl<T: Clean<U>, U> Clean<~[U]> for syntax::opt_vec::OptVec<T> {
60     fn clean(&self) -> ~[U] {
61         match self {
62             &syntax::opt_vec::Empty => ~[],
63             &syntax::opt_vec::Vec(ref v) => v.clean()
64         }
65     }
66 }
67
68 #[deriving(Clone, Encodable, Decodable)]
69 pub struct Crate {
70     name: ~str,
71     module: Option<Item>,
72     externs: HashMap<ast::CrateNum, ExternalCrate>,
73 }
74
75 impl<'a> Clean<Crate> for visit_ast::RustdocVisitor<'a> {
76     fn clean(&self) -> Crate {
77         use syntax::attr::find_crateid;
78         let cx = local_data::get(super::ctxtkey, |x| *x.unwrap());
79
80         let mut externs = HashMap::new();
81         cx.sess.cstore.iter_crate_data(|n, meta| {
82             externs.insert(n, meta.clean());
83         });
84
85         Crate {
86             name: match find_crateid(self.attrs) {
87                 Some(n) => n.name,
88                 None => fail!("rustdoc requires a `crate_id` crate attribute"),
89             },
90             module: Some(self.module.clean()),
91             externs: externs,
92         }
93     }
94 }
95
96 #[deriving(Clone, Encodable, Decodable)]
97 pub struct ExternalCrate {
98     name: ~str,
99     attrs: ~[Attribute],
100 }
101
102 impl Clean<ExternalCrate> for cstore::crate_metadata {
103     fn clean(&self) -> ExternalCrate {
104         ExternalCrate {
105             name: self.name.to_owned(),
106             attrs: decoder::get_crate_attributes(self.data()).clean()
107         }
108     }
109 }
110
111 /// Anything with a source location and set of attributes and, optionally, a
112 /// name. That is, anything that can be documented. This doesn't correspond
113 /// directly to the AST's concept of an item; it's a strict superset.
114 #[deriving(Clone, Encodable, Decodable)]
115 pub struct Item {
116     /// Stringified span
117     source: Span,
118     /// Not everything has a name. E.g., impls
119     name: Option<~str>,
120     attrs: ~[Attribute],
121     inner: ItemEnum,
122     visibility: Option<Visibility>,
123     id: ast::NodeId,
124 }
125
126 impl Item {
127     /// Finds the `doc` attribute as a List and returns the list of attributes
128     /// nested inside.
129     pub fn doc_list<'a>(&'a self) -> Option<&'a [Attribute]> {
130         for attr in self.attrs.iter() {
131             match *attr {
132                 List(~"doc", ref list) => { return Some(list.as_slice()); }
133                 _ => {}
134             }
135         }
136         return None;
137     }
138
139     /// Finds the `doc` attribute as a NameValue and returns the corresponding
140     /// value found.
141     pub fn doc_value<'a>(&'a self) -> Option<&'a str> {
142         for attr in self.attrs.iter() {
143             match *attr {
144                 NameValue(~"doc", ref v) => { return Some(v.as_slice()); }
145                 _ => {}
146             }
147         }
148         return None;
149     }
150
151     pub fn is_mod(&self) -> bool {
152         match self.inner { ModuleItem(..) => true, _ => false }
153     }
154     pub fn is_trait(&self) -> bool {
155         match self.inner { TraitItem(..) => true, _ => false }
156     }
157     pub fn is_struct(&self) -> bool {
158         match self.inner { StructItem(..) => true, _ => false }
159     }
160     pub fn is_enum(&self) -> bool {
161         match self.inner { EnumItem(..) => true, _ => false }
162     }
163     pub fn is_fn(&self) -> bool {
164         match self.inner { FunctionItem(..) => true, _ => false }
165     }
166 }
167
168 #[deriving(Clone, Encodable, Decodable)]
169 pub enum ItemEnum {
170     StructItem(Struct),
171     EnumItem(Enum),
172     FunctionItem(Function),
173     ModuleItem(Module),
174     TypedefItem(Typedef),
175     StaticItem(Static),
176     TraitItem(Trait),
177     ImplItem(Impl),
178     ViewItemItem(ViewItem),
179     TyMethodItem(TyMethod),
180     MethodItem(Method),
181     StructFieldItem(StructField),
182     VariantItem(Variant),
183     ForeignFunctionItem(Function),
184     ForeignStaticItem(Static),
185 }
186
187 #[deriving(Clone, Encodable, Decodable)]
188 pub struct Module {
189     items: ~[Item],
190 }
191
192 impl Clean<Item> for doctree::Module {
193     fn clean(&self) -> Item {
194         let name = if self.name.is_some() {
195             self.name.unwrap().clean()
196         } else {
197             ~""
198         };
199         Item {
200             name: Some(name),
201             attrs: self.attrs.clean(),
202             source: self.where.clean(),
203             visibility: self.vis.clean(),
204             id: self.id,
205             inner: ModuleItem(Module {
206                items: [self.structs.clean(), self.enums.clean(),
207                        self.fns.clean(), self.foreigns.clean().concat_vec(),
208                        self.mods.clean(), self.typedefs.clean(),
209                        self.statics.clean(), self.traits.clean(),
210                        self.impls.clean(), self.view_items.clean()].concat_vec()
211             })
212         }
213     }
214 }
215
216 #[deriving(Clone, Encodable, Decodable)]
217 pub enum Attribute {
218     Word(~str),
219     List(~str, ~[Attribute]),
220     NameValue(~str, ~str)
221 }
222
223 impl Clean<Attribute> for ast::MetaItem {
224     fn clean(&self) -> Attribute {
225         match self.node {
226             ast::MetaWord(ref s) => Word(s.get().to_owned()),
227             ast::MetaList(ref s, ref l) => {
228                 List(s.get().to_owned(), l.clean())
229             }
230             ast::MetaNameValue(ref s, ref v) => {
231                 NameValue(s.get().to_owned(), lit_to_str(v))
232             }
233         }
234     }
235 }
236
237 impl Clean<Attribute> for ast::Attribute {
238     fn clean(&self) -> Attribute {
239         self.desugar_doc().node.value.clean()
240     }
241 }
242
243 // This is a rough approximation that gets us what we want.
244 impl<'a> attr::AttrMetaMethods for &'a Attribute {
245     fn name(&self) -> InternedString {
246         match **self {
247             Word(ref n) | List(ref n, _) | NameValue(ref n, _) => {
248                 token::intern_and_get_ident(*n)
249             }
250         }
251     }
252
253     fn value_str(&self) -> Option<InternedString> {
254         match **self {
255             NameValue(_, ref v) => Some(token::intern_and_get_ident(*v)),
256             _ => None,
257         }
258     }
259     fn meta_item_list<'a>(&'a self) -> Option<&'a [@ast::MetaItem]> { None }
260     fn name_str_pair(&self) -> Option<(InternedString, InternedString)> {
261         None
262     }
263 }
264
265 #[deriving(Clone, Encodable, Decodable)]
266 pub struct TyParam {
267     name: ~str,
268     id: ast::NodeId,
269     bounds: ~[TyParamBound]
270 }
271
272 impl Clean<TyParam> for ast::TyParam {
273     fn clean(&self) -> TyParam {
274         TyParam {
275             name: self.ident.clean(),
276             id: self.id,
277             bounds: self.bounds.clean(),
278         }
279     }
280 }
281
282 #[deriving(Clone, Encodable, Decodable)]
283 pub enum TyParamBound {
284     RegionBound,
285     TraitBound(Type)
286 }
287
288 impl Clean<TyParamBound> for ast::TyParamBound {
289     fn clean(&self) -> TyParamBound {
290         match *self {
291             ast::RegionTyParamBound => RegionBound,
292             ast::TraitTyParamBound(ref t) => TraitBound(t.clean()),
293         }
294     }
295 }
296
297 #[deriving(Clone, Encodable, Decodable)]
298 pub struct Lifetime(~str);
299
300 impl Lifetime {
301     pub fn get_ref<'a>(&'a self) -> &'a str {
302         let Lifetime(ref s) = *self;
303         let s: &'a str = *s;
304         return s;
305     }
306 }
307
308 impl Clean<Lifetime> for ast::Lifetime {
309     fn clean(&self) -> Lifetime {
310         Lifetime(self.ident.clean())
311     }
312 }
313
314 // maybe use a Generic enum and use ~[Generic]?
315 #[deriving(Clone, Encodable, Decodable)]
316 pub struct Generics {
317     lifetimes: ~[Lifetime],
318     type_params: ~[TyParam]
319 }
320
321 impl Clean<Generics> for ast::Generics {
322     fn clean(&self) -> Generics {
323         Generics {
324             lifetimes: self.lifetimes.clean(),
325             type_params: self.ty_params.clean(),
326         }
327     }
328 }
329
330 #[deriving(Clone, Encodable, Decodable)]
331 pub struct Method {
332     generics: Generics,
333     self_: SelfTy,
334     purity: ast::Purity,
335     decl: FnDecl,
336 }
337
338 impl Clean<Item> for ast::Method {
339     fn clean(&self) -> Item {
340         let inputs = match self.explicit_self.node {
341             ast::SelfStatic => self.decl.inputs.as_slice(),
342             _ => self.decl.inputs.slice_from(1)
343         };
344         let decl = FnDecl {
345             inputs: inputs.iter().map(|x| x.clean()).collect(),
346             output: (self.decl.output.clean()),
347             cf: self.decl.cf.clean(),
348             attrs: ~[]
349         };
350         Item {
351             name: Some(self.ident.clean()),
352             attrs: self.attrs.clean(),
353             source: self.span.clean(),
354             id: self.id.clone(),
355             visibility: self.vis.clean(),
356             inner: MethodItem(Method {
357                 generics: self.generics.clean(),
358                 self_: self.explicit_self.clean(),
359                 purity: self.purity.clone(),
360                 decl: decl,
361             }),
362         }
363     }
364 }
365
366 #[deriving(Clone, Encodable, Decodable)]
367 pub struct TyMethod {
368     purity: ast::Purity,
369     decl: FnDecl,
370     generics: Generics,
371     self_: SelfTy,
372 }
373
374 impl Clean<Item> for ast::TypeMethod {
375     fn clean(&self) -> Item {
376         let inputs = match self.explicit_self.node {
377             ast::SelfStatic => self.decl.inputs.as_slice(),
378             _ => self.decl.inputs.slice_from(1)
379         };
380         let decl = FnDecl {
381             inputs: inputs.iter().map(|x| x.clean()).collect(),
382             output: (self.decl.output.clean()),
383             cf: self.decl.cf.clean(),
384             attrs: ~[]
385         };
386         Item {
387             name: Some(self.ident.clean()),
388             attrs: self.attrs.clean(),
389             source: self.span.clean(),
390             id: self.id,
391             visibility: None,
392             inner: TyMethodItem(TyMethod {
393                 purity: self.purity.clone(),
394                 decl: decl,
395                 self_: self.explicit_self.clean(),
396                 generics: self.generics.clean(),
397             }),
398         }
399     }
400 }
401
402 #[deriving(Clone, Encodable, Decodable)]
403 pub enum SelfTy {
404     SelfStatic,
405     SelfValue,
406     SelfBorrowed(Option<Lifetime>, Mutability),
407     SelfManaged,
408     SelfOwned,
409 }
410
411 impl Clean<SelfTy> for ast::ExplicitSelf {
412     fn clean(&self) -> SelfTy {
413         match self.node {
414             ast::SelfStatic => SelfStatic,
415             ast::SelfValue => SelfValue,
416             ast::SelfUniq => SelfOwned,
417             ast::SelfRegion(lt, mt) => SelfBorrowed(lt.clean(), mt.clean()),
418             ast::SelfBox => SelfManaged,
419         }
420     }
421 }
422
423 #[deriving(Clone, Encodable, Decodable)]
424 pub struct Function {
425     decl: FnDecl,
426     generics: Generics,
427     purity: ast::Purity,
428 }
429
430 impl Clean<Item> for doctree::Function {
431     fn clean(&self) -> Item {
432         Item {
433             name: Some(self.name.clean()),
434             attrs: self.attrs.clean(),
435             source: self.where.clean(),
436             visibility: self.vis.clean(),
437             id: self.id,
438             inner: FunctionItem(Function {
439                 decl: self.decl.clean(),
440                 generics: self.generics.clean(),
441                 purity: self.purity,
442             }),
443         }
444     }
445 }
446
447 #[deriving(Clone, Encodable, Decodable)]
448 pub struct ClosureDecl {
449     sigil: ast::Sigil,
450     region: Option<Lifetime>,
451     lifetimes: ~[Lifetime],
452     decl: FnDecl,
453     onceness: ast::Onceness,
454     purity: ast::Purity,
455     bounds: ~[TyParamBound]
456 }
457
458 impl Clean<ClosureDecl> for ast::ClosureTy {
459     fn clean(&self) -> ClosureDecl {
460         ClosureDecl {
461             sigil: self.sigil,
462             region: self.region.clean(),
463             lifetimes: self.lifetimes.clean(),
464             decl: self.decl.clean(),
465             onceness: self.onceness,
466             purity: self.purity,
467             bounds: match self.bounds {
468                 Some(ref x) => x.clean(),
469                 None        => ~[]
470             },
471         }
472     }
473 }
474
475 #[deriving(Clone, Encodable, Decodable)]
476 pub struct FnDecl {
477     inputs: ~[Argument],
478     output: Type,
479     cf: RetStyle,
480     attrs: ~[Attribute]
481 }
482
483 impl Clean<FnDecl> for ast::FnDecl {
484     fn clean(&self) -> FnDecl {
485         FnDecl {
486             inputs: self.inputs.iter().map(|x| x.clean()).collect(),
487             output: (self.output.clean()),
488             cf: self.cf.clean(),
489             attrs: ~[]
490         }
491     }
492 }
493
494 #[deriving(Clone, Encodable, Decodable)]
495 pub struct Argument {
496     type_: Type,
497     name: ~str,
498     id: ast::NodeId
499 }
500
501 impl Clean<Argument> for ast::Arg {
502     fn clean(&self) -> Argument {
503         Argument {
504             name: name_from_pat(self.pat),
505             type_: (self.ty.clean()),
506             id: self.id
507         }
508     }
509 }
510
511 #[deriving(Clone, Encodable, Decodable)]
512 pub enum RetStyle {
513     NoReturn,
514     Return
515 }
516
517 impl Clean<RetStyle> for ast::RetStyle {
518     fn clean(&self) -> RetStyle {
519         match *self {
520             ast::Return => Return,
521             ast::NoReturn => NoReturn
522         }
523     }
524 }
525
526 #[deriving(Clone, Encodable, Decodable)]
527 pub struct Trait {
528     methods: ~[TraitMethod],
529     generics: Generics,
530     parents: ~[Type],
531 }
532
533 impl Clean<Item> for doctree::Trait {
534     fn clean(&self) -> Item {
535         Item {
536             name: Some(self.name.clean()),
537             attrs: self.attrs.clean(),
538             source: self.where.clean(),
539             id: self.id,
540             visibility: self.vis.clean(),
541             inner: TraitItem(Trait {
542                 methods: self.methods.clean(),
543                 generics: self.generics.clean(),
544                 parents: self.parents.clean(),
545             }),
546         }
547     }
548 }
549
550 impl Clean<Type> for ast::TraitRef {
551     fn clean(&self) -> Type {
552         resolve_type(self.path.clean(), None, self.ref_id)
553     }
554 }
555
556 #[deriving(Clone, Encodable, Decodable)]
557 pub enum TraitMethod {
558     Required(Item),
559     Provided(Item),
560 }
561
562 impl TraitMethod {
563     pub fn is_req(&self) -> bool {
564         match self {
565             &Required(..) => true,
566             _ => false,
567         }
568     }
569     pub fn is_def(&self) -> bool {
570         match self {
571             &Provided(..) => true,
572             _ => false,
573         }
574     }
575     pub fn item<'a>(&'a self) -> &'a Item {
576         match *self {
577             Required(ref item) => item,
578             Provided(ref item) => item,
579         }
580     }
581 }
582
583 impl Clean<TraitMethod> for ast::TraitMethod {
584     fn clean(&self) -> TraitMethod {
585         match self {
586             &ast::Required(ref t) => Required(t.clean()),
587             &ast::Provided(ref t) => Provided(t.clean()),
588         }
589     }
590 }
591
592 /// A representation of a Type suitable for hyperlinking purposes. Ideally one can get the original
593 /// type out of the AST/ty::ctxt given one of these, if more information is needed. Most importantly
594 /// it does not preserve mutability or boxes.
595 #[deriving(Clone, Encodable, Decodable)]
596 pub enum Type {
597     /// structs/enums/traits (anything that'd be an ast::TyPath)
598     ResolvedPath {
599         path: Path,
600         typarams: Option<~[TyParamBound]>,
601         id: ast::NodeId,
602     },
603     /// Same as above, but only external variants
604     ExternalPath {
605         path: Path,
606         typarams: Option<~[TyParamBound]>,
607         fqn: ~[~str],
608         kind: TypeKind,
609         crate: ast::CrateNum,
610     },
611     // I have no idea how to usefully use this.
612     TyParamBinder(ast::NodeId),
613     /// For parameterized types, so the consumer of the JSON don't go looking
614     /// for types which don't exist anywhere.
615     Generic(ast::NodeId),
616     /// For references to self
617     Self(ast::NodeId),
618     /// Primitives are just the fixed-size numeric types (plus int/uint/float), and char.
619     Primitive(ast::PrimTy),
620     Closure(~ClosureDecl),
621     /// extern "ABI" fn
622     BareFunction(~BareFunctionDecl),
623     Tuple(~[Type]),
624     Vector(~Type),
625     FixedVector(~Type, ~str),
626     String,
627     Bool,
628     /// aka TyNil
629     Unit,
630     /// aka TyBot
631     Bottom,
632     Unique(~Type),
633     Managed(~Type),
634     RawPointer(Mutability, ~Type),
635     BorrowedRef { lifetime: Option<Lifetime>, mutability: Mutability, type_: ~Type},
636     // region, raw, other boxes, mutable
637 }
638
639 #[deriving(Clone, Encodable, Decodable)]
640 pub enum TypeKind {
641     TypeStruct,
642     TypeEnum,
643     TypeTrait,
644     TypeFunction,
645 }
646
647 impl Clean<Type> for ast::Ty {
648     fn clean(&self) -> Type {
649         use syntax::ast::*;
650         debug!("cleaning type `{:?}`", self);
651         let codemap = local_data::get(super::ctxtkey, |x| *x.unwrap()).sess.codemap;
652         debug!("span corresponds to `{}`", codemap.span_to_str(self.span));
653         match self.node {
654             TyNil => Unit,
655             TyPtr(ref m) => RawPointer(m.mutbl.clean(), ~m.ty.clean()),
656             TyRptr(ref l, ref m) =>
657                 BorrowedRef {lifetime: l.clean(), mutability: m.mutbl.clean(),
658                              type_: ~m.ty.clean()},
659             TyBox(ty) => Managed(~ty.clean()),
660             TyUniq(ty) => Unique(~ty.clean()),
661             TyVec(ty) => Vector(~ty.clean()),
662             TyFixedLengthVec(ty, ref e) => FixedVector(~ty.clean(),
663                                                        e.span.to_src()),
664             TyTup(ref tys) => Tuple(tys.iter().map(|x| x.clean()).collect()),
665             TyPath(ref p, ref tpbs, id) =>
666                 resolve_type(p.clean(), tpbs.clean(), id),
667             TyClosure(ref c) => Closure(~c.clean()),
668             TyBareFn(ref barefn) => BareFunction(~barefn.clean()),
669             TyBot => Bottom,
670             ref x => fail!("Unimplemented type {:?}", x),
671         }
672     }
673 }
674
675 #[deriving(Clone, Encodable, Decodable)]
676 pub struct StructField {
677     type_: Type,
678 }
679
680 impl Clean<Item> for ast::StructField {
681     fn clean(&self) -> Item {
682         let (name, vis) = match self.node.kind {
683             ast::NamedField(id, vis) => (Some(id), Some(vis)),
684             _ => (None, None)
685         };
686         Item {
687             name: name.clean(),
688             attrs: self.node.attrs.clean(),
689             source: self.span.clean(),
690             visibility: vis,
691             id: self.node.id,
692             inner: StructFieldItem(StructField {
693                 type_: self.node.ty.clean(),
694             }),
695         }
696     }
697 }
698
699 pub type Visibility = ast::Visibility;
700
701 impl Clean<Option<Visibility>> for ast::Visibility {
702     fn clean(&self) -> Option<Visibility> {
703         Some(*self)
704     }
705 }
706
707 #[deriving(Clone, Encodable, Decodable)]
708 pub struct Struct {
709     struct_type: doctree::StructType,
710     generics: Generics,
711     fields: ~[Item],
712     fields_stripped: bool,
713 }
714
715 impl Clean<Item> for doctree::Struct {
716     fn clean(&self) -> Item {
717         Item {
718             name: Some(self.name.clean()),
719             attrs: self.attrs.clean(),
720             source: self.where.clean(),
721             id: self.id,
722             visibility: self.vis.clean(),
723             inner: StructItem(Struct {
724                 struct_type: self.struct_type,
725                 generics: self.generics.clean(),
726                 fields: self.fields.clean(),
727                 fields_stripped: false,
728             }),
729         }
730     }
731 }
732
733 /// This is a more limited form of the standard Struct, different in that it
734 /// it lacks the things most items have (name, id, parameterization). Found
735 /// only as a variant in an enum.
736 #[deriving(Clone, Encodable, Decodable)]
737 pub struct VariantStruct {
738     struct_type: doctree::StructType,
739     fields: ~[Item],
740     fields_stripped: bool,
741 }
742
743 impl Clean<VariantStruct> for syntax::ast::StructDef {
744     fn clean(&self) -> VariantStruct {
745         VariantStruct {
746             struct_type: doctree::struct_type_from_def(self),
747             fields: self.fields.clean(),
748             fields_stripped: false,
749         }
750     }
751 }
752
753 #[deriving(Clone, Encodable, Decodable)]
754 pub struct Enum {
755     variants: ~[Item],
756     generics: Generics,
757     variants_stripped: bool,
758 }
759
760 impl Clean<Item> for doctree::Enum {
761     fn clean(&self) -> Item {
762         Item {
763             name: Some(self.name.clean()),
764             attrs: self.attrs.clean(),
765             source: self.where.clean(),
766             id: self.id,
767             visibility: self.vis.clean(),
768             inner: EnumItem(Enum {
769                 variants: self.variants.clean(),
770                 generics: self.generics.clean(),
771                 variants_stripped: false,
772             }),
773         }
774     }
775 }
776
777 #[deriving(Clone, Encodable, Decodable)]
778 pub struct Variant {
779     kind: VariantKind,
780 }
781
782 impl Clean<Item> for doctree::Variant {
783     fn clean(&self) -> Item {
784         Item {
785             name: Some(self.name.clean()),
786             attrs: self.attrs.clean(),
787             source: self.where.clean(),
788             visibility: self.vis.clean(),
789             id: self.id,
790             inner: VariantItem(Variant {
791                 kind: self.kind.clean(),
792             }),
793         }
794     }
795 }
796
797 #[deriving(Clone, Encodable, Decodable)]
798 pub enum VariantKind {
799     CLikeVariant,
800     TupleVariant(~[Type]),
801     StructVariant(VariantStruct),
802 }
803
804 impl Clean<VariantKind> for ast::VariantKind {
805     fn clean(&self) -> VariantKind {
806         match self {
807             &ast::TupleVariantKind(ref args) => {
808                 if args.len() == 0 {
809                     CLikeVariant
810                 } else {
811                     TupleVariant(args.iter().map(|x| x.ty.clean()).collect())
812                 }
813             },
814             &ast::StructVariantKind(ref sd) => StructVariant(sd.clean()),
815         }
816     }
817 }
818
819 #[deriving(Clone, Encodable, Decodable)]
820 pub struct Span {
821     filename: ~str,
822     loline: uint,
823     locol: uint,
824     hiline: uint,
825     hicol: uint,
826 }
827
828 impl Clean<Span> for syntax::codemap::Span {
829     fn clean(&self) -> Span {
830         let cm = local_data::get(super::ctxtkey, |x| *x.unwrap()).sess.codemap;
831         let filename = cm.span_to_filename(*self);
832         let lo = cm.lookup_char_pos(self.lo);
833         let hi = cm.lookup_char_pos(self.hi);
834         Span {
835             filename: filename.to_owned(),
836             loline: lo.line,
837             locol: lo.col.to_uint(),
838             hiline: hi.line,
839             hicol: hi.col.to_uint(),
840         }
841     }
842 }
843
844 #[deriving(Clone, Encodable, Decodable)]
845 pub struct Path {
846     global: bool,
847     segments: ~[PathSegment],
848 }
849
850 impl Clean<Path> for ast::Path {
851     fn clean(&self) -> Path {
852         Path {
853             global: self.global,
854             segments: self.segments.clean()
855         }
856     }
857 }
858
859 #[deriving(Clone, Encodable, Decodable)]
860 pub struct PathSegment {
861     name: ~str,
862     lifetimes: ~[Lifetime],
863     types: ~[Type],
864 }
865
866 impl Clean<PathSegment> for ast::PathSegment {
867     fn clean(&self) -> PathSegment {
868         PathSegment {
869             name: self.identifier.clean(),
870             lifetimes: self.lifetimes.clean(),
871             types: self.types.clean()
872         }
873     }
874 }
875
876 fn path_to_str(p: &ast::Path) -> ~str {
877     use syntax::parse::token::interner_get;
878
879     let mut s = ~"";
880     let mut first = true;
881     for i in p.segments.iter().map(|x| interner_get(x.identifier.name)) {
882         if !first || p.global {
883             s.push_str("::");
884         } else {
885             first = false;
886         }
887         s.push_str(i);
888     }
889     s
890 }
891
892 impl Clean<~str> for ast::Ident {
893     fn clean(&self) -> ~str {
894         let string = token::get_ident(self.name);
895         string.get().to_owned()
896     }
897 }
898
899 #[deriving(Clone, Encodable, Decodable)]
900 pub struct Typedef {
901     type_: Type,
902     generics: Generics,
903 }
904
905 impl Clean<Item> for doctree::Typedef {
906     fn clean(&self) -> Item {
907         Item {
908             name: Some(self.name.clean()),
909             attrs: self.attrs.clean(),
910             source: self.where.clean(),
911             id: self.id.clone(),
912             visibility: self.vis.clean(),
913             inner: TypedefItem(Typedef {
914                 type_: self.ty.clean(),
915                 generics: self.gen.clean(),
916             }),
917         }
918     }
919 }
920
921 #[deriving(Clone, Encodable, Decodable)]
922 pub struct BareFunctionDecl {
923     purity: ast::Purity,
924     generics: Generics,
925     decl: FnDecl,
926     abi: ~str
927 }
928
929 impl Clean<BareFunctionDecl> for ast::BareFnTy {
930     fn clean(&self) -> BareFunctionDecl {
931         BareFunctionDecl {
932             purity: self.purity,
933             generics: Generics {
934                 lifetimes: self.lifetimes.clean(),
935                 type_params: ~[],
936             },
937             decl: self.decl.clean(),
938             abi: self.abis.to_str(),
939         }
940     }
941 }
942
943 #[deriving(Clone, Encodable, Decodable)]
944 pub struct Static {
945     type_: Type,
946     mutability: Mutability,
947     /// It's useful to have the value of a static documented, but I have no
948     /// desire to represent expressions (that'd basically be all of the AST,
949     /// which is huge!). So, have a string.
950     expr: ~str,
951 }
952
953 impl Clean<Item> for doctree::Static {
954     fn clean(&self) -> Item {
955         debug!("claning static {}: {:?}", self.name.clean(), self);
956         Item {
957             name: Some(self.name.clean()),
958             attrs: self.attrs.clean(),
959             source: self.where.clean(),
960             id: self.id,
961             visibility: self.vis.clean(),
962             inner: StaticItem(Static {
963                 type_: self.type_.clean(),
964                 mutability: self.mutability.clean(),
965                 expr: self.expr.span.to_src(),
966             }),
967         }
968     }
969 }
970
971 #[deriving(ToStr, Clone, Encodable, Decodable)]
972 pub enum Mutability {
973     Mutable,
974     Immutable,
975 }
976
977 impl Clean<Mutability> for ast::Mutability {
978     fn clean(&self) -> Mutability {
979         match self {
980             &ast::MutMutable => Mutable,
981             &ast::MutImmutable => Immutable,
982         }
983     }
984 }
985
986 #[deriving(Clone, Encodable, Decodable)]
987 pub struct Impl {
988     generics: Generics,
989     trait_: Option<Type>,
990     for_: Type,
991     methods: ~[Item],
992 }
993
994 impl Clean<Item> for doctree::Impl {
995     fn clean(&self) -> Item {
996         Item {
997             name: None,
998             attrs: self.attrs.clean(),
999             source: self.where.clean(),
1000             id: self.id,
1001             visibility: self.vis.clean(),
1002             inner: ImplItem(Impl {
1003                 generics: self.generics.clean(),
1004                 trait_: self.trait_.clean(),
1005                 for_: self.for_.clean(),
1006                 methods: self.methods.clean(),
1007             }),
1008         }
1009     }
1010 }
1011
1012 #[deriving(Clone, Encodable, Decodable)]
1013 pub struct ViewItem {
1014     inner: ViewItemInner
1015 }
1016
1017 impl Clean<Item> for ast::ViewItem {
1018     fn clean(&self) -> Item {
1019         Item {
1020             name: None,
1021             attrs: self.attrs.clean(),
1022             source: self.span.clean(),
1023             id: 0,
1024             visibility: self.vis.clean(),
1025             inner: ViewItemItem(ViewItem {
1026                 inner: self.node.clean()
1027             }),
1028         }
1029     }
1030 }
1031
1032 #[deriving(Clone, Encodable, Decodable)]
1033 pub enum ViewItemInner {
1034     ExternMod(~str, Option<~str>, ast::NodeId),
1035     Import(~[ViewPath])
1036 }
1037
1038 impl Clean<ViewItemInner> for ast::ViewItem_ {
1039     fn clean(&self) -> ViewItemInner {
1040         match self {
1041             &ast::ViewItemExternMod(ref i, ref p, ref id) => {
1042                 let string = match *p {
1043                     None => None,
1044                     Some((ref x, _)) => Some(x.get().to_owned()),
1045                 };
1046                 ExternMod(i.clean(), string, *id)
1047             }
1048             &ast::ViewItemUse(ref vp) => Import(vp.clean())
1049         }
1050     }
1051 }
1052
1053 #[deriving(Clone, Encodable, Decodable)]
1054 pub enum ViewPath {
1055     // use str = source;
1056     SimpleImport(~str, ImportSource),
1057     // use source::*;
1058     GlobImport(ImportSource),
1059     // use source::{a, b, c};
1060     ImportList(ImportSource, ~[ViewListIdent]),
1061 }
1062
1063 #[deriving(Clone, Encodable, Decodable)]
1064 pub struct ImportSource {
1065     path: Path,
1066     did: Option<ast::DefId>,
1067 }
1068
1069 impl Clean<ViewPath> for ast::ViewPath {
1070     fn clean(&self) -> ViewPath {
1071         match self.node {
1072             ast::ViewPathSimple(ref i, ref p, id) =>
1073                 SimpleImport(i.clean(), resolve_use_source(p.clean(), id)),
1074             ast::ViewPathGlob(ref p, id) =>
1075                 GlobImport(resolve_use_source(p.clean(), id)),
1076             ast::ViewPathList(ref p, ref pl, id) =>
1077                 ImportList(resolve_use_source(p.clean(), id), pl.clean()),
1078         }
1079     }
1080 }
1081
1082 #[deriving(Clone, Encodable, Decodable)]
1083 pub struct ViewListIdent {
1084     name: ~str,
1085     source: Option<ast::DefId>,
1086 }
1087
1088 impl Clean<ViewListIdent> for ast::PathListIdent {
1089     fn clean(&self) -> ViewListIdent {
1090         ViewListIdent {
1091             name: self.node.name.clean(),
1092             source: resolve_def(self.node.id),
1093         }
1094     }
1095 }
1096
1097 impl Clean<~[Item]> for ast::ForeignMod {
1098     fn clean(&self) -> ~[Item] {
1099         self.items.clean()
1100     }
1101 }
1102
1103 impl Clean<Item> for ast::ForeignItem {
1104     fn clean(&self) -> Item {
1105         let inner = match self.node {
1106             ast::ForeignItemFn(ref decl, ref generics) => {
1107                 ForeignFunctionItem(Function {
1108                     decl: decl.clean(),
1109                     generics: generics.clean(),
1110                     purity: ast::ExternFn,
1111                 })
1112             }
1113             ast::ForeignItemStatic(ref ty, mutbl) => {
1114                 ForeignStaticItem(Static {
1115                     type_: ty.clean(),
1116                     mutability: if mutbl {Mutable} else {Immutable},
1117                     expr: ~"",
1118                 })
1119             }
1120         };
1121         Item {
1122             name: Some(self.ident.clean()),
1123             attrs: self.attrs.clean(),
1124             source: self.span.clean(),
1125             id: self.id,
1126             visibility: self.vis.clean(),
1127             inner: inner,
1128         }
1129     }
1130 }
1131
1132 // Utilities
1133
1134 trait ToSource {
1135     fn to_src(&self) -> ~str;
1136 }
1137
1138 impl ToSource for syntax::codemap::Span {
1139     fn to_src(&self) -> ~str {
1140         debug!("converting span {:?} to snippet", self.clean());
1141         let cm = local_data::get(super::ctxtkey, |x| x.unwrap().clone()).sess.codemap.clone();
1142         let sn = match cm.span_to_snippet(*self) {
1143             Some(x) => x,
1144             None    => ~""
1145         };
1146         debug!("got snippet {}", sn);
1147         sn
1148     }
1149 }
1150
1151 fn lit_to_str(lit: &ast::Lit) -> ~str {
1152     match lit.node {
1153         ast::LitStr(ref st, _) => st.get().to_owned(),
1154         ast::LitBinary(data) => format!("{:?}", data.as_slice()),
1155         ast::LitChar(c) => ~"'" + std::char::from_u32(c).unwrap().to_str() + "'",
1156         ast::LitInt(i, _t) => i.to_str(),
1157         ast::LitUint(u, _t) => u.to_str(),
1158         ast::LitIntUnsuffixed(i) => i.to_str(),
1159         ast::LitFloat(ref f, _t) => f.get().to_str(),
1160         ast::LitFloatUnsuffixed(ref f) => f.get().to_str(),
1161         ast::LitBool(b) => b.to_str(),
1162         ast::LitNil => ~"",
1163     }
1164 }
1165
1166 fn name_from_pat(p: &ast::Pat) -> ~str {
1167     use syntax::ast::*;
1168     debug!("Trying to get a name from pattern: {:?}", p);
1169
1170     match p.node {
1171         PatWild => ~"_",
1172         PatWildMulti => ~"..",
1173         PatIdent(_, ref p, _) => path_to_str(p),
1174         PatEnum(ref p, _) => path_to_str(p),
1175         PatStruct(..) => fail!("tried to get argument name from pat_struct, \
1176                                 which is not allowed in function arguments"),
1177         PatTup(..) => ~"(tuple arg NYI)",
1178         PatUniq(p) => name_from_pat(p),
1179         PatRegion(p) => name_from_pat(p),
1180         PatLit(..) => {
1181             warn!("tried to get argument name from PatLit, \
1182                   which is silly in function arguments");
1183             ~"()"
1184         },
1185         PatRange(..) => fail!("tried to get argument name from PatRange, \
1186                               which is not allowed in function arguments"),
1187         PatVec(..) => fail!("tried to get argument name from pat_vec, \
1188                              which is not allowed in function arguments")
1189     }
1190 }
1191
1192 /// Given a Type, resolve it using the def_map
1193 fn resolve_type(path: Path, tpbs: Option<~[TyParamBound]>,
1194                 id: ast::NodeId) -> Type {
1195     let cx = local_data::get(super::ctxtkey, |x| *x.unwrap());
1196     let tycx = match cx.tycx {
1197         Some(tycx) => tycx,
1198         // If we're extracting tests, this return value doesn't matter.
1199         None => return Bool
1200     };
1201     debug!("searching for {:?} in defmap", id);
1202     let def_map = tycx.def_map.borrow();
1203     let d = match def_map.get().find(&id) {
1204         Some(k) => k,
1205         None => {
1206             debug!("could not find {:?} in defmap (`{}`)", id,
1207                    syntax::ast_map::node_id_to_str(tycx.items, id, cx.sess.intr()));
1208             fail!("Unexpected failure: unresolved id not in defmap (this is a bug!)")
1209         }
1210     };
1211
1212     let (def_id, kind) = match *d {
1213         ast::DefFn(i, _) => (i, TypeFunction),
1214         ast::DefSelfTy(i) => return Self(i),
1215         ast::DefTy(i) => (i, TypeEnum),
1216         ast::DefTrait(i) => {
1217             debug!("saw DefTrait in def_to_id");
1218             (i, TypeTrait)
1219         },
1220         ast::DefPrimTy(p) => match p {
1221             ast::TyStr => return String,
1222             ast::TyBool => return Bool,
1223             _ => return Primitive(p)
1224         },
1225         ast::DefTyParam(i, _) => return Generic(i.node),
1226         ast::DefStruct(i) => (i, TypeStruct),
1227         ast::DefTyParamBinder(i) => {
1228             debug!("found a typaram_binder, what is it? {}", i);
1229             return TyParamBinder(i);
1230         },
1231         x => fail!("resolved type maps to a weird def {:?}", x),
1232     };
1233     if ast_util::is_local(def_id) {
1234         ResolvedPath{ path: path, typarams: tpbs, id: def_id.node }
1235     } else {
1236         let fqn = csearch::get_item_path(tycx, def_id);
1237         let fqn = fqn.move_iter().map(|i| {
1238             match i {
1239                 ast_map::PathMod(id) | ast_map::PathName(id) |
1240                 ast_map::PathPrettyName(id, _) => id.clean()
1241             }
1242         }).to_owned_vec();
1243         ExternalPath{ path: path, typarams: tpbs, fqn: fqn, kind: kind,
1244                       crate: def_id.crate }
1245     }
1246 }
1247
1248 fn resolve_use_source(path: Path, id: ast::NodeId) -> ImportSource {
1249     ImportSource {
1250         path: path,
1251         did: resolve_def(id),
1252     }
1253 }
1254
1255 fn resolve_def(id: ast::NodeId) -> Option<ast::DefId> {
1256     let cx = local_data::get(super::ctxtkey, |x| *x.unwrap());
1257     match cx.tycx {
1258         Some(tcx) => {
1259             let def_map = tcx.def_map.borrow();
1260             def_map.get().find(&id).map(|&d| ast_util::def_id_of_def(d))
1261         }
1262         None => None
1263     }
1264 }