diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs
index 503a09f25e..6c294bf108 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 887ad8dd8b..23f1c5e7f2 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 193c6a9779..9b020db811 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 36daed65b8..30cf9c69e7 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 1fdd7d087a..998158b3e8 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()
}
diff --git a/crates/ra_ide_api/src/completion/complete_path.rs b/crates/ra_ide_api/src/completion/complete_path.rs
index b33ddcde56..9e61c02127 100644
--- a/crates/ra_ide_api/src/completion/complete_path.rs
+++ b/crates/ra_ide_api/src/completion/complete_path.rs
@@ -7,13 +7,13 @@ use crate::{
use hir::Docs;
pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) {
- let (path, module) = match (&ctx.path_prefix, &ctx.module) {
- (Some(path), Some(module)) => (path.clone(), module),
+ let path = match &ctx.path_prefix {
+ Some(path) => path.clone(),
_ => return,
};
- let def_id = match module.resolve_path(ctx.db, &path).take_types() {
- Some(it) => it,
- None => return,
+ let def = match ctx.resolver.resolve_path(ctx.db, &path).take_types() {
+ Some(Resolution::Def { def }) => def,
+ _ => return,
};
match def_id {
hir::ModuleDef::Module(module) => {
@@ -24,7 +24,7 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) {
ctx.source_range(),
name.to_string(),
)
- .from_resolution(ctx, res)
+ .from_resolution(ctx, &res.def.map(|def| hir::Resolution::Def { def }))
.add_to(acc);
}
}
diff --git a/crates/ra_ide_api/src/completion/complete_scope.rs b/crates/ra_ide_api/src/completion/complete_scope.rs
index f837bb1db2..3488d64806 100644
--- a/crates/ra_ide_api/src/completion/complete_scope.rs
+++ b/crates/ra_ide_api/src/completion/complete_scope.rs
@@ -1,61 +1,32 @@
-use rustc_hash::FxHashSet;
-use ra_syntax::ast::AstNode;
-use crate::completion::{CompletionItem, CompletionItemKind, Completions, CompletionKind, CompletionContext};
+use crate::completion::{CompletionItem, Completions, CompletionKind, CompletionContext};
pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) {
if !ctx.is_trivial_path {
return;
}
- let module = match &ctx.module {
- Some(it) => it,
- None => return,
- };
- if let Some(function) = &ctx.function {
- let scopes = function.scopes(ctx.db);
- complete_fn(acc, &scopes, ctx);
- }
+ let names = ctx.resolver.all_names();
- let module_scope = module.scope(ctx.db);
- module_scope
- .entries()
- .filter(|(_name, res)| {
- // For cases like `use self::foo<|>` don't suggest foo itself.
- match res.import {
- None => true,
- Some(import) => {
- let source = module.import_source(ctx.db, import);
- !source.syntax().range().is_subrange(&ctx.leaf.range())
- }
- }
- })
+ // let module_scope = module.scope(ctx.db);
+ names
+ .into_iter()
+ // FIXME check tests
+ // .filter(|(_name, res)| {
+ // // For cases like `use self::foo<|>` don't suggest foo itself.
+ // match res.import {
+ // None => true,
+ // Some(import) => {
+ // let source = module.import_source(ctx.db, import);
+ // !source.syntax().range().is_subrange(&ctx.leaf.range())
+ // }
+ // }
+ // })
.for_each(|(name, res)| {
CompletionItem::new(
CompletionKind::Reference,
ctx.source_range(),
name.to_string(),
)
- .from_resolution(ctx, res)
- .add_to(acc)
- });
-}
-
-fn complete_fn(
- acc: &mut Completions,
- scopes: &hir::ScopesWithSyntaxMapping,
- ctx: &CompletionContext,
-) {
- let mut shadowed = FxHashSet::default();
- scopes
- .scope_chain_for_offset(ctx.offset)
- .flat_map(|scope| scopes.scopes.entries(scope).iter())
- .filter(|entry| shadowed.insert(entry.name()))
- .for_each(|entry| {
- CompletionItem::new(
- CompletionKind::Reference,
- ctx.source_range(),
- entry.name().to_string(),
- )
- .kind(CompletionItemKind::Binding)
+ .from_resolution(ctx, &res)
.add_to(acc)
});
}
diff --git a/crates/ra_ide_api/src/completion/completion_context.rs b/crates/ra_ide_api/src/completion/completion_context.rs
index 578af6e5b3..aea32fce39 100644
--- a/crates/ra_ide_api/src/completion/completion_context.rs
+++ b/crates/ra_ide_api/src/completion/completion_context.rs
@@ -5,7 +5,7 @@ use ra_syntax::{
algo::{find_leaf_at_offset, find_covering_node, find_node_at_offset},
SyntaxKind::*,
};
-use hir::source_binder;
+use hir::{source_binder, Resolver};
use crate::{db, FilePosition};
@@ -16,6 +16,7 @@ pub(crate) struct CompletionContext<'a> {
pub(super) db: &'a db::RootDatabase,
pub(super) offset: TextUnit,
pub(super) leaf: &'a SyntaxNode,
+ pub(super) resolver: Resolver<'static>,
pub(super) module: Option,
pub(super) function: Option,
pub(super) function_syntax: Option<&'a ast::FnDef>,
@@ -42,12 +43,14 @@ impl<'a> CompletionContext<'a> {
original_file: &'a SourceFile,
position: FilePosition,
) -> Option> {
+ let resolver = source_binder::resolver_for_position(db, position);
let module = source_binder::module_from_position(db, position);
let leaf = find_leaf_at_offset(original_file.syntax(), position.offset).left_biased()?;
let mut ctx = CompletionContext {
db,
leaf,
offset: position.offset,
+ resolver,
module,
function: None,
function_syntax: None,
diff --git a/crates/ra_ide_api/src/completion/completion_item.rs b/crates/ra_ide_api/src/completion/completion_item.rs
index d3bc148944..4101ce88a0 100644
--- a/crates/ra_ide_api/src/completion/completion_item.rs
+++ b/crates/ra_ide_api/src/completion/completion_item.rs
@@ -1,5 +1,7 @@
-use hir::{Docs, Documentation};
-use ra_syntax::TextRange;
+use hir::{Docs, Documentation, PerNs, Resolution};
+use ra_syntax::{
+ TextRange,
+};
use ra_text_edit::TextEdit;
use test_utils::tested_by;
@@ -48,6 +50,7 @@ pub enum CompletionItemKind {
Trait,
TypeAlias,
Method,
+ TypeParam,
}
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
@@ -207,23 +210,38 @@ impl Builder {
pub(super) fn from_resolution(
mut self,
ctx: &CompletionContext,
- resolution: &hir::Resolution,
+ resolution: &PerNs,
) -> Builder {
- let def = resolution.def.take_types().or(resolution.def.take_values());
+ use hir::ModuleDef::*;
+
+ let def = resolution
+ .as_ref()
+ .take_types()
+ .or(resolution.as_ref().take_values());
let def = match def {
None => return self,
Some(it) => it,
};
let (kind, docs) = match def {
- hir::ModuleDef::Module(it) => (CompletionItemKind::Module, it.docs(ctx.db)),
- hir::ModuleDef::Function(func) => return self.from_function(ctx, func),
- hir::ModuleDef::Struct(it) => (CompletionItemKind::Struct, it.docs(ctx.db)),
- hir::ModuleDef::Enum(it) => (CompletionItemKind::Enum, it.docs(ctx.db)),
- hir::ModuleDef::EnumVariant(it) => (CompletionItemKind::EnumVariant, it.docs(ctx.db)),
- hir::ModuleDef::Const(it) => (CompletionItemKind::Const, it.docs(ctx.db)),
- hir::ModuleDef::Static(it) => (CompletionItemKind::Static, it.docs(ctx.db)),
- hir::ModuleDef::Trait(it) => (CompletionItemKind::Trait, it.docs(ctx.db)),
- hir::ModuleDef::Type(it) => (CompletionItemKind::TypeAlias, it.docs(ctx.db)),
+ Resolution::Def { def: Module(it) } => (CompletionItemKind::Module, it.docs(ctx.db)),
+ Resolution::Def {
+ def: Function(func),
+ } => return self.from_function(ctx, *func),
+ Resolution::Def { def: Struct(it) } => (CompletionItemKind::Struct, it.docs(ctx.db)),
+ Resolution::Def { def: Enum(it) } => (CompletionItemKind::Enum, it.docs(ctx.db)),
+ Resolution::Def {
+ def: EnumVariant(it),
+ } => (CompletionItemKind::EnumVariant, it.docs(ctx.db)),
+ Resolution::Def { def: Const(it) } => (CompletionItemKind::Const, it.docs(ctx.db)),
+ Resolution::Def { def: Static(it) } => (CompletionItemKind::Static, it.docs(ctx.db)),
+ Resolution::Def { def: Trait(it) } => (CompletionItemKind::Trait, it.docs(ctx.db)),
+ Resolution::Def { def: Type(it) } => (CompletionItemKind::TypeAlias, it.docs(ctx.db)),
+ Resolution::GenericParam { .. } => (CompletionItemKind::TypeParam, None),
+ Resolution::LocalBinding { .. } => (CompletionItemKind::Binding, None),
+ Resolution::SelfType { .. } => (
+ CompletionItemKind::TypeParam, // (does this need its own kind?)
+ None,
+ ),
};
self.kind = Some(kind);
self.documentation = docs;
diff --git a/crates/ra_ide_api/src/completion/snapshots/completion_item__self_in_methods.snap b/crates/ra_ide_api/src/completion/snapshots/completion_item__self_in_methods.snap
index 6a49e325c1..ba1d4abbd5 100644
--- a/crates/ra_ide_api/src/completion/snapshots/completion_item__self_in_methods.snap
+++ b/crates/ra_ide_api/src/completion/snapshots/completion_item__self_in_methods.snap
@@ -1,10 +1,24 @@
---
-created: "2019-01-23T05:27:32.422259+00:00"
-creator: insta@0.4.0
+created: "2019-01-27T20:17:10.051725945+00:00"
+creator: insta@0.5.2
expression: kind_completions
source: crates/ra_ide_api/src/completion/completion_item.rs
---
[
+ CompletionItem {
+ completion_kind: Reference,
+ label: "Self",
+ kind: Some(
+ TypeParam
+ ),
+ detail: None,
+ documentation: None,
+ lookup: None,
+ insert_text: None,
+ insert_text_format: PlainText,
+ source_range: [25; 25),
+ text_edit: None
+ },
CompletionItem {
completion_kind: Reference,
label: "self",
diff --git a/crates/ra_lsp_server/src/conv.rs b/crates/ra_lsp_server/src/conv.rs
index c033ecdeaa..17fa073406 100644
--- a/crates/ra_lsp_server/src/conv.rs
+++ b/crates/ra_lsp_server/src/conv.rs
@@ -70,6 +70,7 @@ impl Conv for CompletionItemKind {
CompletionItemKind::Const => Constant,
CompletionItemKind::Static => Value,
CompletionItemKind::Method => Method,
+ CompletionItemKind::TypeParam => TypeParameter,
}
}
}