visit_ast.rs 10.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

C
Corey Richardson 已提交
11 12 13
//! Rust AST Visitor. Extracts useful information and massages it into a form
//! usable for clean

14
use syntax::abi;
15
use syntax::ast;
A
Alex Crichton 已提交
16 17
use syntax::ast_util;
use syntax::ast_map;
18
use syntax::codemap::Span;
C
Corey Richardson 已提交
19

A
Alex Crichton 已提交
20
use core;
C
Corey Richardson 已提交
21 22
use doctree::*;

A
Alex Crichton 已提交
23
pub struct RustdocVisitor<'a> {
24 25 26 27
    pub module: Module,
    pub attrs: Vec<ast::Attribute>,
    pub cx: &'a core::DocContext,
    pub analysis: Option<&'a core::CrateAnalysis>,
C
Corey Richardson 已提交
28 29
}

A
Alex Crichton 已提交
30 31 32
impl<'a> RustdocVisitor<'a> {
    pub fn new<'b>(cx: &'b core::DocContext,
                   analysis: Option<&'b core::CrateAnalysis>) -> RustdocVisitor<'b> {
C
Corey Richardson 已提交
33 34
        RustdocVisitor {
            module: Module::new(None),
35
            attrs: Vec::new(),
A
Alex Crichton 已提交
36 37
            cx: cx,
            analysis: analysis,
C
Corey Richardson 已提交
38 39 40
        }
    }

41
    pub fn visit(&mut self, krate: &ast::Crate) {
42
        self.attrs = krate.attrs.iter().map(|x| (*x).clone()).collect();
A
Alex Crichton 已提交
43

44 45 46 47 48 49 50 51 52
        self.module = self.visit_mod_contents(krate.span,
                                              krate.attrs
                                                   .iter()
                                                   .map(|x| *x)
                                                   .collect(),
                                              ast::Public,
                                              ast::CRATE_NODE_ID,
                                              &krate.module,
                                              None);
53
        self.module.is_crate = true;
A
Alex Crichton 已提交
54 55
    }

56 57
    pub fn visit_struct_def(&mut self, item: &ast::Item, sd: @ast::StructDef,
                            generics: &ast::Generics) -> Struct {
A
Alex Crichton 已提交
58 59 60 61 62 63 64
        debug!("Visiting struct");
        let struct_type = struct_type_from_def(sd);
        Struct {
            id: item.id,
            struct_type: struct_type,
            name: item.ident,
            vis: item.vis,
65
            attrs: item.attrs.iter().map(|x| *x).collect(),
A
Alex Crichton 已提交
66
            generics: generics.clone(),
67
            fields: sd.fields.iter().map(|x| (*x).clone()).collect(),
A
Alex Crichton 已提交
68
            where: item.span
C
Corey Richardson 已提交
69
        }
A
Alex Crichton 已提交
70
    }
C
Corey Richardson 已提交
71

72 73
    pub fn visit_enum_def(&mut self, it: &ast::Item, def: &ast::EnumDef,
                          params: &ast::Generics) -> Enum {
A
Alex Crichton 已提交
74
        debug!("Visiting enum");
75
        let mut vars: Vec<Variant> = Vec::new();
A
Alex Crichton 已提交
76 77 78
        for x in def.variants.iter() {
            vars.push(Variant {
                name: x.node.name,
79
                attrs: x.node.attrs.iter().map(|x| *x).collect(),
A
Alex Crichton 已提交
80 81 82 83 84 85 86 87 88 89 90
                vis: x.node.vis,
                id: x.node.id,
                kind: x.node.kind.clone(),
                where: x.span,
            });
        }
        Enum {
            name: it.ident,
            variants: vars,
            vis: it.vis,
            generics: params.clone(),
91
            attrs: it.attrs.iter().map(|x| *x).collect(),
A
Alex Crichton 已提交
92 93
            id: it.id,
            where: it.span,
C
Corey Richardson 已提交
94
        }
A
Alex Crichton 已提交
95
    }
C
Corey Richardson 已提交
96

97
    pub fn visit_fn(&mut self, item: &ast::Item, fd: &ast::FnDecl,
98
                    purity: &ast::Purity, _abi: &abi::Abi,
A
Alex Crichton 已提交
99 100 101 102 103
                    gen: &ast::Generics) -> Function {
        debug!("Visiting fn");
        Function {
            id: item.id,
            vis: item.vis,
104
            attrs: item.attrs.iter().map(|x| *x).collect(),
A
Alex Crichton 已提交
105 106 107 108 109
            decl: fd.clone(),
            name: item.ident,
            where: item.span,
            generics: gen.clone(),
            purity: *purity,
C
Corey Richardson 已提交
110
        }
A
Alex Crichton 已提交
111
    }
C
Corey Richardson 已提交
112

113
    pub fn visit_mod_contents(&mut self, span: Span, attrs: Vec<ast::Attribute> ,
114 115
                              vis: ast::Visibility, id: ast::NodeId,
                              m: &ast::Mod,
116
                              name: Option<ast::Ident>) -> Module {
A
Alex Crichton 已提交
117 118 119 120 121 122 123 124 125 126 127 128 129 130
        let mut om = Module::new(name);
        for item in m.view_items.iter() {
            self.visit_view_item(item, &mut om);
        }
        om.where = span;
        om.attrs = attrs;
        om.vis = vis;
        om.id = id;
        for i in m.items.iter() {
            self.visit_item(*i, &mut om);
        }
        om
    }

131 132
    pub fn visit_view_item(&mut self, item: &ast::ViewItem, om: &mut Module) {
        if item.vis != ast::Public {
A
Alex Crichton 已提交
133 134 135
            return om.view_items.push(item.clone());
        }
        let item = match item.node {
136
            ast::ViewItemUse(ref paths) => {
A
Alex Crichton 已提交
137 138
                // rustc no longer supports "use foo, bar;"
                assert_eq!(paths.len(), 1);
139
                match self.visit_view_path(*paths.get(0), om) {
A
Alex Crichton 已提交
140 141
                    None => return,
                    Some(path) => {
142
                        ast::ViewItem {
143
                            node: ast::ViewItemUse(vec!(path)),
A
Alex Crichton 已提交
144 145 146 147 148
                            .. item.clone()
                        }
                    }
                }
            }
149
            ast::ViewItemExternCrate(..) => item.clone()
A
Alex Crichton 已提交
150 151 152 153
        };
        om.view_items.push(item);
    }

154 155
    fn visit_view_path(&mut self, path: @ast::ViewPath,
                       om: &mut Module) -> Option<@ast::ViewPath> {
A
Alex Crichton 已提交
156
        match path.node {
157
            ast::ViewPathSimple(_, _, id) => {
A
Alex Crichton 已提交
158 159
                if self.resolve_id(id, false, om) { return None }
            }
160
            ast::ViewPathList(ref p, ref paths, ref b) => {
161
                let mut mine = Vec::new();
A
Alex Crichton 已提交
162 163 164 165 166 167 168 169
                for path in paths.iter() {
                    if !self.resolve_id(path.node.id, false, om) {
                        mine.push(path.clone());
                    }
                }

                if mine.len() == 0 { return None }
                return Some(@::syntax::codemap::Spanned {
170
                    node: ast::ViewPathList(p.clone(), mine, b.clone()),
A
Alex Crichton 已提交
171 172 173 174 175
                    span: path.span,
                })
            }

            // these are feature gated anyway
176
            ast::ViewPathGlob(_, id) => {
A
Alex Crichton 已提交
177
                if self.resolve_id(id, true, om) { return None }
C
Corey Richardson 已提交
178 179
            }
        }
A
Alex Crichton 已提交
180 181
        return Some(path);
    }
C
Corey Richardson 已提交
182

A
Alex Crichton 已提交
183 184
    fn resolve_id(&mut self, id: ast::NodeId, glob: bool,
                  om: &mut Module) -> bool {
E
Eduard Burtescu 已提交
185 186 187
        let tcx = match self.cx.maybe_typed {
            core::Typed(ref tcx) => tcx,
            core::NotTyped(_) => return false
A
Alex Crichton 已提交
188
        };
189
        let def = ast_util::def_id_of_def(*tcx.def_map.borrow().get(&id));
A
Alex Crichton 已提交
190 191 192 193 194 195
        if !ast_util::is_local(def) { return false }
        let analysis = match self.analysis {
            Some(analysis) => analysis, None => return false
        };
        if analysis.public_items.contains(&def.node) { return false }

E
Eduard Burtescu 已提交
196
        match tcx.map.get(def.node) {
197
            ast_map::NodeItem(it) => {
A
Alex Crichton 已提交
198 199
                if glob {
                    match it.node {
200
                        ast::ItemMod(ref m) => {
A
Alex Crichton 已提交
201 202 203 204 205 206 207 208 209 210 211
                            for vi in m.view_items.iter() {
                                self.visit_view_item(vi, om);
                            }
                            for i in m.items.iter() {
                                self.visit_item(*i, om);
                            }
                        }
                        _ => { fail!("glob not mapped to a module"); }
                    }
                } else {
                    self.visit_item(it, om);
212
                }
A
Alex Crichton 已提交
213
                true
C
Corey Richardson 已提交
214
            }
A
Alex Crichton 已提交
215
            _ => false,
C
Corey Richardson 已提交
216
        }
A
Alex Crichton 已提交
217
    }
C
Corey Richardson 已提交
218

219
    pub fn visit_item(&mut self, item: &ast::Item, om: &mut Module) {
A
Alex Crichton 已提交
220 221
        debug!("Visiting item {:?}", item);
        match item.node {
222
            ast::ItemMod(ref m) => {
223 224 225 226 227 228 229 230 231
                om.mods.push(self.visit_mod_contents(item.span,
                                                     item.attrs
                                                         .iter()
                                                         .map(|x| *x)
                                                         .collect(),
                                                     item.vis,
                                                     item.id,
                                                     m,
                                                     Some(item.ident)));
A
Alex Crichton 已提交
232
            },
233
            ast::ItemEnum(ref ed, ref gen) =>
A
Alex Crichton 已提交
234
                om.enums.push(self.visit_enum_def(item, ed, gen)),
235
            ast::ItemStruct(sd, ref gen) =>
A
Alex Crichton 已提交
236
                om.structs.push(self.visit_struct_def(item, sd, gen)),
237
            ast::ItemFn(fd, ref pur, ref abi, ref gen, _) =>
A
Alex Crichton 已提交
238
                om.fns.push(self.visit_fn(item, fd, pur, abi, gen)),
239
            ast::ItemTy(ty, ref gen) => {
A
Alex Crichton 已提交
240 241 242 243 244
                let t = Typedef {
                    ty: ty,
                    gen: gen.clone(),
                    name: item.ident,
                    id: item.id,
245
                    attrs: item.attrs.iter().map(|x| *x).collect(),
A
Alex Crichton 已提交
246 247 248 249 250
                    where: item.span,
                    vis: item.vis,
                };
                om.typedefs.push(t);
            },
251
            ast::ItemStatic(ty, ref mut_, ref exp) => {
A
Alex Crichton 已提交
252 253 254 255 256 257
                let s = Static {
                    type_: ty,
                    mutability: mut_.clone(),
                    expr: exp.clone(),
                    id: item.id,
                    name: item.ident,
258
                    attrs: item.attrs.iter().map(|x| *x).collect(),
A
Alex Crichton 已提交
259 260 261 262 263
                    where: item.span,
                    vis: item.vis,
                };
                om.statics.push(s);
            },
264
            ast::ItemTrait(ref gen, ref tr, ref met) => {
A
Alex Crichton 已提交
265 266
                let t = Trait {
                    name: item.ident,
267
                    methods: met.iter().map(|x| (*x).clone()).collect(),
A
Alex Crichton 已提交
268
                    generics: gen.clone(),
269
                    parents: tr.iter().map(|x| (*x).clone()).collect(),
A
Alex Crichton 已提交
270
                    id: item.id,
271
                    attrs: item.attrs.iter().map(|x| *x).collect(),
A
Alex Crichton 已提交
272 273 274 275 276
                    where: item.span,
                    vis: item.vis,
                };
                om.traits.push(t);
            },
277
            ast::ItemImpl(ref gen, ref tr, ty, ref meths) => {
A
Alex Crichton 已提交
278 279 280 281
                let i = Impl {
                    generics: gen.clone(),
                    trait_: tr.clone(),
                    for_: ty,
282 283
                    methods: meths.iter().map(|x| *x).collect(),
                    attrs: item.attrs.iter().map(|x| *x).collect(),
A
Alex Crichton 已提交
284 285 286 287 288 289
                    id: item.id,
                    where: item.span,
                    vis: item.vis,
                };
                om.impls.push(i);
            },
290
            ast::ItemForeignMod(ref fm) => {
A
Alex Crichton 已提交
291 292
                om.foreigns.push(fm.clone());
            }
293 294 295
            ast::ItemMac(ref _m) => {
                om.macros.push(Macro {
                    id: item.id,
296
                    attrs: item.attrs.iter().map(|x| *x).collect(),
297 298 299 300
                    name: item.ident,
                    where: item.span,
                })
            }
A
Alex Crichton 已提交
301
        }
C
Corey Richardson 已提交
302 303
    }
}