]> git.lizzy.rs Git - rust.git/commitdiff
Use the new Resolver API for goto def
authorFlorian Diebold <flodiebold@gmail.com>
Tue, 29 Jan 2019 19:49:31 +0000 (20:49 +0100)
committerFlorian Diebold <flodiebold@gmail.com>
Fri, 1 Feb 2019 21:45:43 +0000 (22:45 +0100)
crates/ra_hir/src/expr.rs
crates/ra_hir/src/expr/scope.rs
crates/ra_hir/src/resolve.rs
crates/ra_hir/src/source_binder.rs
crates/ra_ide_api/src/goto_definition.rs
crates/ra_ide_api/src/navigation_target.rs

index 6c294bf108ab53176b5ac5534179f6d6deb5ef24..e78ba889e2f041ea46e7dcfd410adfd40d87d791 100644 (file)
@@ -69,6 +69,10 @@ pub fn body_expr(&self) -> ExprId {
     pub fn owner(&self) -> Function {
         self.owner
     }
+
+    pub fn syntax_mapping(&self, db: &impl HirDatabase) -> Arc<BodySyntaxMapping> {
+        db.body_syntax_mapping(self.owner)
+    }
 }
 
 // needs arbitrary_self_types to be a method... or maybe move to the def?
index 23f1c5e7f2747c70637a0da4db0c2fed4d17069f..9202e367126edc5785e1b31a610b420bc892a941 100644 (file)
@@ -58,6 +58,10 @@ fn new(body: Arc<Body>) -> ExprScopes {
         scopes
     }
 
+    pub fn body(&self) -> Arc<Body> {
+        self.body.clone()
+    }
+
     pub fn entries(&self, scope: ScopeId) -> &[ScopeEntry] {
         &self.scopes[scope].entries
     }
@@ -220,7 +224,7 @@ pub fn find_all_refs(&self, pat: &ast::BindPat) -> Vec<ReferenceDescriptor> {
             .collect()
     }
 
-    fn scope_for(&self, node: &SyntaxNode) -> Option<ScopeId> {
+    pub fn scope_for(&self, node: &SyntaxNode) -> Option<ScopeId> {
         node.ancestors()
             .map(SyntaxNodePtr::new)
             .filter_map(|ptr| self.syntax_mapping.syntax_expr(ptr))
index 30cf9c69e7acdd25284b9daaace9d9f6309c0c89..871f7d8f72ba7e6dbe26328e105ff0b2d5814dae 100644 (file)
@@ -9,7 +9,7 @@
     name::{Name, KnownName},
     nameres::{PerNs, ItemMap},
     generics::GenericParams,
-    expr::{scope::{ExprScopes, ScopeId}, PatId},
+    expr::{scope::{ExprScopes, ScopeId}, PatId, Body},
     impl_block::ImplBlock,
     path::Path,
 };
@@ -106,15 +106,21 @@ pub fn all_names(&self) -> FxHashMap<Name, PerNs<Resolution>> {
     }
 
     fn module(&self) -> Option<(&ItemMap, Module)> {
-        for scope in self.scopes.iter().rev() {
-            match scope {
-                Scope::ModuleScope(m) => {
-                    return Some((&m.item_map, m.module.clone()));
-                }
-                _ => {}
-            }
-        }
-        None
+        self.scopes.iter().rev().find_map(|scope| match scope {
+            Scope::ModuleScope(m) => Some((&*m.item_map, m.module.clone())),
+
+            Scope::ModuleScopeRef(m) => Some((m.item_map, m.module.clone())),
+
+            _ => None,
+        })
+    }
+
+    /// The body from which any `LocalBinding` resolutions in this resolver come.
+    pub fn body(&self) -> Option<Arc<Body>> {
+        self.scopes.iter().rev().find_map(|scope| match scope {
+            Scope::ExprScope(expr_scope) => Some(expr_scope.expr_scopes.body()),
+            _ => None,
+        })
     }
 }
 
index 998158b3e867ccc4614c1a8c49a68f8098d1844f..621215bfb7b29d2ded5281f844afd518f26d1a6d 100644 (file)
@@ -229,3 +229,31 @@ pub fn resolver_for_position(db: &impl HirDatabase, position: FilePosition) -> R
         })
         .unwrap_or_default()
 }
+
+pub fn resolver_for_node(
+    db: &impl HirDatabase,
+    file_id: FileId,
+    node: &SyntaxNode,
+) -> Resolver<'static> {
+    node.ancestors()
+        .find_map(|node| {
+            if ast::Expr::cast(node).is_some() || ast::Block::cast(node).is_some() {
+                if let Some(func) = function_from_child_node(db, file_id, node) {
+                    let scopes = func.scopes(db);
+                    let scope = scopes.scope_for(&node);
+                    Some(expr::resolver_for_scope(func.body(db), db, scope))
+                } else {
+                    // TODO const/static/array length
+                    None
+                }
+            } else if let Some(module) = ast::Module::cast(node) {
+                Some(module_from_declaration(db, file_id, module)?.resolver(db))
+            } else if let Some(_) = ast::SourceFile::cast(node) {
+                Some(module_from_source(db, file_id.into(), None)?.resolver(db))
+            } else {
+                // TODO add missing cases
+                None
+            }
+        })
+        .unwrap_or_default()
+}
index 2a20c20ee9e1ef476e3a518db42dce3ba9a1b5de..f7dd28c7c66a0ca230553acf32dd2651ed922fb9 100644 (file)
@@ -48,14 +48,7 @@ pub(crate) fn reference_definition(
     if let Some(function) =
         hir::source_binder::function_from_child_node(db, file_id, name_ref.syntax())
     {
-        let scope = function.scopes(db);
-        // First try to resolve the symbol locally
-        if let Some(entry) = scope.resolve_local_name(name_ref) {
-            let nav = NavigationTarget::from_scope_entry(file_id, &entry);
-            return Exact(nav);
-        };
-
-        // Next check if it is a method
+        // Check if it is a method
         if let Some(method_call) = name_ref
             .syntax()
             .parent()
@@ -86,19 +79,37 @@ pub(crate) fn reference_definition(
             };
         }
     }
-    // Then try module name resolution
-    if let Some(module) = hir::source_binder::module_from_child_node(db, file_id, name_ref.syntax())
+    // Try name resolution
+    let resolver = hir::source_binder::resolver_for_node(db, file_id, name_ref.syntax());
+    if let Some(path) = name_ref
+        .syntax()
+        .ancestors()
+        .find_map(ast::Path::cast)
+        .and_then(hir::Path::from_ast)
     {
-        if let Some(path) = name_ref
-            .syntax()
-            .ancestors()
-            .find_map(ast::Path::cast)
-            .and_then(hir::Path::from_ast)
-        {
-            let resolved = module.resolve_path(db, &path);
-            if let Some(def_id) = resolved.take_types().or(resolved.take_values()) {
-                return Exact(NavigationTarget::from_def(db, def_id));
+        let resolved = resolver.resolve_path(db, &path);
+        match resolved.clone().take_types().or(resolved.take_values()) {
+            Some(Resolution::Def { def }) => return Exact(NavigationTarget::from_def(db, def)),
+            Some(Resolution::LocalBinding { pat }) => {
+                let body = resolver.body().expect("no body for local binding");
+                let syntax_mapping = body.syntax_mapping(db);
+                let ptr = syntax_mapping
+                    .pat_syntax(pat)
+                    .expect("pattern not found in syntax mapping");
+                let name = path
+                    .as_ident()
+                    .cloned()
+                    .expect("local binding from a multi-segment path");
+                let nav = NavigationTarget::from_scope_entry(file_id, name, ptr);
+                return Exact(nav);
+            }
+            Some(Resolution::GenericParam { .. }) => {
+                // TODO go to the generic param def
+            }
+            Some(Resolution::SelfType(_impl_block)) => {
+                // TODO go to the implemented type
             }
+            None => {}
         }
     }
     // If that fails try the index based approach.
index 5ccb5cc2e3c05fc7d27582a5ed9de78358a174be..617908aedfef9a763410e2c0c1b759ed2380c87b 100644 (file)
@@ -1,9 +1,9 @@
 use ra_db::FileId;
 use ra_syntax::{
-    SyntaxNode, AstNode, SmolStr, TextRange, ast,
+    SyntaxNode, SyntaxNodePtr, AstNode, SmolStr, TextRange, ast,
     SyntaxKind::{self, NAME},
 };
-use hir::{ModuleSource, FieldSource};
+use hir::{ModuleSource, FieldSource, Name};
 
 use crate::{FileSymbol, db::RootDatabase};
 
@@ -58,12 +58,13 @@ pub(crate) fn from_symbol(symbol: FileSymbol) -> NavigationTarget {
 
     pub(crate) fn from_scope_entry(
         file_id: FileId,
-        entry: &hir::ScopeEntryWithSyntax,
+        name: Name,
+        ptr: SyntaxNodePtr,
     ) -> NavigationTarget {
         NavigationTarget {
             file_id,
-            name: entry.name().to_string().into(),
-            full_range: entry.ptr().range(),
+            name: name.to_string().into(),
+            full_range: ptr.range(),
             focus_range: None,
             kind: NAME,
         }