Auto merge of #31097 - DanielJCampbell:SaveAnalysis, r=nrc
Also altered the format_args! syntax extension, and \#[derive(debug)], to maintain compatability. r? @ nrc
This commit is contained in:
commit
eceb96b40d
8 changed files with 248 additions and 198 deletions
|
@ -135,6 +135,9 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
|
|||
// always using the first ones. So, only error out if we don't have enough spans.
|
||||
// What could go wrong...?
|
||||
if spans.len() < path.segments.len() {
|
||||
if generated_code(path.span) {
|
||||
return vec!();
|
||||
}
|
||||
error!("Mis-calculated spans for path '{}'. Found {} spans, expected {}. Found spans:",
|
||||
path_to_string(path),
|
||||
spans.len(),
|
||||
|
@ -308,28 +311,26 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
|
|||
id: ast::NodeId,
|
||||
name: ast::Name,
|
||||
span: Span) {
|
||||
if generated_code(span) {
|
||||
return;
|
||||
}
|
||||
|
||||
debug!("process_method: {}:{}", id, name);
|
||||
|
||||
let 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) {
|
||||
|
||||
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);
|
||||
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 body.is_some() {
|
||||
self.fmt.method_str(span,
|
||||
Some(method_data.span),
|
||||
method_data.id,
|
||||
&method_data.qualname,
|
||||
method_data.declaration,
|
||||
method_data.scope);
|
||||
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);
|
||||
}
|
||||
self.process_generic_params(&sig.generics, span, &method_data.qualname, id);
|
||||
}
|
||||
|
||||
// walk arg and return types
|
||||
|
@ -345,8 +346,6 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
|
|||
if let Some(body) = body {
|
||||
self.nest(id, |v| v.visit_block(body));
|
||||
}
|
||||
|
||||
self.process_generic_params(&sig.generics, span, &method_data.qualname, id);
|
||||
}
|
||||
|
||||
fn process_trait_ref(&mut self, trait_ref: &ast::TraitRef) {
|
||||
|
@ -402,17 +401,17 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
|
|||
decl: &ast::FnDecl,
|
||||
ty_params: &ast::Generics,
|
||||
body: &ast::Block) {
|
||||
let 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 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);
|
||||
|
||||
|
||||
self.process_formals(&decl.inputs, &fn_data.qualname);
|
||||
self.process_generic_params(ty_params, item.span, &fn_data.qualname, item.id);
|
||||
self.process_formals(&decl.inputs, &fn_data.qualname);
|
||||
self.process_generic_params(ty_params, item.span, &fn_data.qualname, item.id);
|
||||
}
|
||||
|
||||
for arg in &decl.inputs {
|
||||
self.visit_ty(&arg.ty);
|
||||
|
@ -426,17 +425,17 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
|
|||
}
|
||||
|
||||
fn process_static_or_const_item(&mut self, item: &ast::Item, typ: &ast::Ty, expr: &ast::Expr) {
|
||||
let 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 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);
|
||||
}
|
||||
self.visit_ty(&typ);
|
||||
self.visit_expr(expr);
|
||||
}
|
||||
|
@ -495,6 +494,10 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
|
|||
enum_definition: &ast::EnumDef,
|
||||
ty_params: &ast::Generics) {
|
||||
let enum_data = self.save_ctxt.get_item_data(item);
|
||||
let enum_data = match enum_data {
|
||||
None => return,
|
||||
Some(data) => data,
|
||||
};
|
||||
down_cast_data!(enum_data, EnumData, self, item.span);
|
||||
self.fmt.enum_str(item.span,
|
||||
Some(enum_data.span),
|
||||
|
@ -547,36 +550,36 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
|
|||
trait_ref: &Option<ast::TraitRef>,
|
||||
typ: &ast::Ty,
|
||||
impl_items: &[P<ast::ImplItem>]) {
|
||||
let impl_data = self.save_ctxt.get_item_data(item);
|
||||
down_cast_data!(impl_data, ImplData, self, item.span);
|
||||
match impl_data.self_ref {
|
||||
Some(ref self_ref) => {
|
||||
let mut has_self_ref = false;
|
||||
if let Some(impl_data) = self.save_ctxt.get_item_data(item) {
|
||||
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);
|
||||
}
|
||||
None => {
|
||||
self.visit_ty(&typ);
|
||||
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);
|
||||
visit::walk_path(self, &trait_ref.as_ref().unwrap().path);
|
||||
}
|
||||
}
|
||||
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);
|
||||
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);
|
||||
|
||||
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 !has_self_ref {
|
||||
self.visit_ty(&typ);
|
||||
}
|
||||
self.process_generic_params(type_parameters, item.span, "", item.id);
|
||||
for impl_item in impl_items {
|
||||
self.visit_impl_item(impl_item);
|
||||
|
@ -633,22 +636,23 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
|
|||
|
||||
// `item` is the module in question, represented as an item.
|
||||
fn process_mod(&mut self, item: &ast::Item) {
|
||||
let 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 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);
|
||||
}
|
||||
}
|
||||
|
||||
fn process_path(&mut self, id: NodeId, path: &ast::Path, ref_kind: Option<recorder::Row>) {
|
||||
if generated_code(path.span) {
|
||||
let path_data = self.save_ctxt.get_path_data(id, path);
|
||||
if generated_code(path.span) && path_data.is_none() {
|
||||
return;
|
||||
}
|
||||
|
||||
let path_data = self.save_ctxt.get_path_data(id, path);
|
||||
let path_data = match path_data {
|
||||
Some(pd) => pd,
|
||||
None => {
|
||||
|
@ -719,10 +723,6 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
|
|||
fields: &Vec<ast::Field>,
|
||||
variant: ty::VariantDef,
|
||||
base: &Option<P<ast::Expr>>) {
|
||||
if generated_code(path.span) {
|
||||
return
|
||||
}
|
||||
|
||||
self.write_sub_paths_truncated(path, false);
|
||||
|
||||
if let Some(struct_lit_data) = self.save_ctxt.get_expr_data(ex) {
|
||||
|
@ -735,16 +735,15 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
|
|||
let scope = self.save_ctxt.enclosing_scope(ex.id);
|
||||
|
||||
for field in fields {
|
||||
if generated_code(field.ident.span) {
|
||||
continue;
|
||||
}
|
||||
if let Some(field_data) = self.save_ctxt
|
||||
.get_field_ref_data(field, variant, scope) {
|
||||
|
||||
let 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);
|
||||
self.fmt.ref_str(recorder::VarRef,
|
||||
field.ident.span,
|
||||
Some(field_data.span),
|
||||
field_data.ref_id,
|
||||
field_data.scope);
|
||||
}
|
||||
|
||||
self.visit_expr(&field.expr)
|
||||
}
|
||||
|
@ -768,10 +767,6 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
|
|||
}
|
||||
|
||||
fn process_pat(&mut self, p: &ast::Pat) {
|
||||
if generated_code(p.span) {
|
||||
return;
|
||||
}
|
||||
|
||||
match p.node {
|
||||
ast::PatStruct(ref path, ref fields, _) => {
|
||||
visit::walk_path(self, path);
|
||||
|
@ -780,10 +775,6 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
|
|||
let variant = adt.variant_of_def(def);
|
||||
|
||||
for &Spanned { node: ref field, span } in fields {
|
||||
if generated_code(span) {
|
||||
continue;
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -827,10 +818,6 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
|
|||
|
||||
impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> {
|
||||
fn visit_item(&mut self, item: &ast::Item) {
|
||||
if generated_code(item.span) {
|
||||
return
|
||||
}
|
||||
|
||||
match item.node {
|
||||
ast::ItemUse(ref use_item) => {
|
||||
match use_item.node {
|
||||
|
@ -1025,10 +1012,6 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> {
|
|||
}
|
||||
|
||||
fn visit_ty(&mut self, t: &ast::Ty) {
|
||||
if generated_code(t.span) {
|
||||
return
|
||||
}
|
||||
|
||||
match t.node {
|
||||
ast::TyPath(_, ref path) => {
|
||||
match self.lookup_type_ref(t.id) {
|
||||
|
@ -1048,10 +1031,6 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> {
|
|||
}
|
||||
|
||||
fn visit_expr(&mut self, ex: &ast::Expr) {
|
||||
if generated_code(ex.span) {
|
||||
return
|
||||
}
|
||||
|
||||
match ex.node {
|
||||
ast::ExprCall(ref _f, ref _args) => {
|
||||
// Don't need to do anything for function calls,
|
||||
|
@ -1070,10 +1049,6 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> {
|
|||
}
|
||||
ast::ExprMethodCall(_, _, ref args) => self.process_method_call(ex, args),
|
||||
ast::ExprField(ref sub_ex, _) => {
|
||||
if generated_code(sub_ex.span) {
|
||||
return
|
||||
}
|
||||
|
||||
self.visit_expr(&sub_ex);
|
||||
|
||||
if let Some(field_data) = self.save_ctxt.get_expr_data(ex) {
|
||||
|
@ -1086,10 +1061,6 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> {
|
|||
}
|
||||
}
|
||||
ast::ExprTupField(ref sub_ex, idx) => {
|
||||
if generated_code(sub_ex.span) {
|
||||
return
|
||||
}
|
||||
|
||||
self.visit_expr(&**sub_ex);
|
||||
|
||||
let hir_node = lower_expr(self.save_ctxt.lcx, sub_ex);
|
||||
|
@ -1110,10 +1081,6 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> {
|
|||
}
|
||||
}
|
||||
ast::ExprClosure(_, ref decl, ref body) => {
|
||||
if generated_code(body.span) {
|
||||
return
|
||||
}
|
||||
|
||||
let mut id = String::from("$");
|
||||
id.push_str(&ex.id.to_string());
|
||||
self.process_formals(&decl.inputs, &id);
|
||||
|
@ -1210,18 +1177,10 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> {
|
|||
}
|
||||
|
||||
fn visit_stmt(&mut self, s: &ast::Stmt) {
|
||||
if generated_code(s.span) {
|
||||
return
|
||||
}
|
||||
|
||||
visit::walk_stmt(self, s)
|
||||
}
|
||||
|
||||
fn visit_local(&mut self, l: &ast::Local) {
|
||||
if generated_code(l.span) {
|
||||
return
|
||||
}
|
||||
|
||||
let value = self.span.snippet(l.span);
|
||||
self.process_var_decl(&l.pat, value);
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ use syntax::print::pprust::ty_to_string;
|
|||
|
||||
use self::span_utils::SpanUtils;
|
||||
|
||||
|
||||
#[macro_use]
|
||||
pub mod span_utils;
|
||||
pub mod recorder;
|
||||
|
||||
|
@ -209,21 +209,21 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
|
|||
result
|
||||
}
|
||||
|
||||
pub fn get_item_data(&self, item: &ast::Item) -> Data {
|
||||
pub fn get_item_data(&self, item: &ast::Item) -> Option<Data> {
|
||||
match item.node {
|
||||
ast::ItemFn(..) => {
|
||||
let name = self.tcx.map.path_to_string(item.id);
|
||||
let qualname = format!("::{}", name);
|
||||
let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Fn);
|
||||
|
||||
Data::FunctionData(FunctionData {
|
||||
filter!(self.span_utils, sub_span, item.span, None);
|
||||
Some(Data::FunctionData(FunctionData {
|
||||
id: item.id,
|
||||
name: name,
|
||||
qualname: qualname,
|
||||
declaration: None,
|
||||
span: sub_span.unwrap(),
|
||||
scope: self.enclosing_scope(item.id),
|
||||
})
|
||||
}))
|
||||
}
|
||||
ast::ItemStatic(ref typ, mt, ref expr) => {
|
||||
let qualname = format!("::{}", self.tcx.map.path_to_string(item.id));
|
||||
|
@ -235,8 +235,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
|
|||
};
|
||||
|
||||
let sub_span = self.span_utils.sub_span_after_keyword(item.span, keyword);
|
||||
|
||||
Data::VariableData(VariableData {
|
||||
filter!(self.span_utils, sub_span, item.span, None);
|
||||
Some(Data::VariableData(VariableData {
|
||||
id: item.id,
|
||||
name: item.ident.to_string(),
|
||||
qualname: qualname,
|
||||
|
@ -244,13 +244,13 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
|
|||
scope: self.enclosing_scope(item.id),
|
||||
value: value,
|
||||
type_value: ty_to_string(&typ),
|
||||
})
|
||||
}))
|
||||
}
|
||||
ast::ItemConst(ref typ, ref expr) => {
|
||||
let qualname = format!("::{}", self.tcx.map.path_to_string(item.id));
|
||||
let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Const);
|
||||
|
||||
Data::VariableData(VariableData {
|
||||
filter!(self.span_utils, sub_span, item.span, None);
|
||||
Some(Data::VariableData(VariableData {
|
||||
id: item.id,
|
||||
name: item.ident.to_string(),
|
||||
qualname: qualname,
|
||||
|
@ -258,7 +258,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
|
|||
scope: self.enclosing_scope(item.id),
|
||||
value: self.span_utils.snippet(expr.span),
|
||||
type_value: ty_to_string(&typ),
|
||||
})
|
||||
}))
|
||||
}
|
||||
ast::ItemMod(ref m) => {
|
||||
let qualname = format!("::{}", self.tcx.map.path_to_string(item.id));
|
||||
|
@ -267,28 +267,28 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
|
|||
let filename = cm.span_to_filename(m.inner);
|
||||
|
||||
let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Mod);
|
||||
|
||||
Data::ModData(ModData {
|
||||
filter!(self.span_utils, sub_span, item.span, None);
|
||||
Some(Data::ModData(ModData {
|
||||
id: item.id,
|
||||
name: item.ident.to_string(),
|
||||
qualname: qualname,
|
||||
span: sub_span.unwrap(),
|
||||
scope: self.enclosing_scope(item.id),
|
||||
filename: filename,
|
||||
})
|
||||
}))
|
||||
}
|
||||
ast::ItemEnum(..) => {
|
||||
let enum_name = format!("::{}", self.tcx.map.path_to_string(item.id));
|
||||
let val = self.span_utils.snippet(item.span);
|
||||
let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Enum);
|
||||
|
||||
Data::EnumData(EnumData {
|
||||
filter!(self.span_utils, sub_span, item.span, None);
|
||||
Some(Data::EnumData(EnumData {
|
||||
id: item.id,
|
||||
value: val,
|
||||
span: sub_span.unwrap(),
|
||||
qualname: enum_name,
|
||||
scope: self.enclosing_scope(item.id),
|
||||
})
|
||||
}))
|
||||
}
|
||||
ast::ItemImpl(_, _, _, ref trait_ref, ref typ, _) => {
|
||||
let mut type_data = None;
|
||||
|
@ -299,10 +299,11 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
|
|||
match typ.node {
|
||||
// Common case impl for a struct or something basic.
|
||||
ast::TyPath(None, ref path) => {
|
||||
sub_span = self.span_utils.sub_span_for_type_name(path.span).unwrap();
|
||||
sub_span = self.span_utils.sub_span_for_type_name(path.span);
|
||||
filter!(self.span_utils, sub_span, path.span, None);
|
||||
type_data = self.lookup_ref_id(typ.id).map(|id| {
|
||||
TypeRefData {
|
||||
span: sub_span,
|
||||
span: sub_span.unwrap(),
|
||||
scope: parent,
|
||||
ref_id: id,
|
||||
}
|
||||
|
@ -311,20 +312,21 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
|
|||
_ => {
|
||||
// Less useful case, impl for a compound type.
|
||||
let span = typ.span;
|
||||
sub_span = self.span_utils.sub_span_for_type_name(span).unwrap_or(span);
|
||||
sub_span = self.span_utils.sub_span_for_type_name(span).or(Some(span));
|
||||
}
|
||||
}
|
||||
|
||||
let trait_data = trait_ref.as_ref()
|
||||
.and_then(|tr| self.get_trait_ref_data(tr, parent));
|
||||
|
||||
Data::ImplData(ImplData {
|
||||
filter!(self.span_utils, sub_span, typ.span, None);
|
||||
Some(Data::ImplData(ImplData {
|
||||
id: item.id,
|
||||
span: sub_span,
|
||||
span: sub_span.unwrap(),
|
||||
scope: parent,
|
||||
trait_ref: trait_data,
|
||||
self_ref: type_data,
|
||||
})
|
||||
}))
|
||||
}
|
||||
_ => {
|
||||
// FIXME
|
||||
|
@ -333,12 +335,14 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_field_data(&self, field: &ast::StructField, scope: NodeId) -> Option<VariableData> {
|
||||
pub fn get_field_data(&self, field: &ast::StructField,
|
||||
scope: NodeId) -> Option<VariableData> {
|
||||
match field.node.kind {
|
||||
ast::NamedField(ident, _) => {
|
||||
let qualname = format!("::{}::{}", self.tcx.map.path_to_string(scope), ident);
|
||||
let typ = self.tcx.node_types().get(&field.node.id).unwrap().to_string();
|
||||
let sub_span = self.span_utils.sub_span_before_token(field.span, token::Colon);
|
||||
filter!(self.span_utils, sub_span, field.span, None);
|
||||
Some(VariableData {
|
||||
id: field.node.id,
|
||||
name: ident.to_string(),
|
||||
|
@ -355,7 +359,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
|
|||
|
||||
// FIXME would be nice to take a MethodItem here, but the ast provides both
|
||||
// trait and impl flavours, so the caller must do the disassembly.
|
||||
pub fn get_method_data(&self, id: ast::NodeId, name: ast::Name, span: Span) -> FunctionData {
|
||||
pub fn get_method_data(&self, id: ast::NodeId,
|
||||
name: ast::Name, span: Span) -> Option<FunctionData> {
|
||||
// The qualname for a method is the trait name or name of the struct in an impl in
|
||||
// which the method is declared in, followed by the method's name.
|
||||
let qualname = match self.tcx.impl_of_method(self.tcx.map.local_def_id(id)) {
|
||||
|
@ -430,29 +435,30 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
|
|||
});
|
||||
|
||||
let sub_span = self.span_utils.sub_span_after_keyword(span, keywords::Fn);
|
||||
|
||||
FunctionData {
|
||||
filter!(self.span_utils, sub_span, span, None);
|
||||
Some(FunctionData {
|
||||
id: id,
|
||||
name: name.to_string(),
|
||||
qualname: qualname,
|
||||
declaration: decl_id,
|
||||
span: sub_span.unwrap(),
|
||||
scope: self.enclosing_scope(id),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_trait_ref_data(&self,
|
||||
trait_ref: &ast::TraitRef,
|
||||
parent: NodeId)
|
||||
-> Option<TypeRefData> {
|
||||
self.lookup_ref_id(trait_ref.ref_id).map(|def_id| {
|
||||
self.lookup_ref_id(trait_ref.ref_id).and_then(|def_id| {
|
||||
let span = trait_ref.path.span;
|
||||
let sub_span = self.span_utils.sub_span_for_type_name(span).unwrap_or(span);
|
||||
TypeRefData {
|
||||
span: sub_span,
|
||||
let sub_span = self.span_utils.sub_span_for_type_name(span).or(Some(span));
|
||||
filter!(self.span_utils, sub_span, span, None);
|
||||
Some(TypeRefData {
|
||||
span: sub_span.unwrap(),
|
||||
scope: parent,
|
||||
ref_id: def_id,
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -465,6 +471,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
|
|||
ty::TyStruct(def, _) => {
|
||||
let f = def.struct_variant().field_named(ident.node.name);
|
||||
let sub_span = self.span_utils.span_for_last_ident(expr.span);
|
||||
filter!(self.span_utils, sub_span, expr.span, None);
|
||||
return Some(Data::VariableRefData(VariableRefData {
|
||||
name: ident.node.to_string(),
|
||||
span: sub_span.unwrap(),
|
||||
|
@ -484,6 +491,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
|
|||
match *ty {
|
||||
ty::TyStruct(def, _) => {
|
||||
let sub_span = self.span_utils.span_for_last_ident(path.span);
|
||||
filter!(self.span_utils, sub_span, path.span, None);
|
||||
Some(Data::TypeRefData(TypeRefData {
|
||||
span: sub_span.unwrap(),
|
||||
scope: self.enclosing_scope(expr.id),
|
||||
|
@ -506,6 +514,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
|
|||
ty::TraitContainer(_) => (None, Some(method_id)),
|
||||
};
|
||||
let sub_span = self.span_utils.sub_span_for_meth_name(expr.span);
|
||||
filter!(self.span_utils, sub_span, expr.span, None);
|
||||
let parent = self.enclosing_scope(expr.id);
|
||||
Some(Data::MethodCallData(MethodCallData {
|
||||
span: sub_span.unwrap(),
|
||||
|
@ -532,6 +541,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
|
|||
}
|
||||
let def = def_map.get(&id).unwrap().full_def();
|
||||
let sub_span = self.span_utils.span_for_last_ident(path.span);
|
||||
filter!(self.span_utils, sub_span, path.span, None);
|
||||
match def {
|
||||
Def::Upvar(..) |
|
||||
Def::Local(..) |
|
||||
|
@ -559,6 +569,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
|
|||
}
|
||||
Def::Method(decl_id) => {
|
||||
let sub_span = self.span_utils.sub_span_for_meth_name(path.span);
|
||||
filter!(self.span_utils, sub_span, path.span, None);
|
||||
let def_id = if decl_id.is_local() {
|
||||
let ti = self.tcx.impl_or_trait_item(decl_id);
|
||||
match ti.container() {
|
||||
|
@ -628,16 +639,17 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
|
|||
field_ref: &ast::Field,
|
||||
variant: ty::VariantDef,
|
||||
parent: NodeId)
|
||||
-> VariableRefData {
|
||||
-> Option<VariableRefData> {
|
||||
let f = variant.field_named(field_ref.ident.node.name);
|
||||
// We don't really need a sub-span here, but no harm done
|
||||
let sub_span = self.span_utils.span_for_last_ident(field_ref.ident.span);
|
||||
VariableRefData {
|
||||
filter!(self.span_utils, sub_span, field_ref.ident.span, None);
|
||||
Some(VariableRefData {
|
||||
name: field_ref.ident.node.to_string(),
|
||||
span: sub_span.unwrap(),
|
||||
scope: parent,
|
||||
ref_id: f.did,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_data_for_id(&self, _id: &NodeId) -> Data {
|
||||
|
@ -677,17 +689,15 @@ impl PathCollector {
|
|||
|
||||
impl<'v> Visitor<'v> for PathCollector {
|
||||
fn visit_pat(&mut self, p: &ast::Pat) {
|
||||
if generated_code(p.span) {
|
||||
return;
|
||||
}
|
||||
|
||||
match p.node {
|
||||
ast::PatStruct(ref path, _, _) => {
|
||||
self.collected_paths.push((p.id, path.clone(), ast::MutMutable, recorder::TypeRef));
|
||||
self.collected_paths.push((p.id, path.clone(),
|
||||
ast::MutMutable, recorder::TypeRef));
|
||||
}
|
||||
ast::PatEnum(ref path, _) |
|
||||
ast::PatQPath(_, ref path) => {
|
||||
self.collected_paths.push((p.id, path.clone(), ast::MutMutable, recorder::VarRef));
|
||||
self.collected_paths.push((p.id, path.clone(),
|
||||
ast::MutMutable, recorder::VarRef));
|
||||
}
|
||||
ast::PatIdent(bm, ref path1, _) => {
|
||||
debug!("PathCollector, visit ident in pat {}: {:?} {:?}",
|
||||
|
@ -719,10 +729,6 @@ pub fn process_crate<'l, 'tcx>(tcx: &'l ty::ctxt<'tcx>,
|
|||
odir: Option<&Path>) {
|
||||
let _ignore = tcx.dep_graph.in_ignore();
|
||||
|
||||
if generated_code(krate.span) {
|
||||
return;
|
||||
}
|
||||
|
||||
assert!(analysis.glob_map.is_some());
|
||||
|
||||
info!("Dumping crate {}", cratename);
|
||||
|
@ -780,8 +786,8 @@ fn escape(s: String) -> String {
|
|||
s.replace("\"", "\"\"")
|
||||
}
|
||||
|
||||
// If the expression is a macro expansion or other generated code, run screaming
|
||||
// and don't index.
|
||||
// Helper function to determine if a span came from a
|
||||
// macro expansion or syntax extension.
|
||||
pub fn generated_code(span: Span) -> bool {
|
||||
span.expn_id != NO_EXPANSION || span == DUMMY_SP
|
||||
}
|
||||
|
|
|
@ -318,6 +318,7 @@ impl<'a, 'tcx: 'a> FmtStrs<'a, 'tcx> {
|
|||
span: Span,
|
||||
sub_span: Option<Span>,
|
||||
values: Vec<String>) {
|
||||
filter!(self.span, sub_span, span);
|
||||
match sub_span {
|
||||
Some(sub_span) => self.record_with_span(kind, span, sub_span, values),
|
||||
None => {
|
||||
|
|
|
@ -66,13 +66,6 @@ impl<'a> SpanUtils<'a> {
|
|||
// sub_span starts at span.lo, so we need to adjust the positions etc.
|
||||
// If sub_span is None, we don't need to adjust.
|
||||
pub fn make_sub_span(&self, span: Span, sub_span: Option<Span>) -> Option<Span> {
|
||||
let loc = self.sess.codemap().lookup_char_pos(span.lo);
|
||||
assert!(!generated_code(span),
|
||||
"generated code; we should not be processing this `{}` in {}, line {}",
|
||||
self.snippet(span),
|
||||
loc.file.name,
|
||||
loc.line);
|
||||
|
||||
match sub_span {
|
||||
None => None,
|
||||
Some(sub) => {
|
||||
|
@ -81,7 +74,7 @@ impl<'a> SpanUtils<'a> {
|
|||
Some(Span {
|
||||
lo: base + self.sess.codemap().lookup_byte_offset(sub.lo).pos,
|
||||
hi: base + self.sess.codemap().lookup_byte_offset(sub.hi).pos,
|
||||
expn_id: NO_EXPANSION,
|
||||
expn_id: span.expn_id,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -259,6 +252,9 @@ impl<'a> SpanUtils<'a> {
|
|||
let ts = toks.real_token();
|
||||
if ts.tok == token::Eof {
|
||||
if bracket_count != 0 {
|
||||
if generated_code(span) {
|
||||
return vec!();
|
||||
}
|
||||
let loc = self.sess.codemap().lookup_char_pos(span.lo);
|
||||
self.sess.span_bug(span,
|
||||
&format!("Mis-counted brackets when breaking path? \
|
||||
|
@ -358,19 +354,12 @@ impl<'a> SpanUtils<'a> {
|
|||
// Returns a list of the spans of idents in a path.
|
||||
// E.g., For foo::bar<x,t>::baz, we return [foo, bar, baz] (well, their spans)
|
||||
pub fn spans_for_path_segments(&self, path: &ast::Path) -> Vec<Span> {
|
||||
if generated_code(path.span) {
|
||||
return vec!();
|
||||
}
|
||||
|
||||
self.spans_with_brackets(path.span, 0, -1)
|
||||
}
|
||||
|
||||
// Return an owned vector of the subspans of the param identifier
|
||||
// tokens found in span.
|
||||
pub fn spans_for_ty_params(&self, span: Span, number: isize) -> Vec<Span> {
|
||||
if generated_code(span) {
|
||||
return vec!();
|
||||
}
|
||||
// Type params are nested within one level of brackets:
|
||||
// i.e. we want Vec<A, B> from Foo<A, B<T,U>>
|
||||
self.spans_with_brackets(span, 1, number)
|
||||
|
@ -388,4 +377,40 @@ impl<'a> SpanUtils<'a> {
|
|||
self.sess.bug("span errors reached 1000, giving up");
|
||||
}
|
||||
}
|
||||
|
||||
/// Return true if the span is generated code, and
|
||||
/// it is not a subspan of the root callsite.
|
||||
///
|
||||
/// Used to filter out spans of minimal value,
|
||||
/// such as references to macro internal variables.
|
||||
pub fn filter_generated(&self, sub_span: Option<Span>, parent: Span) -> bool {
|
||||
if !generated_code(parent) {
|
||||
if sub_span.is_none() {
|
||||
// Edge case - this occurs on generated code with incorrect expansion info.
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// If sub_span is none, filter out generated code.
|
||||
if sub_span.is_none() {
|
||||
return true;
|
||||
}
|
||||
// A generated span is deemed invalid if it is not a sub-span of the root
|
||||
// callsite. This filters out macro internal variables and most malformed spans.
|
||||
let span = self.sess.codemap().source_callsite(parent);
|
||||
!(parent.lo >= span.lo && parent.hi <= span.hi)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! filter {
|
||||
($util: expr, $span: ident, $parent: expr, None) => {
|
||||
if $util.filter_generated($span, $parent) {
|
||||
return None;
|
||||
}
|
||||
};
|
||||
($util: expr, $span: ident, $parent: expr) => {
|
||||
if $util.filter_generated($span, $parent) {
|
||||
return;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -858,10 +858,15 @@ impl CodeMap {
|
|||
let span_str = self.span_to_string(sp);
|
||||
let mut span_snip = self.span_to_snippet(sp)
|
||||
.unwrap_or("Snippet unavailable".to_owned());
|
||||
if span_snip.len() > 50 {
|
||||
span_snip.truncate(50);
|
||||
|
||||
// Truncate by code points - in worst case this will be more than 50 characters,
|
||||
// but ensures at least 50 characters and respects byte boundaries.
|
||||
let char_vec: Vec<(usize, char)> = span_snip.char_indices().collect();
|
||||
if char_vec.len() > 50 {
|
||||
span_snip.truncate(char_vec[49].0);
|
||||
span_snip.push_str("...");
|
||||
}
|
||||
|
||||
output.push_str(&format!("{}{}\n{}`{}`\n", indent, span_str, indent, span_snip));
|
||||
|
||||
if sp.expn_id == NO_EXPANSION || sp.expn_id == COMMAND_LINE_EXPN {
|
||||
|
@ -909,6 +914,22 @@ impl CodeMap {
|
|||
output
|
||||
}
|
||||
|
||||
/// Return the source span - this is either the supplied span, or the span for
|
||||
/// the macro callsite that expanded to it.
|
||||
pub fn source_callsite(&self, sp: Span) -> Span {
|
||||
let mut span = sp;
|
||||
while span.expn_id != NO_EXPANSION && span.expn_id != COMMAND_LINE_EXPN {
|
||||
if let Some(callsite) = self.with_expn_info(span.expn_id,
|
||||
|ei| ei.map(|ei| ei.call_site.clone())) {
|
||||
span = callsite;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
span
|
||||
}
|
||||
|
||||
pub fn span_to_filename(&self, sp: Span) -> FileName {
|
||||
self.lookup_char_pos(sp.lo).file.name.to_string()
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ use deriving::generic::ty::*;
|
|||
|
||||
use syntax::ast;
|
||||
use syntax::ast::{MetaItem, Expr};
|
||||
use syntax::codemap::{Span, respan};
|
||||
use syntax::codemap::{Span, respan, DUMMY_SP};
|
||||
use syntax::ext::base::{ExtCtxt, Annotatable};
|
||||
use syntax::ext::build::AstBuilder;
|
||||
use syntax::parse::token;
|
||||
|
@ -87,7 +87,7 @@ fn show_substructure(cx: &mut ExtCtxt, span: Span,
|
|||
fmt,
|
||||
token::str_to_ident("debug_tuple"),
|
||||
vec![name]);
|
||||
stmts.push(cx.stmt_let(span, true, builder, expr));
|
||||
stmts.push(cx.stmt_let(DUMMY_SP, true, builder, expr));
|
||||
|
||||
for field in fields {
|
||||
// Use double indirection to make sure this works for unsized types
|
||||
|
@ -109,7 +109,7 @@ fn show_substructure(cx: &mut ExtCtxt, span: Span,
|
|||
fmt,
|
||||
token::str_to_ident("debug_struct"),
|
||||
vec![name]);
|
||||
stmts.push(cx.stmt_let(span, true, builder, expr));
|
||||
stmts.push(cx.stmt_let(DUMMY_SP, true, builder, expr));
|
||||
|
||||
for field in fields {
|
||||
let name = cx.expr_lit(field.span, ast::Lit_::LitStr(
|
||||
|
|
|
@ -14,7 +14,7 @@ use self::Position::*;
|
|||
use fmt_macros as parse;
|
||||
|
||||
use syntax::ast;
|
||||
use syntax::codemap::{Span, respan};
|
||||
use syntax::codemap::{Span, respan, DUMMY_SP};
|
||||
use syntax::ext::base::*;
|
||||
use syntax::ext::base;
|
||||
use syntax::ext::build::AstBuilder;
|
||||
|
@ -501,7 +501,7 @@ impl<'a, 'b> Context<'a, 'b> {
|
|||
};
|
||||
|
||||
let name = self.ecx.ident_of(&format!("__arg{}", i));
|
||||
pats.push(self.ecx.pat_ident(e.span, name));
|
||||
pats.push(self.ecx.pat_ident(DUMMY_SP, name));
|
||||
locals.push(Context::format_arg(self.ecx, self.macsp, e.span, arg_ty,
|
||||
self.ecx.expr_ident(e.span, name)));
|
||||
heads.push(self.ecx.expr_addr_of(e.span, e));
|
||||
|
@ -518,7 +518,7 @@ impl<'a, 'b> Context<'a, 'b> {
|
|||
|
||||
let lname = self.ecx.ident_of(&format!("__arg{}",
|
||||
*name));
|
||||
pats.push(self.ecx.pat_ident(e.span, lname));
|
||||
pats.push(self.ecx.pat_ident(DUMMY_SP, lname));
|
||||
names[*self.name_positions.get(name).unwrap()] =
|
||||
Some(Context::format_arg(self.ecx, self.macsp, e.span, arg_ty,
|
||||
self.ecx.expr_ident(e.span, lname)));
|
||||
|
|
|
@ -287,6 +287,26 @@ pub struct blah {
|
|||
used_link_args: RefCell<[&'static str; 0]>,
|
||||
}
|
||||
|
||||
#[macro_use]
|
||||
mod macro_use_test {
|
||||
macro_rules! test_rec {
|
||||
(q, $src: expr) => {{
|
||||
print!("{}", $src);
|
||||
test_rec!($src);
|
||||
}};
|
||||
($src: expr) => {
|
||||
print!("{}", $src);
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! internal_vars {
|
||||
($src: ident) => {{
|
||||
let mut x = $src;
|
||||
x += 100;
|
||||
}};
|
||||
}
|
||||
}
|
||||
|
||||
fn main() { // foo
|
||||
let s = box some_fields {field1: 43};
|
||||
hello((43, "a".to_string()), *s);
|
||||
|
@ -356,6 +376,11 @@ fn main() { // foo
|
|||
while let Some(z) = None {
|
||||
foo_foo(z);
|
||||
}
|
||||
|
||||
let mut x = 4;
|
||||
test_rec!(q, "Hello");
|
||||
assert_eq!(x, 4);
|
||||
internal_vars!(x);
|
||||
}
|
||||
|
||||
fn foo_foo(_: i32) {}
|
||||
|
@ -398,3 +423,16 @@ impl Error + 'static + Send {
|
|||
<Error + 'static>::is::<T>(self)
|
||||
}
|
||||
}
|
||||
extern crate serialize;
|
||||
#[derive(Clone, Copy, Hash, Encodable, Decodable, PartialEq, Eq, PartialOrd, Ord, Debug, Default)]
|
||||
struct AllDerives(i32);
|
||||
|
||||
fn test_format_args() {
|
||||
let x = 1;
|
||||
let y = 2;
|
||||
let name = "Joe Blogg";
|
||||
println!("Hello {}", name);
|
||||
print!("Hello {0}", name);
|
||||
print!("{0} + {} = {}", x, y);
|
||||
print!("x is {}, y is {1}, name is {n}", x, y, n = name);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue