From 3e14f011eceea613b395619d41307cf8d87be84f Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 11 May 2016 13:46:39 -0700 Subject: [PATCH] save-analysis: give better text info in value fields --- src/librustc_save_analysis/dump_visitor.rs | 72 +++++++++++++++++----- src/librustc_save_analysis/json_dumper.rs | 12 ++-- src/librustc_save_analysis/lib.rs | 55 ++++++++++++++--- src/libsyntax/ast.rs | 5 +- 4 files changed, 109 insertions(+), 35 deletions(-) diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 6f84ccc9e36..4d79ddfe8cb 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -39,7 +39,7 @@ use syntax::ast::{self, NodeId, PatKind}; use syntax::codemap::*; use syntax::parse::token::{self, keywords}; use syntax::visit::{self, Visitor}; -use syntax::print::pprust::{path_to_string, ty_to_string}; +use syntax::print::pprust::{path_to_string, ty_to_string, bounds_to_string, generics_to_string}; use syntax::ptr::P; use super::{escape, generated_code, SaveContext, PathCollector}; @@ -388,9 +388,12 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { if let Some(method_data) = self.save_ctxt.get_method_data(id, name, span) { + let sig_str = ::make_signature(&sig.decl, &sig.generics); if body.is_some() { if !self.span.filter_generated(Some(method_data.span), span) { - self.dumper.function(method_data.clone().lower(self.tcx)); + let mut data = method_data.clone(); + data.value = sig_str; + self.dumper.function(data.lower(self.tcx)); } self.process_formals(&sig.decl.inputs, &method_data.qualname); } else { @@ -401,7 +404,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { span: method_data.span, scope: method_data.scope, qualname: method_data.qualname.clone(), - value: String::new(), // TODO + value: sig_str, }.lower(self.tcx)); } } @@ -540,19 +543,33 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { self.visit_expr(expr); } + // FIXME tuple structs should generate tuple-specific data. fn process_struct(&mut self, item: &ast::Item, def: &ast::VariantData, ty_params: &ast::Generics) { + let name = item.ident.to_string(); let qualname = format!("::{}", self.tcx.node_path_str(item.id)); - let val = self.span.snippet(item.span); let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Struct); + let val = if let ast::ItemKind::Struct(ast::VariantData::Struct(ref fields, _), _) = + item.node { + let fields_str = fields.iter() + .enumerate() + .map(|(i, f)| f.ident.map(|i| i.to_string()) + .unwrap_or(i.to_string())) + .collect::>() + .join(", "); + format!("{} {{ {} }}", name, fields_str) + } else { + String::new() + }; + if !self.span.filter_generated(sub_span, item.span) { self.dumper.struct_data(StructData { span: sub_span.expect("No span found for struct"), id: item.id, - name: item.ident.to_string(), + name: name, ctor_id: def.id(), qualname: qualname.clone(), scope: self.cur_scope, @@ -589,11 +606,17 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { let mut qualname = enum_data.qualname.clone(); qualname.push_str("::"); qualname.push_str(&name); - let val = self.span.snippet(variant.span); match variant.node.data { - ast::VariantData::Struct(..) => { + ast::VariantData::Struct(ref fields, _) => { let sub_span = self.span.span_for_first_ident(variant.span); + let fields_str = fields.iter() + .enumerate() + .map(|(i, f)| f.ident.map(|i| i.to_string()) + .unwrap_or(i.to_string())) + .collect::>() + .join(", "); + let val = format!("{}::{} {{ {} }}", enum_data.name, name, fields_str); if !self.span.filter_generated(sub_span, variant.span) { self.dumper.struct_variant(StructVariantData { span: sub_span.expect("No span found for struct variant"), @@ -606,13 +629,22 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { }.lower(self.tcx)); } } - _ => { + ref v => { let sub_span = self.span.span_for_first_ident(variant.span); + let mut val = format!("{}::{}", enum_data.name, name); + if let &ast::VariantData::Tuple(ref fields, _) = v { + val.push('('); + val.push_str(&fields.iter() + .map(|f| ty_to_string(&f.ty)) + .collect::>() + .join(", ")); + val.push(')'); + } if !self.span.filter_generated(sub_span, variant.span) { self.dumper.tuple_variant(TupleVariantData { span: sub_span.expect("No span found for tuple variant"), id: variant.node.data.id(), - name: name.to_string(), + name: name, qualname: qualname, type_value: enum_data.qualname.clone(), value: val, @@ -678,14 +710,22 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { generics: &ast::Generics, trait_refs: &ast::TyParamBounds, methods: &[ast::TraitItem]) { + let name = item.ident.to_string(); let qualname = format!("::{}", self.tcx.node_path_str(item.id)); - let val = self.span.snippet(item.span); + let mut val = name.clone(); + if !generics.lifetimes.is_empty() || !generics.ty_params.is_empty() { + val.push_str(&generics_to_string(generics)); + } + if !trait_refs.is_empty() { + val.push_str(": "); + val.push_str(&bounds_to_string(trait_refs)); + } let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Trait); if !self.span.filter_generated(sub_span, item.span) { self.dumper.trait_data(TraitData { span: sub_span.expect("No span found for trait"), id: item.id, - name: item.ident.to_string(), + name: name, qualname: qualname.clone(), scope: self.cur_scope, value: val @@ -915,13 +955,15 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { self.visit_pat(&p); for &(id, ref p, immut, _) in &collector.collected_paths { - let value = if immut == ast::Mutability::Immutable { + let mut value = if immut == ast::Mutability::Immutable { value.to_string() } else { "".to_string() }; let types = self.tcx.node_types(); let typ = types.get(&id).map(|t| t.to_string()).unwrap_or(String::new()); + value.push_str(": "); + value.push_str(&typ); // Get the span only for the name of the variable (I hope the path // is only ever a variable name, but who knows?). let sub_span = self.span.span_for_last_ident(p.span); @@ -1283,13 +1325,13 @@ impl<'v, 'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'v> for DumpVisitor<'l, 'tcx, } ast::ExprKind::ForLoop(ref pattern, ref subexpression, ref block, _) | ast::ExprKind::WhileLet(ref pattern, ref subexpression, ref block, _) => { - let value = self.span.snippet(mk_sp(ex.span.lo, subexpression.span.hi)); + let value = self.span.snippet(subexpression.span); self.process_var_decl(pattern, value); visit::walk_expr(self, subexpression); visit::walk_block(self, block); } ast::ExprKind::IfLet(ref pattern, ref subexpression, ref block, ref opt_else) => { - let value = self.span.snippet(mk_sp(ex.span.lo, subexpression.span.hi)); + let value = self.span.snippet(subexpression.span); self.process_var_decl(pattern, value); visit::walk_expr(self, subexpression); visit::walk_block(self, block); @@ -1379,7 +1421,7 @@ impl<'v, 'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'v> for DumpVisitor<'l, 'tcx, fn visit_local(&mut self, l: &ast::Local) { self.process_macro_use(l.span, l.id); - let value = self.span.snippet(l.span); + let value = l.init.as_ref().map(|i| self.span.snippet(i.span)).unwrap_or(String::new()); self.process_var_decl(&l.pat, value); // Just walk the initialiser and type (don't want to walk the pattern again). diff --git a/src/librustc_save_analysis/json_dumper.rs b/src/librustc_save_analysis/json_dumper.rs index 156a6f5cc97..bdbecdd1d53 100644 --- a/src/librustc_save_analysis/json_dumper.rs +++ b/src/librustc_save_analysis/json_dumper.rs @@ -167,17 +167,17 @@ struct Def { #[derive(Debug, RustcEncodable)] enum DefKind { - // value = type + generics + // value = variant names Enum, - // value = type + generics + // value = enum name + variant name + types Tuple, - // value = type + generics + types + // value = [enum name +] name + fields Struct, - // value = type + generics + // value = signature Trait, // value = type + generics Function, - // No id + // No id, no value. Macro, // value = file_name Mod, @@ -186,8 +186,6 @@ enum DefKind { // value = type and init expression Variable, } -// TODO value for function and method -// TODO none of the values are right. impl From for Def { fn from(data: EnumData) -> Def { diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 0a5ac3af714..8c00a569993 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -52,7 +52,7 @@ use syntax::ast::{self, NodeId, PatKind}; use syntax::codemap::*; use syntax::parse::token::{self, keywords}; use syntax::visit::{self, Visitor}; -use syntax::print::pprust::ty_to_string; +use syntax::print::pprust::{ty_to_string, arg_to_string}; pub use self::csv_dumper::CsvDumper; pub use self::json_dumper::JsonDumper; @@ -122,11 +122,13 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { pub fn get_item_data(&self, item: &ast::Item) -> Option { match item.node { - ast::ItemKind::Fn(..) => { + ast::ItemKind::Fn(ref decl, _, _, _, ref generics, _) => { let name = self.tcx.node_path_str(item.id); let qualname = format!("::{}", name); let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Fn); filter!(self.span_utils, sub_span, item.span, None); + + Some(Data::FunctionData(FunctionData { id: item.id, name: name, @@ -134,7 +136,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { declaration: None, span: sub_span.unwrap(), scope: self.enclosing_scope(item.id), - value: String::new(), // TODO + value: make_signature(decl, generics), })) } ast::ItemKind::Static(ref typ, mt, ref expr) => { @@ -191,17 +193,22 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { filename: filename, })) } - ast::ItemKind::Enum(..) => { - let enum_name = format!("::{}", self.tcx.node_path_str(item.id)); - let val = self.span_utils.snippet(item.span); + ast::ItemKind::Enum(ref def, _) => { + let name = item.ident.to_string(); + let qualname = format!("::{}", self.tcx.node_path_str(item.id)); let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Enum); filter!(self.span_utils, sub_span, item.span, None); + let variants_str = def.variants.iter() + .map(|v| v.node.name.to_string()) + .collect::>() + .join(", "); + let val = format!("{}::{{{}}}", name, variants_str); Some(Data::EnumData(EnumData { id: item.id, - name: item.ident.to_string(), + name: name, value: val, span: sub_span.unwrap(), - qualname: enum_name, + qualname: qualname, scope: self.enclosing_scope(item.id), })) } @@ -355,7 +362,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { declaration: decl_id, span: sub_span.unwrap(), scope: self.enclosing_scope(id), - value: String::new(), // TODO + // FIXME you get better data here by using the visitor. + value: String::new(), }) } @@ -640,6 +648,35 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } } +fn make_signature(decl: &ast::FnDecl, generics: &ast::Generics) -> String { + let mut sig = String::new(); + if !generics.lifetimes.is_empty() || !generics.ty_params.is_empty() { + sig.push('<'); + sig.push_str(&generics.lifetimes.iter() + .map(|l| l.lifetime.name.to_string()) + .collect::>() + .join(", ")); + if !generics.lifetimes.is_empty() { + sig.push_str(", "); + } + sig.push_str(&generics.ty_params.iter() + .map(|l| l.ident.to_string()) + .collect::>() + .join(", ")); + sig.push_str("> "); + } + sig.push('('); + sig.push_str(&decl.inputs.iter().map(arg_to_string).collect::>().join(", ")); + sig.push(')'); + match decl.output { + ast::FunctionRetTy::None(_) => sig.push_str(" -> !"), + ast::FunctionRetTy::Default(_) => {} + ast::FunctionRetTy::Ty(ref t) => sig.push_str(&format!(" -> {}", ty_to_string(t))), + } + + sig +} + // An AST visitor for collecting paths from patterns. struct PathCollector { // The Row field identifies the kind of pattern. diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index d1ad330c58c..e9f3472c4a1 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -2030,10 +2030,7 @@ pub enum ItemKind { /// A struct definition, e.g. `struct Foo {x: A}` Struct(VariantData, Generics), /// Represents a Trait Declaration - Trait(Unsafety, - Generics, - TyParamBounds, - Vec), + Trait(Unsafety, Generics, TyParamBounds, Vec), // Default trait implementations ///