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