]> git.lizzy.rs Git - rust.git/commitdiff
save-analysis: add `Signature` info to structs
authorNick Cameron <ncameron@mozilla.com>
Sun, 20 Nov 2016 18:07:40 +0000 (07:07 +1300)
committerNick Cameron <ncameron@mozilla.com>
Thu, 22 Dec 2016 02:17:04 +0000 (15:17 +1300)
src/librustc_save_analysis/data.rs
src/librustc_save_analysis/dump_visitor.rs
src/librustc_save_analysis/external_data.rs
src/librustc_save_analysis/json_api_dumper.rs
src/librustc_save_analysis/json_dumper.rs
src/librustc_save_analysis/span_utils.rs

index fc235aaf9276b7450fa4cfec91e900776573fb80..42fdb6a4dd750777eb257fa8b0eef93cb04028cf 100644 (file)
@@ -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,
+}
index afa78a05a63a897c4a49ca447b4f326c3e22808c..a77527cf8bbc40bf1065a5609ecf31a879b2f2ff 100644 (file)
@@ -619,6 +619,9 @@ fn process_struct(&mut self,
         };
 
         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 @@ fn process_struct(&mut self,
                 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 @@ fn process_struct(&mut self,
         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,
index 5847575742342680efc3ed8742c77c1f44c8f436..d35b1bac78f348814c899a61a80e8977d8672f3a 100644 (file)
@@ -15,7 +15,7 @@
 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 @@ fn lower(self, tcx: TyCtxt) -> 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 @@ fn lower(self, tcx: TyCtxt) -> 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,
+        }
+    }
+}
index d56aae18a7cd1f65e49a64d55bacc1acbf47082b..118d2273c13af0b0ebdf82ec78754ece9bc6611f 100644 (file)
@@ -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 @@ fn from(data: EnumData) -> 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 @@ fn from(data: TupleVariantData) -> Option<Def> {
             children: vec![],
             decl_id: None,
             docs: data.docs,
+            sig: None,
         })
     }
 }
@@ -256,6 +259,7 @@ fn from(data: StructVariantData) -> Option<Def> {
             children: vec![],
             decl_id: None,
             docs: data.docs,
+            sig: None,
         })
     }
 }
@@ -273,6 +277,7 @@ fn from(data: StructData) -> 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 @@ fn from(data: TraitData) -> Option<Def> {
                 parent: None,
                 decl_id: None,
                 docs: data.docs,
+                sig: None,
             }),
             _ => None,
         }
@@ -311,6 +317,7 @@ fn from(data: FunctionData) -> Option<Def> {
                 parent: data.parent.map(|id| From::from(id)),
                 decl_id: None,
                 docs: data.docs,
+                sig: None,
             }),
             _ => None,
         }
@@ -330,6 +337,7 @@ fn from(data: MethodData) -> 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 @@ fn from(data: MacroData) -> Option<Def> {
             parent: None,
             decl_id: None,
             docs: data.docs,
+            sig: None,
         })
     }
 }
@@ -365,6 +374,7 @@ fn from(data:ModData) -> Option<Def> {
                 parent: None,
                 decl_id: None,
                 docs: data.docs,
+                sig: None,
             }),
             _ => None,
         }
@@ -384,6 +394,7 @@ fn from(data: TypeDefData) -> Option<Def> {
                 parent: data.parent.map(|id| From::from(id)),
                 decl_id: None,
                 docs: String::new(),
+                sig: None,
             }),
             _ => None,
         }
@@ -408,6 +419,7 @@ fn from(data: VariableData) -> Option<Def> {
                 parent: data.parent.map(|id| From::from(id)),
                 decl_id: None,
                 docs: data.docs,
+                sig: None,
             }),
             _ => None,
         }
index f97272ad5440960a7d112fa3b4f8f4138ee89245..3abb19d53841419fbe00dc523347e5d4193f3a81 100644 (file)
@@ -86,6 +86,7 @@ fn mod_data(&mut self, data: ModData) {
             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 @@ fn from(data: EnumData) -> Def {
             children: data.variants.into_iter().map(|id| From::from(id)).collect(),
             decl_id: None,
             docs: data.docs,
+            sig: None,
         }
     }
 }
@@ -280,6 +283,7 @@ fn from(data: TupleVariantData) -> Def {
             children: vec![],
             decl_id: None,
             docs: data.docs,
+            sig: None,
         }
     }
 }
@@ -295,6 +299,7 @@ fn from(data: StructVariantData) -> Def {
             children: vec![],
             decl_id: None,
             docs: data.docs,
+            sig: None,
         }
     }
 }
@@ -310,6 +315,7 @@ fn from(data: StructData) -> 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 @@ fn from(data: TraitData) -> Def {
             children: data.items.into_iter().map(|id| From::from(id)).collect(),
             decl_id: None,
             docs: data.docs,
+            sig: None,
         }
     }
 }
@@ -340,6 +347,7 @@ fn from(data: FunctionData) -> Def {
             children: vec![],
             decl_id: None,
             docs: data.docs,
+            sig: None,
         }
     }
 }
@@ -355,6 +363,7 @@ fn from(data: MethodData) -> Def {
             children: vec![],
             decl_id: data.decl_id.map(|id| From::from(id)),
             docs: data.docs,
+            sig: None,
         }
     }
 }
@@ -370,10 +379,10 @@ fn from(data: MacroData) -> 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 @@ fn from(data: TypeDefData) -> Def {
             children: vec![],
             decl_id: None,
             docs: String::new(),
+            sig: None,
         }
     }
 }
@@ -406,6 +416,7 @@ fn from(data: VariableData) -> Def {
             children: vec![],
             decl_id: None,
             docs: data.docs,
+            sig: None,
         }
     }
 }
index e06aefd865f1ba6486c1dadf5ab4bb10081f0f84..d09f73755009a8cbbe82eb725e7169a3dfd66697 100644 (file)
@@ -18,8 +18,7 @@
 
 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 @@ pub fn retokenise_span(&self, span: Span) -> StringReader<'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 @@ pub fn spans_with_brackets(&self, span: Span, nesting: isize, limit: isize) -> V
         }
     }
 
+    /// `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();