about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-06-17 04:36:02 +0000
committerbors <bors@rust-lang.org>2017-06-17 04:36:02 +0000
commit08d920cd4d95cc3e3c6ee3dd1ad5c98a4c58639e (patch)
treed5d681951bd035ed2c0d3deb4f486e62a013d6c6
parent3438c0fa8c45255ac7b8813c1253d1b59febb081 (diff)
parent8a2857e6449c1b90355223367fb4884adb0ba860 (diff)
downloadrust-08d920cd4d95cc3e3c6ee3dd1ad5c98a4c58639e.tar.gz
rust-08d920cd4d95cc3e3c6ee3dd1ad5c98a4c58639e.zip
Auto merge of #42650 - nrc:save-slim, r=eddyb
save-analysis: remove a lot of stuff

This commits us to the JSON format and the more general def/ref style of output, rather than also supporting different data formats for different data structures. This does not affect the RLS at all, but will break any clients of the CSV form - AFAIK there are none (beyond a few of my own toy projects) - DXR stopped working long ago.

r? @eddyb
-rw-r--r--src/librustc/session/config.rs4
-rw-r--r--src/librustc_driver/lib.rs3
-rw-r--r--src/librustc_save_analysis/csv_dumper.rs436
-rw-r--r--src/librustc_save_analysis/data.rs421
-rw-r--r--src/librustc_save_analysis/dump.rs40
-rw-r--r--src/librustc_save_analysis/dump_visitor.rs998
-rw-r--r--src/librustc_save_analysis/external_data.rs748
-rw-r--r--src/librustc_save_analysis/json_api_dumper.rs308
-rw-r--r--src/librustc_save_analysis/json_dumper.rs401
-rw-r--r--src/librustc_save_analysis/lib.rs635
-rw-r--r--src/librustc_save_analysis/span_utils.rs129
-rw-r--r--src/test/run-make/save-analysis/Makefile1
12 files changed, 844 insertions, 3280 deletions
diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index f9459953518..4d6579cb204 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -935,8 +935,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
     save_analysis: bool = (false, parse_bool, [UNTRACKED],
         "write syntax and type analysis (in JSON format) information, in \
          addition to normal output"),
-    save_analysis_csv: bool = (false, parse_bool, [UNTRACKED],
-        "write syntax and type analysis (in CSV format) information, in addition to normal output"),
     save_analysis_api: bool = (false, parse_bool, [UNTRACKED],
         "write syntax and type analysis information for opaque libraries (in JSON format), \
          in addition to normal output"),
@@ -2471,8 +2469,6 @@ mod tests {
         assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
         opts.debugging_opts.save_analysis = true;
         assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
-        opts.debugging_opts.save_analysis_csv = true;
-        assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
         opts.debugging_opts.save_analysis_api = true;
         assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
         opts.debugging_opts.print_move_fragments = true;
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index 8bd992b12e6..6839274800c 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -534,15 +534,12 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls {
 
 fn save_analysis(sess: &Session) -> bool {
     sess.opts.debugging_opts.save_analysis ||
-    sess.opts.debugging_opts.save_analysis_csv ||
     sess.opts.debugging_opts.save_analysis_api
 }
 
 fn save_analysis_format(sess: &Session) -> save::Format {
     if sess.opts.debugging_opts.save_analysis {
         save::Format::Json
-    } else if sess.opts.debugging_opts.save_analysis_csv {
-        save::Format::Csv
     } else if sess.opts.debugging_opts.save_analysis_api {
         save::Format::JsonApi
     } else {
diff --git a/src/librustc_save_analysis/csv_dumper.rs b/src/librustc_save_analysis/csv_dumper.rs
deleted file mode 100644
index 4bab135ff12..00000000000
--- a/src/librustc_save_analysis/csv_dumper.rs
+++ /dev/null
@@ -1,436 +0,0 @@
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use std::io::Write;
-
-use super::external_data::*;
-use super::dump::Dump;
-
-use rls_data::{SpanData, CratePreludeData};
-
-pub struct CsvDumper<'b, W: 'b> {
-    output: &'b mut W
-}
-
-impl<'b, W: Write> CsvDumper<'b, W> {
-    pub fn new(writer: &'b mut W) -> CsvDumper<'b, W> {
-        CsvDumper { output: writer }
-    }
-
-    fn record(&mut self, kind: &str, span: SpanData, values: String) {
-        let span_str = span_extent_str(span);
-        if let Err(_) = write!(self.output, "{},{}{}\n", kind, span_str, values) {
-            error!("Error writing output");
-        }
-    }
-
-    fn record_raw(&mut self, info: &str) {
-        if let Err(_) = write!(self.output, "{}", info) {
-            error!("Error writing output '{}'", info);
-        }
-    }
-}
-
-impl<'b, W: Write + 'b> Dump for CsvDumper<'b, W> {
-    fn crate_prelude(&mut self, data: CratePreludeData) {
-        let values = make_values_str(&[
-            ("name", &data.crate_name),
-            ("crate_root", &data.crate_root)
-        ]);
-
-        self.record("crate", data.span, values);
-
-        for c in data.external_crates {
-            let num = c.num.to_string();
-            let values = make_values_str(&[
-                ("name", &c.name),
-                ("crate", &num),
-                ("file_name", &c.file_name)
-            ]);
-
-            self.record_raw(&format!("external_crate{}\n", values));
-        }
-
-        self.record_raw("end_external_crates\n");
-    }
-
-    fn enum_data(&mut self, data: EnumData) {
-        let id = data.id.index.as_u32().to_string();
-        let scope = data.scope.index.as_u32().to_string();
-        let values = make_values_str(&[
-            ("id", &id),
-            ("qualname", &data.qualname),
-            ("scopeid", &scope),
-            ("value", &data.value)
-        ]);
-
-        self.record("enum", data.span, values);
-    }
-
-    fn extern_crate(&mut self, data: ExternCrateData) {
-        let id = data.id.index.as_u32().to_string();
-        let crate_num = data.crate_num.to_string();
-        let scope = data.scope.index.as_u32().to_string();
-        let values = make_values_str(&[
-            ("id", &id),
-            ("name", &data.name),
-            ("location", &data.location),
-            ("crate", &crate_num),
-            ("scopeid", &scope)
-        ]);
-
-        self.record("extern_crate", data.span, values);
-    }
-
-    fn impl_data(&mut self, data: ImplData) {
-        let self_ref = data.self_ref.unwrap_or(null_def_id());
-        let trait_ref = data.trait_ref.unwrap_or(null_def_id());
-
-        let id = data.id.index.as_u32().to_string();
-        let ref_id = self_ref.index.as_usize().to_string();
-        let ref_id_crate = self_ref.krate.to_string();
-        let trait_id = trait_ref.index.as_usize().to_string();
-        let trait_id_crate = trait_ref.krate.to_string();
-        let scope = data.scope.index.as_u32().to_string();
-        let values = make_values_str(&[
-            ("id", &id),
-            ("refid", &ref_id),
-            ("refidcrate", &ref_id_crate),
-            ("traitid", &trait_id),
-            ("traitidcrate", &trait_id_crate),
-            ("scopeid", &scope)
-        ]);
-
-        self.record("impl", data.span, values);
-    }
-
-    fn inheritance(&mut self, data: InheritanceData) {
-       let base_id = data.base_id.index.as_usize().to_string();
-       let base_crate = data.base_id.krate.to_string();
-       let deriv_id = data.deriv_id.index.as_u32().to_string();
-       let deriv_crate = data.deriv_id.krate.to_string();
-       let values = make_values_str(&[
-           ("base", &base_id),
-           ("basecrate", &base_crate),
-           ("derived", &deriv_id),
-           ("derivedcrate", &deriv_crate)
-       ]);
-
-       self.record("inheritance", data.span, values);
-    }
-
-    fn function(&mut self, data: FunctionData) {
-        let (decl_id, decl_crate) = match data.declaration {
-            Some(id) => (id.index.as_usize().to_string(), id.krate.to_string()),
-            None => (String::new(), String::new())
-        };
-
-        let id = data.id.index.as_u32().to_string();
-        let scope = data.scope.index.as_u32().to_string();
-        let values = make_values_str(&[
-            ("id", &id),
-            ("qualname", &data.qualname),
-            ("declid", &decl_id),
-            ("declidcrate", &decl_crate),
-            ("scopeid", &scope)
-        ]);
-
-        self.record("function", data.span, values);
-    }
-
-    fn function_ref(&mut self, data: FunctionRefData) {
-        let ref_id = data.ref_id.index.as_usize().to_string();
-        let ref_crate = data.ref_id.krate.to_string();
-        let scope = data.scope.index.as_u32().to_string();
-        let values = make_values_str(&[
-            ("refid", &ref_id),
-            ("refidcrate", &ref_crate),
-            ("qualname", ""),
-            ("scopeid", &scope)
-        ]);
-
-        self.record("fn_ref", data.span, values);
-    }
-
-    fn function_call(&mut self, data: FunctionCallData) {
-        let ref_id = data.ref_id.index.as_usize().to_string();
-        let ref_crate = data.ref_id.krate.to_string();
-        let qualname = String::new();
-        let scope = data.scope.index.as_u32().to_string();
-        let values = make_values_str(&[
-            ("refid", &ref_id),
-            ("refidcrate", &ref_crate),
-            ("qualname", &qualname),
-            ("scopeid", &scope)
-        ]);
-
-        self.record("fn_call", data.span, values);
-    }
-
-    fn method(&mut self, data: MethodData) {
-        let id = data.id.index.as_u32().to_string();
-        let scope = data.scope.index.as_u32().to_string();
-        let values = make_values_str(&[
-            ("id", &id),
-            ("qualname", &data.qualname),
-            ("scopeid", &scope)
-        ]);
-
-        self.record("method_decl", data.span, values);
-    }
-
-    fn method_call(&mut self, data: MethodCallData) {
-        let (dcn, dck) = match data.decl_id {
-            Some(declid) => (declid.index.as_usize().to_string(), declid.krate.to_string()),
-            None => (String::new(), String::new()),
-        };
-
-        let ref_id = data.ref_id.unwrap_or(null_def_id());
-
-        let def_id = ref_id.index.as_usize().to_string();
-        let def_crate = ref_id.krate.to_string();
-        let scope = data.scope.index.as_u32().to_string();
-        let values = make_values_str(&[
-            ("refid", &def_id),
-            ("refidcrate", &def_crate),
-            ("declid", &dcn),
-            ("declidcrate", &dck),
-            ("scopeid", &scope)
-        ]);
-
-        self.record("method_call", data.span, values);
-    }
-
-    fn macro_data(&mut self, data: MacroData) {
-        let values = make_values_str(&[
-            ("name", &data.name),
-            ("qualname", &data.qualname)
-        ]);
-
-        self.record("macro", data.span, values);
-    }
-
-    fn macro_use(&mut self, data: MacroUseData) {
-        let scope = data.scope.index.as_u32().to_string();
-        let values = make_values_str(&[
-            ("callee_name", &data.name),
-            ("qualname", &data.qualname),
-            ("scopeid", &scope)
-        ]);
-
-        self.record("macro_use", data.span, values);
-    }
-
-    fn mod_data(&mut self, data: ModData) {
-        let id = data.id.index.as_u32().to_string();
-        let scope = data.scope.index.as_u32().to_string();
-        let values = make_values_str(&[
-            ("id", &id),
-            ("qualname", &data.qualname),
-            ("scopeid", &scope),
-            ("def_file", &data.filename)
-        ]);
-
-        self.record("module", data.span, values);
-    }
-
-    fn mod_ref(&mut self, data: ModRefData) {
-        let (ref_id, ref_crate) = match data.ref_id {
-            Some(rid) => (rid.index.as_usize().to_string(), rid.krate.to_string()),
-            None => (0.to_string(), 0.to_string())
-        };
-
-        let scope = data.scope.index.as_u32().to_string();
-        let values = make_values_str(&[
-            ("refid", &ref_id),
-            ("refidcrate", &ref_crate),
-            ("qualname", &data.qualname),
-            ("scopeid", &scope)
-        ]);
-
-        self.record("mod_ref", data.span, values);
-    }
-
-    fn struct_data(&mut self, data: StructData) {
-        let id = data.id.index.as_u32().to_string();
-        let ctor_id = data.ctor_id.index.as_u32().to_string();
-        let scope = data.scope.index.as_u32().to_string();
-        let values = make_values_str(&[
-            ("id", &id),
-            ("ctor_id", &ctor_id),
-            ("qualname", &data.qualname),
-            ("scopeid", &scope),
-            ("value", &data.value)
-        ]);
-
-        self.record("struct", data.span, values);
-    }
-
-    fn struct_variant(&mut self, data: StructVariantData) {
-        let id = data.id.index.as_u32().to_string();
-        let scope = data.scope.index.as_u32().to_string();
-        let values = make_values_str(&[
-            ("id", &id),
-            ("ctor_id", &id),
-            ("qualname", &data.qualname),
-            ("type", &data.type_value),
-            ("value", &data.value),
-            ("scopeid", &scope)
-        ]);
-
-        self.record("variant_struct", data.span, values);
-    }
-
-    fn trait_data(&mut self, data: TraitData) {
-        let id = data.id.index.as_u32().to_string();
-        let scope = data.scope.index.as_u32().to_string();
-        let values = make_values_str(&[
-            ("id", &id),
-            ("qualname", &data.qualname),
-            ("scopeid", &scope),
-            ("value", &data.value)
-        ]);
-
-        self.record("trait", data.span, values);
-    }
-
-    fn tuple_variant(&mut self, data: TupleVariantData) {
-        let id = data.id.index.as_u32().to_string();
-        let scope = data.scope.index.as_u32().to_string();
-        let values = make_values_str(&[
-            ("id", &id),
-            ("name", &data.name),
-            ("qualname", &data.qualname),
-            ("type", &data.type_value),
-            ("value", &data.value),
-            ("scopeid", &scope)
-        ]);
-
-        self.record("variant", data.span, values);
-    }
-
-    fn type_ref(&mut self, data: TypeRefData) {
-        let (ref_id, ref_crate) = match data.ref_id {
-            Some(id) => (id.index.as_usize().to_string(), id.krate.to_string()),
-            None => (0.to_string(), 0.to_string())
-        };
-
-        let scope = data.scope.index.as_u32().to_string();
-        let values = make_values_str(&[
-            ("refid", &ref_id),
-            ("refidcrate", &ref_crate),
-            ("qualname", &data.qualname),
-            ("scopeid", &scope)
-        ]);
-
-        self.record("type_ref", data.span, values);
-    }
-
-    fn typedef(&mut self, data: TypeDefData) {
-        let id = data.id.index.as_u32().to_string();
-        let values = make_values_str(&[
-            ("id", &id),
-            ("qualname", &data.qualname),
-            ("value", &data.value)
-        ]);
-
-        self.record("typedef", data.span, values);
-    }
-
-    fn use_data(&mut self, data: UseData) {
-        let mod_id = data.mod_id.unwrap_or(null_def_id());
-
-        let id = data.id.index.as_u32().to_string();
-        let ref_id = mod_id.index.as_usize().to_string();
-        let ref_crate = mod_id.krate.to_string();
-        let scope = data.scope.index.as_u32().to_string();
-        let values = make_values_str(&[
-            ("id", &id),
-            ("refid", &ref_id),
-            ("refidcrate", &ref_crate),
-            ("name", &data.name),
-            ("scopeid", &scope)
-        ]);
-
-        self.record("use_alias", data.span, values);
-    }
-
-    fn use_glob(&mut self, data: UseGlobData) {
-        let names = data.names.join(", ");
-
-        let id = data.id.index.as_u32().to_string();
-        let scope = data.scope.index.as_u32().to_string();
-        let values = make_values_str(&[
-            ("id", &id),
-            ("value", &names),
-            ("scopeid", &scope)
-        ]);
-
-        self.record("use_glob", data.span, values);
-    }
-
-    fn variable(&mut self, data: VariableData) {
-        let id = data.id.index.as_u32().to_string();
-        let scope = data.scope.index.as_u32().to_string();
-        let values = make_values_str(&[
-            ("id", &id),
-            ("name", &data.name),
-            ("qualname", &data.qualname),
-            ("value", &data.value),
-            ("type", &data.type_value),
-            ("scopeid", &scope)
-        ]);
-
-        self.record("variable", data.span, values);
-    }
-
-    fn variable_ref(&mut self, data: VariableRefData) {
-        let ref_id = data.ref_id.index.as_usize().to_string();
-        let ref_crate = data.ref_id.krate.to_string();
-        let scope = data.scope.index.as_u32().to_string();
-        let values = make_values_str(&[
-            ("refid", &ref_id),
-            ("refidcrate", &ref_crate),
-            ("qualname", ""),
-            ("scopeid", &scope)
-        ]);
-
-        self.record("var_ref", data.span, values)
-    }
-}
-
-// Helper function to escape quotes in a string
-fn escape(s: String) -> String {
-    s.replace("\"", "\"\"")
-}
-
-fn make_values_str(pairs: &[(&'static str, &str)]) -> String {
-    let pairs = pairs.into_iter().map(|&(f, v)| {
-        // Never take more than 1020 chars
-        if v.len() > 1020 {
-            (f, &v[..1020])
-        } else {
-            (f, v)
-        }
-    });
-
-    let strs = pairs.map(|(f, v)| format!(",{},\"{}\"", f, escape(String::from(v))));
-    strs.fold(String::new(), |mut s, ss| {
-        s.push_str(&ss);
-        s
-    })
-}
-
-fn span_extent_str(span: SpanData) -> String {
-    format!("file_name,\"{}\",file_line,{},file_col,{},byte_start,{},\
-             file_line_end,{},file_col_end,{},byte_end,{}",
-             span.file_name.to_str().unwrap(), span.line_start.0, span.column_start.0,
-             span.byte_start, span.line_end.0, span.column_end.0, span.byte_end)
-}
diff --git a/src/librustc_save_analysis/data.rs b/src/librustc_save_analysis/data.rs
deleted file mode 100644
index e15e3f6e79e..00000000000
--- a/src/librustc_save_analysis/data.rs
+++ /dev/null
@@ -1,421 +0,0 @@
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Structs representing the analysis data from a crate.
-//!
-//! The `Dump` trait can be used together with `DumpVisitor` in order to
-//! retrieve the data from a crate.
-
-use rustc::hir;
-use rustc::hir::def_id::{CrateNum, DefId};
-use syntax::ast::{self, Attribute, NodeId};
-use syntax_pos::Span;
-
-use rls_data::{ExternalCrateData, Signature};
-
-pub struct CrateData {
-    pub name: String,
-    pub number: u32,
-    pub span: Span,
-}
-
-/// Data for any entity in the Rust language. The actual data contained varies
-/// with the kind of entity being queried. See the nested structs for details.
-#[derive(Debug)]
-pub enum Data {
-    /// Data for Enums.
-    EnumData(EnumData),
-    /// Data for extern crates.
-    ExternCrateData(ExternCrateData),
-    /// Data about a function call.
-    FunctionCallData(FunctionCallData),
-    /// Data for all kinds of functions and methods.
-    FunctionData(FunctionData),
-    /// Data about a function ref.
-    FunctionRefData(FunctionRefData),
-    /// Data for impls.
-    ImplData(ImplData2),
-    /// Data for trait inheritance.
-    InheritanceData(InheritanceData),
-    /// Data about a macro declaration.
-    MacroData(MacroData),
-    /// Data about a macro use.
-    MacroUseData(MacroUseData),
-    /// Data about a method call.
-    MethodCallData(MethodCallData),
-    /// Data for method declarations (methods with a body are treated as functions).
-    MethodData(MethodData),
-    /// Data for modules.
-    ModData(ModData),
-    /// Data for a reference to a module.
-    ModRefData(ModRefData),
-    /// Data for a struct declaration.
-    StructData(StructData),
-    /// Data for a struct variant.
-    StructVariantDat(StructVariantData),
-    /// Data for a trait declaration.
-    TraitData(TraitData),
-    /// Data for a tuple variant.
-    TupleVariantData(TupleVariantData),
-    /// Data for a typedef.
-    TypeDefData(TypeDefData),
-    /// Data for a reference to a type or trait.
-    TypeRefData(TypeRefData),
-    /// Data for a use statement.
-    UseData(UseData),
-    /// Data for a global use statement.
-    UseGlobData(UseGlobData),
-    /// Data for local and global variables (consts and statics), and fields.
-    VariableData(VariableData),
-    /// Data for the use of some variable (e.g., the use of a local variable, which
-    /// will refere to that variables declaration).
-    VariableRefData(VariableRefData),
-}
-
-#[derive(Eq, PartialEq, Clone, Copy, Debug)]
-pub enum Visibility {
-    Public,
-    Restricted,
-    Inherited,
-}
-
-impl<'a> From<&'a ast::Visibility> for Visibility {
-    fn from(v: &'a ast::Visibility) -> Visibility {
-        match *v {
-            ast::Visibility::Public => Visibility::Public,
-            ast::Visibility::Crate(_) => Visibility::Restricted,
-            ast::Visibility::Restricted { .. } => Visibility::Restricted,
-            ast::Visibility::Inherited => Visibility::Inherited,
-        }
-    }
-}
-
-impl<'a> From<&'a hir::Visibility> for Visibility {
-    fn from(v: &'a hir::Visibility) -> Visibility {
-        match *v {
-            hir::Visibility::Public => Visibility::Public,
-            hir::Visibility::Crate => Visibility::Restricted,
-            hir::Visibility::Restricted { .. } => Visibility::Restricted,
-            hir::Visibility::Inherited => Visibility::Inherited,
-        }
-    }
-}
-
-/// Data for the prelude of a crate.
-#[derive(Debug)]
-pub struct CratePreludeData {
-    pub crate_name: String,
-    pub crate_root: String,
-    pub external_crates: Vec<ExternalCrateData>,
-    pub span: Span,
-}
-
-/// Data for enum declarations.
-#[derive(Clone, Debug)]
-pub struct EnumData {
-    pub id: NodeId,
-    pub name: String,
-    pub value: String,
-    pub qualname: String,
-    pub span: Span,
-    pub scope: NodeId,
-    pub variants: Vec<NodeId>,
-    pub visibility: Visibility,
-    pub docs: String,
-    pub sig: Option<Signature>,
-    pub attributes: Vec<Attribute>,
-}
-
-/// Data for extern crates.
-#[derive(Debug)]
-pub struct ExternCrateData {
-    pub id: NodeId,
-    pub name: String,
-    pub crate_num: CrateNum,
-    pub location: String,
-    pub span: Span,
-    pub scope: NodeId,
-}
-
-/// Data about a function call.
-#[derive(Debug)]
-pub struct FunctionCallData {
-    pub span: Span,
-    pub scope: NodeId,
-    pub ref_id: DefId,
-}
-
-/// Data for all kinds of functions and methods.
-#[derive(Clone, Debug)]
-pub struct FunctionData {
-    pub id: NodeId,
-    pub name: String,
-    pub qualname: String,
-    pub declaration: Option<DefId>,
-    pub span: Span,
-    pub scope: NodeId,
-    pub value: String,
-    pub visibility: Visibility,
-    pub parent: Option<DefId>,
-    pub docs: String,
-    pub sig: Option<Signature>,
-    pub attributes: Vec<Attribute>,
-}
-
-/// Data about a function call.
-#[derive(Debug)]
-pub struct FunctionRefData {
-    pub span: Span,
-    pub scope: NodeId,
-    pub ref_id: DefId,
-}
-
-#[derive(Debug)]
-pub struct ImplData {
-    pub id: NodeId,
-    pub span: Span,
-    pub scope: NodeId,
-    pub trait_ref: Option<DefId>,
-    pub self_ref: Option<DefId>,
-}
-
-#[derive(Debug)]
-// FIXME: this struct should not exist. However, removing it requires heavy
-// refactoring of dump_visitor.rs. See PR 31838 for more info.
-pub struct ImplData2 {
-    pub id: NodeId,
-    pub span: Span,
-    pub scope: NodeId,
-    // FIXME: I'm not really sure inline data is the best way to do this. Seems
-    // OK in this case, but generalising leads to returning chunks of AST, which
-    // feels wrong.
-    pub trait_ref: Option<TypeRefData>,
-    pub self_ref: Option<TypeRefData>,
-}
-
-#[derive(Debug)]
-pub struct InheritanceData {
-    pub span: Span,
-    pub base_id: DefId,
-    pub deriv_id: NodeId
-}
-
-/// Data about a macro declaration.
-#[derive(Debug)]
-pub struct MacroData {
-    pub span: Span,
-    pub name: String,
-    pub qualname: String,
-    pub docs: String,
-}
-
-/// Data about a macro use.
-#[derive(Debug)]
-pub struct MacroUseData {
-    pub span: Span,
-    pub name: String,
-    pub qualname: String,
-    // Because macro expansion happens before ref-ids are determined,
-    // we use the callee span to reference the associated macro definition.
-    pub callee_span: Span,
-    pub scope: NodeId,
-    pub imported: bool,
-}
-
-/// Data about a method call.
-#[derive(Debug)]
-pub struct MethodCallData {
-    pub span: Span,
-    pub scope: NodeId,
-    pub ref_id: Option<DefId>,
-    pub decl_id: Option<DefId>,
-}
-
-/// Data for method declarations (methods with a body are treated as functions).
-#[derive(Clone, Debug)]
-pub struct MethodData {
-    pub id: NodeId,
-    pub name: String,
-    pub qualname: String,
-    pub span: Span,
-    pub scope: NodeId,
-    pub value: String,
-    pub decl_id: Option<DefId>,
-    pub parent: Option<DefId>,
-    pub visibility: Visibility,
-    pub docs: String,
-    pub sig: Option<Signature>,
-    pub attributes: Vec<Attribute>,
-}
-
-/// Data for modules.
-#[derive(Debug)]
-pub struct ModData {
-    pub id: NodeId,
-    pub name: String,
-    pub qualname: String,
-    pub span: Span,
-    pub scope: NodeId,
-    pub filename: String,
-    pub items: Vec<NodeId>,
-    pub visibility: Visibility,
-    pub docs: String,
-    pub sig: Option<Signature>,
-    pub attributes: Vec<Attribute>,
-}
-
-/// Data for a reference to a module.
-#[derive(Debug)]
-pub struct ModRefData {
-    pub span: Span,
-    pub scope: NodeId,
-    pub ref_id: Option<DefId>,
-    pub qualname: String
-}
-
-#[derive(Debug)]
-pub struct StructData {
-    pub span: Span,
-    pub name: String,
-    pub id: NodeId,
-    pub ctor_id: NodeId,
-    pub qualname: String,
-    pub scope: NodeId,
-    pub value: String,
-    pub fields: Vec<NodeId>,
-    pub visibility: Visibility,
-    pub docs: String,
-    pub sig: Option<Signature>,
-    pub attributes: Vec<Attribute>,
-}
-
-#[derive(Debug)]
-pub struct StructVariantData {
-    pub span: Span,
-    pub name: String,
-    pub id: NodeId,
-    pub qualname: String,
-    pub type_value: String,
-    pub value: String,
-    pub scope: NodeId,
-    pub parent: Option<DefId>,
-    pub docs: String,
-    pub sig: Option<Signature>,
-    pub attributes: Vec<Attribute>,
-}
-
-#[derive(Debug)]
-pub struct TraitData {
-    pub span: Span,
-    pub id: NodeId,
-    pub name: String,
-    pub qualname: String,
-    pub scope: NodeId,
-    pub value: String,
-    pub items: Vec<NodeId>,
-    pub visibility: Visibility,
-    pub docs: String,
-    pub sig: Option<Signature>,
-    pub attributes: Vec<Attribute>,
-}
-
-#[derive(Debug)]
-pub struct TupleVariantData {
-    pub span: Span,
-    pub id: NodeId,
-    pub name: String,
-    pub qualname: String,
-    pub type_value: String,
-    pub value: String,
-    pub scope: NodeId,
-    pub parent: Option<DefId>,
-    pub docs: String,
-    pub sig: Option<Signature>,
-    pub attributes: Vec<Attribute>,
-}
-
-/// Data for a typedef.
-#[derive(Debug)]
-pub struct TypeDefData {
-    pub id: NodeId,
-    pub name: String,
-    pub span: Span,
-    pub qualname: String,
-    pub value: String,
-    pub visibility: Visibility,
-    pub parent: Option<DefId>,
-    pub docs: String,
-    pub sig: Option<Signature>,
-    pub attributes: Vec<Attribute>,
-}
-
-/// Data for a reference to a type or trait.
-#[derive(Clone, Debug)]
-pub struct TypeRefData {
-    pub span: Span,
-    pub scope: NodeId,
-    pub ref_id: Option<DefId>,
-    pub qualname: String,
-}
-
-#[derive(Debug)]
-pub struct UseData {
-    pub id: NodeId,
-    pub span: Span,
-    pub name: String,
-    pub mod_id: Option<DefId>,
-    pub scope: NodeId,
-    pub visibility: Visibility,
-}
-
-#[derive(Debug)]
-pub struct UseGlobData {
-    pub id: NodeId,
-    pub span: Span,
-    pub names: Vec<String>,
-    pub scope: NodeId,
-    pub visibility: Visibility,
-}
-
-/// Data for local and global variables (consts and statics).
-#[derive(Debug)]
-pub struct VariableData {
-    pub id: NodeId,
-    pub kind: VariableKind,
-    pub name: String,
-    pub qualname: String,
-    pub span: Span,
-    pub scope: NodeId,
-    pub parent: Option<DefId>,
-    pub value: String,
-    pub type_value: String,
-    pub visibility: Visibility,
-    pub docs: String,
-    pub sig: Option<Signature>,
-    pub attributes: Vec<Attribute>,
-}
-
-#[derive(Debug)]
-pub enum VariableKind {
-    Static,
-    Const,
-    Local,
-    Field,
-}
-
-/// Data for the use of some item (e.g., the use of a local variable, which
-/// will refer to that variables declaration (by ref_id)).
-#[derive(Debug)]
-pub struct VariableRefData {
-    pub name: String,
-    pub span: Span,
-    pub scope: NodeId,
-    pub ref_id: DefId,
-}
diff --git a/src/librustc_save_analysis/dump.rs b/src/librustc_save_analysis/dump.rs
deleted file mode 100644
index 795ff58e206..00000000000
--- a/src/librustc_save_analysis/dump.rs
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use super::external_data::*;
-
-use rls_data::CratePreludeData;
-
-pub trait Dump {
-    fn crate_prelude(&mut self, _: CratePreludeData) {}
-    fn enum_data(&mut self, _: EnumData) {}
-    fn extern_crate(&mut self, _: ExternCrateData) {}
-    fn impl_data(&mut self, _: ImplData) {}
-    fn inheritance(&mut self, _: InheritanceData) {}
-    fn function(&mut self, _: FunctionData) {}
-    fn function_ref(&mut self, _: FunctionRefData) {}
-    fn function_call(&mut self, _: FunctionCallData) {}
-    fn method(&mut self, _: MethodData) {}
-    fn method_call(&mut self, _: MethodCallData) {}
-    fn macro_data(&mut self, _: MacroData) {}
-    fn macro_use(&mut self, _: MacroUseData) {}
-    fn mod_data(&mut self, _: ModData) {}
-    fn mod_ref(&mut self, _: ModRefData) {}
-    fn struct_data(&mut self, _: StructData) {}
-    fn struct_variant(&mut self, _: StructVariantData) {}
-    fn trait_data(&mut self, _: TraitData) {}
-    fn tuple_variant(&mut self, _: TupleVariantData) {}
-    fn type_ref(&mut self, _: TypeRefData) {}
-    fn typedef(&mut self, _: TypeDefData) {}
-    fn use_data(&mut self, _: UseData) {}
-    fn use_glob(&mut self, _: UseGlobData) {}
-    fn variable(&mut self, _: VariableData) {}
-    fn variable_ref(&mut self, _: VariableRefData) {}
-}
diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs
index ea346d99e31..cc33d3db8eb 100644
--- a/src/librustc_save_analysis/dump_visitor.rs
+++ b/src/librustc_save_analysis/dump_visitor.rs
@@ -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
@@ -27,16 +24,12 @@
 //! 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 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};
@@ -48,15 +41,12 @@ use syntax::ptr::P;
 use syntax::codemap::Spanned;
 use syntax_pos::*;
 
-use {escape, generated_code, SaveContext, PathCollector, docs_for_attrs};
-use data::*;
-use dump::Dump;
-use external_data::{Lower, make_def_id};
-use recorder;
+use {escape, generated_code, SaveContext, PathCollector, docs_for_attrs, lower_attributes, Dump};
 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) => {
@@ -82,8 +72,7 @@ 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>,
 }
 
 impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
@@ -98,8 +87,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
             dumper: dumper,
             span: span_utils.clone(),
             cur_scope: CRATE_NODE_ID,
-            mac_defs: HashSet::new(),
-            mac_uses: HashSet::new(),
+            // mac_defs: HashSet::new(),
         }
     }
 
@@ -127,6 +115,10 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
         }
     }
 
+    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| {
@@ -137,25 +129,14 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
             }
         });
 
-        // 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.
@@ -211,13 +192,13 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
 
     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(),
+            });
         }
     }
 
@@ -230,13 +211,13 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
             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(),
+            });
         }
     }
 
@@ -251,32 +232,32 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
         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()),
         }
     }
@@ -285,67 +266,67 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                         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);
@@ -368,21 +349,23 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                 // 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![],
+                    });
                 }
             }
         }
@@ -393,12 +376,11 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                       body: Option<&'l ast::Block>,
                       id: ast::NodeId,
                       name: ast::Ident,
-                      vis: Visibility,
-                      attrs: &'l [Attribute],
+                      vis: ast::Visibility,
                       span: Span) {
         debug!("process_method: {}:{}", id, name);
 
-        if let Some(method_data) = self.save_ctxt.get_method_data(id, name.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() {
@@ -407,61 +389,11 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                 });
             }
 
-            // 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.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: sig::method_signature(id, name, sig, &self.save_ctxt),
-                    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
@@ -480,22 +412,17 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
     }
 
     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);
         }
     }
 
@@ -519,18 +446,23 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                                    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);
@@ -542,13 +474,10 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                   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 {
@@ -567,10 +496,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                                     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);
@@ -583,29 +510,31 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                            typ: &'l ast::Ty,
                            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);
-        let value = expr.map(|e| self.span.snippet(e.span)).unwrap_or(String::new());
 
         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: value,
-                type_value: ty_to_string(&typ),
-                scope: self.cur_scope,
-                parent: Some(parent_id),
-                visibility: vis,
+                qualname,
+                value: ty_to_string(&typ),
+                parent: Some(::id_from_def_id(parent_id)),
+                children: vec![],
+                decl_id: None,
                 docs: docs_for_attrs(attrs),
-                sig: sig::assoc_const_signature(id, name, typ, expr, &self.save_ctxt),
-                attributes: attrs.to_vec(),
-            }.lower(self.tcx));
+                sig,
+                attributes: lower_attributes(attrs.to_owned(), &self.save_ctxt),
+            });
         }
 
         // walk type and init value
@@ -624,7 +553,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
         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()
@@ -633,26 +562,28 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                                                   .unwrap_or(i.to_string()))
                                    .collect::<Vec<_>>()
                                    .join(", ");
-            (format!("{} {{ {} }}", name, fields_str), fields.iter().map(|f| f.id).collect())
+            (format!("{} {{ {} }}", name, fields_str),
+             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),
+                value,
+                parent: None,
+                children: fields,
+                decl_id: None,
                 docs: docs_for_attrs(&item.attrs),
                 sig: sig::item_signature(item, &self.save_ctxt),
-                attributes: item.attrs.clone(),
-            }.lower(self.tcx));
+                attributes: lower_attributes(item.attrs.clone(), &self.save_ctxt),
+            });
         }
 
         for field in def.fields() {
@@ -672,10 +603,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
             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();
@@ -692,48 +620,62 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                                                           .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)),
+                        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: docs_for_attrs(&variant.node.attrs),
                             sig: sig::variant_signature(variant, &self.save_ctxt),
-                            attributes: variant.node.attrs.clone(),
-                        }.lower(self.tcx));
+                            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)),
+                        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: docs_for_attrs(&variant.node.attrs),
                             sig: sig::variant_signature(variant, &self.save_ctxt),
-                            attributes: variant.node.attrs.clone(),
-                        }.lower(self.tcx));
+                            attributes: lower_attributes(variant.node.attrs.clone(),
+                                                         &self.save_ctxt),
+                        });
                     }
                 }
             }
@@ -744,7 +686,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                 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,
@@ -754,25 +697,17 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                     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));
         }
     }
 
@@ -793,19 +728,24 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
         }
         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),
+                parent: None,
+                children,
+                decl_id: None,
                 docs: docs_for_attrs(&item.attrs),
                 sig: sig::item_signature(item, &self.save_ctxt),
-                attributes: item.attrs.clone(),
-            }.lower(self.tcx));
+                attributes: lower_attributes(item.attrs.clone(), &self.save_ctxt),
+            });
         }
 
         // super-traits
@@ -823,21 +763,22 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
             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),
+                    });
                 }
             }
         }
@@ -846,21 +787,19 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
         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;
@@ -873,81 +812,29 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
             }
         };
 
-        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),
             _ => {}
         }
     }
@@ -961,20 +848,15 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
         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)
@@ -986,9 +868,9 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
 
     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);
             }
         }
 
@@ -1013,12 +895,13 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                     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);
@@ -1036,7 +919,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
         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(),
@@ -1058,21 +941,24 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
             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![],
+                });
             }
         }
     }
@@ -1084,46 +970,36 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
     /// 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 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);
+
+        // 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));
+        //     }
+        // }
+        self.dumper.macro_use(data);
     }
 
     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, ref expr) => {
                 self.process_assoc_const(trait_item.id,
@@ -1132,7 +1008,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                                          &ty,
                                          expr.as_ref().map(|e| &**e),
                                          trait_id,
-                                         Visibility::Public,
+                                         ast::Visibility::Public,
                                          &trait_item.attrs);
             }
             ast::TraitItemKind::Method(ref sig, ref body) => {
@@ -1140,8 +1016,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                                     body.as_ref().map(|x| &**x),
                                     trait_item.id,
                                     trait_item.ident,
-                                    Visibility::Public,
-                                    &trait_item.attrs,
+                                    ast::Visibility::Public,
                                     trait_item.span);
             }
             ast::TraitItemKind::Type(ref bounds, ref default_ty) => {
@@ -1151,22 +1026,27 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                 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),
+                        parent: Some(::id_from_def_id(trait_id)),
+                        children: vec![],
+                        decl_id: None,
                         docs: 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: trait_item.attrs.clone(),
-                    }.lower(self.tcx));
+                        attributes: lower_attributes(trait_item.attrs.clone(), &self.save_ctxt),
+                    });
                 }
 
                 if let &Some(ref default_ty) = default_ty {
@@ -1178,7 +1058,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
     }
 
     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,
@@ -1187,7 +1067,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                                          &ty,
                                          Some(expr),
                                          impl_id,
-                                         From::from(&impl_item.vis),
+                                         impl_item.vis.clone(),
                                          &impl_item.attrs);
             }
             ast::ImplItemKind::Method(ref sig, ref body) => {
@@ -1195,8 +1075,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                                     Some(body),
                                     impl_item.id,
                                     impl_item.ident,
-                                    From::from(&impl_item.vis),
-                                    &impl_item.attrs,
+                                    impl_item.vis.clone(),
                                     impl_item.span);
             }
             ast::ImplItemKind::Type(ref ty) => {
@@ -1220,25 +1099,30 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll,
 
         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,
+            qualname,
+            span,
+            value: filename,
+            children,
+            parent: None,
+            decl_id: None,
             docs: 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 +1130,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll,
                         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 +1145,15 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll,
                         };
 
                         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 +1171,24 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll,
                         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 +1196,19 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll,
                     }
                 }
             }
-            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 +1237,23 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll,
                 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,
+                        children: vec![],
+                        decl_id: None,
                         docs: docs_for_attrs(&item.attrs),
                         sig: sig::item_signature(item, &self.save_ctxt),
-                        attributes: item.attrs.clone(),
-                    }.lower(self.tcx));
+                        attributes: lower_attributes(item.attrs.clone(), &self.save_ctxt),
+                    });
                 }
 
                 self.visit_ty(&ty);
@@ -1396,7 +1278,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll,
     }
 
     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 +1287,12 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll,
 
                 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,7 +1309,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll,
 
     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);
@@ -1446,9 +1328,9 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll,
                 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 +1356,13 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll,
                     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 +1423,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll,
     }
 
     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 +1439,9 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll,
         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 +1456,56 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll,
                     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 +1518,12 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll,
         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 +1536,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll,
             }
             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);
diff --git a/src/librustc_save_analysis/external_data.rs b/src/librustc_save_analysis/external_data.rs
deleted file mode 100644
index 245a3bcc617..00000000000
--- a/src/librustc_save_analysis/external_data.rs
+++ /dev/null
@@ -1,748 +0,0 @@
-// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use rustc::hir::def_id::{CrateNum, DefId, DefIndex};
-use rustc::hir::map::Map;
-use rustc::ty::TyCtxt;
-use syntax::ast::{self, NodeId};
-use syntax::codemap::CodeMap;
-use syntax::print::pprust;
-use syntax_pos::Span;
-
-use data::{self, Visibility};
-
-use rls_data::{SpanData, CratePreludeData, Attribute, Signature};
-use rls_span::{Column, Row};
-
-// FIXME: this should be pub(crate), but the current snapshot doesn't allow it yet
-pub trait Lower {
-    type Target;
-    fn lower(self, tcx: TyCtxt) -> Self::Target;
-}
-
-pub fn make_def_id(id: NodeId, map: &Map) -> DefId {
-    map.opt_local_def_id(id).unwrap_or(null_def_id())
-}
-
-pub fn null_def_id() -> DefId {
-    DefId {
-        krate: CrateNum::from_u32(u32::max_value()),
-        index: DefIndex::from_u32(u32::max_value())
-    }
-}
-
-pub fn span_from_span(span: Span, cm: &CodeMap) -> SpanData {
-    let start = cm.lookup_char_pos(span.lo);
-    let end = cm.lookup_char_pos(span.hi);
-
-    SpanData {
-        file_name: start.file.name.clone().into(),
-        byte_start: span.lo.0,
-        byte_end: span.hi.0,
-        line_start: Row::new_one_indexed(start.line as u32),
-        line_end: Row::new_one_indexed(end.line as u32),
-        column_start: Column::new_one_indexed(start.col.0 as u32 + 1),
-        column_end: Column::new_one_indexed(end.col.0 as u32 + 1),
-    }
-}
-
-impl Lower for Vec<ast::Attribute> {
-    type Target = Vec<Attribute>;
-
-    fn lower(self, tcx: TyCtxt) -> Vec<Attribute> {
-        self.into_iter()
-        // Only retain real attributes. Doc comments are lowered separately.
-        .filter(|attr| attr.path != "doc")
-        .map(|mut attr| {
-            // Remove the surrounding '#[..]' or '#![..]' of the pretty printed
-            // attribute. First normalize all inner attribute (#![..]) to outer
-            // ones (#[..]), then remove the two leading and the one trailing character.
-            attr.style = ast::AttrStyle::Outer;
-            let value = pprust::attribute_to_string(&attr);
-            // This str slicing works correctly, because the leading and trailing characters
-            // are in the ASCII range and thus exactly one byte each.
-            let value = value[2..value.len()-1].to_string();
-
-            Attribute {
-                value: value,
-                span: span_from_span(attr.span, tcx.sess.codemap()),
-            }
-        }).collect()
-    }
-}
-
-impl Lower for data::CratePreludeData {
-    type Target = CratePreludeData;
-
-    fn lower(self, tcx: TyCtxt) -> CratePreludeData {
-        CratePreludeData {
-            crate_name: self.crate_name,
-            crate_root: self.crate_root,
-            external_crates: self.external_crates,
-            span: span_from_span(self.span, tcx.sess.codemap()),
-        }
-    }
-}
-
-/// Data for enum declarations.
-#[derive(Clone, Debug)]
-pub struct EnumData {
-    pub id: DefId,
-    pub value: String,
-    pub name: String,
-    pub qualname: String,
-    pub span: SpanData,
-    pub scope: DefId,
-    pub variants: Vec<DefId>,
-    pub visibility: Visibility,
-    pub docs: String,
-    pub sig: Option<Signature>,
-    pub attributes: Vec<Attribute>,
-}
-
-impl Lower for data::EnumData {
-    type Target = EnumData;
-
-    fn lower(self, tcx: TyCtxt) -> EnumData {
-        EnumData {
-            id: make_def_id(self.id, &tcx.hir),
-            name: self.name,
-            value: self.value,
-            qualname: self.qualname,
-            span: span_from_span(self.span, tcx.sess.codemap()),
-            scope: make_def_id(self.scope, &tcx.hir),
-            variants: self.variants.into_iter().map(|id| make_def_id(id, &tcx.hir)).collect(),
-            visibility: self.visibility,
-            docs: self.docs,
-            sig: self.sig,
-            attributes: self.attributes.lower(tcx),
-        }
-    }
-}
-
-/// Data for extern crates.
-#[derive(Debug)]
-pub struct ExternCrateData {
-    pub id: DefId,
-    pub name: String,
-    pub crate_num: CrateNum,
-    pub location: String,
-    pub span: SpanData,
-    pub scope: DefId,
-}
-
-impl Lower for data::ExternCrateData {
-    type Target = ExternCrateData;
-
-    fn lower(self, tcx: TyCtxt) -> ExternCrateData {
-        ExternCrateData {
-            id: make_def_id(self.id, &tcx.hir),
-            name: self.name,
-            crate_num: self.crate_num,
-            location: self.location,
-            span: span_from_span(self.span, tcx.sess.codemap()),
-            scope: make_def_id(self.scope, &tcx.hir),
-        }
-    }
-}
-
-/// Data about a function call.
-#[derive(Debug)]
-pub struct FunctionCallData {
-    pub span: SpanData,
-    pub scope: DefId,
-    pub ref_id: DefId,
-}
-
-impl Lower for data::FunctionCallData {
-    type Target = FunctionCallData;
-
-    fn lower(self, tcx: TyCtxt) -> FunctionCallData {
-        FunctionCallData {
-            span: span_from_span(self.span, tcx.sess.codemap()),
-            scope: make_def_id(self.scope, &tcx.hir),
-            ref_id: self.ref_id,
-        }
-    }
-}
-
-/// Data for all kinds of functions and methods.
-#[derive(Clone, Debug)]
-pub struct FunctionData {
-    pub id: DefId,
-    pub name: String,
-    pub qualname: String,
-    pub declaration: Option<DefId>,
-    pub span: SpanData,
-    pub scope: DefId,
-    pub value: String,
-    pub visibility: Visibility,
-    pub parent: Option<DefId>,
-    pub docs: String,
-    pub sig: Option<Signature>,
-    pub attributes: Vec<Attribute>,
-}
-
-impl Lower for data::FunctionData {
-    type Target = FunctionData;
-
-    fn lower(self, tcx: TyCtxt) -> FunctionData {
-        FunctionData {
-            id: make_def_id(self.id, &tcx.hir),
-            name: self.name,
-            qualname: self.qualname,
-            declaration: self.declaration,
-            span: span_from_span(self.span, tcx.sess.codemap()),
-            scope: make_def_id(self.scope, &tcx.hir),
-            value: self.value,
-            visibility: self.visibility,
-            parent: self.parent,
-            docs: self.docs,
-            sig: self.sig,
-            attributes: self.attributes.lower(tcx),
-        }
-    }
-}
-
-/// Data about a function call.
-#[derive(Debug)]
-pub struct FunctionRefData {
-    pub span: SpanData,
-    pub scope: DefId,
-    pub ref_id: DefId,
-}
-
-impl Lower for data::FunctionRefData {
-    type Target = FunctionRefData;
-
-    fn lower(self, tcx: TyCtxt) -> FunctionRefData {
-        FunctionRefData {
-            span: span_from_span(self.span, tcx.sess.codemap()),
-            scope: make_def_id(self.scope, &tcx.hir),
-            ref_id: self.ref_id,
-        }
-    }
-}
-#[derive(Debug)]
-pub struct ImplData {
-    pub id: DefId,
-    pub span: SpanData,
-    pub scope: DefId,
-    pub trait_ref: Option<DefId>,
-    pub self_ref: Option<DefId>,
-}
-
-impl Lower for data::ImplData {
-    type Target = ImplData;
-
-    fn lower(self, tcx: TyCtxt) -> ImplData {
-        ImplData {
-            id: make_def_id(self.id, &tcx.hir),
-            span: span_from_span(self.span, tcx.sess.codemap()),
-            scope: make_def_id(self.scope, &tcx.hir),
-            trait_ref: self.trait_ref,
-            self_ref: self.self_ref,
-        }
-    }
-}
-
-#[derive(Debug)]
-pub struct InheritanceData {
-    pub span: SpanData,
-    pub base_id: DefId,
-    pub deriv_id: DefId
-}
-
-impl Lower for data::InheritanceData {
-    type Target = InheritanceData;
-
-    fn lower(self, tcx: TyCtxt) -> InheritanceData {
-        InheritanceData {
-            span: span_from_span(self.span, tcx.sess.codemap()),
-            base_id: self.base_id,
-            deriv_id: make_def_id(self.deriv_id, &tcx.hir)
-        }
-    }
-}
-
-/// Data about a macro declaration.
-#[derive(Debug)]
-pub struct MacroData {
-    pub span: SpanData,
-    pub name: String,
-    pub qualname: String,
-    pub docs: String,
-}
-
-impl Lower for data::MacroData {
-    type Target = MacroData;
-
-    fn lower(self, tcx: TyCtxt) -> MacroData {
-        MacroData {
-            span: span_from_span(self.span, tcx.sess.codemap()),
-            name: self.name,
-            qualname: self.qualname,
-            docs: self.docs,
-        }
-    }
-}
-
-/// Data about a macro use.
-#[derive(Debug)]
-pub struct MacroUseData {
-    pub span: SpanData,
-    pub name: String,
-    pub qualname: String,
-    // Because macro expansion happens before ref-ids are determined,
-    // we use the callee span to reference the associated macro definition.
-    pub callee_span: SpanData,
-    pub scope: DefId,
-}
-
-impl Lower for data::MacroUseData {
-    type Target = MacroUseData;
-
-    fn lower(self, tcx: TyCtxt) -> MacroUseData {
-        MacroUseData {
-            span: span_from_span(self.span, tcx.sess.codemap()),
-            name: self.name,
-            qualname: self.qualname,
-            callee_span: span_from_span(self.callee_span, tcx.sess.codemap()),
-            scope: make_def_id(self.scope, &tcx.hir),
-        }
-    }
-}
-
-/// Data about a method call.
-#[derive(Debug)]
-pub struct MethodCallData {
-    pub span: SpanData,
-    pub scope: DefId,
-    pub ref_id: Option<DefId>,
-    pub decl_id: Option<DefId>,
-}
-
-impl Lower for data::MethodCallData {
-    type Target = MethodCallData;
-
-    fn lower(self, tcx: TyCtxt) -> MethodCallData {
-        MethodCallData {
-            span: span_from_span(self.span, tcx.sess.codemap()),
-            scope: make_def_id(self.scope, &tcx.hir),
-            ref_id: self.ref_id,
-            decl_id: self.decl_id,
-        }
-    }
-}
-
-/// Data for method declarations (methods with a body are treated as functions).
-#[derive(Clone, Debug)]
-pub struct MethodData {
-    pub id: DefId,
-    pub name: String,
-    pub qualname: String,
-    pub span: SpanData,
-    pub scope: DefId,
-    pub value: String,
-    pub decl_id: Option<DefId>,
-    pub visibility: Visibility,
-    pub parent: Option<DefId>,
-    pub docs: String,
-    pub sig: Option<Signature>,
-    pub attributes: Vec<Attribute>,
-}
-
-impl Lower for data::MethodData {
-    type Target = MethodData;
-
-    fn lower(self, tcx: TyCtxt) -> MethodData {
-        MethodData {
-            span: span_from_span(self.span, tcx.sess.codemap()),
-            name: self.name,
-            scope: make_def_id(self.scope, &tcx.hir),
-            id: make_def_id(self.id, &tcx.hir),
-            qualname: self.qualname,
-            value: self.value,
-            decl_id: self.decl_id,
-            visibility: self.visibility,
-            parent: self.parent,
-            docs: self.docs,
-            sig: self.sig,
-            attributes: self.attributes.lower(tcx),
-        }
-    }
-}
-
-/// Data for modules.
-#[derive(Debug)]
-pub struct ModData {
-    pub id: DefId,
-    pub name: String,
-    pub qualname: String,
-    pub span: SpanData,
-    pub scope: DefId,
-    pub filename: String,
-    pub items: Vec<DefId>,
-    pub visibility: Visibility,
-    pub docs: String,
-    pub sig: Option<Signature>,
-    pub attributes: Vec<Attribute>,
-}
-
-impl Lower for data::ModData {
-    type Target = ModData;
-
-    fn lower(self, tcx: TyCtxt) -> ModData {
-        ModData {
-            id: make_def_id(self.id, &tcx.hir),
-            name: self.name,
-            qualname: self.qualname,
-            span: span_from_span(self.span, tcx.sess.codemap()),
-            scope: make_def_id(self.scope, &tcx.hir),
-            filename: self.filename,
-            items: self.items.into_iter().map(|id| make_def_id(id, &tcx.hir)).collect(),
-            visibility: self.visibility,
-            docs: self.docs,
-            sig: self.sig,
-            attributes: self.attributes.lower(tcx),
-        }
-    }
-}
-
-/// Data for a reference to a module.
-#[derive(Debug)]
-pub struct ModRefData {
-    pub span: SpanData,
-    pub scope: DefId,
-    pub ref_id: Option<DefId>,
-    pub qualname: String
-}
-
-impl Lower for data::ModRefData {
-    type Target = ModRefData;
-
-    fn lower(self, tcx: TyCtxt) -> ModRefData {
-        ModRefData {
-            span: span_from_span(self.span, tcx.sess.codemap()),
-            scope: make_def_id(self.scope, &tcx.hir),
-            ref_id: self.ref_id,
-            qualname: self.qualname,
-        }
-    }
-}
-
-#[derive(Debug)]
-pub struct StructData {
-    pub span: SpanData,
-    pub name: String,
-    pub id: DefId,
-    pub ctor_id: DefId,
-    pub qualname: String,
-    pub scope: DefId,
-    pub value: String,
-    pub fields: Vec<DefId>,
-    pub visibility: Visibility,
-    pub docs: String,
-    pub sig: Option<Signature>,
-    pub attributes: Vec<Attribute>,
-}
-
-impl Lower for data::StructData {
-    type Target = StructData;
-
-    fn lower(self, tcx: TyCtxt) -> StructData {
-        StructData {
-            span: span_from_span(self.span, tcx.sess.codemap()),
-            name: self.name,
-            id: make_def_id(self.id, &tcx.hir),
-            ctor_id: make_def_id(self.ctor_id, &tcx.hir),
-            qualname: self.qualname,
-            scope: make_def_id(self.scope, &tcx.hir),
-            value: self.value,
-            fields: self.fields.into_iter().map(|id| make_def_id(id, &tcx.hir)).collect(),
-            visibility: self.visibility,
-            docs: self.docs,
-            sig: self.sig,
-            attributes: self.attributes.lower(tcx),
-        }
-    }
-}
-
-#[derive(Debug)]
-pub struct StructVariantData {
-    pub span: SpanData,
-    pub name: String,
-    pub id: DefId,
-    pub qualname: String,
-    pub type_value: String,
-    pub value: String,
-    pub scope: DefId,
-    pub parent: Option<DefId>,
-    pub docs: String,
-    pub sig: Option<Signature>,
-    pub attributes: Vec<Attribute>,
-}
-
-impl Lower for data::StructVariantData {
-    type Target = StructVariantData;
-
-    fn lower(self, tcx: TyCtxt) -> StructVariantData {
-        StructVariantData {
-            span: span_from_span(self.span, tcx.sess.codemap()),
-            name: self.name,
-            id: make_def_id(self.id, &tcx.hir),
-            qualname: self.qualname,
-            type_value: self.type_value,
-            value: self.value,
-            scope: make_def_id(self.scope, &tcx.hir),
-            parent: self.parent,
-            docs: self.docs,
-            sig: self.sig,
-            attributes: self.attributes.lower(tcx),
-        }
-    }
-}
-
-#[derive(Debug)]
-pub struct TraitData {
-    pub span: SpanData,
-    pub name: String,
-    pub id: DefId,
-    pub qualname: String,
-    pub scope: DefId,
-    pub value: String,
-    pub items: Vec<DefId>,
-    pub visibility: Visibility,
-    pub docs: String,
-    pub sig: Option<Signature>,
-    pub attributes: Vec<Attribute>,
-}
-
-impl Lower for data::TraitData {
-    type Target = TraitData;
-
-    fn lower(self, tcx: TyCtxt) -> TraitData {
-        TraitData {
-            span: span_from_span(self.span, tcx.sess.codemap()),
-            name: self.name,
-            id: make_def_id(self.id, &tcx.hir),
-            qualname: self.qualname,
-            scope: make_def_id(self.scope, &tcx.hir),
-            value: self.value,
-            items: self.items.into_iter().map(|id| make_def_id(id, &tcx.hir)).collect(),
-            visibility: self.visibility,
-            docs: self.docs,
-            sig: self.sig,
-            attributes: self.attributes.lower(tcx),
-        }
-    }
-}
-
-#[derive(Debug)]
-pub struct TupleVariantData {
-    pub span: SpanData,
-    pub id: DefId,
-    pub name: String,
-    pub qualname: String,
-    pub type_value: String,
-    pub value: String,
-    pub scope: DefId,
-    pub parent: Option<DefId>,
-    pub docs: String,
-    pub sig: Option<Signature>,
-    pub attributes: Vec<Attribute>,
-}
-
-impl Lower for data::TupleVariantData {
-    type Target = TupleVariantData;
-
-    fn lower(self, tcx: TyCtxt) -> TupleVariantData {
-        TupleVariantData {
-            span: span_from_span(self.span, tcx.sess.codemap()),
-            id: make_def_id(self.id, &tcx.hir),
-            name: self.name,
-            qualname: self.qualname,
-            type_value: self.type_value,
-            value: self.value,
-            scope: make_def_id(self.scope, &tcx.hir),
-            parent: self.parent,
-            docs: self.docs,
-            sig: self.sig,
-            attributes: self.attributes.lower(tcx),
-        }
-    }
-}
-
-/// Data for a typedef.
-#[derive(Debug)]
-pub struct TypeDefData {
-    pub id: DefId,
-    pub name: String,
-    pub span: SpanData,
-    pub qualname: String,
-    pub value: String,
-    pub visibility: Visibility,
-    pub parent: Option<DefId>,
-    pub docs: String,
-    pub sig: Option<Signature>,
-    pub attributes: Vec<Attribute>,
-}
-
-impl Lower for data::TypeDefData {
-    type Target = TypeDefData;
-
-    fn lower(self, tcx: TyCtxt) -> TypeDefData {
-        TypeDefData {
-            id: make_def_id(self.id, &tcx.hir),
-            name: self.name,
-            span: span_from_span(self.span, tcx.sess.codemap()),
-            qualname: self.qualname,
-            value: self.value,
-            visibility: self.visibility,
-            parent: self.parent,
-            docs: self.docs,
-            sig: self.sig,
-            attributes: self.attributes.lower(tcx),
-        }
-    }
-}
-
-/// Data for a reference to a type or trait.
-#[derive(Clone, Debug)]
-pub struct TypeRefData {
-    pub span: SpanData,
-    pub scope: DefId,
-    pub ref_id: Option<DefId>,
-    pub qualname: String,
-}
-
-impl Lower for data::TypeRefData {
-    type Target = TypeRefData;
-
-    fn lower(self, tcx: TyCtxt) -> TypeRefData {
-        TypeRefData {
-            span: span_from_span(self.span, tcx.sess.codemap()),
-            scope: make_def_id(self.scope, &tcx.hir),
-            ref_id: self.ref_id,
-            qualname: self.qualname,
-        }
-    }
-}
-
-#[derive(Debug)]
-pub struct UseData {
-    pub id: DefId,
-    pub span: SpanData,
-    pub name: String,
-    pub mod_id: Option<DefId>,
-    pub scope: DefId,
-    pub visibility: Visibility,
-}
-
-impl Lower for data::UseData {
-    type Target = UseData;
-
-    fn lower(self, tcx: TyCtxt) -> UseData {
-        UseData {
-            id: make_def_id(self.id, &tcx.hir),
-            span: span_from_span(self.span, tcx.sess.codemap()),
-            name: self.name,
-            mod_id: self.mod_id,
-            scope: make_def_id(self.scope, &tcx.hir),
-            visibility: self.visibility,
-        }
-    }
-}
-
-#[derive(Debug)]
-pub struct UseGlobData {
-    pub id: DefId,
-    pub span: SpanData,
-    pub names: Vec<String>,
-    pub scope: DefId,
-    pub visibility: Visibility,
-}
-
-impl Lower for data::UseGlobData {
-    type Target = UseGlobData;
-
-    fn lower(self, tcx: TyCtxt) -> UseGlobData {
-        UseGlobData {
-            id: make_def_id(self.id, &tcx.hir),
-            span: span_from_span(self.span, tcx.sess.codemap()),
-            names: self.names,
-            scope: make_def_id(self.scope, &tcx.hir),
-            visibility: self.visibility,
-        }
-    }
-}
-
-/// Data for local and global variables (consts and statics).
-#[derive(Debug)]
-pub struct VariableData {
-    pub id: DefId,
-    pub name: String,
-    pub kind: data::VariableKind,
-    pub qualname: String,
-    pub span: SpanData,
-    pub scope: DefId,
-    pub value: String,
-    pub type_value: String,
-    pub parent: Option<DefId>,
-    pub visibility: Visibility,
-    pub docs: String,
-    pub sig: Option<Signature>,
-    pub attributes: Vec<Attribute>,
-}
-
-impl Lower for data::VariableData {
-    type Target = VariableData;
-
-    fn lower(self, tcx: TyCtxt) -> VariableData {
-        VariableData {
-            id: make_def_id(self.id, &tcx.hir),
-            kind: self.kind,
-            name: self.name,
-            qualname: self.qualname,
-            span: span_from_span(self.span, tcx.sess.codemap()),
-            scope: make_def_id(self.scope, &tcx.hir),
-            value: self.value,
-            type_value: self.type_value,
-            parent: self.parent,
-            visibility: self.visibility,
-            docs: self.docs,
-            sig: self.sig,
-            attributes: self.attributes.lower(tcx),
-        }
-    }
-}
-
-/// Data for the use of some item (e.g., the use of a local variable, which
-/// will refer to that variables declaration (by ref_id)).
-#[derive(Debug)]
-pub struct VariableRefData {
-    pub name: String,
-    pub span: SpanData,
-    pub scope: DefId,
-    pub ref_id: DefId,
-}
-
-impl Lower for data::VariableRefData {
-    type Target = VariableRefData;
-
-    fn lower(self, tcx: TyCtxt) -> VariableRefData {
-        VariableRefData {
-            name: self.name,
-            span: span_from_span(self.span, tcx.sess.codemap()),
-            scope: make_def_id(self.scope, &tcx.hir),
-            ref_id: self.ref_id,
-        }
-    }
-}
diff --git a/src/librustc_save_analysis/json_api_dumper.rs b/src/librustc_save_analysis/json_api_dumper.rs
index bddee6460ff..4b2301fd7f8 100644
--- a/src/librustc_save_analysis/json_api_dumper.rs
+++ b/src/librustc_save_analysis/json_api_dumper.rs
@@ -12,12 +12,9 @@ use std::io::Write;
 
 use rustc_serialize::json::as_json;
 
-use external_data::*;
-use data::{VariableKind, Visibility};
-use dump::Dump;
-use id_from_def_id;
+use Dump;
 
-use rls_data::{Analysis, Import, ImportKind, Def, DefKind, CratePreludeData, Format};
+use rls_data::{Analysis, Import, Def, CratePreludeData, Format, Relation};
 
 
 // A dumper to dump a restricted set of JSON information, designed for use with
@@ -47,306 +44,23 @@ impl<'b, W: Write> Drop for JsonApiDumper<'b, W> {
     }
 }
 
-macro_rules! impl_fn {
-    ($fn_name: ident, $data_type: ident, $bucket: ident) => {
-        fn $fn_name(&mut self, data: $data_type) {
-            if let Some(datum) = data.into() {
-                self.result.$bucket.push(datum);
-            }
-        }
-    }
-}
-
 impl<'b, W: Write + 'b> Dump for JsonApiDumper<'b, W> {
     fn crate_prelude(&mut self, data: CratePreludeData) {
         self.result.prelude = Some(data)
     }
 
-    impl_fn!(use_data, UseData, imports);
-    impl_fn!(use_glob, UseGlobData, imports);
-
-    impl_fn!(enum_data, EnumData, defs);
-    impl_fn!(tuple_variant, TupleVariantData, defs);
-    impl_fn!(struct_variant, StructVariantData, defs);
-    impl_fn!(struct_data, StructData, defs);
-    impl_fn!(trait_data, TraitData, defs);
-    impl_fn!(function, FunctionData, defs);
-    impl_fn!(method, MethodData, defs);
-    impl_fn!(macro_data, MacroData, defs);
-    impl_fn!(mod_data, ModData, defs);
-    impl_fn!(typedef, TypeDefData, defs);
-    impl_fn!(variable, VariableData, defs);
-
-    fn impl_data(&mut self, data: ImplData) {
-        if data.self_ref.is_some() {
-            self.result.relations.push(data.into());
-        }
-    }
-    fn inheritance(&mut self, data: InheritanceData) {
-        self.result.relations.push(data.into());
+    fn dump_relation(&mut self, data: Relation) {
+        self.result.relations.push(data);
     }
-}
-
-// FIXME methods. The defs have information about possible overriding and the
-// refs have decl information (e.g., a trait method where we know the required
-// method, but not the supplied method). In both cases, we are currently
-// ignoring it.
-
-impl Into<Option<Import>> for UseData {
-    fn into(self) -> Option<Import> {
-        match self.visibility {
-            Visibility::Public => Some(Import {
-                kind: ImportKind::Use,
-                ref_id: self.mod_id.map(|id| id_from_def_id(id)),
-                span: self.span,
-                name: self.name,
-                value: String::new(),
-            }),
-            _ => None,
+    fn import(&mut self, public: bool, import: Import) {
+        if public {
+            self.result.imports.push(import);
         }
     }
-}
-impl Into<Option<Import>> for UseGlobData {
-    fn into(self) -> Option<Import> {
-        match self.visibility {
-            Visibility::Public => Some(Import {
-                kind: ImportKind::GlobUse,
-                ref_id: None,
-                span: self.span,
-                name: "*".to_owned(),
-                value: self.names.join(", "),
-            }),
-            _ => None,
-        }
-    }
-}
-
-impl Into<Option<Def>> for EnumData {
-    fn into(self) -> Option<Def> {
-        match self.visibility {
-            Visibility::Public => Some(Def {
-                kind: DefKind::Enum,
-                id: id_from_def_id(self.id),
-                span: self.span,
-                name: self.name,
-                qualname: self.qualname,
-                value: self.value,
-                parent: None,
-                children: self.variants.into_iter().map(|id| id_from_def_id(id)).collect(),
-                decl_id: None,
-                docs: self.docs,
-                sig: self.sig,
-                attributes: vec![],
-            }),
-            _ => None,
-        }
-    }
-}
-
-impl Into<Option<Def>> for TupleVariantData {
-    fn into(self) -> Option<Def> {
-        Some(Def {
-            kind: DefKind::Tuple,
-            id: id_from_def_id(self.id),
-            span: self.span,
-            name: self.name,
-            qualname: self.qualname,
-            value: self.value,
-            parent: self.parent.map(|id| id_from_def_id(id)),
-            children: vec![],
-            decl_id: None,
-            docs: self.docs,
-            sig: self.sig,
-            attributes: vec![],
-        })
-    }
-}
-impl Into<Option<Def>> for StructVariantData {
-    fn into(self) -> Option<Def> {
-        Some(Def {
-            kind: DefKind::Struct,
-            id: id_from_def_id(self.id),
-            span: self.span,
-            name: self.name,
-            qualname: self.qualname,
-            value: self.value,
-            parent: self.parent.map(|id| id_from_def_id(id)),
-            children: vec![],
-            decl_id: None,
-            docs: self.docs,
-            sig: self.sig,
-            attributes: vec![],
-        })
-    }
-}
-impl Into<Option<Def>> for StructData {
-    fn into(self) -> Option<Def> {
-        match self.visibility {
-            Visibility::Public => Some(Def {
-            kind: DefKind::Struct,
-            id: id_from_def_id(self.id),
-            span: self.span,
-            name: self.name,
-            qualname: self.qualname,
-            value: self.value,
-            parent: None,
-            children: self.fields.into_iter().map(|id| id_from_def_id(id)).collect(),
-            decl_id: None,
-            docs: self.docs,
-            sig: self.sig,
-            attributes: vec![],
-        }),
-            _ => None,
-        }
-    }
-}
-impl Into<Option<Def>> for TraitData {
-    fn into(self) -> Option<Def> {
-        match self.visibility {
-            Visibility::Public => Some(Def {
-                kind: DefKind::Trait,
-                id: id_from_def_id(self.id),
-                span: self.span,
-                name: self.name,
-                qualname: self.qualname,
-                value: self.value,
-                children: self.items.into_iter().map(|id| id_from_def_id(id)).collect(),
-                parent: None,
-                decl_id: None,
-                docs: self.docs,
-                sig: self.sig,
-                attributes: vec![],
-            }),
-            _ => None,
-        }
-    }
-}
-impl Into<Option<Def>> for FunctionData {
-    fn into(self) -> Option<Def> {
-        match self.visibility {
-            Visibility::Public => Some(Def {
-                kind: DefKind::Function,
-                id: id_from_def_id(self.id),
-                span: self.span,
-                name: self.name,
-                qualname: self.qualname,
-                value: self.value,
-                children: vec![],
-                parent: self.parent.map(|id| id_from_def_id(id)),
-                decl_id: None,
-                docs: self.docs,
-                sig: self.sig,
-                attributes: vec![],
-            }),
-            _ => None,
-        }
-    }
-}
-impl Into<Option<Def>> for MethodData {
-    fn into(self) -> Option<Def> {
-        match self.visibility {
-            Visibility::Public => Some(Def {
-                kind: DefKind::Method,
-                id: id_from_def_id(self.id),
-                span: self.span,
-                name: self.name,
-                qualname: self.qualname,
-                value: self.value,
-                children: vec![],
-                parent: self.parent.map(|id| id_from_def_id(id)),
-                decl_id: self.decl_id.map(|id| id_from_def_id(id)),
-                docs: self.docs,
-                sig: self.sig,
-                attributes: vec![],
-            }),
-            _ => None,
-        }
-    }
-}
-impl Into<Option<Def>> for MacroData {
-    fn into(self) -> Option<Def> {
-        Some(Def {
-            kind: DefKind::Macro,
-            id: id_from_def_id(null_def_id()),
-            span: self.span,
-            name: self.name,
-            qualname: self.qualname,
-            value: String::new(),
-            children: vec![],
-            parent: None,
-            decl_id: None,
-            docs: self.docs,
-            sig: None,
-            attributes: vec![],
-        })
-    }
-}
-impl Into<Option<Def>> for ModData {
-    fn into(self) -> Option<Def> {
-        match self.visibility {
-            Visibility::Public => Some(Def {
-                kind: DefKind::Mod,
-                id: id_from_def_id(self.id),
-                span: self.span,
-                name: self.name,
-                qualname: self.qualname,
-                value: self.filename,
-                children: self.items.into_iter().map(|id| id_from_def_id(id)).collect(),
-                parent: None,
-                decl_id: None,
-                docs: self.docs,
-                sig: self.sig.map(|s| s.into()),
-                attributes: vec![],
-            }),
-            _ => None,
-        }
-    }
-}
-impl Into<Option<Def>> for TypeDefData {
-    fn into(self) -> Option<Def> {
-        match self.visibility {
-            Visibility::Public => Some(Def {
-                kind: DefKind::Type,
-                id: id_from_def_id(self.id),
-                span: self.span,
-                name: self.name,
-                qualname: self.qualname,
-                value: self.value,
-                children: vec![],
-                parent: self.parent.map(|id| id_from_def_id(id)),
-                decl_id: None,
-                docs: String::new(),
-                sig: self.sig.map(|s| s.into()),
-                attributes: vec![],
-            }),
-            _ => None,
-        }
-    }
-}
-
-impl Into<Option<Def>> for VariableData {
-    fn into(self) -> Option<Def> {
-        match self.visibility {
-            Visibility::Public => Some(Def {
-                kind: match self.kind {
-                    VariableKind::Static => DefKind::Static,
-                    VariableKind::Const => DefKind::Const,
-                    VariableKind::Local => { return None }
-                    VariableKind::Field => DefKind::Field,
-                },
-                id: id_from_def_id(self.id),
-                span: self.span,
-                name: self.name,
-                qualname: self.qualname,
-                value: self.value,
-                children: vec![],
-                parent: self.parent.map(|id| id_from_def_id(id)),
-                decl_id: None,
-                docs: self.docs,
-                sig: self.sig.map(|s| s.into()),
-                attributes: vec![],
-            }),
-            _ => None,
+    fn dump_def(&mut self, public: bool, mut data: Def) {
+        if public {
+            data.attributes = vec![];
+            self.result.defs.push(data);
         }
     }
 }
diff --git a/src/librustc_save_analysis/json_dumper.rs b/src/librustc_save_analysis/json_dumper.rs
index 58df612c687..9cd375e9855 100644
--- a/src/librustc_save_analysis/json_dumper.rs
+++ b/src/librustc_save_analysis/json_dumper.rs
@@ -12,14 +12,11 @@ use std::io::Write;
 
 use rustc_serialize::json::as_json;
 
-use rls_data::{self, Id, Analysis, Import, ImportKind, Def, DefKind, Ref, RefKind, MacroRef,
-               Relation, RelationKind, CratePreludeData};
+use rls_data::{self, Analysis, Import, Def, DefKind, Ref, RefKind, MacroRef,
+               Relation, CratePreludeData};
 use rls_span::{Column, Row};
 
-use external_data::*;
-use data::VariableKind;
-use dump::Dump;
-use id_from_def_id;
+use Dump;
 
 pub struct JsonDumper<O: DumpOutput> {
     result: Analysis,
@@ -70,71 +67,35 @@ impl<O: DumpOutput> Drop for JsonDumper<O> {
     }
 }
 
-macro_rules! impl_fn {
-    ($fn_name: ident, $data_type: ident, $bucket: ident) => {
-        fn $fn_name(&mut self, data: $data_type) {
-            self.result.$bucket.push(data.into());
-        }
-    }
-}
-
 impl<'b, O: DumpOutput + 'b> Dump for JsonDumper<O> {
     fn crate_prelude(&mut self, data: CratePreludeData) {
         self.result.prelude = Some(data)
     }
 
-    impl_fn!(extern_crate, ExternCrateData, imports);
-    impl_fn!(use_data, UseData, imports);
-    impl_fn!(use_glob, UseGlobData, imports);
-
-    impl_fn!(enum_data, EnumData, defs);
-    impl_fn!(tuple_variant, TupleVariantData, defs);
-    impl_fn!(struct_variant, StructVariantData, defs);
-    impl_fn!(struct_data, StructData, defs);
-    impl_fn!(trait_data, TraitData, defs);
-    impl_fn!(function, FunctionData, defs);
-    impl_fn!(method, MethodData, defs);
-    impl_fn!(macro_data, MacroData, defs);
-    impl_fn!(typedef, TypeDefData, defs);
-    impl_fn!(variable, VariableData, defs);
-
-    impl_fn!(function_ref, FunctionRefData, refs);
-    impl_fn!(function_call, FunctionCallData, refs);
-    impl_fn!(method_call, MethodCallData, refs);
-    impl_fn!(mod_ref, ModRefData, refs);
-    impl_fn!(type_ref, TypeRefData, refs);
-    impl_fn!(variable_ref, VariableRefData, refs);
+    fn macro_use(&mut self, data: MacroRef) {
+        self.result.macro_refs.push(data);
+    }
 
-    impl_fn!(macro_use, MacroUseData, macro_refs);
+    fn import(&mut self, _: bool, import: Import) {
+        self.result.imports.push(import);
+    }
 
-    fn mod_data(&mut self, data: ModData) {
-        let id: Id = id_from_def_id(data.id);
-        let mut def = Def {
-            kind: DefKind::Mod,
-            id: id,
-            span: data.span.into(),
-            name: data.name,
-            qualname: data.qualname,
-            value: data.filename,
-            parent: None,
-            children: data.items.into_iter().map(|id| id_from_def_id(id)).collect(),
-            decl_id: None,
-            docs: data.docs,
-            sig: data.sig,
-            attributes: data.attributes.into_iter().map(|a| a.into()).collect(),
-        };
-        if def.span.file_name.to_str().unwrap() != def.value {
+    fn dump_ref(&mut self, data: Ref) {
+        self.result.refs.push(data);
+    }
+    fn dump_def(&mut self, _: bool, mut data: Def) {
+        if data.kind == DefKind::Mod && data.span.file_name.to_str().unwrap() != data.value {
             // If the module is an out-of-line defintion, then we'll make the
             // defintion the first character in the module's file and turn the
             // the declaration into a reference to it.
             let rf = Ref {
                 kind: RefKind::Mod,
-                span: def.span,
-                ref_id: id,
+                span: data.span,
+                ref_id: data.id,
             };
             self.result.refs.push(rf);
-            def.span = rls_data::SpanData {
-                file_name: def.value.clone().into(),
+            data.span = rls_data::SpanData {
+                file_name: data.value.clone().into(),
                 byte_start: 0,
                 byte_end: 0,
                 line_start: Row::new_one_indexed(1),
@@ -143,330 +104,10 @@ impl<'b, O: DumpOutput + 'b> Dump for JsonDumper<O> {
                 column_end: Column::new_one_indexed(1),
             }
         }
-
-        self.result.defs.push(def);
-    }
-
-    fn impl_data(&mut self, data: ImplData) {
-        if data.self_ref.is_some() {
-            self.result.relations.push(data.into());
-        }
-    }
-    fn inheritance(&mut self, data: InheritanceData) {
-        self.result.relations.push(data.into());
-    }
-}
-
-// FIXME do we want to change ExternalData to this mode? It will break DXR.
-// FIXME methods. The defs have information about possible overriding and the
-// refs have decl information (e.g., a trait method where we know the required
-// method, but not the supplied method). In both cases, we are currently
-// ignoring it.
-
-impl Into<Import> for ExternCrateData {
-    fn into(self) -> Import {
-        Import {
-            kind: ImportKind::ExternCrate,
-            ref_id: None,
-            span: self.span,
-            name: self.name,
-            value: String::new(),
-        }
-    }
-}
-impl Into<Import> for UseData {
-    fn into(self) -> Import {
-        Import {
-            kind: ImportKind::Use,
-            ref_id: self.mod_id.map(|id| id_from_def_id(id)),
-            span: self.span,
-            name: self.name,
-            value: String::new(),
-        }
-    }
-}
-impl Into<Import> for UseGlobData {
-    fn into(self) -> Import {
-        Import {
-            kind: ImportKind::GlobUse,
-            ref_id: None,
-            span: self.span,
-            name: "*".to_owned(),
-            value: self.names.join(", "),
-        }
-    }
-}
-
-impl Into<Def> for EnumData {
-    fn into(self) -> Def {
-        Def {
-            kind: DefKind::Enum,
-            id: id_from_def_id(self.id),
-            span: self.span,
-            name: self.name,
-            qualname: self.qualname,
-            value: self.value,
-            parent: None,
-            children: self.variants.into_iter().map(|id| id_from_def_id(id)).collect(),
-            decl_id: None,
-            docs: self.docs,
-            sig: self.sig,
-            attributes: self.attributes,
-        }
-    }
-}
-
-impl Into<Def> for TupleVariantData {
-    fn into(self) -> Def {
-        Def {
-            kind: DefKind::Tuple,
-            id: id_from_def_id(self.id),
-            span: self.span,
-            name: self.name,
-            qualname: self.qualname,
-            value: self.value,
-            parent: None,
-            children: vec![],
-            decl_id: None,
-            docs: self.docs,
-            sig: self.sig,
-            attributes: self.attributes,
-        }
-    }
-}
-impl Into<Def> for StructVariantData {
-    fn into(self) -> Def {
-        Def {
-            kind: DefKind::Struct,
-            id: id_from_def_id(self.id),
-            span: self.span,
-            name: self.name,
-            qualname: self.qualname,
-            value: self.value,
-            parent: None,
-            children: vec![],
-            decl_id: None,
-            docs: self.docs,
-            sig: self.sig,
-            attributes: self.attributes,
-        }
-    }
-}
-impl Into<Def> for StructData {
-    fn into(self) -> Def {
-        Def {
-            kind: DefKind::Struct,
-            id: id_from_def_id(self.id),
-            span: self.span,
-            name: self.name,
-            qualname: self.qualname,
-            value: self.value,
-            parent: None,
-            children: self.fields.into_iter().map(|id| id_from_def_id(id)).collect(),
-            decl_id: None,
-            docs: self.docs,
-            sig: self.sig,
-            attributes: self.attributes,
-        }
-    }
-}
-impl Into<Def> for TraitData {
-    fn into(self) -> Def {
-        Def {
-            kind: DefKind::Trait,
-            id: id_from_def_id(self.id),
-            span: self.span,
-            name: self.name,
-            qualname: self.qualname,
-            value: self.value,
-            parent: None,
-            children: self.items.into_iter().map(|id| id_from_def_id(id)).collect(),
-            decl_id: None,
-            docs: self.docs,
-            sig: self.sig,
-            attributes: self.attributes,
-        }
-    }
-}
-impl Into<Def> for FunctionData {
-    fn into(self) -> Def {
-        Def {
-            kind: DefKind::Function,
-            id: id_from_def_id(self.id),
-            span: self.span,
-            name: self.name,
-            qualname: self.qualname,
-            value: self.value,
-            parent: None,
-            children: vec![],
-            decl_id: None,
-            docs: self.docs,
-            sig: self.sig,
-            attributes: self.attributes,
-        }
-    }
-}
-impl Into<Def> for MethodData {
-    fn into(self) -> Def {
-        Def {
-            kind: DefKind::Method,
-            id: id_from_def_id(self.id),
-            span: self.span,
-            name: self.name,
-            qualname: self.qualname,
-            value: self.value,
-            parent: None,
-            children: vec![],
-            decl_id: self.decl_id.map(|id| id_from_def_id(id)),
-            docs: self.docs,
-            sig: self.sig,
-            attributes: self.attributes,
-        }
-    }
-}
-impl Into<Def> for MacroData {
-    fn into(self) -> Def {
-        Def {
-            kind: DefKind::Macro,
-            id: id_from_def_id(null_def_id()),
-            span: self.span,
-            name: self.name,
-            qualname: self.qualname,
-            value: String::new(),
-            parent: None,
-            children: vec![],
-            decl_id: None,
-            docs: self.docs,
-            sig: None,
-            attributes: vec![],
-        }
-    }
-}
-impl Into<Def> for TypeDefData {
-    fn into(self) -> Def {
-        Def {
-            kind: DefKind::Type,
-            id: id_from_def_id(self.id),
-            span: self.span,
-            name: self.name,
-            qualname: self.qualname,
-            value: self.value,
-            parent: None,
-            children: vec![],
-            decl_id: None,
-            docs: String::new(),
-            sig: self.sig,
-            attributes: self.attributes,
-        }
+        self.result.defs.push(data);
     }
-}
-impl Into<Def> for VariableData {
-    fn into(self) -> Def {
-        Def {
-            kind: match self.kind {
-                VariableKind::Static => DefKind::Static,
-                VariableKind::Const => DefKind::Const,
-                VariableKind::Local => DefKind::Local,
-                VariableKind::Field => DefKind::Field,
-            },
-            id: id_from_def_id(self.id),
-            span: self.span,
-            name: self.name,
-            qualname: self.qualname,
-            value: self.type_value,
-            parent: None,
-            children: vec![],
-            decl_id: None,
-            docs: self.docs,
-            sig: None,
-            attributes: self.attributes,
-        }
-    }
-}
 
-impl Into<Ref> for FunctionRefData {
-    fn into(self) -> Ref {
-        Ref {
-            kind: RefKind::Function,
-            span: self.span,
-            ref_id: id_from_def_id(self.ref_id),
-        }
-    }
-}
-impl Into<Ref> for FunctionCallData {
-    fn into(self) -> Ref {
-        Ref {
-            kind: RefKind::Function,
-            span: self.span,
-            ref_id: id_from_def_id(self.ref_id),
-        }
-    }
-}
-impl Into<Ref> for MethodCallData {
-    fn into(self) -> Ref {
-        Ref {
-            kind: RefKind::Function,
-            span: self.span,
-            ref_id: id_from_def_id(self.ref_id.or(self.decl_id).unwrap_or(null_def_id())),
-        }
-    }
-}
-impl Into<Ref> for ModRefData {
-    fn into(self) -> Ref {
-        Ref {
-            kind: RefKind::Mod,
-            span: self.span,
-            ref_id: id_from_def_id(self.ref_id.unwrap_or(null_def_id())),
-        }
-    }
-}
-impl Into<Ref> for TypeRefData {
-    fn into(self) -> Ref {
-        Ref {
-            kind: RefKind::Type,
-            span: self.span,
-            ref_id: id_from_def_id(self.ref_id.unwrap_or(null_def_id())),
-        }
-    }
-}
-impl Into<Ref> for VariableRefData {
-    fn into(self) -> Ref {
-        Ref {
-            kind: RefKind::Variable,
-            span: self.span,
-            ref_id: id_from_def_id(self.ref_id),
-        }
-    }
-}
-
-impl Into<MacroRef> for MacroUseData {
-    fn into(self) -> MacroRef {
-        MacroRef {
-            span: self.span,
-            qualname: self.qualname,
-            callee_span: self.callee_span.into(),
-        }
-    }
-}
-
-impl Into<Relation> for ImplData {
-    fn into(self) -> Relation {
-        Relation {
-            span: self.span,
-            kind: RelationKind::Impl,
-            from: id_from_def_id(self.self_ref.unwrap_or(null_def_id())),
-            to: id_from_def_id(self.trait_ref.unwrap_or(null_def_id())),
-        }
-    }
-}
-
-impl Into<Relation> for InheritanceData {
-    fn into(self) -> Relation {
-        Relation {
-            span: self.span,
-            kind: RelationKind::SuperTrait,
-            from: id_from_def_id(self.base_id),
-            to: id_from_def_id(self.deriv_id),
-        }
+    fn dump_relation(&mut self, data: Relation) {
+        self.result.relations.push(data);
     }
 }
diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs
index 4ab2c1aa63c..4e9e72fe249 100644
--- a/src/librustc_save_analysis/lib.rs
+++ b/src/librustc_save_analysis/lib.rs
@@ -35,20 +35,16 @@ extern crate rls_data;
 extern crate rls_span;
 
 
-mod csv_dumper;
 mod json_api_dumper;
 mod json_dumper;
-mod data;
-mod dump;
 mod dump_visitor;
-pub mod external_data;
 #[macro_use]
-pub mod span_utils;
+mod span_utils;
 mod sig;
 
 use rustc::hir;
-use rustc::hir::def::Def;
-use rustc::hir::map::Node;
+use rustc::hir::def::Def as HirDef;
+use rustc::hir::map::{Node, NodeItem};
 use rustc::hir::def_id::DefId;
 use rustc::session::config::CrateType::CrateTypeExecutable;
 use rustc::session::Session;
@@ -62,33 +58,21 @@ use std::path::{Path, PathBuf};
 use syntax::ast::{self, NodeId, PatKind, Attribute, CRATE_NODE_ID};
 use syntax::parse::lexer::comments::strip_doc_comment_decoration;
 use syntax::parse::token;
+use syntax::print::pprust;
 use syntax::symbol::keywords;
 use syntax::visit::{self, Visitor};
 use syntax::print::pprust::{ty_to_string, arg_to_string};
 use syntax::codemap::MacroAttribute;
 use syntax_pos::*;
 
-pub use self::csv_dumper::CsvDumper;
-pub use self::json_api_dumper::JsonApiDumper;
-pub use self::json_dumper::JsonDumper;
-pub use self::data::*;
-pub use self::external_data::make_def_id;
-pub use self::dump::Dump;
-pub use self::dump_visitor::DumpVisitor;
-use self::span_utils::SpanUtils;
-
-// FIXME this is legacy code and should be removed
-pub mod recorder {
-    pub use self::Row::*;
-
-    #[derive(Copy, Clone, Debug, Eq, PartialEq)]
-    pub enum Row {
-        TypeRef,
-        ModRef,
-        VarRef,
-        FnRef,
-    }
-}
+pub use json_api_dumper::JsonApiDumper;
+pub use json_dumper::JsonDumper;
+use dump_visitor::DumpVisitor;
+use span_utils::SpanUtils;
+
+use rls_data::{Ref, RefKind, SpanData, MacroRef, Def, DefKind, Relation, RelationKind,
+               ExternalCrateData, Import, CratePreludeData};
+
 
 pub struct SaveContext<'l, 'tcx: 'l> {
     tcx: TyCtxt<'l, 'tcx, 'tcx>,
@@ -97,13 +81,49 @@ pub struct SaveContext<'l, 'tcx: 'l> {
     span_utils: SpanUtils<'tcx>,
 }
 
+#[derive(Debug)]
+pub enum Data {
+    /// Data about a macro use.
+    MacroUseData(MacroRef),
+    RefData(Ref),
+    DefData(Def),
+    RelationData(Relation),
+}
+
+pub trait Dump {
+    fn crate_prelude(&mut self, _: CratePreludeData);
+    fn macro_use(&mut self, _: MacroRef) {}
+    fn import(&mut self, _: bool, _: Import);
+    fn dump_ref(&mut self, _: Ref) {}
+    fn dump_def(&mut self, _: bool, _: Def);
+    fn dump_relation(&mut self, data: Relation);
+}
+
 macro_rules! option_try(
     ($e:expr) => (match $e { Some(e) => e, None => return None })
 );
 
 impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
+    fn span_from_span(&self, span: Span) -> SpanData {
+        use rls_span::{Row, Column};
+
+        let cm = self.tcx.sess.codemap();
+        let start = cm.lookup_char_pos(span.lo);
+        let end = cm.lookup_char_pos(span.hi);
+
+        SpanData {
+            file_name: start.file.name.clone().into(),
+            byte_start: span.lo.0,
+            byte_end: span.hi.0,
+            line_start: Row::new_one_indexed(start.line as u32),
+            line_end: Row::new_one_indexed(end.line as u32),
+            column_start: Column::new_one_indexed(start.col.0 as u32 + 1),
+            column_end: Column::new_one_indexed(end.col.0 as u32 + 1),
+        }
+    }
+
     // List external crates used by the current crate.
-    pub fn get_external_crates(&self) -> Vec<CrateData> {
+    pub fn get_external_crates(&self) -> Vec<ExternalCrateData> {
         let mut result = Vec::new();
 
         for n in self.tcx.sess.cstore.crates() {
@@ -114,10 +134,11 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                     continue;
                 }
             };
-            result.push(CrateData {
+            let lo_loc = self.span_utils.sess.codemap().lookup_char_pos(span.lo);
+            result.push(ExternalCrateData {
                 name: self.tcx.sess.cstore.crate_name(n).to_string(),
-                number: n.as_u32(),
-                span: span,
+                num: n.as_u32(),
+                file_name: SpanUtils::make_path_string(&lo_loc.file.name),
             });
         }
 
@@ -130,39 +151,43 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
             ast::ForeignItemKind::Fn(ref decl, ref generics) => {
                 let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Fn);
                 filter!(self.span_utils, sub_span, item.span, None);
-                Some(Data::FunctionData(FunctionData {
-                    id: item.id,
+
+                Some(Data::DefData(Def {
+                    kind: DefKind::Function,
+                    id: id_from_node_id(item.id, self),
+                    span: self.span_from_span(sub_span.unwrap()),
                     name: item.ident.to_string(),
-                    qualname: qualname,
-                    declaration: None,
-                    span: sub_span.unwrap(),
-                    scope: self.enclosing_scope(item.id),
+                    qualname,
                     value: make_signature(decl, generics),
-                    visibility: From::from(&item.vis),
                     parent: None,
+                    children: vec![],
+                    decl_id: None,
                     docs: docs_for_attrs(&item.attrs),
                     sig: sig::foreign_item_signature(item, self),
-                    attributes: item.attrs.clone(),
+                    attributes: lower_attributes(item.attrs.clone(), self),
                 }))
             }
             ast::ForeignItemKind::Static(ref ty, m) => {
                 let keyword = if m { keywords::Mut } else { keywords::Static };
                 let sub_span = self.span_utils.sub_span_after_keyword(item.span, keyword);
                 filter!(self.span_utils, sub_span, item.span, None);
-                Some(Data::VariableData(VariableData {
-                    id: item.id,
-                    kind: VariableKind::Static,
+
+                let id = ::id_from_node_id(item.id, self);
+                let span = self.span_from_span(sub_span.unwrap());
+
+                Some(Data::DefData(Def {
+                    kind: DefKind::Static,
+                    id,
+                    span,
                     name: item.ident.to_string(),
-                    qualname: qualname,
-                    span: sub_span.unwrap(),
-                    scope: self.enclosing_scope(item.id),
+                    qualname,
+                    value: ty_to_string(ty),
                     parent: None,
-                    value: String::new(),
-                    type_value: ty_to_string(ty),
-                    visibility: From::from(&item.vis),
+                    children: vec![],
+                    decl_id: None,
                     docs: docs_for_attrs(&item.attrs),
                     sig: sig::foreign_item_signature(item, self),
-                    attributes: item.attrs.clone(),
+                    attributes: lower_attributes(item.attrs.clone(), self),
                 }))
             }
         }
@@ -174,70 +199,71 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                 let qualname = format!("::{}", self.tcx.node_path_str(item.id));
                 let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Fn);
                 filter!(self.span_utils, sub_span, item.span, None);
-
-
-                Some(Data::FunctionData(FunctionData {
-                    id: item.id,
+                Some(Data::DefData(Def {
+                    kind: DefKind::Function,
+                    id: id_from_node_id(item.id, self),
+                    span: self.span_from_span(sub_span.unwrap()),
                     name: item.ident.to_string(),
-                    qualname: qualname,
-                    declaration: None,
-                    span: sub_span.unwrap(),
-                    scope: self.enclosing_scope(item.id),
+                    qualname,
                     value: make_signature(decl, generics),
-                    visibility: From::from(&item.vis),
                     parent: None,
+                    children: vec![],
+                    decl_id: None,
                     docs: docs_for_attrs(&item.attrs),
                     sig: sig::item_signature(item, self),
-                    attributes: item.attrs.clone(),
+                    attributes: lower_attributes(item.attrs.clone(), self),
                 }))
             }
-            ast::ItemKind::Static(ref typ, mt, ref expr) => {
+            ast::ItemKind::Static(ref typ, mt, _) => {
                 let qualname = format!("::{}", self.tcx.node_path_str(item.id));
 
-                // If the variable is immutable, save the initialising expression.
-                let (value, keyword) = match mt {
-                    ast::Mutability::Mutable => (String::from("<mutable>"), keywords::Mut),
-                    ast::Mutability::Immutable => {
-                        (self.span_utils.snippet(expr.span), keywords::Static)
-                    },
+                let keyword = match mt {
+                    ast::Mutability::Mutable => keywords::Mut,
+                    ast::Mutability::Immutable => keywords::Static,
                 };
 
                 let sub_span = self.span_utils.sub_span_after_keyword(item.span, keyword);
                 filter!(self.span_utils, sub_span, item.span, None);
-                Some(Data::VariableData(VariableData {
-                    id: item.id,
-                    kind: VariableKind::Static,
+
+                let id = id_from_node_id(item.id, self);
+                let span = self.span_from_span(sub_span.unwrap());
+
+                Some(Data::DefData(Def {
+                    kind: DefKind::Static,
+                    id,
+                    span,
                     name: item.ident.to_string(),
-                    qualname: qualname,
-                    span: sub_span.unwrap(),
-                    scope: self.enclosing_scope(item.id),
+                    qualname,
+                    value: ty_to_string(&typ),
                     parent: None,
-                    value: value,
-                    type_value: ty_to_string(&typ),
-                    visibility: From::from(&item.vis),
+                    children: vec![],
+                    decl_id: None,
                     docs: docs_for_attrs(&item.attrs),
                     sig: sig::item_signature(item, self),
-                    attributes: item.attrs.clone(),
+                    attributes: lower_attributes(item.attrs.clone(), self),
                 }))
             }
-            ast::ItemKind::Const(ref typ, ref expr) => {
+            ast::ItemKind::Const(ref typ, _) => {
                 let qualname = format!("::{}", self.tcx.node_path_str(item.id));
                 let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Const);
                 filter!(self.span_utils, sub_span, item.span, None);
-                Some(Data::VariableData(VariableData {
-                    id: item.id,
-                    kind: VariableKind::Const,
+
+                let id = id_from_node_id(item.id, self);
+                let span = self.span_from_span(sub_span.unwrap());
+
+                Some(Data::DefData(Def {
+                    kind: DefKind::Const,
+                    id,
+                    span,
                     name: item.ident.to_string(),
-                    qualname: qualname,
-                    span: sub_span.unwrap(),
-                    scope: self.enclosing_scope(item.id),
+                    qualname,
+                    value: ty_to_string(typ),
                     parent: None,
-                    value: self.span_utils.snippet(expr.span),
-                    type_value: ty_to_string(&typ),
-                    visibility: From::from(&item.vis),
+                    children: vec![],
+                    decl_id: None,
                     docs: docs_for_attrs(&item.attrs),
                     sig: sig::item_signature(item, self),
-                    attributes: item.attrs.clone(),
+                    attributes: lower_attributes(item.attrs.clone(), self),
                 }))
             }
             ast::ItemKind::Mod(ref m) => {
@@ -249,18 +275,19 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                 let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Mod);
                 filter!(self.span_utils, sub_span, item.span, None);
 
-                Some(Data::ModData(ModData {
-                    id: item.id,
+                Some(Data::DefData(Def {
+                    kind: DefKind::Mod,
+                    id: id_from_node_id(item.id, self),
                     name: item.ident.to_string(),
-                    qualname: qualname,
-                    span: sub_span.unwrap(),
-                    scope: self.enclosing_scope(item.id),
-                    filename: filename,
-                    items: m.items.iter().map(|i| i.id).collect(),
-                    visibility: From::from(&item.vis),
+                    qualname,
+                    span: self.span_from_span(sub_span.unwrap()),
+                    value: filename,
+                    parent: None,
+                    children: m.items.iter().map(|i| id_from_node_id(i.id, self)).collect(),
+                    decl_id: None,
                     docs: docs_for_attrs(&item.attrs),
                     sig: sig::item_signature(item, self),
-                    attributes: item.attrs.clone(),
+                    attributes: lower_attributes(item.attrs.clone(), self),
                 }))
             }
             ast::ItemKind::Enum(ref def, _) => {
@@ -272,61 +299,47 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                                       .map(|v| v.node.name.to_string())
                                       .collect::<Vec<_>>()
                                       .join(", ");
-                let val = format!("{}::{{{}}}", name, variants_str);
-                Some(Data::EnumData(EnumData {
-                    id: item.id,
-                    name: name,
-                    value: val,
-                    span: sub_span.unwrap(),
-                    qualname: qualname,
-                    scope: self.enclosing_scope(item.id),
-                    variants: def.variants.iter().map(|v| v.node.data.id()).collect(),
-                    visibility: From::from(&item.vis),
+                let value = format!("{}::{{{}}}", name, variants_str);
+                Some(Data::DefData(Def {
+                    kind: DefKind::Enum,
+                    id: id_from_node_id(item.id, self),
+                    span: self.span_from_span(sub_span.unwrap()),
+                    name,
+                    qualname,
+                    value,
+                    parent: None,
+                    children: def.variants
+                                 .iter()
+                                 .map(|v| id_from_node_id(v.node.data.id(), self))
+                                 .collect(),
+                    decl_id: None,
                     docs: docs_for_attrs(&item.attrs),
                     sig: sig::item_signature(item, self),
-                    attributes: item.attrs.clone(),
+                    attributes: lower_attributes(item.attrs.to_owned(), self),
                 }))
             }
             ast::ItemKind::Impl(.., ref trait_ref, ref typ, _) => {
-                let mut type_data = None;
-                let sub_span;
-
-                let parent = self.enclosing_scope(item.id);
-
-                match typ.node {
+                if let ast::TyKind::Path(None, ref path) = typ.node {
                     // Common case impl for a struct or something basic.
-                    ast::TyKind::Path(None, ref path) => {
-                        if generated_code(path.span) {
-                            return None;
-                        }
-                        sub_span = self.span_utils.sub_span_for_type_name(path.span);
-                        type_data = self.lookup_ref_id(typ.id).map(|id| {
-                            TypeRefData {
-                                span: sub_span.unwrap(),
-                                scope: parent,
-                                ref_id: Some(id),
-                                qualname: String::new() // FIXME: generate the real qualname
-                            }
-                        });
-                    }
-                    _ => {
-                        // Less useful case, impl for a compound type.
-                        let span = typ.span;
-                        sub_span = self.span_utils.sub_span_for_type_name(span).or(Some(span));
+                    if generated_code(path.span) {
+                        return None;
                     }
+                    let sub_span = self.span_utils.sub_span_for_type_name(path.span);
+                    filter!(self.span_utils, sub_span, typ.span, None);
+
+                    let type_data = self.lookup_ref_id(typ.id);
+                    type_data.map(|type_data| Data::RelationData(Relation {
+                        kind: RelationKind::Impl,
+                        span: self.span_from_span(sub_span.unwrap()),
+                        from: id_from_def_id(type_data),
+                        to: trait_ref.as_ref()
+                                     .and_then(|t| self.lookup_ref_id(t.ref_id))
+                                     .map(id_from_def_id)
+                                     .unwrap_or(null_id()),
+                    }))
+                } else {
+                    None
                 }
-
-                let trait_data = trait_ref.as_ref()
-                                          .and_then(|tr| self.get_trait_ref_data(tr, parent));
-
-                filter!(self.span_utils, sub_span, typ.span, None);
-                Some(Data::ImplData(ImplData2 {
-                    id: item.id,
-                    span: sub_span.unwrap(),
-                    scope: parent,
-                    trait_ref: trait_data,
-                    self_ref: type_data,
-                }))
             }
             _ => {
                 // FIXME
@@ -338,7 +351,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
     pub fn get_field_data(&self,
                           field: &ast::StructField,
                           scope: NodeId)
-                          -> Option<VariableData> {
+                          -> Option<Def> {
         if let Some(ident) = field.ident {
             let name = ident.to_string();
             let qualname = format!("::{}::{}", self.tcx.node_path_str(scope), ident);
@@ -347,20 +360,23 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
             let def_id = self.tcx.hir.local_def_id(field.id);
             let typ = self.tcx.type_of(def_id).to_string();
 
-            Some(VariableData {
-                id: field.id,
-                kind: VariableKind::Field,
-                name: name,
-                qualname: qualname,
-                span: sub_span.unwrap(),
-                scope: scope,
-                parent: Some(make_def_id(scope, &self.tcx.hir)),
-                value: "".to_owned(),
-                type_value: typ,
-                visibility: From::from(&field.vis),
+
+            let id = id_from_node_id(field.id, self);
+            let span = self.span_from_span(sub_span.unwrap());
+
+            Some(Def {
+                kind: DefKind::Field,
+                id,
+                span,
+                name,
+                qualname,
+                value: typ,
+                parent: Some(id_from_node_id(scope, self)),
+                children: vec![],
+                decl_id: None,
                 docs: docs_for_attrs(&field.attrs),
                 sig: sig::field_signature(field, self),
-                attributes: field.attrs.clone(),
+                attributes: lower_attributes(field.attrs.clone(), self),
             })
         } else {
             None
@@ -373,10 +389,10 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                            id: ast::NodeId,
                            name: ast::Name,
                            span: Span)
-                           -> Option<FunctionData> {
+                           -> Option<Def> {
         // The qualname for a method is the trait name or name of the struct in an impl in
         // which the method is declared in, followed by the method's name.
-        let (qualname, parent_scope, decl_id, vis, docs, attributes) =
+        let (qualname, parent_scope, decl_id, docs, attributes) =
           match self.tcx.impl_of_method(self.tcx.hir.local_def_id(id)) {
             Some(impl_id) => match self.tcx.hir.get_if_local(impl_id) {
                 Some(Node::NodeItem(item)) => {
@@ -385,7 +401,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                             let mut result = String::from("<");
                             result.push_str(&self.tcx.hir.node_to_pretty_string(ty.id));
 
-                            let trait_id = self.tcx.trait_id_of_impl(impl_id);
+                            let mut trait_id = self.tcx.trait_id_of_impl(impl_id);
                             let mut decl_id = None;
                             if let Some(def_id) = trait_id {
                                 result.push_str(" as ");
@@ -393,11 +409,16 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                                 self.tcx.associated_items(def_id)
                                     .find(|item| item.name == name)
                                     .map(|item| decl_id = Some(item.def_id));
+                            } else {
+                                if let Some(NodeItem(item)) = self.tcx.hir.find(id) {
+                                    if let hir::ItemImpl(_, _, _, _, _, ref ty, _) = item.node {
+                                        trait_id = self.lookup_ref_id(ty.id);
+                                    }
+                                }
                             }
                             result.push_str(">");
 
                             (result, trait_id, decl_id,
-                             From::from(&item.vis),
                              docs_for_attrs(&item.attrs),
                              item.attrs.to_vec())
                         }
@@ -423,7 +444,6 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                         Some(Node::NodeItem(item)) => {
                             (format!("::{}", self.tcx.item_path_str(def_id)),
                              Some(def_id), None,
-                             From::from(&item.vis),
                              docs_for_attrs(&item.attrs),
                              item.attrs.to_vec())
                         }
@@ -451,27 +471,26 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
         let sub_span = self.span_utils.sub_span_after_keyword(span, keywords::Fn);
         filter!(self.span_utils, sub_span, span, None);
 
-        Some(FunctionData {
-            id: id,
+        Some(Def {
+            kind: DefKind::Method,
+            id: id_from_node_id(id, self),
+            span: self.span_from_span(sub_span.unwrap()),
             name: name.to_string(),
-            qualname: qualname,
-            declaration: decl_id,
-            span: sub_span.unwrap(),
-            scope: self.enclosing_scope(id),
+            qualname,
             // FIXME you get better data here by using the visitor.
             value: String::new(),
-            visibility: vis,
-            parent: parent_scope,
-            docs: docs,
+            parent: parent_scope.map(|id| id_from_def_id(id)),
+            children: vec![],
+            decl_id: decl_id.map(|id| id_from_def_id(id)),
+            docs,
             sig: None,
-            attributes: attributes,
+            attributes: lower_attributes(attributes, self),
         })
     }
 
     pub fn get_trait_ref_data(&self,
-                              trait_ref: &ast::TraitRef,
-                              parent: NodeId)
-                              -> Option<TypeRefData> {
+                              trait_ref: &ast::TraitRef)
+                              -> Option<Ref> {
         self.lookup_ref_id(trait_ref.ref_id).and_then(|def_id| {
             let span = trait_ref.path.span;
             if generated_code(span) {
@@ -479,11 +498,11 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
             }
             let sub_span = self.span_utils.sub_span_for_type_name(span).or(Some(span));
             filter!(self.span_utils, sub_span, span, None);
-            Some(TypeRefData {
-                span: sub_span.unwrap(),
-                scope: parent,
-                ref_id: Some(def_id),
-                qualname: String::new() // FIXME: generate the real qualname
+            let span = self.span_from_span(sub_span.unwrap());
+            Some(Ref {
+                kind: RefKind::Type,
+                span,
+                ref_id: id_from_def_id(def_id),
             })
         })
     }
@@ -509,11 +528,11 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                         let f = def.struct_variant().field_named(ident.node.name);
                         let sub_span = self.span_utils.span_for_last_ident(expr.span);
                         filter!(self.span_utils, sub_span, expr.span, None);
-                        return Some(Data::VariableRefData(VariableRefData {
-                            name: ident.node.to_string(),
-                            span: sub_span.unwrap(),
-                            scope: self.enclosing_scope(expr.id),
-                            ref_id: f.did,
+                        let span = self.span_from_span(sub_span.unwrap());
+                        return Some(Data::RefData(Ref {
+                            kind: RefKind::Variable,
+                            span,
+                            ref_id: id_from_def_id(f.did),
                         }));
                     }
                     _ => {
@@ -527,11 +546,11 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                     ty::TyAdt(def, _) if !def.is_enum() => {
                         let sub_span = self.span_utils.span_for_last_ident(path.span);
                         filter!(self.span_utils, sub_span, path.span, None);
-                        Some(Data::TypeRefData(TypeRefData {
-                            span: sub_span.unwrap(),
-                            scope: self.enclosing_scope(expr.id),
-                            ref_id: Some(def.did),
-                            qualname: String::new() // FIXME: generate the real qualname
+                        let span = self.span_from_span(sub_span.unwrap());
+                        Some(Data::RefData(Ref {
+                            kind: RefKind::Type,
+                            span,
+                            ref_id: id_from_def_id(def.did),
                         }))
                     }
                     _ => {
@@ -550,16 +569,15 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                 };
                 let sub_span = self.span_utils.sub_span_for_meth_name(expr.span);
                 filter!(self.span_utils, sub_span, expr.span, None);
-                let parent = self.enclosing_scope(expr.id);
-                Some(Data::MethodCallData(MethodCallData {
-                    span: sub_span.unwrap(),
-                    scope: parent,
-                    ref_id: def_id,
-                    decl_id: decl_id,
+                let span = self.span_from_span(sub_span.unwrap());
+                Some(Data::RefData(Ref {
+                    kind: RefKind::Function,
+                    span,
+                    ref_id: def_id.or(decl_id).map(|id| id_from_def_id(id)).unwrap_or(null_id()),
                 }))
             }
             ast::ExprKind::Path(_, ref path) => {
-                self.get_path_data(expr.id, path)
+                self.get_path_data(expr.id, path).map(|d| Data::RefData(d))
             }
             _ => {
                 // FIXME
@@ -568,7 +586,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
         }
     }
 
-    pub fn get_path_def(&self, id: NodeId) -> Def {
+    pub fn get_path_def(&self, id: NodeId) -> HirDef {
         match self.tcx.hir.get(id) {
             Node::NodeTraitRef(tr) => tr.path.def,
 
@@ -584,7 +602,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
             }
 
             Node::NodeLocal(&hir::Pat { node: hir::PatKind::Binding(_, def_id, ..), .. }) => {
-                Def::Local(def_id)
+                HirDef::Local(def_id)
             }
 
             Node::NodeTy(ty) => {
@@ -597,58 +615,58 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                                 for item in self.tcx.associated_items(proj.trait_ref.def_id) {
                                     if item.kind == ty::AssociatedKind::Type {
                                         if item.name == proj.item_name(self.tcx) {
-                                            return Def::AssociatedTy(item.def_id);
+                                            return HirDef::AssociatedTy(item.def_id);
                                         }
                                     }
                                 }
                             }
-                            Def::Err
+                            HirDef::Err
                         }
                     }
                 } else {
-                    Def::Err
+                    HirDef::Err
                 }
             }
 
-            _ => Def::Err
+            _ => HirDef::Err
         }
     }
 
-    pub fn get_path_data(&self, id: NodeId, path: &ast::Path) -> Option<Data> {
+    pub fn get_path_data(&self, id: NodeId, path: &ast::Path) -> Option<Ref> {
         let def = self.get_path_def(id);
         let sub_span = self.span_utils.span_for_last_ident(path.span);
         filter!(self.span_utils, sub_span, path.span, None);
         match def {
-            Def::Upvar(..) |
-            Def::Local(..) |
-            Def::Static(..) |
-            Def::Const(..) |
-            Def::AssociatedConst(..) |
-            Def::StructCtor(..) |
-            Def::VariantCtor(..) => {
-                Some(Data::VariableRefData(VariableRefData {
-                    name: self.span_utils.snippet(sub_span.unwrap()),
-                    span: sub_span.unwrap(),
-                    scope: self.enclosing_scope(id),
-                    ref_id: def.def_id(),
-                }))
+            HirDef::Upvar(..) |
+            HirDef::Local(..) |
+            HirDef::Static(..) |
+            HirDef::Const(..) |
+            HirDef::AssociatedConst(..) |
+            HirDef::StructCtor(..) |
+            HirDef::VariantCtor(..) => {
+                let span = self.span_from_span(sub_span.unwrap());
+                Some(Ref {
+                    kind: RefKind::Variable,
+                    span,
+                    ref_id: id_from_def_id(def.def_id()),
+                })
             }
-            Def::Struct(def_id) |
-            Def::Variant(def_id, ..) |
-            Def::Union(def_id) |
-            Def::Enum(def_id) |
-            Def::TyAlias(def_id) |
-            Def::AssociatedTy(def_id) |
-            Def::Trait(def_id) |
-            Def::TyParam(def_id) => {
-                Some(Data::TypeRefData(TypeRefData {
-                    span: sub_span.unwrap(),
-                    ref_id: Some(def_id),
-                    scope: self.enclosing_scope(id),
-                    qualname: String::new() // FIXME: generate the real qualname
-                }))
+            HirDef::Struct(def_id) |
+            HirDef::Variant(def_id, ..) |
+            HirDef::Union(def_id) |
+            HirDef::Enum(def_id) |
+            HirDef::TyAlias(def_id) |
+            HirDef::AssociatedTy(def_id) |
+            HirDef::Trait(def_id) |
+            HirDef::TyParam(def_id) => {
+                let span = self.span_from_span(sub_span.unwrap());
+                Some(Ref {
+                    kind: RefKind::Type,
+                    span,
+                    ref_id: id_from_def_id(def_id),
+                })
             }
-            Def::Method(decl_id) => {
+            HirDef::Method(decl_id) => {
                 let sub_span = self.span_utils.sub_span_for_meth_name(path.span);
                 filter!(self.span_utils, sub_span, path.span, None);
                 let def_id = if decl_id.is_local() {
@@ -659,60 +677,60 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                 } else {
                     None
                 };
-                Some(Data::MethodCallData(MethodCallData {
-                    span: sub_span.unwrap(),
-                    scope: self.enclosing_scope(id),
-                    ref_id: def_id,
-                    decl_id: Some(decl_id),
-                }))
+                let span = self.span_from_span(sub_span.unwrap());
+                Some(Ref {
+                    kind: RefKind::Function,
+                    span,
+                    ref_id: id_from_def_id(def_id.unwrap_or(decl_id)),
+                })
             }
-            Def::Fn(def_id) => {
-                Some(Data::FunctionCallData(FunctionCallData {
-                    ref_id: def_id,
-                    span: sub_span.unwrap(),
-                    scope: self.enclosing_scope(id),
-                }))
+            HirDef::Fn(def_id) => {
+                let span = self.span_from_span(sub_span.unwrap());
+                Some(Ref {
+                    kind: RefKind::Function,
+                    span,
+                    ref_id: id_from_def_id(def_id),
+                })
             }
-            Def::Mod(def_id) => {
-                Some(Data::ModRefData(ModRefData {
-                    ref_id: Some(def_id),
-                    span: sub_span.unwrap(),
-                    scope: self.enclosing_scope(id),
-                    qualname: String::new() // FIXME: generate the real qualname
-                }))
+            HirDef::Mod(def_id) => {
+                let span = self.span_from_span(sub_span.unwrap());
+                Some(Ref {
+                    kind: RefKind::Mod,
+                    span,
+                    ref_id: id_from_def_id(def_id),
+                })
             }
-            Def::PrimTy(..) |
-            Def::SelfTy(..) |
-            Def::Label(..) |
-            Def::Macro(..) |
-            Def::GlobalAsm(..) |
-            Def::Err => None,
+            HirDef::PrimTy(..) |
+            HirDef::SelfTy(..) |
+            HirDef::Label(..) |
+            HirDef::Macro(..) |
+            HirDef::GlobalAsm(..) |
+            HirDef::Err => None,
         }
     }
 
     pub fn get_field_ref_data(&self,
                               field_ref: &ast::Field,
-                              variant: &ty::VariantDef,
-                              parent: NodeId)
-                              -> Option<VariableRefData> {
+                              variant: &ty::VariantDef)
+                              -> Option<Ref> {
         let f = variant.field_named(field_ref.ident.node.name);
         // We don't really need a sub-span here, but no harm done
         let sub_span = self.span_utils.span_for_last_ident(field_ref.ident.span);
         filter!(self.span_utils, sub_span, field_ref.ident.span, None);
-        Some(VariableRefData {
-            name: field_ref.ident.node.to_string(),
-            span: sub_span.unwrap(),
-            scope: parent,
-            ref_id: f.did,
+        let span = self.span_from_span(sub_span.unwrap());
+        Some(Ref {
+            kind: RefKind::Variable,
+            span,
+            ref_id: id_from_def_id(f.did),
         })
     }
 
-    /// Attempt to return MacroUseData for any AST node.
+    /// Attempt to return MacroRef for any AST node.
     ///
     /// For a given piece of AST defined by the supplied Span and NodeId,
     /// returns None if the node is not macro-generated or the span is malformed,
-    /// else uses the expansion callsite and callee to return some MacroUseData.
-    pub fn get_macro_use_data(&self, span: Span, id: NodeId) -> Option<MacroUseData> {
+    /// else uses the expansion callsite and callee to return some MacroRef.
+    pub fn get_macro_use_data(&self, span: Span) -> Option<MacroRef> {
         if !generated_code(span) {
             return None;
         }
@@ -720,6 +738,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
         // nested expansions and ensure we only generate data for source-visible
         // macro uses.
         let callsite = span.source_callsite();
+        let callsite_span = self.span_from_span(callsite);
         let callee = option_try!(span.source_callee());
         let callee_span = option_try!(callee.span);
 
@@ -733,34 +752,25 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
         // when read in, and no longer correspond to the source.
         if let Some(mac) = self.tcx.sess.imported_macro_spans.borrow().get(&callee_span) {
             let &(ref mac_name, mac_span) = mac;
-            return Some(MacroUseData {
-                                        span: callsite,
-                                        name: mac_name.clone(),
-                                        callee_span: mac_span,
-                                        scope: self.enclosing_scope(id),
-                                        imported: true,
-                                        qualname: String::new()// FIXME: generate the real qualname
-                                    });
+            let mac_span = self.span_from_span(mac_span);
+            return Some(MacroRef {
+                span: callsite_span,
+                qualname: mac_name.clone(), // FIXME: generate the real qualname
+                callee_span: mac_span,
+            });
         }
 
-        Some(MacroUseData {
-            span: callsite,
-            name: callee.name().to_string(),
-            callee_span: callee_span,
-            scope: self.enclosing_scope(id),
-            imported: false,
-            qualname: String::new() // FIXME: generate the real qualname
+        let callee_span = self.span_from_span(callee_span);
+        Some(MacroRef {
+            span: callsite_span,
+            qualname: callee.name().to_string(), // FIXME: generate the real qualname
+            callee_span,
         })
     }
 
-    pub fn get_data_for_id(&self, _id: &NodeId) -> Data {
-        // FIXME
-        bug!();
-    }
-
     fn lookup_ref_id(&self, ref_id: NodeId) -> Option<DefId> {
         match self.get_path_def(ref_id) {
-            Def::PrimTy(_) | Def::SelfTy(..) | Def::Err => None,
+            HirDef::PrimTy(_) | HirDef::SelfTy(..) | HirDef::Err => None,
             def => Some(def.def_id()),
         }
     }
@@ -802,7 +812,7 @@ fn make_signature(decl: &ast::FnDecl, generics: &ast::Generics) -> String {
 // An AST visitor for collecting paths from patterns.
 struct PathCollector {
     // The Row field identifies the kind of pattern.
-    collected_paths: Vec<(NodeId, ast::Path, ast::Mutability, recorder::Row)>,
+    collected_paths: Vec<(NodeId, ast::Path, ast::Mutability)>,
 }
 
 impl PathCollector {
@@ -816,12 +826,12 @@ impl<'a> Visitor<'a> for PathCollector {
         match p.node {
             PatKind::Struct(ref path, ..) => {
                 self.collected_paths.push((p.id, path.clone(),
-                                           ast::Mutability::Mutable, recorder::TypeRef));
+                                           ast::Mutability::Mutable));
             }
             PatKind::TupleStruct(ref path, ..) |
             PatKind::Path(_, ref path) => {
                 self.collected_paths.push((p.id, path.clone(),
-                                           ast::Mutability::Mutable, recorder::VarRef));
+                                           ast::Mutability::Mutable));
             }
             PatKind::Ident(bm, ref path1, _) => {
                 debug!("PathCollector, visit ident in pat {}: {:?} {:?}",
@@ -837,7 +847,7 @@ impl<'a> Visitor<'a> for PathCollector {
                 };
                 // collect path for either visit_local or visit_arm
                 let path = ast::Path::from_ident(path1.span, path1.node);
-                self.collected_paths.push((p.id, path, immut, recorder::VarRef));
+                self.collected_paths.push((p.id, path, immut));
             }
             _ => {}
         }
@@ -866,17 +876,13 @@ fn docs_for_attrs(attrs: &[Attribute]) -> String {
 
 #[derive(Clone, Copy, Debug, RustcEncodable)]
 pub enum Format {
-    Csv,
     Json,
     JsonApi,
 }
 
 impl Format {
     fn extension(&self) -> &'static str {
-        match *self {
-            Format::Csv => ".csv",
-            Format::Json | Format::JsonApi => ".json",
-        }
+        ".json"
     }
 }
 
@@ -959,7 +965,6 @@ impl<'a> SaveHandler for DumpHandler<'a> {
         let output = &mut self.output_file(&save_ctxt.tcx.sess);
 
         match self.format {
-            Format::Csv => dump!(CsvDumper::new(output)),
             Format::Json => dump!(JsonDumper::new(output)),
             Format::JsonApi => dump!(JsonApiDumper::new(output)),
         }
@@ -1039,6 +1044,34 @@ fn id_from_def_id(id: DefId) -> rls_data::Id {
 }
 
 fn id_from_node_id(id: NodeId, scx: &SaveContext) -> rls_data::Id {
-    let def_id = scx.tcx.hir.local_def_id(id);
-    id_from_def_id(def_id)
+    let def_id = scx.tcx.hir.opt_local_def_id(id);
+    def_id.map(|id| id_from_def_id(id)).unwrap_or_else(null_id)
+}
+
+fn null_id() -> rls_data::Id {
+    rls_data::Id {
+        krate: u32::max_value(),
+        index: u32::max_value(),
+    }
+}
+
+fn lower_attributes(attrs: Vec<Attribute>, scx: &SaveContext) -> Vec<rls_data::Attribute> {
+    attrs.into_iter()
+    // Only retain real attributes. Doc comments are lowered separately.
+    .filter(|attr| attr.path != "doc")
+    .map(|mut attr| {
+        // Remove the surrounding '#[..]' or '#![..]' of the pretty printed
+        // attribute. First normalize all inner attribute (#![..]) to outer
+        // ones (#[..]), then remove the two leading and the one trailing character.
+        attr.style = ast::AttrStyle::Outer;
+        let value = pprust::attribute_to_string(&attr);
+        // This str slicing works correctly, because the leading and trailing characters
+        // are in the ASCII range and thus exactly one byte each.
+        let value = value[2..value.len()-1].to_string();
+
+        rls_data::Attribute {
+            value: value,
+            span: scx.span_from_span(attr.span),
+        }
+    }).collect()
 }
diff --git a/src/librustc_save_analysis/span_utils.rs b/src/librustc_save_analysis/span_utils.rs
index af3efb48090..77cde33e962 100644
--- a/src/librustc_save_analysis/span_utils.rs
+++ b/src/librustc_save_analysis/span_utils.rs
@@ -20,7 +20,6 @@ use syntax::ast;
 use syntax::parse::lexer::{self, StringReader};
 use syntax::parse::token::{self, Token};
 use syntax::symbol::keywords;
-use syntax::tokenstream::TokenTree;
 use syntax_pos::*;
 
 #[derive(Clone)]
@@ -277,45 +276,6 @@ impl<'a> SpanUtils<'a> {
         }
     }
 
-    /// `span` must be the span for an item such as a function or struct. This
-    /// function returns the program text from the start of the span until the
-    /// end of the 'signature' part, that is up to, but not including an opening
-    /// brace or semicolon.
-    pub fn signature_string_for_span(&self, span: Span) -> String {
-        let mut toks = self.retokenise_span(span);
-        toks.real_token();
-        let mut toks = toks.parse_all_token_trees().unwrap().trees();
-        let mut prev = toks.next().unwrap();
-
-        let first_span = prev.span();
-        let mut angle_count = 0;
-        for tok in toks {
-            if let TokenTree::Token(_, ref tok) = prev {
-                angle_count += match *tok {
-                    token::Eof => { break; }
-                    token::Lt => 1,
-                    token::Gt => -1,
-                    token::BinOp(token::Shl) => 2,
-                    token::BinOp(token::Shr) => -2,
-                    _ => 0,
-                };
-            }
-            if angle_count > 0 {
-                prev = tok;
-                continue;
-            }
-            if let TokenTree::Token(_, token::Semi) = tok {
-                return self.snippet(first_span.to(prev.span()));
-            } else if let TokenTree::Delimited(_, ref d) = tok {
-                if d.delim == token::Brace {
-                    return self.snippet(first_span.to(prev.span()));
-                }
-            }
-            prev = tok;
-        }
-        self.snippet(span)
-    }
-
     pub fn sub_span_before_token(&self, span: Span, tok: Token) -> Option<Span> {
         let mut toks = self.retokenise_span(span);
         let mut prev = toks.real_token();
@@ -385,57 +345,44 @@ impl<'a> SpanUtils<'a> {
         self.spans_with_brackets(span, 1, number)
     }
 
-    pub fn report_span_err(&self, kind: &str, span: Span) {
-        let loc = self.sess.codemap().lookup_char_pos(span.lo);
-        info!("({}) Could not find sub_span in `{}` in {}, line {}",
-              kind,
-              self.snippet(span),
-              loc.file.name,
-              loc.line);
-        self.err_count.set(self.err_count.get() + 1);
-        if self.err_count.get() > 1000 {
-            bug!("span errors reached 1000, giving up");
-        }
-    }
-
-    // Return the name for a macro definition (identifier after first `!`)
-    pub fn span_for_macro_def_name(&self, span: Span) -> Option<Span> {
-        let mut toks = self.retokenise_span(span);
-        loop {
-            let ts = toks.real_token();
-            if ts.tok == token::Eof {
-                return None;
-            }
-            if ts.tok == token::Not {
-                let ts = toks.real_token();
-                if ts.tok.is_ident() {
-                    return Some(ts.sp);
-                } else {
-                    return None;
-                }
-            }
-        }
-    }
-
-    // Return the name for a macro use (identifier before first `!`).
-    pub fn span_for_macro_use_name(&self, span:Span) -> Option<Span> {
-        let mut toks = self.retokenise_span(span);
-        let mut prev = toks.real_token();
-        loop {
-            if prev.tok == token::Eof {
-                return None;
-            }
-            let ts = toks.real_token();
-            if ts.tok == token::Not {
-                if prev.tok.is_ident() {
-                    return Some(prev.sp);
-                } else {
-                    return None;
-                }
-            }
-            prev = ts;
-        }
-    }
+    // // Return the name for a macro definition (identifier after first `!`)
+    // pub fn span_for_macro_def_name(&self, span: Span) -> Option<Span> {
+    //     let mut toks = self.retokenise_span(span);
+    //     loop {
+    //         let ts = toks.real_token();
+    //         if ts.tok == token::Eof {
+    //             return None;
+    //         }
+    //         if ts.tok == token::Not {
+    //             let ts = toks.real_token();
+    //             if ts.tok.is_ident() {
+    //                 return Some(ts.sp);
+    //             } else {
+    //                 return None;
+    //             }
+    //         }
+    //     }
+    // }
+
+    // // Return the name for a macro use (identifier before first `!`).
+    // pub fn span_for_macro_use_name(&self, span:Span) -> Option<Span> {
+    //     let mut toks = self.retokenise_span(span);
+    //     let mut prev = toks.real_token();
+    //     loop {
+    //         if prev.tok == token::Eof {
+    //             return None;
+    //         }
+    //         let ts = toks.real_token();
+    //         if ts.tok == token::Not {
+    //             if prev.tok.is_ident() {
+    //                 return Some(prev.sp);
+    //             } else {
+    //                 return None;
+    //             }
+    //         }
+    //         prev = ts;
+    //     }
+    // }
 
     /// Return true if the span is generated code, and
     /// it is not a subspan of the root callsite.
diff --git a/src/test/run-make/save-analysis/Makefile b/src/test/run-make/save-analysis/Makefile
index 3711b6ea895..9ebc40d4013 100644
--- a/src/test/run-make/save-analysis/Makefile
+++ b/src/test/run-make/save-analysis/Makefile
@@ -3,6 +3,5 @@ all: code
 krate2: krate2.rs
 	$(RUSTC) $<
 code: foo.rs krate2
-	$(RUSTC) foo.rs -Zsave-analysis-csv
 	$(RUSTC) foo.rs -Zsave-analysis
 	$(RUSTC) foo.rs -Zsave-analysis-api