]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_save_analysis/dump_visitor.rs
Appease tidy and fix save-analysis config for dist builds
[rust.git] / src / librustc_save_analysis / dump_visitor.rs
index a95236e2a5072936710d1dcb4ac14adca87ec876..4740f9a0d5a59662808fc170494908df69e565a2 100644 (file)
@@ -8,10 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//! Write the output of rustc's analysis to an implementor of Dump. The data is
-//! primarily designed to be used as input to the DXR tool, specifically its
-//! Rust plugin. It could also be used by IDEs or other code browsing, search, or
-//! cross-referencing tools.
+//! Write the output of rustc's analysis to an implementor of Dump.
 //!
 //! Dumping the analysis is implemented by walking the AST and getting a bunch of
 //! info out from all over the place. We use Def IDs to identify objects. The
 //! is used for recording the output in a format-agnostic way (see CsvDumper
 //! for an example).
 
-use rustc::hir;
-use rustc::hir::def::Def;
-use rustc::hir::def_id::{DefId, LOCAL_CRATE};
-use rustc::hir::map::{Node, NodeItem};
+use rustc::hir::def::Def as HirDef;
+use rustc::hir::def_id::DefId;
+use rustc::hir::map::Node;
 use rustc::session::Session;
-use rustc::ty::{self, TyCtxt, AssociatedItemContainer};
+use rustc::ty::{self, TyCtxt};
+use rustc_data_structures::fx::FxHashSet;
 
-use std::collections::HashSet;
-use std::collections::hash_map::DefaultHasher;
-use std::hash::*;
 use std::path::Path;
 
 use syntax::ast::{self, NodeId, PatKind, Attribute, CRATE_NODE_ID};
 use syntax::codemap::Spanned;
 use syntax_pos::*;
 
-use super::{escape, generated_code, SaveContext, PathCollector, docs_for_attrs};
-use super::data::*;
-use super::dump::Dump;
-use super::external_data::{Lower, make_def_id};
-use super::span_utils::SpanUtils;
-use super::recorder;
+use {escape, generated_code, SaveContext, PathCollector, lower_attributes};
+use json_dumper::{JsonDumper, DumpOutput};
+use span_utils::SpanUtils;
+use sig;
 
-use rls_data::ExternalCrateData;
+use rls_data::{CratePreludeData, Import, ImportKind, SpanData, Ref, RefKind,
+               Def, DefKind, Relation, RelationKind};
 
 macro_rules! down_cast_data {
     ($id:ident, $kind:ident, $sp:expr) => {
@@ -67,11 +60,11 @@ macro_rules! down_cast_data {
     };
 }
 
-pub struct DumpVisitor<'l, 'tcx: 'l, 'll, D: 'll> {
+pub struct DumpVisitor<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> {
     save_ctxt: SaveContext<'l, 'tcx>,
     sess: &'l Session,
     tcx: TyCtxt<'l, 'tcx, 'tcx>,
-    dumper: &'ll mut D,
+    dumper: &'ll mut JsonDumper<O>,
 
     span: SpanUtils<'l>,
 
@@ -81,14 +74,14 @@ pub struct DumpVisitor<'l, 'tcx: 'l, 'll, D: 'll> {
     // of macro use (callsite) spans. We store these to ensure
     // we only write one macro def per unique macro definition, and
     // one macro use per unique callsite span.
-    mac_defs: HashSet<Span>,
-    mac_uses: HashSet<Span>,
+    // mac_defs: HashSet<Span>,
+    macro_calls: FxHashSet<Span>,
 }
 
-impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
+impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
     pub fn new(save_ctxt: SaveContext<'l, 'tcx>,
-               dumper: &'ll mut D)
-               -> DumpVisitor<'l, 'tcx, 'll, D> {
+               dumper: &'ll mut JsonDumper<O>)
+               -> DumpVisitor<'l, 'tcx, 'll, O> {
         let span_utils = SpanUtils::new(&save_ctxt.tcx.sess);
         DumpVisitor {
             sess: &save_ctxt.tcx.sess,
@@ -97,13 +90,13 @@ pub fn new(save_ctxt: SaveContext<'l, 'tcx>,
             dumper: dumper,
             span: span_utils.clone(),
             cur_scope: CRATE_NODE_ID,
-            mac_defs: HashSet::new(),
-            mac_uses: HashSet::new(),
+            // mac_defs: HashSet::new(),
+            macro_calls: FxHashSet(),
         }
     }
 
     fn nest_scope<F>(&mut self, scope_id: NodeId, f: F)
-        where F: FnOnce(&mut DumpVisitor<'l, 'tcx, 'll, D>)
+        where F: FnOnce(&mut DumpVisitor<'l, 'tcx, 'll, O>)
     {
         let parent_scope = self.cur_scope;
         self.cur_scope = scope_id;
@@ -112,7 +105,7 @@ fn nest_scope<F>(&mut self, scope_id: NodeId, f: F)
     }
 
     fn nest_tables<F>(&mut self, item_id: NodeId, f: F)
-        where F: FnOnce(&mut DumpVisitor<'l, 'tcx, 'll, D>)
+        where F: FnOnce(&mut DumpVisitor<'l, 'tcx, 'll, O>)
     {
         let item_def_id = self.tcx.hir.local_def_id(item_id);
         if self.tcx.has_typeck_tables(item_def_id) {
@@ -126,6 +119,10 @@ fn nest_tables<F>(&mut self, item_id: NodeId, f: F)
         }
     }
 
+    fn span_from_span(&self, span: Span) -> SpanData {
+        self.save_ctxt.span_from_span(span)
+    }
+
     pub fn dump_crate_info(&mut self, name: &str, krate: &ast::Crate) {
         let source_file = self.tcx.sess.local_crate_source_file.as_ref();
         let crate_root = source_file.map(|source_file| {
@@ -136,25 +133,14 @@ pub fn dump_crate_info(&mut self, name: &str, krate: &ast::Crate) {
             }
         });
 
-        // Info about all the external crates referenced from this crate.
-        let external_crates = self.save_ctxt.get_external_crates().into_iter().map(|c| {
-            let lo_loc = self.span.sess.codemap().lookup_char_pos(c.span.lo);
-            ExternalCrateData {
-                name: c.name,
-                num: c.number,
-                file_name: SpanUtils::make_path_string(&lo_loc.file.name),
-            }
-        }).collect();
-
-        // The current crate.
         let data = CratePreludeData {
             crate_name: name.into(),
             crate_root: crate_root.unwrap_or("<no source>".to_owned()),
-            external_crates: external_crates,
-            span: krate.span,
+            external_crates: self.save_ctxt.get_external_crates(),
+            span: self.span_from_span(krate.span),
         };
 
-        self.dumper.crate_prelude(data.lower(self.tcx));
+        self.dumper.crate_prelude(data);
     }
 
     // Return all non-empty prefixes of a path.
@@ -210,13 +196,13 @@ fn process_path_prefixes(&self, path: &ast::Path) -> Vec<(Span, String)> {
 
     fn write_sub_paths(&mut self, path: &ast::Path) {
         let sub_paths = self.process_path_prefixes(path);
-        for (span, qualname) in sub_paths {
-            self.dumper.mod_ref(ModRefData {
-                span: span,
-                qualname: qualname,
-                scope: self.cur_scope,
-                ref_id: None
-            }.lower(self.tcx));
+        for (span, _) in sub_paths {
+            let span = self.span_from_span(span);
+            self.dumper.dump_ref(Ref {
+                kind: RefKind::Mod,
+                span,
+                ref_id: ::null_id(),
+            });
         }
     }
 
@@ -229,13 +215,13 @@ fn write_sub_paths_truncated(&mut self, path: &ast::Path) {
             return;
         }
 
-        for (span, qualname) in sub_paths.into_iter().take(len - 1) {
-            self.dumper.mod_ref(ModRefData {
-                span: span,
-                qualname: qualname,
-                scope: self.cur_scope,
-                ref_id: None
-            }.lower(self.tcx));
+        for (span, _) in sub_paths.into_iter().take(len - 1) {
+            let span = self.span_from_span(span);
+            self.dumper.dump_ref(Ref {
+                kind: RefKind::Mod,
+                span,
+                ref_id: ::null_id(),
+            });
         }
     }
 
@@ -250,32 +236,32 @@ fn write_sub_path_trait_truncated(&mut self, path: &ast::Path) {
         let sub_paths = &sub_paths[.. (len-1)];
 
         // write the trait part of the sub-path
-        let (ref span, ref qualname) = sub_paths[len-2];
-        self.dumper.type_ref(TypeRefData {
-            ref_id: None,
-            span: *span,
-            qualname: qualname.to_owned(),
-            scope: CRATE_NODE_ID
-        }.lower(self.tcx));
+        let (ref span, _) = sub_paths[len-2];
+        let span = self.span_from_span(*span);
+        self.dumper.dump_ref(Ref {
+            kind: RefKind::Type,
+            ref_id: ::null_id(),
+            span,
+        });
 
         // write the other sub-paths
         if len <= 2 {
             return;
         }
         let sub_paths = &sub_paths[..len-2];
-        for &(ref span, ref qualname) in sub_paths {
-            self.dumper.mod_ref(ModRefData {
-                span: *span,
-                qualname: qualname.to_owned(),
-                scope: self.cur_scope,
-                ref_id: None
-            }.lower(self.tcx));
+        for &(ref span, _) in sub_paths {
+            let span = self.span_from_span(*span);
+            self.dumper.dump_ref(Ref {
+                kind: RefKind::Mod,
+                span,
+                ref_id: ::null_id(),
+            });
         }
     }
 
     fn lookup_def_id(&self, ref_id: NodeId) -> Option<DefId> {
         match self.save_ctxt.get_path_def(ref_id) {
-            Def::PrimTy(..) | Def::SelfTy(..) | Def::Err => None,
+            HirDef::PrimTy(..) | HirDef::SelfTy(..) | HirDef::Err => None,
             def => Some(def.def_id()),
         }
     }
@@ -284,67 +270,67 @@ fn process_def_kind(&mut self,
                         ref_id: NodeId,
                         span: Span,
                         sub_span: Option<Span>,
-                        def_id: DefId,
-                        scope: NodeId) {
+                        def_id: DefId) {
         if self.span.filter_generated(sub_span, span) {
             return;
         }
 
         let def = self.save_ctxt.get_path_def(ref_id);
         match def {
-            Def::Mod(_) => {
-                self.dumper.mod_ref(ModRefData {
-                    span: sub_span.expect("No span found for mod ref"),
-                    ref_id: Some(def_id),
-                    scope: scope,
-                    qualname: String::new()
-                }.lower(self.tcx));
+            HirDef::Mod(_) => {
+                let span = self.span_from_span(sub_span.expect("No span found for mod ref"));
+                self.dumper.dump_ref(Ref {
+                    kind: RefKind::Mod,
+                    span,
+                    ref_id: ::id_from_def_id(def_id),
+                });
             }
-            Def::Struct(..) |
-            Def::Variant(..) |
-            Def::Union(..) |
-            Def::Enum(..) |
-            Def::TyAlias(..) |
-            Def::Trait(_) => {
-                self.dumper.type_ref(TypeRefData {
-                    span: sub_span.expect("No span found for type ref"),
-                    ref_id: Some(def_id),
-                    scope: scope,
-                    qualname: String::new()
-                }.lower(self.tcx));
+            HirDef::Struct(..) |
+            HirDef::Variant(..) |
+            HirDef::Union(..) |
+            HirDef::Enum(..) |
+            HirDef::TyAlias(..) |
+            HirDef::Trait(_) => {
+                let span = self.span_from_span(sub_span.expect("No span found for type ref"));
+                self.dumper.dump_ref(Ref {
+                    kind: RefKind::Type,
+                    span,
+                    ref_id: ::id_from_def_id(def_id),
+                });
             }
-            Def::Static(..) |
-            Def::Const(..) |
-            Def::StructCtor(..) |
-            Def::VariantCtor(..) => {
-                self.dumper.variable_ref(VariableRefData {
-                    span: sub_span.expect("No span found for var ref"),
-                    ref_id: def_id,
-                    scope: scope,
-                    name: String::new()
-                }.lower(self.tcx));
+            HirDef::Static(..) |
+            HirDef::Const(..) |
+            HirDef::StructCtor(..) |
+            HirDef::VariantCtor(..) => {
+                let span = self.span_from_span(sub_span.expect("No span found for var ref"));
+                self.dumper.dump_ref(Ref {
+                    kind: RefKind::Variable,
+                    span,
+                    ref_id: ::id_from_def_id(def_id),
+                });
             }
-            Def::Fn(..) => {
-                self.dumper.function_ref(FunctionRefData {
-                    span: sub_span.expect("No span found for fn ref"),
-                    ref_id: def_id,
-                    scope: scope
-                }.lower(self.tcx));
+            HirDef::Fn(..) => {
+                let span = self.span_from_span(sub_span.expect("No span found for fn ref"));
+                self.dumper.dump_ref(Ref {
+                    kind: RefKind::Function,
+                    span,
+                    ref_id: ::id_from_def_id(def_id),
+                });
             }
             // With macros 2.0, we can legitimately get a ref to a macro, but
             // we don't handle it properly for now (FIXME).
-            Def::Macro(..) => {}
-            Def::Local(..) |
-            Def::Upvar(..) |
-            Def::SelfTy(..) |
-            Def::Label(_) |
-            Def::TyParam(..) |
-            Def::Method(..) |
-            Def::AssociatedTy(..) |
-            Def::AssociatedConst(..) |
-            Def::PrimTy(_) |
-            Def::GlobalAsm(_) |
-            Def::Err => {
+            HirDef::Macro(..) => {}
+            HirDef::Local(..) |
+            HirDef::Upvar(..) |
+            HirDef::SelfTy(..) |
+            HirDef::Label(_) |
+            HirDef::TyParam(..) |
+            HirDef::Method(..) |
+            HirDef::AssociatedTy(..) |
+            HirDef::AssociatedConst(..) |
+            HirDef::PrimTy(_) |
+            HirDef::GlobalAsm(_) |
+            HirDef::Err => {
                span_bug!(span,
                          "process_def_kind for unexpected item: {:?}",
                          def);
@@ -367,21 +353,23 @@ fn process_formals(&mut self, formals: &'l [ast::Arg], qualname: &str) {
                 // variable name, but who knows?)
                 let sub_span = span_utils.span_for_last_ident(p.span);
                 if !self.span.filter_generated(sub_span, p.span) {
-                    self.dumper.variable(VariableData {
-                        id: id,
-                        kind: VariableKind::Local,
-                        span: sub_span.expect("No span found for variable"),
+                    let id = ::id_from_node_id(id, &self.save_ctxt);
+                    let span = self.span_from_span(sub_span.expect("No span found for variable"));
+
+                    self.dumper.dump_def(false, Def {
+                        kind: DefKind::Local,
+                        id,
+                        span,
                         name: path_to_string(p),
                         qualname: format!("{}::{}", qualname, path_to_string(p)),
-                        type_value: typ,
-                        value: String::new(),
-                        scope: CRATE_NODE_ID,
+                        value: typ,
                         parent: None,
-                        visibility: Visibility::Inherited,
+                        children: vec![],
+                        decl_id: None,
                         docs: String::new(),
                         sig: None,
-                        attributes: vec![],
-                    }.lower(self.tcx));
+                        attributes:vec![],
+                    });
                 }
             }
         }
@@ -391,13 +379,12 @@ fn process_method(&mut self,
                       sig: &'l ast::MethodSig,
                       body: Option<&'l ast::Block>,
                       id: ast::NodeId,
-                      name: ast::Name,
-                      vis: Visibility,
-                      attrs: &'l [Attribute],
+                      name: ast::Ident,
+                      vis: ast::Visibility,
                       span: Span) {
         debug!("process_method: {}:{}", id, name);
 
-        if let Some(method_data) = self.save_ctxt.get_method_data(id, name, span) {
+        if let Some(mut method_data) = self.save_ctxt.get_method_data(id, name.name, span) {
 
             let sig_str = ::make_signature(&sig.decl, &sig.generics);
             if body.is_some() {
@@ -406,61 +393,11 @@ fn process_method(&mut self,
                 });
             }
 
-            // If the method is defined in an impl, then try and find the corresponding
-            // method decl in a trait, and if there is one, make a decl_id for it. This
-            // requires looking up the impl, then the trait, then searching for a method
-            // with the right name.
-            if !self.span.filter_generated(Some(method_data.span), span) {
-                let container =
-                    self.tcx.associated_item(self.tcx.hir.local_def_id(id)).container;
-                let mut trait_id;
-                let mut decl_id = None;
-                match container {
-                    AssociatedItemContainer::ImplContainer(id) => {
-                        trait_id = self.tcx.trait_id_of_impl(id);
-
-                        match trait_id {
-                            Some(id) => {
-                                for item in self.tcx.associated_items(id) {
-                                    if item.kind == ty::AssociatedKind::Method {
-                                        if item.name == name {
-                                            decl_id = Some(item.def_id);
-                                            break;
-                                        }
-                                    }
-                                }
-                            }
-                            None => {
-                                if let Some(NodeItem(item)) = self.tcx.hir.get_if_local(id) {
-                                    if let hir::ItemImpl(_, _, _, _, _, ref ty, _) = item.node {
-                                        trait_id = self.lookup_def_id(ty.id);
-                                    }
-                                }
-                            }
-                        }
-                    }
-                    AssociatedItemContainer::TraitContainer(id) => {
-                        trait_id = Some(id);
-                    }
-                }
-
-                self.dumper.method(MethodData {
-                    id: method_data.id,
-                    name: method_data.name,
-                    span: method_data.span,
-                    scope: method_data.scope,
-                    qualname: method_data.qualname.clone(),
-                    value: sig_str,
-                    decl_id: decl_id,
-                    parent: trait_id,
-                    visibility: vis,
-                    docs: docs_for_attrs(attrs),
-                    sig: method_data.sig,
-                    attributes: attrs.to_vec(),
-                }.lower(self.tcx));
-            }
-
             self.process_generic_params(&sig.generics, span, &method_data.qualname, id);
+
+            method_data.value = sig_str;
+            method_data.sig = sig::method_signature(id, name, sig, &self.save_ctxt);
+            self.dumper.dump_def(vis == ast::Visibility::Public, method_data);
         }
 
         // walk arg and return types
@@ -479,22 +416,17 @@ fn process_method(&mut self,
     }
 
     fn process_trait_ref(&mut self, trait_ref: &'l ast::TraitRef) {
-        let trait_ref_data = self.save_ctxt.get_trait_ref_data(trait_ref, self.cur_scope);
+        let trait_ref_data = self.save_ctxt.get_trait_ref_data(trait_ref);
         if let Some(trait_ref_data) = trait_ref_data {
-            if !self.span.filter_generated(Some(trait_ref_data.span), trait_ref.path.span) {
-                self.dumper.type_ref(trait_ref_data.lower(self.tcx));
-            }
+            self.dumper.dump_ref(trait_ref_data);
         }
-        self.process_path(trait_ref.ref_id, &trait_ref.path, Some(recorder::TypeRef));
+        self.process_path(trait_ref.ref_id, &trait_ref.path);
     }
 
     fn process_struct_field_def(&mut self, field: &ast::StructField, parent_id: NodeId) {
         let field_data = self.save_ctxt.get_field_data(field, parent_id);
-        if let Some(mut field_data) = field_data {
-            if !self.span.filter_generated(Some(field_data.span), field.span) {
-                field_data.value = String::new();
-                self.dumper.variable(field_data.lower(self.tcx));
-            }
+        if let Some(field_data) = field_data {
+            self.dumper.dump_def(field.vis == ast::Visibility::Public, field_data);
         }
     }
 
@@ -518,18 +450,23 @@ fn process_generic_params(&mut self,
                                    name,
                                    id);
             if !self.span.filter_generated(Some(param_ss), full_span) {
-                self.dumper.typedef(TypeDefData {
-                    span: param_ss,
-                    name: name,
-                    id: param.id,
-                    qualname: qualname,
+                let id = ::id_from_node_id(param.id, &self.save_ctxt);
+                let span = self.span_from_span(param_ss);
+
+                self.dumper.dump_def(false, Def {
+                    kind: DefKind::Type,
+                    id,
+                    span,
+                    name,
+                    qualname,
                     value: String::new(),
-                    visibility: Visibility::Inherited,
                     parent: None,
+                    children: vec![],
+                    decl_id: None,
                     docs: String::new(),
                     sig: None,
                     attributes: vec![],
-                }.lower(self.tcx));
+                });
             }
         }
         self.visit_generics(generics);
@@ -541,13 +478,10 @@ fn process_fn(&mut self,
                   ty_params: &'l ast::Generics,
                   body: &'l ast::Block) {
         if let Some(fn_data) = self.save_ctxt.get_item_data(item) {
-            down_cast_data!(fn_data, FunctionData, item.span);
-            if !self.span.filter_generated(Some(fn_data.span), item.span) {
-                self.dumper.function(fn_data.clone().lower(self.tcx));
-            }
-
+            down_cast_data!(fn_data, DefData, item.span);
             self.nest_tables(item.id, |v| v.process_formals(&decl.inputs, &fn_data.qualname));
             self.process_generic_params(ty_params, item.span, &fn_data.qualname, item.id);
+            self.dumper.dump_def(item.vis == ast::Visibility::Public, fn_data);
         }
 
         for arg in &decl.inputs {
@@ -566,10 +500,8 @@ fn process_static_or_const_item(&mut self,
                                     typ: &'l ast::Ty,
                                     expr: &'l ast::Expr) {
         if let Some(var_data) = self.save_ctxt.get_item_data(item) {
-            down_cast_data!(var_data, VariableData, item.span);
-            if !self.span.filter_generated(Some(var_data.span), item.span) {
-                self.dumper.variable(var_data.lower(self.tcx));
-            }
+            down_cast_data!(var_data, DefData, item.span);
+            self.dumper.dump_def(item.vis == ast::Visibility::Public, var_data);
         }
         self.visit_ty(&typ);
         self.visit_expr(expr);
@@ -580,35 +512,40 @@ fn process_assoc_const(&mut self,
                            name: ast::Name,
                            span: Span,
                            typ: &'l ast::Ty,
-                           expr: &'l ast::Expr,
+                           expr: Option<&'l ast::Expr>,
                            parent_id: DefId,
-                           vis: Visibility,
+                           vis: ast::Visibility,
                            attrs: &'l [Attribute]) {
         let qualname = format!("::{}", self.tcx.node_path_str(id));
 
         let sub_span = self.span.sub_span_after_keyword(span, keywords::Const);
 
         if !self.span.filter_generated(sub_span, span) {
-            self.dumper.variable(VariableData {
-                span: sub_span.expect("No span found for variable"),
-                kind: VariableKind::Const,
-                id: id,
+            let sig = sig::assoc_const_signature(id, name, typ, expr, &self.save_ctxt);
+            let id = ::id_from_node_id(id, &self.save_ctxt);
+            let span = self.span_from_span(sub_span.expect("No span found for variable"));
+
+            self.dumper.dump_def(vis == ast::Visibility::Public, Def {
+                kind: DefKind::Const,
+                id,
+                span,
                 name: name.to_string(),
-                qualname: qualname,
-                value: self.span.snippet(expr.span),
-                type_value: ty_to_string(&typ),
-                scope: self.cur_scope,
-                parent: Some(parent_id),
-                visibility: vis,
-                docs: docs_for_attrs(attrs),
-                sig: None,
-                attributes: attrs.to_vec(),
-            }.lower(self.tcx));
+                qualname,
+                value: ty_to_string(&typ),
+                parent: Some(::id_from_def_id(parent_id)),
+                children: vec![],
+                decl_id: None,
+                docs: self.save_ctxt.docs_for_attrs(attrs),
+                sig,
+                attributes: lower_attributes(attrs.to_owned(), &self.save_ctxt),
+            });
         }
 
         // walk type and init value
         self.visit_ty(typ);
-        self.visit_expr(expr);
+        if let Some(expr) = expr {
+            self.visit_expr(expr);
+        }
     }
 
     // FIXME tuple structs should generate tuple-specific data.
@@ -620,35 +557,44 @@ fn process_struct(&mut self,
         let qualname = format!("::{}", self.tcx.node_path_str(item.id));
 
         let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Struct);
-        let (val, fields) =
+        let (value, fields) =
             if let ast::ItemKind::Struct(ast::VariantData::Struct(ref fields, _), _) = item.node
         {
-            let fields_str = fields.iter()
-                                   .enumerate()
-                                   .map(|(i, f)| f.ident.map(|i| i.to_string())
-                                                  .unwrap_or(i.to_string()))
-                                   .collect::<Vec<_>>()
-                                   .join(", ");
-            (format!("{} {{ {} }}", name, fields_str), fields.iter().map(|f| f.id).collect())
+            let include_priv_fields = !self.save_ctxt.config.pub_only;
+            let fields_str = fields
+                .iter()
+                .enumerate()
+                .filter_map(|(i, f)| {
+                     if include_priv_fields || f.vis == ast::Visibility::Public {
+                         f.ident.map(|i| i.to_string()).or_else(|| Some(i.to_string()))
+                     } else {
+                         None
+                     }
+                })
+                .collect::<Vec<_>>()
+                .join(", ");
+            let value = format!("{} {{ {} }}", name, fields_str);
+            (value, fields.iter().map(|f| ::id_from_node_id(f.id, &self.save_ctxt)).collect())
         } else {
             (String::new(), vec![])
         };
 
         if !self.span.filter_generated(sub_span, item.span) {
-            self.dumper.struct_data(StructData {
-                span: sub_span.expect("No span found for struct"),
-                id: item.id,
-                name: name,
-                ctor_id: def.id(),
+            let span = self.span_from_span(sub_span.expect("No span found for struct"));
+            self.dumper.dump_def(item.vis == ast::Visibility::Public, Def {
+                kind: DefKind::Struct,
+                id: ::id_from_node_id(item.id, &self.save_ctxt),
+                span,
+                name,
                 qualname: qualname.clone(),
-                scope: self.cur_scope,
-                value: val,
-                fields: fields,
-                visibility: From::from(&item.vis),
-                docs: docs_for_attrs(&item.attrs),
-                sig: self.save_ctxt.sig_base(item),
-                attributes: item.attrs.clone(),
-            }.lower(self.tcx));
+                value,
+                parent: None,
+                children: fields,
+                decl_id: None,
+                docs: self.save_ctxt.docs_for_attrs(&item.attrs),
+                sig: sig::item_signature(item, &self.save_ctxt),
+                attributes: lower_attributes(item.attrs.clone(), &self.save_ctxt),
+            });
         }
 
         for field in def.fields() {
@@ -668,10 +614,7 @@ fn process_enum(&mut self,
             None => return,
             Some(data) => data,
         };
-        down_cast_data!(enum_data, EnumData, item.span);
-        if !self.span.filter_generated(Some(enum_data.span), item.span) {
-            self.dumper.enum_data(enum_data.clone().lower(self.tcx));
-        }
+        down_cast_data!(enum_data, DefData, item.span);
 
         for variant in &enum_definition.variants {
             let name = variant.node.name.name.to_string();
@@ -679,18 +622,6 @@ fn process_enum(&mut self,
             qualname.push_str("::");
             qualname.push_str(&name);
 
-            let text = self.span.signature_string_for_span(variant.span);
-            let ident_start = text.find(&name).unwrap();
-            let ident_end = ident_start + name.len();
-            let sig = Signature {
-                span: variant.span,
-                text: text,
-                ident_start: ident_start,
-                ident_end: ident_end,
-                defs: vec![],
-                refs: vec![],
-            };
-
             match variant.node.data {
                 ast::VariantData::Struct(ref fields, _) => {
                     let sub_span = self.span.span_for_first_ident(variant.span);
@@ -700,48 +631,62 @@ fn process_enum(&mut self,
                                                           .unwrap_or(i.to_string()))
                                            .collect::<Vec<_>>()
                                            .join(", ");
-                    let val = format!("{}::{} {{ {} }}", enum_data.name, name, fields_str);
+                    let value = format!("{}::{} {{ {} }}", enum_data.name, name, fields_str);
                     if !self.span.filter_generated(sub_span, variant.span) {
-                        self.dumper.struct_variant(StructVariantData {
-                            span: sub_span.expect("No span found for struct variant"),
-                            id: variant.node.data.id(),
-                            name: name,
-                            qualname: qualname,
-                            type_value: enum_data.qualname.clone(),
-                            value: val,
-                            scope: enum_data.scope,
-                            parent: Some(make_def_id(item.id, &self.tcx.hir)),
-                            docs: docs_for_attrs(&variant.node.attrs),
-                            sig: sig,
-                            attributes: variant.node.attrs.clone(),
-                        }.lower(self.tcx));
+                        let span = self.span_from_span(
+                            sub_span.expect("No span found for struct variant"));
+                        let id = ::id_from_node_id(variant.node.data.id(), &self.save_ctxt);
+                        let parent = Some(::id_from_node_id(item.id, &self.save_ctxt));
+
+                        self.dumper.dump_def(item.vis == ast::Visibility::Public, Def {
+                            kind: DefKind::Struct,
+                            id,
+                            span,
+                            name,
+                            qualname,
+                            value,
+                            parent,
+                            children: vec![],
+                            decl_id: None,
+                            docs: self.save_ctxt.docs_for_attrs(&variant.node.attrs),
+                            sig: sig::variant_signature(variant, &self.save_ctxt),
+                            attributes: lower_attributes(variant.node.attrs.clone(),
+                                                         &self.save_ctxt),
+                        });
                     }
                 }
                 ref v => {
                     let sub_span = self.span.span_for_first_ident(variant.span);
-                    let mut val = format!("{}::{}", enum_data.name, name);
+                    let mut value = format!("{}::{}", enum_data.name, name);
                     if let &ast::VariantData::Tuple(ref fields, _) = v {
-                        val.push('(');
-                        val.push_str(&fields.iter()
-                                            .map(|f| ty_to_string(&f.ty))
-                                            .collect::<Vec<_>>()
-                                            .join(", "));
-                        val.push(')');
+                        value.push('(');
+                        value.push_str(&fields.iter()
+                                              .map(|f| ty_to_string(&f.ty))
+                                              .collect::<Vec<_>>()
+                                              .join(", "));
+                        value.push(')');
                     }
                     if !self.span.filter_generated(sub_span, variant.span) {
-                        self.dumper.tuple_variant(TupleVariantData {
-                            span: sub_span.expect("No span found for tuple variant"),
-                            id: variant.node.data.id(),
-                            name: name,
-                            qualname: qualname,
-                            type_value: enum_data.qualname.clone(),
-                            value: val,
-                            scope: enum_data.scope,
-                            parent: Some(make_def_id(item.id, &self.tcx.hir)),
-                            docs: docs_for_attrs(&variant.node.attrs),
-                            sig: sig,
-                            attributes: variant.node.attrs.clone(),
-                        }.lower(self.tcx));
+                        let span =
+                            self.span_from_span(sub_span.expect("No span found for tuple variant"));
+                        let id = ::id_from_node_id(variant.node.data.id(), &self.save_ctxt);
+                        let parent = Some(::id_from_node_id(item.id, &self.save_ctxt));
+
+                        self.dumper.dump_def(item.vis == ast::Visibility::Public, Def {
+                            kind: DefKind::Tuple,
+                            id,
+                            span,
+                            name,
+                            qualname,
+                            value,
+                            parent,
+                            children: vec![],
+                            decl_id: None,
+                            docs: self.save_ctxt.docs_for_attrs(&variant.node.attrs),
+                            sig: sig::variant_signature(variant, &self.save_ctxt),
+                            attributes: lower_attributes(variant.node.attrs.clone(),
+                                                         &self.save_ctxt),
+                        });
                     }
                 }
             }
@@ -752,7 +697,8 @@ fn process_enum(&mut self,
                 self.visit_ty(&field.ty);
             }
         }
-        self.process_generic_params(ty_params, item.span, &enum_data.qualname, enum_data.id);
+        self.process_generic_params(ty_params, item.span, &enum_data.qualname, item.id);
+        self.dumper.dump_def(item.vis == ast::Visibility::Public, enum_data);
     }
 
     fn process_impl(&mut self,
@@ -762,25 +708,17 @@ fn process_impl(&mut self,
                     typ: &'l ast::Ty,
                     impl_items: &'l [ast::ImplItem]) {
         if let Some(impl_data) = self.save_ctxt.get_item_data(item) {
-            down_cast_data!(impl_data, ImplData, item.span);
-            if !self.span.filter_generated(Some(impl_data.span), item.span) {
-                self.dumper.impl_data(ImplData {
-                    id: impl_data.id,
-                    span: impl_data.span,
-                    scope: impl_data.scope,
-                    trait_ref: impl_data.trait_ref.map(|d| d.ref_id.unwrap()),
-                    self_ref: impl_data.self_ref.map(|d| d.ref_id.unwrap())
-                }.lower(self.tcx));
-            }
+            down_cast_data!(impl_data, RelationData, item.span);
+            self.dumper.dump_relation(impl_data);
         }
         self.visit_ty(&typ);
         if let &Some(ref trait_ref) = trait_ref {
-            self.process_path(trait_ref.ref_id, &trait_ref.path, Some(recorder::TypeRef));
+            self.process_path(trait_ref.ref_id, &trait_ref.path);
         }
         self.process_generic_params(type_parameters, item.span, "", item.id);
         for impl_item in impl_items {
             let map = &self.tcx.hir;
-            self.process_impl_item(impl_item, make_def_id(item.id, map));
+            self.process_impl_item(impl_item, map.local_def_id(item.id));
         }
     }
 
@@ -801,19 +739,24 @@ fn process_trait(&mut self,
         }
         let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Trait);
         if !self.span.filter_generated(sub_span, item.span) {
-            self.dumper.trait_data(TraitData {
-                span: sub_span.expect("No span found for trait"),
-                id: item.id,
-                name: name,
+            let id = ::id_from_node_id(item.id, &self.save_ctxt);
+            let span = self.span_from_span(sub_span.expect("No span found for trait"));
+            let children =
+                methods.iter().map(|i| ::id_from_node_id(i.id, &self.save_ctxt)).collect();
+            self.dumper.dump_def(item.vis == ast::Visibility::Public, Def {
+                kind: DefKind::Trait,
+                id,
+                span,
+                name,
                 qualname: qualname.clone(),
-                scope: self.cur_scope,
                 value: val,
-                items: methods.iter().map(|i| i.id).collect(),
-                visibility: From::from(&item.vis),
-                docs: docs_for_attrs(&item.attrs),
-                sig: self.save_ctxt.sig_base(item),
-                attributes: item.attrs.clone(),
-            }.lower(self.tcx));
+                parent: None,
+                children,
+                decl_id: None,
+                docs: self.save_ctxt.docs_for_attrs(&item.attrs),
+                sig: sig::item_signature(item, &self.save_ctxt),
+                attributes: lower_attributes(item.attrs.clone(), &self.save_ctxt),
+            });
         }
 
         // super-traits
@@ -831,21 +774,22 @@ fn process_trait(&mut self,
             if let Some(id) = self.lookup_def_id(trait_ref.ref_id) {
                 let sub_span = self.span.sub_span_for_type_name(trait_ref.path.span);
                 if !self.span.filter_generated(sub_span, trait_ref.path.span) {
-                    self.dumper.type_ref(TypeRefData {
-                        span: sub_span.expect("No span found for trait ref"),
-                        ref_id: Some(id),
-                        scope: self.cur_scope,
-                        qualname: String::new()
-                    }.lower(self.tcx));
+                    let span = self.span_from_span(sub_span.expect("No span found for trait ref"));
+                    self.dumper.dump_ref(Ref {
+                        kind: RefKind::Type,
+                        span,
+                        ref_id: ::id_from_def_id(id),
+                    });
                 }
 
                 if !self.span.filter_generated(sub_span, trait_ref.path.span) {
-                    let sub_span = sub_span.expect("No span for inheritance");
-                    self.dumper.inheritance(InheritanceData {
+                    let sub_span = self.span_from_span(sub_span.expect("No span for inheritance"));
+                    self.dumper.dump_relation(Relation {
+                        kind: RelationKind::SuperTrait,
                         span: sub_span,
-                        base_id: id,
-                        deriv_id: item.id
-                    }.lower(self.tcx));
+                        from: ::id_from_def_id(id),
+                        to: ::id_from_node_id(item.id, &self.save_ctxt),
+                    });
                 }
             }
         }
@@ -854,21 +798,19 @@ fn process_trait(&mut self,
         self.process_generic_params(generics, item.span, &qualname, item.id);
         for method in methods {
             let map = &self.tcx.hir;
-            self.process_trait_item(method, make_def_id(item.id, map))
+            self.process_trait_item(method, map.local_def_id(item.id))
         }
     }
 
     // `item` is the module in question, represented as an item.
     fn process_mod(&mut self, item: &ast::Item) {
         if let Some(mod_data) = self.save_ctxt.get_item_data(item) {
-            down_cast_data!(mod_data, ModData, item.span);
-            if !self.span.filter_generated(Some(mod_data.span), item.span) {
-                self.dumper.mod_data(mod_data.lower(self.tcx));
-            }
+            down_cast_data!(mod_data, DefData, item.span);
+            self.dumper.dump_def(item.vis == ast::Visibility::Public, mod_data);
         }
     }
 
-    fn process_path(&mut self, id: NodeId, path: &ast::Path, ref_kind: Option<recorder::Row>) {
+    fn process_path(&mut self, id: NodeId, path: &ast::Path) {
         let path_data = self.save_ctxt.get_path_data(id, path);
         if generated_code(path.span) && path_data.is_none() {
             return;
@@ -881,81 +823,29 @@ fn process_path(&mut self, id: NodeId, path: &ast::Path, ref_kind: Option<record
             }
         };
 
-        match path_data {
-            Data::VariableRefData(vrd) => {
-                // FIXME: this whole block duplicates the code in process_def_kind
-                if !self.span.filter_generated(Some(vrd.span), path.span) {
-                    match ref_kind {
-                        Some(recorder::TypeRef) => {
-                            self.dumper.type_ref(TypeRefData {
-                                span: vrd.span,
-                                ref_id: Some(vrd.ref_id),
-                                scope: vrd.scope,
-                                qualname: String::new()
-                            }.lower(self.tcx));
-                        }
-                        Some(recorder::FnRef) => {
-                            self.dumper.function_ref(FunctionRefData {
-                                span: vrd.span,
-                                ref_id: vrd.ref_id,
-                                scope: vrd.scope
-                            }.lower(self.tcx));
-                        }
-                        Some(recorder::ModRef) => {
-                            self.dumper.mod_ref( ModRefData {
-                                span: vrd.span,
-                                ref_id: Some(vrd.ref_id),
-                                scope: vrd.scope,
-                                qualname: String::new()
-                            }.lower(self.tcx));
-                        }
-                        Some(recorder::VarRef) | None
-                            => self.dumper.variable_ref(vrd.lower(self.tcx))
-                    }
-                }
-
-            }
-            Data::TypeRefData(trd) => {
-                if !self.span.filter_generated(Some(trd.span), path.span) {
-                    self.dumper.type_ref(trd.lower(self.tcx));
-                }
-            }
-            Data::MethodCallData(mcd) => {
-                if !self.span.filter_generated(Some(mcd.span), path.span) {
-                    self.dumper.method_call(mcd.lower(self.tcx));
-                }
-            }
-            Data::FunctionCallData(fcd) => {
-                if !self.span.filter_generated(Some(fcd.span), path.span) {
-                    self.dumper.function_call(fcd.lower(self.tcx));
-                }
-            }
-            _ => {
-               span_bug!(path.span, "Unexpected data: {:?}", path_data);
-            }
-        }
+        self.dumper.dump_ref(path_data);
 
         // Modules or types in the path prefix.
         match self.save_ctxt.get_path_def(id) {
-            Def::Method(did) => {
+            HirDef::Method(did) => {
                 let ti = self.tcx.associated_item(did);
                 if ti.kind == ty::AssociatedKind::Method && ti.method_has_self_argument {
                     self.write_sub_path_trait_truncated(path);
                 }
             }
-            Def::Fn(..) |
-            Def::Const(..) |
-            Def::Static(..) |
-            Def::StructCtor(..) |
-            Def::VariantCtor(..) |
-            Def::AssociatedConst(..) |
-            Def::Local(..) |
-            Def::Upvar(..) |
-            Def::Struct(..) |
-            Def::Union(..) |
-            Def::Variant(..) |
-            Def::TyAlias(..) |
-            Def::AssociatedTy(..) => self.write_sub_paths_truncated(path),
+            HirDef::Fn(..) |
+            HirDef::Const(..) |
+            HirDef::Static(..) |
+            HirDef::StructCtor(..) |
+            HirDef::VariantCtor(..) |
+            HirDef::AssociatedConst(..) |
+            HirDef::Local(..) |
+            HirDef::Upvar(..) |
+            HirDef::Struct(..) |
+            HirDef::Union(..) |
+            HirDef::Variant(..) |
+            HirDef::TyAlias(..) |
+            HirDef::AssociatedTy(..) => self.write_sub_paths_truncated(path),
             _ => {}
         }
     }
@@ -969,20 +859,15 @@ fn process_struct_lit(&mut self,
         self.write_sub_paths_truncated(path);
 
         if let Some(struct_lit_data) = self.save_ctxt.get_expr_data(ex) {
-            down_cast_data!(struct_lit_data, TypeRefData, ex.span);
-            if !self.span.filter_generated(Some(struct_lit_data.span), ex.span) {
-                self.dumper.type_ref(struct_lit_data.lower(self.tcx));
+            down_cast_data!(struct_lit_data, RefData, ex.span);
+            if !generated_code(ex.span) {
+                self.dumper.dump_ref(struct_lit_data);
             }
 
-            let scope = self.save_ctxt.enclosing_scope(ex.id);
-
             for field in fields {
                 if let Some(field_data) = self.save_ctxt
-                                              .get_field_ref_data(field, variant, scope) {
-
-                    if !self.span.filter_generated(Some(field_data.span), field.ident.span) {
-                        self.dumper.variable_ref(field_data.lower(self.tcx));
-                    }
+                                              .get_field_ref_data(field, variant) {
+                    self.dumper.dump_ref(field_data);
                 }
 
                 self.visit_expr(&field.expr)
@@ -994,9 +879,9 @@ fn process_struct_lit(&mut self,
 
     fn process_method_call(&mut self, ex: &'l ast::Expr, args: &'l [P<ast::Expr>]) {
         if let Some(mcd) = self.save_ctxt.get_expr_data(ex) {
-            down_cast_data!(mcd, MethodCallData, ex.span);
-            if !self.span.filter_generated(Some(mcd.span), ex.span) {
-                self.dumper.method_call(mcd.lower(self.tcx));
+            down_cast_data!(mcd, RefData, ex.span);
+            if !generated_code(ex.span) {
+                self.dumper.dump_ref(mcd);
             }
         }
 
@@ -1021,12 +906,13 @@ fn process_pat(&mut self, p: &'l ast::Pat) {
                     let sub_span = self.span.span_for_first_ident(span);
                     if let Some(f) = variant.find_field_named(field.ident.name) {
                         if !self.span.filter_generated(sub_span, span) {
-                            self.dumper.variable_ref(VariableRefData {
-                                span: sub_span.expect("No span fund for var ref"),
-                                ref_id: f.did,
-                                scope: self.cur_scope,
-                                name: String::new()
-                            }.lower(self.tcx));
+                            let span =
+                                self.span_from_span(sub_span.expect("No span fund for var ref"));
+                            self.dumper.dump_ref(Ref {
+                                kind: RefKind::Variable,
+                                span,
+                                ref_id: ::id_from_def_id(f.did),
+                            });
                         }
                     }
                     self.visit_pat(&field.pat);
@@ -1044,7 +930,7 @@ fn process_var_decl(&mut self, p: &'l ast::Pat, value: String) {
         collector.visit_pat(&p);
         self.visit_pat(&p);
 
-        for &(id, ref p, immut, _) in &collector.collected_paths {
+        for &(id, ref p, immut) in &collector.collected_paths {
             let mut value = match immut {
                 ast::Mutability::Immutable => value.to_string(),
                 _ => String::new(),
@@ -1066,21 +952,24 @@ fn process_var_decl(&mut self, p: &'l ast::Pat, value: String) {
             let sub_span = self.span.span_for_last_ident(p.span);
             // Rust uses the id of the pattern for var lookups, so we'll use it too.
             if !self.span.filter_generated(sub_span, p.span) {
-                self.dumper.variable(VariableData {
-                    span: sub_span.expect("No span found for variable"),
-                    kind: VariableKind::Local,
-                    id: id,
+                let qualname = format!("{}${}", path_to_string(p), id);
+                let id = ::id_from_node_id(id, &self.save_ctxt);
+                let span = self.span_from_span(sub_span.expect("No span found for variable"));
+
+                self.dumper.dump_def(false, Def {
+                    kind: DefKind::Local,
+                    id,
+                    span,
                     name: path_to_string(p),
-                    qualname: format!("{}${}", path_to_string(p), id),
-                    value: value,
-                    type_value: typ,
-                    scope: CRATE_NODE_ID,
+                    qualname,
+                    value: typ,
                     parent: None,
-                    visibility: Visibility::Inherited,
+                    children: vec![],
+                    decl_id: None,
                     docs: String::new(),
                     sig: None,
-                    attributes: vec![],
-                }.lower(self.tcx));
+                    attributes:vec![],
+                });
             }
         }
     }
@@ -1092,125 +981,133 @@ fn process_var_decl(&mut self, p: &'l ast::Pat, value: String) {
     /// If the span is not macro-generated, do nothing, else use callee and
     /// callsite spans to record macro definition and use data, using the
     /// mac_uses and mac_defs sets to prevent multiples.
-    fn process_macro_use(&mut self, span: Span, id: NodeId) {
-        let data = match self.save_ctxt.get_macro_use_data(span, id) {
+    fn process_macro_use(&mut self, span: Span) {
+        let source_span = span.source_callsite();
+        if self.macro_calls.contains(&source_span) {
+            return;
+        }
+        self.macro_calls.insert(source_span);
+
+        let data = match self.save_ctxt.get_macro_use_data(span) {
             None => return,
             Some(data) => data,
         };
-        let mut hasher = DefaultHasher::new();
-        data.callee_span.hash(&mut hasher);
-        let hash = hasher.finish();
-        let qualname = format!("{}::{}", data.name, hash);
+
+        self.dumper.macro_use(data);
+
+        // FIXME write the macro def
+        // let mut hasher = DefaultHasher::new();
+        // data.callee_span.hash(&mut hasher);
+        // let hash = hasher.finish();
+        // let qualname = format!("{}::{}", data.name, hash);
         // Don't write macro definition for imported macros
-        if !self.mac_defs.contains(&data.callee_span)
-            && !data.imported {
-            self.mac_defs.insert(data.callee_span);
-            if let Some(sub_span) = self.span.span_for_macro_def_name(data.callee_span) {
-                self.dumper.macro_data(MacroData {
-                    span: sub_span,
-                    name: data.name.clone(),
-                    qualname: qualname.clone(),
-                    // FIXME where do macro docs come from?
-                    docs: String::new(),
-                }.lower(self.tcx));
-            }
-        }
-        if !self.mac_uses.contains(&data.span) {
-            self.mac_uses.insert(data.span);
-            if let Some(sub_span) = self.span.span_for_macro_use_name(data.span) {
-                self.dumper.macro_use(MacroUseData {
-                    span: sub_span,
-                    name: data.name,
-                    qualname: qualname,
-                    scope: data.scope,
-                    callee_span: data.callee_span,
-                    imported: data.imported,
-                }.lower(self.tcx));
-            }
-        }
+        // if !self.mac_defs.contains(&data.callee_span)
+        //     && !data.imported {
+        //     self.mac_defs.insert(data.callee_span);
+        //     if let Some(sub_span) = self.span.span_for_macro_def_name(data.callee_span) {
+        //         self.dumper.macro_data(MacroData {
+        //             span: sub_span,
+        //             name: data.name.clone(),
+        //             qualname: qualname.clone(),
+        //             // FIXME where do macro docs come from?
+        //             docs: String::new(),
+        //         }.lower(self.tcx));
+        //     }
+        // }
     }
 
     fn process_trait_item(&mut self, trait_item: &'l ast::TraitItem, trait_id: DefId) {
-        self.process_macro_use(trait_item.span, trait_item.id);
+        self.process_macro_use(trait_item.span);
         match trait_item.node {
-            ast::TraitItemKind::Const(ref ty, Some(ref expr)) => {
+            ast::TraitItemKind::Const(ref ty, ref expr) => {
                 self.process_assoc_const(trait_item.id,
                                          trait_item.ident.name,
                                          trait_item.span,
                                          &ty,
-                                         &expr,
+                                         expr.as_ref().map(|e| &**e),
                                          trait_id,
-                                         Visibility::Public,
+                                         ast::Visibility::Public,
                                          &trait_item.attrs);
             }
             ast::TraitItemKind::Method(ref sig, ref body) => {
                 self.process_method(sig,
                                     body.as_ref().map(|x| &**x),
                                     trait_item.id,
-                                    trait_item.ident.name,
-                                    Visibility::Public,
-                                    &trait_item.attrs,
+                                    trait_item.ident,
+                                    ast::Visibility::Public,
                                     trait_item.span);
             }
-            ast::TraitItemKind::Type(ref _bounds, ref default_ty) => {
+            ast::TraitItemKind::Type(ref bounds, ref default_ty) => {
                 // FIXME do something with _bounds (for type refs)
                 let name = trait_item.ident.name.to_string();
                 let qualname = format!("::{}", self.tcx.node_path_str(trait_item.id));
                 let sub_span = self.span.sub_span_after_keyword(trait_item.span, keywords::Type);
 
                 if !self.span.filter_generated(sub_span, trait_item.span) {
-                    self.dumper.typedef(TypeDefData {
-                        span: sub_span.expect("No span found for assoc type"),
-                        name: name,
-                        id: trait_item.id,
-                        qualname: qualname,
+                    let span = self.span_from_span(sub_span.expect("No span found for assoc type"));
+                    let id = ::id_from_node_id(trait_item.id, &self.save_ctxt);
+
+                    self.dumper.dump_def(true, Def {
+                        kind: DefKind::Type,
+                        id,
+                        span,
+                        name,
+                        qualname,
                         value: self.span.snippet(trait_item.span),
-                        visibility: Visibility::Public,
-                        parent: Some(trait_id),
-                        docs: docs_for_attrs(&trait_item.attrs),
-                        sig: None,
-                        attributes: trait_item.attrs.clone(),
-                    }.lower(self.tcx));
+                        parent: Some(::id_from_def_id(trait_id)),
+                        children: vec![],
+                        decl_id: None,
+                        docs: self.save_ctxt.docs_for_attrs(&trait_item.attrs),
+                        sig: sig::assoc_type_signature(trait_item.id,
+                                                       trait_item.ident,
+                                                       Some(bounds),
+                                                       default_ty.as_ref().map(|ty| &**ty),
+                                                       &self.save_ctxt),
+                        attributes: lower_attributes(trait_item.attrs.clone(), &self.save_ctxt),
+                    });
                 }
 
                 if let &Some(ref default_ty) = default_ty {
                     self.visit_ty(default_ty)
                 }
             }
-            ast::TraitItemKind::Const(ref ty, None) => self.visit_ty(ty),
             ast::TraitItemKind::Macro(_) => {}
         }
     }
 
     fn process_impl_item(&mut self, impl_item: &'l ast::ImplItem, impl_id: DefId) {
-        self.process_macro_use(impl_item.span, impl_item.id);
+        self.process_macro_use(impl_item.span);
         match impl_item.node {
             ast::ImplItemKind::Const(ref ty, ref expr) => {
                 self.process_assoc_const(impl_item.id,
                                          impl_item.ident.name,
                                          impl_item.span,
                                          &ty,
-                                         &expr,
+                                         Some(expr),
                                          impl_id,
-                                         From::from(&impl_item.vis),
+                                         impl_item.vis.clone(),
                                          &impl_item.attrs);
             }
             ast::ImplItemKind::Method(ref sig, ref body) => {
                 self.process_method(sig,
                                     Some(body),
                                     impl_item.id,
-                                    impl_item.ident.name,
-                                    From::from(&impl_item.vis),
-                                    &impl_item.attrs,
+                                    impl_item.ident,
+                                    impl_item.vis.clone(),
                                     impl_item.span);
             }
-            ast::ImplItemKind::Type(ref ty) => self.visit_ty(ty),
+            ast::ImplItemKind::Type(ref ty) => {
+                // FIXME uses of the assoc type should ideally point to this
+                // 'def' and the name here should be a ref to the def in the
+                // trait.
+                self.visit_ty(ty)
+            }
             ast::ImplItemKind::Macro(_) => {}
         }
     }
 }
 
-impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, D> {
+impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, O> {
     fn visit_mod(&mut self, m: &'l ast::Mod, span: Span, attrs: &[ast::Attribute], id: NodeId) {
         // Since we handle explicit modules ourselves in visit_item, this should
         // only get called for the root module of a crate.
@@ -1220,25 +1117,30 @@ fn visit_mod(&mut self, m: &'l ast::Mod, span: Span, attrs: &[ast::Attribute], i
 
         let cm = self.tcx.sess.codemap();
         let filename = cm.span_to_filename(span);
-        self.dumper.mod_data(ModData {
-            id: id,
+        let data_id = ::id_from_node_id(id, &self.save_ctxt);
+        let children = m.items.iter().map(|i| ::id_from_node_id(i.id, &self.save_ctxt)).collect();
+        let span = self.span_from_span(span);
+
+        self.dumper.dump_def(true, Def {
+            kind: DefKind::Mod,
+            id: data_id,
             name: String::new(),
-            qualname: qualname,
-            span: span,
-            scope: id,
-            filename: filename,
-            items: m.items.iter().map(|i| i.id).collect(),
-            visibility: Visibility::Public,
-            docs: docs_for_attrs(attrs),
+            qualname,
+            span,
+            value: filename,
+            children,
+            parent: None,
+            decl_id: None,
+            docs: self.save_ctxt.docs_for_attrs(attrs),
             sig: None,
-            attributes: attrs.to_owned(),
-        }.lower(self.tcx));
+            attributes: lower_attributes(attrs.to_owned(), &self.save_ctxt),
+        });
         self.nest_scope(id, |v| visit::walk_mod(v, m));
     }
 
     fn visit_item(&mut self, item: &'l ast::Item) {
         use syntax::ast::ItemKind::*;
-        self.process_macro_use(item.span, item.id);
+        self.process_macro_use(item.span);
         match item.node {
             Use(ref use_item) => {
                 match use_item.node {
@@ -1246,9 +1148,7 @@ fn visit_item(&mut self, item: &'l ast::Item) {
                         let sub_span = self.span.span_for_last_ident(path.span);
                         let mod_id = match self.lookup_def_id(item.id) {
                             Some(def_id) => {
-                                let scope = self.cur_scope;
-                                self.process_def_kind(item.id, path.span, sub_span, def_id, scope);
-
+                                self.process_def_kind(item.id, path.span, sub_span, def_id);
                                 Some(def_id)
                             }
                             None => None,
@@ -1263,14 +1163,15 @@ fn visit_item(&mut self, item: &'l ast::Item) {
                         };
 
                         if !self.span.filter_generated(sub_span, path.span) {
-                            self.dumper.use_data(UseData {
-                                span: sub_span.expect("No span found for use"),
-                                id: item.id,
-                                mod_id: mod_id,
+                            let span =
+                                self.span_from_span(sub_span.expect("No span found for use"));
+                            self.dumper.import(item.vis == ast::Visibility::Public, Import {
+                                kind: ImportKind::Use,
+                                ref_id: mod_id.map(|id| ::id_from_def_id(id)),
+                                span,
                                 name: ident.to_string(),
-                                scope: self.cur_scope,
-                                visibility: From::from(&item.vis),
-                            }.lower(self.tcx));
+                                value: String::new(),
+                            });
                         }
                         self.write_sub_paths_truncated(path);
                     }
@@ -1288,23 +1189,24 @@ fn visit_item(&mut self, item: &'l ast::Item) {
                         let sub_span = self.span
                                            .sub_span_of_token(item.span, token::BinOp(token::Star));
                         if !self.span.filter_generated(sub_span, item.span) {
-                            self.dumper.use_glob(UseGlobData {
-                                span: sub_span.expect("No span found for use glob"),
-                                id: item.id,
-                                names: names,
-                                scope: self.cur_scope,
-                                visibility: From::from(&item.vis),
-                            }.lower(self.tcx));
+                            let span =
+                                self.span_from_span(sub_span.expect("No span found for use glob"));
+                            self.dumper.import(item.vis == ast::Visibility::Public, Import {
+                                kind: ImportKind::GlobUse,
+                                ref_id: None,
+                                span,
+                                name: "*".to_owned(),
+                                value: names.join(", "),
+                            });
                         }
                         self.write_sub_paths(path);
                     }
                     ast::ViewPathList(ref path, ref list) => {
                         for plid in list {
-                            let scope = self.cur_scope;
                             let id = plid.node.id;
                             if let Some(def_id) = self.lookup_def_id(id) {
                                 let span = plid.span;
-                                self.process_def_kind(id, span, Some(span), def_id, scope);
+                                self.process_def_kind(id, span, Some(span), def_id);
                             }
                         }
 
@@ -1312,26 +1214,19 @@ fn visit_item(&mut self, item: &'l ast::Item) {
                     }
                 }
             }
-            ExternCrate(ref s) => {
-                let location = match *s {
-                    Some(s) => s.to_string(),
-                    None => item.ident.to_string(),
-                };
+            ExternCrate(_) => {
                 let alias_span = self.span.span_for_last_ident(item.span);
-                let cnum = match self.sess.cstore.extern_mod_stmt_cnum(item.id) {
-                    Some(cnum) => cnum,
-                    None => LOCAL_CRATE,
-                };
 
                 if !self.span.filter_generated(alias_span, item.span) {
-                    self.dumper.extern_crate(ExternCrateData {
-                        id: item.id,
+                    let span =
+                        self.span_from_span(alias_span.expect("No span found for extern crate"));
+                    self.dumper.import(false, Import {
+                        kind: ImportKind::ExternCrate,
+                        ref_id: None,
+                        span,
                         name: item.ident.to_string(),
-                        crate_num: cnum,
-                        location: location,
-                        span: alias_span.expect("No span found for extern crate"),
-                        scope: self.cur_scope,
-                    }.lower(self.tcx));
+                        value: String::new(),
+                    });
                 }
             }
             Fn(ref decl, .., ref ty_params, ref body) =>
@@ -1360,18 +1255,23 @@ fn visit_item(&mut self, item: &'l ast::Item) {
                 let value = ty_to_string(&ty);
                 let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Type);
                 if !self.span.filter_generated(sub_span, item.span) {
-                    self.dumper.typedef(TypeDefData {
-                        span: sub_span.expect("No span found for typedef"),
+                    let span = self.span_from_span(sub_span.expect("No span found for typedef"));
+                    let id = ::id_from_node_id(item.id, &self.save_ctxt);
+
+                    self.dumper.dump_def(item.vis == ast::Visibility::Public, Def {
+                        kind: DefKind::Type,
+                        id,
+                        span,
                         name: item.ident.to_string(),
-                        id: item.id,
                         qualname: qualname.clone(),
-                        value: value,
-                        visibility: From::from(&item.vis),
+                        value,
                         parent: None,
-                        docs: docs_for_attrs(&item.attrs),
-                        sig: Some(self.save_ctxt.sig_base(item)),
-                        attributes: item.attrs.clone(),
-                    }.lower(self.tcx));
+                        children: vec![],
+                        decl_id: None,
+                        docs: self.save_ctxt.docs_for_attrs(&item.attrs),
+                        sig: sig::item_signature(item, &self.save_ctxt),
+                        attributes: lower_attributes(item.attrs.clone(), &self.save_ctxt),
+                    });
                 }
 
                 self.visit_ty(&ty);
@@ -1396,7 +1296,7 @@ fn visit_generics(&mut self, generics: &'l ast::Generics) {
     }
 
     fn visit_ty(&mut self, t: &'l ast::Ty) {
-        self.process_macro_use(t.span, t.id);
+        self.process_macro_use(t.span);
         match t.node {
             ast::TyKind::Path(_, ref path) => {
                 if generated_code(t.span) {
@@ -1405,12 +1305,12 @@ fn visit_ty(&mut self, t: &'l ast::Ty) {
 
                 if let Some(id) = self.lookup_def_id(t.id) {
                     if let Some(sub_span) = self.span.sub_span_for_type_name(t.span) {
-                        self.dumper.type_ref(TypeRefData {
-                            span: sub_span,
-                            ref_id: Some(id),
-                            scope: self.cur_scope,
-                            qualname: String::new()
-                        }.lower(self.tcx));
+                        let span = self.span_from_span(sub_span);
+                        self.dumper.dump_ref(Ref {
+                            kind: RefKind::Type,
+                            span,
+                            ref_id: ::id_from_def_id(id),
+                        });
                     }
                 }
 
@@ -1427,13 +1327,13 @@ fn visit_ty(&mut self, t: &'l ast::Ty) {
 
     fn visit_expr(&mut self, ex: &'l ast::Expr) {
         debug!("visit_expr {:?}", ex.node);
-        self.process_macro_use(ex.span, ex.id);
+        self.process_macro_use(ex.span);
         match ex.node {
             ast::ExprKind::Struct(ref path, ref fields, ref base) => {
                 let hir_expr = self.save_ctxt.tcx.hir.expect_expr(ex.id);
                 let adt = match self.save_ctxt.tables.expr_ty_opt(&hir_expr) {
-                    Some(ty) => ty.ty_adt_def().unwrap(),
-                    None => {
+                    Some(ty) if ty.ty_adt_def().is_some() => ty.ty_adt_def().unwrap(),
+                    _ => {
                         visit::walk_expr(self, ex);
                         return;
                     }
@@ -1446,9 +1346,9 @@ fn visit_expr(&mut self, ex: &'l ast::Expr) {
                 self.visit_expr(&sub_ex);
 
                 if let Some(field_data) = self.save_ctxt.get_expr_data(ex) {
-                    down_cast_data!(field_data, VariableRefData, ex.span);
-                    if !self.span.filter_generated(Some(field_data.span), ex.span) {
-                        self.dumper.variable_ref(field_data.lower(self.tcx));
+                    down_cast_data!(field_data, RefData, ex.span);
+                    if !generated_code(ex.span) {
+                        self.dumper.dump_ref(field_data);
                     }
                 }
             }
@@ -1474,12 +1374,13 @@ fn visit_expr(&mut self, ex: &'l ast::Expr) {
                     ty::TyAdt(def, _) => {
                         let sub_span = self.span.sub_span_after_token(ex.span, token::Dot);
                         if !self.span.filter_generated(sub_span, ex.span) {
-                            self.dumper.variable_ref(VariableRefData {
-                                span: sub_span.expect("No span found for var ref"),
-                                ref_id: def.struct_variant().fields[idx.node].did,
-                                scope: self.cur_scope,
-                                name: String::new()
-                            }.lower(self.tcx));
+                            let span =
+                                self.span_from_span(sub_span.expect("No span found for var ref"));
+                            self.dumper.dump_ref(Ref {
+                                kind: RefKind::Variable,
+                                span: span,
+                                ref_id: ::id_from_def_id(def.struct_variant().fields[idx.node].did),
+                            });
                         }
                     }
                     ty::TyTuple(..) => {}
@@ -1540,7 +1441,7 @@ fn visit_mac(&mut self, mac: &'l ast::Mac) {
     }
 
     fn visit_pat(&mut self, p: &'l ast::Pat) {
-        self.process_macro_use(p.span, p.id);
+        self.process_macro_use(p.span);
         self.process_pat(p);
     }
 
@@ -1556,9 +1457,9 @@ fn visit_arm(&mut self, arm: &'l ast::Arm) {
         let mut paths_to_process = vec![];
 
         // process collected paths
-        for &(id, ref p, immut, ref_kind) in &collector.collected_paths {
+        for &(id, ref p, immut) in &collector.collected_paths {
             match self.save_ctxt.get_path_def(id) {
-                Def::Local(def_id) => {
+                HirDef::Local(def_id) => {
                     let id = self.tcx.hir.as_local_node_id(def_id).unwrap();
                     let mut value = if immut == ast::Mutability::Immutable {
                         self.span.snippet(p.span).to_string()
@@ -1573,53 +1474,56 @@ fn visit_arm(&mut self, arm: &'l ast::Arm) {
                     assert!(p.segments.len() == 1,
                             "qualified path for local variable def in arm");
                     if !self.span.filter_generated(Some(p.span), p.span) {
-                        self.dumper.variable(VariableData {
-                            span: p.span,
-                            kind: VariableKind::Local,
-                            id: id,
+                        let qualname = format!("{}${}", path_to_string(p), id);
+                        let id = ::id_from_node_id(id, &self.save_ctxt);
+                        let span = self.span_from_span(p.span);
+
+                        self.dumper.dump_def(false, Def {
+                            kind: DefKind::Local,
+                            id,
+                            span,
                             name: path_to_string(p),
-                            qualname: format!("{}${}", path_to_string(p), id),
-                            value: value,
-                            type_value: typ,
-                            scope: CRATE_NODE_ID,
+                            qualname,
+                            value: typ,
                             parent: None,
-                            visibility: Visibility::Inherited,
+                            children: vec![],
+                            decl_id: None,
                             docs: String::new(),
                             sig: None,
-                            attributes: vec![],
-                        }.lower(self.tcx));
+                            attributes:vec![],
+                        });
                     }
                 }
-                Def::StructCtor(..) | Def::VariantCtor(..) |
-                Def::Const(..) | Def::AssociatedConst(..) |
-                Def::Struct(..) | Def::Variant(..) |
-                Def::TyAlias(..) | Def::AssociatedTy(..) |
-                Def::SelfTy(..) => {
-                    paths_to_process.push((id, p.clone(), Some(ref_kind)))
+                HirDef::StructCtor(..) | HirDef::VariantCtor(..) |
+                HirDef::Const(..) | HirDef::AssociatedConst(..) |
+                HirDef::Struct(..) | HirDef::Variant(..) |
+                HirDef::TyAlias(..) | HirDef::AssociatedTy(..) |
+                HirDef::SelfTy(..) => {
+                    paths_to_process.push((id, p.clone()))
                 }
                 def => error!("unexpected definition kind when processing collected paths: {:?}",
                               def),
             }
         }
 
-        for &(id, ref path, ref_kind) in &paths_to_process {
-            self.process_path(id, path, ref_kind);
+        for &(id, ref path) in &paths_to_process {
+            self.process_path(id, path);
         }
         walk_list!(self, visit_expr, &arm.guard);
         self.visit_expr(&arm.body);
     }
 
     fn visit_path(&mut self, p: &'l ast::Path, id: NodeId) {
-        self.process_path(id, p, None);
+        self.process_path(id, p);
     }
 
     fn visit_stmt(&mut self, s: &'l ast::Stmt) {
-        self.process_macro_use(s.span, s.id);
+        self.process_macro_use(s.span);
         visit::walk_stmt(self, s)
     }
 
     fn visit_local(&mut self, l: &'l ast::Local) {
-        self.process_macro_use(l.span, l.id);
+        self.process_macro_use(l.span);
         let value = l.init.as_ref().map(|i| self.span.snippet(i.span)).unwrap_or(String::new());
         self.process_var_decl(&l.pat, value);
 
@@ -1632,14 +1536,12 @@ fn visit_foreign_item(&mut self, item: &'l ast::ForeignItem) {
         match item.node {
             ast::ForeignItemKind::Fn(ref decl, ref generics) => {
                 if let Some(fn_data) = self.save_ctxt.get_extern_item_data(item) {
-                    down_cast_data!(fn_data, FunctionData, item.span);
-                    if !self.span.filter_generated(Some(fn_data.span), item.span) {
-                        self.dumper.function(fn_data.clone().lower(self.tcx));
-                    }
+                    down_cast_data!(fn_data, DefData, item.span);
 
                     self.nest_tables(item.id, |v| v.process_formals(&decl.inputs,
                                                                     &fn_data.qualname));
                     self.process_generic_params(generics, item.span, &fn_data.qualname, item.id);
+                    self.dumper.dump_def(item.vis == ast::Visibility::Public, fn_data);
                 }
 
                 for arg in &decl.inputs {
@@ -1652,10 +1554,8 @@ fn visit_foreign_item(&mut self, item: &'l ast::ForeignItem) {
             }
             ast::ForeignItemKind::Static(ref ty, _) => {
                 if let Some(var_data) = self.save_ctxt.get_extern_item_data(item) {
-                    down_cast_data!(var_data, VariableData, item.span);
-                    if !self.span.filter_generated(Some(var_data.span), item.span) {
-                        self.dumper.variable(var_data.lower(self.tcx));
-                    }
+                    down_cast_data!(var_data, DefData, item.span);
+                    self.dumper.dump_def(item.vis == ast::Visibility::Public, var_data);
                 }
 
                 self.visit_ty(ty);