switch completion to new scope
This commit is contained in:
parent
b70b6bce19
commit
049f8df93c
@ -204,9 +204,9 @@ fn quux() {
|
||||
<|>
|
||||
}
|
||||
",
|
||||
r#"[CompletionItem { label: "Foo", lookup: None, snippet: None },
|
||||
CompletionItem { label: "Baz", lookup: None, snippet: None },
|
||||
CompletionItem { label: "quux", lookup: None, snippet: None }]"#,
|
||||
r#"[CompletionItem { label: "quux", lookup: None, snippet: None },
|
||||
CompletionItem { label: "Foo", lookup: None, snippet: None },
|
||||
CompletionItem { label: "Baz", lookup: None, snippet: None }]"#,
|
||||
);
|
||||
}
|
||||
|
||||
@ -230,8 +230,8 @@ mod m {
|
||||
fn quux() { <|> }
|
||||
}
|
||||
",
|
||||
r#"[CompletionItem { label: "Bar", lookup: None, snippet: None },
|
||||
CompletionItem { label: "quux", lookup: None, snippet: None }]"#,
|
||||
r#"[CompletionItem { label: "quux", lookup: None, snippet: None },
|
||||
CompletionItem { label: "Bar", lookup: None, snippet: None }]"#,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -39,14 +39,17 @@ pub(super) fn completions(
|
||||
let module_scope = module.scope(db)?;
|
||||
acc.extend(
|
||||
module_scope
|
||||
.entries()
|
||||
.items
|
||||
.iter()
|
||||
.filter(|entry| {
|
||||
.filter(|(_name, res)| {
|
||||
// Don't expose this item
|
||||
!entry.ptr().range().is_subrange(&name_ref.syntax().range())
|
||||
match res.import_name {
|
||||
None => true,
|
||||
Some(ptr) => !ptr.range().is_subrange(&name_ref.syntax().range()),
|
||||
}
|
||||
})
|
||||
.map(|entry| CompletionItem {
|
||||
label: entry.name().to_string(),
|
||||
.map(|(name, _res)| CompletionItem {
|
||||
label: name.to_string(),
|
||||
lookup: None,
|
||||
snippet: None,
|
||||
}),
|
||||
@ -173,11 +176,14 @@ fn complete_path(
|
||||
Some(it) => it,
|
||||
};
|
||||
let module_scope = target_module.scope(db)?;
|
||||
let completions = module_scope.entries().iter().map(|entry| CompletionItem {
|
||||
label: entry.name().to_string(),
|
||||
lookup: None,
|
||||
snippet: None,
|
||||
});
|
||||
let completions = module_scope
|
||||
.items
|
||||
.iter()
|
||||
.map(|(name, _res)| CompletionItem {
|
||||
label: name.to_string(),
|
||||
lookup: None,
|
||||
snippet: None,
|
||||
});
|
||||
acc.extend(completions);
|
||||
Ok(())
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
use crate::{
|
||||
db,
|
||||
descriptors::{
|
||||
DescriptorDatabase, FnScopesQuery, FnSyntaxQuery, ModuleScopeQuery, ModuleTreeQuery,
|
||||
DescriptorDatabase, FnScopesQuery, FnSyntaxQuery, ModuleTreeQuery,
|
||||
SubmodulesQuery, ItemMapQuery, InputModuleItemsQuery,
|
||||
},
|
||||
symbol_index::SymbolIndex,
|
||||
@ -88,7 +88,6 @@ impl DescriptorDatabase {
|
||||
fn fn_scopes() for FnScopesQuery;
|
||||
fn _input_module_items() for InputModuleItemsQuery;
|
||||
fn _item_map() for ItemMapQuery;
|
||||
fn _module_scope() for ModuleScopeQuery;
|
||||
fn _fn_syntax() for FnSyntaxQuery;
|
||||
fn _submodules() for SubmodulesQuery;
|
||||
}
|
||||
|
@ -11,7 +11,7 @@
|
||||
use crate::{
|
||||
db::SyntaxDatabase,
|
||||
descriptors::function::{resolve_local_name, FnId, FnScopes},
|
||||
descriptors::module::{ModuleId, ModuleScope, ModuleTree, ModuleSource, nameres::{ItemMap, InputModuleItems}},
|
||||
descriptors::module::{ModuleId, ModuleTree, ModuleSource, nameres::{ItemMap, InputModuleItems}},
|
||||
input::SourceRootId,
|
||||
loc2id::IdDatabase,
|
||||
syntax_ptr::LocalSyntaxPtr,
|
||||
@ -37,10 +37,6 @@ fn _module_tree(source_root_id: SourceRootId) -> Cancelable<Arc<ModuleTree>> {
|
||||
type ModuleTreeQuery;
|
||||
use fn module::imp::module_tree;
|
||||
}
|
||||
fn _module_scope(source_root_id: SourceRootId, module_id: ModuleId) -> Cancelable<Arc<ModuleScope>> {
|
||||
type ModuleScopeQuery;
|
||||
use fn module::imp::module_scope;
|
||||
}
|
||||
fn _fn_syntax(fn_id: FnId) -> FnDefNode {
|
||||
type FnSyntaxQuery;
|
||||
// Don't retain syntax trees in memory
|
||||
|
@ -1,7 +1,7 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use ra_syntax::{
|
||||
ast::{self, ModuleItemOwner, NameOwner},
|
||||
ast::{self, NameOwner},
|
||||
SmolStr,
|
||||
};
|
||||
use relative_path::RelativePathBuf;
|
||||
@ -15,7 +15,7 @@
|
||||
};
|
||||
|
||||
use super::{
|
||||
LinkData, LinkId, ModuleData, ModuleId, ModuleScope, ModuleSource, ModuleSourceNode,
|
||||
LinkData, LinkId, ModuleData, ModuleId, ModuleSource, ModuleSourceNode,
|
||||
ModuleTree, Problem,
|
||||
};
|
||||
|
||||
@ -81,23 +81,6 @@ pub(crate) fn modules<'a>(
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn module_scope(
|
||||
db: &impl DescriptorDatabase,
|
||||
source_root_id: SourceRootId,
|
||||
module_id: ModuleId,
|
||||
) -> Cancelable<Arc<ModuleScope>> {
|
||||
let tree = db._module_tree(source_root_id)?;
|
||||
let source = module_id.source(&tree).resolve(db);
|
||||
let res = match source {
|
||||
ModuleSourceNode::SourceFile(it) => ModuleScope::new(it.borrowed().items()),
|
||||
ModuleSourceNode::Module(it) => match it.borrowed().item_list() {
|
||||
Some(items) => ModuleScope::new(items.items()),
|
||||
None => ModuleScope::new(std::iter::empty()),
|
||||
},
|
||||
};
|
||||
Ok(Arc::new(res))
|
||||
}
|
||||
|
||||
pub(crate) fn module_tree(
|
||||
db: &impl DescriptorDatabase,
|
||||
source_root: SourceRootId,
|
||||
|
@ -1,5 +1,4 @@
|
||||
pub(super) mod imp;
|
||||
mod scope;
|
||||
pub(super) mod nameres;
|
||||
|
||||
use std::sync::Arc;
|
||||
@ -19,7 +18,7 @@
|
||||
input::SourceRootId
|
||||
};
|
||||
|
||||
pub(crate) use self::scope::ModuleScope;
|
||||
pub(crate) use self::{nameres::ModuleScope};
|
||||
|
||||
/// `ModuleDescriptor` is API entry point to get all the information
|
||||
/// about a particular module.
|
||||
@ -126,8 +125,10 @@ pub fn child(&self, name: &str) -> Option<ModuleDescriptor> {
|
||||
}
|
||||
|
||||
/// Returns a `ModuleScope`: a set of items, visible in this module.
|
||||
pub fn scope(&self, db: &impl DescriptorDatabase) -> Cancelable<Arc<ModuleScope>> {
|
||||
db._module_scope(self.source_root_id, self.module_id)
|
||||
pub(crate) fn scope(&self, db: &impl DescriptorDatabase) -> Cancelable<ModuleScope> {
|
||||
let item_map = db._item_map(self.source_root_id)?;
|
||||
let res = item_map.per_module[&self.module_id].clone();
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
pub fn problems(&self, db: &impl DescriptorDatabase) -> Vec<(SyntaxNode, Problem)> {
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
use ra_syntax::{
|
||||
SmolStr, SyntaxKind::{self, *},
|
||||
ast::{self, NameOwner, AstNode, ModuleItemOwner}
|
||||
ast::{self, AstNode, ModuleItemOwner}
|
||||
};
|
||||
|
||||
use crate::{
|
||||
@ -26,13 +26,13 @@
|
||||
/// module, the set of visible items.
|
||||
#[derive(Default, Debug, PartialEq, Eq)]
|
||||
pub(crate) struct ItemMap {
|
||||
per_module: FxHashMap<ModuleId, ModuleItems>,
|
||||
pub(crate) per_module: FxHashMap<ModuleId, ModuleScope>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, PartialEq, Eq)]
|
||||
struct ModuleItems {
|
||||
items: FxHashMap<SmolStr, Resolution>,
|
||||
import_resolutions: FxHashMap<LocalSyntaxPtr, DefId>,
|
||||
#[derive(Debug, Default, PartialEq, Eq, Clone)]
|
||||
pub(crate) struct ModuleScope {
|
||||
pub(crate) items: FxHashMap<SmolStr, Resolution>,
|
||||
pub(crate) import_resolutions: FxHashMap<LocalSyntaxPtr, DefId>,
|
||||
}
|
||||
|
||||
/// A set of items and imports declared inside a module, without relation to
|
||||
@ -117,22 +117,25 @@ pub(crate) fn item_map(
|
||||
/// Resolution is basically `DefId` atm, but it should account for stuff like
|
||||
/// multiple namespaces, ambiguity and errors.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
struct Resolution {
|
||||
pub(crate) struct Resolution {
|
||||
/// None for unresolved
|
||||
def_id: Option<DefId>,
|
||||
pub(crate) def_id: Option<DefId>,
|
||||
/// ident by whitch this is imported into local scope.
|
||||
/// TODO: make this offset-independent.
|
||||
pub(crate) import_name: Option<LocalSyntaxPtr>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
enum Namespace {
|
||||
Types,
|
||||
Values,
|
||||
}
|
||||
// #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
// enum Namespace {
|
||||
// Types,
|
||||
// Values,
|
||||
// }
|
||||
|
||||
#[derive(Debug)]
|
||||
struct PerNs<T> {
|
||||
types: Option<T>,
|
||||
values: Option<T>,
|
||||
}
|
||||
// #[derive(Debug)]
|
||||
// struct PerNs<T> {
|
||||
// types: Option<T>,
|
||||
// values: Option<T>,
|
||||
// }
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
struct ModuleItem {
|
||||
@ -144,7 +147,7 @@ struct ModuleItem {
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
enum Vis {
|
||||
Priv,
|
||||
// Priv,
|
||||
Other,
|
||||
}
|
||||
|
||||
@ -302,13 +305,17 @@ fn resolve(&mut self) -> Cancelable<()> {
|
||||
fn populate_module(&mut self, module_id: ModuleId, input: &InputModuleItems) {
|
||||
let file_id = module_id.source(&self.module_tree).file_id();
|
||||
|
||||
let mut module_items = ModuleItems::default();
|
||||
let mut module_items = ModuleScope::default();
|
||||
|
||||
for import in input.imports.iter() {
|
||||
if let Some((_, name)) = import.segments.last() {
|
||||
module_items
|
||||
.items
|
||||
.insert(name.clone(), Resolution { def_id: None });
|
||||
if let Some((ptr, name)) = import.segments.last() {
|
||||
module_items.items.insert(
|
||||
name.clone(),
|
||||
Resolution {
|
||||
def_id: None,
|
||||
import_name: Some(*ptr),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -322,6 +329,7 @@ fn populate_module(&mut self, module_id: ModuleId, input: &InputModuleItems) {
|
||||
let def_id = self.db.id_maps().def_id(def_loc);
|
||||
let resolution = Resolution {
|
||||
def_id: Some(def_id),
|
||||
import_name: None,
|
||||
};
|
||||
module_items.items.insert(item.name.clone(), resolution);
|
||||
}
|
||||
@ -334,6 +342,7 @@ fn populate_module(&mut self, module_id: ModuleId, input: &InputModuleItems) {
|
||||
let def_id = self.db.id_maps().def_id(def_loc);
|
||||
let resolution = Resolution {
|
||||
def_id: Some(def_id),
|
||||
import_name: None,
|
||||
};
|
||||
module_items.items.insert(name, resolution);
|
||||
}
|
||||
@ -386,6 +395,7 @@ fn resolve_import(&mut self, module_id: ModuleId, import: &Path) {
|
||||
self.update(module_id, |items| {
|
||||
let res = Resolution {
|
||||
def_id: Some(def_id),
|
||||
import_name: Some(*ptr),
|
||||
};
|
||||
items.items.insert(name.clone(), res);
|
||||
})
|
||||
@ -393,7 +403,7 @@ fn resolve_import(&mut self, module_id: ModuleId, import: &Path) {
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, module_id: ModuleId, f: impl FnOnce(&mut ModuleItems)) {
|
||||
fn update(&mut self, module_id: ModuleId, f: impl FnOnce(&mut ModuleScope)) {
|
||||
let module_items = self.result.per_module.get_mut(&module_id).unwrap();
|
||||
f(module_items)
|
||||
}
|
||||
|
@ -1,124 +0,0 @@
|
||||
//! Backend for module-level scope resolution & completion
|
||||
|
||||
use ra_syntax::{ast, AstNode, SmolStr};
|
||||
|
||||
use crate::syntax_ptr::LocalSyntaxPtr;
|
||||
|
||||
/// `ModuleScope` contains all named items declared in the scope.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub(crate) struct ModuleScope {
|
||||
entries: Vec<Entry>,
|
||||
}
|
||||
|
||||
/// `Entry` is a single named declaration iside a module.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub(crate) struct Entry {
|
||||
ptr: LocalSyntaxPtr,
|
||||
kind: EntryKind,
|
||||
name: SmolStr,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
enum EntryKind {
|
||||
Item,
|
||||
Import,
|
||||
}
|
||||
|
||||
impl ModuleScope {
|
||||
pub(super) fn new<'a>(items: impl Iterator<Item = ast::ModuleItem<'a>>) -> ModuleScope {
|
||||
let mut entries = Vec::new();
|
||||
for item in items {
|
||||
let entry = match item {
|
||||
ast::ModuleItem::StructDef(item) => Entry::new(item),
|
||||
ast::ModuleItem::EnumDef(item) => Entry::new(item),
|
||||
ast::ModuleItem::FnDef(item) => Entry::new(item),
|
||||
ast::ModuleItem::ConstDef(item) => Entry::new(item),
|
||||
ast::ModuleItem::StaticDef(item) => Entry::new(item),
|
||||
ast::ModuleItem::TraitDef(item) => Entry::new(item),
|
||||
ast::ModuleItem::TypeDef(item) => Entry::new(item),
|
||||
ast::ModuleItem::Module(item) => Entry::new(item),
|
||||
ast::ModuleItem::UseItem(item) => {
|
||||
if let Some(tree) = item.use_tree() {
|
||||
collect_imports(tree, &mut entries);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
ast::ModuleItem::ExternCrateItem(_) | ast::ModuleItem::ImplItem(_) => continue,
|
||||
};
|
||||
entries.extend(entry)
|
||||
}
|
||||
|
||||
ModuleScope { entries }
|
||||
}
|
||||
|
||||
pub fn entries(&self) -> &[Entry] {
|
||||
self.entries.as_slice()
|
||||
}
|
||||
}
|
||||
|
||||
impl Entry {
|
||||
fn new<'a>(item: impl ast::NameOwner<'a>) -> Option<Entry> {
|
||||
let name = item.name()?;
|
||||
Some(Entry {
|
||||
name: name.text(),
|
||||
ptr: LocalSyntaxPtr::new(name.syntax()),
|
||||
kind: EntryKind::Item,
|
||||
})
|
||||
}
|
||||
fn new_import(path: ast::Path) -> Option<Entry> {
|
||||
let name_ref = path.segment()?.name_ref()?;
|
||||
Some(Entry {
|
||||
name: name_ref.text(),
|
||||
ptr: LocalSyntaxPtr::new(name_ref.syntax()),
|
||||
kind: EntryKind::Import,
|
||||
})
|
||||
}
|
||||
pub fn name(&self) -> &SmolStr {
|
||||
&self.name
|
||||
}
|
||||
pub fn ptr(&self) -> LocalSyntaxPtr {
|
||||
self.ptr
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_imports(tree: ast::UseTree, acc: &mut Vec<Entry>) {
|
||||
if let Some(use_tree_list) = tree.use_tree_list() {
|
||||
return use_tree_list
|
||||
.use_trees()
|
||||
.for_each(|it| collect_imports(it, acc));
|
||||
}
|
||||
if let Some(path) = tree.path() {
|
||||
acc.extend(Entry::new_import(path));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use ra_syntax::{ast::ModuleItemOwner, SourceFileNode};
|
||||
|
||||
fn do_check(code: &str, expected: &[&str]) {
|
||||
let file = SourceFileNode::parse(&code);
|
||||
let scope = ModuleScope::new(file.ast().items());
|
||||
let actual = scope.entries.iter().map(|it| it.name()).collect::<Vec<_>>();
|
||||
assert_eq!(expected, actual.as_slice());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_module_scope() {
|
||||
do_check(
|
||||
"
|
||||
struct Foo;
|
||||
enum Bar {}
|
||||
mod baz {}
|
||||
fn quux() {}
|
||||
use x::{
|
||||
y::z,
|
||||
t,
|
||||
};
|
||||
type T = ();
|
||||
",
|
||||
&["Foo", "Bar", "baz", "quux", "z", "t", "T"],
|
||||
)
|
||||
}
|
||||
}
|
@ -447,8 +447,8 @@ fn test_complete_crate_path() {
|
||||
);
|
||||
let completions = analysis.completions(position).unwrap().unwrap();
|
||||
assert_eq_dbg(
|
||||
r#"[CompletionItem { label: "foo", lookup: None, snippet: None },
|
||||
CompletionItem { label: "Spam", lookup: None, snippet: None }]"#,
|
||||
r#"[CompletionItem { label: "Spam", lookup: None, snippet: None },
|
||||
CompletionItem { label: "foo", lookup: None, snippet: None }]"#,
|
||||
&completions,
|
||||
);
|
||||
}
|
||||
@ -466,8 +466,8 @@ fn test_complete_crate_path_with_braces() {
|
||||
);
|
||||
let completions = analysis.completions(position).unwrap().unwrap();
|
||||
assert_eq_dbg(
|
||||
r#"[CompletionItem { label: "foo", lookup: None, snippet: None },
|
||||
CompletionItem { label: "Spam", lookup: None, snippet: None }]"#,
|
||||
r#"[CompletionItem { label: "Spam", lookup: None, snippet: None },
|
||||
CompletionItem { label: "foo", lookup: None, snippet: None }]"#,
|
||||
&completions,
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user