about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2016-05-14 09:36:52 -0700
committerbors <bors@rust-lang.org>2016-05-14 09:36:52 -0700
commit5029a60d8353def48e8d4a020236e7e35a9f07f6 (patch)
treebcea115af83e18a18b1379e1d4d359a0abcd380f /src
parent5f6eb14b28eab9824492f9f82f5f25ad56dda30a (diff)
parent6d6986b87a23ca3fcc62636808ce625fc228bcc0 (diff)
downloadrust-5029a60d8353def48e8d4a020236e7e35a9f07f6.tar.gz
rust-5029a60d8353def48e8d4a020236e7e35a9f07f6.zip
Auto merge of #33568 - nrc:save-json-2, r=pnkfelix
save-analysis: JSON mk2

cc @aochagavia

r? @pnkfelix
Diffstat (limited to 'src')
-rw-r--r--src/librustc_save_analysis/csv_dumper.rs2
-rw-r--r--src/librustc_save_analysis/data.rs12
-rw-r--r--src/librustc_save_analysis/dump.rs2
-rw-r--r--src/librustc_save_analysis/dump_visitor.rs92
-rw-r--r--src/librustc_save_analysis/external_data.rs28
-rw-r--r--src/librustc_save_analysis/json_dumper.rs426
-rw-r--r--src/librustc_save_analysis/lib.rs52
-rw-r--r--src/libsyntax/ast.rs5
8 files changed, 536 insertions, 83 deletions
diff --git a/src/librustc_save_analysis/csv_dumper.rs b/src/librustc_save_analysis/csv_dumper.rs
index ac658af4006..e7cc534c5b5 100644
--- a/src/librustc_save_analysis/csv_dumper.rs
+++ b/src/librustc_save_analysis/csv_dumper.rs
@@ -331,7 +331,7 @@ impl<'b, W: Write + 'b> Dump for CsvDumper<'b, W> {
         self.record("type_ref", data.span, values);
     }
 
-    fn typedef(&mut self, data: TypedefData) {
+    fn typedef(&mut self, data: TypeDefData) {
         let id = data.id.index.as_u32().to_string();
         let values = make_values_str(&[
             ("id", &id),
diff --git a/src/librustc_save_analysis/data.rs b/src/librustc_save_analysis/data.rs
index 19f9ba95b35..2275a1c5c65 100644
--- a/src/librustc_save_analysis/data.rs
+++ b/src/librustc_save_analysis/data.rs
@@ -62,7 +62,7 @@ pub enum Data {
     /// Data for a tuple variant.
     TupleVariantData(TupleVariantData),
     /// Data for a typedef.
-    TypeDefData(TypedefData),
+    TypeDefData(TypeDefData),
     /// Data for a reference to a type or trait.
     TypeRefData(TypeRefData),
     /// Data for a use statement.
@@ -97,6 +97,7 @@ pub struct ExternalCrateData {
 #[derive(Clone, Debug, RustcEncodable)]
 pub struct EnumData {
     pub id: NodeId,
+    pub name: String,
     pub value: String,
     pub qualname: String,
     pub span: Span,
@@ -131,6 +132,7 @@ pub struct FunctionData {
     pub declaration: Option<DefId>,
     pub span: Span,
     pub scope: NodeId,
+    pub value: String,
 }
 
 /// Data about a function call.
@@ -205,9 +207,11 @@ pub struct MethodCallData {
 #[derive(Clone, Debug, RustcEncodable)]
 pub struct MethodData {
     pub id: NodeId,
+    pub name: String,
     pub qualname: String,
     pub span: Span,
     pub scope: NodeId,
+    pub value: String,
 }
 
 /// Data for modules.
@@ -233,6 +237,7 @@ pub struct ModRefData {
 #[derive(Debug, RustcEncodable)]
 pub struct StructData {
     pub span: Span,
+    pub name: String,
     pub id: NodeId,
     pub ctor_id: NodeId,
     pub qualname: String,
@@ -243,6 +248,7 @@ pub struct StructData {
 #[derive(Debug, RustcEncodable)]
 pub struct StructVariantData {
     pub span: Span,
+    pub name: String,
     pub id: NodeId,
     pub qualname: String,
     pub type_value: String,
@@ -254,6 +260,7 @@ pub struct StructVariantData {
 pub struct TraitData {
     pub span: Span,
     pub id: NodeId,
+    pub name: String,
     pub qualname: String,
     pub scope: NodeId,
     pub value: String
@@ -272,8 +279,9 @@ pub struct TupleVariantData {
 
 /// Data for a typedef.
 #[derive(Debug, RustcEncodable)]
-pub struct TypedefData {
+pub struct TypeDefData {
     pub id: NodeId,
+    pub name: String,
     pub span: Span,
     pub qualname: String,
     pub value: String,
diff --git a/src/librustc_save_analysis/dump.rs b/src/librustc_save_analysis/dump.rs
index adbf1e0a35e..18241b394cc 100644
--- a/src/librustc_save_analysis/dump.rs
+++ b/src/librustc_save_analysis/dump.rs
@@ -30,7 +30,7 @@ pub trait Dump {
     fn trait_data(&mut self, TraitData) {}
     fn tuple_variant(&mut self, TupleVariantData) {}
     fn type_ref(&mut self, TypeRefData) {}
-    fn typedef(&mut self, TypedefData) {}
+    fn typedef(&mut self, TypeDefData) {}
     fn use_data(&mut self, UseData) {}
     fn use_glob(&mut self, UseGlobData) {}
     fn variable(&mut self, VariableData) {}
diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs
index f0dd7b8b9bb..4d79ddfe8cb 100644
--- a/src/librustc_save_analysis/dump_visitor.rs
+++ b/src/librustc_save_analysis/dump_visitor.rs
@@ -39,7 +39,7 @@ use syntax::ast::{self, NodeId, PatKind};
 use syntax::codemap::*;
 use syntax::parse::token::{self, keywords};
 use syntax::visit::{self, Visitor};
-use syntax::print::pprust::{path_to_string, ty_to_string};
+use syntax::print::pprust::{path_to_string, ty_to_string, bounds_to_string, generics_to_string};
 use syntax::ptr::P;
 
 use super::{escape, generated_code, SaveContext, PathCollector};
@@ -388,18 +388,23 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
 
         if let Some(method_data) = self.save_ctxt.get_method_data(id, name, span) {
 
+            let sig_str = ::make_signature(&sig.decl, &sig.generics);
             if body.is_some() {
                 if !self.span.filter_generated(Some(method_data.span), span) {
-                    self.dumper.function(method_data.clone().lower(self.tcx));
+                    let mut data = method_data.clone();
+                    data.value = sig_str;
+                    self.dumper.function(data.lower(self.tcx));
                 }
                 self.process_formals(&sig.decl.inputs, &method_data.qualname);
             } else {
                 if !self.span.filter_generated(Some(method_data.span), span) {
                     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,
                     }.lower(self.tcx));
                 }
             }
@@ -455,16 +460,18 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
         let param_sub_spans = self.span.spans_for_ty_params(full_span,
                                                             (generics.ty_params.len() as isize));
         for (param, param_ss) in generics.ty_params.iter().zip(param_sub_spans) {
+            let name = escape(self.span.snippet(param_ss));
             // Append $id to name to make sure each one is unique
-            let name = format!("{}::{}${}",
-                               prefix,
-                               escape(self.span.snippet(param_ss)),
-                               id);
+            let qualname = format!("{}::{}${}",
+                                   prefix,
+                                   name,
+                                   id);
             if !self.span.filter_generated(Some(param_ss), full_span) {
-                self.dumper.typedef(TypedefData {
+                self.dumper.typedef(TypeDefData {
                     span: param_ss,
+                    name: name,
                     id: param.id,
-                    qualname: name,
+                    qualname: qualname,
                     value: String::new()
                 }.lower(self.tcx));
             }
@@ -536,18 +543,33 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
         self.visit_expr(expr);
     }
 
+    // FIXME tuple structs should generate tuple-specific data.
     fn process_struct(&mut self,
                       item: &ast::Item,
                       def: &ast::VariantData,
                       ty_params: &ast::Generics) {
+        let name = item.ident.to_string();
         let qualname = format!("::{}", self.tcx.node_path_str(item.id));
 
-        let val = self.span.snippet(item.span);
         let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Struct);
+        let val = if let ast::ItemKind::Struct(ast::VariantData::Struct(ref fields, _), _) =
+                    item.node {
+            let fields_str = fields.iter()
+                                   .enumerate()
+                                   .map(|(i, f)| f.ident.map(|i| i.to_string())
+                                                  .unwrap_or(i.to_string()))
+                                   .collect::<Vec<_>>()
+                                   .join(", ");
+            format!("{} {{ {} }}", name, fields_str)
+        } else {
+            String::new()
+        };
+
         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(),
                 qualname: qualname.clone(),
                 scope: self.cur_scope,
@@ -580,19 +602,26 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
         }
 
         for variant in &enum_definition.variants {
-            let name = &variant.node.name.name.as_str();
+            let name = variant.node.name.name.to_string();
             let mut qualname = enum_data.qualname.clone();
             qualname.push_str("::");
-            qualname.push_str(name);
-            let val = self.span.snippet(variant.span);
+            qualname.push_str(&name);
 
             match variant.node.data {
-                ast::VariantData::Struct(..) => {
+                ast::VariantData::Struct(ref fields, _) => {
                     let sub_span = self.span.span_for_first_ident(variant.span);
+                    let fields_str = fields.iter()
+                                           .enumerate()
+                                           .map(|(i, f)| f.ident.map(|i| i.to_string())
+                                                          .unwrap_or(i.to_string()))
+                                           .collect::<Vec<_>>()
+                                           .join(", ");
+                    let val = 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,
@@ -600,13 +629,22 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                         }.lower(self.tcx));
                     }
                 }
-                _ => {
+                ref v => {
                     let sub_span = self.span.span_for_first_ident(variant.span);
+                    let mut val = 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(')');
+                    }
                     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.to_string(),
+                            name: name,
                             qualname: qualname,
                             type_value: enum_data.qualname.clone(),
                             value: val,
@@ -672,13 +710,22 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                      generics: &ast::Generics,
                      trait_refs: &ast::TyParamBounds,
                      methods: &[ast::TraitItem]) {
+        let name = item.ident.to_string();
         let qualname = format!("::{}", self.tcx.node_path_str(item.id));
-        let val = self.span.snippet(item.span);
+        let mut val = name.clone();
+        if !generics.lifetimes.is_empty() || !generics.ty_params.is_empty() {
+            val.push_str(&generics_to_string(generics));
+        }
+        if !trait_refs.is_empty() {
+            val.push_str(": ");
+            val.push_str(&bounds_to_string(trait_refs));
+        }
         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,
                 qualname: qualname.clone(),
                 scope: self.cur_scope,
                 value: val
@@ -908,13 +955,15 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
         self.visit_pat(&p);
 
         for &(id, ref p, immut, _) in &collector.collected_paths {
-            let value = if immut == ast::Mutability::Immutable {
+            let mut value = if immut == ast::Mutability::Immutable {
                 value.to_string()
             } else {
                 "<mutable>".to_string()
             };
             let types = self.tcx.node_types();
             let typ = types.get(&id).map(|t| t.to_string()).unwrap_or(String::new());
+            value.push_str(": ");
+            value.push_str(&typ);
             // Get the span only for the name of the variable (I hope the path
             // is only ever a variable name, but who knows?).
             let sub_span = self.span.span_for_last_ident(p.span);
@@ -1107,8 +1156,9 @@ impl<'v, 'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'v> for DumpVisitor<'l, 'tcx,
                 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 {
+                    self.dumper.typedef(TypeDefData {
                         span: sub_span.expect("No span found for typedef"),
+                        name: item.ident.to_string(),
                         id: item.id,
                         qualname: qualname.clone(),
                         value: value
@@ -1275,13 +1325,13 @@ impl<'v, 'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'v> for DumpVisitor<'l, 'tcx,
             }
             ast::ExprKind::ForLoop(ref pattern, ref subexpression, ref block, _) |
             ast::ExprKind::WhileLet(ref pattern, ref subexpression, ref block, _) => {
-                let value = self.span.snippet(mk_sp(ex.span.lo, subexpression.span.hi));
+                let value = self.span.snippet(subexpression.span);
                 self.process_var_decl(pattern, value);
                 visit::walk_expr(self, subexpression);
                 visit::walk_block(self, block);
             }
             ast::ExprKind::IfLet(ref pattern, ref subexpression, ref block, ref opt_else) => {
-                let value = self.span.snippet(mk_sp(ex.span.lo, subexpression.span.hi));
+                let value = self.span.snippet(subexpression.span);
                 self.process_var_decl(pattern, value);
                 visit::walk_expr(self, subexpression);
                 visit::walk_block(self, block);
@@ -1371,7 +1421,7 @@ impl<'v, 'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'v> for DumpVisitor<'l, 'tcx,
 
     fn visit_local(&mut self, l: &ast::Local) {
         self.process_macro_use(l.span, l.id);
-        let value = self.span.snippet(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);
 
         // Just walk the initialiser and type (don't want to walk the pattern again).
diff --git a/src/librustc_save_analysis/external_data.rs b/src/librustc_save_analysis/external_data.rs
index 51134f8383b..dc51c41f296 100644
--- a/src/librustc_save_analysis/external_data.rs
+++ b/src/librustc_save_analysis/external_data.rs
@@ -86,6 +86,7 @@ impl Lower for data::CratePreludeData {
 pub struct EnumData {
     pub id: DefId,
     pub value: String,
+    pub name: String,
     pub qualname: String,
     pub span: SpanData,
     pub scope: DefId,
@@ -97,6 +98,7 @@ impl Lower for data::EnumData {
     fn lower(self, tcx: TyCtxt) -> EnumData {
         EnumData {
             id: make_def_id(self.id, &tcx.map),
+            name: self.name,
             value: self.value,
             qualname: self.qualname,
             span: SpanData::from_span(self.span, tcx.sess.codemap()),
@@ -160,6 +162,7 @@ pub struct FunctionData {
     pub declaration: Option<DefId>,
     pub span: SpanData,
     pub scope: DefId,
+    pub value: String,
 }
 
 impl Lower for data::FunctionData {
@@ -173,6 +176,7 @@ impl Lower for data::FunctionData {
             declaration: self.declaration,
             span: SpanData::from_span(self.span, tcx.sess.codemap()),
             scope: make_def_id(self.scope, &tcx.map),
+            value: self.value,
         }
     }
 }
@@ -268,7 +272,6 @@ pub struct MacroUseData {
     // we use the callee span to reference the associated macro definition.
     pub callee_span: SpanData,
     pub scope: DefId,
-    pub imported: bool,
 }
 
 impl Lower for data::MacroUseData {
@@ -281,7 +284,6 @@ impl Lower for data::MacroUseData {
             qualname: self.qualname,
             callee_span: SpanData::from_span(self.callee_span, tcx.sess.codemap()),
             scope: make_def_id(self.scope, &tcx.map),
-            imported: self.imported,
         }
     }
 }
@@ -312,9 +314,11 @@ impl Lower for data::MethodCallData {
 #[derive(Clone, Debug, RustcEncodable)]
 pub struct MethodData {
     pub id: DefId,
+    pub name: String,
     pub qualname: String,
     pub span: SpanData,
     pub scope: DefId,
+    pub value: String,
 }
 
 impl Lower for data::MethodData {
@@ -323,9 +327,11 @@ impl Lower for data::MethodData {
     fn lower(self, tcx: TyCtxt) -> MethodData {
         MethodData {
             span: SpanData::from_span(self.span, tcx.sess.codemap()),
+            name: self.name,
             scope: make_def_id(self.scope, &tcx.map),
             id: make_def_id(self.id, &tcx.map),
             qualname: self.qualname,
+            value: self.value,
         }
     }
 }
@@ -381,6 +387,7 @@ impl Lower for data::ModRefData {
 #[derive(Debug, RustcEncodable)]
 pub struct StructData {
     pub span: SpanData,
+    pub name: String,
     pub id: DefId,
     pub ctor_id: DefId,
     pub qualname: String,
@@ -394,6 +401,7 @@ impl Lower for data::StructData {
     fn lower(self, tcx: TyCtxt) -> StructData {
         StructData {
             span: SpanData::from_span(self.span, tcx.sess.codemap()),
+            name: self.name,
             id: make_def_id(self.id, &tcx.map),
             ctor_id: make_def_id(self.ctor_id, &tcx.map),
             qualname: self.qualname,
@@ -406,6 +414,7 @@ impl Lower for data::StructData {
 #[derive(Debug, RustcEncodable)]
 pub struct StructVariantData {
     pub span: SpanData,
+    pub name: String,
     pub id: DefId,
     pub qualname: String,
     pub type_value: String,
@@ -419,6 +428,7 @@ impl Lower for data::StructVariantData {
     fn lower(self, tcx: TyCtxt) -> StructVariantData {
         StructVariantData {
             span: SpanData::from_span(self.span, tcx.sess.codemap()),
+            name: self.name,
             id: make_def_id(self.id, &tcx.map),
             qualname: self.qualname,
             type_value: self.type_value,
@@ -431,6 +441,7 @@ impl Lower for data::StructVariantData {
 #[derive(Debug, RustcEncodable)]
 pub struct TraitData {
     pub span: SpanData,
+    pub name: String,
     pub id: DefId,
     pub qualname: String,
     pub scope: DefId,
@@ -443,6 +454,7 @@ impl Lower for data::TraitData {
     fn lower(self, tcx: TyCtxt) -> TraitData {
         TraitData {
             span: SpanData::from_span(self.span, tcx.sess.codemap()),
+            name: self.name,
             id: make_def_id(self.id, &tcx.map),
             qualname: self.qualname,
             scope: make_def_id(self.scope, &tcx.map),
@@ -480,19 +492,21 @@ impl Lower for data::TupleVariantData {
 
 /// Data for a typedef.
 #[derive(Debug, RustcEncodable)]
-pub struct TypedefData {
+pub struct TypeDefData {
     pub id: DefId,
+    pub name: String,
     pub span: SpanData,
     pub qualname: String,
     pub value: String,
 }
 
-impl Lower for data::TypedefData {
-    type Target = TypedefData;
+impl Lower for data::TypeDefData {
+    type Target = TypeDefData;
 
-    fn lower(self, tcx: TyCtxt) -> TypedefData {
-        TypedefData {
+    fn lower(self, tcx: TyCtxt) -> TypeDefData {
+        TypeDefData {
             id: make_def_id(self.id, &tcx.map),
+            name: self.name,
             span: SpanData::from_span(self.span, tcx.sess.codemap()),
             qualname: self.qualname,
             value: self.value,
diff --git a/src/librustc_save_analysis/json_dumper.rs b/src/librustc_save_analysis/json_dumper.rs
index 9ad2bcef4ed..610a9ac2ad6 100644
--- a/src/librustc_save_analysis/json_dumper.rs
+++ b/src/librustc_save_analysis/json_dumper.rs
@@ -10,6 +10,7 @@
 
 use std::io::Write;
 
+use rustc::hir::def_id::DefId;
 use rustc_serialize::json::as_json;
 
 use super::external_data::*;
@@ -17,66 +18,409 @@ use super::dump::Dump;
 
 pub struct JsonDumper<'b, W: Write + 'b> {
     output: &'b mut W,
-    first: bool,
+    result: Analysis,
 }
 
 impl<'b, W: Write> JsonDumper<'b, W> {
     pub fn new(writer: &'b mut W) -> JsonDumper<'b, W> {
-        if let Err(_) = write!(writer, "[") {
-            error!("Error writing output");
-        }
-        JsonDumper { output: writer, first: true }
+        JsonDumper { output: writer, result: Analysis::new() }
     }
 }
 
 impl<'b, W: Write> Drop for JsonDumper<'b, W> {
     fn drop(&mut self) {
-        if let Err(_) = write!(self.output, "]") {
+        if let Err(_) = write!(self.output, "{}", as_json(&self.result)) {
             error!("Error writing output");
         }
     }
 }
 
 macro_rules! impl_fn {
-    ($fn_name: ident, $data_type: ident) => {
+    ($fn_name: ident, $data_type: ident, $bucket: ident) => {
         fn $fn_name(&mut self, data: $data_type) {
-            if self.first {
-                self.first = false;
-            } else {
-                if let Err(_) = write!(self.output, ",") {
-                    error!("Error writing output");
-                }
-            }
-            if let Err(_) = write!(self.output, "{}", as_json(&data)) {
-                error!("Error writing output '{}'", as_json(&data));
-            }
+            self.result.$bucket.push(From::from(data));
         }
     }
 }
 
 impl<'b, W: Write + 'b> Dump for JsonDumper<'b, W> {
-    impl_fn!(crate_prelude, CratePreludeData);
-    impl_fn!(enum_data, EnumData);
-    impl_fn!(extern_crate, ExternCrateData);
-    impl_fn!(impl_data, ImplData);
-    impl_fn!(inheritance, InheritanceData);
-    impl_fn!(function, FunctionData);
-    impl_fn!(function_ref, FunctionRefData);
-    impl_fn!(function_call, FunctionCallData);
-    impl_fn!(method, MethodData);
-    impl_fn!(method_call, MethodCallData);
-    impl_fn!(macro_data, MacroData);
-    impl_fn!(macro_use, MacroUseData);
-    impl_fn!(mod_data, ModData);
-    impl_fn!(mod_ref, ModRefData);
-    impl_fn!(struct_data, StructData);
-    impl_fn!(struct_variant, StructVariantData);
-    impl_fn!(trait_data, TraitData);
-    impl_fn!(tuple_variant, TupleVariantData);
-    impl_fn!(type_ref, TypeRefData);
-    impl_fn!(typedef, TypedefData);
-    impl_fn!(use_data, UseData);
-    impl_fn!(use_glob, UseGlobData);
-    impl_fn!(variable, VariableData);
-    impl_fn!(variable_ref, VariableRefData);
+    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!(mod_data, ModData, 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);
+
+    impl_fn!(macro_use, MacroUseData, macro_refs);
+
+    // FIXME store this instead of throwing it away.
+    fn impl_data(&mut self, _data: ImplData) {}
+    fn inheritance(&mut self, _data: InheritanceData) {}
+}
+
+// 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.
+
+#[derive(Debug, RustcEncodable)]
+struct Analysis {
+    prelude: Option<CratePreludeData>,
+    imports: Vec<Import>,
+    defs: Vec<Def>,
+    refs: Vec<Ref>,
+    macro_refs: Vec<MacroRef>,
+}
+
+impl Analysis {
+    fn new() -> Analysis {
+        Analysis {
+            prelude: None,
+            imports: vec![],
+            defs: vec![],
+            refs: vec![],
+            macro_refs: vec![],
+        }
+    }
+}
+
+// DefId::index is a newtype and so the JSON serialisation is ugly. Therefore
+// we use our own Id which is the same, but without the newtype.
+#[derive(Debug, RustcEncodable)]
+struct Id {
+    krate: u32,
+    index: u32,
+}
+
+impl From<DefId> for Id {
+    fn from(id: DefId) -> Id {
+        Id {
+            krate: id.krate,
+            index: id.index.as_u32(),
+        }
+    }
+}
+
+#[derive(Debug, RustcEncodable)]
+struct Import {
+    kind: ImportKind,
+    id: Id,
+    span: SpanData,
+    name: String,
+    value: String,
+}
+
+#[derive(Debug, RustcEncodable)]
+enum ImportKind {
+    ExternCrate,
+    Use,
+    GlobUse,
+}
+
+impl From<ExternCrateData> for Import {
+    fn from(data: ExternCrateData) -> Import {
+        Import {
+            kind: ImportKind::ExternCrate,
+            id: From::from(data.id),
+            span: data.span,
+            name: data.name,
+            value: String::new(),
+        }
+    }
+}
+impl From<UseData> for Import {
+    fn from(data: UseData) -> Import {
+        Import {
+            kind: ImportKind::Use,
+            id: From::from(data.id),
+            span: data.span,
+            name: data.name,
+            value: String::new(),
+        }
+    }
+}
+impl From<UseGlobData> for Import {
+    fn from(data: UseGlobData) -> Import {
+        Import {
+            kind: ImportKind::GlobUse,
+            id: From::from(data.id),
+            span: data.span,
+            name: "*".to_owned(),
+            value: data.names.join(", "),
+        }
+    }
+}
+
+#[derive(Debug, RustcEncodable)]
+struct Def {
+    kind: DefKind,
+    id: Id,
+    span: SpanData,
+    name: String,
+    qualname: String,
+    value: String,
+}
+
+#[derive(Debug, RustcEncodable)]
+enum DefKind {
+    // value = variant names
+    Enum,
+    // value = enum name + variant name + types
+    Tuple,
+    // value = [enum name +] name + fields
+    Struct,
+    // value = signature
+    Trait,
+    // value = type + generics
+    Function,
+    // No id, no value.
+    Macro,
+    // value = file_name
+    Mod,
+    // value = aliased type
+    Type,
+    // value = type and init expression
+    Variable,
+}
+
+impl From<EnumData> for Def {
+    fn from(data: EnumData) -> Def {
+        Def {
+            kind: DefKind::Enum,
+            id: From::from(data.id),
+            span: data.span,
+            name: data.name,
+            qualname: data.qualname,
+            value: data.value,
+        }
+    }
+}
+
+impl From<TupleVariantData> for Def {
+    fn from(data: TupleVariantData) -> Def {
+        Def {
+            kind: DefKind::Tuple,
+            id: From::from(data.id),
+            span: data.span,
+            name: data.name,
+            qualname: data.qualname,
+            value: data.value,
+        }
+    }
+}
+impl From<StructVariantData> for Def {
+    fn from(data: StructVariantData) -> Def {
+        Def {
+            kind: DefKind::Struct,
+            id: From::from(data.id),
+            span: data.span,
+            name: data.name,
+            qualname: data.qualname,
+            value: data.value,
+        }
+    }
+}
+impl From<StructData> for Def {
+    fn from(data: StructData) -> Def {
+        Def {
+            kind: DefKind::Struct,
+            id: From::from(data.id),
+            span: data.span,
+            name: data.name,
+            qualname: data.qualname,
+            value: data.value,
+        }
+    }
+}
+impl From<TraitData> for Def {
+    fn from(data: TraitData) -> Def {
+        Def {
+            kind: DefKind::Trait,
+            id: From::from(data.id),
+            span: data.span,
+            name: data.name,
+            qualname: data.qualname,
+            value: data.value,
+        }
+    }
+}
+impl From<FunctionData> for Def {
+    fn from(data: FunctionData) -> Def {
+        Def {
+            kind: DefKind::Function,
+            id: From::from(data.id),
+            span: data.span,
+            name: data.name,
+            qualname: data.qualname,
+            value: data.value,
+        }
+    }
+}
+impl From<MethodData> for Def {
+    fn from(data: MethodData) -> Def {
+        Def {
+            kind: DefKind::Function,
+            id: From::from(data.id),
+            span: data.span,
+            name: data.name,
+            qualname: data.qualname,
+            value: data.value,
+        }
+    }
+}
+impl From<MacroData> for Def {
+    fn from(data: MacroData) -> Def {
+        Def {
+            kind: DefKind::Macro,
+            id: From::from(null_def_id()),
+            span: data.span,
+            name: data.name,
+            qualname: data.qualname,
+            value: String::new(),
+        }
+    }
+}
+impl From<ModData> for Def {
+    fn from(data:ModData) -> Def {
+        Def {
+            kind: DefKind::Mod,
+            id: From::from(data.id),
+            span: data.span,
+            name: data.name,
+            qualname: data.qualname,
+            value: data.filename,
+        }
+    }
+}
+impl From<TypeDefData> for Def {
+    fn from(data: TypeDefData) -> Def {
+        Def {
+            kind: DefKind::Type,
+            id: From::from(data.id),
+            span: data.span,
+            name: data.name,
+            qualname: data.qualname,
+            value: data.value,
+        }
+    }
+}
+impl From<VariableData> for Def {
+    fn from(data: VariableData) -> Def {
+        Def {
+            kind: DefKind::Variable,
+            id: From::from(data.id),
+            span: data.span,
+            name: data.name,
+            qualname: data.qualname,
+            value: data.value,
+        }
+    }
+}
+
+#[derive(Debug, RustcEncodable)]
+enum RefKind {
+    Function,
+    Mod,
+    Type,
+    Variable,
+}
+
+#[derive(Debug, RustcEncodable)]
+struct Ref {
+    kind: RefKind,
+    span: SpanData,
+    ref_id: Id,
+}
+
+impl From<FunctionRefData> for Ref {
+    fn from(data: FunctionRefData) -> Ref {
+        Ref {
+            kind: RefKind::Function,
+            span: data.span,
+            ref_id: From::from(data.ref_id),
+        }
+    }
+}
+impl From<FunctionCallData> for Ref {
+    fn from(data: FunctionCallData) -> Ref {
+        Ref {
+            kind: RefKind::Function,
+            span: data.span,
+            ref_id: From::from(data.ref_id),
+        }
+    }
+}
+impl From<MethodCallData> for Ref {
+    fn from(data: MethodCallData) -> Ref {
+        Ref {
+            kind: RefKind::Function,
+            span: data.span,
+            ref_id: From::from(data.ref_id.or(data.decl_id).unwrap_or(null_def_id())),
+        }
+    }
+}
+impl From<ModRefData> for Ref {
+    fn from(data: ModRefData) -> Ref {
+        Ref {
+            kind: RefKind::Mod,
+            span: data.span,
+            ref_id: From::from(data.ref_id.unwrap_or(null_def_id())),
+        }
+    }
+}
+impl From<TypeRefData> for Ref {
+    fn from(data: TypeRefData) -> Ref {
+        Ref {
+            kind: RefKind::Type,
+            span: data.span,
+            ref_id: From::from(data.ref_id.unwrap_or(null_def_id())),
+        }
+    }
+}
+impl From<VariableRefData> for Ref {
+    fn from(data: VariableRefData) -> Ref {
+        Ref {
+            kind: RefKind::Variable,
+            span: data.span,
+            ref_id: From::from(data.ref_id),
+        }
+    }
+}
+
+#[derive(Debug, RustcEncodable)]
+struct MacroRef {
+    span: SpanData,
+    qualname: String,
+    callee_span: SpanData,
+}
+
+impl From<MacroUseData> for MacroRef {
+    fn from(data: MacroUseData) -> MacroRef {
+        MacroRef {
+            span: data.span,
+            qualname: data.qualname,
+            callee_span: data.callee_span,
+        }
+    }
 }
diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs
index d62c14d2c57..8c00a569993 100644
--- a/src/librustc_save_analysis/lib.rs
+++ b/src/librustc_save_analysis/lib.rs
@@ -52,7 +52,7 @@ use syntax::ast::{self, NodeId, PatKind};
 use syntax::codemap::*;
 use syntax::parse::token::{self, keywords};
 use syntax::visit::{self, Visitor};
-use syntax::print::pprust::ty_to_string;
+use syntax::print::pprust::{ty_to_string, arg_to_string};
 
 pub use self::csv_dumper::CsvDumper;
 pub use self::json_dumper::JsonDumper;
@@ -122,11 +122,13 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
 
     pub fn get_item_data(&self, item: &ast::Item) -> Option<Data> {
         match item.node {
-            ast::ItemKind::Fn(..) => {
+            ast::ItemKind::Fn(ref decl, _, _, _, ref generics, _) => {
                 let name = self.tcx.node_path_str(item.id);
                 let qualname = format!("::{}", name);
                 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,
                     name: name,
@@ -134,6 +136,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                     declaration: None,
                     span: sub_span.unwrap(),
                     scope: self.enclosing_scope(item.id),
+                    value: make_signature(decl, generics),
                 }))
             }
             ast::ItemKind::Static(ref typ, mt, ref expr) => {
@@ -190,16 +193,22 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                     filename: filename,
                 }))
             }
-            ast::ItemKind::Enum(..) => {
-                let enum_name = format!("::{}", self.tcx.node_path_str(item.id));
-                let val = self.span_utils.snippet(item.span);
+            ast::ItemKind::Enum(ref def, _) => {
+                let name = item.ident.to_string();
+                let qualname = format!("::{}", self.tcx.node_path_str(item.id));
                 let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Enum);
                 filter!(self.span_utils, sub_span, item.span, None);
+                let variants_str = def.variants.iter()
+                                      .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: enum_name,
+                    qualname: qualname,
                     scope: self.enclosing_scope(item.id),
                 }))
             }
@@ -353,6 +362,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
             declaration: decl_id,
             span: sub_span.unwrap(),
             scope: self.enclosing_scope(id),
+            // FIXME you get better data here by using the visitor.
+            value: String::new(),
         })
     }
 
@@ -637,6 +648,35 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
     }
 }
 
+fn make_signature(decl: &ast::FnDecl, generics: &ast::Generics) -> String {
+    let mut sig = String::new();
+    if !generics.lifetimes.is_empty() || !generics.ty_params.is_empty() {
+        sig.push('<');
+        sig.push_str(&generics.lifetimes.iter()
+                              .map(|l| l.lifetime.name.to_string())
+                              .collect::<Vec<_>>()
+                              .join(", "));
+        if !generics.lifetimes.is_empty() {
+            sig.push_str(", ");
+        }
+        sig.push_str(&generics.ty_params.iter()
+                              .map(|l| l.ident.to_string())
+                              .collect::<Vec<_>>()
+                              .join(", "));
+        sig.push_str("> ");
+    }
+    sig.push('(');
+    sig.push_str(&decl.inputs.iter().map(arg_to_string).collect::<Vec<_>>().join(", "));
+    sig.push(')');
+    match decl.output {
+        ast::FunctionRetTy::None(_) => sig.push_str(" -> !"),
+        ast::FunctionRetTy::Default(_) => {}
+        ast::FunctionRetTy::Ty(ref t) => sig.push_str(&format!(" -> {}", ty_to_string(t))),
+    }
+
+    sig
+}
+
 // An AST visitor for collecting paths from patterns.
 struct PathCollector {
     // The Row field identifies the kind of pattern.
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index d1ad330c58c..e9f3472c4a1 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -2030,10 +2030,7 @@ pub enum ItemKind {
     /// A struct definition, e.g. `struct Foo<A> {x: A}`
     Struct(VariantData, Generics),
     /// Represents a Trait Declaration
-    Trait(Unsafety,
-              Generics,
-              TyParamBounds,
-              Vec<TraitItem>),
+    Trait(Unsafety, Generics, TyParamBounds, Vec<TraitItem>),
 
     // Default trait implementations
     ///