]> git.lizzy.rs Git - rust.git/commitdiff
Use the new Resolver API in completion
authorFlorian Diebold <flodiebold@gmail.com>
Sun, 27 Jan 2019 19:50:57 +0000 (20:50 +0100)
committerFlorian Diebold <flodiebold@gmail.com>
Fri, 1 Feb 2019 21:45:25 +0000 (22:45 +0100)
crates/ra_hir/src/expr.rs
crates/ra_hir/src/expr/scope.rs
crates/ra_hir/src/nameres.rs
crates/ra_hir/src/resolve.rs
crates/ra_hir/src/source_binder.rs
crates/ra_ide_api/src/completion/complete_path.rs
crates/ra_ide_api/src/completion/complete_scope.rs
crates/ra_ide_api/src/completion/completion_context.rs
crates/ra_ide_api/src/completion/completion_item.rs
crates/ra_ide_api/src/completion/snapshots/completion_item__self_in_methods.snap
crates/ra_lsp_server/src/conv.rs

index 503a09f25e58cb008d1b70a2ae5d4c37ea063749..6c294bf108ab53176b5ac5534179f6d6deb5ef24 100644 (file)
@@ -72,11 +72,23 @@ pub fn owner(&self) -> Function {
 }
 
 // needs arbitrary_self_types to be a method... or maybe move to the def?
-#[allow(dead_code)]
-pub fn resolver_for_expr(body: Arc<Body>, db: &impl HirDatabase, expr_id: ExprId) -> Resolver {
+pub fn resolver_for_expr(
+    body: Arc<Body>,
+    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<Body>,
+    db: &impl HirDatabase,
+    scope_id: Option<scope::ScopeId>,
+) -> 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::<Vec<_>>();
+    let scope_chain = scopes.scope_chain_for(scope_id).collect::<Vec<_>>();
     for scope in scope_chain.into_iter().rev() {
         r = r.push_expr_scope(Arc::clone(&scopes), scope);
     }
index 887ad8dd8b9247da798d9b396af96b47cb03ca50..23f1c5e7f2747c70637a0da4db0c2fed4d17069f 100644 (file)
@@ -62,25 +62,11 @@ pub fn entries(&self, scope: ScopeId) -> &[ScopeEntry] {
         &self.scopes[scope].entries
     }
 
-    pub fn scope_chain_for<'a>(&'a self, expr: ExprId) -> impl Iterator<Item = ScopeId> + '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<ScopeId>,
+    ) -> impl Iterator<Item = ScopeId> + 'a {
+        generate(scope, move |&scope| self.scopes[scope].parent)
     }
 
     fn root_scope(&mut self) -> ScopeId {
@@ -123,7 +109,7 @@ fn set_scope(&mut self, node: ExprId, scope: ScopeId) {
         self.scope_for.insert(node, scope);
     }
 
-    fn scope_for(&self, expr: ExprId) -> Option<ScopeId> {
+    pub fn scope_for(&self, expr: ExprId) -> Option<ScopeId> {
         self.scope_for.get(&expr).map(|&scope| scope)
     }
 }
@@ -151,18 +137,14 @@ pub fn ptr(&self) -> SyntaxNodePtr {
 }
 
 impl ScopesWithSyntaxMapping {
-    pub fn scope_chain<'a>(&'a self, node: &SyntaxNode) -> impl Iterator<Item = ScopeId> + 'a {
+    fn scope_chain<'a>(&'a self, node: &SyntaxNode) -> impl Iterator<Item = ScopeId> + '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<Item = ScopeId> + 'a {
-        let scope = self
-            .scopes
+    pub fn scope_for_offset<'a>(&'a self, offset: TextUnit) -> Option<ScopeId> {
+        self.scopes
             .scope_for
             .iter()
             .filter_map(|(id, scope)| Some((self.syntax_mapping.expr_syntax(*id)?, scope)))
@@ -173,9 +155,7 @@ pub fn scope_chain_for_offset<'a>(
                     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
index 193c6a9779eb12ddb3cf157ed312663cd5cedb0b..9b020db811df5853b79fc76fc58bd2349a6dd5d2 100644 (file)
@@ -81,6 +81,15 @@ pub struct PerNs<T> {
     pub values: Option<T>,
 }
 
+impl<T> Default for PerNs<T> {
+    fn default() -> Self {
+        PerNs {
+            types: None,
+            values: None,
+        }
+    }
+}
+
 impl<T> PerNs<T> {
     pub fn none() -> PerNs<T> {
         PerNs {
index 36daed65b8518cbefa4366113ea24d8405022fb5..30cf9c69e7acdd25284b9daaace9d9f6309c0c89 100644 (file)
@@ -89,8 +89,20 @@ pub fn resolve_path(&self, db: &impl HirDatabase, path: &Path) -> PerNs<Resoluti
         }
     }
 
-    pub fn all_names(&self) -> FxHashMap<Name, Resolution> {
-        unimplemented!()
+    pub fn all_names(&self) -> FxHashMap<Name, PerNs<Resolution>> {
+        let mut names = FxHashMap::default();
+        for scope in &self.scopes {
+            scope.collect_names(&mut |name, res| {
+                let current: &mut PerNs<Resolution> = 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 @@ fn resolve_name(&self, name: &Name) -> PerNs<Resolution> {
             }
         }
     }
+
+    fn collect_names(&self, f: &mut FnMut(Name, PerNs<Resolution>)) {
+        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() }),
+                    );
+                });
+            }
+        }
+    }
 }
index 1fdd7d087a33fd480270cd8b2ffbd714a5faf7b3..998158b3e867ccc4614c1a8c49a68f8098d1844f 100644 (file)
@@ -9,13 +9,14 @@
 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()
 }
index b33ddcde56a6e29eb2110b6813c55585868163b3..9e61c021275c13683a541599cc81f7b86ce2ca35 100644 (file)
@@ -7,13 +7,13 @@
 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);
             }
         }
index f837bb1db2bcaff0f0ce60c356c482419cc5650c..3488d648060baddc39641c204bbef55efab9ae8e 100644 (file)
@@ -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)
         });
 }
index 578af6e5b3b839043f19dbda25b59e8053ecb54a..aea32fce397c30fe61bcd2aaba42f30e0470bb5c 100644 (file)
@@ -5,7 +5,7 @@
     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<hir::Module>,
     pub(super) function: Option<hir::Function>,
     pub(super) function_syntax: Option<&'a ast::FnDef>,
@@ -42,12 +43,14 @@ pub(super) fn new(
         original_file: &'a SourceFile,
         position: FilePosition,
     ) -> Option<CompletionContext<'a>> {
+        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,
index d3bc148944e1be9a1d6107d2c95f82df49bc6b41..4101ce88a0d95c2279367f8ec0572dbacf4b5ad9 100644 (file)
@@ -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 @@ pub(crate) fn set_documentation(mut self, docs: Option<Documentation>) -> Builde
     pub(super) fn from_resolution(
         mut self,
         ctx: &CompletionContext,
-        resolution: &hir::Resolution,
+        resolution: &PerNs<Resolution>,
     ) -> 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;
index 6a49e325c1aaf805dfbf7a43ba036e7dbf8afea9..ba1d4abbd5b2a10ae1f493eb657250a1ebd5fa5c 100644 (file)
@@ -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",
index c033ecdeaa10a1c570b9b4e4bec72b7dee60dca4..17fa073406b286d1e324cc50d6139112f3f0f432 100644 (file)
@@ -70,6 +70,7 @@ fn conv(self) -> <Self as Conv>::Output {
             CompletionItemKind::Const => Constant,
             CompletionItemKind::Static => Value,
             CompletionItemKind::Method => Method,
+            CompletionItemKind::TypeParam => TypeParameter,
         }
     }
 }