about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNick Cameron <ncameron@mozilla.com>2016-11-21 07:07:40 +1300
committerNick Cameron <ncameron@mozilla.com>2016-12-22 15:17:04 +1300
commit5a6ca7a38dbb34f89c8a0381db5ab23b56f44737 (patch)
tree4f4c3a33655d607f58af5248736d5cb380044853
parentc217ab6c8dc1a305304b00a414be5f39ea6a2c81 (diff)
downloadrust-5a6ca7a38dbb34f89c8a0381db5ab23b56f44737.tar.gz
rust-5a6ca7a38dbb34f89c8a0381db5ab23b56f44737.zip
save-analysis: add `Signature` info to structs
-rw-r--r--src/librustc_save_analysis/data.rs26
-rw-r--r--src/librustc_save_analysis/dump_visitor.rs18
-rw-r--r--src/librustc_save_analysis/external_data.rs31
-rw-r--r--src/librustc_save_analysis/json_api_dumper.rs12
-rw-r--r--src/librustc_save_analysis/json_dumper.rs13
-rw-r--r--src/librustc_save_analysis/span_utils.rs45
6 files changed, 139 insertions, 6 deletions
diff --git a/src/librustc_save_analysis/data.rs b/src/librustc_save_analysis/data.rs
index fc235aaf927..42fdb6a4dd7 100644
--- a/src/librustc_save_analysis/data.rs
+++ b/src/librustc_save_analysis/data.rs
@@ -290,6 +290,7 @@ pub struct StructData {
     pub fields: Vec<NodeId>,
     pub visibility: Visibility,
     pub docs: String,
+    pub sig: Signature,
 }
 
 #[derive(Debug, RustcEncodable)]
@@ -405,3 +406,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(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(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 afa78a05a63..a77527cf8bb 100644
--- a/src/librustc_save_analysis/dump_visitor.rs
+++ b/src/librustc_save_analysis/dump_visitor.rs
@@ -619,6 +619,9 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
         };
 
         if !self.span.filter_generated(sub_span, item.span) {
+            let mut sig = self.sig_base(item);
+            sig.ident_start = sig.text.find(&name).expect("Name not in struct signature?");
+            sig.ident_end = sig.ident_start + name.len();
             self.dumper.struct_data(StructData {
                 span: sub_span.expect("No span found for struct"),
                 id: item.id,
@@ -630,11 +633,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: sig,
             }.lower(self.tcx));
         }
 
-
-        // fields
         for field in def.fields() {
             self.process_struct_field_def(field, item.id);
             self.visit_ty(&field.ty);
@@ -643,6 +645,18 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
         self.process_generic_params(ty_params, item.span, &qualname, item.id);
     }
 
+    fn sig_base(&self, item: &ast::Item) -> Signature {
+        let text = self.span.signature_string_for_span(item.span).expect("Couldn't make signature");
+        Signature {
+            span: mk_sp(item.span.lo, item.span.lo + BytePos(text.len() as u32)),
+            text: text,
+            ident_start: 0,
+            ident_end: 0,
+            defs: vec![],
+            refs: vec![],
+        }
+    }
+
     fn process_enum(&mut self,
                     item: &'l ast::Item,
                     enum_definition: &'l ast::EnumDef,
diff --git a/src/librustc_save_analysis/external_data.rs b/src/librustc_save_analysis/external_data.rs
index 58475757423..d35b1bac78f 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 {
@@ -428,6 +428,7 @@ pub struct StructData {
     pub fields: Vec<DefId>,
     pub visibility: Visibility,
     pub docs: String,
+    pub sig: Signature,
 }
 
 impl Lower for data::StructData {
@@ -445,6 +446,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),
         }
     }
 }
@@ -700,3 +702,30 @@ impl Lower for data::VariableRefData {
         }
     }
 }
+
+#[derive(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..118d2273c13 100644
--- a/src/librustc_save_analysis/json_api_dumper.rs
+++ b/src/librustc_save_analysis/json_api_dumper.rs
@@ -179,6 +179,7 @@ struct Def {
     children: Vec<Id>,
     decl_id: Option<Id>,
     docs: String,
+    sig: Option<Signature>,
 }
 
 #[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: None,
             }),
             _ => None,
         }
@@ -240,6 +242,7 @@ impl From<TupleVariantData> for Option<Def> {
             children: vec![],
             decl_id: None,
             docs: data.docs,
+            sig: None,
         })
     }
 }
@@ -256,6 +259,7 @@ impl From<StructVariantData> for Option<Def> {
             children: vec![],
             decl_id: None,
             docs: data.docs,
+            sig: None,
         })
     }
 }
@@ -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(data.sig),
         }),
             _ => None,
         }
@@ -292,6 +297,7 @@ impl From<TraitData> for Option<Def> {
                 parent: None,
                 decl_id: None,
                 docs: data.docs,
+                sig: None,
             }),
             _ => 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: None,
             }),
             _ => 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: None,
             }),
             _ => 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: None,
             }),
             _ => None,
         }
@@ -384,6 +394,7 @@ impl From<TypeDefData> for Option<Def> {
                 parent: data.parent.map(|id| From::from(id)),
                 decl_id: None,
                 docs: String::new(),
+                sig: None,
             }),
             _ => None,
         }
@@ -408,6 +419,7 @@ impl From<VariableData> for Option<Def> {
                 parent: data.parent.map(|id| From::from(id)),
                 decl_id: None,
                 docs: data.docs,
+                sig: None,
             }),
             _ => None,
         }
diff --git a/src/librustc_save_analysis/json_dumper.rs b/src/librustc_save_analysis/json_dumper.rs
index f97272ad544..3abb19d5384 100644
--- a/src/librustc_save_analysis/json_dumper.rs
+++ b/src/librustc_save_analysis/json_dumper.rs
@@ -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: None,
         };
         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<Signature>,
 }
 
 #[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: None,
         }
     }
 }
@@ -280,6 +283,7 @@ impl From<TupleVariantData> for Def {
             children: vec![],
             decl_id: None,
             docs: data.docs,
+            sig: None,
         }
     }
 }
@@ -295,6 +299,7 @@ impl From<StructVariantData> for Def {
             children: vec![],
             decl_id: None,
             docs: data.docs,
+            sig: None,
         }
     }
 }
@@ -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(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: None,
         }
     }
 }
@@ -340,6 +347,7 @@ impl From<FunctionData> for Def {
             children: vec![],
             decl_id: None,
             docs: data.docs,
+            sig: None,
         }
     }
 }
@@ -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: None,
         }
     }
 }
@@ -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: None,
         }
     }
 }
@@ -406,6 +416,7 @@ impl From<VariableData> for Def {
             children: vec![],
             decl_id: None,
             docs: data.docs,
+            sig: None,
         }
     }
 }
diff --git a/src/librustc_save_analysis/span_utils.rs b/src/librustc_save_analysis/span_utils.rs
index e06aefd865f..d09f7375500 100644
--- a/src/librustc_save_analysis/span_utils.rs
+++ b/src/librustc_save_analysis/span_utils.rs
@@ -18,8 +18,7 @@ use std::path::Path;
 
 use syntax::ast;
 use syntax::parse::lexer::{self, Reader, StringReader};
-use syntax::parse::token::{self, Token};
-use syntax::symbol::keywords;
+use syntax::tokenstream::TokenTree;
 use syntax_pos::*;
 
 #[derive(Clone)]
@@ -87,6 +86,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));
+        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 +313,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) -> Option<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 => { return None; }
+                    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 Some(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 Some(self.snippet(mk_sp(first_span.lo, prev.get_span().hi)));
+                }
+            }
+            prev = tok;
+        }
+        None
+    }
+
     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();