save-analysis: add Signature
info to structs
This commit is contained in:
parent
c217ab6c8d
commit
5a6ca7a38d
6 changed files with 139 additions and 6 deletions
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue