From c1d3e441a8c6d24bc61d3deb22a0909401767ada Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 1 Nov 2017 17:59:06 +1300 Subject: [PATCH] save-analysis: handle function types in bounds This special cases the function type sugar in paths and deals with traits bounds as just the path parts. That required refactoring the path collector to distinguish between variable decls and references in patterns, basically just to please the borrow checker. cc https://github.com/nrc/rls-analysis/issues/37 --- src/librustc_save_analysis/dump_visitor.rs | 84 +++++++++++----------- src/librustc_save_analysis/lib.rs | 55 +++++++++----- 2 files changed, 81 insertions(+), 58 deletions(-) diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 4eac4398c18..11f62b4bd80 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -318,16 +318,15 @@ fn process_formals(&mut self, formals: &'l [ast::Arg], qualname: &str) { let mut collector = PathCollector::new(); collector.visit_pat(&arg.pat); let span_utils = self.span.clone(); - for &(id, ref p, ..) in &collector.collected_paths { + + for (id, i, sp, ..) in collector.collected_idents { let hir_id = self.tcx.hir.node_to_hir_id(id); let typ = match self.save_ctxt.tables.node_id_to_type_opt(hir_id) { Some(s) => s.to_string(), None => continue, }; - // 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 = span_utils.span_for_last_ident(p.span); - if !self.span.filter_generated(sub_span, p.span) { + let sub_span = span_utils.span_for_last_ident(sp); + if !self.span.filter_generated(sub_span, sp) { let id = ::id_from_node_id(id, &self.save_ctxt); let span = self.span_from_span(sub_span.expect("No span found for variable")); @@ -335,8 +334,8 @@ fn process_formals(&mut self, formals: &'l [ast::Arg], qualname: &str) { kind: DefKind::Local, id, span, - name: path_to_string(p), - qualname: format!("{}::{}", qualname, path_to_string(p)), + name: i.to_string(), + qualname: format!("{}::{}", qualname, i.to_string()), value: typ, parent: None, children: vec![], @@ -391,14 +390,6 @@ fn process_method(&mut self, } } - fn process_trait_ref(&mut self, trait_ref: &'l ast::TraitRef) { - let trait_ref_data = self.save_ctxt.get_trait_ref_data(trait_ref); - if let Some(trait_ref_data) = trait_ref_data { - self.dumper.dump_ref(trait_ref_data); - } - self.process_path(trait_ref.ref_id, &trait_ref.path); - } - fn process_struct_field_def(&mut self, field: &ast::StructField, parent_id: NodeId) { let field_data = self.save_ctxt.get_field_data(field, parent_id); if let Some(field_data) = field_data { @@ -783,7 +774,7 @@ fn process_mod(&mut self, item: &ast::Item) { } } - fn process_path(&mut self, id: NodeId, path: &ast::Path) { + fn process_path(&mut self, id: NodeId, path: &'l ast::Path) { let path_data = self.save_ctxt.get_path_data(id, path); if generated_code(path.span) && path_data.is_none() { return; @@ -798,6 +789,27 @@ fn process_path(&mut self, id: NodeId, path: &ast::Path) { self.dumper.dump_ref(path_data); + // Type parameters + for seg in &path.segments { + if let Some(ref params) = seg.parameters { + match **params { + ast::PathParameters::AngleBracketed(ref data) => { + for t in &data.types { + self.visit_ty(t); + } + } + ast::PathParameters::Parenthesized(ref data) => { + for t in &data.inputs { + self.visit_ty(t); + } + if let Some(ref t) = data.output { + self.visit_ty(t); + } + } + } + } + } + // Modules or types in the path prefix. match self.save_ctxt.get_path_def(id) { HirDef::Method(did) => { @@ -904,7 +916,7 @@ fn process_var_decl(&mut self, p: &'l ast::Pat, value: String) { collector.visit_pat(&p); self.visit_pat(&p); - for &(id, ref p, immut) in &collector.collected_paths { + for (id, i, sp, immut) in collector.collected_idents { let mut value = match immut { ast::Mutability::Immutable => value.to_string(), _ => String::new(), @@ -924,10 +936,10 @@ fn process_var_decl(&mut self, p: &'l ast::Pat, value: String) { // 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); + let sub_span = self.span.span_for_last_ident(sp); // Rust uses the id of the pattern for var lookups, so we'll use it too. - if !self.span.filter_generated(sub_span, p.span) { - let qualname = format!("{}${}", path_to_string(p), id); + if !self.span.filter_generated(sub_span, sp) { + let qualname = format!("{}${}", i.to_string(), id); let id = ::id_from_node_id(id, &self.save_ctxt); let span = self.span_from_span(sub_span.expect("No span found for variable")); @@ -935,7 +947,7 @@ fn process_var_decl(&mut self, p: &'l ast::Pat, value: String) { kind: DefKind::Local, id, span, - name: path_to_string(p), + name: i.to_string(), qualname, value: typ, parent: None, @@ -1263,7 +1275,7 @@ fn visit_generics(&mut self, generics: &'l ast::Generics) { for param in generics.ty_params.iter() { for bound in param.bounds.iter() { if let ast::TraitTyParamBound(ref trait_ref, _) = *bound { - self.process_trait_ref(&trait_ref.trait_ref); + self.process_path(trait_ref.trait_ref.ref_id, &trait_ref.trait_ref.path) } } if let Some(ref ty) = param.default { @@ -1430,15 +1442,12 @@ fn visit_arm(&mut self, arm: &'l ast::Arm) { self.visit_pat(&pattern); } - // This is to get around borrow checking, because we need mut self to call process_path. - let mut paths_to_process = vec![]; - // process collected paths - for &(id, ref p, immut) in &collector.collected_paths { + for (id, i, sp, immut) in collector.collected_idents { match self.save_ctxt.get_path_def(id) { HirDef::Local(id) => { let mut value = if immut == ast::Mutability::Immutable { - self.span.snippet(p.span).to_string() + self.span.snippet(sp).to_string() } else { "".to_string() }; @@ -1451,18 +1460,16 @@ fn visit_arm(&mut self, arm: &'l ast::Arm) { value.push_str(": "); value.push_str(&typ); - assert!(p.segments.len() == 1, - "qualified path for local variable def in arm"); - if !self.span.filter_generated(Some(p.span), p.span) { - let qualname = format!("{}${}", path_to_string(p), id); + if !self.span.filter_generated(Some(sp), sp) { + let qualname = format!("{}${}", i.to_string(), id); let id = ::id_from_node_id(id, &self.save_ctxt); - let span = self.span_from_span(p.span); + let span = self.span_from_span(sp); self.dumper.dump_def(false, Def { kind: DefKind::Local, id, span, - name: path_to_string(p), + name: i.to_string(), qualname, value: typ, parent: None, @@ -1474,19 +1481,12 @@ fn visit_arm(&mut self, arm: &'l ast::Arm) { }); } } - HirDef::StructCtor(..) | HirDef::VariantCtor(..) | - HirDef::Const(..) | HirDef::AssociatedConst(..) | - HirDef::Struct(..) | HirDef::Variant(..) | - HirDef::TyAlias(..) | HirDef::AssociatedTy(..) | - HirDef::SelfTy(..) => { - paths_to_process.push((id, p.clone())) - } - def => error!("unexpected definition kind when processing collected paths: {:?}", + def => error!("unexpected definition kind when processing collected idents: {:?}", def), } } - for &(id, ref path) in &paths_to_process { + for (id, ref path) in collector.collected_paths { self.process_path(id, path); } walk_list!(self, visit_expr, &arm.guard); diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index cf2cad1b38c..9769f3905c7 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -614,6 +614,19 @@ pub fn get_path_def(&self, id: NodeId) -> HirDef { } pub fn get_path_data(&self, id: NodeId, path: &ast::Path) -> Option { + // Returns true if the path is function type sugar, e.g., `Fn(A) -> B`. + fn fn_type(path: &ast::Path) -> bool { + if path.segments.len() != 1 { + return false; + } + if let Some(ref params) = path.segments[0].parameters { + if let ast::PathParameters::Parenthesized(_) = **params { + return true; + } + } + false + } + let def = self.get_path_def(id); let sub_span = self.span_utils.span_for_last_ident(path.span); filter!(self.span_utils, sub_span, path.span, None); @@ -639,6 +652,16 @@ pub fn get_path_data(&self, id: NodeId, path: &ast::Path) -> Option { ref_id: id_from_def_id(def.def_id()), }) } + HirDef::Trait(def_id) if fn_type(path) => { + // Function type bounds are desugared in the parser, so we have to + // special case them here. + let fn_span = self.span_utils.span_for_first_ident(path.span); + fn_span.map(|span| Ref { + kind: RefKind::Type, + span: self.span_from_span(span), + ref_id: id_from_def_id(def_id), + }) + } HirDef::Struct(def_id) | HirDef::Variant(def_id, ..) | HirDef::Union(def_id) | @@ -818,29 +841,31 @@ fn make_signature(decl: &ast::FnDecl, generics: &ast::Generics) -> String { sig } -// An AST visitor for collecting paths from patterns. -struct PathCollector { - // The Row field identifies the kind of pattern. - collected_paths: Vec<(NodeId, ast::Path, ast::Mutability)>, +// An AST visitor for collecting paths (e.g., the names of structs) and formal +// variables (idents) from patterns. +struct PathCollector<'l> { + collected_paths: Vec<(NodeId, &'l ast::Path)>, + collected_idents: Vec<(NodeId, ast::Ident, Span, ast::Mutability)>, } -impl PathCollector { - fn new() -> PathCollector { - PathCollector { collected_paths: vec![] } +impl<'l> PathCollector<'l> { + fn new() -> PathCollector<'l> { + PathCollector { + collected_paths: vec![], + collected_idents: vec![], + } } } -impl<'a> Visitor<'a> for PathCollector { - fn visit_pat(&mut self, p: &ast::Pat) { +impl<'l, 'a: 'l> Visitor<'a> for PathCollector<'l> { + fn visit_pat(&mut self, p: &'a ast::Pat) { match p.node { PatKind::Struct(ref path, ..) => { - self.collected_paths.push((p.id, path.clone(), - ast::Mutability::Mutable)); + self.collected_paths.push((p.id, path)); } PatKind::TupleStruct(ref path, ..) | PatKind::Path(_, ref path) => { - self.collected_paths.push((p.id, path.clone(), - ast::Mutability::Mutable)); + self.collected_paths.push((p.id, path)); } PatKind::Ident(bm, ref path1, _) => { debug!("PathCollector, visit ident in pat {}: {:?} {:?}", @@ -854,9 +879,7 @@ fn visit_pat(&mut self, p: &ast::Pat) { ast::BindingMode::ByRef(_) => ast::Mutability::Immutable, ast::BindingMode::ByValue(mt) => mt, }; - // collect path for either visit_local or visit_arm - let path = ast::Path::from_ident(path1.span, path1.node); - self.collected_paths.push((p.id, path, immut)); + self.collected_idents.push((p.id, path1.node, path1.span, immut)); } _ => {} } -- 2.44.0