From: Nick Cameron Date: Sun, 20 Nov 2016 18:07:40 +0000 (+1300) Subject: save-analysis: add `Signature` info to structs X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=5a6ca7a38dbb34f89c8a0381db5ab23b56f44737;p=rust.git save-analysis: add `Signature` info to structs --- 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, 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, + pub refs: Vec, +} + +/// 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 @@ 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, 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::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, 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, + pub refs: Vec, +} + +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, decl_id: Option, docs: String, + sig: Option, } #[derive(Debug, RustcEncodable)] @@ -221,6 +222,7 @@ fn from(data: EnumData) -> Option { 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 { children: vec![], decl_id: None, docs: data.docs, + sig: None, }) } } @@ -256,6 +259,7 @@ fn from(data: StructVariantData) -> Option { children: vec![], decl_id: None, docs: data.docs, + sig: None, }) } } @@ -273,6 +277,7 @@ fn from(data: StructData) -> Option { 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 { parent: None, decl_id: None, docs: data.docs, + sig: None, }), _ => None, } @@ -311,6 +317,7 @@ fn from(data: FunctionData) -> Option { 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 { 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 { parent: None, decl_id: None, docs: data.docs, + sig: None, }) } } @@ -365,6 +374,7 @@ fn from(data:ModData) -> Option { parent: None, decl_id: None, docs: data.docs, + sig: None, }), _ => None, } @@ -384,6 +394,7 @@ fn from(data: TypeDefData) -> Option { 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 { 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 @@ 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, decl_id: Option, docs: String, + sig: Option, } #[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 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, } } } 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 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 { + 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 { 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 { + 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 { let mut toks = self.retokenise_span(span); let mut prev = toks.real_token();