]> git.lizzy.rs Git - rust.git/blob - src/librustdoc/clean.rs
rustdoc: Fill in external trait methods
[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::back::link;
24 use rustc::driver::driver;
25 use rustc::metadata::cstore;
26 use rustc::metadata::csearch;
27 use rustc::metadata::decoder;
28 use rustc::middle::ty;
29
30 use std::strbuf::StrBuf;
31
32 use core;
33 use doctree;
34 use visit_ast;
35
36 /// A stable identifier to the particular version of JSON output.
37 /// Increment this when the `Crate` and related structures change.
38 pub static SCHEMA_VERSION: &'static str = "0.8.2";
39
40 pub trait Clean<T> {
41     fn clean(&self) -> T;
42 }
43
44 impl<T: Clean<U>, U> Clean<Vec<U>> for Vec<T> {
45     fn clean(&self) -> Vec<U> {
46         self.iter().map(|x| x.clean()).collect()
47     }
48 }
49
50 impl<T: Clean<U>, U> Clean<U> for @T {
51     fn clean(&self) -> U {
52         (**self).clean()
53     }
54 }
55
56 impl<T: Clean<U>, U> Clean<Option<U>> for Option<T> {
57     fn clean(&self) -> Option<U> {
58         match self {
59             &None => None,
60             &Some(ref v) => Some(v.clean())
61         }
62     }
63 }
64
65 impl<T: Clean<U>, U> Clean<Vec<U>> for syntax::owned_slice::OwnedSlice<T> {
66     fn clean(&self) -> Vec<U> {
67         self.iter().map(|x| x.clean()).collect()
68     }
69 }
70
71 #[deriving(Clone, Encodable, Decodable)]
72 pub struct Crate {
73     pub name: StrBuf,
74     pub module: Option<Item>,
75     pub externs: Vec<(ast::CrateNum, ExternalCrate)>,
76 }
77
78 impl<'a> Clean<Crate> for visit_ast::RustdocVisitor<'a> {
79     fn clean(&self) -> Crate {
80         let cx = super::ctxtkey.get().unwrap();
81
82         let mut externs = Vec::new();
83         cx.sess().cstore.iter_crate_data(|n, meta| {
84             externs.push((n, meta.clean()));
85         });
86
87         let input = driver::FileInput(cx.src.clone());
88         let t_outputs = driver::build_output_filenames(&input,
89                                                        &None,
90                                                        &None,
91                                                        self.attrs.as_slice(),
92                                                        cx.sess());
93         let id = link::find_crate_id(self.attrs.as_slice(),
94                                      t_outputs.out_filestem.as_slice());
95         Crate {
96             name: id.name.to_strbuf(),
97             module: Some(self.module.clean()),
98             externs: externs,
99         }
100     }
101 }
102
103 #[deriving(Clone, Encodable, Decodable)]
104 pub struct ExternalCrate {
105     pub name: StrBuf,
106     pub attrs: Vec<Attribute>,
107 }
108
109 impl Clean<ExternalCrate> for cstore::crate_metadata {
110     fn clean(&self) -> ExternalCrate {
111         ExternalCrate {
112             name: self.name.to_strbuf(),
113             attrs: decoder::get_crate_attributes(self.data()).clean()
114                                                              .move_iter()
115                                                              .collect(),
116         }
117     }
118 }
119
120 /// Anything with a source location and set of attributes and, optionally, a
121 /// name. That is, anything that can be documented. This doesn't correspond
122 /// directly to the AST's concept of an item; it's a strict superset.
123 #[deriving(Clone, Encodable, Decodable)]
124 pub struct Item {
125     /// Stringified span
126     pub source: Span,
127     /// Not everything has a name. E.g., impls
128     pub name: Option<StrBuf>,
129     pub attrs: Vec<Attribute> ,
130     pub inner: ItemEnum,
131     pub visibility: Option<Visibility>,
132     pub def_id: ast::DefId,
133 }
134
135 impl Item {
136     /// Finds the `doc` attribute as a List and returns the list of attributes
137     /// nested inside.
138     pub fn doc_list<'a>(&'a self) -> Option<&'a [Attribute]> {
139         for attr in self.attrs.iter() {
140             match *attr {
141                 List(ref x, ref list) if "doc" == x.as_slice() => {
142                     return Some(list.as_slice());
143                 }
144                 _ => {}
145             }
146         }
147         return None;
148     }
149
150     /// Finds the `doc` attribute as a NameValue and returns the corresponding
151     /// value found.
152     pub fn doc_value<'a>(&'a self) -> Option<&'a str> {
153         for attr in self.attrs.iter() {
154             match *attr {
155                 NameValue(ref x, ref v) if "doc" == x.as_slice() => {
156                     return Some(v.as_slice());
157                 }
158                 _ => {}
159             }
160         }
161         return None;
162     }
163
164     pub fn is_hidden_from_doc(&self) -> bool {
165         match self.doc_list() {
166             Some(ref l) => {
167                 for innerattr in l.iter() {
168                     match *innerattr {
169                         Word(ref s) if "hidden" == s.as_slice() => {
170                             return true
171                         }
172                         _ => (),
173                     }
174                 }
175             },
176             None => ()
177         }
178         return false;
179     }
180
181     pub fn is_mod(&self) -> bool {
182         match self.inner { ModuleItem(..) => true, _ => false }
183     }
184     pub fn is_trait(&self) -> bool {
185         match self.inner { TraitItem(..) => true, _ => false }
186     }
187     pub fn is_struct(&self) -> bool {
188         match self.inner { StructItem(..) => true, _ => false }
189     }
190     pub fn is_enum(&self) -> bool {
191         match self.inner { EnumItem(..) => true, _ => false }
192     }
193     pub fn is_fn(&self) -> bool {
194         match self.inner { FunctionItem(..) => true, _ => false }
195     }
196 }
197
198 #[deriving(Clone, Encodable, Decodable)]
199 pub enum ItemEnum {
200     StructItem(Struct),
201     EnumItem(Enum),
202     FunctionItem(Function),
203     ModuleItem(Module),
204     TypedefItem(Typedef),
205     StaticItem(Static),
206     TraitItem(Trait),
207     ImplItem(Impl),
208     /// `use` and `extern crate`
209     ViewItemItem(ViewItem),
210     /// A method signature only. Used for required methods in traits (ie,
211     /// non-default-methods).
212     TyMethodItem(TyMethod),
213     /// A method with a body.
214     MethodItem(Method),
215     StructFieldItem(StructField),
216     VariantItem(Variant),
217     /// `fn`s from an extern block
218     ForeignFunctionItem(Function),
219     /// `static`s from an extern block
220     ForeignStaticItem(Static),
221     MacroItem(Macro),
222 }
223
224 #[deriving(Clone, Encodable, Decodable)]
225 pub struct Module {
226     pub items: Vec<Item>,
227     pub is_crate: bool,
228 }
229
230 impl Clean<Item> for doctree::Module {
231     fn clean(&self) -> Item {
232         let name = if self.name.is_some() {
233             self.name.unwrap().clean()
234         } else {
235             "".to_strbuf()
236         };
237         let mut foreigns = Vec::new();
238         for subforeigns in self.foreigns.clean().move_iter() {
239             for foreign in subforeigns.move_iter() {
240                 foreigns.push(foreign)
241             }
242         }
243         let items: Vec<Vec<Item> > = vec!(
244             self.structs.clean().move_iter().collect(),
245             self.enums.clean().move_iter().collect(),
246             self.fns.clean().move_iter().collect(),
247             foreigns,
248             self.mods.clean().move_iter().collect(),
249             self.typedefs.clean().move_iter().collect(),
250             self.statics.clean().move_iter().collect(),
251             self.traits.clean().move_iter().collect(),
252             self.impls.clean().move_iter().collect(),
253             self.view_items.clean().move_iter().collect(),
254             self.macros.clean().move_iter().collect()
255         );
256
257         // determine if we should display the inner contents or
258         // the outer `mod` item for the source code.
259         let where = {
260             let ctxt = super::ctxtkey.get().unwrap();
261             let cm = ctxt.sess().codemap();
262             let outer = cm.lookup_char_pos(self.where_outer.lo);
263             let inner = cm.lookup_char_pos(self.where_inner.lo);
264             if outer.file.start_pos == inner.file.start_pos {
265                 // mod foo { ... }
266                 self.where_outer
267             } else {
268                 // mod foo; (and a separate FileMap for the contents)
269                 self.where_inner
270             }
271         };
272
273         Item {
274             name: Some(name),
275             attrs: self.attrs.clean(),
276             source: where.clean(),
277             visibility: self.vis.clean(),
278             def_id: ast_util::local_def(self.id),
279             inner: ModuleItem(Module {
280                is_crate: self.is_crate,
281                items: items.iter()
282                            .flat_map(|x| x.iter().map(|x| (*x).clone()))
283                            .collect(),
284             })
285         }
286     }
287 }
288
289 #[deriving(Clone, Encodable, Decodable)]
290 pub enum Attribute {
291     Word(StrBuf),
292     List(StrBuf, Vec<Attribute> ),
293     NameValue(StrBuf, StrBuf)
294 }
295
296 impl Clean<Attribute> for ast::MetaItem {
297     fn clean(&self) -> Attribute {
298         match self.node {
299             ast::MetaWord(ref s) => Word(s.get().to_strbuf()),
300             ast::MetaList(ref s, ref l) => {
301                 List(s.get().to_strbuf(), l.clean().move_iter().collect())
302             }
303             ast::MetaNameValue(ref s, ref v) => {
304                 NameValue(s.get().to_strbuf(), lit_to_str(v))
305             }
306         }
307     }
308 }
309
310 impl Clean<Attribute> for ast::Attribute {
311     fn clean(&self) -> Attribute {
312         self.desugar_doc().node.value.clean()
313     }
314 }
315
316 // This is a rough approximation that gets us what we want.
317 impl<'a> attr::AttrMetaMethods for &'a Attribute {
318     fn name(&self) -> InternedString {
319         match **self {
320             Word(ref n) | List(ref n, _) | NameValue(ref n, _) => {
321                 token::intern_and_get_ident(n.as_slice())
322             }
323         }
324     }
325
326     fn value_str(&self) -> Option<InternedString> {
327         match **self {
328             NameValue(_, ref v) => {
329                 Some(token::intern_and_get_ident(v.as_slice()))
330             }
331             _ => None,
332         }
333     }
334     fn meta_item_list<'a>(&'a self) -> Option<&'a [@ast::MetaItem]> { None }
335     fn name_str_pair(&self) -> Option<(InternedString, InternedString)> {
336         None
337     }
338 }
339
340 #[deriving(Clone, Encodable, Decodable)]
341 pub struct TyParam {
342     pub name: StrBuf,
343     pub did: ast::DefId,
344     pub bounds: Vec<TyParamBound>,
345 }
346
347 impl Clean<TyParam> for ast::TyParam {
348     fn clean(&self) -> TyParam {
349         TyParam {
350             name: self.ident.clean(),
351             did: ast::DefId { krate: ast::LOCAL_CRATE, node: self.id },
352             bounds: self.bounds.clean().move_iter().collect(),
353         }
354     }
355 }
356
357 impl Clean<TyParam> for ty::TypeParameterDef {
358     fn clean(&self) -> TyParam {
359         let cx = super::ctxtkey.get().unwrap();
360         cx.external_typarams.borrow_mut().get_mut_ref().insert(self.def_id,
361                                                                self.ident.clean());
362         TyParam {
363             name: self.ident.clean(),
364             did: self.def_id,
365             bounds: self.bounds.clean(),
366         }
367     }
368 }
369
370 #[deriving(Clone, Encodable, Decodable)]
371 pub enum TyParamBound {
372     RegionBound,
373     TraitBound(Type)
374 }
375
376 impl Clean<TyParamBound> for ast::TyParamBound {
377     fn clean(&self) -> TyParamBound {
378         match *self {
379             ast::StaticRegionTyParamBound => RegionBound,
380             ast::OtherRegionTyParamBound(_) => RegionBound,
381             ast::TraitTyParamBound(ref t) => TraitBound(t.clean()),
382         }
383     }
384 }
385
386 fn external_path(name: &str) -> Path {
387     Path {
388         global: false,
389         segments: vec![PathSegment {
390             name: name.to_strbuf(),
391             lifetimes: Vec::new(),
392             types: Vec::new(),
393         }]
394     }
395 }
396
397 impl Clean<TyParamBound> for ty::BuiltinBound {
398     fn clean(&self) -> TyParamBound {
399         let cx = super::ctxtkey.get().unwrap();
400         let tcx = match cx.maybe_typed {
401             core::Typed(ref tcx) => tcx,
402             core::NotTyped(_) => return RegionBound,
403         };
404         let (did, path) = match *self {
405             ty::BoundStatic => return RegionBound,
406             ty::BoundSend =>
407                 (tcx.lang_items.send_trait().unwrap(), external_path("Send")),
408             ty::BoundSized =>
409                 (tcx.lang_items.sized_trait().unwrap(), external_path("Sized")),
410             ty::BoundCopy =>
411                 (tcx.lang_items.copy_trait().unwrap(), external_path("Copy")),
412             ty::BoundShare =>
413                 (tcx.lang_items.share_trait().unwrap(), external_path("Share")),
414         };
415         let fqn = csearch::get_item_path(tcx, did);
416         let fqn = fqn.move_iter().map(|i| i.to_str().to_strbuf()).collect();
417         cx.external_paths.borrow_mut().get_mut_ref().insert(did,
418                                                             (fqn, TypeTrait));
419         TraitBound(ResolvedPath {
420             path: path,
421             typarams: None,
422             did: did,
423         })
424     }
425 }
426
427 impl Clean<TyParamBound> for ty::TraitRef {
428     fn clean(&self) -> TyParamBound {
429         let cx = super::ctxtkey.get().unwrap();
430         let tcx = match cx.maybe_typed {
431             core::Typed(ref tcx) => tcx,
432             core::NotTyped(_) => return RegionBound,
433         };
434         let fqn = csearch::get_item_path(tcx, self.def_id);
435         let fqn = fqn.move_iter().map(|i| i.to_str().to_strbuf())
436                      .collect::<Vec<StrBuf>>();
437         let path = external_path(fqn.last().unwrap().as_slice());
438         cx.external_paths.borrow_mut().get_mut_ref().insert(self.def_id,
439                                                             (fqn, TypeTrait));
440         TraitBound(ResolvedPath {
441             path: path,
442             typarams: None,
443             did: self.def_id,
444         })
445     }
446 }
447
448 impl Clean<Vec<TyParamBound>> for ty::ParamBounds {
449     fn clean(&self) -> Vec<TyParamBound> {
450         let mut v = Vec::new();
451         for b in self.builtin_bounds.iter() {
452             if b != ty::BoundSized {
453                 v.push(b.clean());
454             }
455         }
456         for t in self.trait_bounds.iter() {
457             v.push(t.clean());
458         }
459         return v;
460     }
461 }
462
463 impl Clean<Option<Vec<TyParamBound>>> for ty::substs {
464     fn clean(&self) -> Option<Vec<TyParamBound>> {
465         let mut v = Vec::new();
466         match self.regions {
467             ty::NonerasedRegions(..) => v.push(RegionBound),
468             ty::ErasedRegions => {}
469         }
470         v.extend(self.tps.iter().map(|t| TraitBound(t.clean())));
471
472         if v.len() > 0 {Some(v)} else {None}
473     }
474 }
475
476 #[deriving(Clone, Encodable, Decodable)]
477 pub struct Lifetime(StrBuf);
478
479 impl Lifetime {
480     pub fn get_ref<'a>(&'a self) -> &'a str {
481         let Lifetime(ref s) = *self;
482         let s: &'a str = s.as_slice();
483         return s;
484     }
485 }
486
487 impl Clean<Lifetime> for ast::Lifetime {
488     fn clean(&self) -> Lifetime {
489         Lifetime(token::get_name(self.name).get().to_strbuf())
490     }
491 }
492
493 impl Clean<Lifetime> for ty::RegionParameterDef {
494     fn clean(&self) -> Lifetime {
495         Lifetime(token::get_name(self.name).get().to_strbuf())
496     }
497 }
498
499 impl Clean<Option<Lifetime>> for ty::Region {
500     fn clean(&self) -> Option<Lifetime> {
501         match *self {
502             ty::ReStatic => Some(Lifetime("static".to_strbuf())),
503             ty::ReLateBound(_, ty::BrNamed(_, name)) =>
504                 Some(Lifetime(token::get_name(name).get().to_strbuf())),
505
506             ty::ReLateBound(..) |
507             ty::ReEarlyBound(..) |
508             ty::ReFree(..) |
509             ty::ReScope(..) |
510             ty::ReInfer(..) |
511             ty::ReEmpty(..) => None
512         }
513     }
514 }
515
516 // maybe use a Generic enum and use ~[Generic]?
517 #[deriving(Clone, Encodable, Decodable)]
518 pub struct Generics {
519     pub lifetimes: Vec<Lifetime>,
520     pub type_params: Vec<TyParam>,
521 }
522
523 impl Clean<Generics> for ast::Generics {
524     fn clean(&self) -> Generics {
525         Generics {
526             lifetimes: self.lifetimes.clean().move_iter().collect(),
527             type_params: self.ty_params.clean().move_iter().collect(),
528         }
529     }
530 }
531
532 impl Clean<Generics> for ty::Generics {
533     fn clean(&self) -> Generics {
534         Generics {
535             lifetimes: self.region_param_defs.clean(),
536             type_params: self.type_param_defs.clean(),
537         }
538     }
539 }
540
541 #[deriving(Clone, Encodable, Decodable)]
542 pub struct Method {
543     pub generics: Generics,
544     pub self_: SelfTy,
545     pub fn_style: ast::FnStyle,
546     pub decl: FnDecl,
547 }
548
549 impl Clean<Item> for ast::Method {
550     fn clean(&self) -> Item {
551         let inputs = match self.explicit_self.node {
552             ast::SelfStatic => self.decl.inputs.as_slice(),
553             _ => self.decl.inputs.slice_from(1)
554         };
555         let decl = FnDecl {
556             inputs: Arguments {
557                 values: inputs.iter().map(|x| x.clean()).collect(),
558             },
559             output: (self.decl.output.clean()),
560             cf: self.decl.cf.clean(),
561             attrs: Vec::new()
562         };
563         Item {
564             name: Some(self.ident.clean()),
565             attrs: self.attrs.clean().move_iter().collect(),
566             source: self.span.clean(),
567             def_id: ast_util::local_def(self.id.clone()),
568             visibility: self.vis.clean(),
569             inner: MethodItem(Method {
570                 generics: self.generics.clean(),
571                 self_: self.explicit_self.node.clean(),
572                 fn_style: self.fn_style.clone(),
573                 decl: decl,
574             }),
575         }
576     }
577 }
578
579 #[deriving(Clone, Encodable, Decodable)]
580 pub struct TyMethod {
581     pub fn_style: ast::FnStyle,
582     pub decl: FnDecl,
583     pub generics: Generics,
584     pub self_: SelfTy,
585 }
586
587 impl Clean<Item> for ast::TypeMethod {
588     fn clean(&self) -> Item {
589         let inputs = match self.explicit_self.node {
590             ast::SelfStatic => self.decl.inputs.as_slice(),
591             _ => self.decl.inputs.slice_from(1)
592         };
593         let decl = FnDecl {
594             inputs: Arguments {
595                 values: inputs.iter().map(|x| x.clean()).collect(),
596             },
597             output: (self.decl.output.clean()),
598             cf: self.decl.cf.clean(),
599             attrs: Vec::new()
600         };
601         Item {
602             name: Some(self.ident.clean()),
603             attrs: self.attrs.clean().move_iter().collect(),
604             source: self.span.clean(),
605             def_id: ast_util::local_def(self.id),
606             visibility: None,
607             inner: TyMethodItem(TyMethod {
608                 fn_style: self.fn_style.clone(),
609                 decl: decl,
610                 self_: self.explicit_self.node.clean(),
611                 generics: self.generics.clean(),
612             }),
613         }
614     }
615 }
616
617 #[deriving(Clone, Encodable, Decodable)]
618 pub enum SelfTy {
619     SelfStatic,
620     SelfValue,
621     SelfBorrowed(Option<Lifetime>, Mutability),
622     SelfOwned,
623 }
624
625 impl Clean<SelfTy> for ast::ExplicitSelf_ {
626     fn clean(&self) -> SelfTy {
627         match *self {
628             ast::SelfStatic => SelfStatic,
629             ast::SelfValue => SelfValue,
630             ast::SelfUniq => SelfOwned,
631             ast::SelfRegion(lt, mt) => SelfBorrowed(lt.clean(), mt.clean()),
632         }
633     }
634 }
635
636 #[deriving(Clone, Encodable, Decodable)]
637 pub struct Function {
638     pub decl: FnDecl,
639     pub generics: Generics,
640     pub fn_style: ast::FnStyle,
641 }
642
643 impl Clean<Item> for doctree::Function {
644     fn clean(&self) -> Item {
645         Item {
646             name: Some(self.name.clean()),
647             attrs: self.attrs.clean(),
648             source: self.where.clean(),
649             visibility: self.vis.clean(),
650             def_id: ast_util::local_def(self.id),
651             inner: FunctionItem(Function {
652                 decl: self.decl.clean(),
653                 generics: self.generics.clean(),
654                 fn_style: self.fn_style,
655             }),
656         }
657     }
658 }
659
660 #[deriving(Clone, Encodable, Decodable)]
661 pub struct ClosureDecl {
662     pub lifetimes: Vec<Lifetime>,
663     pub decl: FnDecl,
664     pub onceness: ast::Onceness,
665     pub fn_style: ast::FnStyle,
666     pub bounds: Vec<TyParamBound>,
667 }
668
669 impl Clean<ClosureDecl> for ast::ClosureTy {
670     fn clean(&self) -> ClosureDecl {
671         ClosureDecl {
672             lifetimes: self.lifetimes.clean(),
673             decl: self.decl.clean(),
674             onceness: self.onceness,
675             fn_style: self.fn_style,
676             bounds: match self.bounds {
677                 Some(ref x) => x.clean().move_iter().collect(),
678                 None        => Vec::new()
679             },
680         }
681     }
682 }
683
684 #[deriving(Clone, Encodable, Decodable)]
685 pub struct FnDecl {
686     pub inputs: Arguments,
687     pub output: Type,
688     pub cf: RetStyle,
689     pub attrs: Vec<Attribute>,
690 }
691
692 #[deriving(Clone, Encodable, Decodable)]
693 pub struct Arguments {
694     pub values: Vec<Argument>,
695 }
696
697 impl Clean<FnDecl> for ast::FnDecl {
698     fn clean(&self) -> FnDecl {
699         FnDecl {
700             inputs: Arguments {
701                 values: self.inputs.iter().map(|x| x.clean()).collect(),
702             },
703             output: (self.output.clean()),
704             cf: self.cf.clean(),
705             attrs: Vec::new()
706         }
707     }
708 }
709
710 impl Clean<FnDecl> for ty::FnSig {
711     fn clean(&self) -> FnDecl {
712         FnDecl {
713             output: self.output.clean(),
714             cf: Return,
715             attrs: Vec::new(), // FIXME: this is likely wrong
716             inputs: Arguments {
717                 values: self.inputs.iter().map(|t| {
718                     Argument {
719                         type_: t.clean(),
720                         id: 0,
721                         name: "".to_strbuf(), // FIXME: where are the names?
722                     }
723                 }).collect(),
724             },
725         }
726     }
727 }
728
729 #[deriving(Clone, Encodable, Decodable)]
730 pub struct Argument {
731     pub type_: Type,
732     pub name: StrBuf,
733     pub id: ast::NodeId,
734 }
735
736 impl Clean<Argument> for ast::Arg {
737     fn clean(&self) -> Argument {
738         Argument {
739             name: name_from_pat(self.pat),
740             type_: (self.ty.clean()),
741             id: self.id
742         }
743     }
744 }
745
746 #[deriving(Clone, Encodable, Decodable)]
747 pub enum RetStyle {
748     NoReturn,
749     Return
750 }
751
752 impl Clean<RetStyle> for ast::RetStyle {
753     fn clean(&self) -> RetStyle {
754         match *self {
755             ast::Return => Return,
756             ast::NoReturn => NoReturn
757         }
758     }
759 }
760
761 #[deriving(Clone, Encodable, Decodable)]
762 pub struct Trait {
763     pub methods: Vec<TraitMethod>,
764     pub generics: Generics,
765     pub parents: Vec<Type>,
766 }
767
768 impl Clean<Item> for doctree::Trait {
769     fn clean(&self) -> Item {
770         Item {
771             name: Some(self.name.clean()),
772             attrs: self.attrs.clean(),
773             source: self.where.clean(),
774             def_id: ast_util::local_def(self.id),
775             visibility: self.vis.clean(),
776             inner: TraitItem(Trait {
777                 methods: self.methods.clean(),
778                 generics: self.generics.clean(),
779                 parents: self.parents.clean(),
780             }),
781         }
782     }
783 }
784
785 impl Clean<Type> for ast::TraitRef {
786     fn clean(&self) -> Type {
787         resolve_type(self.path.clean(), None, self.ref_id)
788     }
789 }
790
791 #[deriving(Clone, Encodable, Decodable)]
792 pub enum TraitMethod {
793     Required(Item),
794     Provided(Item),
795 }
796
797 impl TraitMethod {
798     pub fn is_req(&self) -> bool {
799         match self {
800             &Required(..) => true,
801             _ => false,
802         }
803     }
804     pub fn is_def(&self) -> bool {
805         match self {
806             &Provided(..) => true,
807             _ => false,
808         }
809     }
810     pub fn item<'a>(&'a self) -> &'a Item {
811         match *self {
812             Required(ref item) => item,
813             Provided(ref item) => item,
814         }
815     }
816 }
817
818 impl Clean<TraitMethod> for ast::TraitMethod {
819     fn clean(&self) -> TraitMethod {
820         match self {
821             &ast::Required(ref t) => Required(t.clean()),
822             &ast::Provided(ref t) => Provided(t.clean()),
823         }
824     }
825 }
826
827 impl Clean<TraitMethod> for ty::Method {
828     fn clean(&self) -> TraitMethod {
829         let m = if self.provided_source.is_some() {Provided} else {Required};
830         let cx = super::ctxtkey.get().unwrap();
831         let tcx = match cx.maybe_typed {
832             core::Typed(ref tcx) => tcx,
833             core::NotTyped(_) => fail!(),
834         };
835         let mut attrs = Vec::new();
836         csearch::get_item_attrs(&tcx.sess.cstore, self.def_id, |v| {
837             attrs.extend(v.move_iter().map(|i| i.clean()));
838         });
839         let (self_, sig) = match self.explicit_self {
840             ast::SelfStatic => (ast::SelfStatic.clean(), self.fty.sig.clone()),
841             s => {
842                 let sig = ty::FnSig {
843                     inputs: Vec::from_slice(self.fty.sig.inputs.slice_from(1)),
844                     ..self.fty.sig.clone()
845                 };
846                 let s = match s {
847                     ast::SelfRegion(..) => {
848                         match ty::get(*self.fty.sig.inputs.get(0)).sty {
849                             ty::ty_rptr(r, mt) => {
850                                 SelfBorrowed(r.clean(), mt.mutbl.clean())
851                             }
852                             _ => s.clean(),
853                         }
854                     }
855                     s => s.clean(),
856                 };
857                 (s, sig)
858             }
859         };
860         m(Item {
861             name: Some(self.ident.clean()),
862             visibility: Some(ast::Inherited),
863             def_id: self.def_id,
864             attrs: attrs,
865             source: Span {
866                 filename: "".to_strbuf(),
867                 loline: 0, locol: 0, hiline: 0, hicol: 0,
868             },
869             inner: TyMethodItem(TyMethod {
870                 fn_style: self.fty.fn_style,
871                 generics: self.generics.clean(),
872                 self_: self_,
873                 decl: sig.clean(),
874             })
875         })
876     }
877 }
878
879 /// A representation of a Type suitable for hyperlinking purposes. Ideally one can get the original
880 /// type out of the AST/ty::ctxt given one of these, if more information is needed. Most importantly
881 /// it does not preserve mutability or boxes.
882 #[deriving(Clone, Encodable, Decodable)]
883 pub enum Type {
884     /// structs/enums/traits (anything that'd be an ast::TyPath)
885     ResolvedPath {
886         pub path: Path,
887         pub typarams: Option<Vec<TyParamBound>>,
888         pub did: ast::DefId,
889     },
890     // I have no idea how to usefully use this.
891     TyParamBinder(ast::NodeId),
892     /// For parameterized types, so the consumer of the JSON don't go looking
893     /// for types which don't exist anywhere.
894     Generic(ast::DefId),
895     /// For references to self
896     Self(ast::DefId),
897     /// Primitives are just the fixed-size numeric types (plus int/uint/float), and char.
898     Primitive(ast::PrimTy),
899     Closure(Box<ClosureDecl>, Option<Lifetime>),
900     Proc(Box<ClosureDecl>),
901     /// extern "ABI" fn
902     BareFunction(Box<BareFunctionDecl>),
903     Tuple(Vec<Type>),
904     Vector(Box<Type>),
905     FixedVector(Box<Type>, StrBuf),
906     String,
907     Bool,
908     /// aka TyNil
909     Unit,
910     /// aka TyBot
911     Bottom,
912     Unique(Box<Type>),
913     Managed(Box<Type>),
914     RawPointer(Mutability, Box<Type>),
915     BorrowedRef {
916         pub lifetime: Option<Lifetime>,
917         pub mutability: Mutability,
918         pub type_: Box<Type>,
919     },
920     // region, raw, other boxes, mutable
921 }
922
923 #[deriving(Clone, Encodable, Decodable)]
924 pub enum TypeKind {
925     TypeEnum,
926     TypeFunction,
927     TypeModule,
928     TypeStatic,
929     TypeStruct,
930     TypeTrait,
931     TypeVariant,
932 }
933
934 impl Clean<Type> for ast::Ty {
935     fn clean(&self) -> Type {
936         use syntax::ast::*;
937         match self.node {
938             TyNil => Unit,
939             TyPtr(ref m) => RawPointer(m.mutbl.clean(), box m.ty.clean()),
940             TyRptr(ref l, ref m) =>
941                 BorrowedRef {lifetime: l.clean(), mutability: m.mutbl.clean(),
942                              type_: box m.ty.clean()},
943             TyBox(ty) => Managed(box ty.clean()),
944             TyUniq(ty) => Unique(box ty.clean()),
945             TyVec(ty) => Vector(box ty.clean()),
946             TyFixedLengthVec(ty, ref e) => FixedVector(box ty.clean(),
947                                                        e.span.to_src()),
948             TyTup(ref tys) => Tuple(tys.iter().map(|x| x.clean()).collect()),
949             TyPath(ref p, ref tpbs, id) => {
950                 resolve_type(p.clean(),
951                              tpbs.clean().map(|x| x.move_iter().collect()),
952                              id)
953             }
954             TyClosure(ref c, region) => Closure(box c.clean(), region.clean()),
955             TyProc(ref c) => Proc(box c.clean()),
956             TyBareFn(ref barefn) => BareFunction(box barefn.clean()),
957             TyBot => Bottom,
958             ref x => fail!("Unimplemented type {:?}", x),
959         }
960     }
961 }
962
963 impl Clean<Type> for ty::t {
964     fn clean(&self) -> Type {
965         match ty::get(*self).sty {
966             ty::ty_nil => Unit,
967             ty::ty_bot => Bottom,
968             ty::ty_bool => Bool,
969             ty::ty_char => Primitive(ast::TyChar),
970             ty::ty_int(t) => Primitive(ast::TyInt(t)),
971             ty::ty_uint(u) => Primitive(ast::TyUint(u)),
972             ty::ty_float(f) => Primitive(ast::TyFloat(f)),
973             ty::ty_box(t) => Managed(box t.clean()),
974             ty::ty_uniq(t) => Unique(box t.clean()),
975             ty::ty_str => String,
976             ty::ty_vec(mt, None) => Vector(box mt.ty.clean()),
977             ty::ty_vec(mt, Some(i)) => FixedVector(box mt.ty.clean(),
978                                                    format_strbuf!("{}", i)),
979             ty::ty_ptr(mt) => RawPointer(mt.mutbl.clean(), box mt.ty.clean()),
980             ty::ty_rptr(r, mt) => BorrowedRef {
981                 lifetime: r.clean(),
982                 mutability: mt.mutbl.clean(),
983                 type_: box mt.ty.clean(),
984             },
985             ty::ty_bare_fn(ref fty) => BareFunction(box BareFunctionDecl {
986                 fn_style: fty.fn_style,
987                 generics: Generics {
988                     lifetimes: Vec::new(), type_params: Vec::new()
989                 },
990                 decl: fty.sig.clean(),
991                 abi: fty.abi.to_str().to_strbuf(),
992             }),
993             ty::ty_closure(ref fty) => {
994                 let decl = box ClosureDecl {
995                     lifetimes: Vec::new(), // FIXME: this looks wrong...
996                     decl: fty.sig.clean(),
997                     onceness: fty.onceness,
998                     fn_style: fty.fn_style,
999                     bounds: fty.bounds.iter().map(|i| i.clean()).collect(),
1000                 };
1001                 match fty.store {
1002                     ty::UniqTraitStore => Proc(decl),
1003                     ty::RegionTraitStore(ref r, _) => Closure(decl, r.clean()),
1004                 }
1005             }
1006             ty::ty_struct(did, ref substs) |
1007             ty::ty_enum(did, ref substs) |
1008             ty::ty_trait(box ty::TyTrait { def_id: did, ref substs, .. }) => {
1009                 let cx = super::ctxtkey.get().unwrap();
1010                 let tcx = match cx.maybe_typed {
1011                     core::Typed(ref tycx) => tycx,
1012                     core::NotTyped(_) => fail!(),
1013                 };
1014                 let fqn = csearch::get_item_path(tcx, did);
1015                 let fqn: Vec<StrBuf> = fqn.move_iter().map(|i| {
1016                     i.to_str().to_strbuf()
1017                 }).collect();
1018                 let mut path = external_path(fqn.last().unwrap().to_str());
1019                 let kind = match ty::get(*self).sty {
1020                     ty::ty_struct(..) => TypeStruct,
1021                     ty::ty_trait(..) => TypeTrait,
1022                     _ => TypeEnum,
1023                 };
1024                 path.segments.get_mut(0).lifetimes = match substs.regions {
1025                     ty::ErasedRegions => Vec::new(),
1026                     ty::NonerasedRegions(ref v) => {
1027                         v.iter().filter_map(|v| v.clean()).collect()
1028                     }
1029                 };
1030                 path.segments.get_mut(0).types = substs.tps.clean();
1031                 cx.external_paths.borrow_mut().get_mut_ref().insert(did,
1032                                                                     (fqn, kind));
1033                 ResolvedPath {
1034                     path: path,
1035                     typarams: None,
1036                     did: did,
1037                 }
1038             }
1039             ty::ty_tup(ref t) => Tuple(t.iter().map(|t| t.clean()).collect()),
1040
1041             ty::ty_param(ref p) => Generic(p.def_id),
1042             ty::ty_self(did) => Self(did),
1043
1044             ty::ty_infer(..) => fail!("ty_infer"),
1045             ty::ty_err => fail!("ty_err"),
1046         }
1047     }
1048 }
1049
1050 #[deriving(Clone, Encodable, Decodable)]
1051 pub enum StructField {
1052     HiddenStructField, // inserted later by strip passes
1053     TypedStructField(Type),
1054 }
1055
1056 impl Clean<Item> for ast::StructField {
1057     fn clean(&self) -> Item {
1058         let (name, vis) = match self.node.kind {
1059             ast::NamedField(id, vis) => (Some(id), vis),
1060             ast::UnnamedField(vis) => (None, vis)
1061         };
1062         Item {
1063             name: name.clean(),
1064             attrs: self.node.attrs.clean().move_iter().collect(),
1065             source: self.span.clean(),
1066             visibility: Some(vis),
1067             def_id: ast_util::local_def(self.node.id),
1068             inner: StructFieldItem(TypedStructField(self.node.ty.clean())),
1069         }
1070     }
1071 }
1072
1073 pub type Visibility = ast::Visibility;
1074
1075 impl Clean<Option<Visibility>> for ast::Visibility {
1076     fn clean(&self) -> Option<Visibility> {
1077         Some(*self)
1078     }
1079 }
1080
1081 #[deriving(Clone, Encodable, Decodable)]
1082 pub struct Struct {
1083     pub struct_type: doctree::StructType,
1084     pub generics: Generics,
1085     pub fields: Vec<Item>,
1086     pub fields_stripped: bool,
1087 }
1088
1089 impl Clean<Item> for doctree::Struct {
1090     fn clean(&self) -> Item {
1091         Item {
1092             name: Some(self.name.clean()),
1093             attrs: self.attrs.clean(),
1094             source: self.where.clean(),
1095             def_id: ast_util::local_def(self.id),
1096             visibility: self.vis.clean(),
1097             inner: StructItem(Struct {
1098                 struct_type: self.struct_type,
1099                 generics: self.generics.clean(),
1100                 fields: self.fields.clean(),
1101                 fields_stripped: false,
1102             }),
1103         }
1104     }
1105 }
1106
1107 /// This is a more limited form of the standard Struct, different in that
1108 /// it lacks the things most items have (name, id, parameterization). Found
1109 /// only as a variant in an enum.
1110 #[deriving(Clone, Encodable, Decodable)]
1111 pub struct VariantStruct {
1112     pub struct_type: doctree::StructType,
1113     pub fields: Vec<Item>,
1114     pub fields_stripped: bool,
1115 }
1116
1117 impl Clean<VariantStruct> for syntax::ast::StructDef {
1118     fn clean(&self) -> VariantStruct {
1119         VariantStruct {
1120             struct_type: doctree::struct_type_from_def(self),
1121             fields: self.fields.clean().move_iter().collect(),
1122             fields_stripped: false,
1123         }
1124     }
1125 }
1126
1127 #[deriving(Clone, Encodable, Decodable)]
1128 pub struct Enum {
1129     pub variants: Vec<Item>,
1130     pub generics: Generics,
1131     pub variants_stripped: bool,
1132 }
1133
1134 impl Clean<Item> for doctree::Enum {
1135     fn clean(&self) -> Item {
1136         Item {
1137             name: Some(self.name.clean()),
1138             attrs: self.attrs.clean(),
1139             source: self.where.clean(),
1140             def_id: ast_util::local_def(self.id),
1141             visibility: self.vis.clean(),
1142             inner: EnumItem(Enum {
1143                 variants: self.variants.clean(),
1144                 generics: self.generics.clean(),
1145                 variants_stripped: false,
1146             }),
1147         }
1148     }
1149 }
1150
1151 #[deriving(Clone, Encodable, Decodable)]
1152 pub struct Variant {
1153     pub kind: VariantKind,
1154 }
1155
1156 impl Clean<Item> for doctree::Variant {
1157     fn clean(&self) -> Item {
1158         Item {
1159             name: Some(self.name.clean()),
1160             attrs: self.attrs.clean(),
1161             source: self.where.clean(),
1162             visibility: self.vis.clean(),
1163             def_id: ast_util::local_def(self.id),
1164             inner: VariantItem(Variant {
1165                 kind: self.kind.clean(),
1166             }),
1167         }
1168     }
1169 }
1170
1171 #[deriving(Clone, Encodable, Decodable)]
1172 pub enum VariantKind {
1173     CLikeVariant,
1174     TupleVariant(Vec<Type>),
1175     StructVariant(VariantStruct),
1176 }
1177
1178 impl Clean<VariantKind> for ast::VariantKind {
1179     fn clean(&self) -> VariantKind {
1180         match self {
1181             &ast::TupleVariantKind(ref args) => {
1182                 if args.len() == 0 {
1183                     CLikeVariant
1184                 } else {
1185                     TupleVariant(args.iter().map(|x| x.ty.clean()).collect())
1186                 }
1187             },
1188             &ast::StructVariantKind(ref sd) => StructVariant(sd.clean()),
1189         }
1190     }
1191 }
1192
1193 #[deriving(Clone, Encodable, Decodable)]
1194 pub struct Span {
1195     pub filename: StrBuf,
1196     pub loline: uint,
1197     pub locol: uint,
1198     pub hiline: uint,
1199     pub hicol: uint,
1200 }
1201
1202 impl Clean<Span> for syntax::codemap::Span {
1203     fn clean(&self) -> Span {
1204         let ctxt = super::ctxtkey.get().unwrap();
1205         let cm = ctxt.sess().codemap();
1206         let filename = cm.span_to_filename(*self);
1207         let lo = cm.lookup_char_pos(self.lo);
1208         let hi = cm.lookup_char_pos(self.hi);
1209         Span {
1210             filename: filename.to_strbuf(),
1211             loline: lo.line,
1212             locol: lo.col.to_uint(),
1213             hiline: hi.line,
1214             hicol: hi.col.to_uint(),
1215         }
1216     }
1217 }
1218
1219 #[deriving(Clone, Encodable, Decodable)]
1220 pub struct Path {
1221     pub global: bool,
1222     pub segments: Vec<PathSegment>,
1223 }
1224
1225 impl Clean<Path> for ast::Path {
1226     fn clean(&self) -> Path {
1227         Path {
1228             global: self.global,
1229             segments: self.segments.clean().move_iter().collect(),
1230         }
1231     }
1232 }
1233
1234 #[deriving(Clone, Encodable, Decodable)]
1235 pub struct PathSegment {
1236     pub name: StrBuf,
1237     pub lifetimes: Vec<Lifetime>,
1238     pub types: Vec<Type>,
1239 }
1240
1241 impl Clean<PathSegment> for ast::PathSegment {
1242     fn clean(&self) -> PathSegment {
1243         PathSegment {
1244             name: self.identifier.clean(),
1245             lifetimes: self.lifetimes.clean().move_iter().collect(),
1246             types: self.types.clean().move_iter().collect()
1247         }
1248     }
1249 }
1250
1251 fn path_to_str(p: &ast::Path) -> StrBuf {
1252     use syntax::parse::token;
1253
1254     let mut s = StrBuf::new();
1255     let mut first = true;
1256     for i in p.segments.iter().map(|x| token::get_ident(x.identifier)) {
1257         if !first || p.global {
1258             s.push_str("::");
1259         } else {
1260             first = false;
1261         }
1262         s.push_str(i.get());
1263     }
1264     s
1265 }
1266
1267 impl Clean<StrBuf> for ast::Ident {
1268     fn clean(&self) -> StrBuf {
1269         token::get_ident(*self).get().to_strbuf()
1270     }
1271 }
1272
1273 #[deriving(Clone, Encodable, Decodable)]
1274 pub struct Typedef {
1275     pub type_: Type,
1276     pub generics: Generics,
1277 }
1278
1279 impl Clean<Item> for doctree::Typedef {
1280     fn clean(&self) -> Item {
1281         Item {
1282             name: Some(self.name.clean()),
1283             attrs: self.attrs.clean(),
1284             source: self.where.clean(),
1285             def_id: ast_util::local_def(self.id.clone()),
1286             visibility: self.vis.clean(),
1287             inner: TypedefItem(Typedef {
1288                 type_: self.ty.clean(),
1289                 generics: self.gen.clean(),
1290             }),
1291         }
1292     }
1293 }
1294
1295 #[deriving(Clone, Encodable, Decodable)]
1296 pub struct BareFunctionDecl {
1297     pub fn_style: ast::FnStyle,
1298     pub generics: Generics,
1299     pub decl: FnDecl,
1300     pub abi: StrBuf,
1301 }
1302
1303 impl Clean<BareFunctionDecl> for ast::BareFnTy {
1304     fn clean(&self) -> BareFunctionDecl {
1305         BareFunctionDecl {
1306             fn_style: self.fn_style,
1307             generics: Generics {
1308                 lifetimes: self.lifetimes.clean().move_iter().collect(),
1309                 type_params: Vec::new(),
1310             },
1311             decl: self.decl.clean(),
1312             abi: self.abi.to_str().to_strbuf(),
1313         }
1314     }
1315 }
1316
1317 #[deriving(Clone, Encodable, Decodable)]
1318 pub struct Static {
1319     pub type_: Type,
1320     pub mutability: Mutability,
1321     /// It's useful to have the value of a static documented, but I have no
1322     /// desire to represent expressions (that'd basically be all of the AST,
1323     /// which is huge!). So, have a string.
1324     pub expr: StrBuf,
1325 }
1326
1327 impl Clean<Item> for doctree::Static {
1328     fn clean(&self) -> Item {
1329         debug!("claning static {}: {:?}", self.name.clean(), self);
1330         Item {
1331             name: Some(self.name.clean()),
1332             attrs: self.attrs.clean(),
1333             source: self.where.clean(),
1334             def_id: ast_util::local_def(self.id),
1335             visibility: self.vis.clean(),
1336             inner: StaticItem(Static {
1337                 type_: self.type_.clean(),
1338                 mutability: self.mutability.clean(),
1339                 expr: self.expr.span.to_src(),
1340             }),
1341         }
1342     }
1343 }
1344
1345 #[deriving(Show, Clone, Encodable, Decodable)]
1346 pub enum Mutability {
1347     Mutable,
1348     Immutable,
1349 }
1350
1351 impl Clean<Mutability> for ast::Mutability {
1352     fn clean(&self) -> Mutability {
1353         match self {
1354             &ast::MutMutable => Mutable,
1355             &ast::MutImmutable => Immutable,
1356         }
1357     }
1358 }
1359
1360 #[deriving(Clone, Encodable, Decodable)]
1361 pub struct Impl {
1362     pub generics: Generics,
1363     pub trait_: Option<Type>,
1364     pub for_: Type,
1365     pub methods: Vec<Item>,
1366     pub derived: bool,
1367 }
1368
1369 impl Clean<Item> for doctree::Impl {
1370     fn clean(&self) -> Item {
1371         let mut derived = false;
1372         for attr in self.attrs.iter() {
1373             match attr.node.value.node {
1374                 ast::MetaWord(ref s) => {
1375                     if s.get() == "automatically_derived" {
1376                         derived = true;
1377                     }
1378                 }
1379                 _ => {}
1380             }
1381         }
1382         Item {
1383             name: None,
1384             attrs: self.attrs.clean(),
1385             source: self.where.clean(),
1386             def_id: ast_util::local_def(self.id),
1387             visibility: self.vis.clean(),
1388             inner: ImplItem(Impl {
1389                 generics: self.generics.clean(),
1390                 trait_: self.trait_.clean(),
1391                 for_: self.for_.clean(),
1392                 methods: self.methods.clean(),
1393                 derived: derived,
1394             }),
1395         }
1396     }
1397 }
1398
1399 #[deriving(Clone, Encodable, Decodable)]
1400 pub struct ViewItem {
1401     pub inner: ViewItemInner,
1402 }
1403
1404 impl Clean<Item> for ast::ViewItem {
1405     fn clean(&self) -> Item {
1406         Item {
1407             name: None,
1408             attrs: self.attrs.clean().move_iter().collect(),
1409             source: self.span.clean(),
1410             def_id: ast_util::local_def(0),
1411             visibility: self.vis.clean(),
1412             inner: ViewItemItem(ViewItem {
1413                 inner: self.node.clean()
1414             }),
1415         }
1416     }
1417 }
1418
1419 #[deriving(Clone, Encodable, Decodable)]
1420 pub enum ViewItemInner {
1421     ExternCrate(StrBuf, Option<StrBuf>, ast::NodeId),
1422     Import(ViewPath)
1423 }
1424
1425 impl Clean<ViewItemInner> for ast::ViewItem_ {
1426     fn clean(&self) -> ViewItemInner {
1427         match self {
1428             &ast::ViewItemExternCrate(ref i, ref p, ref id) => {
1429                 let string = match *p {
1430                     None => None,
1431                     Some((ref x, _)) => Some(x.get().to_strbuf()),
1432                 };
1433                 ExternCrate(i.clean(), string, *id)
1434             }
1435             &ast::ViewItemUse(ref vp) => {
1436                 Import(vp.clean())
1437             }
1438         }
1439     }
1440 }
1441
1442 #[deriving(Clone, Encodable, Decodable)]
1443 pub enum ViewPath {
1444     // use str = source;
1445     SimpleImport(StrBuf, ImportSource),
1446     // use source::*;
1447     GlobImport(ImportSource),
1448     // use source::{a, b, c};
1449     ImportList(ImportSource, Vec<ViewListIdent>),
1450 }
1451
1452 #[deriving(Clone, Encodable, Decodable)]
1453 pub struct ImportSource {
1454     pub path: Path,
1455     pub did: Option<ast::DefId>,
1456 }
1457
1458 impl Clean<ViewPath> for ast::ViewPath {
1459     fn clean(&self) -> ViewPath {
1460         match self.node {
1461             ast::ViewPathSimple(ref i, ref p, id) =>
1462                 SimpleImport(i.clean(), resolve_use_source(p.clean(), id)),
1463             ast::ViewPathGlob(ref p, id) =>
1464                 GlobImport(resolve_use_source(p.clean(), id)),
1465             ast::ViewPathList(ref p, ref pl, id) => {
1466                 ImportList(resolve_use_source(p.clean(), id),
1467                            pl.clean().move_iter().collect())
1468             }
1469         }
1470     }
1471 }
1472
1473 #[deriving(Clone, Encodable, Decodable)]
1474 pub struct ViewListIdent {
1475     pub name: StrBuf,
1476     pub source: Option<ast::DefId>,
1477 }
1478
1479 impl Clean<ViewListIdent> for ast::PathListIdent {
1480     fn clean(&self) -> ViewListIdent {
1481         ViewListIdent {
1482             name: self.node.name.clean(),
1483             source: resolve_def(self.node.id),
1484         }
1485     }
1486 }
1487
1488 impl Clean<Vec<Item>> for ast::ForeignMod {
1489     fn clean(&self) -> Vec<Item> {
1490         self.items.clean()
1491     }
1492 }
1493
1494 impl Clean<Item> for ast::ForeignItem {
1495     fn clean(&self) -> Item {
1496         let inner = match self.node {
1497             ast::ForeignItemFn(ref decl, ref generics) => {
1498                 ForeignFunctionItem(Function {
1499                     decl: decl.clean(),
1500                     generics: generics.clean(),
1501                     fn_style: ast::UnsafeFn,
1502                 })
1503             }
1504             ast::ForeignItemStatic(ref ty, mutbl) => {
1505                 ForeignStaticItem(Static {
1506                     type_: ty.clean(),
1507                     mutability: if mutbl {Mutable} else {Immutable},
1508                     expr: "".to_strbuf(),
1509                 })
1510             }
1511         };
1512         Item {
1513             name: Some(self.ident.clean()),
1514             attrs: self.attrs.clean().move_iter().collect(),
1515             source: self.span.clean(),
1516             def_id: ast_util::local_def(self.id),
1517             visibility: self.vis.clean(),
1518             inner: inner,
1519         }
1520     }
1521 }
1522
1523 // Utilities
1524
1525 trait ToSource {
1526     fn to_src(&self) -> StrBuf;
1527 }
1528
1529 impl ToSource for syntax::codemap::Span {
1530     fn to_src(&self) -> StrBuf {
1531         debug!("converting span {:?} to snippet", self.clean());
1532         let ctxt = super::ctxtkey.get().unwrap();
1533         let cm = ctxt.sess().codemap().clone();
1534         let sn = match cm.span_to_snippet(*self) {
1535             Some(x) => x.to_strbuf(),
1536             None    => "".to_strbuf()
1537         };
1538         debug!("got snippet {}", sn);
1539         sn
1540     }
1541 }
1542
1543 fn lit_to_str(lit: &ast::Lit) -> StrBuf {
1544     match lit.node {
1545         ast::LitStr(ref st, _) => st.get().to_strbuf(),
1546         ast::LitBinary(ref data) => format_strbuf!("{:?}", data.as_slice()),
1547         ast::LitChar(c) => format_strbuf!("'{}'", c),
1548         ast::LitInt(i, _t) => i.to_str().to_strbuf(),
1549         ast::LitUint(u, _t) => u.to_str().to_strbuf(),
1550         ast::LitIntUnsuffixed(i) => i.to_str().to_strbuf(),
1551         ast::LitFloat(ref f, _t) => f.get().to_strbuf(),
1552         ast::LitFloatUnsuffixed(ref f) => f.get().to_strbuf(),
1553         ast::LitBool(b) => b.to_str().to_strbuf(),
1554         ast::LitNil => "".to_strbuf(),
1555     }
1556 }
1557
1558 fn name_from_pat(p: &ast::Pat) -> StrBuf {
1559     use syntax::ast::*;
1560     debug!("Trying to get a name from pattern: {:?}", p);
1561
1562     match p.node {
1563         PatWild => "_".to_strbuf(),
1564         PatWildMulti => "..".to_strbuf(),
1565         PatIdent(_, ref p, _) => path_to_str(p),
1566         PatEnum(ref p, _) => path_to_str(p),
1567         PatStruct(..) => fail!("tried to get argument name from pat_struct, \
1568                                 which is not allowed in function arguments"),
1569         PatTup(..) => "(tuple arg NYI)".to_strbuf(),
1570         PatUniq(p) => name_from_pat(p),
1571         PatRegion(p) => name_from_pat(p),
1572         PatLit(..) => {
1573             warn!("tried to get argument name from PatLit, \
1574                   which is silly in function arguments");
1575             "()".to_strbuf()
1576         },
1577         PatRange(..) => fail!("tried to get argument name from PatRange, \
1578                               which is not allowed in function arguments"),
1579         PatVec(..) => fail!("tried to get argument name from pat_vec, \
1580                              which is not allowed in function arguments")
1581     }
1582 }
1583
1584 /// Given a Type, resolve it using the def_map
1585 fn resolve_type(path: Path, tpbs: Option<Vec<TyParamBound>>,
1586                 id: ast::NodeId) -> Type {
1587     let cx = super::ctxtkey.get().unwrap();
1588     let tycx = match cx.maybe_typed {
1589         core::Typed(ref tycx) => tycx,
1590         // If we're extracting tests, this return value doesn't matter.
1591         core::NotTyped(_) => return Bool
1592     };
1593     debug!("searching for {:?} in defmap", id);
1594     let def = match tycx.def_map.borrow().find(&id) {
1595         Some(&k) => k,
1596         None => fail!("unresolved id not in defmap")
1597     };
1598
1599     match def {
1600         ast::DefSelfTy(i) => return Self(ast_util::local_def(i)),
1601         ast::DefPrimTy(p) => match p {
1602             ast::TyStr => return String,
1603             ast::TyBool => return Bool,
1604             _ => return Primitive(p)
1605         },
1606         ast::DefTyParam(i, _) => return Generic(i),
1607         ast::DefTyParamBinder(i) => return TyParamBinder(i),
1608         _ => {}
1609     };
1610     let did = register_def(&**cx, def);
1611     ResolvedPath { path: path, typarams: tpbs, did: did }
1612 }
1613
1614 fn register_def(cx: &core::DocContext, def: ast::Def) -> ast::DefId {
1615     let (did, kind) = match def {
1616         ast::DefFn(i, _) => (i, TypeFunction),
1617         ast::DefTy(i) => (i, TypeEnum),
1618         ast::DefTrait(i) => (i, TypeTrait),
1619         ast::DefStruct(i) => (i, TypeStruct),
1620         ast::DefMod(i) => (i, TypeModule),
1621         ast::DefStatic(i, _) => (i, TypeStatic),
1622         ast::DefVariant(i, _, _) => (i, TypeEnum),
1623         _ => return ast_util::def_id_of_def(def),
1624     };
1625     if ast_util::is_local(did) { return did }
1626     let tcx = match cx.maybe_typed {
1627         core::Typed(ref t) => t,
1628         core::NotTyped(_) => return did
1629     };
1630     let fqn = csearch::get_item_path(tcx, did);
1631     let fqn = fqn.move_iter().map(|i| i.to_str().to_strbuf()).collect();
1632     debug!("recording {} => {}", did, fqn);
1633     cx.external_paths.borrow_mut().get_mut_ref().insert(did, (fqn, kind));
1634     match kind {
1635         TypeTrait => {
1636             let t = build_external_trait(tcx, did);
1637             cx.external_traits.borrow_mut().get_mut_ref().insert(did, t);
1638         }
1639         _ => {}
1640     }
1641     return did;
1642 }
1643
1644 fn build_external_trait(tcx: &ty::ctxt, did: ast::DefId) -> Trait {
1645     let def = csearch::get_trait_def(tcx, did);
1646     let methods = ty::trait_methods(tcx, did);
1647     Trait {
1648         generics: def.generics.clean(),
1649         methods: methods.iter().map(|i| i.clean()).collect(),
1650         parents: Vec::new(), // FIXME: this is likely wrong
1651     }
1652 }
1653
1654 fn resolve_use_source(path: Path, id: ast::NodeId) -> ImportSource {
1655     ImportSource {
1656         path: path,
1657         did: resolve_def(id),
1658     }
1659 }
1660
1661 fn resolve_def(id: ast::NodeId) -> Option<ast::DefId> {
1662     let cx = super::ctxtkey.get().unwrap();
1663     match cx.maybe_typed {
1664         core::Typed(ref tcx) => {
1665             tcx.def_map.borrow().find(&id).map(|&def| register_def(&**cx, def))
1666         }
1667         core::NotTyped(_) => None
1668     }
1669 }
1670
1671 #[deriving(Clone, Encodable, Decodable)]
1672 pub struct Macro {
1673     pub source: StrBuf,
1674 }
1675
1676 impl Clean<Item> for doctree::Macro {
1677     fn clean(&self) -> Item {
1678         Item {
1679             name: Some(format_strbuf!("{}!", self.name.clean())),
1680             attrs: self.attrs.clean(),
1681             source: self.where.clean(),
1682             visibility: ast::Public.clean(),
1683             def_id: ast_util::local_def(self.id),
1684             inner: MacroItem(Macro {
1685                 source: self.where.to_src(),
1686             }),
1687         }
1688     }
1689 }