]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_save_analysis/lib.rs
save-analysis: handle function types in bounds
[rust.git] / src / librustc_save_analysis / lib.rs
index 3de5fda0d45c102c0f9fd52524c26942fed733c7..9769f3905c7b69aaf977ab8c6899fe7b36ae6b00 100644 (file)
@@ -38,7 +38,7 @@
 use rustc::hir;
 use rustc::hir::def::Def as HirDef;
 use rustc::hir::map::{Node, NodeItem};
-use rustc::hir::def_id::DefId;
+use rustc::hir::def_id::{LOCAL_CRATE, DefId};
 use rustc::session::config::CrateType::CrateTypeExecutable;
 use rustc::ty::{self, TyCtxt};
 use rustc_typeck::hir_ty_to_ty;
@@ -173,6 +173,8 @@ pub fn get_extern_item_data(&self, item: &ast::ForeignItem) -> Option<Data> {
                     attributes: lower_attributes(item.attrs.clone(), self),
                 }))
             }
+            // FIXME(plietar): needs a new DefKind in rls-data
+            ast::ForeignItemKind::Ty => None,
         }
     }
 
@@ -586,9 +588,9 @@ pub fn get_path_def(&self, id: NodeId) -> HirDef {
                 self.tables.qpath_def(qpath, hir_id)
             }
 
-            Node::NodeBinding(&hir::Pat { node: hir::PatKind::Binding(_, def_id, ..), .. }) => {
-                HirDef::Local(def_id)
-            }
+            Node::NodeBinding(&hir::Pat {
+                node: hir::PatKind::Binding(_, canonical_id, ..), ..
+            }) => HirDef::Local(canonical_id),
 
             Node::NodeTy(ty) => {
                 if let hir::Ty { node: hir::TyPath(ref qpath), .. } = *ty {
@@ -612,12 +614,32 @@ 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);
         match def {
-            HirDef::Upvar(..) |
-            HirDef::Local(..) |
+            HirDef::Upvar(id, ..) |
+            HirDef::Local(id) => {
+                let span = self.span_from_span(sub_span.unwrap());
+                Some(Ref {
+                    kind: RefKind::Variable,
+                    span,
+                    ref_id: id_from_node_id(id, self),
+                })
+            }
             HirDef::Static(..) |
             HirDef::Const(..) |
             HirDef::AssociatedConst(..) |
@@ -630,11 +652,22 @@ 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) |
             HirDef::Enum(def_id) |
             HirDef::TyAlias(def_id) |
+            HirDef::TyForeign(def_id) |
             HirDef::AssociatedTy(def_id) |
             HirDef::Trait(def_id) |
             HirDef::TyParam(def_id) => {
@@ -808,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 {}: {:?} {:?}",
@@ -844,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));
             }
             _ => {}
         }
@@ -1013,7 +1046,15 @@ fn id_from_def_id(id: DefId) -> rls_data::Id {
 
 fn id_from_node_id(id: NodeId, scx: &SaveContext) -> rls_data::Id {
     let def_id = scx.tcx.hir.opt_local_def_id(id);
-    def_id.map(|id| id_from_def_id(id)).unwrap_or_else(null_id)
+    def_id.map(|id| id_from_def_id(id)).unwrap_or_else(|| {
+        // Create a *fake* `DefId` out of a `NodeId` by subtracting the `NodeId`
+        // out of the maximum u32 value. This will work unless you have *billions*
+        // of definitions in a single crate (very unlikely to actually happen).
+        rls_data::Id {
+            krate: LOCAL_CRATE.as_u32(),
+            index: !id.as_u32(),
+        }
+    })
 }
 
 fn null_id() -> rls_data::Id {