From 33ff7b56ff353410e7bcb7aed27004d4f0a57d8e Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sun, 27 Jan 2019 20:50:57 +0100 Subject: Use the new Resolver API in completion --- crates/ra_hir/src/expr.rs | 18 ++++++++++-- crates/ra_hir/src/expr/scope.rs | 38 ++++++------------------- crates/ra_hir/src/nameres.rs | 9 ++++++ crates/ra_hir/src/resolve.rs | 57 ++++++++++++++++++++++++++++++++++++-- crates/ra_hir/src/source_binder.rs | 31 ++++++++++++++++++--- 5 files changed, 115 insertions(+), 38 deletions(-) (limited to 'crates/ra_hir') diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index 503a09f25..6c294bf10 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs @@ -72,11 +72,23 @@ impl Body { } // needs arbitrary_self_types to be a method... or maybe move to the def? -#[allow(dead_code)] -pub fn resolver_for_expr(body: Arc, db: &impl HirDatabase, expr_id: ExprId) -> Resolver { +pub fn resolver_for_expr( + body: Arc, + db: &impl HirDatabase, + expr_id: ExprId, +) -> Resolver<'static> { + let scopes = db.expr_scopes(body.owner); + resolver_for_scope(body, db, scopes.scope_for(expr_id)) +} + +pub fn resolver_for_scope( + body: Arc, + db: &impl HirDatabase, + scope_id: Option, +) -> Resolver<'static> { let mut r = body.owner.resolver(db); let scopes = db.expr_scopes(body.owner); - let scope_chain = scopes.scope_chain_for(expr_id).collect::>(); + let scope_chain = scopes.scope_chain_for(scope_id).collect::>(); for scope in scope_chain.into_iter().rev() { r = r.push_expr_scope(Arc::clone(&scopes), scope); } diff --git a/crates/ra_hir/src/expr/scope.rs b/crates/ra_hir/src/expr/scope.rs index 887ad8dd8..23f1c5e7f 100644 --- a/crates/ra_hir/src/expr/scope.rs +++ b/crates/ra_hir/src/expr/scope.rs @@ -62,25 +62,11 @@ impl ExprScopes { &self.scopes[scope].entries } - pub fn scope_chain_for<'a>(&'a self, expr: ExprId) -> impl Iterator + 'a { - generate(self.scope_for(expr), move |&scope| { - self.scopes[scope].parent - }) - } - - pub fn resolve_local_name<'a>( + pub fn scope_chain_for<'a>( &'a self, - context_expr: ExprId, - name: Name, - ) -> Option<&'a ScopeEntry> { - // TODO replace by Resolver::resolve_name - let mut shadowed = FxHashSet::default(); - let ret = self - .scope_chain_for(context_expr) - .flat_map(|scope| self.entries(scope).iter()) - .filter(|entry| shadowed.insert(entry.name())) - .find(|entry| entry.name() == &name); - ret + scope: Option, + ) -> impl Iterator + 'a { + generate(scope, move |&scope| self.scopes[scope].parent) } fn root_scope(&mut self) -> ScopeId { @@ -123,7 +109,7 @@ impl ExprScopes { self.scope_for.insert(node, scope); } - fn scope_for(&self, expr: ExprId) -> Option { + pub fn scope_for(&self, expr: ExprId) -> Option { self.scope_for.get(&expr).map(|&scope| scope) } } @@ -151,18 +137,14 @@ impl ScopeEntryWithSyntax { } impl ScopesWithSyntaxMapping { - pub fn scope_chain<'a>(&'a self, node: &SyntaxNode) -> impl Iterator + 'a { + fn scope_chain<'a>(&'a self, node: &SyntaxNode) -> impl Iterator + 'a { generate(self.scope_for(node), move |&scope| { self.scopes.scopes[scope].parent }) } - pub fn scope_chain_for_offset<'a>( - &'a self, - offset: TextUnit, - ) -> impl Iterator + 'a { - let scope = self - .scopes + pub fn scope_for_offset<'a>(&'a self, offset: TextUnit) -> Option { + self.scopes .scope_for .iter() .filter_map(|(id, scope)| Some((self.syntax_mapping.expr_syntax(*id)?, scope))) @@ -173,9 +155,7 @@ impl ScopesWithSyntaxMapping { ptr.range().len(), ) }) - .map(|(ptr, scope)| self.adjust(ptr, *scope, offset)); - - generate(scope, move |&scope| self.scopes.scopes[scope].parent) + .map(|(ptr, scope)| self.adjust(ptr, *scope, offset)) } // XXX: during completion, cursor might be outside of any particular diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index 193c6a977..9b020db81 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs @@ -81,6 +81,15 @@ pub struct PerNs { pub values: Option, } +impl Default for PerNs { + fn default() -> Self { + PerNs { + types: None, + values: None, + } + } +} + impl PerNs { pub fn none() -> PerNs { PerNs { diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index 36daed65b..30cf9c69e 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs @@ -89,8 +89,20 @@ impl Resolver { } } - pub fn all_names(&self) -> FxHashMap { - unimplemented!() + pub fn all_names(&self) -> FxHashMap> { + let mut names = FxHashMap::default(); + for scope in &self.scopes { + scope.collect_names(&mut |name, res| { + let current: &mut PerNs = names.entry(name).or_default(); + if current.types.is_none() { + current.types = res.types; + } + if current.values.is_none() { + current.values = res.values; + } + }); + } + names } fn module(&self) -> Option<(&ItemMap, Module)> { @@ -175,4 +187,45 @@ impl Scope { } } } + + fn collect_names(&self, f: &mut FnMut(Name, PerNs)) { + match self { + Scope::ModuleScope(m) => { + m.item_map[m.module.module_id] + .entries() + .for_each(|(name, res)| { + f(name.clone(), res.def.map(|def| Resolution::Def { def })); + }) + } + Scope::ModuleScopeRef(m) => { + m.item_map[m.module.module_id] + .entries() + .for_each(|(name, res)| { + f(name.clone(), res.def.map(|def| Resolution::Def { def })); + }) + } + Scope::GenericParams(gp) => { + for param in &gp.params { + f( + param.name.clone(), + PerNs::types(Resolution::GenericParam { idx: param.idx }), + ) + } + } + Scope::ImplBlockScope(i) => { + f( + Name::self_type(), + PerNs::types(Resolution::SelfType(i.clone())), + ); + } + Scope::ExprScope(e) => { + e.expr_scopes.entries(e.scope_id).iter().for_each(|e| { + f( + e.name().clone(), + PerNs::values(Resolution::LocalBinding { pat: e.pat() }), + ); + }); + } + } + } } diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index 1fdd7d087..998158b3e 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs @@ -9,13 +9,14 @@ use ra_db::{FileId, FilePosition}; use ra_syntax::{ SmolStr, TextRange, SyntaxNode, ast::{self, AstNode, NameOwner}, - algo::find_node_at_offset, + algo::{find_node_at_offset, find_leaf_at_offset}, }; use crate::{ HirDatabase, Function, ModuleDef, Struct, Enum, AsName, Module, HirFileId, Crate, Trait, Resolver, ids::{LocationCtx, SourceFileItemId}, + expr }; /// Locates the module by `FileId`. Picks topmost module in the file. @@ -202,7 +203,29 @@ pub fn macro_symbols(db: &impl HirDatabase, file_id: FileId) -> Vec<(SmolStr, Te res } -#[allow(unused_variables)] -pub fn resolver_for_position(db: &impl HirDatabase, position: FilePosition) -> Resolver { - unimplemented!() +pub fn resolver_for_position(db: &impl HirDatabase, position: FilePosition) -> Resolver<'static> { + let file = db.parse(position.file_id); + find_leaf_at_offset(file.syntax(), position.offset) + .find_map(|node| { + 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, position.file_id, node) { + let scopes = func.scopes(db); + let scope = scopes.scope_for_offset(position.offset); + 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, position.file_id, module)?.resolver(db)) + } else if let Some(_) = ast::SourceFile::cast(node) { + Some(module_from_source(db, position.file_id.into(), None)?.resolver(db)) + } else { + // TODO add missing cases + None + } + }) + }) + .unwrap_or_default() } -- cgit v1.2.3