diff --git a/src/librustc_trans/save/dump_csv.rs b/src/librustc_trans/save/dump_csv.rs index b109353fac0bf..2968f86d2c49d 100644 --- a/src/librustc_trans/save/dump_csv.rs +++ b/src/librustc_trans/save/dump_csv.rs @@ -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); - - - 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 @@ 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), @@ -533,36 +536,36 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { trait_ref: &Option, typ: &ast::Ty, impl_items: &[P]) { - 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); @@ -619,22 +622,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) { - 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 => { @@ -705,10 +709,6 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { fields: &Vec, variant: ty::VariantDef, base: &Option>) { - 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) { @@ -721,16 +721,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) } @@ -754,10 +753,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); @@ -766,10 +761,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); @@ -813,10 +804,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 { @@ -1011,10 +998,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) { @@ -1034,10 +1017,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, @@ -1056,10 +1035,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) { @@ -1072,10 +1047,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); @@ -1096,10 +1067,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); @@ -1196,18 +1163,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); diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs index 00554419e649c..37b23d6ee9ce9 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -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 { 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 { + pub fn get_field_data(&self, field: &ast::StructField, + scope: NodeId) -> Option { 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 { // 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 { - 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 { 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 } diff --git a/src/librustc_trans/save/recorder.rs b/src/librustc_trans/save/recorder.rs index 1db31baf30dcc..682a74c8f0c38 100644 --- a/src/librustc_trans/save/recorder.rs +++ b/src/librustc_trans/save/recorder.rs @@ -318,6 +318,7 @@ impl<'a, 'tcx: 'a> FmtStrs<'a, 'tcx> { 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 => { diff --git a/src/librustc_trans/save/span_utils.rs b/src/librustc_trans/save/span_utils.rs index 773d5caea5f1a..344431032d694 100644 --- a/src/librustc_trans/save/span_utils.rs +++ b/src/librustc_trans/save/span_utils.rs @@ -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) -> Option { - 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::baz, we return [foo, bar, baz] (well, their spans) pub fn spans_for_path_segments(&self, path: &ast::Path) -> Vec { - 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 { - if generated_code(span) { - return vec!(); - } // Type params are nested within one level of brackets: // i.e. we want Vec from Foo> 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, 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; + } + }; } diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 8d6c0df981f23..432c1688536bb 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -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() } diff --git a/src/libsyntax_ext/deriving/debug.rs b/src/libsyntax_ext/deriving/debug.rs index ed3f764c1d2aa..008067f39a352 100644 --- a/src/libsyntax_ext/deriving/debug.rs +++ b/src/libsyntax_ext/deriving/debug.rs @@ -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( diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index 1fb2b55215ded..77bf90abbcc14 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -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))); diff --git a/src/test/run-make/save-analysis/foo.rs b/src/test/run-make/save-analysis/foo.rs index 3e4ba5af80c4d..7a1c200ba20e8 100644 --- a/src/test/run-make/save-analysis/foo.rs +++ b/src/test/run-make/save-analysis/foo.rs @@ -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 { ::is::(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