about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2016-12-23 15:59:07 +0000
committerbors <bors@rust-lang.org>2016-12-23 15:59:07 +0000
commit00b4019f28f3e7f9ae3990ed871cb4917fd9e659 (patch)
tree10588f7afa6278048c2181342dcf906b780f98e1 /src
parentce4461f4cfa09045e5c03f45e343b01bc5dd22e4 (diff)
parentc24b1928ca97f98b72b4413b177a7eb3fe73456f (diff)
downloadrust-00b4019f28f3e7f9ae3990ed871cb4917fd9e659.tar.gz
rust-00b4019f28f3e7f9ae3990ed871cb4917fd9e659.zip
Auto merge of #38529 - nrc:save-sig, r=nikomatsakis
save-analysis: add signature info

These 'signatures' for definitions contain enough info for the RLS to create Rustdoc-style info on the fly.
Diffstat (limited to 'src')
-rw-r--r--src/librustc_save_analysis/data.rs35
-rw-r--r--src/librustc_save_analysis/dump_visitor.rs33
-rw-r--r--src/librustc_save_analysis/external_data.rs49
-rw-r--r--src/librustc_save_analysis/json_api_dumper.rs55
-rw-r--r--src/librustc_save_analysis/json_dumper.rs55
-rw-r--r--src/librustc_save_analysis/lib.rs65
-rw-r--r--src/librustc_save_analysis/span_utils.rs44
7 files changed, 320 insertions, 16 deletions
diff --git a/src/librustc_save_analysis/data.rs b/src/librustc_save_analysis/data.rs
index fc235aaf927..0a6281bf8c5 100644
--- a/src/librustc_save_analysis/data.rs
+++ b/src/librustc_save_analysis/data.rs
@@ -135,6 +135,7 @@ pub struct EnumData {
     pub variants: Vec<NodeId>,
     pub visibility: Visibility,
     pub docs: String,
+    pub sig: Signature,
 }
 
 /// Data for extern crates.
@@ -169,6 +170,7 @@ pub struct FunctionData {
     pub visibility: Visibility,
     pub parent: Option<DefId>,
     pub docs: String,
+    pub sig: Signature,
 }
 
 /// Data about a function call.
@@ -253,6 +255,7 @@ pub struct MethodData {
     pub parent: Option<DefId>,
     pub visibility: Visibility,
     pub docs: String,
+    pub sig: Signature,
 }
 
 /// Data for modules.
@@ -267,6 +270,7 @@ pub struct ModData {
     pub items: Vec<NodeId>,
     pub visibility: Visibility,
     pub docs: String,
+    pub sig: Signature,
 }
 
 /// Data for a reference to a module.
@@ -290,6 +294,7 @@ pub struct StructData {
     pub fields: Vec<NodeId>,
     pub visibility: Visibility,
     pub docs: String,
+    pub sig: Signature,
 }
 
 #[derive(Debug, RustcEncodable)]
@@ -303,6 +308,7 @@ pub struct StructVariantData {
     pub scope: NodeId,
     pub parent: Option<DefId>,
     pub docs: String,
+    pub sig: Signature,
 }
 
 #[derive(Debug, RustcEncodable)]
@@ -316,6 +322,7 @@ pub struct TraitData {
     pub items: Vec<NodeId>,
     pub visibility: Visibility,
     pub docs: String,
+    pub sig: Signature,
 }
 
 #[derive(Debug, RustcEncodable)]
@@ -329,6 +336,7 @@ pub struct TupleVariantData {
     pub scope: NodeId,
     pub parent: Option<DefId>,
     pub docs: String,
+    pub sig: Signature,
 }
 
 /// Data for a typedef.
@@ -342,6 +350,7 @@ pub struct TypeDefData {
     pub visibility: Visibility,
     pub parent: Option<DefId>,
     pub docs: String,
+    pub sig: Option<Signature>,
 }
 
 /// Data for a reference to a type or trait.
@@ -386,6 +395,7 @@ pub struct VariableData {
     pub type_value: String,
     pub visibility: Visibility,
     pub docs: String,
+    pub sig: Option<Signature>,
 }
 
 #[derive(Debug, RustcEncodable)]
@@ -405,3 +415,28 @@ pub struct VariableRefData {
     pub scope: NodeId,
     pub ref_id: DefId,
 }
+
+
+/// Encodes information about the signature of a definition. This should have
+/// enough information to create a nice display about a definition without
+/// access to the source code.
+#[derive(Clone, Debug, RustcEncodable)]
+pub struct Signature {
+    pub span: Span,
+    pub text: String,
+    // These identify the main identifier for the defintion as byte offsets into
+    // `text`. E.g., of `foo` in `pub fn foo(...)`
+    pub ident_start: usize,
+    pub ident_end: usize,
+    pub defs: Vec<SigElement>,
+    pub refs: Vec<SigElement>,
+}
+
+/// An element of a signature. `start` and `end` are byte offsets into the `text`
+/// of the parent `Signature`.
+#[derive(Clone, Debug, RustcEncodable)]
+pub struct SigElement {
+    pub id: DefId,
+    pub start: usize,
+    pub end: usize,
+}
diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs
index 65372d4dca9..093a739c69f 100644
--- a/src/librustc_save_analysis/dump_visitor.rs
+++ b/src/librustc_save_analysis/dump_visitor.rs
@@ -357,6 +357,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                         parent: None,
                         visibility: Visibility::Inherited,
                         docs: String::new(),
+                        sig: None,
                     }.lower(self.tcx));
                 }
             }
@@ -429,6 +430,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                     parent: trait_id,
                     visibility: vis,
                     docs: docs_for_attrs(attrs),
+                    sig: method_data.sig,
                 }.lower(self.tcx));
             }
 
@@ -500,6 +502,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                     visibility: Visibility::Inherited,
                     parent: None,
                     docs: String::new(),
+                    sig: None,
                 }.lower(self.tcx));
             }
         }
@@ -572,6 +575,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                 parent: Some(parent_id),
                 visibility: vis,
                 docs: docs_for_attrs(attrs),
+                sig: None,
             }.lower(self.tcx));
         }
 
@@ -615,11 +619,10 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                 fields: fields,
                 visibility: From::from(&item.vis),
                 docs: docs_for_attrs(&item.attrs),
+                sig: self.save_ctxt.sig_base(item),
             }.lower(self.tcx));
         }
 
-
-        // fields
         for field in def.fields() {
             self.process_struct_field_def(field, item.id);
             self.visit_ty(&field.ty);
@@ -648,6 +651,18 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
             qualname.push_str("::");
             qualname.push_str(&name);
 
+            let text = self.span.signature_string_for_span(variant.span);
+            let ident_start = text.find(&name).unwrap();
+            let ident_end = ident_start + name.len();
+            let sig = Signature {
+                span: variant.span,
+                text: text,
+                ident_start: ident_start,
+                ident_end: ident_end,
+                defs: vec![],
+                refs: vec![],
+            };
+
             match variant.node.data {
                 ast::VariantData::Struct(ref fields, _) => {
                     let sub_span = self.span.span_for_first_ident(variant.span);
@@ -669,6 +684,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                             scope: enum_data.scope,
                             parent: Some(make_def_id(item.id, &self.tcx.map)),
                             docs: docs_for_attrs(&variant.node.attrs),
+                            sig: sig,
                         }.lower(self.tcx));
                     }
                 }
@@ -694,6 +710,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                             scope: enum_data.scope,
                             parent: Some(make_def_id(item.id, &self.tcx.map)),
                             docs: docs_for_attrs(&variant.node.attrs),
+                            sig: sig,
                         }.lower(self.tcx));
                     }
                 }
@@ -778,6 +795,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                 items: methods.iter().map(|i| i.id).collect(),
                 visibility: From::from(&item.vis),
                 docs: docs_for_attrs(&item.attrs),
+                sig: self.save_ctxt.sig_base(item),
             }.lower(self.tcx));
         }
 
@@ -1043,6 +1061,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                     parent: None,
                     visibility: Visibility::Inherited,
                     docs: String::new(),
+                    sig: None,
                 }.lower(self.tcx));
             }
         }
@@ -1257,10 +1276,10 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll,
             Struct(ref def, ref ty_params) => self.process_struct(item, def, ty_params),
             Enum(ref def, ref ty_params) => self.process_enum(item, def, ty_params),
             Impl(..,
-                          ref ty_params,
-                          ref trait_ref,
-                          ref typ,
-                          ref impl_items) => {
+                 ref ty_params,
+                 ref trait_ref,
+                 ref typ,
+                 ref impl_items) => {
                 self.process_impl(item, ty_params, trait_ref, &typ, impl_items)
             }
             Trait(_, ref generics, ref trait_refs, ref methods) =>
@@ -1283,6 +1302,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll,
                         visibility: From::from(&item.vis),
                         parent: None,
                         docs: docs_for_attrs(&item.attrs),
+                        sig: Some(self.save_ctxt.sig_base(item)),
                     }.lower(self.tcx));
                 }
 
@@ -1492,6 +1512,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll,
                             parent: None,
                             visibility: Visibility::Inherited,
                             docs: String::new(),
+                            sig: None,
                         }.lower(self.tcx));
                     }
                 }
diff --git a/src/librustc_save_analysis/external_data.rs b/src/librustc_save_analysis/external_data.rs
index 58475757423..18ae3a7fa9e 100644
--- a/src/librustc_save_analysis/external_data.rs
+++ b/src/librustc_save_analysis/external_data.rs
@@ -15,7 +15,7 @@ use syntax::ast::NodeId;
 use syntax::codemap::CodeMap;
 use syntax_pos::Span;
 
-use data::{self, Visibility};
+use data::{self, Visibility, SigElement};
 
 // FIXME: this should be pub(crate), but the current snapshot doesn't allow it yet
 pub trait Lower {
@@ -97,6 +97,7 @@ pub struct EnumData {
     pub variants: Vec<DefId>,
     pub visibility: Visibility,
     pub docs: String,
+    pub sig: Signature,
 }
 
 impl Lower for data::EnumData {
@@ -113,6 +114,7 @@ impl Lower for data::EnumData {
             variants: self.variants.into_iter().map(|id| make_def_id(id, &tcx.map)).collect(),
             visibility: self.visibility,
             docs: self.docs,
+            sig: self.sig.lower(tcx),
         }
     }
 }
@@ -176,6 +178,7 @@ pub struct FunctionData {
     pub visibility: Visibility,
     pub parent: Option<DefId>,
     pub docs: String,
+    pub sig: Signature,
 }
 
 impl Lower for data::FunctionData {
@@ -193,6 +196,7 @@ impl Lower for data::FunctionData {
             visibility: self.visibility,
             parent: self.parent,
             docs: self.docs,
+            sig: self.sig.lower(tcx),
         }
     }
 }
@@ -341,6 +345,7 @@ pub struct MethodData {
     pub visibility: Visibility,
     pub parent: Option<DefId>,
     pub docs: String,
+    pub sig: Signature,
 }
 
 impl Lower for data::MethodData {
@@ -358,6 +363,7 @@ impl Lower for data::MethodData {
             visibility: self.visibility,
             parent: self.parent,
             docs: self.docs,
+            sig: self.sig.lower(tcx),
         }
     }
 }
@@ -374,6 +380,7 @@ pub struct ModData {
     pub items: Vec<DefId>,
     pub visibility: Visibility,
     pub docs: String,
+    pub sig: Signature,
 }
 
 impl Lower for data::ModData {
@@ -390,6 +397,7 @@ impl Lower for data::ModData {
             items: self.items.into_iter().map(|id| make_def_id(id, &tcx.map)).collect(),
             visibility: self.visibility,
             docs: self.docs,
+            sig: self.sig.lower(tcx),
         }
     }
 }
@@ -428,6 +436,7 @@ pub struct StructData {
     pub fields: Vec<DefId>,
     pub visibility: Visibility,
     pub docs: String,
+    pub sig: Signature,
 }
 
 impl Lower for data::StructData {
@@ -445,6 +454,7 @@ impl Lower for data::StructData {
             fields: self.fields.into_iter().map(|id| make_def_id(id, &tcx.map)).collect(),
             visibility: self.visibility,
             docs: self.docs,
+            sig: self.sig.lower(tcx),
         }
     }
 }
@@ -460,6 +470,7 @@ pub struct StructVariantData {
     pub scope: DefId,
     pub parent: Option<DefId>,
     pub docs: String,
+    pub sig: Signature,
 }
 
 impl Lower for data::StructVariantData {
@@ -476,6 +487,7 @@ impl Lower for data::StructVariantData {
             scope: make_def_id(self.scope, &tcx.map),
             parent: self.parent,
             docs: self.docs,
+            sig: self.sig.lower(tcx),
         }
     }
 }
@@ -491,6 +503,7 @@ pub struct TraitData {
     pub items: Vec<DefId>,
     pub visibility: Visibility,
     pub docs: String,
+    pub sig: Signature,
 }
 
 impl Lower for data::TraitData {
@@ -507,6 +520,7 @@ impl Lower for data::TraitData {
             items: self.items.into_iter().map(|id| make_def_id(id, &tcx.map)).collect(),
             visibility: self.visibility,
             docs: self.docs,
+            sig: self.sig.lower(tcx),
         }
     }
 }
@@ -522,6 +536,7 @@ pub struct TupleVariantData {
     pub scope: DefId,
     pub parent: Option<DefId>,
     pub docs: String,
+    pub sig: Signature,
 }
 
 impl Lower for data::TupleVariantData {
@@ -538,6 +553,7 @@ impl Lower for data::TupleVariantData {
             scope: make_def_id(self.scope, &tcx.map),
             parent: self.parent,
             docs: self.docs,
+            sig: self.sig.lower(tcx),
         }
     }
 }
@@ -553,6 +569,7 @@ pub struct TypeDefData {
     pub visibility: Visibility,
     pub parent: Option<DefId>,
     pub docs: String,
+    pub sig: Option<Signature>,
 }
 
 impl Lower for data::TypeDefData {
@@ -568,6 +585,7 @@ impl Lower for data::TypeDefData {
             visibility: self.visibility,
             parent: self.parent,
             docs: self.docs,
+            sig: self.sig.map(|s| s.lower(tcx)),
         }
     }
 }
@@ -656,6 +674,7 @@ pub struct VariableData {
     pub parent: Option<DefId>,
     pub visibility: Visibility,
     pub docs: String,
+    pub sig: Option<Signature>,
 }
 
 impl Lower for data::VariableData {
@@ -674,6 +693,7 @@ impl Lower for data::VariableData {
             parent: self.parent,
             visibility: self.visibility,
             docs: self.docs,
+            sig: self.sig.map(|s| s.lower(tcx)),
         }
     }
 }
@@ -700,3 +720,30 @@ impl Lower for data::VariableRefData {
         }
     }
 }
+
+#[derive(Clone, Debug, RustcEncodable)]
+pub struct Signature {
+    pub span: SpanData,
+    pub text: String,
+    // These identify the main identifier for the defintion as byte offsets into
+    // `text`. E.g., of `foo` in `pub fn foo(...)`
+    pub ident_start: usize,
+    pub ident_end: usize,
+    pub defs: Vec<SigElement>,
+    pub refs: Vec<SigElement>,
+}
+
+impl Lower for data::Signature {
+    type Target = Signature;
+
+    fn lower(self, tcx: TyCtxt) -> Signature {
+        Signature {
+            span: SpanData::from_span(self.span, tcx.sess.codemap()),
+            text: self.text,
+            ident_start: self.ident_start,
+            ident_end: self.ident_end,
+            defs: self.defs,
+            refs: self.refs,
+        }
+    }
+}
diff --git a/src/librustc_save_analysis/json_api_dumper.rs b/src/librustc_save_analysis/json_api_dumper.rs
index d56aae18a7c..342c33af2f8 100644
--- a/src/librustc_save_analysis/json_api_dumper.rs
+++ b/src/librustc_save_analysis/json_api_dumper.rs
@@ -14,7 +14,7 @@ use rustc::hir::def_id::DefId;
 use rustc_serialize::json::as_json;
 
 use external_data::*;
-use data::{VariableKind, Visibility};
+use data::{VariableKind, Visibility, SigElement};
 use dump::Dump;
 use super::Format;
 
@@ -179,6 +179,7 @@ struct Def {
     children: Vec<Id>,
     decl_id: Option<Id>,
     docs: String,
+    sig: Option<JsonSignature>,
 }
 
 #[derive(Debug, RustcEncodable)]
@@ -221,6 +222,7 @@ impl From<EnumData> for Option<Def> {
                 children: data.variants.into_iter().map(|id| From::from(id)).collect(),
                 decl_id: None,
                 docs: data.docs,
+                sig: Some(From::from(data.sig)),
             }),
             _ => None,
         }
@@ -240,6 +242,7 @@ impl From<TupleVariantData> for Option<Def> {
             children: vec![],
             decl_id: None,
             docs: data.docs,
+            sig: Some(From::from(data.sig)),
         })
     }
 }
@@ -256,6 +259,7 @@ impl From<StructVariantData> for Option<Def> {
             children: vec![],
             decl_id: None,
             docs: data.docs,
+            sig: Some(From::from(data.sig)),
         })
     }
 }
@@ -273,6 +277,7 @@ impl From<StructData> for Option<Def> {
             children: data.fields.into_iter().map(|id| From::from(id)).collect(),
             decl_id: None,
             docs: data.docs,
+            sig: Some(From::from(data.sig)),
         }),
             _ => None,
         }
@@ -292,6 +297,7 @@ impl From<TraitData> for Option<Def> {
                 parent: None,
                 decl_id: None,
                 docs: data.docs,
+                sig: Some(From::from(data.sig)),
             }),
             _ => None,
         }
@@ -311,6 +317,7 @@ impl From<FunctionData> for Option<Def> {
                 parent: data.parent.map(|id| From::from(id)),
                 decl_id: None,
                 docs: data.docs,
+                sig: Some(From::from(data.sig)),
             }),
             _ => None,
         }
@@ -330,6 +337,7 @@ impl From<MethodData> for Option<Def> {
                 parent: data.parent.map(|id| From::from(id)),
                 decl_id: data.decl_id.map(|id| From::from(id)),
                 docs: data.docs,
+                sig: Some(From::from(data.sig)),
             }),
             _ => None,
         }
@@ -348,6 +356,7 @@ impl From<MacroData> for Option<Def> {
             parent: None,
             decl_id: None,
             docs: data.docs,
+            sig: None,
         })
     }
 }
@@ -365,6 +374,7 @@ impl From<ModData> for Option<Def> {
                 parent: None,
                 decl_id: None,
                 docs: data.docs,
+                sig: Some(From::from(data.sig)),
             }),
             _ => None,
         }
@@ -384,11 +394,13 @@ impl From<TypeDefData> for Option<Def> {
                 parent: data.parent.map(|id| From::from(id)),
                 decl_id: None,
                 docs: String::new(),
+                sig: data.sig.map(|s| From::from(s)),
             }),
             _ => None,
         }
     }
 }
+
 impl From<VariableData> for Option<Def> {
     fn from(data: VariableData) -> Option<Def> {
         match data.visibility {
@@ -408,8 +420,49 @@ impl From<VariableData> for Option<Def> {
                 parent: data.parent.map(|id| From::from(id)),
                 decl_id: None,
                 docs: data.docs,
+                sig: data.sig.map(|s| From::from(s)),
             }),
             _ => None,
         }
     }
 }
+
+#[derive(Debug, RustcEncodable)]
+pub struct JsonSignature {
+    span: SpanData,
+    text: String,
+    ident_start: usize,
+    ident_end: usize,
+    defs: Vec<JsonSigElement>,
+    refs: Vec<JsonSigElement>,
+}
+
+impl From<Signature> for JsonSignature {
+    fn from(data: Signature) -> JsonSignature {
+        JsonSignature {
+            span: data.span,
+            text: data.text,
+            ident_start: data.ident_start,
+            ident_end: data.ident_end,
+            defs: data.defs.into_iter().map(|s| From::from(s)).collect(),
+            refs: data.refs.into_iter().map(|s| From::from(s)).collect(),
+        }
+    }
+}
+
+#[derive(Debug, RustcEncodable)]
+pub struct JsonSigElement {
+    id: Id,
+    start: usize,
+    end: usize,
+}
+
+impl From<SigElement> for JsonSigElement {
+    fn from(data: SigElement) -> JsonSigElement {
+        JsonSigElement {
+            id: From::from(data.id),
+            start: data.start,
+            end: data.end,
+        }
+    }
+}
diff --git a/src/librustc_save_analysis/json_dumper.rs b/src/librustc_save_analysis/json_dumper.rs
index f97272ad544..16c06a556df 100644
--- a/src/librustc_save_analysis/json_dumper.rs
+++ b/src/librustc_save_analysis/json_dumper.rs
@@ -14,7 +14,7 @@ use rustc::hir::def_id::DefId;
 use rustc_serialize::json::as_json;
 
 use external_data::*;
-use data::VariableKind;
+use data::{VariableKind, SigElement};
 use dump::Dump;
 use super::Format;
 
@@ -86,6 +86,7 @@ impl<'b, W: Write + 'b> Dump for JsonDumper<'b, W> {
             children: data.items.into_iter().map(|id| From::from(id)).collect(),
             decl_id: None,
             docs: data.docs,
+            sig: Some(From::from(data.sig)),
         };
         if def.span.file_name != def.value {
             // If the module is an out-of-line defintion, then we'll make the
@@ -223,6 +224,7 @@ struct Def {
     children: Vec<Id>,
     decl_id: Option<Id>,
     docs: String,
+    sig: Option<JsonSignature>,
 }
 
 #[derive(Debug, RustcEncodable)]
@@ -264,6 +266,7 @@ impl From<EnumData> for Def {
             children: data.variants.into_iter().map(|id| From::from(id)).collect(),
             decl_id: None,
             docs: data.docs,
+            sig: Some(From::from(data.sig)),
         }
     }
 }
@@ -280,6 +283,7 @@ impl From<TupleVariantData> for Def {
             children: vec![],
             decl_id: None,
             docs: data.docs,
+            sig: Some(From::from(data.sig)),
         }
     }
 }
@@ -295,6 +299,7 @@ impl From<StructVariantData> for Def {
             children: vec![],
             decl_id: None,
             docs: data.docs,
+            sig: Some(From::from(data.sig)),
         }
     }
 }
@@ -310,6 +315,7 @@ impl From<StructData> for Def {
             children: data.fields.into_iter().map(|id| From::from(id)).collect(),
             decl_id: None,
             docs: data.docs,
+            sig: Some(From::from(data.sig)),
         }
     }
 }
@@ -325,6 +331,7 @@ impl From<TraitData> for Def {
             children: data.items.into_iter().map(|id| From::from(id)).collect(),
             decl_id: None,
             docs: data.docs,
+            sig: Some(From::from(data.sig)),
         }
     }
 }
@@ -340,6 +347,7 @@ impl From<FunctionData> for Def {
             children: vec![],
             decl_id: None,
             docs: data.docs,
+            sig: Some(From::from(data.sig)),
         }
     }
 }
@@ -355,6 +363,7 @@ impl From<MethodData> for Def {
             children: vec![],
             decl_id: data.decl_id.map(|id| From::from(id)),
             docs: data.docs,
+            sig: Some(From::from(data.sig)),
         }
     }
 }
@@ -370,10 +379,10 @@ impl From<MacroData> for Def {
             children: vec![],
             decl_id: None,
             docs: data.docs,
+            sig: None,
         }
     }
 }
-
 impl From<TypeDefData> for Def {
     fn from(data: TypeDefData) -> Def {
         Def {
@@ -386,6 +395,7 @@ impl From<TypeDefData> for Def {
             children: vec![],
             decl_id: None,
             docs: String::new(),
+            sig: data.sig.map(|s| From::from(s)),
         }
     }
 }
@@ -406,6 +416,7 @@ impl From<VariableData> for Def {
             children: vec![],
             decl_id: None,
             docs: data.docs,
+            sig: None,
         }
     }
 }
@@ -496,3 +507,43 @@ impl From<MacroUseData> for MacroRef {
         }
     }
 }
+
+#[derive(Debug, RustcEncodable)]
+pub struct JsonSignature {
+    span: SpanData,
+    text: String,
+    ident_start: usize,
+    ident_end: usize,
+    defs: Vec<JsonSigElement>,
+    refs: Vec<JsonSigElement>,
+}
+
+impl From<Signature> for JsonSignature {
+    fn from(data: Signature) -> JsonSignature {
+        JsonSignature {
+            span: data.span,
+            text: data.text,
+            ident_start: data.ident_start,
+            ident_end: data.ident_end,
+            defs: data.defs.into_iter().map(|s| From::from(s)).collect(),
+            refs: data.refs.into_iter().map(|s| From::from(s)).collect(),
+        }
+    }
+}
+
+#[derive(Debug, RustcEncodable)]
+pub struct JsonSigElement {
+    id: Id,
+    start: usize,
+    end: usize,
+}
+
+impl From<SigElement> for JsonSigElement {
+    fn from(data: SigElement) -> JsonSigElement {
+        JsonSigElement {
+            id: From::from(data.id),
+            start: data.start,
+            end: data.end,
+        }
+    }
+}
diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs
index 862345fd46e..491521a3239 100644
--- a/src/librustc_save_analysis/lib.rs
+++ b/src/librustc_save_analysis/lib.rs
@@ -152,6 +152,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                     visibility: From::from(&item.vis),
                     parent: None,
                     docs: docs_for_attrs(&item.attrs),
+                    sig: self.sig_base(item),
                 }))
             }
             ast::ItemKind::Static(ref typ, mt, ref expr) => {
@@ -179,6 +180,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                     type_value: ty_to_string(&typ),
                     visibility: From::from(&item.vis),
                     docs: docs_for_attrs(&item.attrs),
+                    sig: Some(self.sig_base(item)),
                 }))
             }
             ast::ItemKind::Const(ref typ, ref expr) => {
@@ -197,6 +199,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                     type_value: ty_to_string(&typ),
                     visibility: From::from(&item.vis),
                     docs: docs_for_attrs(&item.attrs),
+                    sig: Some(self.sig_base(item)),
                 }))
             }
             ast::ItemKind::Mod(ref m) => {
@@ -207,6 +210,7 @@ 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,
                     name: item.ident.to_string(),
@@ -217,6 +221,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                     items: m.items.iter().map(|i| i.id).collect(),
                     visibility: From::from(&item.vis),
                     docs: docs_for_attrs(&item.attrs),
+                    sig: self.sig_base(item),
                 }))
             }
             ast::ItemKind::Enum(ref def, _) => {
@@ -239,6 +244,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                     variants: def.variants.iter().map(|v| v.node.data.id()).collect(),
                     visibility: From::from(&item.vis),
                     docs: docs_for_attrs(&item.attrs),
+                    sig: self.sig_base(item),
                 }))
             }
             ast::ItemKind::Impl(.., ref trait_ref, ref typ, _) => {
@@ -287,18 +293,34 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
         }
     }
 
-    pub fn get_field_data(&self, field: &ast::StructField,
-                          scope: NodeId) -> Option<VariableData> {
+    pub fn get_field_data(&self,
+                          field: &ast::StructField,
+                          scope: NodeId)
+                          -> Option<VariableData> {
         if let Some(ident) = field.ident {
+            let name = ident.to_string();
             let qualname = format!("::{}::{}", self.tcx.node_path_str(scope), ident);
-            let def_id = self.tcx.map.local_def_id(field.id);
-            let typ = self.tcx.item_type(def_id).to_string();
             let sub_span = self.span_utils.sub_span_before_token(field.span, token::Colon);
             filter!(self.span_utils, sub_span, field.span, None);
+            let def_id = self.tcx.map.local_def_id(field.id);
+            let typ = self.tcx.item_type(def_id).to_string();
+
+            let span = field.span;
+            let text = self.span_utils.snippet(field.span);
+            let ident_start = text.find(&name).unwrap();
+            let ident_end = ident_start + name.len();
+            let sig = Signature {
+                span: span,
+                text: text,
+                ident_start: ident_start,
+                ident_end: ident_end,
+                defs: vec![],
+                refs: vec![],
+            };
             Some(VariableData {
                 id: field.id,
                 kind: VariableKind::Field,
-                name: ident.to_string(),
+                name: name,
                 qualname: qualname,
                 span: sub_span.unwrap(),
                 scope: scope,
@@ -307,6 +329,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                 type_value: typ,
                 visibility: From::from(&field.vis),
                 docs: docs_for_attrs(&field.attrs),
+                sig: Some(sig),
             })
         } else {
             None
@@ -388,9 +411,23 @@ 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);
+
+        let name = name.to_string();
+        let text = self.span_utils.signature_string_for_span(span);
+        let ident_start = text.find(&name).unwrap();
+        let ident_end = ident_start + name.len();
+        let sig = Signature {
+            span: span,
+            text: text,
+            ident_start: ident_start,
+            ident_end: ident_end,
+            defs: vec![],
+            refs: vec![],
+        };
+
         Some(FunctionData {
             id: id,
-            name: name.to_string(),
+            name: name,
             qualname: qualname,
             declaration: decl_id,
             span: sub_span.unwrap(),
@@ -400,6 +437,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
             visibility: vis,
             parent: parent_scope,
             docs: docs,
+            sig: sig,
         })
     }
 
@@ -695,6 +733,21 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
         }
     }
 
+    fn sig_base(&self, item: &ast::Item) -> Signature {
+        let text = self.span_utils.signature_string_for_span(item.span);
+        let name = item.ident.to_string();
+        let ident_start = text.find(&name).expect("Name not in signature?");
+        let ident_end = ident_start + name.len();
+        Signature {
+            span: mk_sp(item.span.lo, item.span.lo + BytePos(text.len() as u32)),
+            text: text,
+            ident_start: ident_start,
+            ident_end: ident_end,
+            defs: vec![],
+            refs: vec![],
+        }
+    }
+
     #[inline]
     pub fn enclosing_scope(&self, id: NodeId) -> NodeId {
         self.tcx.map.get_enclosing_scope(id).unwrap_or(CRATE_NODE_ID)
diff --git a/src/librustc_save_analysis/span_utils.rs b/src/librustc_save_analysis/span_utils.rs
index e06aefd865f..448bb2e7617 100644
--- a/src/librustc_save_analysis/span_utils.rs
+++ b/src/librustc_save_analysis/span_utils.rs
@@ -19,7 +19,9 @@ use std::path::Path;
 use syntax::ast;
 use syntax::parse::lexer::{self, Reader, StringReader};
 use syntax::parse::token::{self, Token};
+use syntax::parse::parser::Parser;
 use syntax::symbol::keywords;
+use syntax::tokenstream::TokenTree;
 use syntax_pos::*;
 
 #[derive(Clone)]
@@ -87,6 +89,12 @@ impl<'a> SpanUtils<'a> {
         lexer::StringReader::new(s.diagnostic(), filemap)
     }
 
+    fn span_to_tts(&self, span: Span) -> Vec<TokenTree> {
+        let srdr = self.retokenise_span(span);
+        let mut p = Parser::new(&self.sess.parse_sess, Box::new(srdr), None, false);
+        p.parse_all_token_trees().expect("Couldn't re-parse span")
+    }
+
     // Re-parses a path and returns the span for the last identifier in the path
     pub fn span_for_last_ident(&self, span: Span) -> Option<Span> {
         let mut result = None;
@@ -308,6 +316,42 @@ 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.span_to_tts(span).into_iter();
+        let mut prev = toks.next().unwrap();
+        let first_span = prev.get_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(mk_sp(first_span.lo, prev.get_span().hi));
+            } else if let TokenTree::Delimited(_, ref d) = tok {
+                if d.delim == token::Brace {
+                    return self.snippet(mk_sp(first_span.lo, prev.get_span().hi));
+                }
+            }
+            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();