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