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