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