提交 eceb96b4 编写于 作者: B bors

Auto merge of #31097 - DanielJCampbell:SaveAnalysis, r=nrc

Also altered the format_args! syntax extension, and \#[derive(debug)], to maintain compatability.
r? @ nrc
......@@ -135,6 +135,9 @@ fn process_path_prefixes(&self, path: &ast::Path) -> Vec<(Span, String)> {
// 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 @@ fn process_method(&mut self,
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 @@ fn process_method(&mut self,
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 @@ fn process_fn(&mut self,
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);
self.process_formals(&decl.inputs, &fn_data.qualname);
self.process_generic_params(ty_params, item.span, &fn_data.qualname, item.id);
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);
}
for arg in &decl.inputs {
self.visit_ty(&arg.ty);
......@@ -426,17 +425,17 @@ fn process_fn(&mut self,
}
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 @@ fn process_enum(&mut self,
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 @@ fn process_impl(&mut self,
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);
}
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 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 !has_self_ref {
self.visit_ty(&typ);
}
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.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 @@ fn process_trait(&mut self,
// `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 @@ fn process_struct_lit(&mut self,
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 @@ fn process_struct_lit(&mut self,
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 @@ fn process_method_call(&mut self, ex: &ast::Expr, args: &Vec<P<ast::Expr>>) {
}
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 @@ fn process_pat(&mut self, p: &ast::Pat) {
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 @@ fn process_var_decl(&mut self, p: &ast::Pat, value: String) {
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 @@ fn visit_impl_item(&mut self, impl_item: &ast::ImplItem) {
}
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 @@ fn visit_ty(&mut self, t: &ast::Ty) {
}
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 @@ fn visit_expr(&mut self, ex: &ast::Expr) {
}
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 @@ fn visit_expr(&mut self, ex: &ast::Expr) {
}
}
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 @@ fn visit_expr(&mut self, ex: &ast::Expr) {
}
}
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 @@ fn visit_arm(&mut self, arm: &ast::Arm) {
}
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 self::span_utils::SpanUtils;
#[macro_use]
pub mod span_utils;
pub mod recorder;
......@@ -209,21 +209,21 @@ pub fn get_external_crates(&self) -> Vec<CrateData> {
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 @@ pub fn get_item_data(&self, item: &ast::Item) -> Data {
};
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 @@ pub fn get_item_data(&self, item: &ast::Item) -> Data {
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 @@ pub fn get_item_data(&self, item: &ast::Item) -> Data {
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 @@ pub fn get_item_data(&self, item: &ast::Item) -> Data {
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 @@ pub fn get_item_data(&self, item: &ast::Item) -> Data {
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 @@ pub fn get_item_data(&self, item: &ast::Item) -> Data {
_ => {
// 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 @@ pub fn get_item_data(&self, item: &ast::Item) -> Data {
}
}
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 @@ pub fn get_field_data(&self, field: &ast::StructField, scope: NodeId) -> Option<
// 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 @@ pub fn get_method_data(&self, id: ast::NodeId, name: ast::Name, span: Span) -> F
});
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 @@ pub fn get_expr_data(&self, expr: &ast::Expr) -> Option<Data> {
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 @@ pub fn get_expr_data(&self, expr: &ast::Expr) -> Option<Data> {
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 @@ pub fn get_expr_data(&self, expr: &ast::Expr) -> Option<Data> {
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 @@ pub fn get_path_data(&self, id: NodeId, path: &ast::Path) -> Option<Data> {
}
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 @@ pub fn get_path_data(&self, id: NodeId, path: &ast::Path) -> Option<Data> {
}
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 @@ pub fn get_field_ref_data(&self,
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 @@ fn new() -> 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 @@ pub fn check_and_record(&mut self,
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 @@ pub fn extent_str(&self, span: Span) -> String {
// 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 @@ pub fn make_sub_span(&self, span: Span, sub_span: Option<Span>) -> Option<Span>
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 @@ pub fn spans_with_brackets(&self, span: Span, nesting: isize, limit: isize) -> V
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 @@ fn sub_span_after<F: Fn(Token) -> bool>(&self, span: Span, f: F) -> Option<Span>
// 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 @@ pub fn report_span_err(&self, kind: &str, span: Span) {
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 @@ fn span_to_expanded_string_internal(&self, sp:Span, indent: &str) -> String {
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 @@ fn span_to_expanded_string_internal(&self, sp:Span, indent: &str) -> String {
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 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 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 @@ fn into_expr(mut self) -> P<ast::Expr> {
};
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 @@ fn into_expr(mut self) -> P<ast::Expr> {
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 @@ pub fn is<T: Error + 'static>(&self) -> bool {
<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);
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册