(index<- )        ./librustdoc/visit_ast.rs

    git branch:    * master           5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
    modified:    Fri May  9 13:02:28 2014
   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 syntax::abi;
  15  use syntax::ast;
  16  use syntax::ast_util;
  17  use syntax::ast_map;
  18  use syntax::attr::AttrMetaMethods;
  19  use syntax::codemap::Span;
  20  
  21  use core;
  22  use doctree::*;
  23  
  24  pub struct RustdocVisitor<'a> {
  25      pub module: Module,
  26      pub attrs: Vec<ast::Attribute>,
  27      pub cx: &'a core::DocContext,
  28      pub analysis: Option<&'a core::CrateAnalysis>,
  29  }
  30  
  31  impl<'a> RustdocVisitor<'a> {
  32      pub fn new<'b>(cx&'b core::DocContext,
  33                     analysisOption<&'b core::CrateAnalysis>) -> RustdocVisitor<'b> {
  34          RustdocVisitor {
  35              module: Module::new(None),
  36              attrs: Vec::new(),
  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 varsVec<Variant> = Vec::new();
  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                      fn_style&ast::FnStyle, _abi&abi::Abi,
 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              fn_style: *fn_style,
 111          }
 112      }
 113  
 114      pub fn visit_mod_contents(&mut self, spanSpan, attrsVec<ast::Attribute> ,
 115                                visast::Visibility, idast::NodeId,
 116                                m&ast::Mod,
 117                                nameOption<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_outer = span;
 123          om.where_inner = m.inner;
 124          om.attrs = attrs;
 125          om.vis = vis;
 126          om.id = id;
 127          for i in m.items.iter() {
 128              self.visit_item(*i, &mut om);
 129          }
 130          om
 131      }
 132  
 133      pub fn visit_view_item(&mut self, item&ast::ViewItem, om&mut Module) {
 134          if item.vis != ast::Public {
 135              return om.view_items.push(item.clone());
 136          }
 137          let please_inline = item.attrs.iter().any(|item| {
 138              match item.meta_item_list() {
 139                  Some(list) => {
 140                      list.iter().any(|i| i.name().get() == "inline")
 141                  }
 142                  None => false,
 143              }
 144          });
 145          let item = match item.node {
 146              ast::ViewItemUse(ref vpath) => {
 147                  match self.visit_view_path(*vpath, om, please_inline) {
 148                      None => return,
 149                      Some(path) => {
 150                          ast::ViewItem {
 151                              node: ast::ViewItemUse(path),
 152                              .. item.clone()
 153                          }
 154                      }
 155                  }
 156              }
 157              ast::ViewItemExternCrate(..) => item.clone()
 158          };
 159          om.view_items.push(item);
 160      }
 161  
 162      fn visit_view_path(&mut self, path@ast::ViewPath,
 163                         om&mut Module,
 164                         please_inlinebool) -> Option<@ast::ViewPath> {
 165          match path.node {
 166              ast::ViewPathSimple(_, _, id) => {
 167                  if self.resolve_id(id, false, om, please_inline) { return None }
 168              }
 169              ast::ViewPathList(ref p, ref paths, ref b) => {
 170                  let mut mine = Vec::new();
 171                  for path in paths.iter() {
 172                      if !self.resolve_id(path.node.id, false, om, please_inline) {
 173                          mine.push(path.clone());
 174                      }
 175                  }
 176  
 177                  if mine.len() == 0 { return None }
 178                  return Some(@::syntax::codemap::Spanned {
 179                      node: ast::ViewPathList(p.clone(), mine, b.clone()),
 180                      span: path.span,
 181                  })
 182              }
 183  
 184              // these are feature gated anyway
 185              ast::ViewPathGlob(_, id) => {
 186                  if self.resolve_id(id, true, om, please_inline) { return None }
 187              }
 188          }
 189          return Some(path);
 190      }
 191  
 192      fn resolve_id(&mut self, idast::NodeId, globbool,
 193                    om&mut Module, please_inlinebool) -> bool {
 194          let tcx = match self.cx.maybe_typed {
 195              core::Typed(ref tcx) => tcx,
 196              core::NotTyped(_) => return false
 197          };
 198          let def = ast_util::def_id_of_def(*tcx.def_map.borrow().get(&id));
 199          if !ast_util::is_local(def) { return false }
 200          let analysis = match self.analysis {
 201              Some(analysis) => analysis, None => return false
 202          };
 203          if !please_inline && analysis.public_items.contains(&def.node) {
 204              return false
 205          }
 206  
 207          match tcx.map.get(def.node) {
 208              ast_map::NodeItem(it) => {
 209                  if glob {
 210                      match it.node {
 211                          ast::ItemMod(ref m) => {
 212                              for vi in m.view_items.iter() {
 213                                  self.visit_view_item(vi, om);
 214                              }
 215                              for i in m.items.iter() {
 216                                  self.visit_item(*i, om);
 217                              }
 218                          }
 219                          _ => { fail!("glob not mapped to a module"); }
 220                      }
 221                  } else {
 222                      self.visit_item(it, om);
 223                  }
 224                  true
 225              }
 226              _ => false,
 227          }
 228      }
 229  
 230      pub fn visit_item(&mut self, item&ast::Item, om&mut Module) {
 231          debug!("Visiting item {:?}", item);
 232          match item.node {
 233              ast::ItemMod(ref m) => {
 234                  om.mods.push(self.visit_mod_contents(item.span,
 235                                                       item.attrs
 236                                                           .iter()
 237                                                           .map(|x| *x)
 238                                                           .collect(),
 239                                                       item.vis,
 240                                                       item.id,
 241                                                       m,
 242                                                       Some(item.ident)));
 243              },
 244              ast::ItemEnum(ref ed, ref gen) =>
 245                  om.enums.push(self.visit_enum_def(item, ed, gen)),
 246              ast::ItemStruct(sd, ref gen) =>
 247                  om.structs.push(self.visit_struct_def(item, sd, gen)),
 248              ast::ItemFn(fd, ref pur, ref abi, ref gen, _) =>
 249                  om.fns.push(self.visit_fn(item, fd, pur, abi, gen)),
 250              ast::ItemTy(ty, ref gen) => {
 251                  let t = Typedef {
 252                      ty: ty,
 253                      gen: gen.clone(),
 254                      name: item.ident,
 255                      id: item.id,
 256                      attrs: item.attrs.iter().map(|x| *x).collect(),
 257                      where: item.span,
 258                      vis: item.vis,
 259                  };
 260                  om.typedefs.push(t);
 261              },
 262              ast::ItemStatic(ty, ref mut_, ref exp) => {
 263                  let s = Static {
 264                      type_: ty,
 265                      mutability: mut_.clone(),
 266                      expr: exp.clone(),
 267                      id: item.id,
 268                      name: item.ident,
 269                      attrs: item.attrs.iter().map(|x| *x).collect(),
 270                      where: item.span,
 271                      vis: item.vis,
 272                  };
 273                  om.statics.push(s);
 274              },
 275              ast::ItemTrait(ref gen, _, ref tr, ref met) => {
 276                  let t = Trait {
 277                      name: item.ident,
 278                      methods: met.iter().map(|x| (*x).clone()).collect(),
 279                      generics: gen.clone(),
 280                      parents: tr.iter().map(|x| (*x).clone()).collect(),
 281                      id: item.id,
 282                      attrs: item.attrs.iter().map(|x| *x).collect(),
 283                      where: item.span,
 284                      vis: item.vis,
 285                  };
 286                  om.traits.push(t);
 287              },
 288              ast::ItemImpl(ref gen, ref tr, ty, ref meths) => {
 289                  let i = Impl {
 290                      generics: gen.clone(),
 291                      trait_: tr.clone(),
 292                      for_: ty,
 293                      methods: meths.iter().map(|x| *x).collect(),
 294                      attrs: item.attrs.iter().map(|x| *x).collect(),
 295                      id: item.id,
 296                      where: item.span,
 297                      vis: item.vis,
 298                  };
 299                  om.impls.push(i);
 300              },
 301              ast::ItemForeignMod(ref fm) => {
 302                  om.foreigns.push(fm.clone());
 303              }
 304              ast::ItemMac(ref _m) => {
 305                  om.macros.push(Macro {
 306                      id: item.id,
 307                      attrs: item.attrs.iter().map(|x| *x).collect(),
 308                      name: item.ident,
 309                      where: item.span,
 310                  })
 311              }
 312          }
 313      }
 314  }