visit_ast.rs 13.1 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::attr;
19
use syntax::attr::AttrMetaMethods;
20
use syntax::codemap::Span;
C
Corey Richardson 已提交
21

22 23
use rustc::middle::stability;

24
use std::gc::{Gc, GC};
25

A
Alex Crichton 已提交
26
use core;
C
Corey Richardson 已提交
27 28
use doctree::*;

J
John Clements 已提交
29 30 31 32 33 34 35 36
// looks to me like the first two of these are actually
// output parameters, maybe only mutated once; perhaps
// better simply to have the visit method return a tuple
// containing them?

// also, is there some reason that this doesn't use the 'visit'
// framework from syntax?

A
Alex Crichton 已提交
37
pub struct RustdocVisitor<'a> {
38 39 40 41
    pub module: Module,
    pub attrs: Vec<ast::Attribute>,
    pub cx: &'a core::DocContext,
    pub analysis: Option<&'a core::CrateAnalysis>,
C
Corey Richardson 已提交
42 43
}

A
Alex Crichton 已提交
44 45 46
impl<'a> RustdocVisitor<'a> {
    pub fn new<'b>(cx: &'b core::DocContext,
                   analysis: Option<&'b core::CrateAnalysis>) -> RustdocVisitor<'b> {
C
Corey Richardson 已提交
47 48
        RustdocVisitor {
            module: Module::new(None),
49
            attrs: Vec::new(),
A
Alex Crichton 已提交
50 51
            cx: cx,
            analysis: analysis,
C
Corey Richardson 已提交
52 53 54
        }
    }

55 56 57 58 59 60 61 62
    fn stability(&self, id: ast::NodeId) -> Option<attr::Stability> {
        let tcx = match self.cx.maybe_typed {
            core::Typed(ref tcx) => tcx,
            core::NotTyped(_) => return None
        };
        stability::lookup(tcx, ast_util::local_def(id))
    }

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

66 67 68 69 70 71 72 73 74
        self.module = self.visit_mod_contents(krate.span,
                                              krate.attrs
                                                   .iter()
                                                   .map(|x| *x)
                                                   .collect(),
                                              ast::Public,
                                              ast::CRATE_NODE_ID,
                                              &krate.module,
                                              None);
J
John Clements 已提交
75 76 77
        // attach the crate's exported macros to the top-level module:
        self.module.macros = krate.exported_macros.iter()
            .map(|it| self.visit_macro(&**it)).collect();
78
        self.module.is_crate = true;
A
Alex Crichton 已提交
79 80
    }

81
    pub fn visit_struct_def(&mut self, item: &ast::Item, sd: Gc<ast::StructDef>,
82
                            generics: &ast::Generics) -> Struct {
A
Alex Crichton 已提交
83
        debug!("Visiting struct");
84
        let struct_type = struct_type_from_def(&*sd);
A
Alex Crichton 已提交
85 86 87 88 89
        Struct {
            id: item.id,
            struct_type: struct_type,
            name: item.ident,
            vis: item.vis,
90
            stab: self.stability(item.id),
91
            attrs: item.attrs.iter().map(|x| *x).collect(),
A
Alex Crichton 已提交
92
            generics: generics.clone(),
93
            fields: sd.fields.iter().map(|x| (*x).clone()).collect(),
A
Alex Crichton 已提交
94
            where: item.span
C
Corey Richardson 已提交
95
        }
A
Alex Crichton 已提交
96
    }
C
Corey Richardson 已提交
97

98 99
    pub fn visit_enum_def(&mut self, it: &ast::Item, def: &ast::EnumDef,
                          params: &ast::Generics) -> Enum {
A
Alex Crichton 已提交
100
        debug!("Visiting enum");
101
        let mut vars: Vec<Variant> = Vec::new();
A
Alex Crichton 已提交
102 103 104
        for x in def.variants.iter() {
            vars.push(Variant {
                name: x.node.name,
105
                attrs: x.node.attrs.iter().map(|x| *x).collect(),
A
Alex Crichton 已提交
106
                vis: x.node.vis,
107
                stab: self.stability(x.node.id),
A
Alex Crichton 已提交
108 109 110 111 112 113 114 115 116
                id: x.node.id,
                kind: x.node.kind.clone(),
                where: x.span,
            });
        }
        Enum {
            name: it.ident,
            variants: vars,
            vis: it.vis,
117
            stab: self.stability(it.id),
A
Alex Crichton 已提交
118
            generics: params.clone(),
119
            attrs: it.attrs.iter().map(|x| *x).collect(),
A
Alex Crichton 已提交
120 121
            id: it.id,
            where: it.span,
C
Corey Richardson 已提交
122
        }
A
Alex Crichton 已提交
123
    }
C
Corey Richardson 已提交
124

125
    pub fn visit_fn(&mut self, item: &ast::Item, fd: &ast::FnDecl,
126
                    fn_style: &ast::FnStyle, _abi: &abi::Abi,
A
Alex Crichton 已提交
127 128 129 130 131
                    gen: &ast::Generics) -> Function {
        debug!("Visiting fn");
        Function {
            id: item.id,
            vis: item.vis,
132
            stab: self.stability(item.id),
133
            attrs: item.attrs.iter().map(|x| *x).collect(),
A
Alex Crichton 已提交
134 135 136 137
            decl: fd.clone(),
            name: item.ident,
            where: item.span,
            generics: gen.clone(),
138
            fn_style: *fn_style,
C
Corey Richardson 已提交
139
        }
A
Alex Crichton 已提交
140
    }
C
Corey Richardson 已提交
141

142
    pub fn visit_mod_contents(&mut self, span: Span, attrs: Vec<ast::Attribute> ,
143 144
                              vis: ast::Visibility, id: ast::NodeId,
                              m: &ast::Mod,
145
                              name: Option<ast::Ident>) -> Module {
A
Alex Crichton 已提交
146 147 148 149
        let mut om = Module::new(name);
        for item in m.view_items.iter() {
            self.visit_view_item(item, &mut om);
        }
150 151
        om.where_outer = span;
        om.where_inner = m.inner;
A
Alex Crichton 已提交
152 153
        om.attrs = attrs;
        om.vis = vis;
154
        om.stab = self.stability(id);
A
Alex Crichton 已提交
155 156
        om.id = id;
        for i in m.items.iter() {
157
            self.visit_item(&**i, &mut om);
A
Alex Crichton 已提交
158 159 160 161
        }
        om
    }

162 163
    pub fn visit_view_item(&mut self, item: &ast::ViewItem, om: &mut Module) {
        if item.vis != ast::Public {
A
Alex Crichton 已提交
164 165
            return om.view_items.push(item.clone());
        }
166 167 168 169 170 171 172 173
        let please_inline = item.attrs.iter().any(|item| {
            match item.meta_item_list() {
                Some(list) => {
                    list.iter().any(|i| i.name().get() == "inline")
                }
                None => false,
            }
        });
A
Alex Crichton 已提交
174
        let item = match item.node {
175
            ast::ViewItemUse(ref vpath) => {
176
                match self.visit_view_path(*vpath, om, please_inline) {
A
Alex Crichton 已提交
177 178
                    None => return,
                    Some(path) => {
179
                        ast::ViewItem {
180
                            node: ast::ViewItemUse(path),
A
Alex Crichton 已提交
181 182 183 184 185
                            .. item.clone()
                        }
                    }
                }
            }
186
            ast::ViewItemExternCrate(..) => item.clone()
A
Alex Crichton 已提交
187 188 189 190
        };
        om.view_items.push(item);
    }

191
    fn visit_view_path(&mut self, path: Gc<ast::ViewPath>,
192
                       om: &mut Module,
193
                       please_inline: bool) -> Option<Gc<ast::ViewPath>> {
A
Alex Crichton 已提交
194
        match path.node {
195 196 197 198
            ast::ViewPathSimple(dst, _, id) => {
                if self.resolve_id(id, Some(dst), false, om, please_inline) {
                    return None
                }
A
Alex Crichton 已提交
199
            }
200
            ast::ViewPathList(ref p, ref paths, ref b) => {
201
                let mut mine = Vec::new();
A
Alex Crichton 已提交
202
                for path in paths.iter() {
203 204
                    if !self.resolve_id(path.node.id(), None, false, om,
                                        please_inline) {
A
Alex Crichton 已提交
205 206 207 208 209
                        mine.push(path.clone());
                    }
                }

                if mine.len() == 0 { return None }
210
                return Some(box(GC) ::syntax::codemap::Spanned {
211
                    node: ast::ViewPathList(p.clone(), mine, b.clone()),
A
Alex Crichton 已提交
212 213 214 215 216
                    span: path.span,
                })
            }

            // these are feature gated anyway
217
            ast::ViewPathGlob(_, id) => {
218 219 220
                if self.resolve_id(id, None, true, om, please_inline) {
                    return None
                }
C
Corey Richardson 已提交
221 222
            }
        }
A
Alex Crichton 已提交
223 224
        return Some(path);
    }
C
Corey Richardson 已提交
225

226 227
    fn resolve_id(&mut self, id: ast::NodeId, renamed: Option<ast::Ident>,
                  glob: bool, om: &mut Module, please_inline: bool) -> bool {
E
Eduard Burtescu 已提交
228 229 230
        let tcx = match self.cx.maybe_typed {
            core::Typed(ref tcx) => tcx,
            core::NotTyped(_) => return false
A
Alex Crichton 已提交
231
        };
232
        let def = tcx.def_map.borrow().get(&id).def_id();
A
Alex Crichton 已提交
233 234 235 236
        if !ast_util::is_local(def) { return false }
        let analysis = match self.analysis {
            Some(analysis) => analysis, None => return false
        };
237 238 239
        if !please_inline && analysis.public_items.contains(&def.node) {
            return false
        }
A
Alex Crichton 已提交
240

E
Eduard Burtescu 已提交
241
        match tcx.map.get(def.node) {
242
            ast_map::NodeItem(it) => {
243 244 245 246 247 248 249 250 251
                let it = match renamed {
                    Some(ident) => {
                        box(GC) ast::Item {
                            ident: ident,
                            ..(*it).clone()
                        }
                    }
                    None => it,
                };
A
Alex Crichton 已提交
252 253
                if glob {
                    match it.node {
254
                        ast::ItemMod(ref m) => {
A
Alex Crichton 已提交
255 256 257 258
                            for vi in m.view_items.iter() {
                                self.visit_view_item(vi, om);
                            }
                            for i in m.items.iter() {
259
                                self.visit_item(&**i, om);
A
Alex Crichton 已提交
260 261 262 263 264
                            }
                        }
                        _ => { fail!("glob not mapped to a module"); }
                    }
                } else {
265
                    self.visit_item(&*it, om);
266
                }
A
Alex Crichton 已提交
267
                true
C
Corey Richardson 已提交
268
            }
A
Alex Crichton 已提交
269
            _ => false,
C
Corey Richardson 已提交
270
        }
A
Alex Crichton 已提交
271
    }
C
Corey Richardson 已提交
272

273
    pub fn visit_item(&mut self, item: &ast::Item, om: &mut Module) {
A
Alex Crichton 已提交
274 275
        debug!("Visiting item {:?}", item);
        match item.node {
276
            ast::ItemMod(ref m) => {
277 278 279 280 281 282 283 284 285
                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 已提交
286
            },
287
            ast::ItemEnum(ref ed, ref gen) =>
A
Alex Crichton 已提交
288
                om.enums.push(self.visit_enum_def(item, ed, gen)),
289
            ast::ItemStruct(sd, ref gen) =>
A
Alex Crichton 已提交
290
                om.structs.push(self.visit_struct_def(item, sd, gen)),
291 292
            ast::ItemFn(ref fd, ref pur, ref abi, ref gen, _) =>
                om.fns.push(self.visit_fn(item, &**fd, pur, abi, gen)),
293
            ast::ItemTy(ty, ref gen) => {
A
Alex Crichton 已提交
294 295 296 297 298
                let t = Typedef {
                    ty: ty,
                    gen: gen.clone(),
                    name: item.ident,
                    id: item.id,
299
                    attrs: item.attrs.iter().map(|x| *x).collect(),
A
Alex Crichton 已提交
300 301
                    where: item.span,
                    vis: item.vis,
302
                    stab: self.stability(item.id),
A
Alex Crichton 已提交
303 304 305
                };
                om.typedefs.push(t);
            },
306
            ast::ItemStatic(ty, ref mut_, ref exp) => {
A
Alex Crichton 已提交
307 308 309 310 311 312
                let s = Static {
                    type_: ty,
                    mutability: mut_.clone(),
                    expr: exp.clone(),
                    id: item.id,
                    name: item.ident,
313
                    attrs: item.attrs.iter().map(|x| *x).collect(),
A
Alex Crichton 已提交
314 315
                    where: item.span,
                    vis: item.vis,
316
                    stab: self.stability(item.id),
A
Alex Crichton 已提交
317 318 319
                };
                om.statics.push(s);
            },
320
            ast::ItemTrait(ref gen, _, ref tr, ref met) => {
A
Alex Crichton 已提交
321 322
                let t = Trait {
                    name: item.ident,
323
                    methods: met.iter().map(|x| (*x).clone()).collect(),
A
Alex Crichton 已提交
324
                    generics: gen.clone(),
325
                    parents: tr.iter().map(|x| (*x).clone()).collect(),
A
Alex Crichton 已提交
326
                    id: item.id,
327
                    attrs: item.attrs.iter().map(|x| *x).collect(),
A
Alex Crichton 已提交
328 329
                    where: item.span,
                    vis: item.vis,
330
                    stab: self.stability(item.id),
A
Alex Crichton 已提交
331 332 333
                };
                om.traits.push(t);
            },
334
            ast::ItemImpl(ref gen, ref tr, ty, ref meths) => {
A
Alex Crichton 已提交
335 336 337 338
                let i = Impl {
                    generics: gen.clone(),
                    trait_: tr.clone(),
                    for_: ty,
339 340
                    methods: meths.iter().map(|x| *x).collect(),
                    attrs: item.attrs.iter().map(|x| *x).collect(),
A
Alex Crichton 已提交
341 342 343
                    id: item.id,
                    where: item.span,
                    vis: item.vis,
344
                    stab: self.stability(item.id),
A
Alex Crichton 已提交
345 346 347
                };
                om.impls.push(i);
            },
348
            ast::ItemForeignMod(ref fm) => {
A
Alex Crichton 已提交
349 350
                om.foreigns.push(fm.clone());
            }
J
John Clements 已提交
351 352
            ast::ItemMac(_) => {
                fail!("rustdoc: macros should be gone, after expansion");
353
            }
A
Alex Crichton 已提交
354
        }
C
Corey Richardson 已提交
355
    }
J
John Clements 已提交
356 357 358 359 360 361 362 363 364 365 366

    // convert each exported_macro into a doc item
    fn visit_macro(&self, item: &ast::Item) -> Macro {
        Macro {
            id: item.id,
            attrs: item.attrs.iter().map(|x| *x).collect(),
            name: item.ident,
            where: item.span,
            stab: self.stability(item.id),
        }
    }
C
Corey Richardson 已提交
367
}