pub fields: Vec<NodeId>,
pub visibility: Visibility,
pub docs: String,
+ pub sig: Signature,
}
#[derive(Debug, RustcEncodable)]
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,
+}
};
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,
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);
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,
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 {
pub fields: Vec<DefId>,
pub visibility: Visibility,
pub docs: String,
+ pub sig: Signature,
}
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),
}
}
}
}
}
}
+
+#[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,
+ }
+ }
+}
children: Vec<Id>,
decl_id: Option<Id>,
docs: String,
+ sig: Option<Signature>,
}
#[derive(Debug, RustcEncodable)]
children: data.variants.into_iter().map(|id| From::from(id)).collect(),
decl_id: None,
docs: data.docs,
+ sig: None,
}),
_ => None,
}
children: vec![],
decl_id: None,
docs: data.docs,
+ sig: None,
})
}
}
children: vec![],
decl_id: None,
docs: data.docs,
+ sig: None,
})
}
}
children: data.fields.into_iter().map(|id| From::from(id)).collect(),
decl_id: None,
docs: data.docs,
+ sig: Some(data.sig),
}),
_ => None,
}
parent: None,
decl_id: None,
docs: data.docs,
+ sig: None,
}),
_ => None,
}
parent: data.parent.map(|id| From::from(id)),
decl_id: None,
docs: data.docs,
+ sig: None,
}),
_ => None,
}
parent: data.parent.map(|id| From::from(id)),
decl_id: data.decl_id.map(|id| From::from(id)),
docs: data.docs,
+ sig: None,
}),
_ => None,
}
parent: None,
decl_id: None,
docs: data.docs,
+ sig: None,
})
}
}
parent: None,
decl_id: None,
docs: data.docs,
+ sig: None,
}),
_ => None,
}
parent: data.parent.map(|id| From::from(id)),
decl_id: None,
docs: String::new(),
+ sig: None,
}),
_ => None,
}
parent: data.parent.map(|id| From::from(id)),
decl_id: None,
docs: data.docs,
+ sig: None,
}),
_ => None,
}
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
children: Vec<Id>,
decl_id: Option<Id>,
docs: String,
+ sig: Option<Signature>,
}
#[derive(Debug, RustcEncodable)]
children: data.variants.into_iter().map(|id| From::from(id)).collect(),
decl_id: None,
docs: data.docs,
+ sig: None,
}
}
}
children: vec![],
decl_id: None,
docs: data.docs,
+ sig: None,
}
}
}
children: vec![],
decl_id: None,
docs: data.docs,
+ sig: None,
}
}
}
children: data.fields.into_iter().map(|id| From::from(id)).collect(),
decl_id: None,
docs: data.docs,
+ sig: Some(data.sig),
}
}
}
children: data.items.into_iter().map(|id| From::from(id)).collect(),
decl_id: None,
docs: data.docs,
+ sig: None,
}
}
}
children: vec![],
decl_id: None,
docs: data.docs,
+ sig: None,
}
}
}
children: vec![],
decl_id: data.decl_id.map(|id| From::from(id)),
docs: data.docs,
+ sig: None,
}
}
}
children: vec![],
decl_id: None,
docs: data.docs,
+ sig: None,
}
}
}
-
impl From<TypeDefData> for Def {
fn from(data: TypeDefData) -> Def {
Def {
children: vec![],
decl_id: None,
docs: String::new(),
+ sig: None,
}
}
}
children: vec![],
decl_id: None,
docs: data.docs,
+ sig: None,
}
}
}
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)]
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;
}
}
+ /// `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();