diff --git a/src/librustc_trans/save/csv_dumper.rs b/src/librustc_trans/save/csv_dumper.rs new file mode 100644 index 0000000000000..2a5b7d9567be7 --- /dev/null +++ b/src/librustc_trans/save/csv_dumper.rs @@ -0,0 +1,566 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::io::Write; + +use middle::def_id::{DefId, DefIndex}; +use syntax::codemap::Span; + +use super::data::*; +use super::dump::Dump; +use super::span_utils::SpanUtils; + +pub struct CsvDumper<'a, 'b, W: 'b> { + output: &'b mut W, + dump_spans: bool, + span: SpanUtils<'a> +} + +impl<'a, 'b, W: Write> CsvDumper<'a, 'b, W> { + pub fn new(writer: &'b mut W, span: SpanUtils<'a>) -> CsvDumper<'a, 'b, W> { + CsvDumper { output: writer, dump_spans: false, span: span } + } + + fn record(&mut self, kind: &str, span: Span, values: String) { + let span_str = self.span.extent_str(span); + if let Err(_) = write!(self.output, "{},{}{}\n", kind, span_str, values) { + error!("Error writing output"); + } + } + + fn record_raw(&mut self, info: &str) { + if let Err(_) = write!(self.output, "{}", info) { + error!("Error writing output '{}'", info); + } + } + + pub fn dump_span(&mut self, kind: &str, span: Span) { + assert!(self.dump_spans); + let result = format!("span,kind,{},{},text,\"{}\"\n", + kind, + self.span.extent_str(span), + escape(self.span.snippet(span))); + self.record_raw(&result); + } +} + +impl<'a, 'b, W: Write + 'b> Dump for CsvDumper<'a, 'b, W> { + fn crate_prelude(&mut self, span: Span, data: CratePreludeData) { + let crate_root = data.crate_root.unwrap_or("".to_owned()); + + let values = make_values_str(&[ + ("name", &data.crate_name), + ("crate_root", &crate_root) + ]); + + self.record("crate", span, values); + + for c in data.external_crates { + let num = c.num.to_string(); + let lo_loc = self.span.sess.codemap().lookup_char_pos(span.lo); + let file_name = SpanUtils::make_path_string(&lo_loc.file.name); + let values = make_values_str(&[ + ("name", &c.name), + ("crate", &num), + ("file_name", &file_name) + ]); + + self.record_raw(&format!("external_crate{}\n", values)); + } + + self.record_raw("end_external_crates\n"); + } + + fn enum_data(&mut self, span: Span, data: EnumData) { + if self.dump_spans { + self.dump_span("enum", span); + return; + } + + let id = data.id.to_string(); + let scope = data.scope.to_string(); + let values = make_values_str(&[ + ("id", &id), + ("qualname", &data.qualname), + ("scopeid", &scope), + ("value", &data.value) + ]); + + self.record("enum", data.span, values); + } + + fn extern_crate(&mut self, span: Span, data: ExternCrateData) { + if self.dump_spans { + self.dump_span("extern_crate", span); + return; + } + + let id = data.id.to_string(); + let crate_num = data.crate_num.to_string(); + let scope = data.scope.to_string(); + let values = make_values_str(&[ + ("id", &id), + ("name", &data.name), + ("location", &data.location), + ("crate", &crate_num), + ("scopeid", &scope) + ]); + + self.record("extern_crate", data.span, values); + } + + fn impl_data(&mut self, span: Span, data: ImplData) { + if self.dump_spans { + self.dump_span("impl", span); + return; + } + + let self_ref = data.self_ref.unwrap_or(null_def_id()); + let trait_ref = data.trait_ref.unwrap_or(null_def_id()); + + let id = data.id.to_string(); + let ref_id = self_ref.index.as_usize().to_string(); + let ref_id_crate = self_ref.krate.to_string(); + let trait_id = trait_ref.index.as_usize().to_string(); + let trait_id_crate = trait_ref.krate.to_string(); + let scope = data.scope.to_string(); + let values = make_values_str(&[ + ("id", &id), + ("refid", &ref_id), + ("refidcrate", &ref_id_crate), + ("traitid", &trait_id), + ("traitidcrate", &trait_id_crate), + ("scopeid", &scope) + ]); + + self.record("impl", data.span, values); + } + + fn inheritance(&mut self, data: InheritanceData) { + if self.dump_spans { + return; + } + + let base_id = data.base_id.index.as_usize().to_string(); + let base_crate = data.base_id.krate.to_string(); + let deriv_id = data.deriv_id.to_string(); + let deriv_crate = 0.to_string(); + let values = make_values_str(&[ + ("base", &base_id), + ("basecrate", &base_crate), + ("derived", &deriv_id), + ("derivedcrate", &deriv_crate) + ]); + + self.record("inheritance", data.span, values); + } + + fn function(&mut self, span: Span, data: FunctionData) { + if self.dump_spans { + self.dump_span("function", span); + return; + } + + let (decl_id, decl_crate) = match data.declaration { + Some(id) => (id.index.as_usize().to_string(), id.krate.to_string()), + None => (String::new(), String::new()) + }; + + let id = data.id.to_string(); + let scope = data.scope.to_string(); + let values = make_values_str(&[ + ("id", &id), + ("qualname", &data.qualname), + ("declid", &decl_id), + ("declidcrate", &decl_crate), + ("scopeid", &scope) + ]); + + self.record("function", data.span, values); + } + + fn function_ref(&mut self, span: Span, data: FunctionRefData) { + if self.dump_spans { + self.dump_span("fn_ref", span); + return; + } + + let ref_id = data.ref_id.index.as_usize().to_string(); + let ref_crate = data.ref_id.krate.to_string(); + let scope = data.scope.to_string(); + let values = make_values_str(&[ + ("refid", &ref_id), + ("refidcrate", &ref_crate), + ("qualname", ""), + ("scopeid", &scope) + ]); + + self.record("fn_ref", data.span, values); + } + + fn function_call(&mut self, span: Span, data: FunctionCallData) { + if self.dump_spans { + self.dump_span("fn_call", span); + return; + } + + let ref_id = data.ref_id.index.as_usize().to_string(); + let ref_crate = data.ref_id.krate.to_string(); + let qualname = String::new(); + let scope = data.scope.to_string(); + let values = make_values_str(&[ + ("refid", &ref_id), + ("refidcrate", &ref_crate), + ("qualname", &qualname), + ("scopeid", &scope) + ]); + + self.record("fn_call", data.span, values); + } + + fn method(&mut self, span: Span, data: MethodData) { + if self.dump_spans { + self.dump_span("method_decl", span); + return; + } + + let id = data.id.to_string(); + let scope = data.scope.to_string(); + let values = make_values_str(&[ + ("id", &id), + ("qualname", &data.qualname), + ("scopeid", &scope) + ]); + + self.record("method_decl", span, values); + } + + fn method_call(&mut self, span: Span, data: MethodCallData) { + if self.dump_spans { + self.dump_span("method_call", span); + return; + } + + let (dcn, dck) = match data.decl_id { + Some(declid) => (declid.index.as_usize().to_string(), declid.krate.to_string()), + None => (String::new(), String::new()), + }; + + let ref_id = data.ref_id.unwrap_or(null_def_id()); + + let def_id = ref_id.index.as_usize().to_string(); + let def_crate = ref_id.krate.to_string(); + let scope = data.scope.to_string(); + let values = make_values_str(&[ + ("refid", &def_id), + ("refidcrate", &def_crate), + ("declid", &dcn), + ("declidcrate", &dck), + ("scopeid", &scope) + ]); + + self.record("method_call", data.span, values); + } + + fn macro_data(&mut self, span: Span, data: MacroData) { + if self.dump_spans { + self.dump_span("macro", span); + return; + } + + let values = make_values_str(&[ + ("name", &data.name), + ("qualname", &data.qualname) + ]); + + self.record("macro", data.span, values); + } + + fn macro_use(&mut self, span: Span, data: MacroUseData) { + if self.dump_spans { + self.dump_span("macro_use", span); + return; + } + + let scope = data.scope.to_string(); + let values = make_values_str(&[ + ("callee_name", &data.name), + ("qualname", &data.qualname), + ("scopeid", &scope) + ]); + + self.record("macro_use", data.span, values); + } + + fn mod_data(&mut self, data: ModData) { + if self.dump_spans { + return; + } + + let id = data.id.to_string(); + let scope = data.scope.to_string(); + let values = make_values_str(&[ + ("id", &id), + ("qualname", &data.qualname), + ("scopeid", &scope), + ("def_file", &data.filename) + ]); + + self.record("module", data.span, values); + } + + fn mod_ref(&mut self, span: Span, data: ModRefData) { + if self.dump_spans { + self.dump_span("mod_ref", span); + return; + } + + let (ref_id, ref_crate) = match data.ref_id { + Some(rid) => (rid.index.as_usize().to_string(), rid.krate.to_string()), + None => (0.to_string(), 0.to_string()) + }; + + let scope = data.scope.to_string(); + let values = make_values_str(&[ + ("refid", &ref_id), + ("refidcrate", &ref_crate), + ("qualname", &data.qualname), + ("scopeid", &scope) + ]); + + self.record("mod_ref", data.span, values); + } + + fn struct_data(&mut self, span: Span, data: StructData) { + if self.dump_spans { + self.dump_span("struct", span); + return; + } + + let id = data.id.to_string(); + let ctor_id = data.ctor_id.to_string(); + let scope = data.scope.to_string(); + let values = make_values_str(&[ + ("id", &id), + ("ctor_id", &ctor_id), + ("qualname", &data.qualname), + ("scopeid", &scope), + ("value", &data.value) + ]); + + self.record("struct", data.span, values); + } + + fn struct_variant(&mut self, span: Span, data: StructVariantData) { + if self.dump_spans { + self.dump_span("variant_struct", span); + return; + } + + let id = data.id.to_string(); + let scope = data.scope.to_string(); + let values = make_values_str(&[ + ("id", &id), + ("ctor_id", &id), + ("qualname", &data.qualname), + ("type", &data.type_value), + ("value", &data.value), + ("scopeid", &scope) + ]); + + self.record("variant_struct", data.span, values); + } + + fn trait_data(&mut self, span: Span, data: TraitData) { + if self.dump_spans { + self.dump_span("trait", span); + return; + } + + let id = data.id.to_string(); + let scope = data.scope.to_string(); + let values = make_values_str(&[ + ("id", &id), + ("qualname", &data.qualname), + ("scopeid", &scope), + ("value", &data.value) + ]); + + self.record("trait", data.span, values); + } + + fn tuple_variant(&mut self, span: Span, data: TupleVariantData) { + if self.dump_spans { + self.dump_span("variant", span); + return; + } + + let id = data.id.to_string(); + let scope = data.scope.to_string(); + let values = make_values_str(&[ + ("id", &id), + ("name", &data.name), + ("qualname", &data.qualname), + ("type", &data.type_value), + ("value", &data.value), + ("scopeid", &scope) + ]); + + self.record("variant", data.span, values); + } + + fn type_ref(&mut self, span: Span, data: TypeRefData) { + if self.dump_spans { + self.dump_span("type_ref", span); + return; + } + + let (ref_id, ref_crate) = match data.ref_id { + Some(id) => (id.index.as_usize().to_string(), id.krate.to_string()), + None => (0.to_string(), 0.to_string()) + }; + + let scope = data.scope.to_string(); + let values = make_values_str(&[ + ("refid", &ref_id), + ("refidcrate", &ref_crate), + ("qualname", &data.qualname), + ("scopeid", &scope) + ]); + + self.record("type_ref", data.span, values); + } + + fn typedef(&mut self, span: Span, data: TypedefData) { + if self.dump_spans { + self.dump_span("typedef", span); + return; + } + + let id = data.id.to_string(); + let values = make_values_str(&[ + ("id", &id), + ("qualname", &data.qualname), + ("value", &data.value) + ]); + + self.record("typedef", data.span, values); + } + + fn use_data(&mut self, span: Span, data: UseData) { + if self.dump_spans { + self.dump_span("use_alias", span); + return; + } + + let mod_id = data.mod_id.unwrap_or(null_def_id()); + + let id = data.id.to_string(); + let ref_id = mod_id.index.as_usize().to_string(); + let ref_crate = mod_id.krate.to_string(); + let scope = data.scope.to_string(); + let values = make_values_str(&[ + ("id", &id), + ("refid", &ref_id), + ("refidcrate", &ref_crate), + ("name", &data.name), + ("scopeid", &scope) + ]); + + self.record("use_alias", data.span, values); + } + + fn use_glob(&mut self, span: Span, data: UseGlobData) { + if self.dump_spans { + self.dump_span("use_glob", span); + return; + } + + let names = data.names.join(", "); + + let id = data.id.to_string(); + let scope = data.scope.to_string(); + let values = make_values_str(&[ + ("id", &id), + ("value", &names), + ("scopeid", &scope) + ]); + + self.record("use_glob", data.span, values); + } + + fn variable(&mut self, span: Span, data: VariableData) { + if self.dump_spans { + self.dump_span("variable", span); + return; + } + + let id = data.id.to_string(); + let scope = data.scope.to_string(); + let values = make_values_str(&[ + ("id", &id), + ("name", &data.name), + ("qualname", &data.qualname), + ("value", &data.value), + ("type", &data.type_value), + ("scopeid", &scope) + ]); + + self.record("variable", data.span, values); + } + + fn variable_ref(&mut self, span: Span, data: VariableRefData) { + if self.dump_spans { + self.dump_span("var_ref", span); + return; + } + + let ref_id = data.ref_id.index.as_usize().to_string(); + let ref_crate = data.ref_id.krate.to_string(); + let scope = data.scope.to_string(); + let values = make_values_str(&[ + ("refid", &ref_id), + ("refidcrate", &ref_crate), + ("qualname", ""), + ("scopeid", &scope) + ]); + + self.record("var_ref", data.span, values) + } +} + +// Helper function to escape quotes in a string +fn escape(s: String) -> String { + s.replace("\"", "\"\"") +} + +fn make_values_str(pairs: &[(&'static str, &str)]) -> String { + let pairs = pairs.into_iter().map(|&(f, v)| { + // Never take more than 1020 chars + if v.len() > 1020 { + (f, &v[..1020]) + } else { + (f, v) + } + }); + + let strs = pairs.map(|(f, v)| format!(",{},\"{}\"", f, escape(String::from(v)))); + strs.fold(String::new(), |mut s, ss| { + s.push_str(&ss[..]); + s + }) +} + +fn null_def_id() -> DefId { + DefId { + krate: 0, + index: DefIndex::new(0), + } +} diff --git a/src/librustc_trans/save/data.rs b/src/librustc_trans/save/data.rs new file mode 100644 index 0000000000000..3eaaa3fc4930c --- /dev/null +++ b/src/librustc_trans/save/data.rs @@ -0,0 +1,394 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Structs representing the analysis data from a crate. +//! +//! The `Dump` trait can be used together with `DumpVisitor` in order to +//! retrieve the data from a crate. + +use std::hash::Hasher; + +use middle::def_id::DefId; +use middle::ty; +use syntax::ast::{CrateNum, NodeId}; +use syntax::codemap::Span; + +#[macro_export] +macro_rules! down_cast_data { + ($id:ident, $kind:ident, $this:ident, $sp:expr) => { + let $id = if let super::Data::$kind(data) = $id { + data + } else { + $this.sess.span_bug($sp, &format!("unexpected data kind: {:?}", $id)); + } + }; +} + +pub struct CrateData { + pub name: String, + pub number: u32, +} + +/// Data for any entity in the Rust language. The actual data contained varies +/// with the kind of entity being queried. See the nested structs for details. +#[derive(Debug)] +pub enum Data { + /// Data for Enums. + EnumData(EnumData), + /// Data for extern crates. + ExternCrateData(ExternCrateData), + /// Data about a function call. + FunctionCallData(FunctionCallData), + /// Data for all kinds of functions and methods. + FunctionData(FunctionData), + /// Data about a function ref. + FunctionRefData(FunctionRefData), + /// Data for impls. + ImplData(ImplData2), + /// Data for trait inheritance. + InheritanceData(InheritanceData), + /// Data about a macro declaration. + MacroData(MacroData), + /// Data about a macro use. + MacroUseData(MacroUseData), + /// Data about a method call. + MethodCallData(MethodCallData), + /// Data for method declarations (methods with a body are treated as functions). + MethodData(MethodData), + /// Data for modules. + ModData(ModData), + /// Data for a reference to a module. + ModRefData(ModRefData), + /// Data for a struct declaration. + StructData(StructData), + /// Data for a struct variant. + StructVariantDat(StructVariantData), + /// Data for a trait declaration. + TraitData(TraitData), + /// Data for a tuple variant. + TupleVariantData(TupleVariantData), + /// Data for a typedef. + TypeDefData(TypedefData), + /// Data for a reference to a type or trait. + TypeRefData(TypeRefData), + /// Data for a use statement. + UseData(UseData), + /// Data for a global use statement. + UseGlobData(UseGlobData), + /// Data for local and global variables (consts and statics), and fields. + VariableData(VariableData), + /// Data for the use of some variable (e.g., the use of a local variable, which + /// will refere to that variables declaration). + VariableRefData(VariableRefData), +} + +/// Data for the prelude of a crate. +#[derive(Debug)] +pub struct CratePreludeData { + pub crate_name: String, + pub crate_root: Option, + pub external_crates: Vec +} + +/// Data for external crates in the prelude of a crate. +#[derive(Debug)] +pub struct ExternalCrateData { + pub name: String, + pub num: CrateNum +} + +/// Data for enum declarations. +#[derive(Clone, Debug)] +pub struct EnumData { + pub id: NodeId, + pub value: String, + pub qualname: String, + pub span: Span, + pub scope: NodeId, +} + +/// Data for extern crates. +#[derive(Debug)] +pub struct ExternCrateData { + pub id: NodeId, + pub name: String, + pub crate_num: CrateNum, + pub location: String, + pub span: Span, + pub scope: NodeId, +} + +/// Data about a function call. +#[derive(Debug)] +pub struct FunctionCallData { + pub span: Span, + pub scope: NodeId, + pub ref_id: DefId, +} + +/// Data for all kinds of functions and methods. +#[derive(Clone, Debug)] +pub struct FunctionData { + pub id: NodeId, + pub name: String, + pub qualname: String, + pub declaration: Option, + pub span: Span, + pub scope: NodeId, +} + +/// Data about a function call. +#[derive(Debug)] +pub struct FunctionRefData { + pub span: Span, + pub scope: NodeId, + pub ref_id: DefId, +} + +#[derive(Debug)] +pub struct ImplData { + pub id: NodeId, + pub span: Span, + pub scope: NodeId, + pub trait_ref: Option, + pub self_ref: Option, +} + +#[derive(Debug)] +// FIXME: this struct should not exist. However, removing it requires heavy +// refactoring of dump_visitor.rs. See PR 31838 for more info. +pub struct ImplData2 { + pub id: NodeId, + pub span: Span, + pub scope: NodeId, + // FIXME: I'm not really sure inline data is the best way to do this. Seems + // OK in this case, but generalising leads to returning chunks of AST, which + // feels wrong. + pub trait_ref: Option, + pub self_ref: Option, +} + +#[derive(Debug)] +pub struct InheritanceData { + pub span: Span, + pub base_id: DefId, + pub deriv_id: NodeId +} + +/// Data about a macro declaration. +#[derive(Debug)] +pub struct MacroData { + pub span: Span, + pub name: String, + pub qualname: String, +} + +/// Data about a macro use. +#[derive(Debug)] +pub struct MacroUseData { + pub span: Span, + pub name: String, + pub qualname: String, + // Because macro expansion happens before ref-ids are determined, + // we use the callee span to reference the associated macro definition. + pub callee_span: Span, + pub scope: NodeId, + pub imported: bool, +} + +/// Data about a method call. +#[derive(Debug)] +pub struct MethodCallData { + pub span: Span, + pub scope: NodeId, + pub ref_id: Option, + pub decl_id: Option, +} + +/// Data for method declarations (methods with a body are treated as functions). +#[derive(Clone, Debug)] +pub struct MethodData { + pub id: NodeId, + pub qualname: String, + pub span: Span, + pub scope: NodeId, +} + +/// Data for modules. +#[derive(Debug)] +pub struct ModData { + pub id: NodeId, + pub name: String, + pub qualname: String, + pub span: Span, + pub scope: NodeId, + pub filename: String, +} + +/// Data for a reference to a module. +#[derive(Debug)] +pub struct ModRefData { + pub span: Span, + pub scope: NodeId, + pub ref_id: Option, + pub qualname: String +} + +#[derive(Debug)] +pub struct StructData { + pub span: Span, + pub id: NodeId, + pub ctor_id: NodeId, + pub qualname: String, + pub scope: NodeId, + pub value: String +} + +#[derive(Debug)] +pub struct StructVariantData { + pub span: Span, + pub id: NodeId, + pub qualname: String, + pub type_value: String, + pub value: String, + pub scope: NodeId +} + +#[derive(Debug)] +pub struct TraitData { + pub span: Span, + pub id: NodeId, + pub qualname: String, + pub scope: NodeId, + pub value: String +} + +#[derive(Debug)] +pub struct TupleVariantData { + pub span: Span, + pub id: NodeId, + pub name: String, + pub qualname: String, + pub type_value: String, + pub value: String, + pub scope: NodeId +} + +/// Data for a typedef. +#[derive(Debug)] +pub struct TypedefData { + pub id: NodeId, + pub span: Span, + pub qualname: String, + pub value: String, +} + +/// Data for a reference to a type or trait. +#[derive(Clone, Debug)] +pub struct TypeRefData { + pub span: Span, + pub scope: NodeId, + pub ref_id: Option, + pub qualname: String, +} + +#[derive(Debug)] +pub struct UseData { + pub id: NodeId, + pub span: Span, + pub name: String, + pub mod_id: Option, + pub scope: NodeId +} + +#[derive(Debug)] +pub struct UseGlobData { + pub id: NodeId, + pub span: Span, + pub names: Vec, + pub scope: NodeId +} + +/// Data for local and global variables (consts and statics). +#[derive(Debug)] +pub struct VariableData { + pub id: NodeId, + pub name: String, + pub qualname: String, + pub span: Span, + pub scope: NodeId, + pub value: String, + pub type_value: String, +} + +/// Data for the use of some item (e.g., the use of a local variable, which +/// will refer to that variables declaration (by ref_id)). +#[derive(Debug)] +pub struct VariableRefData { + pub name: String, + pub span: Span, + pub scope: NodeId, + pub ref_id: DefId, +} + +// Emitted ids are used to cross-reference items across crates. DefIds and +// NodeIds do not usually correspond in any way. The strategy is to use the +// index from the DefId as a crate-local id. However, within a crate, DefId +// indices and NodeIds can overlap. So, we must adjust the NodeIds. If an +// item can be identified by a DefId as well as a NodeId, then we use the +// DefId index as the id. If it can't, then we have to use the NodeId, but +// need to adjust it so it will not clash with any possible DefId index. +pub fn normalize_node_id<'a>(tcx: &ty::TyCtxt<'a>, id: NodeId) -> usize { + match tcx.map.opt_local_def_id(id) { + Some(id) => id.index.as_usize(), + None => id as usize + tcx.map.num_local_def_ids() + } +} + +// Macro to implement a normalize() function (see below for usage) +macro_rules! impl_normalize { + ($($t:ty => $($field:ident),*);*) => { + $( + impl $t { + pub fn normalize<'a>(mut self, tcx: &ty::TyCtxt<'a>) -> $t { + $( + self.$field = normalize_node_id(tcx, self.$field) as u32; + )* + self + } + } + )* + } +} + +impl_normalize! { + EnumData => id, scope; + ExternCrateData => id, scope; + FunctionCallData => scope; + FunctionData => id, scope; + FunctionRefData => scope; + ImplData => id, scope; + InheritanceData => deriv_id; + MacroUseData => scope; + MethodCallData => scope; + MethodData => id, scope; + ModData => id, scope; + ModRefData => scope; + StructData => ctor_id, id, scope; + StructVariantData => id, scope; + TupleVariantData => id, scope; + TraitData => id, scope; + TypedefData => id; + TypeRefData => scope; + UseData => id, scope; + UseGlobData => id, scope; + VariableData => id; + VariableRefData => scope +} diff --git a/src/librustc_trans/save/dump.rs b/src/librustc_trans/save/dump.rs new file mode 100644 index 0000000000000..b0cc7926f4e34 --- /dev/null +++ b/src/librustc_trans/save/dump.rs @@ -0,0 +1,40 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use syntax::codemap::Span; + +use super::data::*; + +pub trait Dump { + fn crate_prelude(&mut self, _: Span, _: CratePreludeData) {} + fn enum_data(&mut self, _: Span, _: EnumData) {} + fn extern_crate(&mut self, _: Span, _: ExternCrateData) {} + fn impl_data(&mut self, _: Span, _: ImplData) {} + fn inheritance(&mut self, _: InheritanceData) {} + fn function(&mut self, _: Span, _: FunctionData) {} + fn function_ref(&mut self, _: Span, _: FunctionRefData) {} + fn function_call(&mut self, _: Span, _: FunctionCallData) {} + fn method(&mut self, _: Span, _: MethodData) {} + fn method_call(&mut self, _: Span, _: MethodCallData) {} + fn macro_data(&mut self, _: Span, _: MacroData) {} + fn macro_use(&mut self, _: Span, _: MacroUseData) {} + fn mod_data(&mut self, _: ModData) {} + fn mod_ref(&mut self, _: Span, _: ModRefData) {} + fn struct_data(&mut self, _: Span, _: StructData) {} + fn struct_variant(&mut self, _: Span, _: StructVariantData) {} + fn trait_data(&mut self, _: Span, _: TraitData) {} + fn tuple_variant(&mut self, _: Span, _: TupleVariantData) {} + fn type_ref(&mut self, _: Span, _: TypeRefData) {} + fn typedef(&mut self, _: Span, _: TypedefData) {} + fn use_data(&mut self, _: Span, _: UseData) {} + fn use_glob(&mut self, _: Span, _: UseGlobData) {} + fn variable(&mut self, _: Span, _: VariableData) {} + fn variable_ref(&mut self, _: Span, _: VariableRefData) {} +} diff --git a/src/librustc_trans/save/dump_csv.rs b/src/librustc_trans/save/dump_visitor.rs similarity index 64% rename from src/librustc_trans/save/dump_csv.rs rename to src/librustc_trans/save/dump_visitor.rs index c15d5ca86d026..65f48d1ff5eb5 100644 --- a/src/librustc_trans/save/dump_csv.rs +++ b/src/librustc_trans/save/dump_visitor.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Output a CSV file containing the output from rustc's analysis. The data is +//! Write the output of rustc's analysis to an implementor of Dump. The data is //! primarily designed to be used as input to the DXR tool, specifically its //! Rust plugin. It could also be used by IDEs or other code browsing, search, or //! cross-referencing tools. @@ -23,12 +23,9 @@ //! //! SpanUtils is used to manipulate spans. In particular, to extract sub-spans //! from spans (e.g., the span for `bar` from the above example path). -//! Recorder is used for recording the output in csv format. FmtStrs separates -//! the format of the output away from extracting it from the compiler. -//! DumpCsvVisitor walks the AST and processes it. - - -use super::{escape, generated_code, recorder, SaveContext, PathCollector, Data}; +//! DumpVisitor walks the AST and processes it, and an implementor of Dump +//! is used for recording the output in a format-agnostic way (see CsvDumper +//! for an example). use session::Session; @@ -36,9 +33,8 @@ use middle::def::Def; use middle::def_id::DefId; use middle::ty::{self, TyCtxt}; -use std::fs::File; -use std::hash::*; use std::collections::HashSet; +use std::hash::*; use syntax::ast::{self, NodeId, PatKind}; use syntax::codemap::*; @@ -49,8 +45,11 @@ use syntax::ptr::P; use rustc_front::lowering::{lower_expr, LoweringContext}; +use super::{escape, generated_code, SaveContext, PathCollector}; +use super::data::*; +use super::dump::Dump; use super::span_utils::SpanUtils; -use super::recorder::{Recorder, FmtStrs}; +use super::recorder; macro_rules! down_cast_data { ($id:ident, $kind:ident, $this:ident, $sp:expr) => { @@ -62,14 +61,14 @@ macro_rules! down_cast_data { }; } -pub struct DumpCsvVisitor<'l, 'tcx: 'l> { +pub struct DumpVisitor<'l, 'tcx: 'l, D: 'l> { save_ctxt: SaveContext<'l, 'tcx>, sess: &'l Session, tcx: &'l TyCtxt<'tcx>, analysis: &'l ty::CrateAnalysis<'l>, + dumper: &'l mut D, span: SpanUtils<'l>, - fmt: FmtStrs<'l, 'tcx>, cur_scope: NodeId, @@ -82,25 +81,22 @@ pub struct DumpCsvVisitor<'l, 'tcx: 'l> { } -impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { +impl <'l, 'tcx, D> DumpVisitor<'l, 'tcx, D> +where D: Dump +{ pub fn new(tcx: &'l TyCtxt<'tcx>, lcx: &'l LoweringContext<'l>, analysis: &'l ty::CrateAnalysis<'l>, - output_file: Box) - -> DumpCsvVisitor<'l, 'tcx> { + dumper: &'l mut D) + -> DumpVisitor<'l, 'tcx, D> { let span_utils = SpanUtils::new(&tcx.sess); - DumpCsvVisitor { + DumpVisitor { sess: &tcx.sess, tcx: tcx, save_ctxt: SaveContext::from_span_utils(tcx, lcx, span_utils.clone()), analysis: analysis, + dumper: dumper, span: span_utils.clone(), - fmt: FmtStrs::new(box Recorder { - out: output_file, - dump_spans: false, - }, - span_utils, - tcx), cur_scope: 0, mac_defs: HashSet::new(), mac_uses: HashSet::new(), @@ -108,7 +104,7 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { } fn nest(&mut self, scope_id: NodeId, f: F) - where F: FnOnce(&mut DumpCsvVisitor<'l, 'tcx>) + where F: FnOnce(&mut DumpVisitor<'l, 'tcx, D>) { let parent_scope = self.cur_scope; self.cur_scope = scope_id; @@ -118,22 +114,29 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { pub fn dump_crate_info(&mut self, name: &str, krate: &ast::Crate) { let source_file = self.tcx.sess.local_crate_source_file.as_ref(); - let crate_root = match source_file { - Some(source_file) => match source_file.file_name() { + let crate_root = source_file.map(|source_file| { + match source_file.file_name() { Some(_) => source_file.parent().unwrap().display().to_string(), None => source_file.display().to_string(), - }, - None => "".to_owned(), - }; + } + }); + + // Info about all the external crates referenced from this crate. + let external_crates = self.save_ctxt.get_external_crates().into_iter().map(|c| { + ExternalCrateData { + name: c.name, + num: c.number + } + }).collect(); // The current crate. - self.fmt.crate_str(krate.span, name, &crate_root); + let data = CratePreludeData { + crate_name: name.into(), + crate_root: crate_root, + external_crates: external_crates + }; - // Dump info about all the external crates referenced from this crate. - for c in &self.save_ctxt.get_external_crates() { - self.fmt.external_crate_str(krate.span, &c.name, c.number); - } - self.fmt.recorder.record("end_external_crates\n"); + self.dumper.crate_prelude(krate.span, data); } // Return all non-empty prefixes of a path. @@ -198,7 +201,12 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { } else { qualname.clone() }; - self.fmt.sub_mod_ref_str(path.span, *span, &qualname, self.cur_scope); + self.dumper.mod_ref(path.span, ModRefData { + span: *span, + qualname: qualname, + scope: self.cur_scope, + ref_id: None + }.normalize(&self.tcx)); } } @@ -218,7 +226,12 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { } else { qualname.clone() }; - self.fmt.sub_mod_ref_str(path.span, *span, &qualname, self.cur_scope); + self.dumper.mod_ref(path.span, ModRefData { + span: *span, + qualname: qualname, + scope: self.cur_scope, + ref_id: None + }.normalize(&self.tcx)); } } @@ -234,7 +247,12 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { // write the trait part of the sub-path let (ref span, ref qualname) = sub_paths[len-2]; - self.fmt.sub_type_ref_str(path.span, *span, &qualname); + self.dumper.type_ref(path.span, TypeRefData { + ref_id: None, + span: *span, + qualname: qualname.to_owned(), + scope: 0 + }); // write the other sub-paths if len <= 2 { @@ -242,7 +260,12 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { } let sub_paths = &sub_paths[..len-2]; for &(ref span, ref qualname) in sub_paths { - self.fmt.sub_mod_ref_str(path.span, *span, &qualname, self.cur_scope); + self.dumper.mod_ref(path.span, ModRefData { + span: *span, + qualname: qualname.to_owned(), + scope: self.cur_scope, + ref_id: None + }.normalize(&self.tcx)); } } @@ -260,7 +283,16 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { } } - fn lookup_def_kind(&self, ref_id: NodeId, span: Span) -> Option { + fn process_def_kind(&mut self, + ref_id: NodeId, + span: Span, + sub_span: Option, + def_id: DefId, + scope: NodeId) { + if self.span.filter_generated(sub_span, span) { + return; + } + let def_map = self.tcx.def_map.borrow(); if !def_map.contains_key(&ref_id) { self.sess.span_bug(span, @@ -270,21 +302,46 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { let def = def_map.get(&ref_id).unwrap().full_def(); match def { Def::Mod(_) | - Def::ForeignMod(_) => Some(recorder::ModRef), - Def::Struct(..) => Some(recorder::TypeRef), + Def::ForeignMod(_) => { + self.dumper.mod_ref(span, ModRefData { + span: sub_span.expect("No span found for mod ref"), + ref_id: Some(def_id), + scope: scope, + qualname: String::new() + }.normalize(&self.tcx)); + } + Def::Struct(..) | Def::Enum(..) | Def::TyAlias(..) | Def::AssociatedTy(..) | - Def::Trait(_) => Some(recorder::TypeRef), + Def::Trait(_) => { + self.dumper.type_ref(span, TypeRefData { + span: sub_span.expect("No span found for type ref"), + ref_id: Some(def_id), + scope: scope, + qualname: String::new() + }.normalize(&self.tcx)); + } Def::Static(_, _) | Def::Const(_) | Def::AssociatedConst(..) | Def::Local(..) | Def::Variant(..) | - Def::Upvar(..) => Some(recorder::VarRef), - - Def::Fn(..) => Some(recorder::FnRef), - + Def::Upvar(..) => { + self.dumper.variable_ref(span, VariableRefData { + span: sub_span.expect("No span found for var ref"), + ref_id: def_id, + scope: scope, + name: String::new() + }.normalize(&self.tcx)); + } + Def::Fn(..) => { + self.dumper.function_ref(span, FunctionRefData { + span: sub_span.expect("No span found for fn ref"), + ref_id: def_id, + scope: scope + }.normalize(&self.tcx)); + } Def::SelfTy(..) | Def::Label(_) | Def::TyParam(..) | @@ -292,7 +349,7 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { Def::PrimTy(_) | Def::Err => { self.sess.span_bug(span, - &format!("lookup_def_kind for unexpected item: {:?}", def)); + &format!("process_def_kind for unexpected item: {:?}", def)); } } } @@ -307,12 +364,18 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { let typ = self.tcx.node_types().get(&id).unwrap().to_string(); // get the span only for the name of the variable (I hope the path is only ever a // variable name, but who knows?) - self.fmt.formal_str(p.span, - span_utils.span_for_last_ident(p.span), - id, - qualname, - &path_to_string(p), - &typ); + let sub_span = span_utils.span_for_last_ident(p.span); + if !self.span.filter_generated(sub_span, p.span) { + self.dumper.variable(p.span, VariableData { + id: id, + span: sub_span.expect("No span found for variable"), + name: path_to_string(p), + qualname: format!("{}::{}", qualname, path_to_string(p)), + type_value: typ, + value: String::new(), + scope: 0 + }.normalize(&self.tcx)); + } } } } @@ -328,19 +391,19 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { if let Some(method_data) = self.save_ctxt.get_method_data(id, name, span) { if body.is_some() { - self.fmt.method_str(span, - Some(method_data.span), - method_data.id, - &method_data.qualname, - method_data.declaration, - method_data.scope); + if !self.span.filter_generated(Some(method_data.span), span) { + self.dumper.function(span, method_data.clone().normalize(&self.tcx)); + } self.process_formals(&sig.decl.inputs, &method_data.qualname); } else { - self.fmt.method_decl_str(span, - Some(method_data.span), - method_data.id, - &method_data.qualname, - method_data.scope); + if !self.span.filter_generated(Some(method_data.span), span) { + self.dumper.method(span, MethodData { + id: method_data.id, + span: method_data.span, + scope: method_data.scope, + qualname: method_data.qualname.clone(), + }.normalize(&self.tcx)); + } } self.process_generic_params(&sig.generics, span, &method_data.qualname, id); } @@ -363,25 +426,22 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { fn process_trait_ref(&mut self, trait_ref: &ast::TraitRef) { let trait_ref_data = self.save_ctxt.get_trait_ref_data(trait_ref, self.cur_scope); if let Some(trait_ref_data) = trait_ref_data { - self.fmt.ref_str(recorder::TypeRef, - trait_ref.path.span, - Some(trait_ref_data.span), - trait_ref_data.ref_id, - trait_ref_data.scope); + if !self.span.filter_generated(Some(trait_ref_data.span), trait_ref.path.span) { + self.dumper.type_ref(trait_ref.path.span, trait_ref_data.normalize(&self.tcx)); + } + visit::walk_path(self, &trait_ref.path); } } fn process_struct_field_def(&mut self, field: &ast::StructField, parent_id: NodeId) { let field_data = self.save_ctxt.get_field_data(field, parent_id); - if let Some(field_data) = field_data { - self.fmt.field_str(field.span, - Some(field_data.span), - field_data.id, - &field_data.name, - &field_data.qualname, - &field_data.type_value, - field_data.scope); + if let Some(mut field_data) = field_data { + if !self.span.filter_generated(Some(field_data.span), field.span) { + field_data.scope = normalize_node_id(&self.tcx, field_data.scope) as u32; + field_data.value = String::new(); + self.dumper.variable(field.span, field_data.normalize(&self.tcx)); + } } } @@ -403,7 +463,14 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { prefix, escape(self.span.snippet(param_ss)), id); - self.fmt.typedef_str(full_span, Some(param_ss), param.id, &name, ""); + if !self.span.filter_generated(Some(param_ss), full_span) { + self.dumper.typedef(full_span, TypedefData { + span: param_ss, + id: param.id, + qualname: name, + value: String::new() + }.normalize(&self.tcx)); + } } self.visit_generics(generics); } @@ -415,11 +482,9 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { body: &ast::Block) { if let Some(fn_data) = self.save_ctxt.get_item_data(item) { down_cast_data!(fn_data, FunctionData, self, item.span); - self.fmt.fn_str(item.span, - Some(fn_data.span), - fn_data.id, - &fn_data.qualname, - fn_data.scope); + if !self.span.filter_generated(Some(fn_data.span), item.span) { + self.dumper.function(item.span, fn_data.clone().normalize(&self.tcx)); + } self.process_formals(&decl.inputs, &fn_data.qualname); self.process_generic_params(ty_params, item.span, &fn_data.qualname, item.id); @@ -439,14 +504,11 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { fn process_static_or_const_item(&mut self, item: &ast::Item, typ: &ast::Ty, expr: &ast::Expr) { if let Some(var_data) = self.save_ctxt.get_item_data(item) { down_cast_data!(var_data, VariableData, self, item.span); - self.fmt.static_str(item.span, - Some(var_data.span), - var_data.id, - &var_data.name, - &var_data.qualname, - &var_data.value, - &var_data.type_value, - var_data.scope); + if !self.span.filter_generated(Some(var_data.span), item.span) { + let mut var_data = var_data; + var_data.scope = normalize_node_id(&self.tcx, var_data.scope) as u32; + self.dumper.variable(item.span, var_data.normalize(&self.tcx)); + } } self.visit_ty(&typ); self.visit_expr(expr); @@ -462,14 +524,17 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { let sub_span = self.span.sub_span_after_keyword(span, keywords::Const); - self.fmt.static_str(span, - sub_span, - id, - &name.as_str(), - &qualname, - &self.span.snippet(expr.span), - &ty_to_string(&typ), - self.cur_scope); + if !self.span.filter_generated(sub_span, span) { + self.dumper.variable(span, VariableData { + span: sub_span.expect("No span found for variable"), + id: id, + name: name.to_string(), + qualname: qualname, + value: self.span.snippet(expr.span), + type_value: ty_to_string(&typ), + scope: normalize_node_id(&self.tcx, self.cur_scope) as u32 + }.normalize(&self.tcx)); + } // walk type and init value self.visit_ty(typ); @@ -484,13 +549,17 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { let val = self.span.snippet(item.span); let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Struct); - self.fmt.struct_str(item.span, - sub_span, - item.id, - def.id(), - &qualname, - self.cur_scope, - &val); + if !self.span.filter_generated(sub_span, item.span) { + self.dumper.struct_data(item.span, StructData { + span: sub_span.expect("No span found for struct"), + id: item.id, + ctor_id: def.id(), + qualname: qualname.clone(), + scope: self.cur_scope, + value: val + }.normalize(&self.tcx)); + } + // fields for field in def.fields() { @@ -511,12 +580,10 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { Some(data) => data, }; down_cast_data!(enum_data, EnumData, self, item.span); - self.fmt.enum_str(item.span, - Some(enum_data.span), - enum_data.id, - &enum_data.qualname, - enum_data.scope, - &enum_data.value); + let normalized = enum_data.clone().normalize(&self.tcx); + if !self.span.filter_generated(Some(normalized.span), item.span) { + self.dumper.enum_data(item.span, normalized); + } for variant in &enum_definition.variants { let name = &variant.node.name.name.as_str(); @@ -527,23 +594,31 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { match variant.node.data { ast::VariantData::Struct(..) => { - self.fmt.struct_variant_str(variant.span, - self.span.span_for_first_ident(variant.span), - variant.node.data.id(), - &qualname, - &enum_data.qualname, - &val, - enum_data.scope); + let sub_span = self.span.span_for_first_ident(variant.span); + if !self.span.filter_generated(sub_span, variant.span) { + self.dumper.struct_variant(variant.span, StructVariantData { + span: sub_span.expect("No span found for struct variant"), + id: variant.node.data.id(), + qualname: qualname, + type_value: enum_data.qualname.clone(), + value: val, + scope: enum_data.scope + }.normalize(&self.tcx)); + } } _ => { - self.fmt.tuple_variant_str(variant.span, - self.span.span_for_first_ident(variant.span), - variant.node.data.id(), - name, - &qualname, - &enum_data.qualname, - &val, - enum_data.scope); + let sub_span = self.span.span_for_first_ident(variant.span); + if !self.span.filter_generated(sub_span, variant.span) { + self.dumper.tuple_variant(variant.span, TupleVariantData { + span: sub_span.expect("No span found for tuple variant"), + id: variant.node.data.id(), + name: name.to_string(), + qualname: qualname, + type_value: enum_data.qualname.clone(), + value: val, + scope: enum_data.scope + }.normalize(&self.tcx)); + } } } @@ -567,27 +642,27 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { down_cast_data!(impl_data, ImplData, self, item.span); if let Some(ref self_ref) = impl_data.self_ref { has_self_ref = true; - self.fmt.ref_str(recorder::TypeRef, - item.span, - Some(self_ref.span), - self_ref.ref_id, - self_ref.scope); + if !self.span.filter_generated(Some(self_ref.span), item.span) { + self.dumper.type_ref(item.span, self_ref.clone().normalize(&self.tcx)); + } } if let Some(ref trait_ref_data) = impl_data.trait_ref { - self.fmt.ref_str(recorder::TypeRef, - item.span, - Some(trait_ref_data.span), - trait_ref_data.ref_id, - trait_ref_data.scope); + if !self.span.filter_generated(Some(trait_ref_data.span), item.span) { + self.dumper.type_ref(item.span, trait_ref_data.clone().normalize(&self.tcx)); + } + visit::walk_path(self, &trait_ref.as_ref().unwrap().path); } - self.fmt.impl_str(item.span, - Some(impl_data.span), - impl_data.id, - impl_data.self_ref.map(|data| data.ref_id), - impl_data.trait_ref.map(|data| data.ref_id), - impl_data.scope); + if !self.span.filter_generated(Some(impl_data.span), item.span) { + self.dumper.impl_data(item.span, ImplData { + id: impl_data.id, + span: impl_data.span, + scope: impl_data.scope, + trait_ref: impl_data.trait_ref.map(|d| d.ref_id.unwrap()), + self_ref: impl_data.self_ref.map(|d| d.ref_id.unwrap()) + }.normalize(&self.tcx)); + } } if !has_self_ref { self.visit_ty(&typ); @@ -606,12 +681,15 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { let qualname = format!("::{}", self.tcx.map.path_to_string(item.id)); let val = self.span.snippet(item.span); let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Trait); - self.fmt.trait_str(item.span, - sub_span, - item.id, - &qualname, - self.cur_scope, - &val); + if !self.span.filter_generated(sub_span, item.span) { + self.dumper.trait_data(item.span, TraitData { + span: sub_span.expect("No span found for trait"), + id: item.id, + qualname: qualname.clone(), + scope: self.cur_scope, + value: val + }.normalize(&self.tcx)); + } // super-traits for super_bound in trait_refs.iter() { @@ -625,17 +703,25 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { }; let trait_ref = &trait_ref.trait_ref; - match self.lookup_type_ref(trait_ref.ref_id) { - Some(id) => { - let sub_span = self.span.sub_span_for_type_name(trait_ref.path.span); - self.fmt.ref_str(recorder::TypeRef, - trait_ref.path.span, - sub_span, - id, - self.cur_scope); - self.fmt.inherit_str(trait_ref.path.span, sub_span, id, item.id); + if let Some(id) = self.lookup_type_ref(trait_ref.ref_id) { + let sub_span = self.span.sub_span_for_type_name(trait_ref.path.span); + if !self.span.filter_generated(sub_span, trait_ref.path.span) { + self.dumper.type_ref(trait_ref.path.span, TypeRefData { + span: sub_span.expect("No span found for trait ref"), + ref_id: Some(id), + scope: self.cur_scope, + qualname: String::new() + }.normalize(&self.tcx)); + } + + if !self.span.filter_generated(sub_span, trait_ref.path.span) { + let sub_span = sub_span.expect("No span for inheritance"); + self.dumper.inheritance(InheritanceData { + span: sub_span, + base_id: id, + deriv_id: item.id + }.normalize(&self.tcx)); } - None => (), } } @@ -650,12 +736,9 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { fn process_mod(&mut self, item: &ast::Item) { if let Some(mod_data) = self.save_ctxt.get_item_data(item) { down_cast_data!(mod_data, ModData, self, item.span); - self.fmt.mod_str(item.span, - Some(mod_data.span), - mod_data.id, - &mod_data.qualname, - mod_data.scope, - &mod_data.filename); + if !self.span.filter_generated(Some(mod_data.span), item.span) { + self.dumper.mod_data(mod_data.normalize(&self.tcx)); + } } } @@ -674,31 +757,55 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { self.span.snippet(path.span))) } }; + match path_data { - Data::VariableRefData(ref vrd) => { - self.fmt.ref_str(ref_kind.unwrap_or(recorder::VarRef), - path.span, - Some(vrd.span), - vrd.ref_id, - vrd.scope); + Data::VariableRefData(vrd) => { + // FIXME: this whole block duplicates the code in process_def_kind + if !self.span.filter_generated(Some(vrd.span), path.span) { + match ref_kind { + Some(recorder::TypeRef) => { + self.dumper.type_ref(path.span, TypeRefData { + span: vrd.span, + ref_id: Some(vrd.ref_id), + scope: vrd.scope, + qualname: String::new() + }.normalize(&self.tcx)); + } + Some(recorder::FnRef) => { + self.dumper.function_ref(path.span, FunctionRefData { + span: vrd.span, + ref_id: vrd.ref_id, + scope: vrd.scope + }.normalize(&self.tcx)); + } + Some(recorder::ModRef) => { + self.dumper.mod_ref(path.span, ModRefData { + span: vrd.span, + ref_id: Some(vrd.ref_id), + scope: vrd.scope, + qualname: String::new() + }.normalize(&self.tcx)); + } + Some(recorder::VarRef) | None + => self.dumper.variable_ref(path.span, vrd.normalize(&self.tcx)) + } + } } - Data::TypeRefData(ref trd) => { - self.fmt.ref_str(recorder::TypeRef, - path.span, - Some(trd.span), - trd.ref_id, - trd.scope); + Data::TypeRefData(trd) => { + if !self.span.filter_generated(Some(trd.span), path.span) { + self.dumper.type_ref(path.span, trd.normalize(&self.tcx)); + } } - Data::MethodCallData(ref mcd) => { - self.fmt.meth_call_str(path.span, - Some(mcd.span), - mcd.ref_id, - mcd.decl_id, - mcd.scope); + Data::MethodCallData(mcd) => { + if !self.span.filter_generated(Some(mcd.span), path.span) { + self.dumper.method_call(path.span, mcd.normalize(&self.tcx)); + } } Data::FunctionCallData(fcd) => { - self.fmt.fn_call_str(path.span, Some(fcd.span), fcd.ref_id, fcd.scope); + if !self.span.filter_generated(Some(fcd.span), path.span) { + self.dumper.function_call(path.span, fcd.normalize(&self.tcx)); + } } _ => { self.sess.span_bug(path.span, @@ -739,22 +846,19 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { if let Some(struct_lit_data) = self.save_ctxt.get_expr_data(ex) { down_cast_data!(struct_lit_data, TypeRefData, self, ex.span); - self.fmt.ref_str(recorder::TypeRef, - ex.span, - Some(struct_lit_data.span), - struct_lit_data.ref_id, - struct_lit_data.scope); + if !self.span.filter_generated(Some(struct_lit_data.span), ex.span) { + self.dumper.type_ref(ex.span, struct_lit_data.normalize(&self.tcx)); + } + let scope = self.save_ctxt.enclosing_scope(ex.id); for field in fields { if let Some(field_data) = self.save_ctxt .get_field_ref_data(field, variant, scope) { - self.fmt.ref_str(recorder::VarRef, - field.ident.span, - Some(field_data.span), - field_data.ref_id, - field_data.scope); + if !self.span.filter_generated(Some(field_data.span), field.ident.span) { + self.dumper.variable_ref(field.ident.span, field_data.normalize(&self.tcx)); + } } self.visit_expr(&field.expr) @@ -765,13 +869,11 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { } fn process_method_call(&mut self, ex: &ast::Expr, args: &Vec>) { - if let Some(call_data) = self.save_ctxt.get_expr_data(ex) { - down_cast_data!(call_data, MethodCallData, self, ex.span); - self.fmt.meth_call_str(ex.span, - Some(call_data.span), - call_data.ref_id, - call_data.decl_id, - call_data.scope); + if let Some(mcd) = self.save_ctxt.get_expr_data(ex) { + down_cast_data!(mcd, MethodCallData, self, ex.span); + if !self.span.filter_generated(Some(mcd.span), ex.span) { + self.dumper.method_call(ex.span, mcd.normalize(&self.tcx)); + } } // walk receiver and args @@ -789,7 +891,14 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { for &Spanned { node: ref field, span } in fields { let sub_span = self.span.span_for_first_ident(span); if let Some(f) = variant.find_field_named(field.ident.name) { - self.fmt.ref_str(recorder::VarRef, span, sub_span, f.did, self.cur_scope); + if !self.span.filter_generated(sub_span, span) { + self.dumper.variable_ref(span, VariableRefData { + span: sub_span.expect("No span fund for var ref"), + ref_id: f.did, + scope: self.cur_scope, + name: String::new() + }.normalize(&self.tcx)); + } } self.visit_pat(&field.pat); } @@ -818,12 +927,17 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { // is only ever a variable name, but who knows?). let sub_span = self.span.span_for_last_ident(p.span); // Rust uses the id of the pattern for var lookups, so we'll use it too. - self.fmt.variable_str(p.span, - sub_span, - id, - &path_to_string(p), - &value, - &typ); + if !self.span.filter_generated(sub_span, p.span) { + self.dumper.variable(p.span, VariableData { + span: sub_span.expect("No span found for variable"), + id: id, + name: path_to_string(p), + qualname: format!("{}${}", path_to_string(p), id), + value: value, + type_value: typ, + scope: 0 + }.normalize(&self.tcx)); + } } } @@ -848,21 +962,30 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { && !data.imported { self.mac_defs.insert(data.callee_span); if let Some(sub_span) = self.span.span_for_macro_def_name(data.callee_span) { - self.fmt.macro_str(data.callee_span, sub_span, - data.name.clone(), qualname.clone()); + self.dumper.macro_data(data.callee_span, MacroData { + span: sub_span, + name: data.name.clone(), + qualname: qualname.clone() + }); } } if !self.mac_uses.contains(&data.span) { self.mac_uses.insert(data.span); if let Some(sub_span) = self.span.span_for_macro_use_name(data.span) { - self.fmt.macro_use_str(data.span, sub_span, data.name, - qualname, data.scope); + self.dumper.macro_use(data.span, MacroUseData { + span: sub_span, + name: data.name, + qualname: qualname, + scope: data.scope, + callee_span: data.callee_span, + imported: data.imported + }.normalize(&self.tcx)); } } } } -impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> { +impl<'l, 'tcx, 'v, D: Dump + 'l> Visitor<'v> for DumpVisitor<'l, 'tcx, D> { fn visit_item(&mut self, item: &ast::Item) { use syntax::ast::ItemKind::*; self.process_macro_use(item.span, item.id); @@ -873,14 +996,9 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> { let sub_span = self.span.span_for_last_ident(path.span); let mod_id = match self.lookup_type_ref(item.id) { Some(def_id) => { - match self.lookup_def_kind(item.id, path.span) { - Some(kind) => self.fmt.ref_str(kind, - path.span, - sub_span, - def_id, - self.cur_scope), - None => {} - } + let scope = self.cur_scope; + self.process_def_kind(item.id, path.span, sub_span, def_id, scope); + Some(def_id) } None => None, @@ -894,53 +1012,51 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> { None => sub_span, }; - self.fmt.use_alias_str(path.span, - sub_span, - item.id, - mod_id, - &ident.name.as_str(), - self.cur_scope); + if !self.span.filter_generated(sub_span, path.span) { + self.dumper.use_data(path.span, UseData { + span: sub_span.expect("No span found for use"), + id: item.id, + mod_id: mod_id, + name: ident.name.to_string(), + scope: self.cur_scope + }.normalize(&self.tcx)); + } self.write_sub_paths_truncated(path, true); } ast::ViewPathGlob(ref path) => { // Make a comma-separated list of names of imported modules. - let mut name_string = String::new(); + let mut names = vec![]; let glob_map = &self.analysis.glob_map; let glob_map = glob_map.as_ref().unwrap(); if glob_map.contains_key(&item.id) { for n in glob_map.get(&item.id).unwrap() { - if !name_string.is_empty() { - name_string.push_str(", "); - } - name_string.push_str(&n.as_str()); + names.push(n.to_string()); } } let sub_span = self.span .sub_span_of_token(path.span, token::BinOp(token::Star)); - self.fmt.use_glob_str(path.span, - sub_span, - item.id, - &name_string, - self.cur_scope); + if !self.span.filter_generated(sub_span, path.span) { + self.dumper.use_glob(path.span, UseGlobData { + span: sub_span.expect("No span found for use glob"), + id: item.id, + names: names, + scope: self.cur_scope + }.normalize(&self.tcx)); + } self.write_sub_paths(path, true); } ast::ViewPathList(ref path, ref list) => { for plid in list { match plid.node { ast::PathListItemKind::Ident { id, .. } => { - match self.lookup_type_ref(id) { - Some(def_id) => match self.lookup_def_kind(id, plid.span) { - Some(kind) => { - self.fmt.ref_str(kind, - plid.span, - Some(plid.span), - def_id, - self.cur_scope); - } - None => (), - }, - None => (), + let scope = self.cur_scope; + if let Some(def_id) = self.lookup_type_ref(id) { + self.process_def_kind(id, + plid.span, + Some(plid.span), + def_id, + scope); } } ast::PathListItemKind::Mod { .. } => (), @@ -961,13 +1077,17 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> { Some(cnum) => cnum, None => 0, }; - self.fmt.extern_crate_str(item.span, - alias_span, - item.id, - cnum, - &item.ident.name.as_str(), - &location, - self.cur_scope); + + if !self.span.filter_generated(alias_span, item.span) { + self.dumper.extern_crate(item.span, ExternCrateData { + id: item.id, + name: item.ident.name.to_string(), + crate_num: cnum, + location: location, + span: alias_span.expect("No span found for extern crate"), + scope: self.cur_scope, + }.normalize(&self.tcx)); + } } Fn(ref decl, _, _, _, ref ty_params, ref body) => self.process_fn(item, &decl, ty_params, &body), @@ -994,7 +1114,14 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> { let qualname = format!("::{}", self.tcx.map.path_to_string(item.id)); let value = ty_to_string(&ty); let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Type); - self.fmt.typedef_str(item.span, sub_span, item.id, &qualname, &value); + if !self.span.filter_generated(sub_span, item.span) { + self.dumper.typedef(item.span, TypedefData { + span: sub_span.expect("No span found for typedef"), + id: item.id, + qualname: qualname.clone(), + value: value + }.normalize(&self.tcx)); + } self.visit_ty(&ty); self.process_generic_params(ty_params, item.span, &qualname, item.id); @@ -1065,12 +1192,16 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> { self.process_macro_use(t.span, t.id); match t.node { ast::TyKind::Path(_, ref path) => { - match self.lookup_type_ref(t.id) { - Some(id) => { - let sub_span = self.span.sub_span_for_type_name(t.span); - self.fmt.ref_str(recorder::TypeRef, t.span, sub_span, id, self.cur_scope); + if let Some(id) = self.lookup_type_ref(t.id) { + let sub_span = self.span.sub_span_for_type_name(t.span); + if !self.span.filter_generated(sub_span, t.span) { + self.dumper.type_ref(t.span, TypeRefData { + span: sub_span.expect("No span found for type ref"), + ref_id: Some(id), + scope: self.cur_scope, + qualname: String::new() + }.normalize(&self.tcx)); } - None => (), } self.write_sub_paths_truncated(path, false); @@ -1105,11 +1236,9 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> { if let Some(field_data) = self.save_ctxt.get_expr_data(ex) { down_cast_data!(field_data, VariableRefData, self, ex.span); - self.fmt.ref_str(recorder::VarRef, - ex.span, - Some(field_data.span), - field_data.ref_id, - field_data.scope); + if !self.span.filter_generated(Some(field_data.span), ex.span) { + self.dumper.variable_ref(ex.span, field_data.normalize(&self.tcx)); + } } } ast::ExprKind::TupField(ref sub_ex, idx) => { @@ -1120,11 +1249,14 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> { match *ty { ty::TyStruct(def, _) => { let sub_span = self.span.sub_span_after_token(ex.span, token::Dot); - self.fmt.ref_str(recorder::VarRef, - ex.span, - sub_span, - def.struct_variant().fields[idx.node].did, - self.cur_scope); + if !self.span.filter_generated(sub_span, ex.span) { + self.dumper.variable_ref(ex.span, VariableRefData { + span: sub_span.expect("No span found for var ref"), + ref_id: def.struct_variant().fields[idx.node].did, + scope: self.cur_scope, + name: String::new() + }.normalize(&self.tcx)); + } } ty::TyTuple(_) => {} _ => self.sess.span_bug(ex.span, @@ -1208,7 +1340,17 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> { assert!(p.segments.len() == 1, "qualified path for local variable def in arm"); - self.fmt.variable_str(p.span, Some(p.span), id, &path_to_string(p), &value, "") + if !self.span.filter_generated(Some(p.span), p.span) { + self.dumper.variable(p.span, VariableData { + span: p.span, + id: id, + name: path_to_string(p), + qualname: format!("{}${}", path_to_string(p), id), + value: value, + type_value: String::new(), + scope: 0 + }.normalize(&self.tcx)); + } } Def::Variant(..) | Def::Enum(..) | Def::TyAlias(..) | Def::Struct(..) => { diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs index 7f9f876fad1fa..78e91e00baa71 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -28,13 +28,32 @@ use syntax::parse::token::{self, keywords}; use syntax::visit::{self, Visitor}; use syntax::print::pprust::ty_to_string; -use self::span_utils::SpanUtils; - +mod csv_dumper; +#[macro_use] +mod data; +mod dump; +mod dump_visitor; #[macro_use] pub mod span_utils; -pub mod recorder; -mod dump_csv; +pub use self::csv_dumper::CsvDumper; +pub use self::data::*; +pub use self::dump::Dump; +pub use self::dump_visitor::DumpVisitor; +use self::span_utils::SpanUtils; + +// FIXME this is legacy code and should be removed +pub mod recorder { + pub use self::Row::*; + + #[derive(Copy, Clone, Debug, Eq, PartialEq)] + pub enum Row { + TypeRef, + ModRef, + VarRef, + FnRef, + } +} pub struct SaveContext<'l, 'tcx: 'l> { tcx: &'l TyCtxt<'tcx>, @@ -42,158 +61,10 @@ pub struct SaveContext<'l, 'tcx: 'l> { span_utils: SpanUtils<'l>, } -pub struct CrateData { - pub name: String, - pub number: u32, -} - -/// Data for any entity in the Rust language. The actual data contained varied -/// with the kind of entity being queried. See the nested structs for details. -#[derive(Debug)] -pub enum Data { - /// Data for all kinds of functions and methods. - FunctionData(FunctionData), - /// Data for local and global variables (consts and statics), and fields. - VariableData(VariableData), - /// Data for modules. - ModData(ModData), - /// Data for Enums. - EnumData(EnumData), - /// Data for impls. - ImplData(ImplData), - - /// Data for the use of some variable (e.g., the use of a local variable, which - /// will refere to that variables declaration). - VariableRefData(VariableRefData), - /// Data for a reference to a type or trait. - TypeRefData(TypeRefData), - /// Data for a reference to a module. - ModRefData(ModRefData), - /// Data about a function call. - FunctionCallData(FunctionCallData), - /// Data about a method call. - MethodCallData(MethodCallData), - /// Data about a macro use. - MacroUseData(MacroUseData), -} - -/// Data for all kinds of functions and methods. -#[derive(Debug)] -pub struct FunctionData { - pub id: NodeId, - pub name: String, - pub qualname: String, - pub declaration: Option, - pub span: Span, - pub scope: NodeId, -} - -/// Data for local and global variables (consts and statics). -#[derive(Debug)] -pub struct VariableData { - pub id: NodeId, - pub name: String, - pub qualname: String, - pub span: Span, - pub scope: NodeId, - pub value: String, - pub type_value: String, -} - -/// Data for modules. -#[derive(Debug)] -pub struct ModData { - pub id: NodeId, - pub name: String, - pub qualname: String, - pub span: Span, - pub scope: NodeId, - pub filename: String, -} - -/// Data for enum declarations. -#[derive(Debug)] -pub struct EnumData { - pub id: NodeId, - pub value: String, - pub qualname: String, - pub span: Span, - pub scope: NodeId, -} - -#[derive(Debug)] -pub struct ImplData { - pub id: NodeId, - pub span: Span, - pub scope: NodeId, - // FIXME: I'm not really sure inline data is the best way to do this. Seems - // OK in this case, but generalising leads to returning chunks of AST, which - // feels wrong. - pub trait_ref: Option, - pub self_ref: Option, -} - -/// Data for the use of some item (e.g., the use of a local variable, which -/// will refer to that variables declaration (by ref_id)). -#[derive(Debug)] -pub struct VariableRefData { - pub name: String, - pub span: Span, - pub scope: NodeId, - pub ref_id: DefId, -} - -/// Data for a reference to a type or trait. -#[derive(Debug)] -pub struct TypeRefData { - pub span: Span, - pub scope: NodeId, - pub ref_id: DefId, -} - -/// Data for a reference to a module. -#[derive(Debug)] -pub struct ModRefData { - pub span: Span, - pub scope: NodeId, - pub ref_id: DefId, -} - -/// Data about a function call. -#[derive(Debug)] -pub struct FunctionCallData { - pub span: Span, - pub scope: NodeId, - pub ref_id: DefId, -} - -/// Data about a method call. -#[derive(Debug)] -pub struct MethodCallData { - pub span: Span, - pub scope: NodeId, - pub ref_id: Option, - pub decl_id: Option, -} - -/// Data about a macro use. -#[derive(Debug)] -pub struct MacroUseData { - pub span: Span, - pub name: String, - // Because macro expansion happens before ref-ids are determined, - // we use the callee span to reference the associated macro definition. - pub callee_span: Span, - pub scope: NodeId, - pub imported: bool, -} - macro_rules! option_try( ($e:expr) => (match $e { Some(e) => e, None => return None }) ); - - impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { pub fn new(tcx: &'l TyCtxt<'tcx>, lcx: &'l lowering::LoweringContext<'l>) @@ -325,7 +196,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { TypeRefData { span: sub_span.unwrap(), scope: parent, - ref_id: id, + ref_id: Some(id), + qualname: String::new() // FIXME: generate the real qualname } }); } @@ -340,7 +212,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { .and_then(|tr| self.get_trait_ref_data(tr, parent)); filter!(self.span_utils, sub_span, typ.span, None); - Some(Data::ImplData(ImplData { + Some(Data::ImplData(ImplData2 { id: item.id, span: sub_span.unwrap(), scope: parent, @@ -477,7 +349,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { Some(TypeRefData { span: sub_span.unwrap(), scope: parent, - ref_id: def_id, + ref_id: Some(def_id), + qualname: String::new() // FIXME: generate the real qualname }) }) } @@ -518,7 +391,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { Some(Data::TypeRefData(TypeRefData { span: sub_span.unwrap(), scope: self.enclosing_scope(expr.id), - ref_id: def.did, + ref_id: Some(def.did), + qualname: String::new() // FIXME: generate the real qualname })) } _ => { @@ -586,8 +460,9 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { Def::TyParam(_, _, def_id, _) => { Some(Data::TypeRefData(TypeRefData { span: sub_span.unwrap(), - ref_id: def_id, + ref_id: Some(def_id), scope: self.enclosing_scope(id), + qualname: String::new() // FIXME: generate the real qualname })) } Def::Method(decl_id) => { @@ -635,9 +510,10 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } Def::Mod(def_id) => { Some(Data::ModRefData(ModRefData { - ref_id: def_id, + ref_id: Some(def_id), span: sub_span.unwrap(), scope: self.enclosing_scope(id), + qualname: String::new() // FIXME: generate the real qualname })) } _ => None, @@ -708,6 +584,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { callee_span: mac_span, scope: self.enclosing_scope(id), imported: true, + qualname: String::new()// FIXME: generate the real qualname }); } @@ -717,6 +594,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { callee_span: callee_span, scope: self.enclosing_scope(id), imported: false, + qualname: String::new() // FIXME: generate the real qualname }) } @@ -833,16 +711,16 @@ pub fn process_crate<'l, 'tcx>(tcx: &'l TyCtxt<'tcx>, out_name.push_str(&tcx.sess.opts.cg.extra_filename); out_name.push_str(".csv"); root_path.push(&out_name); - let output_file = match File::create(&root_path) { - Ok(f) => box f, - Err(e) => { - let disp = root_path.display(); - tcx.sess.fatal(&format!("Could not open {}: {}", disp, e)); - } - }; + let mut output_file = File::create(&root_path).unwrap_or_else(|e| { + let disp = root_path.display(); + tcx.sess.fatal(&format!("Could not open {}: {}", disp, e)); + }); root_path.pop(); - let mut visitor = dump_csv::DumpCsvVisitor::new(tcx, lcx, analysis, output_file); + let utils = SpanUtils::new(&tcx.sess); + let mut dumper = CsvDumper::new(&mut output_file, utils); + let mut visitor = DumpVisitor::new(tcx, lcx, analysis, &mut dumper); + // FIXME: we don't write anything! visitor.dump_crate_info(cratename, krate); visit::walk_crate(&mut visitor, krate); diff --git a/src/librustc_trans/save/recorder.rs b/src/librustc_trans/save/recorder.rs deleted file mode 100644 index 7ca2cf998bd2d..0000000000000 --- a/src/librustc_trans/save/recorder.rs +++ /dev/null @@ -1,714 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub use self::Row::*; - -use super::escape; -use super::span_utils::SpanUtils; - -use middle::cstore::LOCAL_CRATE; -use middle::def_id::{CRATE_DEF_INDEX, DefId}; -use middle::ty::TyCtxt; - -use std::io::Write; - -use syntax::ast; -use syntax::ast::NodeId; -use syntax::codemap::*; - -const CRATE_ROOT_DEF_ID: DefId = DefId { - krate: LOCAL_CRATE, - index: CRATE_DEF_INDEX, -}; - -pub struct Recorder { - // output file - pub out: Box, - pub dump_spans: bool, -} - -impl Recorder { - pub fn record(&mut self, info: &str) { - match write!(self.out, "{}", info) { - Err(_) => error!("Error writing output '{}'", info), - _ => (), - } - } - - pub fn dump_span(&mut self, su: SpanUtils, kind: &str, span: Span, _sub_span: Option) { - assert!(self.dump_spans); - let result = format!("span,kind,{},{},text,\"{}\"\n", - kind, - su.extent_str(span), - escape(su.snippet(span))); - self.record(&result[..]); - } -} - -pub struct FmtStrs<'a, 'tcx: 'a> { - pub recorder: Box, - span: SpanUtils<'a>, - tcx: &'a TyCtxt<'tcx>, -} - -macro_rules! s { ($e:expr) => { format!("{}", $e) }} -macro_rules! svec { - ($($e:expr),*) => ({ - // leading _ to allow empty construction without a warning. - let mut _temp = ::std::vec::Vec::new(); - $(_temp.push(s!($e));)* - _temp - }) -} - -// FIXME recorder should operate on super::Data, rather than lots of ad hoc -// data. - -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum Row { - Variable, - Enum, - Variant, - VariantStruct, - Function, - MethodDecl, - Struct, - Trait, - Impl, - Module, - UseAlias, - UseGlob, - ExternCrate, - Inheritance, - MethodCall, - Typedef, - ExternalCrate, - Crate, - FnCall, - ModRef, - VarRef, - TypeRef, - FnRef, - Macro, - MacroUse, -} - -impl<'a, 'tcx: 'a> FmtStrs<'a, 'tcx> { - pub fn new(rec: Box, - span: SpanUtils<'a>, - tcx: &'a TyCtxt<'tcx>) - -> FmtStrs<'a, 'tcx> { - FmtStrs { - recorder: rec, - span: span, - tcx: tcx, - } - } - - // Emitted ids are used to cross-reference items across crates. DefIds and - // NodeIds do not usually correspond in any way. The strategy is to use the - // index from the DefId as a crate-local id. However, within a crate, DefId - // indices and NodeIds can overlap. So, we must adjust the NodeIds. If an - // item can be identified by a DefId as well as a NodeId, then we use the - // DefId index as the id. If it can't, then we have to use the NodeId, but - // need to adjust it so it will not clash with any possible DefId index. - fn normalize_node_id(&self, id: NodeId) -> usize { - match self.tcx.map.opt_local_def_id(id) { - Some(id) => id.index.as_usize(), - None => id as usize + self.tcx.map.num_local_def_ids() - } - } - - // A map from kind of item to a tuple of - // a string representation of the name - // a vector of field names - // whether this kind requires a span - // whether dump_spans should dump for this kind - fn lookup_row(r: Row) -> (&'static str, Vec<&'static str>, bool, bool) { - match r { - Variable => ("variable", - vec!("id", "name", "qualname", "value", "type", "scopeid"), - true, - true), - Enum => ("enum", - vec!("id", "qualname", "scopeid", "value"), - true, - true), - Variant => ("variant", - vec!("id", "name", "qualname", "type", "value", "scopeid"), - true, - true), - VariantStruct => ("variant_struct", - vec!("id", "ctor_id", "qualname", "type", "value", "scopeid"), - true, - true), - Function => ("function", - vec!("id", "qualname", "declid", "declidcrate", "scopeid"), - true, - true), - MethodDecl => ("method_decl", - vec!("id", "qualname", "scopeid"), - true, - true), - Struct => ("struct", - vec!("id", "ctor_id", "qualname", "scopeid", "value"), - true, - true), - Trait => ("trait", - vec!("id", "qualname", "scopeid", "value"), - true, - true), - Impl => ("impl", - vec!("id", - "refid", - "refidcrate", - "traitid", - "traitidcrate", - "scopeid"), - true, - true), - Module => ("module", - vec!("id", "qualname", "scopeid", "def_file"), - true, - false), - UseAlias => ("use_alias", - vec!("id", "refid", "refidcrate", "name", "scopeid"), - true, - true), - UseGlob => ("use_glob", vec!("id", "value", "scopeid"), true, true), - ExternCrate => ("extern_crate", - vec!("id", "name", "location", "crate", "scopeid"), - true, - true), - Inheritance => ("inheritance", - vec!("base", "basecrate", "derived", "derivedcrate"), - true, - false), - MethodCall => ("method_call", - vec!("refid", "refidcrate", "declid", "declidcrate", "scopeid"), - true, - true), - Typedef => ("typedef", vec!("id", "qualname", "value"), true, true), - ExternalCrate => ("external_crate", - vec!("name", "crate", "file_name"), - false, - false), - Crate => ("crate", vec!("name", "crate_root"), true, false), - FnCall => ("fn_call", - vec!("refid", "refidcrate", "qualname", "scopeid"), - true, - true), - ModRef => ("mod_ref", - vec!("refid", "refidcrate", "qualname", "scopeid"), - true, - true), - VarRef => ("var_ref", - vec!("refid", "refidcrate", "qualname", "scopeid"), - true, - true), - TypeRef => ("type_ref", - vec!("refid", "refidcrate", "qualname", "scopeid"), - true, - true), - FnRef => ("fn_ref", - vec!("refid", "refidcrate", "qualname", "scopeid"), - true, - true), - Macro => ("macro", - vec!("name", "qualname"), - true, - true), - MacroUse => ("macro_use", - vec!("callee_name", "qualname", "scopeid"), - true, - true), - } - } - - pub fn make_values_str(&self, - kind: &'static str, - fields: &Vec<&'static str>, - values: Vec, - span: Span) - -> Option { - if values.len() != fields.len() { - self.span.sess.span_bug(span, - &format!("Mismatch between length of fields for '{}', \ - expected '{}', found '{}'", - kind, - fields.len(), - values.len())); - } - - let values = values.iter().map(|s| { - // Never take more than 1020 chars - if s.len() > 1020 { - &s[..1020] - } else { - &s[..] - } - }); - - let pairs = fields.iter().zip(values); - let strs = pairs.map(|(f, v)| format!(",{},\"{}\"", f, escape(String::from(v)))); - Some(strs.fold(String::new(), - |mut s, ss| { - s.push_str(&ss[..]); - s - })) - } - - pub fn record_without_span(&mut self, kind: Row, values: Vec, span: Span) { - let (label, ref fields, needs_span, dump_spans) = FmtStrs::lookup_row(kind); - - if needs_span { - self.span.sess.span_bug(span, - &format!("Called record_without_span for '{}' which does \ - requires a span", - label)); - } - assert!(!dump_spans); - - if self.recorder.dump_spans { - return; - } - - let values_str = match self.make_values_str(label, fields, values, span) { - Some(vs) => vs, - None => return, - }; - - let mut result = String::from(label); - result.push_str(&values_str[..]); - result.push_str("\n"); - self.recorder.record(&result[..]); - } - - pub fn record_with_span(&mut self, - kind: Row, - span: Span, - sub_span: Span, - values: Vec) { - let (label, ref fields, needs_span, dump_spans) = FmtStrs::lookup_row(kind); - - if self.recorder.dump_spans { - if dump_spans { - self.recorder.dump_span(self.span.clone(), label, span, Some(sub_span)); - } - return; - } - - if !needs_span { - self.span.sess.span_bug(span, - &format!("Called record_with_span for '{}' which does not \ - require a span", - label)); - } - - let values_str = match self.make_values_str(label, fields, values, span) { - Some(vs) => vs, - None => return, - }; - let result = format!("{},{}{}\n", - label, - self.span.extent_str(sub_span), - values_str); - self.recorder.record(&result[..]); - } - - pub fn check_and_record(&mut self, - kind: Row, - span: Span, - sub_span: Option, - values: Vec) { - filter!(self.span, sub_span, span); - match sub_span { - Some(sub_span) => self.record_with_span(kind, span, sub_span, values), - None => { - let (label, _, _, _) = FmtStrs::lookup_row(kind); - self.span.report_span_err(label, span); - } - } - } - - pub fn variable_str(&mut self, - span: Span, - sub_span: Option, - id: NodeId, - name: &str, - value: &str, - typ: &str) { - // Getting a fully qualified name for a variable is hard because in - // the local case they can be overridden in one block and there is no nice way - // to refer to such a scope in english, so we just hack it by appending the - // variable def's node id - let mut qualname = String::from(name); - qualname.push_str("$"); - qualname.push_str(&id.to_string()); - let id = self.normalize_node_id(id); - self.check_and_record(Variable, - span, - sub_span, - svec!(id, name, qualname, value, typ, 0)); - } - - // formal parameters - pub fn formal_str(&mut self, - span: Span, - sub_span: Option, - id: NodeId, - fn_name: &str, - name: &str, - typ: &str) { - let mut qualname = String::from(fn_name); - qualname.push_str("::"); - qualname.push_str(name); - let id = self.normalize_node_id(id); - self.check_and_record(Variable, - span, - sub_span, - svec!(id, name, qualname, "", typ, 0)); - } - - // value is the initialising expression of the static if it is not mut, otherwise "". - pub fn static_str(&mut self, - span: Span, - sub_span: Option, - id: NodeId, - name: &str, - qualname: &str, - value: &str, - typ: &str, - scope_id: NodeId) { - let id = self.normalize_node_id(id); - let scope_id = self.normalize_node_id(scope_id); - self.check_and_record(Variable, - span, - sub_span, - svec!(id, name, qualname, value, typ, scope_id)); - } - - pub fn field_str(&mut self, - span: Span, - sub_span: Option, - id: NodeId, - name: &str, - qualname: &str, - typ: &str, - scope_id: NodeId) { - let id = self.normalize_node_id(id); - let scope_id = self.normalize_node_id(scope_id); - self.check_and_record(Variable, - span, - sub_span, - svec!(id, name, qualname, "", typ, scope_id)); - } - - pub fn enum_str(&mut self, - span: Span, - sub_span: Option, - id: NodeId, - name: &str, - scope_id: NodeId, - value: &str) { - let id = self.normalize_node_id(id); - let scope_id = self.normalize_node_id(scope_id); - self.check_and_record(Enum, span, sub_span, svec!(id, name, scope_id, value)); - } - - pub fn tuple_variant_str(&mut self, - span: Span, - sub_span: Option, - id: NodeId, - name: &str, - qualname: &str, - typ: &str, - val: &str, - scope_id: NodeId) { - let id = self.normalize_node_id(id); - let scope_id = self.normalize_node_id(scope_id); - self.check_and_record(Variant, - span, - sub_span, - svec!(id, name, qualname, typ, val, scope_id)); - } - - pub fn struct_variant_str(&mut self, - span: Span, - sub_span: Option, - id: NodeId, - name: &str, - typ: &str, - val: &str, - scope_id: NodeId) { - let id = self.normalize_node_id(id); - let ctor_id = id; - let scope_id = self.normalize_node_id(scope_id); - self.check_and_record(VariantStruct, - span, - sub_span, - svec!(id, ctor_id, name, typ, val, scope_id)); - } - - pub fn fn_str(&mut self, - span: Span, - sub_span: Option, - id: NodeId, - name: &str, - scope_id: NodeId) { - let id = self.normalize_node_id(id); - let scope_id = self.normalize_node_id(scope_id); - self.check_and_record(Function, - span, - sub_span, - svec!(id, name, "", "", scope_id)); - } - - pub fn method_str(&mut self, - span: Span, - sub_span: Option, - id: NodeId, - name: &str, - decl_id: Option, - scope_id: NodeId) { - let id = self.normalize_node_id(id); - let scope_id = self.normalize_node_id(scope_id); - let values = match decl_id { - Some(decl_id) => svec!(id, - name, - decl_id.index.as_usize(), - decl_id.krate, - scope_id), - None => svec!(id, name, "", "", scope_id), - }; - self.check_and_record(Function, span, sub_span, values); - } - - pub fn method_decl_str(&mut self, - span: Span, - sub_span: Option, - id: NodeId, - name: &str, - scope_id: NodeId) { - let id = self.normalize_node_id(id); - let scope_id = self.normalize_node_id(scope_id); - self.check_and_record(MethodDecl, span, sub_span, svec!(id, name, scope_id)); - } - - pub fn struct_str(&mut self, - span: Span, - sub_span: Option, - id: NodeId, - ctor_id: NodeId, - name: &str, - scope_id: NodeId, - value: &str) { - let id = self.normalize_node_id(id); - let scope_id = self.normalize_node_id(scope_id); - let ctor_id = self.normalize_node_id(ctor_id); - self.check_and_record(Struct, - span, - sub_span, - svec!(id, ctor_id, name, scope_id, value)); - } - - pub fn trait_str(&mut self, - span: Span, - sub_span: Option, - id: NodeId, - name: &str, - scope_id: NodeId, - value: &str) { - let id = self.normalize_node_id(id); - let scope_id = self.normalize_node_id(scope_id); - self.check_and_record(Trait, span, sub_span, svec!(id, name, scope_id, value)); - } - - pub fn impl_str(&mut self, - span: Span, - sub_span: Option, - id: NodeId, - ref_id: Option, - trait_id: Option, - scope_id: NodeId) { - let id = self.normalize_node_id(id); - let scope_id = self.normalize_node_id(scope_id); - let ref_id = ref_id.unwrap_or(CRATE_ROOT_DEF_ID); - let trait_id = trait_id.unwrap_or(CRATE_ROOT_DEF_ID); - self.check_and_record(Impl, - span, - sub_span, - svec!(id, - ref_id.index.as_usize(), - ref_id.krate, - trait_id.index.as_usize(), - trait_id.krate, - scope_id)); - } - - pub fn mod_str(&mut self, - span: Span, - sub_span: Option, - id: NodeId, - name: &str, - parent: NodeId, - filename: &str) { - let id = self.normalize_node_id(id); - let parent = self.normalize_node_id(parent); - self.check_and_record(Module, - span, - sub_span, - svec!(id, name, parent, filename)); - } - - pub fn use_alias_str(&mut self, - span: Span, - sub_span: Option, - id: NodeId, - mod_id: Option, - name: &str, - parent: NodeId) { - let id = self.normalize_node_id(id); - let parent = self.normalize_node_id(parent); - let mod_id = mod_id.unwrap_or(CRATE_ROOT_DEF_ID); - self.check_and_record(UseAlias, - span, - sub_span, - svec!(id, mod_id.index.as_usize(), mod_id.krate, name, parent)); - } - - pub fn use_glob_str(&mut self, - span: Span, - sub_span: Option, - id: NodeId, - values: &str, - parent: NodeId) { - let id = self.normalize_node_id(id); - let parent = self.normalize_node_id(parent); - self.check_and_record(UseGlob, span, sub_span, svec!(id, values, parent)); - } - - pub fn extern_crate_str(&mut self, - span: Span, - sub_span: Option, - id: NodeId, - cnum: ast::CrateNum, - name: &str, - loc: &str, - parent: NodeId) { - let id = self.normalize_node_id(id); - let parent = self.normalize_node_id(parent); - self.check_and_record(ExternCrate, - span, - sub_span, - svec!(id, name, loc, cnum, parent)); - } - - pub fn inherit_str(&mut self, - span: Span, - sub_span: Option, - base_id: DefId, - deriv_id: NodeId) { - let deriv_id = self.normalize_node_id(deriv_id); - self.check_and_record(Inheritance, - span, - sub_span, - svec!(base_id.index.as_usize(), base_id.krate, deriv_id, 0)); - } - - pub fn fn_call_str(&mut self, - span: Span, - sub_span: Option, - id: DefId, - scope_id: NodeId) { - let scope_id = self.normalize_node_id(scope_id); - self.check_and_record(FnCall, - span, - sub_span, - svec!(id.index.as_usize(), id.krate, "", scope_id)); - } - - pub fn meth_call_str(&mut self, - span: Span, - sub_span: Option, - defid: Option, - declid: Option, - scope_id: NodeId) { - let scope_id = self.normalize_node_id(scope_id); - let defid = defid.unwrap_or(CRATE_ROOT_DEF_ID); - let (dcn, dck) = match declid { - Some(declid) => (s!(declid.index.as_usize()), s!(declid.krate)), - None => ("".to_string(), "".to_string()), - }; - self.check_and_record(MethodCall, - span, - sub_span, - svec!(defid.index.as_usize(), defid.krate, dcn, dck, scope_id)); - } - - pub fn sub_mod_ref_str(&mut self, span: Span, sub_span: Span, qualname: &str, parent: NodeId) { - let parent = self.normalize_node_id(parent); - self.record_with_span(ModRef, span, sub_span, svec!(0, 0, qualname, parent)); - } - - pub fn typedef_str(&mut self, - span: Span, - sub_span: Option, - id: NodeId, - qualname: &str, - value: &str) { - let id = self.normalize_node_id(id); - self.check_and_record(Typedef, span, sub_span, svec!(id, qualname, value)); - } - - pub fn crate_str(&mut self, span: Span, name: &str, crate_root: &str) { - self.record_with_span(Crate, span, span, svec!(name, crate_root)); - } - - pub fn external_crate_str(&mut self, span: Span, name: &str, num: ast::CrateNum) { - let lo_loc = self.span.sess.codemap().lookup_char_pos(span.lo); - self.record_without_span(ExternalCrate, - svec!(name, num, SpanUtils::make_path_string(&lo_loc.file.name)), - span); - } - - pub fn sub_type_ref_str(&mut self, span: Span, sub_span: Span, qualname: &str) { - self.record_with_span(TypeRef, span, sub_span, svec!(0, 0, qualname, 0)); - } - - // A slightly generic function for a reference to an item of any kind. - pub fn ref_str(&mut self, - kind: Row, - span: Span, - sub_span: Option, - id: DefId, - scope_id: NodeId) { - let scope_id = self.normalize_node_id(scope_id); - self.check_and_record(kind, - span, - sub_span, - svec!(id.index.as_usize(), id.krate, "", scope_id)); - } - - pub fn macro_str(&mut self, span: Span, sub_span: Span, name: String, qualname: String) { - self.record_with_span(Macro, span, sub_span, svec!(name, qualname)); - } - - pub fn macro_use_str(&mut self, - span: Span, - sub_span: Span, - name: String, - qualname: String, - scope_id: NodeId) { - let scope_id = self.normalize_node_id(scope_id); - self.record_with_span(MacroUse, span, sub_span, - svec!(name, qualname, scope_id)); - } -}