Use the new Resolver API for goto def
This commit is contained in:
parent
33ff7b56ff
commit
afce8e4426
6 changed files with 89 additions and 35 deletions
|
|
@ -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?
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue