//! Rust AST Visitor. Extracts useful information and massages it into a form //! usable for clean use syntax::abi::AbiSet; use syntax::{ast, ast_map}; use syntax::codemap::Span; use doctree::*; use std::local_data; pub struct RustdocVisitor { module: Module, attrs: ~[ast::Attribute], } impl RustdocVisitor { pub fn new() -> RustdocVisitor { RustdocVisitor { module: Module::new(None), attrs: ~[], } } } impl RustdocVisitor { pub fn visit(@mut self, crate: &ast::Crate) { self.attrs = crate.attrs.clone(); fn visit_struct_def(item: &ast::item, sd: @ast::struct_def, generics: &ast::Generics) -> Struct { 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, attrs: item.attrs.clone(), generics: generics.clone(), fields: sd.fields.iter().map(|x| (*x).clone()).to_owned_vec(), where: item.span } } fn visit_enum_def(it: &ast::item, def: &ast::enum_def, params: &ast::Generics) -> Enum { debug!("Visiting enum"); let mut vars: ~[Variant] = ~[]; for x in def.variants.iter() { vars.push(Variant { name: x.node.name, attrs: x.node.attrs.clone(), 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(), attrs: it.attrs.clone(), id: it.id, where: it.span, } } fn visit_fn(item: &ast::item, fd: &ast::fn_decl, _purity: &ast::purity, _abi: &AbiSet, gen: &ast::Generics) -> Function { debug!("Visiting fn"); Function { id: item.id, vis: item.vis, attrs: item.attrs.clone(), decl: fd.clone(), name: item.ident, where: item.span, generics: gen.clone(), } } fn visit_mod_contents(span: Span, attrs: ~[ast::Attribute], vis: ast::visibility, id: ast::NodeId, m: &ast::_mod) -> Module { let am = local_data::get(super::ctxtkey, |x| *x.unwrap()).tycx.items; let name = match am.find(&id) { Some(m) => match m { &ast_map::node_item(ref it, _) => Some(it.ident), _ => fail!("mod id mapped to non-item in the ast map") }, None => None }; let mut om = Module::new(name); om.view_items = m.view_items.clone(); om.where = span; om.attrs = attrs; om.vis = vis; om.id = id; for i in m.items.iter() { visit_item(*i, &mut om); } om } fn visit_item(item: &ast::item, om: &mut Module) { debug!("Visiting item %?", item); match item.node { ast::item_mod(ref m) => { om.mods.push(visit_mod_contents(item.span, item.attrs.clone(), item.vis, item.id, m)); }, ast::item_enum(ref ed, ref gen) => om.enums.push(visit_enum_def(item, ed, gen)), ast::item_struct(sd, ref gen) => om.structs.push(visit_struct_def(item, sd, gen)), ast::item_fn(ref fd, ref pur, ref abi, ref gen, _) => om.fns.push(visit_fn(item, fd, pur, abi, gen)), ast::item_ty(ref ty, ref gen) => { let t = Typedef { ty: ty.clone(), gen: gen.clone(), name: item.ident, id: item.id, attrs: item.attrs.clone(), where: item.span, vis: item.vis, }; om.typedefs.push(t); }, ast::item_static(ref ty, ref mut_, ref exp) => { let s = Static { type_: ty.clone(), mutability: mut_.clone(), expr: exp.clone(), id: item.id, name: item.ident, attrs: item.attrs.clone(), where: item.span, vis: item.vis, }; om.statics.push(s); }, ast::item_trait(ref gen, ref tr, ref met) => { let t = Trait { name: item.ident, methods: met.clone(), generics: gen.clone(), parents: tr.clone(), id: item.id, attrs: item.attrs.clone(), where: item.span, vis: item.vis, }; om.traits.push(t); }, ast::item_impl(ref gen, ref tr, ref ty, ref meths) => { let i = Impl { generics: gen.clone(), trait_: tr.clone(), for_: ty.clone(), methods: meths.clone(), attrs: item.attrs.clone(), id: item.id, where: item.span, vis: item.vis, }; om.impls.push(i); }, _ => (), } } self.module = visit_mod_contents(crate.span, crate.attrs.clone(), ast::public, ast::CRATE_NODE_ID, &crate.module); } }