Auto merge of #33568 - nrc:save-json-2, r=pnkfelix

save-analysis: JSON mk2

cc @aochagavia

r? @pnkfelix
This commit is contained in:
bors 2016-05-14 09:36:52 -07:00
commit 5029a60d83
8 changed files with 536 additions and 83 deletions

View File

@ -331,7 +331,7 @@ impl<'b, W: Write + 'b> Dump for CsvDumper<'b, W> {
self.record("type_ref", data.span, values); self.record("type_ref", data.span, values);
} }
fn typedef(&mut self, data: TypedefData) { fn typedef(&mut self, data: TypeDefData) {
let id = data.id.index.as_u32().to_string(); let id = data.id.index.as_u32().to_string();
let values = make_values_str(&[ let values = make_values_str(&[
("id", &id), ("id", &id),

View File

@ -62,7 +62,7 @@ pub enum Data {
/// Data for a tuple variant. /// Data for a tuple variant.
TupleVariantData(TupleVariantData), TupleVariantData(TupleVariantData),
/// Data for a typedef. /// Data for a typedef.
TypeDefData(TypedefData), TypeDefData(TypeDefData),
/// Data for a reference to a type or trait. /// Data for a reference to a type or trait.
TypeRefData(TypeRefData), TypeRefData(TypeRefData),
/// Data for a use statement. /// Data for a use statement.
@ -97,6 +97,7 @@ pub struct ExternalCrateData {
#[derive(Clone, Debug, RustcEncodable)] #[derive(Clone, Debug, RustcEncodable)]
pub struct EnumData { pub struct EnumData {
pub id: NodeId, pub id: NodeId,
pub name: String,
pub value: String, pub value: String,
pub qualname: String, pub qualname: String,
pub span: Span, pub span: Span,
@ -131,6 +132,7 @@ pub struct FunctionData {
pub declaration: Option<DefId>, pub declaration: Option<DefId>,
pub span: Span, pub span: Span,
pub scope: NodeId, pub scope: NodeId,
pub value: String,
} }
/// Data about a function call. /// Data about a function call.
@ -205,9 +207,11 @@ pub struct MethodCallData {
#[derive(Clone, Debug, RustcEncodable)] #[derive(Clone, Debug, RustcEncodable)]
pub struct MethodData { pub struct MethodData {
pub id: NodeId, pub id: NodeId,
pub name: String,
pub qualname: String, pub qualname: String,
pub span: Span, pub span: Span,
pub scope: NodeId, pub scope: NodeId,
pub value: String,
} }
/// Data for modules. /// Data for modules.
@ -233,6 +237,7 @@ pub struct ModRefData {
#[derive(Debug, RustcEncodable)] #[derive(Debug, RustcEncodable)]
pub struct StructData { pub struct StructData {
pub span: Span, pub span: Span,
pub name: String,
pub id: NodeId, pub id: NodeId,
pub ctor_id: NodeId, pub ctor_id: NodeId,
pub qualname: String, pub qualname: String,
@ -243,6 +248,7 @@ pub struct StructData {
#[derive(Debug, RustcEncodable)] #[derive(Debug, RustcEncodable)]
pub struct StructVariantData { pub struct StructVariantData {
pub span: Span, pub span: Span,
pub name: String,
pub id: NodeId, pub id: NodeId,
pub qualname: String, pub qualname: String,
pub type_value: String, pub type_value: String,
@ -254,6 +260,7 @@ pub struct StructVariantData {
pub struct TraitData { pub struct TraitData {
pub span: Span, pub span: Span,
pub id: NodeId, pub id: NodeId,
pub name: String,
pub qualname: String, pub qualname: String,
pub scope: NodeId, pub scope: NodeId,
pub value: String pub value: String
@ -272,8 +279,9 @@ pub struct TupleVariantData {
/// Data for a typedef. /// Data for a typedef.
#[derive(Debug, RustcEncodable)] #[derive(Debug, RustcEncodable)]
pub struct TypedefData { pub struct TypeDefData {
pub id: NodeId, pub id: NodeId,
pub name: String,
pub span: Span, pub span: Span,
pub qualname: String, pub qualname: String,
pub value: String, pub value: String,

View File

@ -30,7 +30,7 @@ pub trait Dump {
fn trait_data(&mut self, TraitData) {} fn trait_data(&mut self, TraitData) {}
fn tuple_variant(&mut self, TupleVariantData) {} fn tuple_variant(&mut self, TupleVariantData) {}
fn type_ref(&mut self, TypeRefData) {} fn type_ref(&mut self, TypeRefData) {}
fn typedef(&mut self, TypedefData) {} fn typedef(&mut self, TypeDefData) {}
fn use_data(&mut self, UseData) {} fn use_data(&mut self, UseData) {}
fn use_glob(&mut self, UseGlobData) {} fn use_glob(&mut self, UseGlobData) {}
fn variable(&mut self, VariableData) {} fn variable(&mut self, VariableData) {}

View File

@ -39,7 +39,7 @@ use syntax::ast::{self, NodeId, PatKind};
use syntax::codemap::*; use syntax::codemap::*;
use syntax::parse::token::{self, keywords}; use syntax::parse::token::{self, keywords};
use syntax::visit::{self, Visitor}; use syntax::visit::{self, Visitor};
use syntax::print::pprust::{path_to_string, ty_to_string}; use syntax::print::pprust::{path_to_string, ty_to_string, bounds_to_string, generics_to_string};
use syntax::ptr::P; use syntax::ptr::P;
use super::{escape, generated_code, SaveContext, PathCollector}; use super::{escape, generated_code, SaveContext, PathCollector};
@ -388,18 +388,23 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
if let Some(method_data) = self.save_ctxt.get_method_data(id, name, span) { if let Some(method_data) = self.save_ctxt.get_method_data(id, name, span) {
let sig_str = ::make_signature(&sig.decl, &sig.generics);
if body.is_some() { if body.is_some() {
if !self.span.filter_generated(Some(method_data.span), span) { if !self.span.filter_generated(Some(method_data.span), span) {
self.dumper.function(method_data.clone().lower(self.tcx)); let mut data = method_data.clone();
data.value = sig_str;
self.dumper.function(data.lower(self.tcx));
} }
self.process_formals(&sig.decl.inputs, &method_data.qualname); self.process_formals(&sig.decl.inputs, &method_data.qualname);
} else { } else {
if !self.span.filter_generated(Some(method_data.span), span) { if !self.span.filter_generated(Some(method_data.span), span) {
self.dumper.method(MethodData { self.dumper.method(MethodData {
id: method_data.id, id: method_data.id,
name: method_data.name,
span: method_data.span, span: method_data.span,
scope: method_data.scope, scope: method_data.scope,
qualname: method_data.qualname.clone(), qualname: method_data.qualname.clone(),
value: sig_str,
}.lower(self.tcx)); }.lower(self.tcx));
} }
} }
@ -455,16 +460,18 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
let param_sub_spans = self.span.spans_for_ty_params(full_span, let param_sub_spans = self.span.spans_for_ty_params(full_span,
(generics.ty_params.len() as isize)); (generics.ty_params.len() as isize));
for (param, param_ss) in generics.ty_params.iter().zip(param_sub_spans) { for (param, param_ss) in generics.ty_params.iter().zip(param_sub_spans) {
let name = escape(self.span.snippet(param_ss));
// Append $id to name to make sure each one is unique // Append $id to name to make sure each one is unique
let name = format!("{}::{}${}", let qualname = format!("{}::{}${}",
prefix, prefix,
escape(self.span.snippet(param_ss)), name,
id); id);
if !self.span.filter_generated(Some(param_ss), full_span) { if !self.span.filter_generated(Some(param_ss), full_span) {
self.dumper.typedef(TypedefData { self.dumper.typedef(TypeDefData {
span: param_ss, span: param_ss,
name: name,
id: param.id, id: param.id,
qualname: name, qualname: qualname,
value: String::new() value: String::new()
}.lower(self.tcx)); }.lower(self.tcx));
} }
@ -536,18 +543,33 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
self.visit_expr(expr); self.visit_expr(expr);
} }
// FIXME tuple structs should generate tuple-specific data.
fn process_struct(&mut self, fn process_struct(&mut self,
item: &ast::Item, item: &ast::Item,
def: &ast::VariantData, def: &ast::VariantData,
ty_params: &ast::Generics) { ty_params: &ast::Generics) {
let name = item.ident.to_string();
let qualname = format!("::{}", self.tcx.node_path_str(item.id)); let qualname = format!("::{}", self.tcx.node_path_str(item.id));
let val = self.span.snippet(item.span);
let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Struct); let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Struct);
let val = if let ast::ItemKind::Struct(ast::VariantData::Struct(ref fields, _), _) =
item.node {
let fields_str = fields.iter()
.enumerate()
.map(|(i, f)| f.ident.map(|i| i.to_string())
.unwrap_or(i.to_string()))
.collect::<Vec<_>>()
.join(", ");
format!("{} {{ {} }}", name, fields_str)
} else {
String::new()
};
if !self.span.filter_generated(sub_span, item.span) { if !self.span.filter_generated(sub_span, item.span) {
self.dumper.struct_data(StructData { self.dumper.struct_data(StructData {
span: sub_span.expect("No span found for struct"), span: sub_span.expect("No span found for struct"),
id: item.id, id: item.id,
name: name,
ctor_id: def.id(), ctor_id: def.id(),
qualname: qualname.clone(), qualname: qualname.clone(),
scope: self.cur_scope, scope: self.cur_scope,
@ -580,19 +602,26 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
} }
for variant in &enum_definition.variants { for variant in &enum_definition.variants {
let name = &variant.node.name.name.as_str(); let name = variant.node.name.name.to_string();
let mut qualname = enum_data.qualname.clone(); let mut qualname = enum_data.qualname.clone();
qualname.push_str("::"); qualname.push_str("::");
qualname.push_str(name); qualname.push_str(&name);
let val = self.span.snippet(variant.span);
match variant.node.data { match variant.node.data {
ast::VariantData::Struct(..) => { ast::VariantData::Struct(ref fields, _) => {
let sub_span = self.span.span_for_first_ident(variant.span); let sub_span = self.span.span_for_first_ident(variant.span);
let fields_str = fields.iter()
.enumerate()
.map(|(i, f)| f.ident.map(|i| i.to_string())
.unwrap_or(i.to_string()))
.collect::<Vec<_>>()
.join(", ");
let val = format!("{}::{} {{ {} }}", enum_data.name, name, fields_str);
if !self.span.filter_generated(sub_span, variant.span) { if !self.span.filter_generated(sub_span, variant.span) {
self.dumper.struct_variant(StructVariantData { self.dumper.struct_variant(StructVariantData {
span: sub_span.expect("No span found for struct variant"), span: sub_span.expect("No span found for struct variant"),
id: variant.node.data.id(), id: variant.node.data.id(),
name: name,
qualname: qualname, qualname: qualname,
type_value: enum_data.qualname.clone(), type_value: enum_data.qualname.clone(),
value: val, value: val,
@ -600,13 +629,22 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
}.lower(self.tcx)); }.lower(self.tcx));
} }
} }
_ => { ref v => {
let sub_span = self.span.span_for_first_ident(variant.span); let sub_span = self.span.span_for_first_ident(variant.span);
let mut val = format!("{}::{}", enum_data.name, name);
if let &ast::VariantData::Tuple(ref fields, _) = v {
val.push('(');
val.push_str(&fields.iter()
.map(|f| ty_to_string(&f.ty))
.collect::<Vec<_>>()
.join(", "));
val.push(')');
}
if !self.span.filter_generated(sub_span, variant.span) { if !self.span.filter_generated(sub_span, variant.span) {
self.dumper.tuple_variant(TupleVariantData { self.dumper.tuple_variant(TupleVariantData {
span: sub_span.expect("No span found for tuple variant"), span: sub_span.expect("No span found for tuple variant"),
id: variant.node.data.id(), id: variant.node.data.id(),
name: name.to_string(), name: name,
qualname: qualname, qualname: qualname,
type_value: enum_data.qualname.clone(), type_value: enum_data.qualname.clone(),
value: val, value: val,
@ -672,13 +710,22 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
generics: &ast::Generics, generics: &ast::Generics,
trait_refs: &ast::TyParamBounds, trait_refs: &ast::TyParamBounds,
methods: &[ast::TraitItem]) { methods: &[ast::TraitItem]) {
let name = item.ident.to_string();
let qualname = format!("::{}", self.tcx.node_path_str(item.id)); let qualname = format!("::{}", self.tcx.node_path_str(item.id));
let val = self.span.snippet(item.span); let mut val = name.clone();
if !generics.lifetimes.is_empty() || !generics.ty_params.is_empty() {
val.push_str(&generics_to_string(generics));
}
if !trait_refs.is_empty() {
val.push_str(": ");
val.push_str(&bounds_to_string(trait_refs));
}
let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Trait); let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Trait);
if !self.span.filter_generated(sub_span, item.span) { if !self.span.filter_generated(sub_span, item.span) {
self.dumper.trait_data(TraitData { self.dumper.trait_data(TraitData {
span: sub_span.expect("No span found for trait"), span: sub_span.expect("No span found for trait"),
id: item.id, id: item.id,
name: name,
qualname: qualname.clone(), qualname: qualname.clone(),
scope: self.cur_scope, scope: self.cur_scope,
value: val value: val
@ -908,13 +955,15 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
self.visit_pat(&p); self.visit_pat(&p);
for &(id, ref p, immut, _) in &collector.collected_paths { for &(id, ref p, immut, _) in &collector.collected_paths {
let value = if immut == ast::Mutability::Immutable { let mut value = if immut == ast::Mutability::Immutable {
value.to_string() value.to_string()
} else { } else {
"<mutable>".to_string() "<mutable>".to_string()
}; };
let types = self.tcx.node_types(); let types = self.tcx.node_types();
let typ = types.get(&id).map(|t| t.to_string()).unwrap_or(String::new()); let typ = types.get(&id).map(|t| t.to_string()).unwrap_or(String::new());
value.push_str(": ");
value.push_str(&typ);
// Get the span only for the name of the variable (I hope the path // Get the span only for the name of the variable (I hope the path
// is only ever a variable name, but who knows?). // is only ever a variable name, but who knows?).
let sub_span = self.span.span_for_last_ident(p.span); let sub_span = self.span.span_for_last_ident(p.span);
@ -1107,8 +1156,9 @@ impl<'v, 'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'v> for DumpVisitor<'l, 'tcx,
let value = ty_to_string(&ty); let value = ty_to_string(&ty);
let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Type); let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Type);
if !self.span.filter_generated(sub_span, item.span) { if !self.span.filter_generated(sub_span, item.span) {
self.dumper.typedef(TypedefData { self.dumper.typedef(TypeDefData {
span: sub_span.expect("No span found for typedef"), span: sub_span.expect("No span found for typedef"),
name: item.ident.to_string(),
id: item.id, id: item.id,
qualname: qualname.clone(), qualname: qualname.clone(),
value: value value: value
@ -1275,13 +1325,13 @@ impl<'v, 'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'v> for DumpVisitor<'l, 'tcx,
} }
ast::ExprKind::ForLoop(ref pattern, ref subexpression, ref block, _) | ast::ExprKind::ForLoop(ref pattern, ref subexpression, ref block, _) |
ast::ExprKind::WhileLet(ref pattern, ref subexpression, ref block, _) => { ast::ExprKind::WhileLet(ref pattern, ref subexpression, ref block, _) => {
let value = self.span.snippet(mk_sp(ex.span.lo, subexpression.span.hi)); let value = self.span.snippet(subexpression.span);
self.process_var_decl(pattern, value); self.process_var_decl(pattern, value);
visit::walk_expr(self, subexpression); visit::walk_expr(self, subexpression);
visit::walk_block(self, block); visit::walk_block(self, block);
} }
ast::ExprKind::IfLet(ref pattern, ref subexpression, ref block, ref opt_else) => { ast::ExprKind::IfLet(ref pattern, ref subexpression, ref block, ref opt_else) => {
let value = self.span.snippet(mk_sp(ex.span.lo, subexpression.span.hi)); let value = self.span.snippet(subexpression.span);
self.process_var_decl(pattern, value); self.process_var_decl(pattern, value);
visit::walk_expr(self, subexpression); visit::walk_expr(self, subexpression);
visit::walk_block(self, block); visit::walk_block(self, block);
@ -1371,7 +1421,7 @@ impl<'v, 'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'v> for DumpVisitor<'l, 'tcx,
fn visit_local(&mut self, l: &ast::Local) { fn visit_local(&mut self, l: &ast::Local) {
self.process_macro_use(l.span, l.id); self.process_macro_use(l.span, l.id);
let value = self.span.snippet(l.span); let value = l.init.as_ref().map(|i| self.span.snippet(i.span)).unwrap_or(String::new());
self.process_var_decl(&l.pat, value); self.process_var_decl(&l.pat, value);
// Just walk the initialiser and type (don't want to walk the pattern again). // Just walk the initialiser and type (don't want to walk the pattern again).

View File

@ -86,6 +86,7 @@ impl Lower for data::CratePreludeData {
pub struct EnumData { pub struct EnumData {
pub id: DefId, pub id: DefId,
pub value: String, pub value: String,
pub name: String,
pub qualname: String, pub qualname: String,
pub span: SpanData, pub span: SpanData,
pub scope: DefId, pub scope: DefId,
@ -97,6 +98,7 @@ impl Lower for data::EnumData {
fn lower(self, tcx: TyCtxt) -> EnumData { fn lower(self, tcx: TyCtxt) -> EnumData {
EnumData { EnumData {
id: make_def_id(self.id, &tcx.map), id: make_def_id(self.id, &tcx.map),
name: self.name,
value: self.value, value: self.value,
qualname: self.qualname, qualname: self.qualname,
span: SpanData::from_span(self.span, tcx.sess.codemap()), span: SpanData::from_span(self.span, tcx.sess.codemap()),
@ -160,6 +162,7 @@ pub struct FunctionData {
pub declaration: Option<DefId>, pub declaration: Option<DefId>,
pub span: SpanData, pub span: SpanData,
pub scope: DefId, pub scope: DefId,
pub value: String,
} }
impl Lower for data::FunctionData { impl Lower for data::FunctionData {
@ -173,6 +176,7 @@ impl Lower for data::FunctionData {
declaration: self.declaration, declaration: self.declaration,
span: SpanData::from_span(self.span, tcx.sess.codemap()), span: SpanData::from_span(self.span, tcx.sess.codemap()),
scope: make_def_id(self.scope, &tcx.map), scope: make_def_id(self.scope, &tcx.map),
value: self.value,
} }
} }
} }
@ -268,7 +272,6 @@ pub struct MacroUseData {
// we use the callee span to reference the associated macro definition. // we use the callee span to reference the associated macro definition.
pub callee_span: SpanData, pub callee_span: SpanData,
pub scope: DefId, pub scope: DefId,
pub imported: bool,
} }
impl Lower for data::MacroUseData { impl Lower for data::MacroUseData {
@ -281,7 +284,6 @@ impl Lower for data::MacroUseData {
qualname: self.qualname, qualname: self.qualname,
callee_span: SpanData::from_span(self.callee_span, tcx.sess.codemap()), callee_span: SpanData::from_span(self.callee_span, tcx.sess.codemap()),
scope: make_def_id(self.scope, &tcx.map), scope: make_def_id(self.scope, &tcx.map),
imported: self.imported,
} }
} }
} }
@ -312,9 +314,11 @@ impl Lower for data::MethodCallData {
#[derive(Clone, Debug, RustcEncodable)] #[derive(Clone, Debug, RustcEncodable)]
pub struct MethodData { pub struct MethodData {
pub id: DefId, pub id: DefId,
pub name: String,
pub qualname: String, pub qualname: String,
pub span: SpanData, pub span: SpanData,
pub scope: DefId, pub scope: DefId,
pub value: String,
} }
impl Lower for data::MethodData { impl Lower for data::MethodData {
@ -323,9 +327,11 @@ impl Lower for data::MethodData {
fn lower(self, tcx: TyCtxt) -> MethodData { fn lower(self, tcx: TyCtxt) -> MethodData {
MethodData { MethodData {
span: SpanData::from_span(self.span, tcx.sess.codemap()), span: SpanData::from_span(self.span, tcx.sess.codemap()),
name: self.name,
scope: make_def_id(self.scope, &tcx.map), scope: make_def_id(self.scope, &tcx.map),
id: make_def_id(self.id, &tcx.map), id: make_def_id(self.id, &tcx.map),
qualname: self.qualname, qualname: self.qualname,
value: self.value,
} }
} }
} }
@ -381,6 +387,7 @@ impl Lower for data::ModRefData {
#[derive(Debug, RustcEncodable)] #[derive(Debug, RustcEncodable)]
pub struct StructData { pub struct StructData {
pub span: SpanData, pub span: SpanData,
pub name: String,
pub id: DefId, pub id: DefId,
pub ctor_id: DefId, pub ctor_id: DefId,
pub qualname: String, pub qualname: String,
@ -394,6 +401,7 @@ impl Lower for data::StructData {
fn lower(self, tcx: TyCtxt) -> StructData { fn lower(self, tcx: TyCtxt) -> StructData {
StructData { StructData {
span: SpanData::from_span(self.span, tcx.sess.codemap()), span: SpanData::from_span(self.span, tcx.sess.codemap()),
name: self.name,
id: make_def_id(self.id, &tcx.map), id: make_def_id(self.id, &tcx.map),
ctor_id: make_def_id(self.ctor_id, &tcx.map), ctor_id: make_def_id(self.ctor_id, &tcx.map),
qualname: self.qualname, qualname: self.qualname,
@ -406,6 +414,7 @@ impl Lower for data::StructData {
#[derive(Debug, RustcEncodable)] #[derive(Debug, RustcEncodable)]
pub struct StructVariantData { pub struct StructVariantData {
pub span: SpanData, pub span: SpanData,
pub name: String,
pub id: DefId, pub id: DefId,
pub qualname: String, pub qualname: String,
pub type_value: String, pub type_value: String,
@ -419,6 +428,7 @@ impl Lower for data::StructVariantData {
fn lower(self, tcx: TyCtxt) -> StructVariantData { fn lower(self, tcx: TyCtxt) -> StructVariantData {
StructVariantData { StructVariantData {
span: SpanData::from_span(self.span, tcx.sess.codemap()), span: SpanData::from_span(self.span, tcx.sess.codemap()),
name: self.name,
id: make_def_id(self.id, &tcx.map), id: make_def_id(self.id, &tcx.map),
qualname: self.qualname, qualname: self.qualname,
type_value: self.type_value, type_value: self.type_value,
@ -431,6 +441,7 @@ impl Lower for data::StructVariantData {
#[derive(Debug, RustcEncodable)] #[derive(Debug, RustcEncodable)]
pub struct TraitData { pub struct TraitData {
pub span: SpanData, pub span: SpanData,
pub name: String,
pub id: DefId, pub id: DefId,
pub qualname: String, pub qualname: String,
pub scope: DefId, pub scope: DefId,
@ -443,6 +454,7 @@ impl Lower for data::TraitData {
fn lower(self, tcx: TyCtxt) -> TraitData { fn lower(self, tcx: TyCtxt) -> TraitData {
TraitData { TraitData {
span: SpanData::from_span(self.span, tcx.sess.codemap()), span: SpanData::from_span(self.span, tcx.sess.codemap()),
name: self.name,
id: make_def_id(self.id, &tcx.map), id: make_def_id(self.id, &tcx.map),
qualname: self.qualname, qualname: self.qualname,
scope: make_def_id(self.scope, &tcx.map), scope: make_def_id(self.scope, &tcx.map),
@ -480,19 +492,21 @@ impl Lower for data::TupleVariantData {
/// Data for a typedef. /// Data for a typedef.
#[derive(Debug, RustcEncodable)] #[derive(Debug, RustcEncodable)]
pub struct TypedefData { pub struct TypeDefData {
pub id: DefId, pub id: DefId,
pub name: String,
pub span: SpanData, pub span: SpanData,
pub qualname: String, pub qualname: String,
pub value: String, pub value: String,
} }
impl Lower for data::TypedefData { impl Lower for data::TypeDefData {
type Target = TypedefData; type Target = TypeDefData;
fn lower(self, tcx: TyCtxt) -> TypedefData { fn lower(self, tcx: TyCtxt) -> TypeDefData {
TypedefData { TypeDefData {
id: make_def_id(self.id, &tcx.map), id: make_def_id(self.id, &tcx.map),
name: self.name,
span: SpanData::from_span(self.span, tcx.sess.codemap()), span: SpanData::from_span(self.span, tcx.sess.codemap()),
qualname: self.qualname, qualname: self.qualname,
value: self.value, value: self.value,

View File

@ -10,6 +10,7 @@
use std::io::Write; use std::io::Write;
use rustc::hir::def_id::DefId;
use rustc_serialize::json::as_json; use rustc_serialize::json::as_json;
use super::external_data::*; use super::external_data::*;
@ -17,66 +18,409 @@ use super::dump::Dump;
pub struct JsonDumper<'b, W: Write + 'b> { pub struct JsonDumper<'b, W: Write + 'b> {
output: &'b mut W, output: &'b mut W,
first: bool, result: Analysis,
} }
impl<'b, W: Write> JsonDumper<'b, W> { impl<'b, W: Write> JsonDumper<'b, W> {
pub fn new(writer: &'b mut W) -> JsonDumper<'b, W> { pub fn new(writer: &'b mut W) -> JsonDumper<'b, W> {
if let Err(_) = write!(writer, "[") { JsonDumper { output: writer, result: Analysis::new() }
error!("Error writing output");
}
JsonDumper { output: writer, first: true }
} }
} }
impl<'b, W: Write> Drop for JsonDumper<'b, W> { impl<'b, W: Write> Drop for JsonDumper<'b, W> {
fn drop(&mut self) { fn drop(&mut self) {
if let Err(_) = write!(self.output, "]") { if let Err(_) = write!(self.output, "{}", as_json(&self.result)) {
error!("Error writing output"); error!("Error writing output");
} }
} }
} }
macro_rules! impl_fn { macro_rules! impl_fn {
($fn_name: ident, $data_type: ident) => { ($fn_name: ident, $data_type: ident, $bucket: ident) => {
fn $fn_name(&mut self, data: $data_type) { fn $fn_name(&mut self, data: $data_type) {
if self.first { self.result.$bucket.push(From::from(data));
self.first = false;
} else {
if let Err(_) = write!(self.output, ",") {
error!("Error writing output");
}
}
if let Err(_) = write!(self.output, "{}", as_json(&data)) {
error!("Error writing output '{}'", as_json(&data));
}
} }
} }
} }
impl<'b, W: Write + 'b> Dump for JsonDumper<'b, W> { impl<'b, W: Write + 'b> Dump for JsonDumper<'b, W> {
impl_fn!(crate_prelude, CratePreludeData); fn crate_prelude(&mut self, data: CratePreludeData) {
impl_fn!(enum_data, EnumData); self.result.prelude = Some(data)
impl_fn!(extern_crate, ExternCrateData); }
impl_fn!(impl_data, ImplData);
impl_fn!(inheritance, InheritanceData); impl_fn!(extern_crate, ExternCrateData, imports);
impl_fn!(function, FunctionData); impl_fn!(use_data, UseData, imports);
impl_fn!(function_ref, FunctionRefData); impl_fn!(use_glob, UseGlobData, imports);
impl_fn!(function_call, FunctionCallData);
impl_fn!(method, MethodData); impl_fn!(enum_data, EnumData, defs);
impl_fn!(method_call, MethodCallData); impl_fn!(tuple_variant, TupleVariantData, defs);
impl_fn!(macro_data, MacroData); impl_fn!(struct_variant, StructVariantData, defs);
impl_fn!(macro_use, MacroUseData); impl_fn!(struct_data, StructData, defs);
impl_fn!(mod_data, ModData); impl_fn!(trait_data, TraitData, defs);
impl_fn!(mod_ref, ModRefData); impl_fn!(function, FunctionData, defs);
impl_fn!(struct_data, StructData); impl_fn!(method, MethodData, defs);
impl_fn!(struct_variant, StructVariantData); impl_fn!(macro_data, MacroData, defs);
impl_fn!(trait_data, TraitData); impl_fn!(mod_data, ModData, defs);
impl_fn!(tuple_variant, TupleVariantData); impl_fn!(typedef, TypeDefData, defs);
impl_fn!(type_ref, TypeRefData); impl_fn!(variable, VariableData, defs);
impl_fn!(typedef, TypedefData);
impl_fn!(use_data, UseData); impl_fn!(function_ref, FunctionRefData, refs);
impl_fn!(use_glob, UseGlobData); impl_fn!(function_call, FunctionCallData, refs);
impl_fn!(variable, VariableData); impl_fn!(method_call, MethodCallData, refs);
impl_fn!(variable_ref, VariableRefData); impl_fn!(mod_ref, ModRefData, refs);
impl_fn!(type_ref, TypeRefData, refs);
impl_fn!(variable_ref, VariableRefData, refs);
impl_fn!(macro_use, MacroUseData, macro_refs);
// FIXME store this instead of throwing it away.
fn impl_data(&mut self, _data: ImplData) {}
fn inheritance(&mut self, _data: InheritanceData) {}
}
// FIXME do we want to change ExternalData to this mode? It will break DXR.
// FIXME methods. The defs have information about possible overriding and the
// refs have decl information (e.g., a trait method where we know the required
// method, but not the supplied method). In both cases, we are currently
// ignoring it.
#[derive(Debug, RustcEncodable)]
struct Analysis {
prelude: Option<CratePreludeData>,
imports: Vec<Import>,
defs: Vec<Def>,
refs: Vec<Ref>,
macro_refs: Vec<MacroRef>,
}
impl Analysis {
fn new() -> Analysis {
Analysis {
prelude: None,
imports: vec![],
defs: vec![],
refs: vec![],
macro_refs: vec![],
}
}
}
// DefId::index is a newtype and so the JSON serialisation is ugly. Therefore
// we use our own Id which is the same, but without the newtype.
#[derive(Debug, RustcEncodable)]
struct Id {
krate: u32,
index: u32,
}
impl From<DefId> for Id {
fn from(id: DefId) -> Id {
Id {
krate: id.krate,
index: id.index.as_u32(),
}
}
}
#[derive(Debug, RustcEncodable)]
struct Import {
kind: ImportKind,
id: Id,
span: SpanData,
name: String,
value: String,
}
#[derive(Debug, RustcEncodable)]
enum ImportKind {
ExternCrate,
Use,
GlobUse,
}
impl From<ExternCrateData> for Import {
fn from(data: ExternCrateData) -> Import {
Import {
kind: ImportKind::ExternCrate,
id: From::from(data.id),
span: data.span,
name: data.name,
value: String::new(),
}
}
}
impl From<UseData> for Import {
fn from(data: UseData) -> Import {
Import {
kind: ImportKind::Use,
id: From::from(data.id),
span: data.span,
name: data.name,
value: String::new(),
}
}
}
impl From<UseGlobData> for Import {
fn from(data: UseGlobData) -> Import {
Import {
kind: ImportKind::GlobUse,
id: From::from(data.id),
span: data.span,
name: "*".to_owned(),
value: data.names.join(", "),
}
}
}
#[derive(Debug, RustcEncodable)]
struct Def {
kind: DefKind,
id: Id,
span: SpanData,
name: String,
qualname: String,
value: String,
}
#[derive(Debug, RustcEncodable)]
enum DefKind {
// value = variant names
Enum,
// value = enum name + variant name + types
Tuple,
// value = [enum name +] name + fields
Struct,
// value = signature
Trait,
// value = type + generics
Function,
// No id, no value.
Macro,
// value = file_name
Mod,
// value = aliased type
Type,
// value = type and init expression
Variable,
}
impl From<EnumData> for Def {
fn from(data: EnumData) -> Def {
Def {
kind: DefKind::Enum,
id: From::from(data.id),
span: data.span,
name: data.name,
qualname: data.qualname,
value: data.value,
}
}
}
impl From<TupleVariantData> for Def {
fn from(data: TupleVariantData) -> Def {
Def {
kind: DefKind::Tuple,
id: From::from(data.id),
span: data.span,
name: data.name,
qualname: data.qualname,
value: data.value,
}
}
}
impl From<StructVariantData> for Def {
fn from(data: StructVariantData) -> Def {
Def {
kind: DefKind::Struct,
id: From::from(data.id),
span: data.span,
name: data.name,
qualname: data.qualname,
value: data.value,
}
}
}
impl From<StructData> for Def {
fn from(data: StructData) -> Def {
Def {
kind: DefKind::Struct,
id: From::from(data.id),
span: data.span,
name: data.name,
qualname: data.qualname,
value: data.value,
}
}
}
impl From<TraitData> for Def {
fn from(data: TraitData) -> Def {
Def {
kind: DefKind::Trait,
id: From::from(data.id),
span: data.span,
name: data.name,
qualname: data.qualname,
value: data.value,
}
}
}
impl From<FunctionData> for Def {
fn from(data: FunctionData) -> Def {
Def {
kind: DefKind::Function,
id: From::from(data.id),
span: data.span,
name: data.name,
qualname: data.qualname,
value: data.value,
}
}
}
impl From<MethodData> for Def {
fn from(data: MethodData) -> Def {
Def {
kind: DefKind::Function,
id: From::from(data.id),
span: data.span,
name: data.name,
qualname: data.qualname,
value: data.value,
}
}
}
impl From<MacroData> for Def {
fn from(data: MacroData) -> Def {
Def {
kind: DefKind::Macro,
id: From::from(null_def_id()),
span: data.span,
name: data.name,
qualname: data.qualname,
value: String::new(),
}
}
}
impl From<ModData> for Def {
fn from(data:ModData) -> Def {
Def {
kind: DefKind::Mod,
id: From::from(data.id),
span: data.span,
name: data.name,
qualname: data.qualname,
value: data.filename,
}
}
}
impl From<TypeDefData> for Def {
fn from(data: TypeDefData) -> Def {
Def {
kind: DefKind::Type,
id: From::from(data.id),
span: data.span,
name: data.name,
qualname: data.qualname,
value: data.value,
}
}
}
impl From<VariableData> for Def {
fn from(data: VariableData) -> Def {
Def {
kind: DefKind::Variable,
id: From::from(data.id),
span: data.span,
name: data.name,
qualname: data.qualname,
value: data.value,
}
}
}
#[derive(Debug, RustcEncodable)]
enum RefKind {
Function,
Mod,
Type,
Variable,
}
#[derive(Debug, RustcEncodable)]
struct Ref {
kind: RefKind,
span: SpanData,
ref_id: Id,
}
impl From<FunctionRefData> for Ref {
fn from(data: FunctionRefData) -> Ref {
Ref {
kind: RefKind::Function,
span: data.span,
ref_id: From::from(data.ref_id),
}
}
}
impl From<FunctionCallData> for Ref {
fn from(data: FunctionCallData) -> Ref {
Ref {
kind: RefKind::Function,
span: data.span,
ref_id: From::from(data.ref_id),
}
}
}
impl From<MethodCallData> for Ref {
fn from(data: MethodCallData) -> Ref {
Ref {
kind: RefKind::Function,
span: data.span,
ref_id: From::from(data.ref_id.or(data.decl_id).unwrap_or(null_def_id())),
}
}
}
impl From<ModRefData> for Ref {
fn from(data: ModRefData) -> Ref {
Ref {
kind: RefKind::Mod,
span: data.span,
ref_id: From::from(data.ref_id.unwrap_or(null_def_id())),
}
}
}
impl From<TypeRefData> for Ref {
fn from(data: TypeRefData) -> Ref {
Ref {
kind: RefKind::Type,
span: data.span,
ref_id: From::from(data.ref_id.unwrap_or(null_def_id())),
}
}
}
impl From<VariableRefData> for Ref {
fn from(data: VariableRefData) -> Ref {
Ref {
kind: RefKind::Variable,
span: data.span,
ref_id: From::from(data.ref_id),
}
}
}
#[derive(Debug, RustcEncodable)]
struct MacroRef {
span: SpanData,
qualname: String,
callee_span: SpanData,
}
impl From<MacroUseData> for MacroRef {
fn from(data: MacroUseData) -> MacroRef {
MacroRef {
span: data.span,
qualname: data.qualname,
callee_span: data.callee_span,
}
}
} }

View File

@ -52,7 +52,7 @@ use syntax::ast::{self, NodeId, PatKind};
use syntax::codemap::*; use syntax::codemap::*;
use syntax::parse::token::{self, keywords}; use syntax::parse::token::{self, keywords};
use syntax::visit::{self, Visitor}; use syntax::visit::{self, Visitor};
use syntax::print::pprust::ty_to_string; use syntax::print::pprust::{ty_to_string, arg_to_string};
pub use self::csv_dumper::CsvDumper; pub use self::csv_dumper::CsvDumper;
pub use self::json_dumper::JsonDumper; pub use self::json_dumper::JsonDumper;
@ -122,11 +122,13 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
pub fn get_item_data(&self, item: &ast::Item) -> Option<Data> { pub fn get_item_data(&self, item: &ast::Item) -> Option<Data> {
match item.node { match item.node {
ast::ItemKind::Fn(..) => { ast::ItemKind::Fn(ref decl, _, _, _, ref generics, _) => {
let name = self.tcx.node_path_str(item.id); let name = self.tcx.node_path_str(item.id);
let qualname = format!("::{}", name); let qualname = format!("::{}", name);
let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Fn); let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Fn);
filter!(self.span_utils, sub_span, item.span, None); filter!(self.span_utils, sub_span, item.span, None);
Some(Data::FunctionData(FunctionData { Some(Data::FunctionData(FunctionData {
id: item.id, id: item.id,
name: name, name: name,
@ -134,6 +136,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
declaration: None, declaration: None,
span: sub_span.unwrap(), span: sub_span.unwrap(),
scope: self.enclosing_scope(item.id), scope: self.enclosing_scope(item.id),
value: make_signature(decl, generics),
})) }))
} }
ast::ItemKind::Static(ref typ, mt, ref expr) => { ast::ItemKind::Static(ref typ, mt, ref expr) => {
@ -190,16 +193,22 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
filename: filename, filename: filename,
})) }))
} }
ast::ItemKind::Enum(..) => { ast::ItemKind::Enum(ref def, _) => {
let enum_name = format!("::{}", self.tcx.node_path_str(item.id)); let name = item.ident.to_string();
let val = self.span_utils.snippet(item.span); let qualname = format!("::{}", self.tcx.node_path_str(item.id));
let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Enum); let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Enum);
filter!(self.span_utils, sub_span, item.span, None); filter!(self.span_utils, sub_span, item.span, None);
let variants_str = def.variants.iter()
.map(|v| v.node.name.to_string())
.collect::<Vec<_>>()
.join(", ");
let val = format!("{}::{{{}}}", name, variants_str);
Some(Data::EnumData(EnumData { Some(Data::EnumData(EnumData {
id: item.id, id: item.id,
name: name,
value: val, value: val,
span: sub_span.unwrap(), span: sub_span.unwrap(),
qualname: enum_name, qualname: qualname,
scope: self.enclosing_scope(item.id), scope: self.enclosing_scope(item.id),
})) }))
} }
@ -353,6 +362,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
declaration: decl_id, declaration: decl_id,
span: sub_span.unwrap(), span: sub_span.unwrap(),
scope: self.enclosing_scope(id), scope: self.enclosing_scope(id),
// FIXME you get better data here by using the visitor.
value: String::new(),
}) })
} }
@ -637,6 +648,35 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
} }
} }
fn make_signature(decl: &ast::FnDecl, generics: &ast::Generics) -> String {
let mut sig = String::new();
if !generics.lifetimes.is_empty() || !generics.ty_params.is_empty() {
sig.push('<');
sig.push_str(&generics.lifetimes.iter()
.map(|l| l.lifetime.name.to_string())
.collect::<Vec<_>>()
.join(", "));
if !generics.lifetimes.is_empty() {
sig.push_str(", ");
}
sig.push_str(&generics.ty_params.iter()
.map(|l| l.ident.to_string())
.collect::<Vec<_>>()
.join(", "));
sig.push_str("> ");
}
sig.push('(');
sig.push_str(&decl.inputs.iter().map(arg_to_string).collect::<Vec<_>>().join(", "));
sig.push(')');
match decl.output {
ast::FunctionRetTy::None(_) => sig.push_str(" -> !"),
ast::FunctionRetTy::Default(_) => {}
ast::FunctionRetTy::Ty(ref t) => sig.push_str(&format!(" -> {}", ty_to_string(t))),
}
sig
}
// An AST visitor for collecting paths from patterns. // An AST visitor for collecting paths from patterns.
struct PathCollector { struct PathCollector {
// The Row field identifies the kind of pattern. // The Row field identifies the kind of pattern.

View File

@ -2030,10 +2030,7 @@ pub enum ItemKind {
/// A struct definition, e.g. `struct Foo<A> {x: A}` /// A struct definition, e.g. `struct Foo<A> {x: A}`
Struct(VariantData, Generics), Struct(VariantData, Generics),
/// Represents a Trait Declaration /// Represents a Trait Declaration
Trait(Unsafety, Trait(Unsafety, Generics, TyParamBounds, Vec<TraitItem>),
Generics,
TyParamBounds,
Vec<TraitItem>),
// Default trait implementations // Default trait implementations
/// ///