]> git.lizzy.rs Git - rust.git/commitdiff
save-analysis: handle function types in bounds
authorNick Cameron <ncameron@mozilla.com>
Wed, 1 Nov 2017 04:59:06 +0000 (17:59 +1300)
committerNick Cameron <ncameron@mozilla.com>
Wed, 1 Nov 2017 19:12:05 +0000 (08:12 +1300)
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
src/librustc_save_analysis/lib.rs

index 4eac4398c1827c15da5c684296acae6be7dd34da..11f62b4bd804ee950ca0e68abe8d6ff5725c47df 100644 (file)
@@ -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 {
                         "<mutable>".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);
index cf2cad1b38c42c9280c04a3da78526acb130f9ba..9769f3905c7b69aaf977ab8c6899fe7b36ae6b00 100644 (file)
@@ -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<Ref> {
+        // 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> {
                     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));
             }
             _ => {}
         }