visit_ast.rs 11.0 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 std::vec_ng::Vec;
C
Corey Richardson 已提交
15
use syntax::abi::AbiSet;
16
use syntax::ast;
A
Alex Crichton 已提交
17 18
use syntax::ast_util;
use syntax::ast_map;
19
use syntax::codemap::Span;
C
Corey Richardson 已提交
20

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

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

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

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

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

57 58
    pub fn visit_struct_def(&mut self, item: &ast::Item, sd: @ast::StructDef,
                            generics: &ast::Generics) -> Struct {
A
Alex Crichton 已提交
59 60 61 62 63 64 65
        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,
66
            attrs: item.attrs.iter().map(|x| *x).collect(),
A
Alex Crichton 已提交
67
            generics: generics.clone(),
68
            fields: sd.fields.iter().map(|x| (*x).clone()).collect(),
A
Alex Crichton 已提交
69
            where: item.span
C
Corey Richardson 已提交
70
        }
A
Alex Crichton 已提交
71
    }
C
Corey Richardson 已提交
72

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

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

A
Alex Crichton 已提交
114
    pub fn visit_mod_contents(&mut self, span: Span, attrs: ~[ast::Attribute],
115 116
                              vis: ast::Visibility, id: ast::NodeId,
                              m: &ast::Mod,
117
                              name: Option<ast::Ident>) -> Module {
A
Alex Crichton 已提交
118 119 120 121 122 123 124 125 126 127 128 129 130 131
        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
    }

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

155 156
    fn visit_view_path(&mut self, path: @ast::ViewPath,
                       om: &mut Module) -> Option<@ast::ViewPath> {
A
Alex Crichton 已提交
157
        match path.node {
158
            ast::ViewPathSimple(_, _, id) => {
A
Alex Crichton 已提交
159 160
                if self.resolve_id(id, false, om) { return None }
            }
161
            ast::ViewPathList(ref p, ref paths, ref b) => {
162
                let mut mine = Vec::new();
A
Alex Crichton 已提交
163 164 165 166 167 168 169 170
                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 {
171
                    node: ast::ViewPathList(p.clone(), mine, b.clone()),
A
Alex Crichton 已提交
172 173 174 175 176
                    span: path.span,
                })
            }

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

A
Alex Crichton 已提交
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
    fn resolve_id(&mut self, id: ast::NodeId, glob: bool,
                  om: &mut Module) -> bool {
        let def = {
            let dm = match self.cx.tycx {
                Some(tcx) => tcx.def_map.borrow(),
                None => return false,
            };
            ast_util::def_id_of_def(*dm.get().get(&id))
        };
        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 }

199
        let item = self.cx.tycx.unwrap().map.get(def.node);
A
Alex Crichton 已提交
200
        match item {
201
            ast_map::NodeItem(it) => {
A
Alex Crichton 已提交
202 203
                if glob {
                    match it.node {
204
                        ast::ItemMod(ref m) => {
A
Alex Crichton 已提交
205 206 207 208 209 210 211 212 213 214 215
                            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);
216
                }
A
Alex Crichton 已提交
217
                true
C
Corey Richardson 已提交
218
            }
A
Alex Crichton 已提交
219
            _ => false,
C
Corey Richardson 已提交
220
        }
A
Alex Crichton 已提交
221
    }
C
Corey Richardson 已提交
222

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