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