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