about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2016-01-25 20:41:44 +0000
committerbors <bors@rust-lang.org>2016-01-25 20:41:44 +0000
commiteceb96b40dedd903ddfca6df97bb1e5749b87787 (patch)
tree87751bdeafd78c1d25e462240436bf357b778942 /src
parent62a3a6ecc0668a9a79e8da1f199500ee74862e2e (diff)
parent616bfb6f15c377bc8850030f6239f14b8608b554 (diff)
downloadrust-eceb96b40dedd903ddfca6df97bb1e5749b87787.tar.gz
rust-eceb96b40dedd903ddfca6df97bb1e5749b87787.zip
Auto merge of #31097 - DanielJCampbell:SaveAnalysis, r=nrc
Also altered the format_args! syntax extension, and \#[derive(debug)], to maintain compatability.
r? @ nrc
Diffstat (limited to 'src')
-rw-r--r--src/librustc_trans/save/dump_csv.rs213
-rw-r--r--src/librustc_trans/save/mod.rs102
-rw-r--r--src/librustc_trans/save/recorder.rs1
-rw-r--r--src/librustc_trans/save/span_utils.rs55
-rw-r--r--src/libsyntax/codemap.rs25
-rw-r--r--src/libsyntax_ext/deriving/debug.rs6
-rw-r--r--src/libsyntax_ext/format.rs6
-rw-r--r--src/test/run-make/save-analysis/foo.rs38
8 files changed, 248 insertions, 198 deletions
diff --git a/src/librustc_trans/save/dump_csv.rs b/src/librustc_trans/save/dump_csv.rs
index a6f8e3f10f1..2951cf2ee1b 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),
@@ -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);
             }
+
+            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 @@ 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);
 
diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs
index 00554419e64..37b23d6ee9c 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<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
 }
diff --git a/src/librustc_trans/save/recorder.rs b/src/librustc_trans/save/recorder.rs
index 17fdbe2e839..eaba366c1d4 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<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 => {
diff --git a/src/librustc_trans/save/span_utils.rs b/src/librustc_trans/save/span_utils.rs
index 773d5caea5f..344431032d6 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<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;
+        }
+    };
 }
diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs
index 8d6c0df981f..432c1688536 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 ed3f764c1d2..008067f39a3 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 1fb2b55215d..77bf90abbcc 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 3e4ba5af80c..7a1c200ba20 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 {
         <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