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