Use the new Resolver API for goto def

This commit is contained in:
Florian Diebold 2019-01-29 20:49:31 +01:00
parent 33ff7b56ff
commit afce8e4426
6 changed files with 89 additions and 35 deletions

View file

@ -69,6 +69,10 @@ impl Body {
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?

View file

@ -58,6 +58,10 @@ impl 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 @@ impl ScopesWithSyntaxMapping {
.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))

View file

@ -9,7 +9,7 @@ use crate::{
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 @@ impl Resolver {
}
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,
})
}
}

View 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()
}

View 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.

View 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 @@ impl 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,
}