]> git.lizzy.rs Git - rust.git/blob - src/librustdoc/visit_ast.rs
librustdoc: Fix errors arising from the automated `~[T]` conversion
[rust.git] / src / librustdoc / visit_ast.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 //! Rust AST Visitor. Extracts useful information and massages it into a form
12 //! usable for clean
13
14 use std::vec_ng::Vec;
15 use syntax::abi::AbiSet;
16 use syntax::ast;
17 use syntax::ast_util;
18 use syntax::ast_map;
19 use syntax::codemap::Span;
20
21 use core;
22 use doctree::*;
23
24 pub struct RustdocVisitor<'a> {
25     module: Module,
26     attrs: ~[ast::Attribute],
27     cx: &'a core::DocContext,
28     analysis: Option<&'a core::CrateAnalysis>,
29 }
30
31 impl<'a> RustdocVisitor<'a> {
32     pub fn new<'b>(cx: &'b core::DocContext,
33                    analysis: Option<&'b core::CrateAnalysis>) -> RustdocVisitor<'b> {
34         RustdocVisitor {
35             module: Module::new(None),
36             attrs: ~[],
37             cx: cx,
38             analysis: analysis,
39         }
40     }
41
42     pub fn visit(&mut self, krate: &ast::Crate) {
43         self.attrs = krate.attrs.iter().map(|x| (*x).clone()).collect();
44
45         self.module = self.visit_mod_contents(krate.span,
46                                               krate.attrs
47                                                    .iter()
48                                                    .map(|x| *x)
49                                                    .collect(),
50                                               ast::Public,
51                                               ast::CRATE_NODE_ID,
52                                               &krate.module,
53                                               None);
54         self.module.is_crate = true;
55     }
56
57     pub fn visit_struct_def(&mut self, item: &ast::Item, sd: @ast::StructDef,
58                             generics: &ast::Generics) -> Struct {
59         debug!("Visiting struct");
60         let struct_type = struct_type_from_def(sd);
61         Struct {
62             id: item.id,
63             struct_type: struct_type,
64             name: item.ident,
65             vis: item.vis,
66             attrs: item.attrs.iter().map(|x| *x).collect(),
67             generics: generics.clone(),
68             fields: sd.fields.iter().map(|x| (*x).clone()).collect(),
69             where: item.span
70         }
71     }
72
73     pub fn visit_enum_def(&mut self, it: &ast::Item, def: &ast::EnumDef,
74                           params: &ast::Generics) -> Enum {
75         debug!("Visiting enum");
76         let mut vars: ~[Variant] = ~[];
77         for x in def.variants.iter() {
78             vars.push(Variant {
79                 name: x.node.name,
80                 attrs: x.node.attrs.iter().map(|x| *x).collect(),
81                 vis: x.node.vis,
82                 id: x.node.id,
83                 kind: x.node.kind.clone(),
84                 where: x.span,
85             });
86         }
87         Enum {
88             name: it.ident,
89             variants: vars,
90             vis: it.vis,
91             generics: params.clone(),
92             attrs: it.attrs.iter().map(|x| *x).collect(),
93             id: it.id,
94             where: it.span,
95         }
96     }
97
98     pub fn visit_fn(&mut self, item: &ast::Item, fd: &ast::FnDecl,
99                     purity: &ast::Purity, _abi: &AbiSet,
100                     gen: &ast::Generics) -> Function {
101         debug!("Visiting fn");
102         Function {
103             id: item.id,
104             vis: item.vis,
105             attrs: item.attrs.iter().map(|x| *x).collect(),
106             decl: fd.clone(),
107             name: item.ident,
108             where: item.span,
109             generics: gen.clone(),
110             purity: *purity,
111         }
112     }
113
114     pub fn visit_mod_contents(&mut self, span: Span, attrs: ~[ast::Attribute],
115                               vis: ast::Visibility, id: ast::NodeId,
116                               m: &ast::Mod,
117                               name: Option<ast::Ident>) -> Module {
118         let mut om = Module::new(name);
119         for item in m.view_items.iter() {
120             self.visit_view_item(item, &mut om);
121         }
122         om.where = span;
123         om.attrs = attrs;
124         om.vis = vis;
125         om.id = id;
126         for i in m.items.iter() {
127             self.visit_item(*i, &mut om);
128         }
129         om
130     }
131
132     pub fn visit_view_item(&mut self, item: &ast::ViewItem, om: &mut Module) {
133         if item.vis != ast::Public {
134             return om.view_items.push(item.clone());
135         }
136         let item = match item.node {
137             ast::ViewItemUse(ref paths) => {
138                 // rustc no longer supports "use foo, bar;"
139                 assert_eq!(paths.len(), 1);
140                 match self.visit_view_path(*paths.get(0), om) {
141                     None => return,
142                     Some(path) => {
143                         ast::ViewItem {
144                             node: ast::ViewItemUse(vec!(path)),
145                             .. item.clone()
146                         }
147                     }
148                 }
149             }
150             ast::ViewItemExternMod(..) => item.clone()
151         };
152         om.view_items.push(item);
153     }
154
155     fn visit_view_path(&mut self, path: @ast::ViewPath,
156                        om: &mut Module) -> Option<@ast::ViewPath> {
157         match path.node {
158             ast::ViewPathSimple(_, _, id) => {
159                 if self.resolve_id(id, false, om) { return None }
160             }
161             ast::ViewPathList(ref p, ref paths, ref b) => {
162                 let mut mine = Vec::new();
163                 for path in paths.iter() {
164                     if !self.resolve_id(path.node.id, false, om) {
165                         mine.push(path.clone());
166                     }
167                 }
168
169                 if mine.len() == 0 { return None }
170                 return Some(@::syntax::codemap::Spanned {
171                     node: ast::ViewPathList(p.clone(), mine, b.clone()),
172                     span: path.span,
173                 })
174             }
175
176             // these are feature gated anyway
177             ast::ViewPathGlob(_, id) => {
178                 if self.resolve_id(id, true, om) { return None }
179             }
180         }
181         return Some(path);
182     }
183
184     fn resolve_id(&mut self, id: ast::NodeId, glob: bool,
185                   om: &mut Module) -> bool {
186         let def = {
187             let dm = match self.cx.tycx {
188                 Some(tcx) => tcx.def_map.borrow(),
189                 None => return false,
190             };
191             ast_util::def_id_of_def(*dm.get().get(&id))
192         };
193         if !ast_util::is_local(def) { return false }
194         let analysis = match self.analysis {
195             Some(analysis) => analysis, None => return false
196         };
197         if analysis.public_items.contains(&def.node) { return false }
198
199         let item = self.cx.tycx.unwrap().map.get(def.node);
200         match item {
201             ast_map::NodeItem(it) => {
202                 if glob {
203                     match it.node {
204                         ast::ItemMod(ref m) => {
205                             for vi in m.view_items.iter() {
206                                 self.visit_view_item(vi, om);
207                             }
208                             for i in m.items.iter() {
209                                 self.visit_item(*i, om);
210                             }
211                         }
212                         _ => { fail!("glob not mapped to a module"); }
213                     }
214                 } else {
215                     self.visit_item(it, om);
216                 }
217                 true
218             }
219             _ => false,
220         }
221     }
222
223     pub fn visit_item(&mut self, item: &ast::Item, om: &mut Module) {
224         debug!("Visiting item {:?}", item);
225         match item.node {
226             ast::ItemMod(ref m) => {
227                 om.mods.push(self.visit_mod_contents(item.span,
228                                                      item.attrs
229                                                          .iter()
230                                                          .map(|x| *x)
231                                                          .collect(),
232                                                      item.vis,
233                                                      item.id,
234                                                      m,
235                                                      Some(item.ident)));
236             },
237             ast::ItemEnum(ref ed, ref gen) =>
238                 om.enums.push(self.visit_enum_def(item, ed, gen)),
239             ast::ItemStruct(sd, ref gen) =>
240                 om.structs.push(self.visit_struct_def(item, sd, gen)),
241             ast::ItemFn(fd, ref pur, ref abi, ref gen, _) =>
242                 om.fns.push(self.visit_fn(item, fd, pur, abi, gen)),
243             ast::ItemTy(ty, ref gen) => {
244                 let t = Typedef {
245                     ty: ty,
246                     gen: gen.clone(),
247                     name: item.ident,
248                     id: item.id,
249                     attrs: item.attrs.iter().map(|x| *x).collect(),
250                     where: item.span,
251                     vis: item.vis,
252                 };
253                 om.typedefs.push(t);
254             },
255             ast::ItemStatic(ty, ref mut_, ref exp) => {
256                 let s = Static {
257                     type_: ty,
258                     mutability: mut_.clone(),
259                     expr: exp.clone(),
260                     id: item.id,
261                     name: item.ident,
262                     attrs: item.attrs.iter().map(|x| *x).collect(),
263                     where: item.span,
264                     vis: item.vis,
265                 };
266                 om.statics.push(s);
267             },
268             ast::ItemTrait(ref gen, ref tr, ref met) => {
269                 let t = Trait {
270                     name: item.ident,
271                     methods: met.iter().map(|x| (*x).clone()).collect(),
272                     generics: gen.clone(),
273                     parents: tr.iter().map(|x| (*x).clone()).collect(),
274                     id: item.id,
275                     attrs: item.attrs.iter().map(|x| *x).collect(),
276                     where: item.span,
277                     vis: item.vis,
278                 };
279                 om.traits.push(t);
280             },
281             ast::ItemImpl(ref gen, ref tr, ty, ref meths) => {
282                 let i = Impl {
283                     generics: gen.clone(),
284                     trait_: tr.clone(),
285                     for_: ty,
286                     methods: meths.iter().map(|x| *x).collect(),
287                     attrs: item.attrs.iter().map(|x| *x).collect(),
288                     id: item.id,
289                     where: item.span,
290                     vis: item.vis,
291                 };
292                 om.impls.push(i);
293             },
294             ast::ItemForeignMod(ref fm) => {
295                 om.foreigns.push(fm.clone());
296             }
297             ast::ItemMac(ref _m) => {
298                 om.macros.push(Macro {
299                     id: item.id,
300                     attrs: item.attrs.iter().map(|x| *x).collect(),
301                     name: item.ident,
302                     where: item.span,
303                 })
304             }
305         }
306     }
307 }