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